News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

MasmBasic

Started by jj2007, May 23, 2012, 10:16:07 PM

Previous topic - Next topic

sinsi

Table 1.3 Operator Precedence
Precedence Operators
1 ( ), [ ]
2 LENGTH , SIZE , WIDTH , MASK, LENGTHOF, SIZEOF
3 . (structure-field-name operator)
4 : (segment-override operator), PTR
5 LROFFSET , OFFSET , SEG , THIS , TYPE
6 HIGH , HIGHWORD , LOW , LOWWORD
7 + ,– (unary)
8 *, /, MOD , SHL , SHR
9 +, – (binary)
10 EQ , NE , LT , LE , GT , GE
11 NOT
12 AND
13 OR , XOR
14 OPATTR , SHORT , .TYPE

jj2007

Thanks, Sinsi - this is already fixed with Nidud's suggestion to use brackets: if ((dstyle) and SS_ICON) eq SS_ICON

To my big surprise, I discovered that, after applying that fix, the line that choked was no longer the SS_LEFT or WS_BORDER line but rather the line that followed - see snippet above. After some trial and error, I discovered that cases 1 and 3, although almost identical, act differently:

case 1: DlgControl dcStatic,  "maxMB=", SS_LEFT, 73.0%, -7, 31%
case 3: DlgControl dcStatic,  "maxMB=", SS_LEFT, 73.0%, -7, 31%   ; this one is also OK!!

The first one chokes, the second one is OK. And of course, both are OK for UAsm and AsmC.

TimoVJL

#482
8.14.5 Macro Parameter Expansion and Macro Operators
QuoteOne possible solution, that works well for macros like the above, is to put parentheses
around macro parameters that occur within expressions inside the macro
.
http://www.phatcode.net/res/223/files/html/Chapter_8/CH08-7.html

EDIT: to avoid further misunderstanding, only documentation for that ?
QuoteThe problem above occurs because MASM simply replaces a formal parameter by the actual parameter's text, not the actual parameter's value. This pass by name parameter passing mechanism should be familiar to long-time C and C++ programmers who use the #define statement. If you think that macro (pass by name) parameters work just like Pascal and C's pass by value parameters, you are setting yourself up for eventual disaster.

One possible solution, that works well for macros like the above, is to put parentheses around macro parameters that occur within expressions inside the macro. Consider the following code:
May the source be with you

jj2007

Yes, Timo, but it's not relevant here. Or, rather: it does work if you put parentheses around (x or z) but if you don't put these parentheses, all paras are passed correctly to this macro but the macro in the next line chokes.

And to make things perfect, you can make it assemble if ... tara! ... you add a comment to the next line:
case 1: DlgControl dcStatic,  "maxMB=", SS_LEFT, 73.0%, -7, 31%
case 3: DlgControl dcStatic,  "maxMB=", SS_LEFT, 73.0%, -7, 31%   ; this comment makes the line assemble!!


If there is no comment, you get error A2026: constant expected - and that is complete BS. It's a MASM bug, that's all. Of the same kind as the inability to deal with the "#" character if it's not at a certain position inside the include file. I can't find the reference right now, but that was another ML bug that drove me crazy. My suspicion is that during macro processing, some buffers don't get delimited properly, but that is impossible to chase.

MASM has some serious problems, and I would ditch it completely in favour of UAsm or AsmC if there wasn't a bit of nostalgia around to stick with the original M$ product.

jj2007

Timo,

I use all these macros on a daily basis, they work just fine. The problem is really some kind of buffer overflow in MASM that makes it choke with the % and # characters. I opened a separate MASM bug post with the complete example.

The new MasmBasic version has fixes for the brackets bug, allows using e.g. 12.3% in the first DlgControl (that was the DlgDefY issue), and adds a specific warning to the output window if RichMasm sees "error A2026:constant expected".

Thanks a lot, Timo, Nidud and Sinsi, for your help.

jj2007

MasmBasic version 26 October 2019 is online.

Changes:
- the RichMasm editor lists now macros and procs correctly, as in the image below
- \Masm32\MasmBasic\MbGuide.rtf got a Table of Contents
- For_ ... Next with floats follows a different logic now:
  * previously, the step was added to the float counter (fct in the example below). For small steps and REAL4 counters, significant deviations could accumulate
  * the new version calculates fct as endvalue - step*(total - current iterations), which is much more exact.

include \masm32\MasmBasic\MasmBasic.inc
  SetGlobals fct:REAL4
  Init
  For_ fct=1.5 To 2.0 Step 0.01 ; counter is a float, and therefore needs to be
Print Str$("%Jf\n", fct) ; previously defined in .data? or with SetGlobals
  Next
  Inkey "ok?"
EndOfCode

jj2007

