home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Library / Manuels & Misc / Assembly / AOA.ZIP / CH12 / ITERATOR.ASM < prev    next >
Encoding:
Assembly Source File  |  1994-03-22  |  5.6 KB  |  231 lines

  1.         .286        ;For PUSH imm instr.
  2.         .xlist
  3.         include     stdlib.a
  4.         includelib    stdlib.lib
  5.         .list
  6.  
  7. ; Some "cute" equates:
  8.  
  9. Iterator    textequ    <proc>
  10. endi        textequ    <endp>
  11. wp        textequ    <word ptr>
  12.  
  13.  
  14. ; Yield is a macro which emits the necessary code for the YIELD operation.
  15.  
  16. Yield        macro
  17.         mov    dx, [bp+2]        ;Place to yield back to.
  18.         push    bp            ;Save Iterator link
  19.         mov    bp, [bp]        ;Get ptr to caller's A.R.
  20.         call    dx            ;Push resume address and rtn.
  21.         pop    bp            ;Restore ptr to our A. R.
  22.         endm
  23.  
  24. ; Necessary global variables:
  25.  
  26. dseg        segment    para public 'data'
  27.  
  28. ; As per UCR StdLib instructions, InputStr must hold
  29. ; at least 128 characters.
  30.  
  31. InputStr    byte    128 dup (?)
  32.  
  33. ; Note that the following statement initializes the
  34. ; VowelCnt array to zeros, saving us from having to
  35. ; do this in the main program.
  36.  
  37. VowelCnt    word    256 dup (0)
  38.  
  39. dseg        ends
  40.  
  41.  
  42.  
  43. cseg        segment    para public 'code'
  44.         assume    cs:cseg, ds:dseg
  45.  
  46. ; GetVowel-     This iterator searches for the next vowel in the
  47. ;        input string and returns the index to the value
  48. ;        as the iterator result.    On entry, ES:DI points
  49. ;        at the string to process.  On yield, AX returns
  50. ;        the zero-based index into the string of the
  51. ;        current vowel.
  52. ;
  53. ; GVYield-    Address to call when performing the yield.
  54. ; GVStrPtr-    A local variable which points at our string.
  55.  
  56. GVYield        textequ    <word ptr [bp+2]>
  57. GVStrPtr    textequ    <dword ptr [bp-4]>
  58.  
  59. GetVowel    Iterator
  60.         push    bp
  61.         mov    bp, sp
  62.  
  63. ; Create and initialize GVStrPtr.  This is a pointer to the
  64. ; next character to process in the input string.
  65.  
  66.         push    es
  67.         push    di
  68.  
  69. ; Save original ES:DI values so we can restore them on YIELD
  70. ; and on termination.
  71.  
  72.         push    es
  73.         push    di
  74.  
  75. ; Okay, here's the main body of the iterator.  Fetch each
  76. ; character until the end of the string and see if it is
  77. ; a vowel.  If it is a vowel, yield the index to it.  If
  78. ; it is not a vowel, move on to the next character.
  79.  
  80. GVLoop:        les    di, GVStrPtr    ;Ptr to next char.
  81.         mov    al, es:[di]    ;Get this character.
  82.         cmp    al, 0        ;End of string?
  83.         je    GVDone
  84.  
  85. ; The following statement will convert all lower case
  86. ; characters to upper case.  It will also translate other
  87. ; characters to who knows what, but we don't care since
  88. ; we only look at A, E, I, O, U, W, and Y.
  89.  
  90.         and    al, 5fh
  91.  
  92. ; See if this character is a vowel.  This is a disgusting
  93. ; set membership operation.  See Chapter Ten to learn how
  94. ; to do it right.
  95.  
  96.         cmp    al, 'A'
  97.         je    IsAVowel
  98.         cmp    al, 'E'
  99.         je    IsAVowel
  100.         cmp    al, 'I'
  101.         je    IsAVowel
  102.         cmp    al, 'O'
  103.         je    IsAVowel
  104.         cmp    al, 'U'
  105.         je    IsAVowel
  106.         cmp    al, 'W'
  107.         je    IsAVowel
  108.         cmp    al, 'Y'
  109.         jne    NotAVowel
  110.  
  111. ; If we've got a vowel we need to yield the index into
  112. ; the string to that vowel.  To compute the index, we
  113. ; restore the original ES:DI values (which pointer at
  114. ; the beginning of the string) and subtract the current
  115. ; position (now in AX) from the first position.  This
  116. ; produces a zero-based index into the string.
  117. ; This code must also increment the corresponding entry
  118. ; in the VowelCnt array so we can print the results
  119. ; later.  Unlike the Pascal code, we've converted lower
  120. ; case to upper case so the count for upper and lower
  121. ; case characters will appear in the upper case slot.
  122.  
  123. IsAVowel:       push    bx        ;Bump the vowel
  124.         mov    ah, 0        ; count by one.
  125.         mov    bx, ax
  126.         shl    bx, 1
  127.         inc    VowelCnt[bx]
  128.         pop    bx
  129.  
  130.         mov    ax, di
  131.         pop    di        ;Restore original DI
  132.         sub    ax, di        ;Compute index.
  133.         pop    es        ;Restore original ES
  134.  
  135.         yield
  136.  
  137.         push    es        ;Save ES:DI again
  138.         push    di
  139.  
  140. ; Whether it was a vowel or not, we've now got to move
  141. ; on to the next character in the string.  Increment
  142. ; our string pointer by one and repeat the process
  143. ; over again.
  144.  
  145. NotAVowel:    inc    wp GVStrPtr
  146.         jmp     GVLoop
  147.  
  148. ; If we've reached the end of the string, terminate
  149. ; the iterator here.  We need to restore the original
  150. ; ES:DI values, remove local variables, pop the YIELD
  151. ; address, and then return to the termination address.
  152.  
  153. GVDone:        pop    di        ;Restore ES:DI
  154.         pop    es
  155.         mov    sp, bp        ;Remove locals
  156.         add    sp, 4        ;Pop YIELD/S.L.
  157.         pop    bp
  158.         ret
  159. GetVowel    endi
  160.  
  161.  
  162.  
  163. Main        proc
  164.         mov    ax, dseg
  165.         mov    ds, ax
  166.         mov    es, ax
  167.  
  168.         print
  169.         byte    "Enter a string: ",0
  170.         lesi    InputStr
  171.         gets            ;Read input line.
  172.  
  173. ; The following is the foreach loop.  Note that the label
  174. ; "FOREACH" is present for documentation purpose only.
  175. ; In fact, the foreach loop always begins with the first
  176. ; instruction after the call to GetVowel.
  177. ;
  178. ; One other note: this assembly language code uses
  179. ; zero-based indexes for the string.  The Pascal version
  180. ; uses one-based indexes for strings.  So the actual
  181. ; numbers printed will be different.  If you want the
  182. ; values printed by both programs to be identical,
  183. ; uncomment the INC instruction below.
  184.  
  185.         push    offset ForDone    ;Termination address.
  186.         push    bp        ;Static link.
  187.         call    GetVowel    ;Start iterator
  188. FOREACH:    mov    bx, ax
  189.         print
  190.         byte    "Vowel ",0
  191.         mov    al, InputStr[bx]
  192.         putc
  193.         print
  194.         byte    " at position ",0
  195.         mov    ax, bx
  196. ;        inc    ax
  197.         puti
  198.         putcr
  199.         ret            ;Iterator resume.
  200.  
  201. ForDone:    printf
  202.         byte    "# of A's: %d\n"
  203.         byte    "# of E's: %d\n"
  204.         byte    "# of I's: %d\n"
  205.         byte    "# of O's: %d\n"
  206.         byte    "# of U's: %d\n"
  207.         byte    "# of W's: %d\n"
  208.         byte    "# of Y's: %d\n",0
  209.         dword    VowelCnt + ('A'*2)
  210.         dword    VowelCnt + ('E'*2)
  211.         dword    VowelCnt + ('I'*2)
  212.         dword    VowelCnt + ('O'*2)
  213.         dword    VowelCnt + ('U'*2)
  214.         dword    VowelCnt + ('W'*2)
  215.         dword    VowelCnt + ('Y'*2)
  216.  
  217.  
  218. Quit:        ExitPgm            ;DOS macro to quit program.
  219. Main        endp
  220.  
  221. cseg            ends
  222.  
  223. sseg        segment    para stack 'stack'
  224. stk        db    1024 dup ("stack   ")
  225. sseg        ends
  226.  
  227. zzzzzzseg    segment    para public 'zzzzzz'
  228. LastBytes    db    16 dup (?)
  229. zzzzzzseg    ends
  230.         end    Main
  231.