home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / ASM / GRDBDL17.ZIP / ASM.ASM next >
Encoding:
Assembly Source File  |  1998-10-26  |  41.2 KB  |  1,351 lines

  1. ;
  2. ; GRDB
  3. ;
  4. ; Copyright(c) LADsoft
  5. ;
  6. ; David Lindauer, camille@bluegrass.net
  7. ;
  8. ;
  9. ; ASM.ASM
  10. ;
  11. ; Function: Assembler parser
  12. ;
  13. ; not very efficient, but, fast enough!
  14. ;
  15.     ;MASM MODE
  16.     .MODEL SMALL
  17.     .386
  18.  
  19. include iasm.inc
  20. include iopcodes.inc
  21. include eaoperan.inc
  22. include eopcodes.inc
  23. include eopcom.inc
  24. include eprints.inc
  25. include einput.inc
  26. include emtrap.inc
  27. include    edispatc.inc
  28. include eoperand.inc
  29. include eoptions.inc
  30. include ehistory.inc
  31.  
  32.     PUBLIC    asm
  33.     PUBLIC    arg1
  34.     PUBLIC    arg2
  35.     PUBLIC    arg3
  36.     PUBLIC    RepPfxBitmap
  37.     PUBLIC    lastofs
  38.     PUBLIC    lastbyte
  39.     PUBLIC    PrefixBitmapWord
  40.  
  41.     .data
  42. mtoofew        db    "Not enough operands",0
  43. lastbyte    db    0        ;last char of valid mnemonic
  44. lastofs        dw    0        ;current disassembly offset
  45. lastseg        dw    0        ;and current segment
  46. say_repne    db    "repne",0    ;prefix strings to look for
  47. say_repe    db    "repe",0
  48. say_rep        db    "rep",0
  49. say_lock    db    "lock",0
  50. say_word    db    "word",0    ;opcode size overrides
  51. say_byte    db    "byte",0
  52. say_ptr        db    "ptr"
  53. arg1        asmop    <>        ;three args
  54. arg2        asmop    <>
  55. arg3        asmop    <>
  56. arg4        asmop    <>        ;temp for base-mode register gathering
  57. AsmbldInstrsBuf    db    16 DUP (?)    ;temporary to hold assembled instructions
  58. OpSizeTable    db    16 DUP (?)    ;sizes returned by AOP routines
  59. OpSizeTblIndex    dw    0        ;pointer into OpSizeTable
  60. RepPfxBitmap    db    ?        ;bitmap of which rep prefix found
  61. EnteredMnemonic    db    16 DUP (?)    ;bucket to hold mnemonic as typed
  62.  
  63. ;DefaultSeg appears to hold an index into SegmentPfxBytes.
  64.  
  65. DefaultSeg    db    0        ;current default seg (DS or SS)
  66. SegmentPfxBytes    db    26h,2eh,36h,3eh,64h,65h    ;table of seg prefixes
  67.     SEGPFXLISTSIZE    equ    $-SegmentPfxBytes
  68. OverridePfxList    db    "asosgsfsdssscses"    ;list of prefixes with colon
  69. PrefixBitmapWord    dw    ?    ;bitmap of which prefix found
  70.     .CODE
  71. ;
  72. ; interpreter stub to get params
  73. ; INPUT: DS:SI points at the user input line, just past the command char.
  74. ; I am assuming that someone issued the A command.  This can be by itself, 
  75. ; or it can be followed by some addresses
  76. ; The syntax is A [[segment:]offset]
  77. ;    where 
  78. ;    [segment:] can be any segment register, or it can be any hex
  79. ;        number of up to 4 digits.
  80. ;    [offset] can be any hex number of up to 8 digits
  81. ; OUTPUT: lastseg and lastofs set up to assemble at if user provided a legal 
  82. ;    address. Segment is also in FS
  83. ;    CY if invalid address
  84. ;    code address saved in case an unqualified 'A' command later
  85. ;
  86. ;
  87. asm    PROC
  88.     call    WadeSpace        ; see if address given
  89.     jnz    readaddr        ; yep, get it (not CR past spaces)
  90.     mov    ax,lastseg        ; else see if any last addr
  91.     or    ax,lastofs
  92.     jz    usehere            ;if not, go from where we are
  93.     mov    dx,lastseg        ;else, get prior assemble address
  94.     movzx    ebx,lastofs
  95.     jmp    gotaddr            ;no need to set up our own
  96. usehere:
  97.     mov    ebx,RegdumpEIP        ;else load our CS:IP
  98.     mov    dx,RegdumpCS
  99.     jmp    gotaddr            ;and use that
  100.  
  101. readaddr:
  102.     call    ReadAddress        ; read address from input line
  103.     jc    aserrm            ; out on err
  104.     call    WadeSpace        ; make sure nothing else
  105.     jnz    aserrm            ; NZ means we didn't hit a CR
  106.     call    defCS            ; default CS
  107. gotaddr:
  108.     mov    esi,ebx            ; load address
  109.     mov    fs,dx            ;setup segreg 
  110.     and    esi,0ffffh        ;force to 16-bit offset
  111.     mov    lastseg,fs        ;save current segment/selector
  112.     mov    lastofs,si        ;and current 16-bit offset
  113.     call    histoff
  114.     call    doasm            ; do assembly
  115.     call    histon
  116.     clc                ; exit
  117.     ret
  118. aserrm:
  119.     stc                ; exit with err
  120.     ret
  121. asm    ENDP
  122. ;
  123. ; prompt for a line, parse and assemble
  124. ;
  125. ; main assembler
  126. ;
  127. ; OK, the user pressed A <CR>. Here we solicit each entry, one line
  128. ; at a time, and convert the valid ones to opcodes. Invalid entries are
  129. ; complained about, and we return to the top of this routine to get
  130. ; another attempt.
  131. ; INPUT: address to assemble at is in FS (and lastseg): lastofs
  132. ; OUTPUT: Assembled code placed at target memory location and code ptr
  133. ;      incremented
  134. ; PROCESSING: 
  135. ;    1) Display the segment:offset for the next line 
  136. ;    2) Get an instruction from the user
  137. ;        If CR only, we are done
  138. ;    3) If error, report and goto step 1, else assemble the instruction
  139. ;        into a temporary assembly buffer
  140. ;    4) Add any prefixes or overrides to the buffer as required
  141. ;    5) Copy the buffer to the target memory location
  142. ;    6) Return to step 1 until done.
  143. ; NOTES:
  144. ;    1) GetInputLine places the user input into InputBuffer, an 80-char
  145. ;        buffer. It handles backspacing. It returns with SI pointing
  146. ;        to the beginning of the edited input, which may not make
  147. ;        sense
  148. ;    2) getCode points DI at a 16-char bucket I call EnteredMnemonic,
  149. ;        and returns the first delineated string
  150. ;
  151. doasm    PROC
  152.     call    crlf            ;move to new line
  153.     mov    ax,fs            ;get segment address
  154.     call    printword        ;paint that
  155.     mov    dl,':'            ;and a colon
  156.     call    putchar
  157.     mov    ax,lastofs        ;get last offset
  158.     call    printword        ;print it
  159.     call    printspace        ;and a couple of spaces
  160.     call    printspace
  161.     call    GetInputLine               ; get input line
  162.     call    WadeSpace        ; if nothing there we are done
  163.     jz    doasx            ;since we hit the CR
  164.     sub    al,al            ;clear out AL
  165.     call    setsize            ;put 0 into these 3 fields
  166.     mov    PrefixBitmapWord,0    ;say no prefix found
  167.     mov    DefaultSeg,3
  168.     call    getcode            ; get the opcode
  169.     jc    badop
  170.     mov    di,offset arg1        ; get first arg
  171.     call    parsearg
  172.     jc    badarg
  173.     mov    di,offset arg2        ; get second arg
  174.     call    parsearg
  175.     jc    badarg
  176.     mov    di,offset arg3        ; get third arg
  177.     call    parsearg
  178.     jc    badarg
  179.     jz    assemble        ;if no more, to assemble it
  180. manyerr:
  181.     Call    printAlignedErrorMsg    ;else bitch about too many operands
  182.     db    "Too many operands",0
  183.     jmp    doasm
  184. badarg:
  185.     call    printAlignedErrorMsg    ;complain about invalid operand
  186.     db    "Unknown operand",0
  187.     jmp    doasm
  188. badop:        
  189.     call    printAlignedErrorMsg    ;complain about invalid opcode
  190.     db    "Unknown opcode",0
  191.     jmp    doasm
  192. assemble:
  193.     call    validops        ;size check and set
  194.     jc    doasm            ;size mismatch, ignore
  195.     mov    si,offset mnemonicMatchAddrTable    ;find table we built
  196.     mov     cx,[mnemonicMatchCount]    ;number of valid table entries
  197.     mov    OpSizeTblIndex,0    ;init index to top of table
  198.  
  199. ;mnemonicMatchAddrTable contains a list of up to 10h addresses. Each address
  200. ;points to a structure. Each structure contains (among other things) a
  201. ;pointer to a string for this mnemonic, the base opcode for the
  202. ;mnemonic, and an index to the routine used to assemble the code
  203. ;  This loop is examining every valid element of the table we build to
  204. ;isolate those instances of this mnemonic that are valid in this case (that
  205. ;is, valid for size, addressing mode, etc).
  206.  
  207. assl:
  208.     push    cx            ;save count
  209.     push    si            ;save table address
  210.     mov    si,[si]            ;find structure address
  211.     mov    di,offset AsmbldInstrsBuf    ;where to put binary 
  212.     call    oneasm            ;dispatch for this operand
  213.                     ; copies opcode for this instruction
  214.                     ; into the assembled code buffer
  215.     mov    cl,0            ;assume we didn't do anything
  216.     jc    assx2            ;and if true, cl is right
  217.     mov    cx,di            ;else get offset we ended up at
  218.     sub    cx,offset AsmbldInstrsBuf    ;minus starting offset
  219. assx2:               
  220.     mov    bx,OpSizeTblIndex    ;pointer into opsize table
  221.     mov    [bx+OpSizeTable],cl    ;save how many we did
  222.     inc    OpSizeTblIndex        ;bump to next location
  223.     pop    si            ;restore mnemonic ptr table address
  224.     pop    cx            ;and how many to examine
  225.     add    si,2            ;point to next possibility
  226.     loop    assl            ;do them all
  227.     movzx    ecx,byte ptr OpSizeTblIndex    ;see if we did anything
  228.     jcxz    nomatch            ;nope, not found in table
  229.     sub    bx,bx            ;else init for next loop
  230.  
  231.  
  232. ;at this point we have at least one match between the disassembly
  233. ;strucutre and the mneominc/addressmode / size data we accrued earlier.
  234. ;We are going to search the matched entries for the one with the
  235. ;smallest possible byte sequence
  236.  
  237. szllp:
  238.     or    bh,bh            ;if bh is zero
  239.     jz    szlg            ;skip this stuff
  240.     cmp    bh,[ecx+OpSizeTable-1]    ;see if high byte of table value
  241.                     ;is greater than bh
  242.     jb    sslc            ;go here if it is
  243.     test    byte ptr [ecx+OpSizeTable-1],0FFh    ;see if table value is 0
  244.     jz    sslc            ;and if it is, same place
  245.  
  246. ;OK, BH is keeping track of the length of the sequence, and BL is keeping
  247. ;track of the table offset to that sequence.  We get here in case a) this
  248. ;is the only valid sequence we found, or b) this sequence is shorter than
  249. ;the prior shortest sequence we found.
  250.  
  251. szlg:
  252.     mov    bh,[ecx+OpSizeTable-1]    ;get high byte of tbl element->bh
  253.     mov    bl,cl            ;track the index to the shortest
  254. sslc:
  255.     loop    szllp            ;do for as many valid match instances
  256.                     ;as we found
  257. ssgot:
  258.     or    bh,bh            ;did we find anything?
  259.     jz    nomatch            ;no, we did not
  260.     sub    bh,bh            ;convert BL into a word index
  261.     shl    bx,1            ;into the match table
  262.     mov    si,[bx+mnemonicMatchAddrTable-2]    ;get an address
  263.     mov    di,offset AsmbldInstrsBuf    ;point to buffer
  264.     call    oneasm                ;build our favorite sequence
  265.     mov    cx,di                ;DI is new buffer offset
  266.     mov    si,offset AsmbldInstrsBuf    ;switch top to SI
  267.     sub    cx,si            ;get buffer bytecount
  268.     mov    di,lastofs        ;point to last assemble offset
  269.     push    es            ;save ES
  270.     push    fs            ;mov FS to ES
  271.     pop    es
  272.     push    cx            ;save count
  273.  
  274. ;Now DI points to the actual location in memory where we want to put our
  275. ;assembled buffer.  Since prefixes are not in the assembly buffer, we first
  276. ;stick in as many prefixes as we found, then paste the remainder of the
  277. ;buffer beyond them.
  278.  
  279.     call    InsertPrefixes
  280.     pop    cx            ;restore count
  281.     jc    pfxerr            ;if carry, too many prefixes
  282.     rep    movsb            ;copy to memory location for asm
  283.     mov    lastofs,di        ;update assemble in mem location
  284. doasmn:
  285.     pop    es            ;restore old ES
  286.     jmp    doasm            ;and get next instruction
  287. pfxerr:
  288.     pop    es            ;rectify stack
  289.     call    printAlignedErrorMsg
  290.     db    "Too many prefixes",0
  291.     jmp    doasm
  292.  
  293. nomatch:
  294.     call    printAlignedErrorMsg
  295.     db    "Invalid opcode/operand combo",0
  296.     jmp    doasm
  297. doasx:
  298.     ret
  299. doasm    ENDP
  300.  
  301. ;
  302. ;this routine is the shell which assembles an instruction based
  303. ;on the opcode/operand/size data
  304. ;
  305. ;INPUT: SI points to the opcode structure
  306. ;       DI points to a temp buffer into which we do the assembly
  307. ;OUTPUT: BUFFER FILLED.  This routine does the 0F prefix but none of the
  308. ;        other prefixes
  309.  
  310. oneasm    PROC
  311.     test    [si+OPCODE.FLAGS],prefix0F    ;0F prefix on this guy?
  312.     jz    no386p                ;nope
  313.     mov    al,0fh                ;else stash the 0F
  314.     stosb                    ;into the buffer
  315. no386p:
  316.  
  317. ;The syntax here works, but it can be clarified a little. opcode.operands
  318. ;was never explicitly written to.  Instead, we build a table of pointers
  319. ;into a table of opcode structures. SI contains one of the pointers out
  320. ;of that table. Maybe it's just because I'm more used to it, but I prefer
  321. ;the MASM syntax to indicate this:
  322. ;    mov    al,(opcode ptr [si]).operands
  323.  
  324.     mov    al,[si+opcode.operands]        ;get addressing mode
  325.     push    0                ;TableDispatch calls this subkey
  326.     call    TableDispatch            ;and dispatch it
  327.     dw    58                ;length of table
  328.  
  329.     dw    AOP0,  AOP1,  AOP2,  AOP3,  AOP4,  AOP5,  AOP6,  AOP7
  330.     dw    AOP8,  AOP9,  AOP10, AOP11, AOP12, AOP13, AOP14, AOP15
  331.     dw    AOP16, AOP17, AOP18, AOP19, AOP20, AOP21, AOP22, AOP23
  332.     dw    AOP24, AOP25, AOP26, AOP27, AOP28, AOP29, AOP30, AOP31
  333.     dw    AOP32, AOP33, AOP34, AOP35, AOP36, AOP37, AOP38, AOP39
  334.     dw    AOP40, AOP41, AOP42, AOP43, AOP44, AOP45, AOP46, AOP47
  335.     dw    AOP48, aop49, aop50, AOP51, AOP52, AOP53, AOP54, AOP55
  336.     dw    AOP56, AOP57, AOP58
  337.     ret
  338. oneasm    ENDP
  339.  
  340. ;
  341. ; inserts prefixes into buffer
  342. ;
  343. ;INPUT: ES:DI points to buffer
  344. ;OUTPUT: all prefixes inserted and DI updated
  345. ;
  346. ;
  347. ; first comes th 386 prefixes
  348.  
  349. InsertPrefixes    PROC
  350.     sub    dx,dx
  351.     test    [PrefixBitmapWord],AS_OPSIZE    ;see if 66 override
  352.     jz    nopsiz
  353.     mov    al,66h
  354.     stosb
  355. nopsiz:
  356.     test    [PrefixBitmapWord],AS_ADDRSIZE    ;see if 67 override
  357.     jz    naddrsiz
  358.     mov    al,67h
  359.     stosb
  360.  
  361. naddrsiz:
  362. ;
  363. ; now we do segment overrid prefixes by scanning the prefix bitmap
  364. ; word
  365.     sub    dx,dx            ;start with no override byte count
  366.     mov    dh,byte ptr [PrefixBitmapWord]    ;get prefix bitmap lo byte
  367.     mov    bx,offset SegmentPfxBytes    ;list of prefix bytes
  368.     mov    cx,SEGPFXLISTSIZE        ;there are 6 of these
  369.  
  370. sl2:
  371.     shr    dh,1            ;see if this one required
  372.     jnc    nsl2            ; no, skip
  373.     mov    al,[bx]            ; else load the prefix from the table
  374.     stosb                ; save it
  375.     inc    dx            ; increment prefix count
  376. nsl2:
  377.     inc    bx            ; point to next prefix
  378.     loop    sl2            ; next prefix
  379.     
  380.     cmp    dl,2            ;count of segment prefixes added
  381.     jb    lpnerr            ;can't exceed 1
  382.     stc
  383.     ret
  384. lpnerr:
  385. ;
  386. ; now we do the remainder of the 8086 repeate and lock prefixes
  387. ;
  388.     test    RepPfxBitmap,AF_LOCK    ;see if lock set
  389.     jz    nlock            ;nope, no lock
  390.     mov    al,0f0h            ;else stash lock prefix
  391.     stosb
  392. nlock:
  393.     test    RepPfxBitmap,AF_REPNE OR AF_REP    ;see if REPNE set
  394.     jz    nrepne            ; nope, no REPNE
  395.     mov    al,0f2h            ;stick in repne prefix
  396.     stosb
  397. nrepne:
  398.     test    RepPfxBitmap,AF_REPE    ; See if REPE
  399.     jz    nrepe            ; noe, no repe
  400.     mov    al,0f3h            ;stick in repe prefix
  401.     stosb
  402. nrepe:
  403.     clc
  404.     ret
  405. InsertPrefixes    ENDP
  406. ;
  407. ; routine displays error if operands are mismatched
  408. ;
  409. ; INPUT: none
  410. ; OUTPUT: message displayed
  411. operr    PROC
  412.     call    printAlignedErrorMsg
  413.     db    "Unusable operand combination",0
  414.     stc
  415.     ret
  416. operr    ENDP
  417. ;
  418. ; check for size mismatches and get a size.
  419. ; INPUT: SI points to user's input buffer/
  420. ; OK, a little bit of clarification has happened on this one, thankfully.
  421. ;  Turns out that opcodes fall into several categories with respect to this
  422. ; routine. In general, for any opcode with more than one operand, all
  423. ; subsequent operands must match one another in size except for the
  424. ; exceptions. The exceptions to be permitted are:
  425. ;    1) movzx and movsx, which by definition have mismatched operands
  426. ;    2) In and Out instructions, where DX holds the port, and we can
  427. ;       read or write any size operand through that port
  428. ;    3) SHR,SAR,SHL,SAL,RCR,RCL CL, since any size operand can be shifted 
  429. ;       by CL bits
  430. ;    4) Immediate operands, which can be smaller but not larger than
  431. ;       their targets
  432. ;    5) Memory, if sizes to any memory mode are given they must match
  433. ;       the rest of the arguments.
  434. ;
  435.  
  436. validops    PROC
  437.     cmp    lastbyte,"x"         ;if movzx or movsx
  438.     je    vox            ;then this is OK
  439.  
  440.  
  441. ;OK, the logic here is really hosed. What it is supposed to say is this:
  442. ;IF any operand is provided
  443. ;    IF more than one operand
  444. ;        IF all operands are not equal in size
  445. ;            IF not an allowed exception
  446. ;                THEN error
  447. ;            ELSE OK
  448. ;        ELSE OK
  449. ;    ELSE OK
  450. ;ELSE OK
  451.  
  452. ;The problem here appears to be, immediates have size 0 unless they are
  453. ;prefixed with byte ptr, word ptr, etc.  So for example, any size operand
  454. ;can be stuck into [44], like AL, AX, or EAX.  Furthermore, it was a
  455. ;conscious design decision that mov al,FFFF is allowed as an editing
  456. ;function. That is, you can enter as many hex digits as you want, if
  457. ; the number is too big then digits on the left are truncated.  This
  458. ; allows changing the number without using the backspace key.
  459.  
  460.  
  461. chsize:                    ; collect a size
  462.     mov    al,arg1.asize        ;see if first arg size is 0
  463.     or    al,al            ;used later, so load into AL
  464.     jnz    szch            ;if non0 size, more checking
  465.     mov    al,arg2.asize        ;else load up size of 2d arg
  466.     or    al,al            ;used again
  467.     jnz    szch            ;if non0, keep checking?
  468.     mov    al,arg3.asize        ;check size of final arg
  469.     or    al,al
  470.     jnz    szch            ;if it has non0 size
  471.     clc                ; no size, let it go
  472.     ret
  473. szch:
  474.     test    arg1.asize,0FFh        ;if arg1 has a size
  475.     jz    noa1            ;
  476.     cmp    al,arg1.asize        ;it must match the collected size
  477.     jnz    absx            ; or check for special cases
  478. noa1:
  479.     test    arg2.asize,0FFh        ; if arg2 has a size
  480.     jz    noa2            
  481.     cmp    al,arg2.asize        ; it must match the collected size
  482.     jne    absx              ; or we check for special cases
  483. noa2:    
  484. ;Near as I can tell, we get here if:
  485. ;1) Both arg1.asize and arg2.asize are 0 
  486. ;2) Either or both is nonzero but matches the collected size
  487. ;
  488. ;We have to check the arg3 byte, this is necessary for example in
  489. ; the 386 imul instruction.  If both arg1 and arg2 had no size this
  490. ; extra compare makes no difference as there won't be an arg3 and the
  491. ; size will have been initialized to zero
  492.     test    arg3.asize,0FFh        ; if arg3 has a size
  493.     jz    finalsize
  494.     cmp    al,arg3.asize        ; it must match the collect size
  495.     jne    absx            ; or we check for special cases
  496. finalsize:
  497.     call    setsize            ;set the size we found in all ops
  498.     jmp    chimmsize        ;chk immediates and based addressing
  499. ;
  500. ; get here on size mismatch, must check for special cases
  501. ;
  502. absx:
  503.     mov    eax,dword ptr [EnteredMnemonic] ; get ASCII for mnemonic
  504.     and    eax,0ffffffh
  505.     cmp    eax,"tuo"        ; out?
  506.     je    vox            ; yes, no size error
  507.     cmp    ax,"ni"            ; in?
  508.     je    vox            ; yes, no size error
  509.     mov    di,offset arg2        ; is arg2 cl?
  510.     call    chkcl            ;
  511.     jz    vox                     ; yes, no size error
  512.     mov    di,offset arg3        ; is arg3 cl?
  513.     call    chkcl
  514.     jz    vox
  515.     call    printAlignedErrorMsg    ; otherwise print an error and get out
  516.     db    "Bad size",0
  517.     stc
  518. vox:
  519.     ret
  520. ;
  521. ; get here if we had an immediate, must check sizing
  522. ;
  523. chimmsize:
  524.          mov    di,offset arg1
  525.     call    immsize            ;see if immediate that will fit
  526.     jc    vox            ;nope, won't fit
  527.     call    chkbase            ;else chk for valid based addressing
  528.     jc    vox            ;not valid
  529.          mov    di,offset arg2        ;
  530.     call    immsize            ; see if immed that will fit
  531.     jc    vox                 ; nope, won't fit
  532.     call    chkbase            ; check for valid based mode
  533.     jc    vox            ; not valid
  534.          mov    di,offset arg3
  535.     call    immsize            ; see if immed that will fit
  536.     jc    vox            ; nope, won't fit
  537.     call    chkbase            ; check for valid based mode
  538.     jc    vox            ; not valid
  539.     ret
  540. validops    ENDP
  541.  
  542.  
  543. ;One of the allowed exceptions is a shift or rotate of a register exceeding
  544. ;8 bits by CL, which is 8 bits.  Here we check for that CL, and allow the
  545. ;exception if we find it
  546. ;INPUT: DI points to this structure
  547. ;OUTPUT: ZF if we found CL, NZ if we didn't
  548.  
  549. chkcl    PROC
  550.     cmp    [di+asmop.mode],AM_REG    ; check if register involved
  551.     jne    cclerr            ; if not, can't be CL
  552.     cmp    arg2.areg1,isECX    ; else see if ECX involved at all
  553.     jne    cclerr            ; if not, can't be CL
  554.     cmp    arg2.asize,BYTESIZE    ; if ECX is byte, must be CL
  555. cclerr:
  556.     ret
  557. chkcl    ENDP
  558.  
  559.  
  560. ;INPUT: AL is an argument size 1=byte, 2=word, 4=dword
  561. ;    EnteredMnemonic is a bucket containing what the user typed
  562. ;    PrefixBitmapWord containing a bit for each type of prefix allowed.
  563. ;        AS_OPSIZE is for operand size override prefix OS:, which
  564. ;        means stick in a 66h
  565. ;    arg1,2, and 3 are instances of structure ASMOP. asize is the size
  566. ;        of the operand.  An instruction can have up to 3 operands
  567. ; What we do here is set the passed size as the size of all 3 operands,
  568. ; setting the 66 override if dword size (and not FP), and returning ZF
  569. ; if it was a dword, and NZ if it was not
  570.  
  571. setsize    PROC
  572.     cmp    al,DWORDSIZE            ; is it a dword?
  573.     jne    ssnoop                ; no, no opsize checking
  574.     cmp    byte ptr [EnteredMnemonic],'f'    ; floating point instruction?
  575.     je    ssnoop                ; yes, no opsize prefix
  576.     or    [PrefixBitmapWord],AS_OPSIZE    ;include 'OS:' prefix
  577. ssnoop:
  578.     mov    arg1.asize,al            ;set all sizes the same
  579.     mov    arg2.asize,al
  580.     mov    arg3.asize,al
  581.     cmp    arg1.asize,DWORDSIZE        ;rtn NZ if NOT a dword
  582.     clc
  583.     ret
  584. setsize    ENDP
  585. ;
  586. ; Check the size of an immediate
  587. ;
  588. ;INPUT: DI points to structure built for this instruction
  589. ;    AL contains size of first argument
  590. ;If immediate operand, make sure that the size of the argument passed in
  591. ;AL is valid. Apparently an immediate dword is always OK, but it is necessary
  592. ;in that case to set a bit indicating the operand size prefix, 
  593. ;Otherwise, in cases of byte or word, it is necessary to make sure that
  594. ;the target offset (or segment if seg:ofs) does not exceed the immediate
  595. ;value in size.  This is not nearly well enough understood to draw any
  596. ;conclusions yet.
  597. ;  My guess is that if we have something like mov eax, immediate, then any
  598. ;immediate is OK.  If it is mov ax, immediate, then the value to be moved in
  599. ;must be a byte or word. Finally, if mov al, immediate, then the immediate
  600. ;value must be a byte
  601. ;OUTPUT: NC if immediate operand will fit in target, CY if not.
  602.  
  603. immsize    PROC
  604.     cmp    [di+asmop.mode],AM_IMM        ;see if immediate value
  605.     clc                    ;assume not
  606.     jne    immok                ;and if not, we're OK
  607.     cmp    al,DWORDSIZE            ;else chk for dword size
  608.     jae    immokl                ;go if AL >=4 (dword)
  609.     cmp    al,WORDSIZE            ;else if AL is word size
  610.     clc                    ;assume it is
  611.     jne    bytech                ;if not, go chk byte offset
  612.     test    [di+asmop.addrx],0ffff0000h    ;else test for word offset
  613.     jz    immok                ;if so, we're ok
  614.     stc                    ;else error
  615. immok:
  616.     ret
  617. immokl:
  618.     or    [PrefixBitmapWord],AS_OPSIZE    ;set this
  619.     ret
  620. bytech:
  621.     test    [di+asmop.addrx],0ffffff00h    ;test for byte offset
  622.     jz    immok                ;OK if byte
  623.     stc                    ;else error
  624.     ret
  625. immsize    ENDP
  626.  
  627. ;
  628. ; subroutine to verify that a based/indexed mode has a correct
  629. ; register combination
  630. ;
  631. ; INPUT: DI = pointer to operand (asmop) structure
  632. ; OUPUT: CY set on error, clear if ok
  633. ;
  634. chkbase    PROC
  635.     cmp    [di+asmop.mode],AM_BASED    ;is it base+something?
  636.     jne    cbxnb                ;if not, get out
  637.     cmp    [di+asmop.msize],BYTEMODE    ;see if byte-mode addressing
  638.     je    cberr                ;no can do this
  639.     cmp    [di+asmop.msize],DWORDMODE    ;how about dword?
  640.     je    cb32                ;go check 32-bit addressing
  641. ;
  642. ; if we get here we have 16-bit addressing.  No scale factors allowed.
  643.  
  644.     cmp    [di+asmop.ascale],TIMES1    ;check scale factor against 1
  645.     jne    cberr                ;error if not 1
  646.     cmp    [di+asmop.areg1],isESP        ;check for sp
  647.     je    cberr                ;error if trying to index off sp
  648.  
  649.     cmp    [di+asmop.areg1],isEBX        ;Carry clear if eax,ecx,edx
  650.     jb    cberr                ;error if trying to index off those
  651.  
  652. ;areg2 is any second register (like [bx+si+nnnn]
  653.  
  654.     cmp    [di+asmop.areg2],0FFh        ;any second register
  655.  
  656. ;A table is emerging from the following.  It tells us:
  657. ;
  658.  
  659.     je    cbx                ;didn't get to second base
  660.     cmp    [di+asmop.areg2],isESP        ;is 2d base ESP
  661.     je    cberr                ;if so, illegal
  662.     cmp    [di+asmop.areg2],isEBX        ;compare with EBX value
  663.     jb    cberr                ;error is ax,cx,dx
  664.     cmp    [di+asmop.areg1],isESI        ;compare with ESI
  665.     jae    cbdown                ;ok for  si,di
  666. cbup:
  667.     cmp    [di+asmop.areg2],isESI        ; check second if si or di
  668.     jz    cbx                ; ok if so
  669.     jmp    cberr                ;err if anything else
  670.  
  671. ;
  672. ; we got here if the first arg is si/di, in which case the second arg
  673. ; must be bx or bp
  674.  
  675. cbdown:
  676.     cmp    [di+asmop.areg2],isESI        ;if bx or bp
  677.     jb    cbx                ;we're OK
  678.  
  679. ;Errors go here. By implication, these errors are:
  680. ;1) using ESP at all for a base register
  681. ;2) using EAX, ECX or EDX as a base register
  682. ;3) using a register combo other than [si + bx] [si + bp] [di + bx] [di+bp]
  683.  
  684. cberr:
  685.     call    printAlignedErrorMsg
  686.     db    "Invalid base or index register",0
  687.     stc
  688.     ret
  689.  
  690. ;
  691. ; we get here if we have a 32-bit address mode with based addressing
  692. ;
  693.  
  694. cb32:
  695.     test    [Disassemble32Bit],TRUE        ;dwords allowed at all?
  696.     jz    cberr                ;if not, bomb
  697.     or    [PrefixBitmapWord],AS_ADDRSIZE    ;else set addrsize prefix
  698.     cmp    [di+asmop.areg1],isEBP        ;see if EBP is first reg
  699.     jne    cb32n2bp            ;skip if not
  700.     cmp    [ di+asmop.areg2],isEBP        ;else if second is EBP
  701.     je    cberr                ;that's an error
  702. cb32n2bp:
  703.     cmp    [di+asmop.areg2],isESP        ;check for [exx + esp]
  704.     jne    cbx                ; if not, accept it
  705.     cmp    [di+asmop.ascale],TIMES1    ; else check for a scale factor
  706.     jne    cberr                ; error if not 1
  707. cbx:
  708.     push    ax
  709.     mov    al,[di+asmop.areg1]
  710.  
  711. ;
  712. ; now we have to figure out whether DS or SS is the default segment
  713.  
  714.     and    al,6        ; turn ebp into esp
  715.     cmp    al,isESP    ; is esp or ebp?
  716.     jne    cbx1        ; no
  717.     mov    DefaultSeg,2    ; else default to sseg
  718. cbx1:
  719.     mov    al,[di+asmop.areg2]
  720.  
  721.     and    al,6            ; turn ebp into esp
  722.     cmp    al,isESP    ; is esp or ebp?
  723.     jne    cbxnb        ; no
  724.     mov    DefaultSeg,2    ; else default to sseg
  725. cbxnb:
  726.     pop    ax
  727.  
  728.     clc
  729.     ret
  730. chkbase    ENDP
  731.  
  732.  
  733. ; print out error message
  734. ; INPUT: The error message is embedded in the code immediately following the
  735. ;    call to printAlignedErrorMsg
  736. ;
  737. ; this allows 32 characters for the input string.  It tabs the error
  738. ; message over to 32 columns beyond the first column of input.  If the
  739. ; input took more than 32 characters the error message cannot be aligned
  740. ; and is just tagged right after the input.
  741.  
  742. printAlignedErrorMsg    proc
  743.     mov    cx,0FFFFh    ;search a segment worth
  744.     mov    di,offset inputbuffer    ;in buffer
  745.     mov    al,13        ;for a CR
  746.     repne    scasb        ;find it
  747.     add    cx,32        ; space to line up errs
  748.     jcxz    nospace
  749.     jns    ok
  750.     mov    cx,1        ;if can't align, use single space
  751. ok:
  752.     call    printspace
  753.     loop    ok
  754. nospace:
  755.     PRINT_MESSAGE    "??? "
  756.     jmp    PrintFollowingMessage
  757. printAlignedErrorMsg    ENDP
  758. ;
  759. ; get the opcode and scan the tables for it
  760. ;
  761. ;
  762. getcode    PROC
  763.     mov    RepPfxBitmap,0    ;No Reps/locks found
  764. getcode3:
  765.     mov    di,offset EnteredMnemonic    ;point to mnemonic buffer
  766. getcode2:
  767.     lodsb            ;get input character
  768.     cmp    al,' '        ;see if space or below
  769.     jbe    nomore        ;if so, done, don't store
  770.     stosb            ;else store it
  771.     cmp    al,':'        ;was it a colon?
  772.     je    nomore2        ;if so, ignore it and end the name
  773.     jmp    getcode2
  774. nomore:
  775.     dec    si                  ; all done, backtrack
  776. nomore2:
  777.     mov    ah,[di-1]          ;get last char we stuffed in buffer
  778.     mov    [lastbyte],ah    ; last byte is used by some commands
  779.                 ; string &c
  780.     mov    al,0        ; store the trailer
  781.     stosb
  782.     push    si        ;save where we left off in input string
  783.     mov    si,offset EnteredMnemonic    ;point to buffer we just stuffed
  784.     call    strlen        ; length of name in buffer into AX
  785.     inc    ax        ; plus trailer
  786.     mov    si,offset EnteredMnemonic    ; check for repeats and lock
  787.     mov    di,offset say_repne    ;actual string 'repne'
  788.     mov    cx,ax        ;length to compare
  789.     repe    cmpsb        ;see if a match, lowercase
  790.     mov    bl,AF_REPNE    ;this is 2
  791.     jz    reps        ;if a match, go to reps to stuff in RepPfxBitmap
  792.     mov    si,offset EnteredMnemonic    ;else lets look for repe
  793.     mov    di,offset say_repe
  794.     mov    cx,ax
  795.     repe    cmpsb
  796.     mov    bl,AF_REPE    ;this is 4
  797.     jz    reps
  798.     mov    si,offset EnteredMnemonic
  799.     mov    di,offset say_rep    ;just look for rep
  800.     mov    cx,ax
  801.     repe    cmpsb
  802.     mov    bl,AF_REP    ;this is 1
  803.     jz    reps
  804.     mov    si,offset EnteredMnemonic    
  805.     mov    di,offset say_lock    ;look for lock
  806.     mov    cx,ax
  807.     repe    cmpsb
  808.     mov    bl,AF_LOCK    ;this is 8
  809.     jz    reps
  810.     cmp    ax,4        ;is the length 4 (including 0-terminator?)
  811.     jnz    npf        ;if not, go look it up
  812.     cmp    [EnteredMnemonic+2],':'    ;else maybe segment override, so check colon
  813.     jne    npf        ;not a colon, so go look it up
  814.     mov    ax,word ptr [EnteredMnemonic]    ;else, get 1st 2 chars in AX
  815.     mov    di,offset OverridePfxList    ;point to string of possible prefixes
  816.     mov    cx,8        ;there are 8, 2 of which I've never heard of
  817.     repne    scasw        ;see if any match
  818.     jnz    npf        ;if not, go look it up the hard way
  819.     bts    [PrefixBitmapWord],cx    ;set prefix word bit for this prefix
  820.     pop    si        ;back to our input line
  821.     call    WadeSpace    ;find next string
  822.     jnz    getcode3    ;got one, so start over
  823.     stc            ;else we failed???
  824.     ret
  825. npf:
  826.     mov    si,offset EnteredMnemonic    ;point to buffer containing instruction
  827.     call    LookupOpName    ;and go look it up
  828.     pop    si        ;restore SI ptr to next input
  829.     jc    gcx        ; get out if nonexistant
  830.     call    WadeSpace    ; see if any more...
  831. gcx:
  832.     ret
  833. reps:
  834.     pop    si        ;restore pointer to input
  835.     or    RepPfxBitmap,bl    ;set bitmap for rep prefix found
  836.     call    WadeSpace    ;find next
  837.     jnz    getcode3    ;if more, parse that
  838.     stc            ;else invalid - something must follow rep
  839.     ret
  840. getcode    ENDP
  841. ;
  842. ; get an operand
  843. ;
  844. ; INPUT: DI points to asmop structure for this arg
  845. ;    SI points to input buffer past opcode string
  846. ; OUTPUT: CY if arg is invalid
  847. ; PROCESSING:
  848. ;    1) init asmop structure
  849. ;
  850. parsearg    PROC
  851.     mov    [di+asmop.asize],NOSIZE
  852.     mov    [di+asmop.areg1],0FFh
  853.     mov    [di+asmop.areg2],0FFh
  854.     mov    [di+asmop.ascale],1
  855.     mov    [di+asmop.addrx],0
  856.     mov    [di+asmop.mode],AM_NONE
  857.     mov    [di+asmop.msize],0
  858.     call    wadespace              ;see if any more???
  859.     jz    gax             ; comma taken care of by wadespace
  860.     cmp    byte ptr [si],'['    ;see if opening an indirect addr
  861.     je    getbrack        ;if so, look for contents
  862.     call    parsecontrol        ;else chk for control register
  863.     jc    gax            ;error, bad ctrl reg
  864.     jz    gaxc            ;good ctrol reg, we got it
  865.     call    parsesize        ;set width, 1-10
  866.     jc    gax            ;bad width, bomb
  867.     jz    getbrack        ;else found width, get inside bracket
  868.     call    parseseg        ;else check for segment arg
  869.     jc    gax            ;bad seg arg
  870.     jz    gaxc            ;if good one, find more
  871.     js    getbrack        ;if SF, seg is inside brackets
  872.     call    parsereg        ;so find register
  873.     jz    gaxc            ;got it, find mire
  874.     mov    [di+asmop.mode],AM_NONE    ;assume it is just a number
  875.     call    parseval        ;look for an immediate
  876.     jc    gax            ;nope, bomb
  877.     mov    [di+asmop.mode],AM_IMM    ;else say it is an immediate
  878.     mov    [di+asmop.addrx],ebx    ;so save that
  879.     call    wadespace          ;find next
  880.     cmp    al,':'            ;a colon?
  881.     jnz    gaxc            ;if not, done
  882.     inc    si            ;else move past colon
  883.     call    parseval        ;and get target value
  884.     jc    gax            ;sorry, no value found
  885.     mov    [di+asmop.addrx2],ebx    ;else stash the value in addrx2
  886.  
  887. ;Aha, I think I dig. This flag indicates that addrx1 contains a segment
  888. ;value and addrx2 has the offset.  If this flag is clear, addrx1 has an
  889. ;offset and addrx2 is inoperative.
  890.  
  891.     mov    [di+asmop.mode],AM_SEGOFFS    ;set flag
  892. gaxc:
  893.     call    WadeSpace
  894.     clc
  895. gax:
  896.     ret
  897.  
  898. ;Handle the case where we have something in brackets.
  899. ;SI points to the opening bracket character
  900.  
  901.  
  902. getbrack:
  903.     lodsb            ;consume the bracket
  904.     mov    al,[di+asmop.areg1] ;see if any segment reg
  905.     cmp    al,0ffh
  906.     jz    brklp        ; none
  907.     mov    [di + asmop.areg1],0ffh ; set it back
  908.     sub    ah,ah
  909.     bts    [PrefixBitmapWord],ax    ; set the prefix bit
  910. brklp:
  911.     call    wadespace    ;get next string
  912.     jz    brackerr    ;found CR before closing bracket
  913.     cmp    al,'+'        ;see if plus sign
  914.     jne    brnp        ;might mean bracket-not-plus
  915.     inc    si        ;else move past plus sign
  916.     call    wadespace    ;and find next
  917.     jz    brackerr    ;oops, no closing bracket
  918.  
  919. ;We have ignored any plus sign if it was there
  920.  
  921. brnp:
  922.     cmp    al,'-'        ;is it a minus sign?
  923.     je    brmem        ;if so, must be a value?
  924.     cmp    al,']'        ;if not, closing bracket already?
  925.     je    brackx        ;if so, go exit
  926.     push    di        ;save pointer to buffer
  927.     mov    di,offset arg4    ;point to arg4 for base-mode reg gathering
  928.     call    parsereg    ;see if a register?
  929.     pop    di        ;restore buffer pointer
  930.  
  931. ;parsereg cannot return CY, and does no bracket check anyway. No idea why 
  932. ;this line is even here
  933.  
  934.     jc    brackerr    ; if invalid fp or CRDRTR reg num
  935.     jz    brreg        ;ZF means we found a register
  936. brmem:
  937.     call    parseval        ;glom a number into EBX
  938.     jc    brackerr        ;get out if no number
  939.     add    [di+asmop.addrx],ebx    ;stick in as offset or segment
  940.     call    WadeSpace        ;get next
  941.     jz    brackerr        ;still no closing bracket
  942.     jmp    brklp            ;else get next bracket value
  943.  
  944. ;We get here if we found a named register inside the brackets, like [bx
  945.  
  946. brreg:
  947.     mov    [di+asmop.mode],AM_BASED    ;say base reg involved
  948.     mov    ah,[arg4.areg1]        ;get which register it is
  949.     mov    bl,[arg4.asize]        ;and width of register
  950.     test    [di+asmop.msize],0FFh    ;see if anything assigned yet
  951.     jz    notszyet        ;nope, not yet
  952.     cmp    [di+asmop.msize],bl    ;ok, bl is the size
  953.     jnz    brackerr        ;mismatch, I guess???
  954. notszyet:
  955.     mov    [di+asmop.msize],bl    ;else set the size
  956.     call    WadeSpace
  957.     cmp    al,'*'            ;multiply operation
  958.     jne    notscale        ;nope, no scaling
  959.     cmp    bl,DWORDSIZE        ;else dword scaling?
  960.     jne    brackerr        ;must be dword reg for multiply?
  961.     inc    si            ;move past *
  962.     call    WadeSpace        ;find next
  963.     sub    al,'0'            ;last char returned, cvt to decimal?
  964.     cmp    al,TIMES1        ;*1 is OK
  965.     je    brackok1
  966.     cmp    al,TIMES2        ;*2 is OK
  967.     je    brackok1
  968.     cmp    al,TIMES4        ;*4 is OK
  969.     je    brackok1
  970.     cmp    al,TIMES8        ;*8 is OK
  971.     jne    brackerr        ;else, can't do it
  972. brackok1:
  973.     inc    si            ;bump SI past scaling factor
  974.     mov    byte ptr [di+asmop.ascale],al    ;and set factor in struct
  975. reg2x:
  976.     test    [di+asmop.areg2],0FFh    ;initialized to FF
  977.     jns    brackerr        ;so bit 7 better be set
  978.     mov    [di+asmop.areg2],ah    ;if so stick areg1=reg into it
  979.     jmp    brklp            ;get next thing inside brackets
  980.  
  981. ;Found a register that was NOT followed by a scaling factor. The magic code
  982. ;for the found register is in AH. We stick this register into areg1 unless
  983. ;areg1 is already in use, in which case we stick it in areg2.
  984.  
  985. notscale:
  986.     test    [di+asmop.areg1],0FFh    ;has reg been assigned yet?
  987.     jns    reg2x            ;if not, stick reg into areg2
  988.     mov    [di+asmop.areg1],ah    ;else, stick reg into areg1
  989.     jmp    brklp
  990.  
  991. ;OK, we found the closing bracket.  Presumably everything between brackets
  992. ;was kosher. We also get here with the construct [], with nothing in there.
  993.  
  994. brackx:
  995.     cmp    [di+asmop.msize],DWORDMODE    ;addressing mode size=32?
  996.     jne    brackn32            ;if not, skip
  997.     or    [PrefixBitmapWord],AS_ADDRSIZE    ;else set addrsize prefix flag
  998. brackn32:
  999.     inc    si                ;move past ]
  1000.     cmp    [di+asmop.mode],AM_NONE        ;see if empty
  1001.     Jne    gaxc                ;if not, cool
  1002.     mov    [di+asmop.mode],AM_MEM        ;else set mode to memory
  1003.     mov    [di+asmop.msize],WORDMODE    ;see if word mode
  1004.     test    [di+asmop.addrx],NOT 0FFFFH    ;see if any address
  1005.     jz    gaxc                ;if not, skip out
  1006.     or    [PrefixBitmapWord],AS_ADDRSIZE    ;else set for ???
  1007.     mov    [di+asmop.msize],DWORDMODE    ;and say dword assumed??
  1008.     jmp    gaxc                ;and jmp
  1009. brackerr:
  1010.     stc
  1011.     ret
  1012. parsearg    ENDP
  1013.  
  1014. ; Parse possible control register reference
  1015. ;
  1016. ; INPUT: SI points to buffer containing this argument (a string)
  1017. ; OUTPUT: For this arg, the mode and areg1 fields of the structure are
  1018. ;    filled in.
  1019. ;    NZ if we can't recognize the register
  1020. ;    CY if index for register is out of range
  1021. ; PROCESSING: Look for any control reg, debug reg, FP reg or TR reg. The
  1022. ;    TR regs are the Appendix H test registers.
  1023. ;        Beyond this, we allow up to 8 of each of the ST, CR and DR
  1024. ;    even though there is no DR1 or DR2, nor any CR4,5,6 or 7. I guess
  1025. ;    these exist in opcode space, just not in the CPU!
  1026. ;
  1027. parsecontrol    PROC
  1028.     mov    ax,word ptr [si]
  1029.     mov    cl,AM_CR
  1030.     cmp    ax,"rc"            ;Control register CRx
  1031.     je    gotcontrol
  1032.     mov    cl,AM_DR
  1033.     cmp    ax,"rd"            ;Debug register DRx
  1034.     je    gotcontrol
  1035.     mov    cl,AM_TR
  1036.     cmp    ax,"rt"            ;Test registers, Appendix H
  1037.     je    gotcontrol
  1038.     cmp    ax,"ts"            ;ST(x for FP
  1039.     je    gotfpreg
  1040.     or    al,1
  1041.     ret
  1042.  
  1043. ;Um. There are 8 each of the debug registers and FP stack registers, although
  1044. ;DR1 and DR2 don't exist.  There are only 4 control registers, and I can't
  1045. ;find any reference at all to any TRx registers.
  1046.  
  1047.  
  1048. gotcontrol:
  1049.     lodsw                ;grab control reg 1st 2 chars
  1050.     lodsb                ;and number
  1051.     sub    al,'0'            ;convert to binary
  1052.     jc    gcerrx            ;oops, below 0
  1053.     cmp    al,8            ;see if register 8 or above
  1054.     jae    gcerrx            ;error if so
  1055.     mov    [di+asmop.mode],cl    ;save CL 
  1056.     mov    [di+asmop.areg1],al    ;save which one
  1057.     sub    ax,ax            ;set ZF
  1058.     ret
  1059. gcerrx:
  1060.     stc     
  1061.     ret
  1062. gotfpreg:
  1063.     lodsw                ;consume the 'ST'
  1064.     call    wadespace        ;find next 
  1065.     cmp    al,'('            ;is it (
  1066.     jne    asmgotch        ;if not, check for NASM syntax
  1067.     inc    si            ;bump past (
  1068.     call    wadespace        ;find next
  1069.     push    ax            ;stack the char found
  1070.     inc    si            ;move past it
  1071.     call    wadespace        ;find the next
  1072.     cmp    al,')'            ;end of stack reference?
  1073.     pop    ax            ;restore char between ()
  1074.     jne    badfpreg        ;no close, so bitch
  1075.  
  1076. ;We get here in two cases: we found (x), or we didn't find (
  1077. ;In the first case, x is in AL, in the second, AL has what we found instead
  1078. ;By implication, we accept either ST(x) or STx
  1079.  
  1080. asmgotch:
  1081.     inc    si            ;move to next position anyway
  1082.     sub    al,'0'            ;convert to binary
  1083.     jc    badfpreg        ;must be some number
  1084.     cmp    al,8            ;else see if in range
  1085.     jae    badfpreg        ;if >=8, out of range
  1086.     mov    [di+asmop.mode],AM_FPREG    ;set flag for FP
  1087.     mov    [di+asmop.areg1],al    ;save binary value of this reg
  1088.     sub    ax,ax            ;and return ZF
  1089.     ret
  1090. badfpreg:
  1091.     stc
  1092.     ret
  1093. parsecontrol    ENDP
  1094.  
  1095.  
  1096. ;
  1097. ; parse a size attribute.  the PTR keyword is optional.
  1098. ;
  1099. ; INPUT: SI points to buffer containing this argument (a string)
  1100. ; OUTPUT: bl has size
  1101. ;         CY set if error ins size
  1102. parsesize    PROC
  1103.     mov    ax,[PrefixBitmapWord]    ;get bitmap into AX
  1104.     call    isbyte            ;chk buffer for 'byte'
  1105.     mov    bl,BYTESIZE        ;assume byte size
  1106.     jz    gotsize            ;if match, fine
  1107.     call    isword            ;else chk for word
  1108.     mov    bl,WORDSIZE        ;assume it was
  1109.     jz    gotsize            ;if so, fine
  1110.     inc    si            ;go past first char (could be t)
  1111.     call    isbyte            ;and check if it was 'tbyte'
  1112.     jnz    notbyte            ;if not, really not a byte
  1113.     cmp    byte ptr [si-1],'t'    ;else, was it a t
  1114.     mov    bl,TBYTESIZE        ;assume it was a tbyte
  1115.     jz    gotsize            ;yes, it was
  1116.     or    bl,bl            ;else return NZ
  1117.     ret
  1118.  
  1119. ;OK, it's not 'byte', 'word' or 'tbyte'. Maybe it's 'dword'. To get here,
  1120. ;SI has been moved past the first char, so see if it is dword, qword'or fword
  1121.  
  1122. notbyte:
  1123.     call    isword            ;check for xword
  1124.     jnz    notsize            ;nope, not it
  1125.     mov    al,[si-1]        ;else get that x
  1126.     cmp    al,'d'            ;was it dword
  1127.     mov    bl,DWORDSIZE        ;assume it was
  1128.     je    gotsize            ;yep, got it
  1129.     cmp    al,'q'            ;was it qword
  1130.     mov    bl,QWORDSIZE        ;assume it was
  1131.     je    gotsize            ;yep, that's it
  1132.     cmp    al,'f'            ;how about fword
  1133.     mov    bl,FWORDSIZE        ;assume that
  1134.     je    gotsize            ;yes
  1135. notsize:
  1136.     dec    si            ;back to beginning of string
  1137.     or    bl,1            ;set NZ
  1138.     ret
  1139. gotsize:
  1140.     mov    [di+asmop.asize],bl    ;set requested size
  1141.     add    si,4            ;move past string in buffer
  1142.  
  1143. ;By implication here, it is legal to type 'ptr' as many times as you want.
  1144. ;You can say mov word ptr ptr ptr ptr ptr [44],5
  1145.  
  1146. gs2:
  1147.     call    wadespace        ;find next nonspace
  1148.     jz    operrx            ;didn't find, so error
  1149.     cmp    al,'['            ;'ptr' is optional, so chk bracket
  1150.     je    opok            ;if so, fine
  1151.     push    si            ;else look for 'ptr'
  1152.     push    di
  1153.     mov    cx,3
  1154.     mov    di,offset say_ptr
  1155.     repe    cmpsb
  1156.     pop    di
  1157.     pop    si
  1158.     clc
  1159.     jnz    opok            ;if not, we're ok
  1160.     add    si,3            ;else skip wasted 'ptr'
  1161.     jmp    gs2            ;
  1162. operrx:
  1163.     stc
  1164. opok:
  1165.     ret
  1166. parsesize    ENDP
  1167.  
  1168. ; compare input string with 'byte'
  1169. ;
  1170. ; INPUT: SI points to buffer containing this argument (a string)
  1171. ; OUTPUT: ZF if the argument is 'byte' NZ otherwise
  1172. ; PROCESSING: Simply compare
  1173. ; NOTE: AX must be preserved
  1174. ;
  1175. isbyte     PROC
  1176.     push    si
  1177.     push    di
  1178.     mov    cx,4
  1179.     mov    di, offset say_byte
  1180.     repe    cmpsb
  1181.     pop    di
  1182.     pop    si
  1183.     ret
  1184. isbyte    endp
  1185. ;
  1186. ; compare input string with 'word'
  1187. ;
  1188. ; INPUT: SI points to buffer containing this argument (a string)
  1189. ; OUTPUT: ZF if we matched 'word', else NZ
  1190. ; PROCESSING: just compare
  1191. ;    AX cannot be modified
  1192. ;
  1193. isword     PROC
  1194.     push    si
  1195.     push    di
  1196.     mov    cx,4
  1197.     mov    di, offset say_word
  1198.     repe    cmpsb
  1199.     pop    di
  1200.     pop    si
  1201.     ret
  1202. isword    endp
  1203.  
  1204. ;
  1205. ; INPUT: SI points to buffer containing this argument (a string)
  1206. ; OUTPUT: CY if bad segment argument
  1207. ;    ZF if good segment argument on its own
  1208. ;        In this case, mode and size are set
  1209. ;    SF if valid segment is followed by [
  1210. ; PROCESSING: 
  1211. ;    1) See if string matches list of seg names, return NZ if not
  1212. ;    2) See if segment is only arg (like mov ax,cs. If so, return ZF
  1213. ;    3) Else, see if it is seg:[ and if so, return SF
  1214. ;    4) Else return carry, bad segment argument
  1215. ;
  1216. parseseg    PROC
  1217.     mov    cx,6              ;6 possible segments by name
  1218.     push    di            ;save ptr to struct
  1219.     mov    di,offset psegs        ;names of registers
  1220.     lodsw                ;get what user entered
  1221.     repne    scasw            ;find it in the strings list
  1222.     pop    di            ;restore struct ptr
  1223.     jz    gotseg            ;found a match
  1224.     sub    si,2            ;not a seg, undo the lodsw
  1225.     ret                ;return NZ
  1226.  
  1227. ;Here we have a significant departure from debug.exe syntax.  If you want
  1228. ;a segment override in debug, you must put the override like CS: or ES:
  1229. ;on a separate line, and the remainder on the next line.  Debug requires you
  1230. ;to say:
  1231. ;xxxx:xxxx cs:
  1232. ;xxxx:xxxx mov al,[44]
  1233. ;
  1234. ;Here you are NOT allowed to do this.  Instead, you must enter:
  1235. ;xxxx:xxxx mov al,cs:[44]
  1236. ;
  1237. ;an earlier part of the program also accepted:
  1238. ;
  1239. ;xxxx:xxxx cs:mov al,[44]
  1240. ;
  1241.  
  1242. gotseg:
  1243.     sub    cx,6            ;sub starting value
  1244.     not    cx            ;convert to index
  1245.     mov    [di+asmop.areg1],cl    ;save that index in areg1
  1246.     call    wadespace        ;find next non-0
  1247.     jz    segalone        ;if nothing, fine, just seg
  1248.     cmp    al,':'            ;else chk for colon
  1249.     jne    segalone        ;if not, we just got the segment
  1250.     inc    si            ;bump past colon
  1251.     call    wadespace        ;find next stuff
  1252.     jz    segerr            ;nothing else is error
  1253.     cmp    al,'['             ;do we have a fixed address next?
  1254.     jne    segerr            ;if not, real trouble
  1255.     or    al,80h            ;else return SF
  1256.     ret
  1257. segalone:
  1258.     mov    [di+asmop.mode],AM_SEG    ;say mode is just a segment
  1259.     mov    [di+asmop.asize],WORDSIZE    ;so size is 2 (all segregs are word)
  1260.     sub    ax,ax            ;return ZF
  1261.     ret
  1262. segerr:
  1263.     stc                ;error so return CY
  1264.     ret
  1265. parseseg    ENDP
  1266.  
  1267. ;
  1268. ; parse a register name
  1269. ;
  1270. ; INPUT: SI points to input being parsed
  1271. ;    DI points to structure for this argument, or to arg4 if we are
  1272. ;    inside brackets.
  1273. ; OUTPUT: ZF if reg found, and mode and size set
  1274. ;    NZ if not a name
  1275. ; PROCESSING: parse for all register names, set size and mode if found any,
  1276. ;    else return NZ if not found
  1277. ;NOTES:
  1278. ;    1) If a register name was found, SI was bumped past it, else SI
  1279. ;       remained unmodified
  1280. ;    2) At least one caller to this routine checks the carry. I can't
  1281. ;       find anything in here that would set or clear the carry as a
  1282. ;       return value...    
  1283. ;
  1284. parsereg    PROC
  1285.     mov    bl,2            ;set word size
  1286.     cmp    byte ptr [si],'e'    ;is first char an e
  1287.     jne    nextreg            ;if not, fine
  1288.     mov    bl,4            ;else set dword size
  1289.     inc    si            ;and move past the e
  1290. nextreg:
  1291.     lodsw                ;get next 2 bytes
  1292.     mov    cx,16            ;there are 16 2-char strings for regs
  1293.     push    di            ;save di
  1294.     mov    di,offset regs        ;to scan list of reg names
  1295.     repne    scasw
  1296.     pop    di
  1297.     jz    gotreg            ;if ZF, we hit a match
  1298.     sub    si,2            ;else back to beginning of input
  1299.     cmp    bl,4            ;unless we moved past an e
  1300.     jnz    nextreg2        ;if bl=4, we did
  1301.     dec    si            ;so back up to first char
  1302. nextreg2:
  1303.     or    si,si            ;set NZ
  1304.     ret                ;since not a reg
  1305.  
  1306. ;It just so happens that the regs string has 16 2-char entries, the first 8
  1307. ;are byte registers and the last 8 are word registers
  1308.  
  1309. gotreg:
  1310.     xor    cl,15            ;really, how about 0Fh?
  1311.     mov    [di+asmop.asize],BYTESIZE    ;say byte arg
  1312.     cmp    cx,8            ;if found in positions 0-7
  1313.     jb    gr1            ;then it was a byte
  1314.     mov    [di+asmop.asize],bl    ;else word or dword depending on e
  1315. gr1:
  1316.     and    cl,7               ;get mod8 for index
  1317.     mov    [di+asmop.areg1],cl    ;and save that
  1318.     mov    [di+asmop.mode],AM_REG    ;say a reg asked for by name
  1319.     sub    ax,ax            ;return ZF
  1320.     ret
  1321.     
  1322. parsereg    ENDP
  1323. ;
  1324. ; Make sure that the next string is a number, and return in EBX if so
  1325. ;
  1326. ; INPUT: SI points to string to be parsed
  1327. ; OUTPUT: NC if we find a number
  1328. ;    EBX contains that number (0=extended if required)
  1329. ;    CY if not a number, or not found???
  1330. ; PROCESSING: DI points to the argument structure being built, and must
  1331. ;    be preserved.
  1332. ;NOTES: ReadNumber simply assumes that all bytes in the input buffer are
  1333. ;    hex values up to some special character like space, comma, colon
  1334. ;    or CR. So ReadNumber cannot return an error. In this case, we
  1335. ;    already know that we have no named register at [si], which is
  1336. ;    a good thing, because if we did, ReadNumber would return the
  1337. ;    current contents of that logical register.
  1338. ;
  1339. parseval    PROC
  1340.     call    wadespace    ;find arg string
  1341.     jz    noval        ;oops, not there
  1342.     push    di        ;else save location
  1343.     call    ReadNumber    ;read a number into eax
  1344.     pop    di        ;restore pointer
  1345.     mov    ebx,eax        ;return number in ebx
  1346.     ret
  1347. noval:
  1348.     stc
  1349.     ret
  1350. parseval    ENDP
  1351. end