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

HSE

Equations in Assembly: SmplMath

jj2007

include \masm32\include\masm32rt.inc
.code
start:
  mov ebx, rv(GetProcessHeap)
  invoke HeapAlloc, ebx, 0, 33
  xchg eax, esi
  mov byte ptr [esi+33], "x"   ; oops!
  invoke HeapValidate, ebx, 0, 0
  print LastError$()
  invoke HeapFree, ebx, 0, esi
  print LastError$()
  exit
end start


So far, so clear: 33 bytes allocated, 33 bytes used (or was it 34 with esi+33? anybody good at math?  ;))
And, as we all expect, LastError$ is 2 x "The operation completed successfully."

However, if you build this snippet with RichMasm, you'll get a different message:
## HEAP[DebugHeapTestMasm32.exe]:
## Heap block at 00583F08 modified at 00583F31 past requested size of 21
The operation completed successfully.

## HEAP[DebugHeapTestMasm32.exe]:
## Heap block at 00583F08 modified at 00583F31 past requested size of 21

## HEAP[DebugHeapTestMasm32.exe]:
## Invalid address specified to RtlFreeHeap( 00580000, 00583F10 )
The operation completed successfully.

** DebugHeap found errors **


From version 1 March 2016 onwards, RichMasm will debug console mode applications (and this includes Gui apps built with subsys console, so that's how you can test windows applications).

This feature can be suppressed by inserting OPT_NoDebug somewhere in the code (same for OPT_Wait 0, i.e. don't wait for a keypress). It will also not be used if RichMasm finds an int 3 somewhere in the source, as this will invoke Olly instead.

My tests with timing code from The Laboratory showed no performance differences to non-debugged code.

jj2007

Version 3 March 2016:
- DebugHeap now handles the infamous SHBrowseForFolder exception
- If Structured Exception Handling is being used, DebugHeap is off; this was a problem for the SEH example in MbSnippets.asc (the file you see in the middle of the MbGuide welcome screen as "try 90+ snippets")
- Also, when scrolling through the code examples in MbSnippets.asc, the "Init" listbox does no longer lose the focus when you hit F6

jj2007

Recent versions of MasmBasic returned wrong results for the case-insensitive version of StringsDiffer(), with consequences for QSort().
Please reinstall.

The good news is that the new version works correctly, is 40% shorter and 30% faster :biggrin:

jj2007

Version 12 March has a new feature - sorting by a column's value:

Quote; spreadsheet mode - you can sort tab-delimited files by column:
      Recall "MyDataBase.tab", db$(), tab            ; tab = tell Recall it's a tab-delimited file, Excel style
      xchg eax, ecx            ; keep #rows read in ecx
      QSort db$(), 0, [, 0]            ; sort db$(), all rows, by column 3; [optional 0: do not skip the header row]
      QSort db$(), 0, 2003h            ; same but 2000h added: sort using Val() of column 3

This snippet sorts Windows.inc by the value of its equates, regardless if they are expressed as hex or decimal (see e.g. VT_ILLEGAL in the output below):

include \masm32\MasmBasic\MasmBasic.inc      ; download
  Init
  Recall "\Masm32\include\Windows.inc", L$(), tab      ; load file to two-dimensional string array
  QSortMode cis, sls      ; case-insensitive, skip leading spaces
  QSort L$()            ; pre-sort alphabetically
  For_ ecx=0 To eax-1
      .if Instr_(L$(ecx), "equ", 5)      ; 5: 4=full word, 1=case-insensitive
            .Repeat
                  inc eax
                  mov dl, [eax]
            .Until !dl || dl>="0" && dl<="9"      ; e.g. SOMECONSTANT equ <123h>
            .if dl
                  mov byte ptr [eax-1], 9      ; insert a tab to separate string from numerical column
            .endif
      .endif
  Next

  QSort L$(), 0, 2001h, 0      ; sort all rows, 2000h to force MovVal() sort, column 1, 0=don't skip header row
  Store "MyFile.txt", L$()      ; save to file
  Print Str$("%i lines stored, now launching text viewer", L$(?))
  ShEx "MyFile.txt"      ; have a look - search for IMAGE_ORDINAL_FLAG64
EndOfCode


Output:
MAXLONGLONG                      equ 7fffffffffffffffh
CLR_NONE         equ 0FFFFFFFFh
ColorsWhite                 EQU 0FFFFFFFFh
FLS_OUT_OF_INDEXES               equ 0FFFFFFFFh
HOVER_DEFAULT   equ 0FFFFFFFFh
INADDR_BROADCAST          equ      0FFFFFFFFh
INADDR_NONE          equ            0FFFFFFFFh
...
VT_ILLEGAL          equ 0ffffh
Yellow                               equ 00FFFFh
UNICODE_STRING_MAX_BYTES         equ 065534
MCI_SEQ_NONE                         equ 65533
WCH_EMBEDDING                    equ 0FFFCh
Green                                equ 00FF00h
...
WS_EX_RIGHTSCROLLBAR                 equ 00000000h
WS_OVERLAPPED                        equ 0h
WSA_WAIT_EVENT_0                 equ ((DWORD 0)
WT_EXECUTEDEFAULT equ 00000000h                           
X3_BTYPE_QP_INST_VAL_POS_X       equ 0
X3_D_WH_SIGN_VAL_POS_X           equ 0
X3_EMPTY_INST_VAL_POS_X          equ 0
X3_IMM20_SIGN_VAL_POS_X          equ 0
...
IMAGE_ORDINAL_FLAG64             equ 8000000000000000h


Since MasmBasic's string sort is stable, the "pre-sort" after Recall() provides alphabetical order for identical values, e.g. for CLR_NONE ... INADDR_NONE in the example above. The numerical sort is not overwhelmingly fast, due to the complexity of Val(), but sorting one Million lines in three seconds looks acceptable IMHO.

Full code attached. Note that in 21 lines you cannot handle the more complex equates 8)

jj2007

include \masm32\MasmBasic\MasmBasic.inc
  SetGlobals someinteger=5      ; for testing a case with a variable
  Init                          ; ## fast switch with jump table ##
  PrintLine "---------------- testing MasmBasic Switch_ ----------------"
  For_ ct=-3 To 20
      m2m ecx, 3
      Print Str$(ct), Tb$

      Switch_ ct
      Case_ -2
            PrintLine "Case -2"
      Case_ 0
            PrintLine "Case NULL"
      Case_ 8, 10, 12, ecx
            PrintLine "Case 8, 10, 12 or ecx"             ; ecx is set to 3
      Case_ someinteger
            PrintLine Str$("Case int var=%i", someinteger) ; case is a variable (or register)
      Case_ 19 : PrintLine "Case 19 (one line)" ; one-liner if only one instruction is needed
      Case_ 15 .. 17
            PrintLine "Case 15 .. 17"
      Default_
            PrintLine "..."
      Endsw_
  Next
EndOfCode


Output:
---------------- testing MasmBasic Switch_ ----------------
-3      ...
-2      Case -2
-1      ...
0       Case NULL
1       ...
2       ...
3       Case 8, 10, 12 or ecx
4       ...
5       Case int var=5
6       ...
7       ...
8       Case 8, 10, 12 or ecx
9       ...
10      Case 8, 10, 12 or ecx
11      ...
12      Case 8, 10, 12 or ecx
13      ...
14      ...
15      Case 15 .. 17
16      Case 15 .. 17
17      Case 15 .. 17
18      ...
19      Case 19 (one line)
20      ...


Requires MasmBasic of 28 April 2016, available here. During installation, click on try 90+ snippets to see more examples.

The new Switch_ macro works with Microsoft MASM versions 6.15 ... 10.0 (11 not tested, grateful if somebody can do that...), JWasm, HJWasm and AsmC.

With the exception of the colon-separated one liner, Switch_ is perfectly compatible with the standard Masm32 switch macro. Under the hood, however, it creates a jump table, which makes it faster and shorter.

HSE

Very nice JJ!

Give me a couple of years to study the macros :biggrin:

At first read it's unexpected that I obtain:

### line 343: case 19 : PrintLine "Case 19 (one line)",13,10 already defined ###


when I was expecting nothing or:
     < not possible, use separate line ##>


This is my PrintLine:PrintLine MACRO args:VARARG
  ifb <args>
print
  else
print args, 13,10
  endif
ENDM
Equations in Assembly: SmplMath

jj2007

Interesting... you should get "already defined" when a Case_ is already defined, e.g. you have 2x Case 123 (which wouldn't make sense, therefore the forced error).

Would you mind post a complete little example? Thanks.

HSE

Apparently the problem is that the comma of the arguments are interpreted like a multiple case (case_ 10 already exist). 

Case_ 19 : PrintLine "Case 19 (one line)",13,10

With Case_ 19 : PrintLine "Case 19 (one line)",13 ; A Case_ 13 is constructed (see the .exe)

Work perfect with only one argument (and no comma) Case_ 19 : PrintLine "Case 19 (one line)"
Equations in Assembly: SmplMath

jj2007

It also works if you move it to the next line as shown below, but anyway, this is a very odd problem. Thanks for flagging this, HSE :icon14:

      Case_ 19
            PrintLine "Case 19 (one line)", 13, 10 ; one-liner if only one instruction is needed

nidud

#325
Post deleted per PM request

jj2007

*** archive 28 April was temporarily removed - under certain conditions, the Switch_ macro would unbalance the stack ***

But it's fixed now - please reinstall. Sorry for the inconvenience, and thanks again to HSE for informing me about the problem.


jj2007

Please install MB version 6 May 2016:
Inspired by point #2 of a blog post on the merits of Visual Basic, the Switch_ macro can now handle lt and gt:

include \masm32\MasmBasic\MasmBasic.inc      ; download
  Init
  PrintLine cfm$("years\tclassification")       ; see #2, VB Case a<b
  For_ ecx=6 To 34 Step 2
      Print Str$(ecx), Tb$

      Switch_ ecx
      Case_ lt 10 :      PrintLine "child"
      Case_ lt 19
            Print "teenie, "

            Switch_ ecx
            Case_ 10..13:      PrintLine "10..13"
            Case_ 14:          PrintLine "14"
            Case_ gt 14:       PrintLine "over 14"
            Endsw_

      Case_ gt 32 :            PrintLine "very old"
      Case_ gt 29, 29 :        PrintLine "old"
      Case_ 24, 26 :           PrintLine "the ideal age"
      Default_
            PrintLine "twen"
      Endsw_
  Next
EndOfCode


Output:
years   classification
6       child
8       child
10      teenie, 10..13
12      teenie, 10..13
14      teenie, 14
16      teenie, over 14
18      teenie, over 14
20      twen
22      twen
24      the ideal age
26      the ideal age
28      twen
30      old
32      old
34      very old


Source attached, tested with ML 6.15 and 10.0, JWasm, HJWasm and AsmC.

jj2007

MasmBasic version 14 May 2016 has two new features:

1. For each x$ in My$():
See demo here. Works with arrays of strings, integers, real numbers and structures (created e.g. with Dim myrc() As RECT)

2. Val("12, 45, 67", pos):
Imagine you have a line of settings in some ini file, and you want to know the value of the sixth entry... cumbersome, right?

include \masm32\MasmBasic\MasmBasic.inc      ; download
  SetGlobals settings$="0, 0, 1366, 768, 3, 123, 456, 789"
  Init
  Inkey Str$("The value of the 6th number is %i", Val(settings$, 6))
EndOfCode

Output:
The value of the 6th number is 123

jj2007

Following this thread about the Rich Edit control, and unexpected error messages in Windows 10, RichMasm got a minor revision of the way it loads RichEd20.dll

Please reinstall. The new function is available to MasmBasic users as invoke MbLoadRich. A simple window (<50 lines) with a Rich Edit control is attached; check the WM_CREATE handler, as shown below. In a nutshell: If you have MS Office or the free Word Viewer installed, loading a fat RTF file will be a factor 30-50 faster.

WndProc proc uses esi edi ebx hWnd, uMsg, wParam:WPARAM, lParam:LPARAM
  SWITCH uMsg
  CASE WM_CREATE
      ; picks the best RichEd20.dll available, or, if available, the one in the current folder:
      invoke MbLoadRich
      invoke CreateWindowEx, WS_EX_CLIENTEDGE, chr$("RichEdit20A"), NULL,
        WS_CHILD or WS_VISIBLE or WS_BORDER or WS_VSCROLL or ES_MULTILINE,
        9, 9, 570, 352, hWnd, 103, wcx.hInstance, NULL
ExternDef RichEditUsed:DWORD ; optional: check which version was installed
xchg eax, ecx
SetWin$ ecx=Cat$("This control was created using "+CrLf$+RichEditUsed)