News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

MasmBasic

Started by jj2007, October 06, 2009, 08:24:57 PM

Previous topic - Next topic

qWord

hi jj,
what nice tool/script are you using for creating this highlighted code in quotes? - self made?
FPU in a trice: SmplMath
It's that simple!

jj2007

Quote from: qWord on July 14, 2011, 12:19:43 PM
hi jj,
what nice tool/script are you using for creating this highlighted code in quotes? - self made?

Yes. As you might know :bg, RichMasm stands for Rich Text Format Masm editor - and it has a special key (F11) that puts the selected text onto the clipboard in the Forum's format. Not perfect, sometimes I have to correct little things by hand, but overall I believe that individual colouring improves readibility. What I can't stand is automatic Christmas tree highlighting of the mov eax, byte ptr [esi] sort...

qWord

Quote from: jj2007 on July 14, 2011, 04:34:13 PMYes. As you might know :bg, RichMasm stands for Rich Text Format Masm editor - and it has a special key (F11) that puts the selected text onto the clipboard in the Forum's format.
I've seen, that key words could be add, by modifying the file Keywords.ini - unfortunately this doesn't match my requirements. (AFAIKS)
Now I've written a small program, that transform text currently  on the clipboard  (keyword highlightning, tab->space)  :P
FPU in a trice: SmplMath
It's that simple!

jj2007

Quote from: qWord on July 15, 2011, 03:05:15 AM
I've seen, that key words could be add, by modifying the file Keywords.ini - unfortunately this doesn't match my requirements.

Hi qWord,
\masm32\RichMasm\Res\Keywords.ini does something else: you type e.g. ism[space] in RichMasm, and invoke Sendmessage, gets inserted. Other example: if you type .rep[space], you get...
   .Repeat
      ¨
   .Until 0
... and the red double-dot in the middle is selected, so that you can just continue typing, e.g. dec ecx or whatever. That is a just a feature which saves typing, but for me it has become incredibly important.

The "F11 forum highlighter", in contrast, takes what is currently selected in the editor and converts the colours etc:

@@:
  Open "I", #1, RecFiles$
  cmp eax, INVALID_HANDLE_VALUE
  jne @F
   Open "O", #1, RecFiles$   ; no recent files list yet, let's create one
   
Print #1, offset txHelp2   ; "Res\RichMasmGuide.asc", default first file
   Close #1
   jmp @B
@@:
  Input #1, edi, Lof(#1)
;  deb 1, "New recent files list:", $edi
  Close 1

The blue text stems from using the keyboard feature: if you type opi [space], you get Open "I", #1,. Same for the grey comments: RichMasm changes the colour to grey if you press TAB, ; - but you can always change the colour afterwards, such as in recent files above.
The other colours, green for the "good" jump, red for the "bad" one, are inserted by hand. I use such colours sparingly to highlight specific code elements, often for very tricky code sequences. When I reexamine such code after some months, the colours help me to understand why I made certain stupid-looking choices ;-)

Now if you copy the same selected text and run your exe, the result is this:
@@:
  Open "I", #1, RecFiles$
  cmp eax, INVALID_HANDLE_VALUE
  jne @F
    Open "O", #1, RecFiles$ ; no recent files list yet, let's create one
    Print #1, offset txHelp2    ; "Res\RichMasmGuide.asc", default first file
    Close #1
    jmp @B
@@:
  Input #1, edi, Lof(#1)
;  deb 1, "New recent files list:", $edi
  Close 1


That is probably not what you intended...??

qWord

hi,
Quote from: jj2007 on July 15, 2011, 10:01:37 AMThat is probably not what you intended...??
:bg it has diffrent sets own keywords, which are automatically colored - your example simply doesn't use the right keywords. Also it automatically convert tabs to spaces.
Quote    ldl x=3.5, a=1, b=5, _c=1

    fSlv y = a*x^2+b*x +_c
    print "a*x^2+b*x +_c = "
    print real4$(y),13,10

    mov sz[0],0
    print cat$(ADDR sz,"the logarithm of 12 to base 3 is: ",real8$( @fSlv8(x= logbx(3,12) ) )),13,10
    mov sz[0],0
    print cat$(ADDR sz,"3^",real8$(x)," = ",real8$( @fSlv8(x= 3^x))),13,10     

    .if fEQ( 1 , 2.E-7 ) || fGT( @fSlv4(x^2) , y )
        print "whatever",13,10
    .endif

    fSlv y = 1*2+3*4.0 +_c {i2,r4}
   
    .if fEQ( 1.2 , x {r8})
        ;...
    .endif