Version 7 December 2019 is online. Minor improvements, e.g. it's now possible to add a legend to an ArrayPlot (project attached):



The code required to add the legend:

        ArrayPlot RgbCol(192, 255, 255)         ; init & set background
        If_ useLegend Then Legend ld$(), mr, hLegendFont                ; corners: ul, ur, ll, lr, mr
...
        ArrayPlot exit, 0005000032#T title$, fcol Black         ; finish with a title, xxxxyyyyfsize


ld$() can be any Utf8 string array; mr indicates the position middle/right

To build the project,
- install the latest MasmBasic version
- extract the archive below to a folder on your Masm32 drive
- open LifeExpOECD.asc in RichMasm (\Masm32\MasmBasic\RichMasm.exe)
- hit F6

JK

Hi jj2007,


just downloaded your MasmBasic - interesting! I think there will be questions ...


JK

jj2007


JK

The idea is very cool, the implementation (RichMasm) is ... not easy to get used to. I would like to discuss a few things (MasmBasic and FreeBASIC related) in private - would you please drop me a mail at "jklwn44 at mail dot de".

jj2007

Email sent, although I prefer discussing here in this thread, or, if necessary, via PMs.

Re RichMasm, there are some posts here. I know it looks different, but I couldn't do any serious work with one of the standard editors. For example, the RichMasm source has currently 21,000 lines, try working with such a source without the listbox, the bookmarks and the history (Alt cursor left/right) :cool:

Note you can build FreeBasic sources with RichMasm, but a little add-on is needed. Let me know if you want to test it.

My biggest nuisance with RichMasm is that the MRU is limited to 25 files. The library itself is easy to handle, just one big file with 30 or so modules, but I have over 5,000 sources hanging around, and I am always playing with a dozen new ideas.

jj2007

Update 22 Feb 2020:
- minor improvements of the RichMasm editor
- changes to the deb macro:

  - displaying a string by address is now possible via e.g. deb 4, "test", $addr MyAnsi$, $$addr MyWide$
  - the handling of strings in structures was improved
  - debugging the FPU was improved - now the state of the registers is displayed:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  FpuFill ; fill FPU with 1001.0 ... 1008.0
  ffree st(7) ; create some problems
  fldz
  fldpi
  ffree st(5)
  ffree st(7)
  fldl2e
  deb 4, "FPU filled, NaN in ST1, zero in ST2, ST6 empty", ST(0), ST(1), ST(2), ST(3), ST(4), ST(5), ST(6), ST(7)
  fstp st
  ffree st(7)
  ffree st(6)
  ffree st(5)
  ffree st(4)
  ffree st(3)
  deb 1, "As previous, one fstp st plus 5*ffree", ST(0), ST(1), ST(2), ST(3), ST(4), ST(5), ST(6), ST(7)
EndOfCode


You may wonder why there are five ffree instructions: it is a special service for the Windows 10 users :bgrin:

Console output (deb 1 produces a MsgBox):
FPU filled, NaN in ST1, zero in ST2, ST6 empty
ST(0)           1.442695040888963407
ST(1)           - NaN -
ST(2)           zero
ST(3)           1001.000000000000000
ST(4)           1002.000000000000000
ST(5)           1003.000000000000000
ST(6)           empty 1004.000000000
ST(7)           1005.000000000000000


- various trigonometric functions added (source attached):

include \masm32\MasmBasic\MasmBasic.inc
  SetGlobals fct:REAL8
  Init
  Cls
  Print cfm$("degrees\tSinus\tCosinus\t  Tangens    Cotangens")
  For_ fct=0.1 To 360.0 Step 15.0
Print Str$("\n%__i", fct), Str$("\t%3f", Sinus(fct)v), Str$("\t%3f", Cosinus(fct)v), Str$("\t  %3f", Tangens(fct)v)
Print At(37) Str$("%3f", Cotangens(fct)v)
  Next
  Print
  Print Str$("\nrTangens(PI/3)=30°    \t%3f", rTangens(0.5236)v)
  Print Str$("\nrCotangens(PI/6)=15° \t%3f", rCotangens(0.2618)v)
  Print Str$("\nArctangens(0.268) \t%3f", Arctangens(0.268)v)
  Print Str$("\nArctangens(0.577) \t%3f", Arctangens(0.577)v)
  Print Str$("\nArctangens(1)    \t%3f", Arctangens(1)v)
  Print Str$("\nArctangens(1.732) \t%3f", Arctangens(1.732)v)
  Print Str$("\nArctangens(60/30) \t%3f", Arctangens(60, 30)v) ; ideally opposite/adjacent sides of a rectangular triangle
  Print Str$("\nArctangens(4/3) \t%3f", Arctangens(4, 3)v) ; Pythagoras: 25=16+9
EndOfCode


