home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / asm / MACROS.ZIP / MACROS.INC next >
Encoding:
Text File  |  1986-11-18  |  13.7 KB  |  528 lines

  1. .xlist
  2.  
  3. ;------------------------------------------------------------------------
  4. ;This file contains macros for use with Microsoft's MASM v4.00.
  5. ;
  6. ;Written by John Friend
  7. ;Compuserve ID, 73317,2204
  8. ;Released to the public domain on November 18, 1986 for any use or purpose.
  9. ;
  10. ;Syntax for using these macros is as follows:
  11. ;
  12. ;IF STATEMENT:
  13. ;-------------
  14. ;
  15. ;_IF <param1> condition <param2>
  16. ;
  17. ;    <your code for if the condition is satisfied>
  18. ;
  19. ;_ENDIF
  20. ;
  21. ;
  22. ;IF THEN ELSE STATEMENT:
  23. ;-----------------------
  24. ;
  25. ;_IFELSE <param1> condition <param2>
  26. ;
  27. ;    <your code for if the condition is satisfied>
  28. ;
  29. ;_ELSE
  30. ;
  31. ;    <your code for if the condition is not satisfied>
  32. ;
  33. ;_ENDIF
  34. ;
  35. ;
  36. ;WHILE STATEMENT:
  37. ;----------------
  38. ;
  39. ;_WHILE <param1> condition <param2>
  40. ;
  41. ;    <your code for if the condition is satisfied>
  42. ;
  43. ;_ENDWHILE
  44. ;
  45. ;
  46. ;
  47. ;FOR STATEMENT:
  48. ;--------------
  49. ;
  50. ;_FOR <param1> eq <startvalue> to <endvalue> step <stepvalue>
  51. ;
  52. ;    <your code for the for loop>
  53. ;
  54. ;_ENDFOR
  55. ;
  56. ;
  57. ;The macros allow you to create IF, WHILE, and FOR statements in
  58. ;assembly language.  They work on the principle that any one of the
  59. ;above statements can be generated with a combination of cmp and jump
  60. ;instructions.
  61. ;
  62. ;There are a number of tricks used to get these macros to work:
  63. ;
  64. ;1) A way to generate the appropriate labels is needed.  Each label has
  65. ;   to be unique in order to not get assembler conflicts.  This is done
  66. ;   by keeping a counter of what label number we are on (varcntr) and
  67. ;   the next time we need a label, we convert varcntr to ascii and insert
  68. ;   it in the label string.  Since varcntr is incremented each time we
  69. ;   create a new label, we never get two identical labels.
  70. ;
  71. ;2) IF, WHILE, and FOR statements can be simulated with the inverse
  72. ;   comparison from what is found in the statement declaration.  For example,
  73. ;   the statement:
  74. ;
  75. ;   IF (ax > 0) then
  76. ;    begin
  77. ;    <body of code>
  78. ;    end
  79. ;
  80. ;   This statement can be simulated with the inverse comparison and a jump
  81. ;   as follows:
  82. ;
  83. ;   If (ax <= 0) then jump around <body of code>
  84. ;    <body of code>
  85. ;
  86. ;   In assembly language:
  87. ;
  88. ;   cmp    ax,0
  89. ;   jbe    SKIP_BODY_OF_CODE
  90. ;   <body of code>
  91. ;SKIP_BODY_OF_CODE:
  92. ;   
  93. ;   The trick is how to generate the inverse comparison in an assembly macro.
  94. ;   This is done by comparing the comparison string to a number of pre-defined
  95. ;   ones using the IFIDN macro command and then substituting the inverse one.
  96. ;   See the macro OPP_JMP.
  97. ;
  98. ;3) We want to be able to nest the statements.  In order to do this we need
  99. ;   some kind of a stack where we can push a label name each time we create
  100. ;   an IF statement and pop the label name each time an ENDIF is
  101. ;   encountered.  This is done using the NAMEPUSH and NAMEPOP.
  102. ;
  103. ;
  104. ;LIMITATIONS:
  105. ;
  106. ;1) Bodies of code between an _IF statement and an _ENDIF are limited to 
  107. ;   128 bytes because short jumps are used. This could be increased either 
  108. ;   by using long jumps or creating a separate set of macros with long 
  109. ;   jumps (perhaps preceded with an L).
  110. ;2) Statements may only be nested 9 deep.  This is the size of the NAMEPUSH
  111. ;   stack and could be made as large as desired.
  112. ;3) Param1 and Param2 may not both be variables.  This is because 8088
  113. ;   assembly cannot compare two variables directly.  The macros could be
  114. ;   rewritten to move one parameter into a register first and then do the
  115. ;   compare, but that would cost some code size.  I tried to use the .TYPE
  116. ;   function to discern whether a passed parameter was a constant, a variable
  117. ;   or a register, but it does not seem to work as specified in the manual
  118. ;   and there appears to be no way in a macro to tell whether a parameter is
  119. ;   a variable or not (I could be wrong, but I couldn't find a way).
  120. ;
  121. ;
  122. ;------------------------------------------------------------------------
  123.  
  124. varcntr = 0        ;init the variable counter
  125.  
  126. ;these 9 variables are used as a stack so we can have nested
  127. ;statements
  128. savednum1 = 0        ;init the stack variables
  129. savednum2 = 0
  130. savednum3 = 0
  131. savednum4 = 0
  132. savednum5 = 0
  133. savednum6 = 0
  134. savednum7 = 0
  135. savednum8 = 0
  136. savednum9 = 0
  137.  
  138. usesigns equ 0        ;use signed comparisons
  139. nosigns  equ 1        ;use unsigned comparisons
  140. signflag = nosigns    ;init to no signs
  141.  
  142. ;to generate signed comparisons, set signflag = usesigns
  143.  
  144. ;------------------------------------------------------------------------
  145. ;Format for the while macro is as follows:
  146. ;
  147. ;Comparison operators are as follows:
  148. ;We can't acutally use the arithmetic symbols (<,>,=,etc) because
  149. ;they are treated specially by the assembler not as the literal chars.
  150. ;
  151. ;gt    >
  152. ;lt    <
  153. ;eq    =
  154. ;gte    >=
  155. ;lte    <=
  156. ;ne    <>
  157. ;
  158. ;For example, this statement:
  159. ;
  160. ;_WHILE ax gt [loopcnt] END_LOOP
  161. ;
  162. ;    <body of while loop>
  163. ;
  164. ;_ENDWHILE
  165. ;
  166. ;
  167. ;Would generate this code:
  168. ;
  169. ;    cmp    ax,[loopcnt]
  170. ;    jbe    END_LOOP
  171. ;
  172. ;    <Body of while loop>
  173. ;
  174. ;END_LOOP:
  175. ;
  176. ;
  177. ;------------------------------------------------------------------------
  178.  
  179. _WHILE    macro    param1,condition,param2
  180.  
  181. def_label <top_label>,%varcntr            ;;define the top label
  182. cmp    param1,param2                ;;do the comparison
  183. opp_jmp   <condition>,<bot_label>,%varcntr    ;;make the condition jump
  184. namepush                    ;;push varcntr onto the stack
  185.  
  186. ENDM
  187.  
  188. ;------------------------------------------------------------------------
  189.  
  190. _WHILE2    macro    param1,condition,param2        ;;used for comparing two variables
  191.  
  192. def_label <top_label>,%varcntr            ;;define the top label
  193. mov    dx,param2
  194. cmp    param1,dx
  195. opp_jmp   <condition>,<bot_label>,%varcntr    ;;make the condition jump
  196. namepush                    ;;push varcntr onto the stack
  197.  
  198. ENDM
  199.  
  200. ;------------------------------------------------------------------------
  201.  
  202. _ENDWHILE macro
  203.  
  204. gen_jmp2 <top_label>,%savednum1        ;;jump back to the top of the loop
  205. def_label <bot_label>,%savednum1    ;;make bottom loop label
  206. namepop                    ;;pop the stack down
  207.  
  208. ENDM
  209.  
  210. ;------------------------------------------------------------------------
  211.  
  212. DEF_LABEL    macro    first_text,num        ;;make a label with passed text and number
  213.  
  214. &first_text&num    label    near
  215.  
  216. ENDM
  217.  
  218. ;------------------------------------------------------------------------
  219. ;OPP_JUMP is a macro to generate the opposite comparison of the passed
  220. ;condition and generate a jump to a label made from the passed text and
  221. ;the ascii characters of the passed number.
  222. ;
  223. ;There are two types of comparison, either signed comparisons or unsigned
  224. ;comparisons depending upon the value of the signflag.  Unsigned comparisons
  225. ;use comparisons like jbe,jae,ja,jb.  Signed comparisons use comparisons like
  226. ;jg,jl,jge,jle.
  227. ;
  228. ;Passed:    condition (gt,lt,gte,lte,eq,ne)
  229. ;        text (for lable)
  230. ;        number (to be converted to ascii and put in the label)
  231. ;------------------------------------------------------------------------
  232.  
  233. OPP_JMP    macro    jmp_condition,first_text,num1    ;do an opposite jump to the requested label
  234.  
  235. IF signflag eq nosigns        ;;if we should do unsigned comparisons
  236.  ifidn    <jmp_condition>,<gt>
  237.  jbe    &first_text&num1    ;;inverse condition to stop loop
  238.  else
  239.   ifidn    <jmp_condition>,<eq>
  240.   jnz    &first_text&num1    ;;inverse condition to stop loop
  241.   else
  242.    ifidn    <jmp_condition>,<lt>
  243.    jae    &first_text&num1    ;;inverse condition to stop loop
  244.    else
  245.     ifidn    <jmp_condition>,<gte>
  246.     jb    &first_text&num1    ;;inverse condition to stop loop
  247.     else
  248.      ifidn    <jmp_condition>,<lte>
  249.      ja    &first_text&num1 ;;inverse condition to stop loop
  250.      else
  251.       ifidn    <jmp_condition>,<ne>
  252.       jz    &first_text&num1    ;;inverse condition to stop loop
  253.       else
  254.        if1
  255.        %out ERROR - unsupported while condition &jmp_condition
  256.        .ERR        ;;force error
  257.        endif
  258.       endif
  259.      endif
  260.     endif
  261.    endif
  262.   endif
  263.  endif
  264. ELSE                ;;else, if we should do signed comparisons
  265.  ifidn    <jmp_condition>,<gt>
  266.  jle    &first_text&num1    ;;inverse condition to stop loop
  267.  else
  268.   ifidn    <jmp_condition>,<eq>
  269.   jnz    &first_text&num1    ;;inverse condition to stop loop
  270.   else
  271.    ifidn    <jmp_condition>,<lt>
  272.    jge    &first_text&num1    ;;inverse condition to stop loop
  273.    else
  274.     ifidn    <jmp_condition>,<gte>
  275.     jl    &first_text&num1    ;;inverse condition to stop loop
  276.     else
  277.      ifidn    <jmp_condition>,<lte>
  278.      jg    &first_text&num1 ;;inverse condition to stop loop
  279.      else
  280.       ifidn    <jmp_condition>,<ne>
  281.       jz    &first_text&num1    ;;inverse condition to stop loop
  282.       else
  283.        if1
  284.        %out ERROR - unsupported while condition &jmp_condition
  285.        .ERR        ;;force error
  286.        endif
  287.       endif
  288.      endif
  289.     endif
  290.    endif
  291.   endif
  292.  endif
  293. ENDIF
  294.  
  295. ENDM
  296.  
  297. ;------------------------------------------------------------------------
  298.  
  299. GEN_JMP2 macro first_text,num1
  300.     jmp    &first_text&num1
  301. ENDM
  302.  
  303. ;------------------------------------------------------------------------
  304.  
  305. ;push the label number onto a stack to allow nesting.
  306.  
  307. NAMEPUSH macro
  308. IF savednum9 ne 0            ;;if stack overflows
  309. %out ERROR - NAMEPUSH macro overflow.    ;;show error msg
  310. %out Nesting too deep.
  311. .err                    ;;stop assembly
  312. ENDIF
  313. savednum9 = savednum8
  314. savednum8 = savednum7
  315. savednum7 = savednum6
  316. savednum6 = savednum5
  317. savednum5 = savednum4
  318. savednum4 = savednum3
  319. savednum3 = savednum2
  320. savednum2 = savednum1
  321. savednum1 = varcntr
  322. varcntr = varcntr + 1            ;;inc the counter forever
  323.  
  324. ENDM
  325.  
  326. ;------------------------------------------------------------------------
  327.  
  328. ;pop a label number off the stack
  329.  
  330. NAMEPOP macro
  331. savednum1 = savednum2
  332. savednum2 = savednum3
  333. savednum3 = savednum4
  334. savednum4 = savednum5
  335. savednum5 = savednum6
  336. savednum6 = savednum7
  337. savednum7 = savednum8
  338. savednum8 = savednum9
  339. ENDM
  340.  
  341. ;------------------------------------------------------------------------
  342.  
  343. _IF    macro    param1,condition,param2
  344.  
  345. cmp    param1,param2
  346. opp_jmp    <condition>,<endif_label>,%varcntr
  347. namepush
  348.  
  349. ENDM
  350.  
  351. ;------------------------------------------------------------------------
  352.  
  353. _IF2    macro    param1,condition,param2        ;used for comparing two variables
  354.  
  355. mov    dx,param2
  356. cmp    param1,dx
  357. opp_jmp    <condition>,<endif_label>,%varcntr
  358. namepush
  359.  
  360. ENDM
  361.  
  362. ;------------------------------------------------------------------------
  363.  
  364. _ENDIF    macro
  365.  
  366. def_label <endif_label>,%savednum1
  367. namepop                        ;;pop the variable name counter
  368.  
  369. ENDM
  370.  
  371. ;------------------------------------------------------------------------
  372.  
  373. _IFELSE macro param1,condition,param2        ;if-then-else construct
  374.  
  375. cmp    param1,param2
  376. opp_jmp    <condition>,<else_label>,%varcntr
  377. namepush
  378.  
  379. ENDM
  380.  
  381. ;------------------------------------------------------------------------
  382.  
  383. _ELSE macro
  384.  
  385. gen_jmp2 <endif_label>,%savednum1    ;first end the above condition by jumping around the else
  386. def_label <else_label>,%savednum1    ;now make the label for jumping to the else condition
  387.  
  388. ENDM
  389.  
  390. ;------------------------------------------------------------------------
  391.  
  392. _ENDIFELSE macro
  393.  
  394. _endif                    ;same as an endif
  395.  
  396. ENDM
  397.  
  398. ;------------------------------------------------------------------------
  399.  
  400. _FOR macro loopvar,eq_text,loopvar_init,to_text,loopvar_end,step_text,stepvalue
  401. Local AROUND_INC
  402. ;;_FOR ax eq 0 to 5 step 1
  403.  
  404. IF2
  405. IFDIF <&eq_text>,<eq>
  406. %out ERROR in _FOR declaration (eq not correct)
  407. %out Example: "_FOR ax eq 0 to 5 step 1"
  408. %out 
  409. .err
  410. ENDIF
  411. IFDIF <&to_text>,<to>
  412. %out ERROR in _FOR declaration (to not correct)
  413. %out Example: "_FOR ax eq 0 to 5 step 1"
  414. %out
  415. .err
  416. ENDIF
  417. IFDIF <&step_text>,<step>
  418. %out ERROR in _FOR declaration (step not correct)
  419. %out Example: "_FOR ax eq 0 to 5 step 1"
  420. %out
  421. .err
  422. ENDIF
  423. ENDIF
  424.  
  425. mov    [loopvar],loopvar_init        ;;initialize the loop variable
  426. jmp    short AROUND_INC        ;;skip over the increment the first time
  427. def_label <top_for>,%varcntr        ;;set label at the top of the loop
  428. add    [loopvar],stepvalue        ;;add the step value
  429. cmp    [loopvar],loopvar_end        ;;do the loop comparison
  430. opp_jmp <ne>,<bot_for>,%varcntr        ;;don't jump if loopvar <> loopvar_end
  431. namepush
  432. AROUND_INC:
  433. ENDM
  434.  
  435. _ENDFOR macro
  436.  
  437. gen_jmp2  <top_for>,%savednum1        ;;jump back to the top of the loop
  438. def_label <bot_for>,%savednum1        ;;set label for the end of the loop
  439. namepop                    ;;pop the variable name counter
  440.  
  441. ENDM
  442.  
  443. ;------------------------------------------------------------------------
  444. ;The following macros are for doing long jumps as efficiently as possible.
  445. ;They all consist of the regular short jump on condition syntax preceded
  446. ;by an "l".  For example.  These are real handy to fix those assembly errors
  447. ;that report "jump out of range".  Just put an "l" in front of the
  448. ;condition and the macro does all the work.
  449. ;
  450. ;For example:
  451. ;
  452. ;ljc    label1            ;jump long to label1 if carry set
  453. ;ljnz    label2            ;jump long to label2 if zero not set
  454. ;
  455. ;------------------------------------------------------------------------
  456.  
  457. ljc    macro    label
  458. local    short_label
  459. jnc    short_label        ;;use to opposite condition to jump short
  460. jmp    label
  461. short_label:
  462. endm
  463.  
  464. ljnc    macro    label
  465. local    short_label
  466. jc    short_label
  467. jmp    label
  468. short_label:
  469. endm
  470.  
  471. ljz    macro    label
  472. local    short_label
  473. jnz    short_label        ;;use to opposite condition to jump short
  474. jmp    label
  475. short_label:
  476. endm
  477.  
  478. ljnz    macro    label
  479. local    short_label
  480. jz    short_label        ;;use to opposite condition to jump short
  481. jmp    label
  482. short_label:
  483. endm
  484.  
  485. lja    macro    label
  486. local    short_label
  487. jbe    short_label        ;;use to opposite condition to jump short
  488. jmp    label
  489. short_label:
  490. endm
  491.  
  492. ljb    macro    label
  493. local    short_label
  494. jae    short_label        ;;use to opposite condition to jump short
  495. jmp    label
  496. short_label:
  497. endm
  498.  
  499. ljae    macro    label
  500. local    short_label
  501. jb    short_label        ;;use to opposite condition to jump short
  502. jmp    label
  503. short_label:
  504. endm
  505.  
  506. ljbe    macro    label
  507. local    short_label
  508. ja    short_label        ;;use to opposite condition to jump short
  509. jmp    label
  510. short_label:
  511. endm
  512.  
  513. ljs    macro    label
  514. local    short_label
  515. jns    short_label        ;;use to opposite condition to jump short
  516. jmp    label
  517. short_label:
  518. endm
  519.  
  520. ljns    macro    label
  521. local    short_label
  522. js    short_label        ;;use to opposite condition to jump short
  523. jmp    label
  524. short_label:
  525. endm
  526.  
  527. .list
  528.