Beginning I've just thought, that all highlighting is done automatically by RichMasm. Also it can only highlight keywords (from keyword.ini) with one color?. You may add some 'remember coloring' or 'remember this keyword' function.

Quote from: jj2007 on July 15, 2011, 10:01:37 AM
Other example: if you type .rep[space], you get...
   .Repeat
      ¨
   .Until 0
... and the red double-dot in the middle is selected, so that you can just continue typing,
that's really nice

qWord
FPU in a trice: SmplMath
It's that simple!

jj2007

Quote from: qWord on July 15, 2011, 04:29:58 PM
I've just thought, that all highlighting is done automatically by RichMasm.

Only a few are highlighted automatically, by typing the keyboard shortcut for the MasmBasic keywords, or by typing push xxx or tab:

   Open "O", #1, "Test.txt"   ; MasmBasic keyword
   push esi   ; push & pop
   Print #1, "Test"   ; comments
   
pop esi   ; push & pop
   
Close #1   ; MasmBasic keyword

All text can be formatted manually. I tend to write FPU code in blue to distinguish it a bit, but it's merely a matter of taste.
I will reflect on conversion of tabs to spaces for the Forum export. The browsers don't provide enough indent for tabs.

jj2007

Relax - this is for JWasm users only...

As reported in bug report 3142937 of 23.12.2010, Jwasm has problems with macros that appear inside quoted text. This is difficult to reproduce without using MasmBasic, but below is a snippet showing the effect. Use the workaround in case you stumble over this problem.

Again: there is no problem for users of Microsoft Macro Assembler aka MASM.


Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; download
   Init
   GetFiles *.txt   ; put text files of current folder into Files$() array
   Let Files$('A')=String$(8,"abc")   ; prefill Files$(65) (A=Ascii 65)

