; aoaMacros.inc ; ; Various macros used by examples in ; The Art of Assembly Language (Volumes 1 and 2). ifndef aoaMacros_inc aoaMacros_inc = 0 ; Some useful character sets for use with instr function ; Note: best to copy/paste these rather than use the symbols. ;cs20_2f textequ < !!!"#$%&!'()*+,-./> ;cs30_3f textequ <0123456789:;!<=!>?> ;cs40_4f textequ <@ABCDEFGHIJKLMNO> ;cs50_5f textequ ;cs60_6f textequ <`abcdefghijklmno> ;cs70_7e textequ ; ;cs_decimal textequ <0123456789> ;cs_hex textequ <0123456789ABCDEFabcdef> ;cs_upper textequ ;cs_lower textequ ;cs_alpha textequ ;cs_ID textequ <0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_> ; ;cs_notAlpha textequ < !!!"#$%&!'()*+,-./0123456789:!<=!>?@[\]^_`{|}~> ;cs_notAlNum textequ < !!!"#$%&!'()*+,-./:!<=!>?@[\]^_`{|}~> ;cs_notID textequ < !!!"#$%&!'()*+,-./:!<=!>?@[\]^`{|}~> ;cs_notDec textequ < !!!"#$%&!'()*+,-./:!<=!>?@[\]^_`{|}~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz> ;cs_notHex textequ < !!!"#$%&!'()*+,-./:!<=!>?@[\]^_`{|}~GHIJKLMNOPQRSTUVWXYZghijklmnopqrstuvwxyz> ;----------------------------------------------------- ; ; bsEscape- ; ; Backslash Escape processing. ; ; Handles the following escape sequences: ; ; \| becomes ! ; \{ becomes ( ; \} becomes ) ; \[ becomes < ; \] becomes > ; ; \x (x any other character) becomes \x ; so the resulting text value can be ; further processed by a different ; escape processing macro. bsEscape macro arg local result,ndx,chr,len ; Get the length of the argument string ; and process the characters in the string ; from position 1 to length: len sizestr <&arg> result textequ <> ndx = 1 while ndx le len ; Extract the current character (1..len) ; from the string: chr substr <&arg>, ndx, 1 ;; Check for a "\" escape sequence: ifidn chr,<\> ;; Get the next char after the "\" ndx = ndx + 1 chr substr <&arg>, ndx, 1 ;; Check for \| and translate to "!" ifidn chr, <|> result catstr result, else ;;dif <&arg>, <|> ;; Check for \{ and translate it to "(" ifidn chr, <{> result catstr result, <(> else ;;dif <&arg>, <{> ;; Check for \} and translate it to ")" ifidn chr, <}> result catstr result, <)> else ;;dif <&arg>, <}> ;; Check for \[ and translate it to ">" ifidn chr, <[> result catstr result, else ;;dif <&arg>, <[> ;; Check for \] and translate it to ">" ifidn chr, <]> result catstr result, > else ;;dif <&arg>, <]> ;; Backslash in front of an arbitrary ;; character, return "x" (where x is the ;; character). Note that this handles "\\": result catstr result, chr endif ;;<&arg>, <]> endif ;;<&arg>, <[> endif ;;<&arg>, <}> endif ;;<&arg>, <{> endif ;;<&arg>, <|> else ;;dif <&>,<\> ;; If an unescaped character, append ;; it to the result: result catstr result, chr endif ;;<&arg>, <\> ndx = ndx + 1 endm ;; while loop exitm result endm ;; bsEscape ;------------------------------------------------ ; ; Macro for creating namespaces. ; ; Typical use: ; ; NSname macro arg ; namespace (&arg, , ) ; namespace (&arg, , ) ; . ; . ; . ; namespace (&arg, , ) ; endm ;;NSname ; ;NSname1 macro ; << macro body to handle name1 >> ; endm ; ;NSname2 macro ; << macro body to handle name2 >> ; endm ; . ; . ; . ;NSnamen macro ; << macro body to handle namen >> ; endm ; ; This allow invocations such as: ; ; ; NSname(name1) ;For procedures and ; NSname(name2) ; macros. ; -or- ; mov rax, NSname(namen) ;For variables namespace macro arg, subname, fullname ifidn <&arg>,<&subname> exitm > endif endm ;------------------------------------------------ ; ; aoa namespace: ; ; Namespace declarations for various aoa macros: aoa macro func namespace (&func, , ) namespace (&func, , ) namespace (&func, , ) namespace (&func, , ) namespace (&func, , ) namespace (&func, , ) namespace (&func, , ) echo ***************************** echo Error:unexpected aoa member % echo function=func echo ***************************** exitm <.err> endm ;------------------------------------------------ ; ; mout- ; ; Replacement for echo. Allows "%" operator ; in operand field to expand text symbols. ; ; e.g., aoa_mout value=%value ; ; aoa namespace invocation: ; ; aoa(mout) expression_to_print aoa_mout macro valToPrint:vararg local cmd cmd catstr <%echo >, <&valToPrint> cmd endm ;------------------------------------------------ ; ; isStr is a macro function that tests its ; operand to see if it is a string literal. aoa_isStr macro strParm local firstChar, lastChar, len local isQuote len sizestr strParm if len ne 0 ;; See if the first and last characters are both ;; the same and either an apostrophe or quote: firstChar substr , 1, 1 lastChar substr , len, 1 ifdif firstChar,lastChar exitm <0> endif isQuote instr 1, <"'>, firstChar if isQuote eq 0 exitm <0> endif ;; First and last characters were apostrophes ;; or quotes, so assume it's a string. exitm <1> endif ;; Empty string: exitm <0> endm ;------------------------------------------------------- ; ; trimWS macro- ; ; Trims white space from the end of a text value. aoa_trimWS macro txt local szTxt, lastChar, trimmed trimmed textequ <&txt> szTxt sizestr trimmed while szTxt gt 0 lastChar substr txt, szTxt, 1 ifidn lastChar, < > trimmed substr trimmed, 1, szTxt-1 else exitm trimmed endif szTxt sizestr trimmed endm exitm trimmed endm ;------------------------------------------------------- ; ; delWS macro- ; ; Trims white space from the beginning of a text value. aoa_delWS macro txt local szTxt, firstChar, trimmed trimmed textequ <&txt> szTxt sizestr trimmed while szTxt gt 0 ;Stop on empty str firstChar substr trimmed, 1, 1 ;Get 1st char ifidn firstChar, < > ;Is it blank? if szTxt gt 1 ;Must handle trimmed substr trimmed, 2 ; single char else ; as a special exitm <> ; case and return endif ; empty string. else ;Not blank char, exitm trimmed ; so return whole endif ; string. szTxt sizestr trimmed endm ; If length hits zero, return the empty string. exitm trimmed endm ;------------------------------------------------------- ; ; The following macros are not part of the aoa namespace ; because they do weird things when expanded by the aoa ; macro. ; ; expand is a little "helper" macro that expands ; the text in the identifier passed to it and ; returns that text as the macro result. expand macro arg local expand_txt expand_txt textequ <&arg> exitm expand_txt endm ; Another variant. Expansion occurs ; on macro invocation rather than in ; the macro itself. expand2 macro symbol exitm symbol endm ; mkID is a simple macro that concatenates ; its two (text) operands and creates an ; identifier from them without expanding ; that id (if it was already a text equate). ; Useful for redefining synthesized text ; equate symbols. mkID macro a, b exitm <&a&&b&> endm ;------------------------------------------------------- ; ; Compile-time push, pop, and peek macros. ; The aoa_push macro requires two arguments: ; a stack object and a value to push. ; Initially, the stack object should be assigned ; the value 0, as follow: ; ; someStk = 0 ; ; This macro will automatically create text constants ; names taking the form: "stkName_n" where "stkName" ; is the name of the stack variable (e.g., "someStk") ; and "n" is the current stack element (e.g., "0" ; through the current depth of the stack). For ; example, if you push two items onto the stack, ; the _push macro will set the stack variable to ; the value "2" and create the following two ; text constants: ; ; stkName_0 textequ <1st value pushed> ; stkName_1 textequ <2nd value pushed> ; ; The important thing to keep in mind is that you ; must not use names of the form "stkName_n" (where ; stkName is some stack identifer and "n" is a decimal ; value) in your programs as this may create ; duplicate symbol errors in your code. aoa_push macro theStack, theValue local suffix ;; Convert the stack variable's value to ;; text string we can append to the stack ;; variable's name to create the name of ;; current stack element: suffix textequ %theStack identifier catstr <&theStack>, <_>, suffix ;; Take the identifier just created and ;; assign the pushed value to it; this, effectively, ;; pushes the item onto the stack into the ;; stack position specified by theStack variable. expand(identifier) textequ <&theValue> ;; Bump up the stack pointer so the next ;; push operation will store its value in ;; the next greater stack element: theStack = theStack+1 exitm <> endm ; aoa_pop macro- ; ; "theStack" is a global numeric variable ; whose value is the current size of the ; stack. Fetch the item at element(theStack-1) ; and return this as the function result. Also, ; decrement the stack pointer. aoa_pop macro theStack local suffix, identifier ;; First, check for an empty stack: if theStack le 0 echo Attempt to pop an empty stack! .err exitm <> endif ;; Generate an identifier that corresponds to ;; element "suffix" in the stack array: suffix textequ %(theStack-1) identifier catstr <&theStack>, <_>, suffix ; Return the popped text as part of a "textequ" ; directive. exitm > endm ; aoa_peek macro- ; ; "theStack" is a global numeric variable ; whose value is the current size of the ; stack. Fetch the item at element(theStack-1) ; and return this as the function result. aoa_peek macro theStack local suffix, identifier ;; First, check for an empty stack: if theStack le 0 echo Attempt to pop an empty stack! .err exitm <> endif ;; Generate an identifier that corresponds to ;; element "suffix" in the stack array: suffix textequ %(theStack-1) identifier catstr <&theStack>, <_>, suffix ; Return the popped text as part of a "textequ" ; directive. exitm > endm ;----------------------------------------------------- ; ; @defined- Macro function that returns true if the ; symbol is defined, false otherwise. ; ; This function actually has to jump through a bunch ; of hoops to work properly. Just using "ifdef &id&" ; doesn't work because "id" is always defined (it's ; the @defined parameter). This macro simulates ; "ifdef" by using the opattr operator. This leaves ; bit 5 set if there are no undefined symbols in the ; associated expression (conversely, it returns 0 ; if there are undefined symbols in the expression). @defined macro id local result, ifstmt result = (((opattr &id&) and 20h) ne 0) and 1 exitm %result endm endif ;aoaMacros_inc