home *** CD-ROM | disk | FTP | other *** search
- .xlist
-
- ;------------------------------------------------------------------------
- ;This file contains macros for use with Microsoft's MASM v4.00.
- ;
- ;Written by John Friend
- ;Compuserve ID, 73317,2204
- ;Released to the public domain on November 18, 1986 for any use or purpose.
- ;
- ;Syntax for using these macros is as follows:
- ;
- ;IF STATEMENT:
- ;-------------
- ;
- ;_IF <param1> condition <param2>
- ;
- ; <your code for if the condition is satisfied>
- ;
- ;_ENDIF
- ;
- ;
- ;IF THEN ELSE STATEMENT:
- ;-----------------------
- ;
- ;_IFELSE <param1> condition <param2>
- ;
- ; <your code for if the condition is satisfied>
- ;
- ;_ELSE
- ;
- ; <your code for if the condition is not satisfied>
- ;
- ;_ENDIF
- ;
- ;
- ;WHILE STATEMENT:
- ;----------------
- ;
- ;_WHILE <param1> condition <param2>
- ;
- ; <your code for if the condition is satisfied>
- ;
- ;_ENDWHILE
- ;
- ;
- ;
- ;FOR STATEMENT:
- ;--------------
- ;
- ;_FOR <param1> eq <startvalue> to <endvalue> step <stepvalue>
- ;
- ; <your code for the for loop>
- ;
- ;_ENDFOR
- ;
- ;
- ;The macros allow you to create IF, WHILE, and FOR statements in
- ;assembly language. They work on the principle that any one of the
- ;above statements can be generated with a combination of cmp and jump
- ;instructions.
- ;
- ;There are a number of tricks used to get these macros to work:
- ;
- ;1) A way to generate the appropriate labels is needed. Each label has
- ; to be unique in order to not get assembler conflicts. This is done
- ; by keeping a counter of what label number we are on (varcntr) and
- ; the next time we need a label, we convert varcntr to ascii and insert
- ; it in the label string. Since varcntr is incremented each time we
- ; create a new label, we never get two identical labels.
- ;
- ;2) IF, WHILE, and FOR statements can be simulated with the inverse
- ; comparison from what is found in the statement declaration. For example,
- ; the statement:
- ;
- ; IF (ax > 0) then
- ; begin
- ; <body of code>
- ; end
- ;
- ; This statement can be simulated with the inverse comparison and a jump
- ; as follows:
- ;
- ; If (ax <= 0) then jump around <body of code>
- ; <body of code>
- ;
- ; In assembly language:
- ;
- ; cmp ax,0
- ; jbe SKIP_BODY_OF_CODE
- ; <body of code>
- ;SKIP_BODY_OF_CODE:
- ;
- ; The trick is how to generate the inverse comparison in an assembly macro.
- ; This is done by comparing the comparison string to a number of pre-defined
- ; ones using the IFIDN macro command and then substituting the inverse one.
- ; See the macro OPP_JMP.
- ;
- ;3) We want to be able to nest the statements. In order to do this we need
- ; some kind of a stack where we can push a label name each time we create
- ; an IF statement and pop the label name each time an ENDIF is
- ; encountered. This is done using the NAMEPUSH and NAMEPOP.
- ;
- ;
- ;LIMITATIONS:
- ;
- ;1) Bodies of code between an _IF statement and an _ENDIF are limited to
- ; 128 bytes because short jumps are used. This could be increased either
- ; by using long jumps or creating a separate set of macros with long
- ; jumps (perhaps preceded with an L).
- ;2) Statements may only be nested 9 deep. This is the size of the NAMEPUSH
- ; stack and could be made as large as desired.
- ;3) Param1 and Param2 may not both be variables. This is because 8088
- ; assembly cannot compare two variables directly. The macros could be
- ; rewritten to move one parameter into a register first and then do the
- ; compare, but that would cost some code size. I tried to use the .TYPE
- ; function to discern whether a passed parameter was a constant, a variable
- ; or a register, but it does not seem to work as specified in the manual
- ; and there appears to be no way in a macro to tell whether a parameter is
- ; a variable or not (I could be wrong, but I couldn't find a way).
- ;
- ;
- ;------------------------------------------------------------------------
-
- varcntr = 0 ;init the variable counter
-
- ;these 9 variables are used as a stack so we can have nested
- ;statements
- savednum1 = 0 ;init the stack variables
- savednum2 = 0
- savednum3 = 0
- savednum4 = 0
- savednum5 = 0
- savednum6 = 0
- savednum7 = 0
- savednum8 = 0
- savednum9 = 0
-
- usesigns equ 0 ;use signed comparisons
- nosigns equ 1 ;use unsigned comparisons
- signflag = nosigns ;init to no signs
-
- ;to generate signed comparisons, set signflag = usesigns
-
- ;------------------------------------------------------------------------
- ;Format for the while macro is as follows:
- ;
- ;Comparison operators are as follows:
- ;We can't acutally use the arithmetic symbols (<,>,=,etc) because
- ;they are treated specially by the assembler not as the literal chars.
- ;
- ;gt >
- ;lt <
- ;eq =
- ;gte >=
- ;lte <=
- ;ne <>
- ;
- ;For example, this statement:
- ;
- ;_WHILE ax gt [loopcnt] END_LOOP
- ;
- ; <body of while loop>
- ;
- ;_ENDWHILE
- ;
- ;
- ;Would generate this code:
- ;
- ; cmp ax,[loopcnt]
- ; jbe END_LOOP
- ;
- ; <Body of while loop>
- ;
- ;END_LOOP:
- ;
- ;
- ;------------------------------------------------------------------------
-
- _WHILE macro param1,condition,param2
-
- def_label <top_label>,%varcntr ;;define the top label
- cmp param1,param2 ;;do the comparison
- opp_jmp <condition>,<bot_label>,%varcntr ;;make the condition jump
- namepush ;;push varcntr onto the stack
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- _WHILE2 macro param1,condition,param2 ;;used for comparing two variables
-
- def_label <top_label>,%varcntr ;;define the top label
- mov dx,param2
- cmp param1,dx
- opp_jmp <condition>,<bot_label>,%varcntr ;;make the condition jump
- namepush ;;push varcntr onto the stack
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- _ENDWHILE macro
-
- gen_jmp2 <top_label>,%savednum1 ;;jump back to the top of the loop
- def_label <bot_label>,%savednum1 ;;make bottom loop label
- namepop ;;pop the stack down
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- DEF_LABEL macro first_text,num ;;make a label with passed text and number
-
- &first_text&num label near
-
- ENDM
-
- ;------------------------------------------------------------------------
- ;OPP_JUMP is a macro to generate the opposite comparison of the passed
- ;condition and generate a jump to a label made from the passed text and
- ;the ascii characters of the passed number.
- ;
- ;There are two types of comparison, either signed comparisons or unsigned
- ;comparisons depending upon the value of the signflag. Unsigned comparisons
- ;use comparisons like jbe,jae,ja,jb. Signed comparisons use comparisons like
- ;jg,jl,jge,jle.
- ;
- ;Passed: condition (gt,lt,gte,lte,eq,ne)
- ; text (for lable)
- ; number (to be converted to ascii and put in the label)
- ;------------------------------------------------------------------------
-
- OPP_JMP macro jmp_condition,first_text,num1 ;do an opposite jump to the requested label
-
- IF signflag eq nosigns ;;if we should do unsigned comparisons
- ifidn <jmp_condition>,<gt>
- jbe &first_text&num1 ;;inverse condition to stop loop
- else
- ifidn <jmp_condition>,<eq>
- jnz &first_text&num1 ;;inverse condition to stop loop
- else
- ifidn <jmp_condition>,<lt>
- jae &first_text&num1 ;;inverse condition to stop loop
- else
- ifidn <jmp_condition>,<gte>
- jb &first_text&num1 ;;inverse condition to stop loop
- else
- ifidn <jmp_condition>,<lte>
- ja &first_text&num1 ;;inverse condition to stop loop
- else
- ifidn <jmp_condition>,<ne>
- jz &first_text&num1 ;;inverse condition to stop loop
- else
- if1
- %out ERROR - unsupported while condition &jmp_condition
- .ERR ;;force error
- endif
- endif
- endif
- endif
- endif
- endif
- endif
- ELSE ;;else, if we should do signed comparisons
- ifidn <jmp_condition>,<gt>
- jle &first_text&num1 ;;inverse condition to stop loop
- else
- ifidn <jmp_condition>,<eq>
- jnz &first_text&num1 ;;inverse condition to stop loop
- else
- ifidn <jmp_condition>,<lt>
- jge &first_text&num1 ;;inverse condition to stop loop
- else
- ifidn <jmp_condition>,<gte>
- jl &first_text&num1 ;;inverse condition to stop loop
- else
- ifidn <jmp_condition>,<lte>
- jg &first_text&num1 ;;inverse condition to stop loop
- else
- ifidn <jmp_condition>,<ne>
- jz &first_text&num1 ;;inverse condition to stop loop
- else
- if1
- %out ERROR - unsupported while condition &jmp_condition
- .ERR ;;force error
- endif
- endif
- endif
- endif
- endif
- endif
- endif
- ENDIF
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- GEN_JMP2 macro first_text,num1
- jmp &first_text&num1
- ENDM
-
- ;------------------------------------------------------------------------
-
- ;push the label number onto a stack to allow nesting.
-
- NAMEPUSH macro
- IF savednum9 ne 0 ;;if stack overflows
- %out ERROR - NAMEPUSH macro overflow. ;;show error msg
- %out Nesting too deep.
- .err ;;stop assembly
- ENDIF
- savednum9 = savednum8
- savednum8 = savednum7
- savednum7 = savednum6
- savednum6 = savednum5
- savednum5 = savednum4
- savednum4 = savednum3
- savednum3 = savednum2
- savednum2 = savednum1
- savednum1 = varcntr
- varcntr = varcntr + 1 ;;inc the counter forever
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- ;pop a label number off the stack
-
- NAMEPOP macro
- savednum1 = savednum2
- savednum2 = savednum3
- savednum3 = savednum4
- savednum4 = savednum5
- savednum5 = savednum6
- savednum6 = savednum7
- savednum7 = savednum8
- savednum8 = savednum9
- ENDM
-
- ;------------------------------------------------------------------------
-
- _IF macro param1,condition,param2
-
- cmp param1,param2
- opp_jmp <condition>,<endif_label>,%varcntr
- namepush
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- _IF2 macro param1,condition,param2 ;used for comparing two variables
-
- mov dx,param2
- cmp param1,dx
- opp_jmp <condition>,<endif_label>,%varcntr
- namepush
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- _ENDIF macro
-
- def_label <endif_label>,%savednum1
- namepop ;;pop the variable name counter
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- _IFELSE macro param1,condition,param2 ;if-then-else construct
-
- cmp param1,param2
- opp_jmp <condition>,<else_label>,%varcntr
- namepush
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- _ELSE macro
-
- gen_jmp2 <endif_label>,%savednum1 ;first end the above condition by jumping around the else
- def_label <else_label>,%savednum1 ;now make the label for jumping to the else condition
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- _ENDIFELSE macro
-
- _endif ;same as an endif
-
- ENDM
-
- ;------------------------------------------------------------------------
-
- _FOR macro loopvar,eq_text,loopvar_init,to_text,loopvar_end,step_text,stepvalue
- Local AROUND_INC
- ;;_FOR ax eq 0 to 5 step 1
-
- IF2
- IFDIF <&eq_text>,<eq>
- %out ERROR in _FOR declaration (eq not correct)
- %out Example: "_FOR ax eq 0 to 5 step 1"
- %out
- .err
- ENDIF
- IFDIF <&to_text>,<to>
- %out ERROR in _FOR declaration (to not correct)
- %out Example: "_FOR ax eq 0 to 5 step 1"
- %out
- .err
- ENDIF
- IFDIF <&step_text>,<step>
- %out ERROR in _FOR declaration (step not correct)
- %out Example: "_FOR ax eq 0 to 5 step 1"
- %out
- .err
- ENDIF
- ENDIF
-
- mov [loopvar],loopvar_init ;;initialize the loop variable
- jmp short AROUND_INC ;;skip over the increment the first time
- def_label <top_for>,%varcntr ;;set label at the top of the loop
- add [loopvar],stepvalue ;;add the step value
- cmp [loopvar],loopvar_end ;;do the loop comparison
- opp_jmp <ne>,<bot_for>,%varcntr ;;don't jump if loopvar <> loopvar_end
- namepush
- AROUND_INC:
- ENDM
-
- _ENDFOR macro
-
- gen_jmp2 <top_for>,%savednum1 ;;jump back to the top of the loop
- def_label <bot_for>,%savednum1 ;;set label for the end of the loop
- namepop ;;pop the variable name counter
-
- ENDM
-
- ;------------------------------------------------------------------------
- ;The following macros are for doing long jumps as efficiently as possible.
- ;They all consist of the regular short jump on condition syntax preceded
- ;by an "l". For example. These are real handy to fix those assembly errors
- ;that report "jump out of range". Just put an "l" in front of the
- ;condition and the macro does all the work.
- ;
- ;For example:
- ;
- ;ljc label1 ;jump long to label1 if carry set
- ;ljnz label2 ;jump long to label2 if zero not set
- ;
- ;------------------------------------------------------------------------
-
- ljc macro label
- local short_label
- jnc short_label ;;use to opposite condition to jump short
- jmp label
- short_label:
- endm
-
- ljnc macro label
- local short_label
- jc short_label
- jmp label
- short_label:
- endm
-
- ljz macro label
- local short_label
- jnz short_label ;;use to opposite condition to jump short
- jmp label
- short_label:
- endm
-
- ljnz macro label
- local short_label
- jz short_label ;;use to opposite condition to jump short
- jmp label
- short_label:
- endm
-
- lja macro label
- local short_label
- jbe short_label ;;use to opposite condition to jump short
- jmp label
- short_label:
- endm
-
- ljb macro label
- local short_label
- jae short_label ;;use to opposite condition to jump short
- jmp label
- short_label:
- endm
-
- ljae macro label
- local short_label
- jb short_label ;;use to opposite condition to jump short
- jmp label
- short_label:
- endm
-
- ljbe macro label
- local short_label
- ja short_label ;;use to opposite condition to jump short
- jmp label
- short_label:
- endm
-
- ljs macro label
- local short_label
- jns short_label ;;use to opposite condition to jump short
- jmp label
- short_label:
- endm
-
- ljns macro label
- local short_label
- js short_label ;;use to opposite condition to jump short
- jmp label
- short_label:
- endm
-
- .list