What is asmc if I may ask?
Asmc is basically a modified version of JWasm made in 2011. It was used as a TASM clone to maintain some DOS tools at the time.https://github.com/nidud/asmc/blob/master/source/dos/tasm/tasm.asm
I later added some enhancement to the HLL section and a few other things, so I have been playing with it for some time. However the features added so far seems stable so in that sense the playtime has come to a conclusion in a somewhat usable product.
Some more info from the help file:Asmc Macro Assembler Reference
This lists some of the differences between Asmc, JWasm, and Masm.Asmc Extensions
The main goal with Asmc is an attempt to provide more readability to the assembly language based on Masm syntax but at the same time keep compatibility with existing source code. In order to achieve this some of the main core of the assembler has to be rewritten and the HLL section enhanced as discussed below.Parsing of labels
All expansions are pre-processed by the assembler and this may expand macros and other directives before labels. If a macro is added at the same line as a label this may fail.
foo macro reg
do: mov eax,foo( eax )
As a result the code produced by the macro will be expanded above the label and thus the jump will fail.
do: mov eax,ecx
Asmc will expand the line left to right in this case.Expansion of macros
The label issue becomes a problem in the HLL section where labels are created later: .WHILE macro(...)
Asmc will for this reason delay expansion of macros in some of the HLL directives until labels are created. This include .WHILE, .ELSEIF, and .CASE.The invoke directive
In Asmc a macro is handled at the same level as a procedure. The header file may then control the expansion:
strlen macro string
strlen proto :dword
This is achieved by simply excluding invoke as appose to allow invocations of macros.
strlen( esi )
Asmc sees the combination of a procedure followed by an open bracket as invoke. Empty brackets will be given special handling if the token in front is not a macro.
This simple solution avoids breaking any existing code with a few exceptions: Masm allows brackets to access memory
. .if edx < foo( 1 )
; MASM: cmp edx,foo+1
; ASMC: invoke foo, 1 : cmp edx,eax
So square brackets should be used for accessing memory
and round brackets to execute. However, an error must then be issued if Asmc extensions are turned off and labels are accessed using round brackets to ensure compatibility.
The inside of brackets may be recursive used at any length including C-strings. However, the return code for a procedure is [R|E]AX so there is a limit with regards to OR/AND testing of nested functions.
.if foo( bar( 1 ), 2 ) == TRUEHandling of strings
Given "quoted strings" may be used as arguments, or in general as a const value, C-strings are limited to be used inside brackets of a procedure.
.if fopen( "readme.txt", "rt" )
Macro function that creates a string in the .DATA segment. The macro accepts C-escape characters in the string. Strings are added to a stack and reused if duplicated strings are found. The macro returns offset string.
mov eax,@CStr( "\tCreate a \"C\" string: %s%d\n" )
mov ebx,@CStr( "string: %s%d\n" )
mov ecx,@CStr( "%s%d\n" )
mov edx,@CStr( "%d\n" )
mov edi,@CStr( "\n" )
DS0000 db 9,"Create a ",'"',"C",'"'," string: %s%d",10,0
mov eax,offset DS0000
mov ebx,offset DS0000
mov ecx,offset DS0000
mov edx,offset DS0000
mov edi,offset DS0000
The system date in the format yyyy-mm-dd
The switch comes in three main variants: a structured switch, as in Pascal, which takes exactly one branch, an unstructured switch, as in C, which functions as a type of goto, and a control table switch with the added possibility of testing for combinations of input values, using boolean style AND/OR conditions, and potentially calling subroutines instead of just a single set of values.
The control table switch is declared with no arguments and each .CASE directive does all the testing.
.case strchr( esi, '<' )
.case strchr( esi, '>' )
The unstructured switch works as a regular C switch where each .CASE directive is just a label.
.case 0: .repeat : movsb
.case 7: movsb
.case 6: movsb
.case 5: movsb
.case 4: movsb
.case 3: movsb
.case 2: movsb
.case 1: movsb : .untilcxz
The structured switch works as a regular Pascal switch where each .CASE directive is a closed branch.
.case 1: printf("Gold medal")
.case 2: printf("Silver medal")
.case 3: printf("Bronze medal")
printf("Better luck next time")
Case opens a case statement. The case statement compares the value of an ordinal expression to each selector, which can be a constant, a subrange, or a list of them separated by commas.
The selector field is separated from action field by Colon or a new line.
.CASE 1: mov ax,2 : .ENDC
In the control table switch .CASE is equal to .IF:
.CASE ax <= 2 && !bx
.ENDC closes a .CASE statement.
The name was separated from BREAK to have more flexibility with regards to control flow of loops. However, ENDC have the same qualities as BREAK and thus can be used in combination with .IF:
.ENDC .IF al == 2.DEFAULT
.DEFAULT executes when none of the other cases match the control expression..ENDSW
.ENDSW closes a .SWITCH statement.