Output:
degrees Sinus   Cosinus   Tangens    Cotangens
  0     0.00175 1.000     0.00175    573.
15     0.259   0.966     0.268      3.73
30     0.500   0.866     0.577      1.73
45     0.707   0.707     1.00       1.00
60     0.866   0.500     1.73       0.577
75     0.966   0.259     3.73       0.268
90     1.00    0.0       -3.69e+19  -2.71e-20
105     0.966   -0.259    -3.73      -0.268
120     0.866   -0.500    -1.73      -0.577
135     0.707   -0.707    -1.000     -1.00
150     0.500   -0.866    -0.577     -1.73
165     0.259   -0.966    -0.268     -3.73
180     0.0     -1.00     5.42e-20   1.84e+19
195     -0.259  -0.966    0.268      3.73
210     -0.500  -0.866    0.577      1.73
225     -0.707  -0.707    1.00       1.00
240     -0.866  -0.500    1.73       0.577
255     -0.966  -0.259    3.73       0.268
270     -1.00   0.0       -5.27e+18  -1.90e-19
285     -0.966  0.259     -3.73      -0.268
300     -0.866  0.500     -1.73      -0.577
315     -0.707  0.707     -1.00      -1.000
330     -0.500  0.866     -0.577     -1.73
345     -0.259  0.966     -0.268     -3.73
360     0.0     1.00      1.08e-19   9.22e+18

rTangens(PI/3)=30°      0.577
rCotangens(PI/6)=15°    3.73
Arctangens(0.268)       15.0
Arctangens(0.577)       30.0
Arctangens(1)           45.0
Arctangens(1.732)       60.0
Arctangens(60/30)       63.4
Arctangens(4/3)         53.1

jj2007

MasmBasic of 2 May 2020 features the Say macro (source included). Simple example:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Say "Hello World"
EndOfCode


Attached is a project (tested with Win10, Win7 and WinXP) that might amuse Hutch - here is the complete source, it's a fascinating lecture :bgrin:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Say wRec$(NoTag$(FileRead$("http://masm32.com/why.htm")))
EndOfCode


Using Say from a GUI application is also quite easy:

- in RichMasm's File menu, click "New Masm source" to open the greenish window with the templates
- pick "controls" (the third item in the list with white background)
- hit F6 to test it, then check the syntax in the source.

Excerpt from \Masm32\MasmBasic\MbGuide.rtf:

Sound
       Sound "880:200"         ; plays frequency 880Hz for 200 ms; allowed separators are space, tab, / and :
       Sound "880/200/150"     ; plays frequency 880Hz for 200 ms, followed by 150 ms of silence
       Sound 111               ; plays a wav resource with ID 111 (in rc file: 111 WAVE "hello.wav")
       Sound "hello.wav"       ; plays a file directly (wav only)
       Sound "hello.mp3"       ; plays a file in its associated player
       Sound "大桥在混乱的水.mp3"  ; Unicode names are allowed
       Sound wCL$()            ; even if passed via the commandline
Rem    - The simple "frequency:duration" syntax works on Windows 7 and higher but not on Windows Vista;
          a minimum duration of about 90...100 ms is required
        - PlaySound/Beep/ShellExecute results can be checked with Err$()
Say
       include \masm32\MasmBasic\MasmBasic.inc
       Init                            ; select Init and hit F6
        Say "Hello World"
        Say "Low and slow", SetVolume(50), SetRate(-7)  ; you can use some methods of the ISpVoice interface
       ; Say wWin$(hEdit)              ; any Unicode string is ok
       ; Say FileRead$("TTS_Unicode.txt")
       ; Say wRec$(FileRead$("TTS_Ansi.txt"))  ; conversion necessary
       EndOfCode
Rem    uses ISpVoice


P.S.: Does anybody know how to use SpCreateBestObject? In theory, SetVoice(...) should work with the Say macro, but I can find only one female voice under Win7 and Win10.

Siekmanski

Speaking of source code, literally.  :cool:
Creative coders use backward thinking techniques as a strategy.

jj2007

Exactly :tongue:

Here is another one for you: it reads the Say macro source for you :bgrin:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Say wRec$(Extract$(FileRead$("\masm32\MasmBasic\MasmBasic.inc"), "Say MACRO", "ENDM", xsIncL or xsIncR, 99))
EndOfCode


Obviously, you need the last MB installation to extract the macro from the inc file, otherwise Extract$(..) will only return a question mark.

Another variant, reading a very old short source:
include \masm32\MasmBasic\MasmBasic.inc
  Init
  Recall "\Masm32\examples\Tut17\2\USEDLL.ASM", L$()
  For_ each ecx in L$()
PrintLine ecx
Say wRec$(ecx), SetRate(5)
  Next
EndOfCode