;   
RichMasm options (if you use another IDE, change the assembler option accordingly, and don't forget to set console assembly):
;   OPT_Assembler
   Jwasm   ; requires \masm32\bin\JWASM.EXE
;   OxPT_Assembler   ml   ; the x disables this option - delete to use \masm32\bin\ML.exe
   ; 0+1=trigger error, 2=show incorrect result in Jwasm, 3=workaround
   TheCase=2


   ; we try to print the prefilled Files$(65)
   ife TheCase
      ; wrong syntax for String$, so Jwasm (trying to expand) complains with Error A2220
      Print Chr$("This text was put as String$(8) into Files$('A'): "), CrLf$, Files$('A')
   elseif TheCase eq 1
      ; same wrong syntax for String$, echo only - but Jwasm (trying to expand) complains
      % echo Print Chr$("This text was put as String$(8) into Files$('A'): "), CrLf$, Files$('A')
   elseif TheCase eq 2
      ; correct syntax for String$, Jwasm expands silently, we see ( eAx) instead of String$(32767, 0)
      Print Chr$("This text was put as String$(8,'abc') into Files$('A'): "), CrLf$, Files$('A')
   else
      
; workaround - split the quoted text to confuse Jwasm:
      Print Chr$("This text was put as Str", "ing$(8,'abc') into Fil", "es$('A'): "), CrLf$, Files$('A')
   endif
   Inkey Files$(65)
   Exit
end start

; expected output:
This text was put as String$(8, 'abc') into Files$('A'):
abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc

; JWasm, TheCase=2 (the two eax are the exitm values of the string$() and files$() macros):
This text was put as ( eAx) into ( EaX):
abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc

Note this snippet works fine with recent Jwasm versions:
   Dim My$(1)
   Let My$(0)="This is string zero"
   Let My$(1)="This is string one"
   Print "These are My$(0) and My$(1): ", CrLf$, My$(0), CrLf$, My$(1)

jj2007

Clip$() did not work properly, inter alia because of the problems mentioned in the GetClipboardText thread. The new archive of 21 August (here) fixes these problems and adds a new functionality, namely a check if any new text is on the clipboard - a handy function if, for example, you want to build a database of snippets copied from various websites.

Clip$, wClip$
      Print "[", Clip$(), "]"            ; displays the content of the clipboard
      MsgBox 0, Clip$(), "Text on the clipboard:", MB_OK      ; same as MessageBox
      MsgBox 0,\
      Cat$("The text on the clipboard:"+CrLf$+String$(33,"-")+CrLf$+Clip$(20)+CrLf$+String$(0,0)),\
      "MasmBasic:", MB_OK            ; displays a MessageBox with two horizontal delimiters
      
MsgBox 0, Clip$(40), "The text on the clipboard, truncated to 40 chars:", MB_OK
      invoke lstrcpy, offset my40charbuffer, Clip$(40-1)      ; yep, don't forget space for the zero delimiter
      .Repeat
            void Clip$(30)                        ; this loop waits for changes on the clipboard
            .if !Zero?
               PrintLine "New clipboard content=[", eax, "]"      ; non-zero means new valid content available
            .endif
            invoke Sleep, 1                     ; note: "new" is defined as (len(string)+first dword) different
      .Until signed rv(GetKeyState, VK_ESCAPE)<0
Rem   - returns ptr in eax,  to Null$ if clipboard is empty
   - you can truncate the content for security reasons, e.g. for use in a MessageBox
   - if no argument is specified, up to 160k will be copied into the internal buffer

The Unicode version is named wClip$():

Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; download
   Init
   wMsgBox 0, wCat$("Found on clipboard: ["+wClip$()+"]"), "This is Unicode:", MB_OK
   Exit
end start

jj2007

Some minor bugfixes and two new functions. Download version 23 September from top of thread.

ArrayMinMax
            Dim[/color] MyR4(9) As REAL4
            ArrayMinMax MyR4()         ; min in eax, max in edx - both as "pushable" REAL4
            push edx
            push eax
            
ffree st(7)
            
fld REAL4 ptr [esp]
            Print Str$("The Real Min=\t%Df\n", ST(0))
            pop edx
            ffree st(7)
            
fld REAL4 ptr [esp]
            Print Str$("The Real Max=\t %Df\n", ST(0))
            pop edx
            fstp st
            fstp st
            Dim
MyDw(9) As DWORD
            ArrayMinMax MyDw()         ; uses ArraySort syntax
            push edx
            Print Str$("The dw Min=\t%i\n", eax)
            pop edx
            Print Str$("The dw Max=\t %i\n", edx)
Rem            no return value

ArraySearch
            ; mov eax, ArraySearch(pSrc, sizeof Src, pattern [, size])      ; src, len(src), pattern, byte/word/dword
            Print Str$("Len %i\n", ArraySearch(esi, sizeof Src, 0, BYTE))      ; look for a nullbyte
            mov eax, dword ptr bins                     ; where bins is db "al", 0, 0
            Print Str$("Pos %i\n", ArraySearch(esi, sizeof Src, eax, WORD))   ; word given in eax
            Print Str$("Pos %i\n", ArraySearch(esi, sizeof Src, 6c61h, WORD))   ; immediate word
            Print Str$("Pos %i\n", ArraySearch(esi, sizeof Src, "al", WORD))   ; same but as string
            Print Str$("Pos %i\n", ArraySearch(esi, sizeof Src, MyPattern, word))   ; taken from mem, i.e. "al" is MyPattern dd "la"
            Print Str$("Pos %i\n", ArraySearch(esi, sizeof Src, "algo", DWORD))   ; dword as string
            Print Str$("Pos %i\n", ArraySearch(esi, sizeof Src, 'algo'))      ; same, dword assumed
            Print Str$("Pos %i\n", ArraySearch(esi, sizeof Src, "olgo", DWORD))   ; this one won't be found
Rem            - returns offset into first occurrence of pattern: if src is "This is my algo", then
              pattern algo as dword will not be found (eax=-1), but for "This was my algo", pos 12 would be returned
              pattern my as word will be found at pos 8
              pattern i as byte will be found at pos 2
            - ArraySearch uses SSE2 and is fast: it searches a 400 byte string more than four times
              as fast as repne scasd and 5 times as fast as BinSearch
            - by specifying zero as a byte pattern, you can use ArraySearch as a Len() substitute;
              however, MasmBasic Len() is twice as fast
            - do not confuse with Masm32 BinSearch, which finds patterns at "odd" positions, too, i.e.
              in the example above, invoke BinSearch, 0, chr$("This is my algo"), 16, chr$("al"), 3 would
              return a valid position 11
[/color]

jj2007

Here is a crispy little PureMasmTM example showing how to use the new functions:
- create a floating point array
- fill it with random numbers
- display them unsorted and sorted
- write them to disk
- read them back
- sort them

include \masm32\MasmBasic\MasmBasic.inc   ; library download
ShowProperties   PROTO: DWORD
ArrayWrite = 0   ; equates just for
ArrayRead = 1      
; the ease of reading

   Init
   [/color]mov ebx, 999   ; you may play with this number for speed tests

   Dim
MyR4w(ebx) As REAL4   ; this would work also for a DWORD array
   Dim MyR4r(ebx) As REAL4   ; create an array to hold the data from file

   ; ------- writing --------------
   
Rand()   ; create a seed using rdtsc
   For_ n=0 To ebx
      Rand(-33.33, 55.55)   ; push random numbers on the FPU stack
      
fstp MyR4w(n)   ; pop them to an array element
   Next
   Open "O", #1, "Real4.dat"   ; we create a file for output
   Store #1, MyR4w()   ; write them to file, unsorted
   Close
   
ArrayMinMax MyR4w()   ; get the minimum and maximum values
   push edx   ; save max to stack (edx is a REAL4)
   push eax   ; save min to stack (eax is a REAL4)
   
Print "Unsorted:"
   invoke ShowProperties, ArrayWrite   ; show the first and last items
   
ArraySort MyR4w()
   Print Str$("\n\nMin of the write array is %f\n", REAL4 PTR [esp])
   pop eax
   Print Str$("Max of the write array is %f\n", REAL4 PTR [esp])
   pop eax
   invoke ShowProperties, ArrayWrite   ; show the first and last items
   Erase MyR4w()

   ; ------- reading --------------
   Open "I", #2, "Real4.dat"   ; we open the file for input
   Recall #2, MyR4r()   ; read data into array
   Close
   
ArrayMinMax MyR4r()   ; calculate minimum and maximum
   push edx   ; save max to stack (edx is a REAL4)
   push eax   ; save min to stack (eax is a REAL4)
   
ArraySort MyR4r()
   Print Str$("\n\nMin of the read array is %f\n", REAL4 PTR [esp])
   pop eax
   Print Str$("Max of the read array is %f\n", REAL4 PTR [esp])
   pop eax
   invoke ShowProperties, ArrayRead   ; show the first and last items
   Inkey CrLf$, CrLf$, "bye"
   
Exit

ShowProperties proc ModeRead
  For_ ecx=0 To ebx                     ; ecx is safe to use if there are no Windows API calls
     lea eax, [ebx-3]
   .if ecx<3 || ecx>eax               ; show the first and last three items
      Print CrLf$, Str$(ecx), Tb$
      .if ModeRead
         Print Str$(MyR4r(ecx))    ; show the number read from file
      .else
         Print Str$(MyR4w(ecx))    ; show the numbers that will be written to file
      .endif
   .else
        mov eax, ebx
        sar eax, 1                     ; halfway...
        .if ecx==eax
         Print CrLf$, "..."            ; ... insert a separator
      .endif
   .endif
  Next

  ret
ShowProperties endp
end start


Sample output:
Unsorted:
0       26.34964
1       -16.69160
2       32.47115
...
997     51.35131
998     48.90986
999     -31.98609

Min of the write array is -33.18150
Max of the write array is 55.54166

0       -33.18150
1       -33.13496
2       -33.10025
...
997     55.31524
998     55.42580
999     55.54166

Min of the read array is -33.18150
Max of the read array is 55.54166

0       -33.18150
1       -33.13496
2       -33.10025
...
997     55.31524
998     55.42580
999     55.54166

juozas

Hi, Thanks for the update :D Works great. The editor works ok and compiles fine. But SkelMasmBasic example doesn't output all output as expected, I get this is:
QuoteThe command line: This
0 files found:
No.     Bytes   Name
#1      -1
The highlighted (bold) ones doesn't look all right to me, is this ok? It still doesn't look ok even i change compiler and linker to jwasm and polink. OS: WinXP Pro SP3 Fully Updated.

The versions of updated binaries I have are as shown below (I have backups of old ver. too):
ml.exe Version 6.15; poasm, polink, polib, porc Versions 6.00.*; rc.exe Version 6.1; wrc.exe Version 1.9

Also the editor hangs while trying to load another file (TestMasmBasic) from the menu or by draggin' in...

The zipped screenshot attached.
Сделано в СССР

jj2007

Hi juozas,
thanks for the feedback:

The command line: This
OPT_Arg1   This is a command line with many spaces

Try OPT_Arg1   "This is a command line with many spaces"

Quote0 files found:
No.     Bytes   Name
#1      -1
If you run GetFiles *.asm on an empty folder, that is what you get: 0 files found. Since a For loop is run at least once (in contrast to a While..Endw loop), the file size returns -1, i.e. an error.

Re the editor hangs: I have done many improvements "under the hood", and yes it hangs if you use the Open file dialog. You can "unhang" it, though, by clicking on a bookmark or by searching something. But that is indeed a fat ugly bug which will be fixed hopefully today :red

EDIT: the bug is fixed. New version on top of thread. Inter alia, Open File via the file menu and dragn' drop work fine now.

jj2007

The deb macro in version 30Sept2011 can now monitor changes to global variables (actually, to any variables including reg32).
The variable to watch is marked e.g. as deb 4, "Change for ...", chg:MyGlobalVar
Here is a demo using a marginally modified \masm32\examples\exampl02\mdidemo\mditest.asm (see attachment):

WndProc proc hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
    LOCAL var, caW, caH, hDC, tbH, sbH, mdihWnd
    LOCAL Rct:RECT
    LOCAL Ps:PAINTSTRUCT
    LOCAL tbab:TBADDBITMAP
    LOCAL tbb:TBBUTTON
    LOCAL cc:CLIENTCREATESTRUCT

    deb 4, "Top of WndProc", chg:hClient

Output to console:
Top of WndProc  chg:hClient     1116898
# uMsg #        WM_PARENTNOTIFY


... which is kind of surprising since hClient is being set in WM_CREATE.
To solve the mystery, we use three more "normal" deb calls as follows:

WndProc proc hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
    LOCAL var, caW, caH, hDC, tbH, sbH, mdihWnd
    LOCAL Rct:RECT
    LOCAL Ps:PAINTSTRUCT
    LOCAL tbab:TBADDBITMAP
    LOCAL tbb:TBBUTTON
    LOCAL cc:CLIENTCREATESTRUCT

    deb 4, "Top of WndProc", chg:hClient
    .if uMsg == WM_CREATE
        ...
        deb 4, "Before CwEx", hClient
        invoke CreateWindowEx,WS_EX_CLIENTEDGE,
                              ADDR mdiCl,NULL,
                              WS_CHILD or WS_CLIPCHILDREN or \
                              WS_VISIBLE or WS_VSCROLL or WS_HSCROLL,
                              0,0,0,0,hWin,NULL,hInstance,ADDR cc
        mov hClient, eax
        deb 4, "After CwEx", hClient

    .elseif uMsg == WM_PARENTNOTIFY
        deb 4, "ParentNoti", hClient

New output to console:
ParentNoti      hClient         0
ParentNoti      hClient         0
Before CwEx     hClient         0
ParentNoti      hClient         0
After CwEx      hClient         2034354
Top of WndProc  chg:hClient     2034354
# uMsg #        WM_PARENTNOTIFY

Now we see that indeed WndProc is being called during CreateWindowEx.

dedndave

several times   :P

the entire list represents all messages received by WndProc prior to execution of the message loop
i placed dummy messages into the list (handle=00000000) to mark entry and exit of WM_CREATE code
notice that, WM_CREATE returning to the OS seems to coincide with CreateWindowEx returning to the caller

http://www.masm32.com/board/index.php?topic=16633.msg138337#msg138337

that is only an example window that had 6 control windows (i think that's right)
the results will vary, of course, from program to program

jj2007

Yep, now I remember that thread :bg

Dave, there is a little trick to get your list of messages:

WndProc proc hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
    LOCAL whatever
    deb 4, "Top of WndProc", chg:msgCounter
    inc msgCounter      ; every message triggers a change...

Output:
Top of WndProc  chg:msgCounter  1
# uMsg #        WM_GETMINMAXINFO
Top of WndProc  chg:msgCounter  2
# uMsg #        WM_NCCREATE
Top of WndProc  chg:msgCounter  3
# uMsg #        WM_NCCALCSIZE
Top of WndProc  chg:msgCounter  4
# uMsg #        WM_CREATE
Top of WndProc  chg:msgCounter  5
# uMsg #        WM_NOTIFYFORMAT
Top of WndProc  chg:msgCounter  6
# uMsg #        WM_QUERYUISTATE
Top of WndProc  chg:msgCounter  7
# uMsg #        WM_PARENTNOTIFY
Top of WndProc  chg:msgCounter  8
# uMsg #        WM_NOTIFYFORMAT
Top of WndProc  chg:msgCounter  9
# uMsg #        WM_QUERYUISTATE
Top of WndProc  chg:msgCounter  10
# uMsg #        WM_PARENTNOTIFY