📄 macros.asm
字号:
comment * -----------------------------------------------------------------
Preprocessor code for high level language simulation in MASM32
Updated 4th November 2005
---------------------------------------------------------------- *
; *******************************************************************
; The following block of macros are macro functions that are designed
; to be called by other macros. In part they function as a library of
; components for writing other macros without having to repeatedly
; reproduce the same capacity. Effectively macro code reuse.
; *******************************************************************
; -----------------------------------------------------------
; This macro replaces quoted text with a DATA section OFFSET
; and returns it in ADDR "name" format. It is used by other
; macros that handle optional quoted text as a parameter.
; -----------------------------------------------------------
reparg MACRO arg
LOCAL nustr
quot SUBSTR <arg>,1,1
IFIDN quot,<"> ;; if 1st char = "
.data
nustr db arg,0 ;; write arg to .DATA section
.code
EXITM <ADDR nustr> ;; append name to ADDR operator
ELSE
EXITM <arg> ;; else return arg
ENDIF
ENDM
; -------------------------------------
; variation returns address in register
; so it can be assigned to a variable.
; -------------------------------------
repargv MACRO arg
LOCAL nustr
quot SUBSTR <arg>,1,1
IFIDN quot,<"> ;; if 1st char = "
.data
nustr db arg,0 ;; write arg to .DATA section
.code
mov eax, OFFSET nustr
EXITM <eax> ;; return data section offset in eax
ELSE
mov eax, arg
EXITM <eax> ;; else return arg
ENDIF
ENDM
; -----------------------------------------------------------
; replace a quoted string with its OFFSET in the data section
; -----------------------------------------------------------
repargof MACRO arg
LOCAL nustr
quot SUBSTR <arg>,1,1
IFIDN quot,<"> ;; if 1st char = "
.data
nustr db arg,0 ;; write arg to .DATA section
.code
EXITM <OFFSET nustr> ;; append name to OFFSET operator
ELSE
EXITM <arg> ;; else return arg
ENDIF
ENDM
; -------------------------------------------------------
; This is a parameter checking macro. It is used to test
; if a parameter in a macro is a quoted string when a
; quoted string should not be used as a parameter. If it
; is a user defined error message is displayed at
; assembly time so that the error can be fixed.
; -------------------------------------------------------
tstarg MACRO arg
quot SUBSTR <arg>,1,1
IFIDN quot,<"> ;; if 1st char = "
% echo arg ** QUOTED TEXT ERROR ** memory address expected
.ERR
ELSE
EXITM <arg> ;; else return arg
ENDIF
ENDM
; -----------------------------------------------
; count the number of arguments passed to a macro
; This is a slightly modified 1990 MASM 6.0 macro
; -----------------------------------------------
argcount MACRO args:VARARG
LOCAL cnt
cnt = 0
FOR item, <args>
cnt = cnt + 1
ENDM
EXITM %cnt ;; return as a number
ENDM
; ---------------------------------------------------
; return an arguments specified in "num" from a macro
; argument list or "-1" if the number is out of range
; ---------------------------------------------------
getarg MACRO num:REQ,args:VARARG
LOCAL cnt, txt
cnt = 0
FOR arg, <args>
cnt = cnt + 1
IF cnt EQ num
txt TEXTEQU <arg> ;; set "txt" to content of arg num
EXITM
ENDIF
ENDM
IFNDEF txt
txt TEXTEQU <-1> ;; return -1 if num out of range
ENDIF
EXITM txt
ENDM
; -------------------------
; determine an operand type
; -------------------------
op_type MACRO arg:REQ
LOCAL result
result = opattr(arg)
IF result eq 37 ;; label, either local or global
EXITM %1
ELSEIF result eq 42 ;; GLOBAL var
EXITM %2
ELSEIF result eq 98 ;; LOCAL var
EXITM %3
ELSEIF result eq 36 ;; immediate operand or constant
EXITM %4
ELSEIF result eq 48 ;; register
EXITM %5
ELSEIF result eq 805 ;; local procedure in code
EXITM %6
ELSEIF result eq 933 ;; external procedure or API call
EXITM %7
ENDIF
EXITM %0 ;; anything else
ENDM
; *************************************
; Return a register size in BYTES or *
; 0 if the argument is not a register *
; *************************************
regsize MACRO item
LOCAL rv,ln
rv = 0
ln SIZESTR <item>
IF ln EQ 2
goto two
ELSEIF ln EQ 3
goto three
ELSEIF ln EQ 4
goto four
ELSEIF ln EQ 5
goto five
ELSEIF ln EQ 6
goto six
ELSEIF ln EQ 8
goto eight
ELSE
goto notreg
ENDIF
:two
for arg,<al,ah,bl,bh,cl,ch,dl,dh>
IFIDNI <arg>,<item>
rv = 1
EXITM
ENDIF
ENDM
IF rv NE 0
EXITM %rv
ENDIF
for arg,<ax,bx,cx,dx,sp,bp,si,di>
IFIDNI <arg>,<item>
rv = 2
EXITM
ENDIF
ENDM
IF rv NE 0
EXITM %rv
ENDIF
goto notreg
:three
for arg,<eax,ebx,ecx,edx,esp,ebp,esi,edi>
IFIDNI <arg>,<item>
rv = 4
EXITM
ENDIF
ENDM
IF rv NE 0
EXITM %rv
ENDIF
for arg,<st0,st1,st2,st3,st4,st5,st6,st7>
IFIDNI <arg>,<item>
rv = 10
EXITM
ENDIF
ENDM
IF rv NE 0
EXITM %rv
ENDIF
for arg,<mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7>
IFIDNI <arg>,<item>
rv = 8
EXITM
ENDIF
ENDM
IF rv NE 0
EXITM %rv
ENDIF
goto notreg
:four
for arg,<xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7>
IFIDNI <arg>,<item>
rv = 16
EXITM
ENDIF
ENDM
IF rv NE 0
EXITM %rv
ENDIF
goto notreg
:five
for arg,<mm(0),mm(1),mm(2),mm(3),mm(4),mm(5),mm(6),mm(7)>
IFIDNI <arg>,<item>
rv = 8
EXITM
ENDIF
ENDM
IF rv NE 0
EXITM %rv
ENDIF
for arg,<st(0),st(1),st(2),st(3),st(4),st(5),st(6),st(7)>
IFIDNI <arg>,<item>
rv = 10
EXITM
ENDIF
ENDM
IF rv NE 0
EXITM %rv
ENDIF
goto notreg
:six
for arg,<xmm(0),xmm(1),xmm(2),xmm(3),xmm(4),xmm(5),xmm(6),xmm(7)>
IFIDNI <arg>,<item>
rv = 16
EXITM
ENDIF
ENDM
IF rv NE 0
EXITM %rv
ENDIF
:eight
for arg,<edx::eax,ecx::ebx>
IFIDNI <arg>,<item>
rv = 8
EXITM
ENDIF
ENDM
IF rv NE 0
EXITM %rv
ENDIF
:notreg
EXITM %rv
ENDM
;---------------------------------------------------
issize MACRO var:req, bytes:req
LOCAL rv
rv = regsize(var)
IFE rv ; if not a register use SIZE
IF SIZE var EQ bytes
EXITM <1>
ELSE
EXITM <0>
ENDIF
ELSE ; it's a register
IF rv EQ bytes
EXITM <1>
ELSE
EXITM <0>
ENDIF
ENDIF
ENDM
; ----------------------------------------------
isregister MACRO var:req
IF regsize(var)
EXITM <1>
ELSE
EXITM <0>
ENDIF
ENDM
; -----------------------------------------------------
; "catargs" takes 3 arguments.
; 1. the NAME of the calling macro for error reporting
; 2. the ADDRESS of the memory allocated for the text
; 3. the ARGUMENTLIST of strings passed to the caller
; -----------------------------------------------------
catargs MACRO mname,mem,args:VARARG
LOCAL lcnt,var ;; LOCAL loop counter
lcnt = argcount(args) ;; get the VARARG argument count
REPEAT lcnt
var equ repargof(getarg(lcnt,args))
;; -------------------------------------------------
;; if argument is a register, display error and stop
;; -------------------------------------------------
IF op_type(repargof(getarg(lcnt,args))) EQ 4
echo -------------------------------------------
% echo Argument num2str(lcnt) INVALID OPERAND in mname
echo ERROR Register or register return
echo value not allowed in this context
echo Valid options must be memory operands.
echo They can occur in the following forms,
echo * 1. quoted text
echo * 2. zero terminated string address
echo * 3. macro that returns an OFFSET
echo * 4. built in character operators
echo -------------------------------------------
.err
ENDIF
IFIDN var,<lb> ;; ( notation
IFNDEF @left_bracket@
.data
@left_bracket@ db "(",0
.code
ENDIF
push OFFSET @left_bracket@
goto overit
ENDIF
IFIDN var,<rb> ;; ) notation
IFNDEF @right_bracket@
.data
@right_bracket@ db ")",0
.code
ENDIF
push OFFSET @right_bracket@
goto overit
ENDIF
IFIDN var,<la> ;; < notation
IFNDEF @left_angle@
.data
@left_angle@ db "<",0
.code
ENDIF
push OFFSET @left_angle@
goto overit
ENDIF
IFIDN var,<ra> ;; > notation
IFNDEF @right_angle@
.data
@right_angle@ db ">",0
.code
ENDIF
push OFFSET @right_angle@
goto overit
ENDIF
IFIDN var,<q> ;; quote notation
IFNDEF @quote@
.data
@quote@ db 34,0
.code
ENDIF
push OFFSET @quote@
goto overit
ENDIF
IFIDN var,<n> ;; newline notation
IFNDEF @nln@
.data
@nln@ db 13,10,0
.code
ENDIF
push OFFSET @nln@
goto overit
ENDIF
IFIDN var,<t> ;; tab notation
IFNDEF @tab@
.data
@tab@ db 9,0
.code
endif
push offset @tab@
goto overit
ENDIF
push var ;; push current argument
:overit
lcnt = lcnt - 1
ENDM
push mem ;; push the buffer address
push argcount(args) ;; push the argument count
call szMultiCat ;; call the C calling procedure
add esp, argcount(args)*4+8 ;; correct the stack
ENDM
; ******************************************************
; num2str feeds a numeric macro value through a seperate
; macro to force a text return value. It is useful for
; displaying loop based debugging info and for display
; purposes with error reporting.
; NOTE :
; prefix the "echo" to display this result with "%"
; EXAMPLE :
; % echo num2str(arg)
; ******************************************************
num2str MACRO arg
EXITM % arg
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -