?login_element?

Subversion Repositories NedoOS

Rev

Rev 632 | Blame | Compare with Previous | Last modification | View Log | Download

  1.  
  2. ;
  3. ; ccd.asm:
  4. ;
  5.  
  6. ;
  7. ; preprocessor directive handler:
  8. ;
  9.  
  10. defstr: db '#defin', 'e'+80h
  11. undfst: db '#unde','f'+80h
  12. ifst:   db '#i','f'+80h
  13. ifdfst: db '#ifde','f'+80h
  14. ifndst: db '#ifnde','f'+80h
  15. endfst: db '#endi','f'+80h
  16. elsest: db '#els','e'+80h
  17. prepw:  db 'Warning: Ignoring unknown preprocessor directive',cr,lf,0
  18. stgppo: db 'String overflow; call BDS+'
  19. stgmmp: db 'EOF found when expecting #endif+'
  20. stgbds: db 'Bad parameter list syntax+'
  21. stgbd1: db 'Missing parameter list+'
  22. stgbd2: db 'Parameter mismatch+'
  23. stgnwc: db 'Not in a conditional block+'
  24. stgbce: db 'Conditional expr bad or beyond implemented subset+'
  25.  
  26. prep:   ld hl,lblt      ;set pointer to start of string space table
  27.         shld def2p
  28.  
  29.         xor a
  30.         sta bcnstf      ;supress errors on bad constants till later on...
  31.  
  32.         ld hl,lblt+strsiz
  33.         shld stp
  34.         ld (hl),0
  35.  
  36.         call initps     ;initialize for pass through text
  37.  
  38.         xor a           ;initialize nested conditional control variables
  39.         sta nestl       ;current conditional nesting level
  40.         sta didelse     ;didn't see an #else yet in current macro
  41.         sta dstgf       ;not in a string (for prlin)
  42.         inc a
  43.         sta active      ;currently conditionally active
  44.  
  45. prep1:  call nextch     ;handle bookkeeping
  46.         jp nc,prep1a    ;EOF?
  47.  
  48.         lda nestl       ;Yes. In a conditional block?
  49.         or a
  50.         ld hl,stgmmp
  51.         jp nz,perrab    ;if so, go complain and abort
  52.         xor a
  53.         sta preflag     ;not in preprocessor anymore
  54.         ret             ;otherwise done with preprocessor
  55.  
  56. prep1a: lhld nlcnt      ;save line count
  57.         shld nlcsav
  58.         cp cr           ;line only a lone CR?
  59.         jp nz,prep1b    ;if not, process the line
  60.  
  61.         dec hl          ;else debump line count
  62.         shld nlcsav
  63.         jp prep2a       ;and go wrap up
  64.  
  65. prep1b: push de         ;process #defined substitutions on current line,
  66.         lda active      ;but only if active
  67.         or a
  68.         call nz,prlin
  69.         pop de
  70.  
  71.         call igwsp
  72.         ld a,(de)               ;a preprocessor directive?
  73.         cp '#'
  74.         jp nz,prep2     ;if not, don't bother with rest of this stuff
  75.  
  76.         ld hl,endfst    ;#endif?
  77.         call stcmp
  78.         jp z,pendif
  79.  
  80.         ld hl,elsest    ;#else?
  81.         call stcmp
  82.         jp z,pelse
  83.  
  84.         ld hl,ifdfst    ;#ifdef?
  85.         call stcmp
  86.         jp z,pifdef
  87.  
  88.         ld hl,ifndst    ;#ifndef?
  89.         call stcmp
  90.         jp z,pifndef
  91.  
  92.         ld hl,ifst      ;#if?
  93.         call stcmp
  94.         jp z,pif
  95.  
  96.         lda active
  97.         or a            ;if not active, don't do any more processing
  98.         jp z,prep2
  99.  
  100.         ld hl,defstr    ;#define?
  101.         call stcmp
  102.         jp z,pdef
  103.  
  104.         ld hl,undfst    ;#undef?
  105.         call stcmp
  106.         jp z,pundef
  107.  
  108.         push de         ;check for possible '#' on a line by itself; this
  109. prpwlp: inc de          ;should be ignored by turning the line into FF's:
  110.         ld a,(de)
  111.         cp 0ffh ;we'll allow this between # and NL
  112.         jp z,prpwlp
  113.         cp cr           ;end of line?
  114.         jp z,prpwrn0
  115.  
  116. prpwrn: ld hl,prepw     ;print this warning ONLY if
  117.         call pwarn
  118. prpwrn0: pop de
  119.         jp prep2b
  120.  
  121.  
  122. ;
  123. ; Come here when current line is NOT a preprocessor directive:
  124. ;
  125.  
  126. prep2:  lda active      ;active?
  127.         or a
  128.         jp z,prep2b
  129.        
  130. prep2a: call nextch     ;find CR or EOF
  131.         ret c
  132.         cp cr
  133.         inc de
  134.         jp nz,prep2a
  135.         jp prep2c
  136.  
  137. prep2b: call dellin     ;delete line
  138. prep2c: lhld nlcsav     ;bump saved line count
  139.         inc hl
  140.         shld nlcnt
  141.         jp prep1        ;and go for more text
  142.  
  143.  
  144. ;
  145. ; Delete current line of text at DE, up to CR:
  146. ;      
  147.  
  148. dellin: ld a,(de)
  149.         cp cr
  150.         jp nz,dell2
  151.         inc de
  152.         ret
  153.  
  154. dell2:  ld a,0ffh
  155.         ld (de),a
  156.         inc de
  157.         jp dellin
  158.  
  159.  
  160. ;
  161. ; Process #endif:
  162. ;
  163.  
  164. pendif: lda nestl       ;if not in a conditional, complain
  165.         or a
  166.         jp nz,pendf2
  167. pendf1: ld hl,stgnwc    ;"Not within conditional block"
  168.         jp perrab
  169.  
  170. pendf2: dec a           ;decrement nest level
  171.         sta nestl
  172.  
  173.         pop af          ;pop old activity state
  174.         sta active
  175.         pop af
  176.         sta didelse
  177.  
  178.         jp prep2b      
  179.  
  180.                
  181. ;
  182. ; Process #else:
  183. ;
  184.  
  185. pelse:  lda nestl       ;if not in a conditional block, error
  186.         or a
  187.         jp z,pendf1
  188.         lda didelse     ;have we already done an #else this block?
  189.         or a
  190.         jp nz,pendf1    ;if so, error
  191.  
  192.         pop af          ;peek at last activity state
  193.         push af
  194.         or a
  195.         jp z,pelse2     ;last level active? If not, leave this one inactive
  196.  
  197.         lda active      ;yes. flip current state
  198.         or a
  199.         ld a,1          ;was active false?
  200.         jp z,pelse1     ;if so, make it true
  201.         xor a           ;else was true: make it false
  202. pelse1: sta active
  203. pelse2: ld a,1          ;set didelse
  204.         sta didelse
  205.         jp prep2b      
  206.  
  207. ;
  208. ; Process #ifdef:
  209. ;
  210.  
  211. pifdef: push de         ;save text pointer
  212.         lda active      ;if not active, don't bother evaluating identifier
  213.         or a
  214.         jp z,doif
  215.         call defined    ;test to see if identifier defined
  216.         jp doif ;go wrap up
  217.  
  218. ;
  219. ; Process #ifndef:
  220. ;
  221.  
  222. pifndef: push de                ;just like for #ifdef,
  223.         lda active
  224.         or a
  225.         jp z,doif
  226.         call defined
  227.         cpl             ;execpt flip the logical result
  228.         jp doif
  229.  
  230. ;
  231. ; Process #if:
  232. ;
  233.  
  234. pif:    push de         ;save text pointer
  235.         lda active
  236.         or a
  237.         jp z,doif               ;if not active, don't bother evaluating line
  238.         ld hl,3
  239.         add hl,de
  240.         ex de,hl
  241.         call ifexp      ;otherwise evaluate conditional expression
  242.         jp doif
  243.  
  244. ;
  245. ; Evaluate conditional expression at DE, having  BNF:
  246. ;
  247. ;       ifexp :=  <ifexp2>
  248. ;           (or)  <ifexp2> && <ifexp>
  249. ;           (or)  <ifexp2> || <ifexp>
  250. ;
  251. ;       ifexp2 := <constant>
  252. ;           (or)  <(ifexp)>
  253. ;           (or)  not<ifexp2>   ("not" is an exclamation point)
  254. ;
  255.  
  256. ifexp:  call ifexp1     ;evaluate expression
  257.         ld b,a          ;save result in B
  258.         call gndch      ;make sure there isn't anything after it
  259.         cp cr
  260.         ld a,b          ;get back the result
  261.         ret z           ;if CR, all done
  262. ifexp0: ld hl,stgbce    ;bad conditional expression
  263.         jp perrab
  264.  
  265. ;
  266. ; Recursive entry point for conditional expression evaluator:
  267. ;
  268.  
  269. ifexp1: call ifexp2     ;evaluate subexpression
  270.         jp c,ifexp0     ;error if not legal expression
  271.         ld b,a          ;put result in B
  272.         call igwsp      ;check for operators
  273.         ld c,'&'
  274.         cp c
  275.         jp z,ifxp1a
  276.         ld c,'|'
  277.         cp c
  278.         jp z,ifxp1a
  279.         ld a,b          ;no legal operators..return evaluated value.
  280.         ret
  281.  
  282. ifxp1a: inc de          ;check for second identical character
  283.         ld a,(de)
  284.         cp c
  285.         jp nz,ifexp0    ;if not, syntax error
  286.         push bc         ;OK, save last result (B) and operator (C)
  287.         inc de          ;evaluate next operand
  288.         call ifexp1
  289.         ld l,a          ;put result in L
  290.         pop bc          ;get back previous result and operator
  291.         ld a,c          ;look at operator
  292.         cp '&'          ;logical and?
  293.         ld a,b          ;get previous result in A
  294.         jp nz,ifxp1b
  295.         and l           ;if so, AND the two and return result
  296.         ret
  297. ifxp1b: or l            ;else OR the two and return result
  298.         ret
  299.  
  300. ifexp2: call igwsp      ;skip leading whitespace
  301.         cp '('          ;parenthesized expression?
  302.         jp nz,ifxp2a
  303.         inc de          ;yes. pass the opening paren
  304.         call ifexp1     ;evaluate inner expression
  305.         ld b,a
  306.         call igwsp      ;check for closing paren
  307.         cp ')'
  308.         scf             ;return Cy if not closed
  309.         ret nz
  310.         inc de          ;otherwise pass the close paren
  311.         ld a,b          ;get back result
  312.         ccf             ;clear Cy
  313.         ret             ;and return
  314.  
  315. ifxp2a: cp '!'          ;negation operator?
  316.         jp nz,ifxp2b
  317.         inc de          ;yes. evaluate operand
  318.         call ifexp2
  319.         ret c           ;ignore if error
  320.         or a            ;otherwise flip result
  321.         ld a,1
  322.         ret z           ;return 1 if result was 0
  323.         dec a           ;return 0 if result was 1
  324.         ret
  325.  
  326. ifxp2b: call digt       ;otherwise must be decimal constant
  327.         ret c           ;return error if not
  328. ifxp2c: ld a,(de)               ;check a char of the constant
  329.         call digt       ;digit?
  330.         jp nc,ifxp2     ;if so, go process
  331.         xor a           ;else result is zero.
  332.         ret
  333.  
  334. ifxp2:  inc de          ;bump ptr to next digit
  335.         or a            ;was last digit zero?
  336.         jp z,ifxp2c     ;if so, go loop
  337. ifxp3:  ld a,(de)               ;otherwise find end of value
  338.         call digt
  339.         inc de
  340.         jp nc,ifxp3     ;keep looping till we find a non-digit
  341.         dec de          ;all done
  342.         xor a           ;return no Cy
  343.         inc a           ;and a value of 1
  344.         ret
  345.  
  346.  
  347. ;
  348. ; Come here after #if, #ifdef or #ifndef condition has been
  349. ; evaluated, with A = <condition>, either 0 or non-0:
  350. ;
  351.  
  352. doif:   ld b,a          ;save condition in B
  353.         lda nestl       ;bump nesting level
  354.         inc a
  355.         sta nestl
  356.  
  357.         pop de          ;get back text pointer
  358.  
  359.         lda didelse     ;push current activity state
  360.         push af
  361.         lda active
  362.         push af
  363.  
  364.         or a            ;currently active
  365.         jp z,doif2      ;if not, remain inactive
  366.         ld a,b          ;look at conditional test result
  367.         or a
  368.         jp z,doif2      ;if false, active = 0;
  369.         ld a,1          ;else active = 1.
  370. doif2:  sta active
  371.  
  372.         xor a
  373.         sta didelse     ;clear didelse for the new level
  374.         jp prep2b       ;and go clean up
  375.  
  376.  
  377. ;
  378. ; Process #undef:
  379. ;
  380.  
  381. pundef: push de
  382.         call defined
  383.         pop de
  384.         jp c,prep2b     ;if already not defined, ignore it
  385.         ld (hl),'*'     ;otherwise place a strange char there to erase it
  386.         jp prep2b       ;and go wrap up
  387.  
  388. ;
  389. ; Process #define definition:
  390. ;
  391.  
  392. pdef:   push de         ;found #define line. Save text ptr for later deletion.
  393.         call defined    ;re-defining an identifier?
  394.         jp c,pdef2
  395.         call prepa      ;yes. go do that
  396.         jp pdef3
  397.  
  398. ;
  399. ; Install the identifier at DE for the first time:
  400. ;
  401.  
  402. pdef2:  lhld stp
  403.         call prepa      ;install identifier
  404.         shld stp
  405.         ld (hl),0
  406.  
  407. ;
  408. ; Collect up the substitution text in the string table:
  409. ;
  410.  
  411. pdef3:  push af
  412.         call igwsp
  413.         pop af
  414.         or a            ;parameterized?
  415.         jp nz,prargs    ;if so, go handle elsewhere
  416.  
  417.         call gndch      ;a null definition?
  418.         cp cr
  419.         jp nz,pdef4a
  420.         ld a,0ffh       ;if so, define as a whitespace (FF) byte
  421.         jp pdef4b
  422.  
  423. pdef4:  call gndch      ;else install simple text, till end of line
  424. pdef4a: ld (bc),a
  425.         inc bc
  426.         cp cr
  427.         jp nz,pdef4
  428.         dec bc          ;turn b7 high on last char of replacement text
  429.         dec bc
  430.         ld a,(bc)
  431.         or 80h
  432. pdef4b: ld (bc),a
  433.         inc bc
  434.         ld h,b          ;and replace text table pointer
  435.         ld l,c
  436.  
  437. pdef5:  shld def2p      ;make sure def2p hasn't collided with identifier table
  438.         ld de,lblt+strsiz
  439.         call cmphd      ;return C if def2p < end of table2 (ie. no overflow)
  440.         jp c,pdef6      ;if no overflow, no problem
  441.  
  442.         ld hl,stgppo    ;preprocessor overflow: complain and abort
  443.         jp pstgab
  444.  
  445. pdef6:  pop de
  446.         jp prep2b       ;go delete line and finish up
  447.  
  448. ;
  449. ; Process parameterized substitution text: replace arg keywords with
  450. ; special codes (80, 81, etc.) as it is stored in string table:
  451. ;
  452.  
  453.         IF 0
  454. stgflg: ds 1            ;in a string flag, for parameterized definitions
  455. escflg: ds 1            ;escaped char in text string flag
  456.         ENDIF
  457.  
  458. prargs: ld h,b          ;copy string table address into HL
  459.         ld l,c
  460.         and 7fh         ;strip b7 off arg count
  461.         ld c,a          ;put in C
  462.         inc c           ;C = # of args + 1
  463.  
  464.  
  465. prarg0: call gndch      ;see if text at DE matches one of the formal args
  466.  
  467.         call varch2
  468.         jp nc,prarg2
  469.  
  470. prarg1: ld (hl),a               ;no match...just store it
  471.         inc hl
  472.         cp cr
  473.         jp nz,prarg0    ;and go for more
  474.         jp pdef5        ;when done, go wrap up.
  475.  
  476. prarg2: dec de          ;go back to start of the identifier
  477.         push bc         ;get set to search arg text table for match
  478.         push hl
  479.         ld b,80h
  480.         ld hl,deformt
  481. prarg3: dec c           ;done searching list?
  482.         jp z,prarg6
  483.         ld a,(hl)               ;no. compare strings
  484.         inc hl
  485.         push hl
  486.         ld h,(hl)
  487.         ld l,a
  488.         push bc
  489.         call idcmp
  490.         jp nz,prarg5    ;match?
  491. prarg4: inc de          ;yes.
  492.         dec c           ;replace arg with code number
  493.         jp nz,prarg4
  494.         pop bc
  495.         ld a,b          ;get code number
  496.         pop hl
  497.         pop hl
  498.         pop bc
  499.         jp prarg1       ;and go store it
  500.  
  501. prarg5: pop bc          ;no match. try next table entry
  502.         pop hl          ;get table pointer
  503.         inc hl          ;point to next arg string
  504.         inc b           ;bump current code number
  505.         jp prarg3
  506.  
  507. prarg6: pop hl
  508.         pop bc          ;no match. Copy identifier literally
  509.         ld a,(de)
  510. prarg7: ld (hl),a
  511.         inc hl
  512.         inc de
  513.         ld a,(de)
  514.         call varch      ;still part of identifier?
  515.         jp nc,prarg7    ;if so, keep on storing
  516.         jp prarg0       ;else go for next piece of text
  517.        
  518. ;
  519. ; Install the identifier at DE in the defined constant id table. For
  520. ; parameterized defines, count up formal args and make sure the count
  521. ; gets into the table.
  522. ;
  523. ; On entry, HL points to the spot in the table where the id is to be
  524. ; inserted:
  525. ;
  526. ; Return A == argcount (b7 high if args present), BC --> text area
  527. ; where key text is to be stored.
  528. ;
  529.  
  530. prepa:  push hl         ;push id table pointer
  531.         lhld stp        ;get id table free slot pointer
  532.         ex (sp),hl              ;push on stack, get back id table pointer
  533.         shld stp        ;make id pointer act as free slot pointer for now
  534.         call instt      ;install identifier at DE
  535.  
  536.         push hl         ;save pointer to argcount byte
  537.         ld l,c          ;put identifier length in HL
  538.         ld h,0
  539.         add hl,de               ;now HL -> char after identifier in text
  540.         ld a,(hl)               ;look at it
  541.         cp '('          ;parameterized define?
  542.         ld a,0
  543.         jp nz,prepa2    ;if not, install 0 in argcount byte position
  544.         call deform     ;else go count up formal args, return A = # of args
  545.         jp nc,prepa1
  546.         ld hl,stgbds
  547.         jp perrab
  548.  
  549. prepa1: or 80h          ;set b7 to indicate parameterized define
  550. prepa2: ex (sp),hl              ;push text pointer from HL, get HL = table pointer
  551.         ld (hl),a               ;store argcount value in id table
  552.         inc hl          ;bump table pointer to string addr area
  553.         push hl         ;save str addr area ptr
  554.         lhld def2p      ;get string table free area pointer
  555.         ld b,h          ;lde to BC
  556.         ld c,l
  557.         pop hl          ;get back str addr area ptr
  558.         ld (hl),c               ;save string pointer in id table
  559.         inc hl
  560.         ld (hl),b
  561.         inc hl          ;HL now points to next id slot
  562.         pop de          ;get back text pointer
  563.         ex (sp),hl              ;push text pointer, pop old id table free slot ptr
  564.         shld stp        ;save id table free slot ptr
  565.  
  566.         push de         ;check for table overflow...we have one if
  567.         ex de,hl                ;stp not less than coda
  568.         lhld coda
  569.         ex de,hl
  570.         push af ;save argcount value
  571.         call cmphd      ;return C if stp < coda
  572.         jp nc,instt0    ;if stp >= coda, go complain and abort
  573.         pop af          ;restore argcount value
  574.         pop de
  575.         pop hl
  576.         ret
  577.  
  578. ;
  579. ; Given HL -> formal arg list for parameterized define,
  580. ;  1. Put list of pointers to the args at deformt
  581. ;  2. put b7 high on last byte of each arg
  582. ;  3. return A = # of formal args (0 is legal), and HL -> after list
  583. ;
  584. ; If A == 0 on entry, allow only identifiers,
  585. ; If A <> 0,  allow any type of objects
  586. ;
  587.  
  588. deform: ld b,a          ;save strings_ok flag in B
  589.  
  590.         xor a           ;initialize extra line count
  591.         sta lcnt
  592.  
  593.         ld c,0          ;init arg count
  594.         ex de,hl                ;put text pointer in DE
  595.         ld hl,deformt   ;init arg ptr list ptr
  596.         inc de          ;pass '('
  597.         call igwsp      ;ignore trash
  598.         cp ')'          ;null list?
  599.         jp nz,defrm2
  600.  
  601. defrm1a:
  602.         inc de          ;yes. pass over ')'
  603.         ex de,hl                ;put text ptr back in HL
  604.         ld a,c          ;get arg count in A
  605.         ret
  606.  
  607. defrm2: call igwsp      ;ignore leading trash
  608.         cp cr           ;newline character?
  609.         jp nz,defr2a    ;if not, assume it's legal starting char
  610.         lda lcnt        ;bump extra line count
  611.         inc a
  612.         sta lcnt
  613.         inc de          ;go on to next char
  614.         jp defrm2       ;and go check for more extra newlines
  615.        
  616. defr2a: ld (hl),e               ;add adress of next arg to list
  617.         inc hl
  618.         ld (hl),d
  619.         inc hl
  620.  
  621.         ld a,b
  622.         or a            ;if allowing identifiers only,
  623.         jp z,defrm4     ;then go do that
  624.  
  625.         xor a           ;clear paren nest level
  626.         sta parenc
  627.  
  628. defr3a: ld a,(de)               ;else process generalized arg: get char of text
  629.         inc de          ;bump text pointer
  630.         cp '"'          ;quote?
  631.         jp nz,defr3d    ;if not, go check for terminators
  632.                         ;process string arg:
  633. defr3b: ld a,(de)               ;look at next arg of string
  634.         inc de
  635.         cp '\'          ;backslash?
  636.         jp nz,defr3c
  637.         inc de          ;if so, pass over the next char
  638.         jp defr3b
  639. defr3c: cp '"'          ;closing quote?
  640.         jp nz,defr3b    ;if not, keep looping till we find one
  641.         jp defr3a       ;found closing quote. go for more of the arg
  642.  
  643. defr3d: dec de          ;temporrily place txt ptr on current char
  644.         cp ','          ;comma?
  645.         jp nz,dfr3d1    ;if not, check for close paren
  646.         lda parenc      ;in parens?
  647.         or a
  648.         jp z,defr4a     ;if not, found end
  649.         jp dfr3d2       ;else inside parens, so ignore 
  650.  
  651. dfr3d1: cp ')'          ;close paren?
  652.         jp nz,dfr3d3    ;if not, go check for other special chars
  653.         lda parenc
  654.         or a
  655.         jp z,defr4a     ;if already zilch, all done with this paren
  656.         dec a           ;else debump paren count
  657.         sta parenc
  658. dfr3d2: inc de          ;else go on with term
  659.         jp defr3a
  660.  
  661. dfr3d3: inc de          ;advance txt ptr back past current char
  662.         cp '''' ;single quote?
  663.         jp z,defr3e     ;if so, go handle
  664.         cp '('          ;open paren?
  665.         jp nz,defr3a    ;if not, go for next char
  666.         lda parenc      ;bump paren count
  667.         inc a  
  668.         sta parenc
  669.         jp defr3a       ;and go for more text
  670.  
  671. defr3e: ld a,(de)               ;process object in single quotes
  672.         inc de
  673.         cp '\'
  674.         jp nz,defr3f
  675.         inc de          ;ignore char after backslash
  676.         jp defr3e      
  677. defr3f: cp '''' ;closing single quote?
  678.         jp nz,defr3e    ;if not, keep scanning
  679.         jp defr3a       ;else done with single quote object; go for more arg
  680.  
  681. defrm4: ld a,(de)               ;get character at txt ptr
  682.         call varch2     ;legal 1st char of identifier?
  683.         ret c           ;if not, error.
  684. defr40: inc de          ;find char after last char of identifier
  685.         ld a,(de)
  686.         call varch
  687.         jp nc,defr40
  688.  
  689. defr4a: dec de          ;go back to last char of arg
  690.         ld a,(de)               ;set b7
  691.         or 80h
  692.         ld (de),a
  693.         inc c           ;bump arg count
  694.         inc de          ;get next char
  695.         call igwsp
  696.         cp ','          ;comma?
  697.         jp nz,defrm5    ;if not, go check for ')'
  698.         inc de          ;else pass comma and look for identifier
  699.         jp defrm2
  700.        
  701. defrm5: cp ')'          ;now must be either close or an error
  702.         jp z,defrm1a
  703.         scf             ;error. set Cy and return
  704.         ret
  705.  
  706. ;
  707. ; Test to see if identifier at DE has already been defined in a previous
  708. ; #define line. Return Cy clear if previously defined.
  709. ;
  710.  
  711. defined:
  712.         ld l,c          ;look at the identifier.
  713.         ld h,0
  714.         add hl,de
  715.         ex de,hl
  716.         call igwsp
  717.         call findd      ;is it already defined? set C if not.
  718.         lhld deftmp
  719.         ld a,0ffh       ;also A = 0ffh if no carry,
  720.         ret nc
  721.         cpl             ;A = 0 if carry
  722.         ret
  723.  
  724.  
  725. ;
  726. ; Process all text substitutions on the line pointed to by DE:
  727. ;
  728.  
  729. prlin:  push de         ;save pointer to start of line for later retrieval
  730.         lda dstgf       ;and save state of in-string flag
  731.         push af
  732.  
  733.         or a            ;in a string from previous line?
  734.         jp nz,prln0     ;if so, don't check for preprocessor directives
  735.  
  736.         call igwsp      ;ignore leading white space, checking for directives
  737.         ld hl,ifst      ;line begin with #if?
  738.         call stcmp
  739.         jp z,prln1     
  740.         ld a,(de)               ;line start with #?
  741.         cp '#'
  742.         jp z,prl0a      ;if so, don't preprocess.
  743.         jp prln0
  744.  
  745. prln1:  inc de          ;line starts with #if. Pass "#if"
  746.         inc de
  747.         inc de
  748.         call igwsp      ;process rest of #if line.
  749.  
  750.  
  751. prln0:  dec de
  752. prlin9: inc de
  753. prlin0: ld a,(de)               ;end of file?
  754.         or a
  755.         jp z,prl0a      ;if so, end of line for sure.
  756.         cp cr           ;end of line?
  757.         jp nz,prlin1
  758. prl0a:  pop af          ;yes. all done. clean up stack (pushed dstgf)
  759.         pop de          ;and pop text pointer to start of line
  760.         ret
  761.  
  762. prlin1: lda dstgf       ;in a string right now?
  763.         or a
  764.         ld a,(de)
  765.         jp z,prlinc
  766.         cp '"'          ;yes. close quote?
  767.         jp z,prlinb     ;if so, go flip "in string" state
  768.         cp '\'          ;no. escape?
  769.         jp nz,prlin9    ;if not, just go to next char
  770.         inc de          ;if so, skip next character
  771.         jp prlin9
  772.  
  773. prlinb: lda dstgf
  774.         cpl
  775.         sta dstgf
  776.         jp prlin9
  777.  
  778. prlinc: cp '"'          ;not in a string. start of string quote?
  779.         jp z,prlinb     ;if so, go flip "in string" state
  780.         cp '''' ;character constant?
  781.         jp nz,prlind
  782.         call chcnst1    ;yes. pass over it
  783.         jp prlin0
  784.  
  785.        
  786. prlind: call varch2     ;identifier?
  787.         jp c,prlin9
  788.  
  789. prline: call subst      ;yes. do substitutions
  790.         jp c,prlinf     ;any done?
  791.         pop af          ;yes. restore dstgf
  792.         sta dstgf
  793.         pop de          ;and text pointer, then start processing line again.
  794.         jp prlin
  795.  
  796. prlinf: inc de          ;pass over rest of identifier name
  797.         ld a,(de)
  798.         call varch
  799.         jp nc,prlinf
  800.         jp prlin0       ;and go for more stuff.
  801.  
  802.  
  803. ;
  804. ; Search for identifier pointed to by DE in the identifier
  805. ; table. Return Cy set if not found, else HL pointing to
  806. ; the arg count byte immediately following the name entry
  807. ; in the table:
  808. ;
  809.  
  810. findd:  ld hl,lblt+strsiz       ;start of identifier table
  811.  
  812. findd2: ld a,(hl)
  813.         or a
  814.         scf
  815.         ret z
  816.         shld deftmp
  817.         call idcmp
  818.         jp nz,findd3
  819.         lhld deftmp
  820.         push bc
  821.         ld bc,8
  822.         add hl,bc
  823.         pop bc
  824.         ret
  825.  
  826. findd3: ld bc,11
  827.         add hl,bc
  828.         jp findd2
  829.  
  830.  
  831. ;
  832. ; Ignore white space at DE:
  833. ;
  834.  
  835. igwsp:  ld a,(de)
  836.         inc de
  837.         call twsp
  838.         jp z,igwsp
  839.         dec de
  840.         ret
  841.  
  842.  
  843. ;
  844. ; Do all potential substitutions for the text at DE:
  845. ;
  846.  
  847. subst:  call findd      ;is identifier at DE a defined symbol?
  848.         ret c
  849.  
  850.         ld b,(hl)               ;put arg count in B
  851.         inc hl
  852.         ld a,(hl)
  853.         inc hl
  854.         ld h,(hl)
  855.         ld l,a 
  856.  
  857.         ld a,b          ;parameterized?
  858.         or a
  859.         jp z,substs     ;if so, go handle simple substitution
  860.  
  861.         and 7fh         ;otherwise put arg count in B
  862.         ld b,a
  863.         push de         ;save  ->old text
  864.         call pasvr      ;param list?
  865.         call igwsp      ;ignore white space between var and possible param list
  866.         cp '('
  867.         jp z,subst2
  868.         ld hl,stgbd1
  869.         jp perrab
  870.  
  871. subst2: push hl         ;save ->new text
  872.         ex de,hl                ;put text ptr in HL
  873.         push bc
  874.         call deform     ;build list of param ptrs
  875.         ex de,hl                ;put text ptr back in DE
  876.         jp nc,subst3
  877.         ld hl,stgbds
  878.         jp perrab              
  879.  
  880. subst3: pop bc
  881.         cp b
  882.         jp z,subst4     ;correct # of args?
  883.         ld hl,stgbd2
  884.         call perrab
  885.  
  886. subst4: pop hl          ;HL ->new text
  887.         push de         ;save DE (->after old text)
  888.         ld de,txbuf     ;now create new text image at txbuf
  889.  
  890.         ld a,(hl)               ;check for a null text image
  891.         cp cr
  892.         jp nz,subst5    ;if not null, handle normally
  893.         ld a,0ffh       ;else place null FF byte in text area
  894.         ld (de),a
  895.         jp subst9a
  896.  
  897. subst5: ld a,(hl)
  898.         inc hl
  899.         cp cr
  900.         jp z,subst9
  901.         or a
  902.         jp m,subst6     ;if arg code, go substitute
  903.         ld (de),a               ;otherwise just a char
  904.         inc de
  905.         jp subst5
  906.  
  907. subst6: and 7fh         ;now substitute an arg for the code byte
  908.         add a
  909.         ld c,a
  910.         ld b,0
  911.         push hl
  912.         ld hl,deformt
  913.         add hl,bc
  914.         ld a,(hl)
  915.         inc hl
  916.         ld h,(hl)
  917.         ld l,a          ;HL -> arg text represented by code byte
  918. subst7: ld a,(hl)
  919.         and 7fh
  920.         ld (de),a
  921.         inc de
  922.         ld a,(hl)
  923.         inc hl
  924.         or a
  925.         jp p,subst7     ;keep copying till b7 is high on last char
  926.         pop hl
  927.         jp subst5
  928.  
  929. subst9: dec de          ;turn on b7 of last char of text area
  930.         ld a,(de)
  931.         or 80h
  932. subst9a:
  933.         ld (de),a
  934.         pop de          ;all done...now just replace old text with new text
  935.         pop hl
  936.         push hl
  937.         call cmh
  938.         add hl,de
  939.         ld c,l
  940.         pop de
  941.         ld hl,txbuf
  942.         call substs
  943.  
  944.         lda lcnt        ;get extra line count
  945.         ld b,a          ;save in B
  946.         cpl             ;negate for "mvtxt"
  947.         inc a
  948.         call mvtxt     
  949.  
  950. substa: ld a,b
  951.         or a
  952.         ret z  
  953.         ld a,cr
  954.         ld (de),a
  955.         inc de
  956.         dec b
  957.         jp substa
  958.  
  959. ;
  960. ; Substitute text at HL for identifier at DE, length of id at DE is in C:
  961. ;
  962.  
  963. substs: push hl         ;save ->new text
  964.         push bc         ;save id length
  965.         push hl         ;push ->new text
  966.         call cmh        ;HL = -(new text addr)
  967.         ex (sp),hl              ;push -(new addr), get HL = new addr
  968. subs2:  ld a,(hl)               ;compute length of new text
  969.         inc hl
  970.         or a
  971.         jp p,subs2
  972.         pop bc          ;get -(new addr) in BC
  973.         add hl,bc               ;HL = length
  974.         ex (sp),hl              ;push lengh, HL = id length (in L)
  975.         ld h,0          ;HL = id length
  976.         call cmh        ;HL = -(id length)
  977.         pop bc
  978.         push bc         ;BC = new text length
  979.         add hl,bc               ;HL = difference in lengths
  980.         ld a,l          ;negate difference
  981.         cpl
  982.         inc a
  983.         call mvtxt      ;shift text
  984.         pop bc
  985.         pop hl
  986.         inc bc
  987. subs3:  dec bc          ;insert new text
  988.         ld a,b
  989.         or c
  990.         ret z
  991.         ld a,(hl)
  992.         cp 0FFh ;filler byte?
  993.         jp z,subs4
  994.         and 7fh
  995. subs4:  ld (de),a
  996.         inc de
  997.         inc hl
  998.         jp subs3
  999.                
  1000.  
  1001. ;
  1002. ; Print out intermediate text if "-p" option given:
  1003. ;
  1004.  
  1005. pitext:
  1006.         lda pflag       ;return if intermediate text
  1007.         or a            ;       printout not desired
  1008.         ret z
  1009.  
  1010.         lda werrs       ;output to console only
  1011.         push af
  1012.         xor a
  1013.         sta werrs
  1014.  
  1015.         lhld coda
  1016.         ex de,hl                ;DE points to text
  1017.         ld hl,0         ;HL holds line count
  1018.         call initps     ;initialize for pass through text
  1019.         sta nlflag      ;enable null line numbering
  1020.  
  1021.         call crlf       ; leading blank lines
  1022.         call crlf
  1023.  
  1024. ploop:  call gndch      ;get next significant character
  1025.         or a
  1026.         jp nz,ploop1
  1027.  
  1028. ploopd: call crlf       ;end of file.
  1029.         pop af          ;restore RED file output status
  1030.         sta werrs
  1031.         ret             ;all done.
  1032.  
  1033. ploop1: cp cr
  1034.         jp nz,ploop2
  1035.         call ckabrt     ;check for control-C on console
  1036.         lda nlflag      ;ok to number null lines?
  1037.         or a
  1038.         jp nz,ploop7    ;print empty line number on first null line in 
  1039.         ld a,1          ; a series of null lines, but not on rest of them.
  1040.         sta nlflag
  1041.         call number
  1042.         jp ploop7
  1043.  
  1044. ploop2: cp modbeg       ;start of module?
  1045.         jp nz,ploop3
  1046.         shld nlcnt      ;save line count for pushmn to use
  1047.         push de         ;save ptr to filename
  1048.         call pushmn     ;process start of include file.
  1049.         call crlf
  1050.         call indnt      ;indent for new module name
  1051.         call indnt      ;  extra indentation lines name up with text
  1052.         ex de,hl                ;save current DE in HL
  1053.         pop de          ;get filename
  1054.         call pfnam2     ;print out module name
  1055.         ex de,hl                ;put text ptr back in DE
  1056.         ld a,':'
  1057.         call outch
  1058.         ld hl,0         ;clear new line count
  1059.         jp ploop
  1060.  
  1061. ploop3: cp modend       ;and of module?
  1062.         jp nz,ploop4
  1063.  
  1064.         call popmn      ;process end-of-module by putting out
  1065.         call crlf       ;an extra cr-lf for readability.
  1066.         lhld nlcnt      ;restore line count from where popmn put it
  1067.         jp ploop
  1068.  
  1069.  
  1070. ploop4: call number     ;number the new line
  1071. ploop5: cp 255
  1072.         jp z,ploop6     ;don't print filler bytes
  1073.         call outch
  1074. ploop6: ld a,(de)               ;put out the line
  1075.         inc de
  1076.         or a
  1077.         jp z,ploopd
  1078.         cp cr
  1079.         jp nz,ploop5
  1080.         xor a
  1081.         sta nlflag      ;enable numbering of next null line
  1082.  
  1083. ploop7: inc hl
  1084.         jp ploop
  1085.  
  1086. ;
  1087. ; Get next char of text at DE, but if there's nothing but trash
  1088. ; between it and the end of the line, just return the CR:
  1089. ;
  1090.  
  1091. gndch:  ld a,(de)
  1092.         inc de
  1093.         cp 255
  1094.         jp z,gndch      ;ignore FF's
  1095.         call twsp       ;is next char white space?
  1096.         ret nz          ;if not, must use it.
  1097.         push af ;else if rest of the stuff on the line is trash
  1098.         push de
  1099.         call tnbcr      ;is it?
  1100.         jp z,gndch2
  1101.         pop de          ;no, there's more useful stuff.
  1102.         pop af
  1103.         ret
  1104.  
  1105. gndch2: pop af          ;no more useful stuff. return a CR
  1106.         pop af
  1107.         inc de          ;and pass over the CR.
  1108.         ld a,cr
  1109.         ret    
  1110.  
  1111.  
  1112. ;
  1113. ; Return Z set if there's nothing but trash until the end of the line:
  1114. ;
  1115.  
  1116. tnbcr:  ld a,(de)
  1117.         cp cr           ;return?
  1118.         ret z           ;if so, NOT a garbage character
  1119.         call twsp       ;white space?  
  1120.         ret nz          ;if not, not a garbage char
  1121.         inc de
  1122.         jp tnbcr        ;else keep scanning line for cr or non-space.
  1123.  
  1124. ;
  1125. ; Number the current pitext line:
  1126. ;
  1127.  
  1128. number: push af
  1129.         call crlf
  1130.         call indnt      ;indent 2 spaces per module stacking
  1131. numb2:  push hl
  1132.         xor a           ;all line numbers take 4 characters
  1133.         call prhcs
  1134.         pop hl
  1135.         pop af
  1136.         ret
  1137.  
  1138. ;
  1139. ; Indent according to module stack count (2 spaces per module):
  1140. ;
  1141.  
  1142. indnt:  lda modstc      ;get module nesting count
  1143.         dec a           ;print (A-1)*3 spaces
  1144.         ld b,a
  1145.         add a
  1146.         add b
  1147.         inc a
  1148.         ld b,a
  1149. indnt1: dec b
  1150.         ret z
  1151.         ld a,' '
  1152.         call outch
  1153.         jp indnt1
  1154.  
  1155. ;
  1156. ; Perform constant substitutions, keyword encodings,
  1157. ; and string constant encodings:
  1158. ;
  1159.  
  1160. pass1:  call initps     ;initialize for pass
  1161.         dec de
  1162. ps1a:   inc de
  1163. ps1b:   call nextch     ;process current char, return Cy on EOF
  1164.         ret c           ;done if EOF
  1165.  
  1166. ps1ba:  cp '"'          ;string to be processed?
  1167.         jp z,psstg
  1168.  
  1169.         push de         ;no. constant?
  1170.         push bc
  1171.  
  1172.         ld a,1          ;force error reporting on bad constant
  1173.         sta bcnstf
  1174.         call const
  1175.         ld a,0
  1176.         sta bcnstf      ;turn bad constant reporting back off
  1177.  
  1178.         ld a,c
  1179.         pop bc
  1180.         pop de
  1181.  
  1182.         jp c,ps1c               ;if not a constant, do potential keyword substitutions
  1183.  
  1184.         sub 3           ;it was a constant.  substitute a constant code
  1185.         call mvtxt      ; for the text of the constant.
  1186.         ld a,concd      ;key byte
  1187.         ld (de),a
  1188.         inc de
  1189.         ld a,l          ;low order byte of value
  1190.         ld (de),a
  1191.         inc de
  1192.         ld a,h          ;high order byte of value
  1193.         ld (de),a
  1194.         jp ps1a
  1195.  
  1196. ;
  1197. ; Try to match the keyword at DE (whose first char
  1198. ; is in A, already converted to upper case) with an
  1199. ; entry in the keyword table. Hashing is used on the
  1200. ; bits 0-3 of the first character. If no match is found
  1201. ; and the first character was NOT a legal identifier
  1202. ; character, then a syntax error occurs; else it is
  1203. ; assumed the string is an identifier and it is left
  1204. ; alone.
  1205. ;
  1206.  
  1207. ps1c:   ld a,b
  1208.         cp 05fh ;underscore?
  1209.         jp z,ps1h               ;if so, assume identifier
  1210.         cp 'A'          ;legal identifier char?
  1211.         jp c,ps1c3
  1212.         cp 'Z'+1
  1213.         jp c,ps1c2
  1214.         scf             ;no. set carry for later.
  1215.         jp ps1c3
  1216.  
  1217. ps1c2:  xor a           ;yes, legal ident. char.
  1218. ps1c3:  push af ;now let's do some hashing...
  1219.         ld a,b          ;get 1st char of test string
  1220.         rlca
  1221.         and 1eh
  1222.         push bc
  1223.         ld c,a
  1224.         ld b,0          ;BC = disp into hash table
  1225.         ld hl,khasht    ;HL = start of table
  1226.         add hl,bc               ;HL = address of sublist
  1227.         ld a,(hl)      
  1228.         inc hl
  1229.         ld h,(hl)
  1230.         ld l,a          ;HL -> sublist
  1231.         pop bc
  1232. ps1d:   ld a,(hl)               ;done searching list?
  1233.         cp 255
  1234.         jp z,ps1g
  1235.         and 7fh         ;no. 1st char match?
  1236.         cp b            ;if not, don't bother comparing
  1237.         jp nz,ps1f      ;       rest of string
  1238.         push bc         ;OK, compare rest of string!
  1239.         call stcmp
  1240.         ld a,c          ;save length of strings
  1241.         pop bc
  1242.         jp nz,ps1f      ;if no match, keep searching
  1243.         ld c,a          ;match...restore length into C
  1244.         pop af          ;clean up stack
  1245.         ld a,(hl)               ;get 1 byte code into text
  1246. ps1e:   ld (de),a
  1247.         inc de 
  1248.         dec c
  1249.         jp z,ps1b
  1250.         ld a,0ffh       ;and fill out space with FF's
  1251.         jp ps1e
  1252.  
  1253. ps1f:   ld a,(hl)               ;go to next table entry
  1254.         inc hl
  1255.         or a
  1256.         jp p,ps1f
  1257.         inc hl
  1258.         jp ps1d
  1259.  
  1260. ps1g:   pop af          ;search failed. could it have
  1261.         jp nc,ps1h      ; been an identifier?
  1262.         ld hl,stg99     ;no: must be syntax error.
  1263.         call perr
  1264.         jp ps1a
  1265.  
  1266. ps1h:   ld a,(de)               ;possible identifier; let it be
  1267.         call varch
  1268.         jp c,ps1b
  1269.         inc de
  1270.         jp ps1h
  1271.  
  1272.  
  1273. ;
  1274. ; process a string constant:
  1275. ;
  1276.  
  1277. psstg:  push de
  1278. psstg1: call glbl
  1279.         ld a,l
  1280.         cp 1ah
  1281.         jp z,psstg1
  1282.         ex de,hl
  1283.         lhld eofad
  1284.         ld (hl),e
  1285.         inc hl
  1286.         ld (hl),d
  1287.         inc hl
  1288.         shld stgcct
  1289.         inc hl
  1290.         pop de
  1291.         push de
  1292.         xor a
  1293.         ld c,a
  1294.         sta scc
  1295. psstg2: inc de
  1296.         ld a,(de)
  1297.  
  1298.         or a
  1299.         jp z,pstger     ;if EOF, REALLY missing quote.
  1300.  
  1301.         cp '"'
  1302.         jp z,psstg3
  1303.         cp cr
  1304.         jp z,pstger     ;if CR in text, error.
  1305.         cp newlin       ;same for newlin
  1306.         jp z,pstger
  1307.         call stgelt
  1308.         ld (hl),a
  1309.         call ckov
  1310.         inc hl
  1311.         push hl
  1312.         ld hl,scc
  1313.         inc (hl)
  1314.         pop hl
  1315.         jp nz,psstg2
  1316.  
  1317. pstger: ld hl,stgmq
  1318.         jp fatal
  1319.  
  1320. psstg3: shld eofad
  1321.         ld (hl),1ah
  1322.         lhld stgcct
  1323.         lda scc
  1324.         ld (hl),a               ;set length byte for string
  1325.         pop hl          ;get start of string
  1326.         push hl
  1327.         call cmh
  1328.         add hl,de
  1329.         ld de,78
  1330.         call cmphd      ;is HL < 78?
  1331.         jp nc,pstg3a    ;if not, do big squish
  1332.  
  1333.         ld a,l          ;else do normal mvtxt
  1334.         sub 2
  1335.         pop de
  1336.         call mvtxt
  1337.         jp pstg3b
  1338.  
  1339. pstg3a: dec hl          ;do big squish
  1340.         dec hl          ;now HL is # of bytes to squish
  1341.         pop de
  1342.         call bsqsh      ;big squish routine
  1343.  
  1344. pstg3b: ld a,strcd
  1345.         ld (de),a
  1346.         inc de
  1347.         lhld lbln
  1348.         dec hl
  1349.         ld a,l
  1350.         ld (de),a
  1351.         inc de
  1352.         ld a,h
  1353.         ld (de),a
  1354.         inc de
  1355.  
  1356.         ld b,0
  1357.         lhld nlcnt
  1358.         add hl,bc
  1359.         shld nlcnt
  1360.  
  1361.         inc c
  1362. psstg4: dec c
  1363.         jp z,ps1b
  1364.         ld a,negone
  1365.         push bc
  1366.         call mvtxt
  1367.         pop bc
  1368.         ld a,nlcd
  1369.         ld (de),a
  1370.         inc de
  1371.         jp psstg4
  1372.  
  1373. bsqsh:  push de
  1374.         ld de,80
  1375.         call cmphd      ;is HL < 80?   
  1376.         jp c,bsqsh2
  1377.         ld de,-79
  1378.         add hl,de
  1379.         pop de
  1380.         call bsqsh      ;bsqsh(HL-79);
  1381.         ld hl,79
  1382.         call bsqsh
  1383.         ret
  1384.  
  1385. bsqsh2: pop de
  1386.         ld a,l
  1387.         call mvtxt
  1388.         ret
  1389.  
  1390. ;
  1391. ; Get next string element, set carry if EOF encountered:
  1392. ;
  1393.  
  1394. stgelt: cp '\'
  1395.         ret nz
  1396.         inc de
  1397.         ld a,(de)
  1398.         cp '"'
  1399.         ret z
  1400.         cp 0ffh
  1401.         jp nz,stglt2
  1402. stglt0: inc de
  1403.         ld a,(de)
  1404.         cp 0ffh
  1405.         jp z,stglt0
  1406.         inc c
  1407. stglt1: inc de
  1408.         ld a,(de)
  1409.         cp 0ffh
  1410.         jp z,stglt1
  1411.         jp stgelt
  1412.  
  1413. stglt2: push hl
  1414.         dec de
  1415.         call chkesc
  1416.         pop hl
  1417.         dec de
  1418.         ret
  1419.  
  1420. ;
  1421. ; Check for escape sequence at text at DE:
  1422. ;
  1423.  
  1424. chkesc: ld a,(de)
  1425.         cp '\'
  1426.         scf
  1427.         inc de
  1428.         ret nz          ;did we see a backslash?
  1429.         ld a,(de)               ;yes. save the next character for later retrieval
  1430.         inc de          ;and point to character after that
  1431.         sta esctmp
  1432.         call mapuc
  1433.         cp 'N'          ;check for special escape codes. \n?
  1434.         jp nz,esc2
  1435.         ld a,newlin
  1436.         ret
  1437. esc2:   cp 'T'          ;\t?
  1438.         jp nz,esc3
  1439.         ld a,ht ;if so, turn into tab
  1440.         ret
  1441. esc3:   cp 'B'          ;\b?
  1442.         jp nz,esc4
  1443.         ld a,bs ;if so, turn into backspace
  1444.         ret
  1445. esc4:   cp 'R'          ;\r?
  1446.         jp nz,esc5
  1447.         ld a,cr ;if so, turn into carriage return
  1448.         ret
  1449. esc5:   cp 'F'          ;\f?
  1450.         jp nz,esc6
  1451.         ld a,ff ;if so, turn into formfeed
  1452.         ret
  1453. esc6:   cp '\'          ;if \\, return \ character
  1454.         ret z
  1455.         cp 27h          ;if \', return ' character
  1456.         ret z
  1457.         call odig2      ;otherwise check for octal digit
  1458.         jp nc,esc7
  1459.         lda bcnstf      ;report constant errors?
  1460.         or a
  1461.         lda esctmp      ;if not octal digit, use the character and ignore the
  1462.         ret z           ; backslash, unless we need to report an error...
  1463. esc6a:  ld hl,stg8a     ;bad octal constant error.
  1464.         jp cnst2b
  1465.  
  1466.  
  1467. esc7:   ld l,a          ;OK, we have an octal digit. Put into L
  1468.         ld a,(de)               ;look at next character
  1469.         call odig2      ;octal digit?
  1470.         ld h,a          ;save in H
  1471.         ld a,l          ;get first digit
  1472.         jp c,esc8               ;if second character not octal digit, go finish up
  1473.         ld a,h          ;otherwise get second digit
  1474.         inc de          ;point to potential third digit
  1475.         call shfto      ;shift first digit to left
  1476.         ld a,(de)               ;look at potential third digit
  1477.         call odig2      ;is it octal?
  1478.         ld h,a          ;save in H in case it is
  1479.         ld a,l          ;get total of first two digits
  1480.         jp c,esc8               ;finish up  if no third digit
  1481.         ld a,h          ;get third digit
  1482.         inc de          ;point to character after third digit (closing qoute?)
  1483.                         ;and add third digit to the sum.
  1484.  
  1485. shfto:  ld h,a          ;this little routine adds the octal digit in H to
  1486.         ld a,l          ;the octal value in L, after multiplying the value
  1487.         rlca            ;in L by 8.
  1488.         rlca
  1489.         rlca
  1490.         add h
  1491.         ld l,a
  1492.         ret
  1493.  
  1494. esc8:   push af ;we've seen an illegal octal digit. if bcnstf is
  1495.         ld a,(de)               ;true and the current character isn't a quote, then
  1496.         cp '''' ;report an error. Else just return the value.
  1497.         jp z,esc9               ;Do we see a quote?
  1498.         lda bcnstf      ;no...
  1499.         or a
  1500.         jp z,esc9               ;is bcnstf true?
  1501.         pop af          ;yes, so report error
  1502.         jp esc6a
  1503.  
  1504. esc9:   pop af          ;don't need to report error; simply return value
  1505.         ret
  1506.  
  1507. odig2:  cp '0'
  1508.         ret c
  1509.         cp '8'
  1510.         ccf
  1511.         ret c
  1512.         sub '0'
  1513.         ret
  1514.  
  1515.  
  1516. ;
  1517. ; Look at current text at DE. If a constant is seen, return NC with
  1518. ; the value of the constant in HL and C containing the length of the
  1519. ; text of the constant. Else, return C set:
  1520. ;
  1521.  
  1522. const:  ld a,(de)
  1523.         cp '''' ;character constant?
  1524.         jp z,chcnst     ;if so, go handle it elsewhere
  1525.  
  1526.         call digt       ;a decimal digit?
  1527.         ret c           ;if not, then it isn't the start of any constant
  1528.                         ;else it is.
  1529.         ld c,0          ;clear character count
  1530.         ld hl,0         ;and clear accumulated value
  1531.         or a            ;first digit a zero?
  1532.         jp nz,deccn     ;if not, go handle decimal constant
  1533.         inc de          ;yes. look at next character after the zero.
  1534.         ld a,(de)
  1535.         inc c           ;and bump length count
  1536.         call mapuc
  1537.         cp 'X'          ;hex constant?
  1538.         jp z,hexcn      ;if so, go handle it
  1539.         dec c           ;else must be an octal constant or 0. go back to
  1540.         dec de          ;the zero and let the octal handler take care of it.
  1541.         xor a
  1542.         jp octcn
  1543.  
  1544. cnst2a: ld hl,stg8      ;come here to diagnose constant errors.
  1545. cnst2b: call perr       ;print the error
  1546.         scf             ;set carry to indicate a bad happenning
  1547.         ret
  1548.  
  1549. hexcn:  inc de          ;process a hex constant
  1550.         ld a,(de)               ;look at next digit
  1551.         call tsthd      ;hex?
  1552.         jp c,cnst2a     ;if not, there weren't any legal digits, so complain
  1553.         dec de          ;otherwise begin accumulating
  1554. hexcn1: inc de          ;go to next character
  1555.         inc c           ;bump count
  1556.         ld a,(de)
  1557.         call tsthd      ;legal hex digit?
  1558.         jp c,octcn1     ;if not, all done
  1559.         add hl,hl               ;else shift previous sum left by 4
  1560.         add hl,hl
  1561.         add hl,hl
  1562.         add hl,hl
  1563.         add l
  1564.         ld l,a          ;add new digit
  1565.         jp hexcn1       ;and go for more
  1566.  
  1567. octcn:  add hl,hl               ;process an octal constant
  1568.         add hl,hl
  1569.         add hl,hl
  1570.         add l
  1571.         ld l,a 
  1572.         inc de
  1573.         inc c
  1574.         ld a,(de)
  1575.         call odigt
  1576.         jp nc,octcn
  1577.         ld a,(de)               ;see if this is a hex or decimal digit in an octal #...
  1578.         call tsthd
  1579.         jp c,octcn1    
  1580.         ld hl,stg8a
  1581. octcn0: call perr
  1582. octcn1: xor a
  1583.         ret
  1584.  
  1585. deccn:  push de         ;process a decimal constant..push text pointer
  1586.         inc c           ;bump char count
  1587.         ld d,h
  1588.         ld e,l          ;lde previous sum to DE
  1589.         add hl,hl               ;multiply previous sum by 10
  1590.         add hl,hl
  1591.         add hl,de
  1592.         add hl,hl
  1593.         ld e,a          ;add new digit
  1594.         ld d,0
  1595.         add hl,de
  1596.         pop de          ;get back text pointer
  1597.         inc de
  1598.         ld a,(de)               ;look at next digit
  1599.         call digt
  1600.         jp nc,deccn     ;decimal digit? if so, go process it
  1601.         ld a,(de)               ;else check for a common error, a hex digit
  1602.         call tsthd
  1603.         jp c,octcn1     ;if it isn't, no problem
  1604.         ld hl,stg8b     ;else complain about illegal decimal digit
  1605.         jp octcn0
  1606.  
  1607. ;
  1608. ; Evaluate character constant at DE, and print an error if no closing
  1609. ; quote found:
  1610. ;
  1611.  
  1612. chcnst: call chcnst1
  1613.         jp c,cnst2a
  1614.         ret
  1615.  
  1616. chcnst1:  push de
  1617.         ld b,0
  1618.         inc de
  1619.         call chkesc
  1620.         ld c,a
  1621.         ld a,(de)
  1622.         cp ''''
  1623.         jp z,chcns3
  1624.         call chkesc
  1625.         ld b,a
  1626.         ld a,(de)
  1627.         cp ''''
  1628.         jp z,chcns3
  1629.         pop hl
  1630.         scf
  1631.         ret
  1632.  
  1633. chcns3: inc de
  1634.         pop hl
  1635.         call cmh
  1636.         add hl,de
  1637.         ld h,b
  1638.         ld b,l
  1639.         ld l,c
  1640.         ld c,b
  1641.         xor a
  1642.         ret
  1643.  
  1644.  
  1645. digt:   call mapuc
  1646.         sub '0'
  1647.         cp 10
  1648.         ccf
  1649.         ret
  1650.  
  1651. tsthd:  call digt
  1652.         ret nc
  1653.         sub 7
  1654.         cp 10
  1655.         ret c
  1656.         cp 16
  1657.         ccf
  1658.         ret
  1659.  
  1660. odigt:  call digt
  1661.         ret c
  1662.         cp 8
  1663.         ccf
  1664.         ret
  1665.  
  1666.  
  1667.  
  1668. ;
  1669. ; This routine gets next character from text area, returning Cy set
  1670. ; if EOF encountered, Z set if byte is to be ignored,  and properly
  1671. ; handling MODBEG, MODEND and line count via NLCNT:
  1672. ;
  1673.  
  1674. nextch: ld a,(de)
  1675.         cp 0ffh ;ignore FF (filler) bytes
  1676.         jp z,nextc5
  1677.  
  1678.         or a            ;zero byte indicates EOF
  1679.         scf             ;set Cy for EOF
  1680.         ret z
  1681.  
  1682.         cp modbeg       ;adjust line number processing for include files
  1683.         jp nz,nextc2
  1684.         inc de
  1685.         call pushmn
  1686.         jp nextch       ;and go for next char
  1687.  
  1688. nextc2: cp modend
  1689.         jp nz,nextc3
  1690.         call popmn
  1691.         jp nextc5       ;and go for 'nother char
  1692.  
  1693. nextc3: call mapuc
  1694.         ld b,a
  1695.         cp cr
  1696.         jp nz,nextc4    ;if not CR, all done...return the char
  1697.  
  1698.         call ckabrt     ;found CR: check for abortion at end of every line
  1699.         call bumpnl
  1700. nextc4: or a            ;clear Cy
  1701.         ret
  1702.  
  1703. nextc5: inc de          ;internal looping point for nextch
  1704.         jp nextch
  1705.  
  1706.  
  1707. ;
  1708. ; Process all labels in the source file.
  1709. ;
  1710.  
  1711. lblpr:
  1712.         ld a,1
  1713.         sta mapucv      ;DON'T map to upper case in stcmp routine
  1714.         call initps
  1715.         dec de
  1716. lblp1:  inc de
  1717.         call pascd
  1718.         cp lbrcd        ; '{' for start of new function?
  1719.         jp nz,lblp2
  1720.         push de         ;yes.
  1721.         lhld nlcnt
  1722.         shld savnlc     ;save line number of function start for error reports
  1723.         push hl
  1724.         call flblp      ;find labels
  1725.         pop hl
  1726.         shld nlcnt
  1727.         pop de
  1728.         call flblv      ;resolve labels.
  1729.         call ckabrt     ;check for using typing control-C
  1730.         jp lblp1
  1731.  
  1732. lblp2:  or a            ;EOF?
  1733.         jp nz,lblp1     ;if not, go for more text.
  1734.         xor a
  1735.         sta mapucv      ;restore stcmp to normal map-to-upper-case mode
  1736.         ret             ;yes. all done.
  1737.  
  1738. ;
  1739. ; Find labels in a function.
  1740. ;
  1741.  
  1742. flblp:  ld hl,lblt
  1743.         shld lblp
  1744.         ld (hl),0
  1745.         xor a
  1746.         sta clev
  1747.         dec de
  1748. flp0:   inc de
  1749. flp1:   call pascd
  1750.         jp nz,flp1a     ;EOF before function ends?
  1751.                         ;if so...
  1752. lblerr: lhld savnlc     ;put start of function into line number register
  1753.         shld nlcnt
  1754.         lhld modstp     ;advance module stack ptr to cancel popping at EOF
  1755.         ld de,14
  1756.         add hl,de
  1757.         shld modstp
  1758.         ld hl,stgsuf    ;screwed-up function message
  1759.         jp fatal
  1760.  
  1761. flp1a:  cp lbrcd        ; '{'?
  1762.         jp nz,flp2
  1763.         ld hl,clev      ;yes. bump level count.
  1764.         inc (hl)
  1765.         jp flp4
  1766.  
  1767. flp2:   cp rbrcd        ; '}' ?
  1768.         jp nz,flp3
  1769.         ld hl,clev      ;yes. decrement level count.
  1770.         dec (hl)
  1771.         jp nz,flp4      ;done with funciton?
  1772.         ret             ;if so, return.
  1773.  
  1774. flp3:   cp elscd        ;look for keywords.
  1775.         jp z,flp4
  1776.         cp docd
  1777.         jp z,flp4
  1778.         cp semi
  1779.         jp nz,flp0      ;pass expressions.
  1780.  
  1781. flp4:   inc de          ;check for identifier.
  1782.         call igsht
  1783.         call varch      ;legal first char?
  1784.         jp c,flp1
  1785.         push de         ;yes. save text ptr.
  1786.         ld c,0          ;init char count
  1787. flp5:   inc de
  1788.         ld a,(de)
  1789.         inc c
  1790.         call varch      ;still an ident?
  1791.         jp nc,flp5
  1792. flpwsp: cp 255          ;no. ignore trailing spaces
  1793.         jp nz,flpcln    ;if no more spaces, check for colon    
  1794.         inc de          ;else pass over the space
  1795.         ld a,(de)               ;get next char
  1796.         inc c           ;bump count
  1797.         jp flpwsp       ;and keep looking for non-space
  1798.  
  1799. flpcln: cp colon        ;no. followed by a colon?
  1800.         pop hl          ;pop start of label into HL
  1801.         jp nz,flp1
  1802.         ex de,hl                ;put start of label ptr into DE
  1803.         push de         ;push it
  1804.         push bc         ;push count
  1805.         push bc         ; a few times
  1806.         push de         ;and push label ptr again
  1807.         xor a
  1808.         sta sf
  1809.         call flbl
  1810.         pop de          ;restore label ptr in DE
  1811.         pop bc          ;restore count into C
  1812.         jp c,flp5a
  1813.         ld hl,stgml     ;all labels must be unique
  1814.         call perr
  1815.         ld hl,sf
  1816.         inc (hl)
  1817. flp5a:  lhld lblp       ;store the label away
  1818. flp6:   ld a,(de)
  1819.         dec c
  1820.         jp z,flp7
  1821.         cp 255          ;don't save space as part of the name
  1822.         jp z,flp6a     
  1823.         ld (hl),a
  1824.         inc hl
  1825. flp6a:  inc de
  1826.         jp flp6
  1827.  
  1828. flp7:   cp 255          ;last char space?
  1829.         jp nz,flp7a     ;if not, treat normally
  1830.         dec hl
  1831.         ld a,(hl)               ;else get last legit char      
  1832. flp7a:  or 80h
  1833.         ld (hl),a
  1834.         inc hl
  1835.         ex de,hl
  1836.         lhld lbln
  1837.         ex de,hl
  1838.         ld (hl),e      
  1839.         inc hl
  1840.         ld (hl),d
  1841.         inc hl
  1842.         lda sf
  1843.         or a
  1844.         jp nz,flp8
  1845.         shld lblp
  1846.         ld (hl),0
  1847. flp8:   pop bc
  1848.         pop de
  1849.         ld a,c
  1850.         sub 2
  1851.         call mvtxt
  1852.         call glbl
  1853.         ld a,lblcd
  1854.         ld (de),a
  1855.         inc de
  1856.         ld a,l
  1857.         ld (de),a
  1858.         inc de
  1859.         ld a,h
  1860.         ld (de),a
  1861.         jp flp4
  1862.  
  1863. stgml:  db 'Duplicate label+'
  1864.  
  1865. ;
  1866. ; Resolve label references:
  1867. ;
  1868.  
  1869. flblv:  dec de
  1870.         xor a
  1871.         sta clev
  1872. flv0:   inc de
  1873.         call pascd
  1874.         jp z,lblerr     ;if EOF, go complain
  1875.  
  1876.         cp lbrcd
  1877.         jp nz,flv1
  1878.         ld hl,clev
  1879.         inc (hl)
  1880.         jp flv0
  1881.  
  1882. flv1:   cp rbrcd
  1883.         jp nz,flv2
  1884.         ld hl,clev
  1885.         dec (hl)
  1886.         jp nz,flv0
  1887.         ret
  1888.  
  1889. flv2:   cp gotcd        ;"goto" keyword?
  1890.         jp nz,flv0
  1891.         inc de          ;yes.
  1892.         call flbl       ;label entered in table?
  1893.         jp nc,flv5      ;if so, go process
  1894.         ld hl,stg26
  1895.         call perr
  1896.         push de
  1897.         ld c,0
  1898. flv3:   ld a,(de)
  1899.         call varch
  1900.         jp c,flv4
  1901.         inc de
  1902.         inc c
  1903.         jp flv3
  1904.  
  1905. flv4:   pop de
  1906. flv5:   call lblsb      ;do substitution
  1907.         jp flv0
  1908.  
  1909. ;
  1910. ; Find label in label table:
  1911.  
  1912. flbl:   call igsht
  1913.         ld hl,lblt
  1914. flbl2:  ld a,(hl)
  1915.         or a
  1916.         scf
  1917.         ret z
  1918.         call stcmp
  1919.         ret z
  1920.  
  1921. flbl3:  ld a,(hl)              
  1922.         or a
  1923.         inc hl
  1924.         jp p,flbl3
  1925.         inc hl
  1926.         inc hl
  1927.         jp flbl2
  1928.  
  1929. lblsb:  ld a,(hl)
  1930.         inc hl
  1931.         ld h,(hl)
  1932.         ld l,a
  1933.         ld a,c
  1934.         sub 3
  1935.         push hl
  1936.         call mvtxt
  1937.         pop hl
  1938.         ld a,labrc
  1939.         ld (de),a
  1940.         inc de 
  1941.         ld a,l
  1942.         ld (de),a
  1943.         inc de
  1944.         ld a,h
  1945.         ld (de),a
  1946.         ret
  1947.  
  1948.  
  1949. stcmp:  push de
  1950.         push hl
  1951.         ld c,1
  1952. stcp1:  ld a,(hl)
  1953.         and 7fh
  1954.         call mapuc0
  1955.         ld b,a
  1956.         ld a,(de)
  1957.         call mapuc0
  1958.         cp b
  1959.         jp z,stcp2
  1960. stcp1a: pop hl
  1961.         pop de
  1962.         xor a
  1963.         inc a
  1964.         ret
  1965. stcp2:  ld a,(hl)
  1966.         or a
  1967.         inc hl
  1968.         jp m,stcp3
  1969.         inc de
  1970.         inc c
  1971.         jp stcp1
  1972. stcp3:  ld a,b
  1973.         call varch
  1974.         jp nc,stcp4
  1975. stcp3a: xor a
  1976.         pop de
  1977.         pop de
  1978.         ret
  1979. stcp4:  inc de
  1980.         ld a,(de)
  1981.         call varch
  1982.         ccf
  1983.         jp c,stcp1a
  1984.         jp stcp3a
  1985.  
  1986.  
  1987. ;
  1988. ; This section of code (PASS X) goes through the code and
  1989. ; simplifies all constant expressions. Any code following
  1990. ; an open bracket ("["), open parenthesis, "case" keyword,
  1991. ; or assignment operator is checked to see if it is a
  1992. ; constant expression. If so, it is replaced by its simple
  1993. ; constant equivalent.
  1994. ;
  1995.  
  1996. passx:  call initps
  1997.         dec de
  1998. psx1:   inc de
  1999.         call igsht
  2000.         call cdtst
  2001.         jp c,psx1z
  2002.         inc de
  2003.         inc de
  2004.         jp psx1
  2005. psx1z:  inc de
  2006.         or a
  2007.         ret z
  2008.         cp comma
  2009.         jp z,psx1a
  2010.         cp openb
  2011.         jp z,psx1a
  2012.         cp open
  2013.         jp z,psx1a
  2014.         cp cascd
  2015.         jp z,psx1a
  2016.         cp rencd
  2017.         jp z,psx1a
  2018.         call asgnop
  2019.         jp z,psx1a
  2020.         dec de 
  2021.         jp psx1
  2022.  
  2023. psx1a:  call ckabrt     ;check for using typing control-C
  2024.         push de
  2025.         ld hl,opstk
  2026.         shld opstp
  2027.         ld (hl),0
  2028.         ld hl,valstk
  2029.         shld valsp
  2030.         call ckce
  2031.         jp nc,psx2
  2032.         pop de
  2033.         call igsht
  2034.         call cdtst     
  2035.         jp c,psx1
  2036.         inc de
  2037.         inc de
  2038.         jp psx1
  2039.  
  2040. psx2:   ex (sp),hl
  2041.         ex de,hl
  2042.         dec hl
  2043.         dec de
  2044.         ld c,0
  2045.  
  2046. psx2a:  inc de
  2047.         ld a,(de)
  2048.         cp nlcd
  2049.         jp nz,psx2b
  2050.         inc c
  2051. psx2b:  ld a,0ffh
  2052.         ld (de),a
  2053.         ld a,l
  2054.         cp e
  2055.         jp nz,psx2a
  2056.         ld a,h
  2057.         cp d
  2058.         jp nz,psx2a
  2059.         pop hl
  2060.         ld a,concd
  2061.         dec de
  2062.         dec de
  2063.         ld (de),a
  2064.         inc de
  2065.         ld a,l
  2066.         ld (de),a
  2067.         inc de
  2068.         ld a,h
  2069.         ld (de),a
  2070.         ld a,c
  2071.         or a
  2072.         jp z,psx1
  2073.         inc de
  2074.         ld a,c
  2075.         cpl
  2076.         inc a
  2077.         push bc
  2078.         push hl
  2079.         call mvtxt
  2080.         pop hl
  2081.         pop bc
  2082.         ld a,nlcd
  2083.  
  2084. psx2c:  ld (de),a
  2085.         inc de
  2086.         dec c  
  2087.         jp nz,psx2c
  2088.         dec de
  2089.         jp psx1
  2090.  
  2091. ;
  2092. ; This routine looks at text at DE and returns C reset
  2093. ; if there is a legal constant expression there, with
  2094. ; the value in HL; else C is set. DE is left pointing to
  2095. ; the end of the expression, or wherever it became illegal.
  2096. ;
  2097.  
  2098. ckce:   call ckce2
  2099.         ret c
  2100.         call igsht
  2101.         cp 0c0h
  2102.         jp z,qexpr
  2103.         or a
  2104.         ret
  2105.  
  2106. ckce2:  push de
  2107.         call psce
  2108.         pop de
  2109.         ret c
  2110.         call binop
  2111.         jp z,bexpr
  2112.         call sce
  2113.         ret
  2114.  
  2115. ;
  2116. ; Pass over a simple constant expression:
  2117. ;       unop sce
  2118. ;       sce
  2119. ;
  2120.  
  2121. psce:   call igsht
  2122.         cp mincd
  2123.         jp z,psce2
  2124.         cp circum
  2125.         jp z,psce2
  2126.         call pvsce
  2127.         ret
  2128.  
  2129. psce2:  inc de
  2130.         jp psce
  2131.  
  2132. ;
  2133. ; Pass very simple constant expression:
  2134. ;       (ce)
  2135. ;       constant
  2136. ;
  2137.  
  2138. pvsce:  cp open
  2139.         jp nz,pvsce2
  2140.         call mtchp
  2141.         call igsht
  2142.         or a
  2143.         ret
  2144.  
  2145. pvsce2: cp concd
  2146.         scf
  2147.         ret nz
  2148.         inc de
  2149.         inc de
  2150.         inc de
  2151.         call igsht
  2152.         or a
  2153.         ret
  2154.  
  2155. ;
  2156. ; process ?: expression:
  2157. ;
  2158.  
  2159. qexpr:  inc de
  2160.         ld a,h
  2161.         or l
  2162.         jp z,qexp2
  2163.         call ckce
  2164.         ret c
  2165.         cp colon
  2166.         scf
  2167.         ret nz
  2168.         inc de
  2169.         push hl
  2170.         call ckce
  2171.         pop hl
  2172.         ret
  2173.  
  2174. qexp2:  call psce
  2175.         cp colon
  2176.         scf
  2177.         ret nz
  2178.         inc de
  2179.         call ckce
  2180.         ret
  2181.  
  2182. ;
  2183. ; process simple constant expression:
  2184. ;       unop sce
  2185. ;       sce
  2186. ;
  2187.  
  2188. sce:    call igsht
  2189.         cp mincd
  2190.         jp nz,sce2
  2191.         inc de
  2192.         call sce
  2193.         ret c
  2194.         call cmh
  2195.         or a
  2196.         ret
  2197.  
  2198. sce2:   cp circum
  2199.         jp nz,sce3
  2200.         inc de
  2201.         call sce
  2202.         ret c
  2203.         call cmh
  2204.         dec hl
  2205.         or a
  2206.         ret
  2207.  
  2208. sce3:   call vsce
  2209.         ret
  2210.  
  2211. ;
  2212. ; process very simple constant expression:
  2213. ;       constant
  2214. ;       (ce)
  2215. ;
  2216.  
  2217. vsce:   cp open
  2218.         jp nz,vsce2
  2219.         inc de
  2220.         call ckce
  2221.         ret c
  2222.         call igsht
  2223.         cp close
  2224.         scf
  2225.         ret nz
  2226.         inc de
  2227.         ccf
  2228.         ret
  2229.  
  2230. vsce2:  cp concd
  2231.         scf
  2232.         ret nz
  2233.         inc de
  2234.         ld a,(de)
  2235.         ld l,a
  2236.         inc de
  2237.         ld a,(de)
  2238.         ld h,a
  2239.         inc de
  2240.         call igsht
  2241.         or a
  2242.         ret
  2243.  
  2244. ;
  2245. ; handle binary expression:
  2246. ;  sce binop sce binop sce ...
  2247. ;
  2248.  
  2249. bexpr:  xor a
  2250.         call oppsh
  2251.         call sce
  2252.         ret c
  2253.         call pshh
  2254.         call oppop
  2255. bxprab: call igsht
  2256.         call binop
  2257.         jp z,bxpr2
  2258.  
  2259. bxpr1:  call tstop
  2260.         jp z,bxpr5
  2261.         call popb
  2262.         call poph
  2263.         call oppop
  2264.         call alugen
  2265.         call pshh
  2266.         jp bxpr1
  2267.  
  2268. bxpr2:  call tstop
  2269.         jp z,bxpr3
  2270.         ld c,b
  2271.         call binop
  2272.         ld a,c
  2273.         cp b
  2274.         jp z,bxpr4
  2275.         jp c,bxpr4
  2276.  
  2277. bxpr3:  ld a,(de)
  2278.         call oppsh
  2279.         inc de
  2280.         jp bexpr
  2281.  
  2282. bxpr4:  call popb
  2283.         call poph
  2284.         call oppop
  2285.         call alugen
  2286.         call pshh
  2287.         jp bxprab
  2288.  
  2289. bxpr5:  call poph
  2290.         xor a
  2291.         ret
  2292.  
  2293. oppsh:  push hl
  2294.         lhld opstp
  2295.         inc hl
  2296.         shld opstp
  2297.         ld (hl),a
  2298.         pop hl
  2299.         ret
  2300.  
  2301. oppop:  push hl
  2302.         lhld opstp
  2303.         ld a,(hl)
  2304.         dec hl
  2305.         shld opstp
  2306.         pop hl
  2307.         ret
  2308.  
  2309. tstop:  push hl
  2310.         lhld opstp
  2311.         ld a,(hl)
  2312.         or a
  2313.         pop hl
  2314.         ret
  2315.  
  2316. popb:   push hl
  2317.         call poph
  2318.         ld b,h
  2319.         ld c,l
  2320.         pop hl
  2321.         ret
  2322.  
  2323. poph:   lhld valsp
  2324.         push de
  2325.         ld d,(hl)
  2326.         dec hl
  2327.         ld e,(hl)
  2328.         dec hl
  2329.         shld valsp
  2330.         ex de,hl
  2331.         pop de
  2332.         ret
  2333.  
  2334. pshh:   push de
  2335.         ex de,hl
  2336.         lhld valsp
  2337.         inc hl
  2338.         ld (hl),e
  2339.         inc hl
  2340.         ld (hl),d
  2341.         shld valsp
  2342.         ex de,hl
  2343.         pop de
  2344.         ret
  2345.  
  2346.  
  2347.  
  2348.  
  2349. binop:  ld b,9
  2350.         cp mulcd
  2351.         ret z
  2352.         cp divcd
  2353.         ret z
  2354.         cp modcd
  2355.         ret z
  2356.         dec b
  2357.         cp plus
  2358.         ret z
  2359.         cp mincd
  2360.         ret z
  2361.         dec b
  2362.         cp 0b0h
  2363.         ret z
  2364.         cp 0b1h
  2365.         ret z
  2366.         dec b
  2367.         cp 0b9h
  2368.         ret z
  2369.         cp 0bah
  2370.         ret z
  2371.         cp 0aeh
  2372.         ret z
  2373.         cp 0afh
  2374.         ret z
  2375.         dec b
  2376.         cp 0aah
  2377.         ret z
  2378.         cp 0abh
  2379.         ret z
  2380.         dec b
  2381.         cp ancd
  2382.         ret z
  2383.         dec b
  2384.         cp 0bch
  2385.         ret z
  2386.         dec b
  2387.         cp 0bdh
  2388.         ret
  2389.  
  2390. asgnop: cp letcd
  2391.         ret z
  2392.         cp 0a0h
  2393.         ret c
  2394.         cp 0aah
  2395.         jp c,asgn2
  2396.         xor a
  2397.         inc a
  2398.         ret
  2399.  
  2400. asgn2:  xor a
  2401.         ret
  2402.  
  2403.  
  2404. alugen: cp mulcd        ;*
  2405.         jp nz,alu2
  2406. alu1s:  call initsn     ;initialize sign memory
  2407.         push de
  2408.         ex de,hl
  2409.         ld hl,0
  2410. alu1a:  ld a,b
  2411.         or c
  2412.         jp nz,alu1b
  2413.         call aplysn     ;apply sign memory to result
  2414.         jp adone
  2415. alu1b:  add hl,de
  2416.         dec bc
  2417.         jp alu1a
  2418.  
  2419. initsn: xor a
  2420.         sta signm       ;clear sign memory
  2421.         push hl
  2422.  
  2423.         ld h,b
  2424.         ld l,c
  2425.         call tests      ;test BC for negativity
  2426.         ld b,h
  2427.         ld c,l
  2428.  
  2429.         pop hl
  2430.         call tests      ;test HL for negativity
  2431.         ret
  2432.  
  2433. aplysn: lda signm       ;if signm true, negate HL
  2434.         or a
  2435.         ret z
  2436.         call cmh
  2437.         ret
  2438.  
  2439. tests:  ld a,h          ;if HL is positive, do nothing
  2440.         or a
  2441.         ret p
  2442.         call cmh        ;else negate HL
  2443.         lda signm       ;and reverse sense of sign memory byte
  2444.         or a
  2445.         ld a,1
  2446.         jp z,tests2
  2447.         xor a
  2448. tests2: sta signm
  2449.         ret    
  2450.  
  2451. alu2:   cp divcd        ;/
  2452.         jp nz,alu3
  2453. alu2s:  call initsn
  2454.         push de
  2455.         ex de,hl
  2456.         ld hl,0
  2457. alu2a:  ld a,d
  2458.         cp b
  2459.         jp c,alu2c
  2460.         jp nz,alu2b
  2461.         ld a,e
  2462.         cp c
  2463.         jp c,alu2c
  2464. alu2b:  push hl
  2465.         ld h,b 
  2466.         ld l,c
  2467.         call cmh
  2468.         add hl,de
  2469.         ex de,hl
  2470.         pop hl
  2471.         inc hl
  2472.         jp alu2a
  2473. alu2c:  call aplysn
  2474.         jp adone
  2475.  
  2476. adone:  pop de
  2477.         ret
  2478.  
  2479. alu3:   cp modcd        ;%
  2480.         jp nz,alu4
  2481.         ld a,h
  2482.         or a            ;check sign of 1st operand
  2483.         push af ;save for final result sign computation
  2484.  
  2485.         call initsn     ;make sure mod is computed on positive numbers
  2486.         xor a           ;zero sign memory to force unsigned result
  2487.         sta signm
  2488.         push de
  2489.         push hl
  2490.         push bc
  2491.         call alu2s
  2492.         pop bc
  2493.         call alu1s
  2494.         call cmh
  2495.         pop de
  2496.         add hl,de
  2497.         pop de
  2498.  
  2499.         pop af          ;get sign of original 2nd operand
  2500.         ret p           ;if it was positive, leave result positive
  2501.         call cmh        ;otherwise negate result       
  2502.         ret
  2503.  
  2504. alu4:   cp plus ;+
  2505.         jp nz,alu5
  2506.         add hl,bc
  2507.         ret
  2508.  
  2509. alu5:   cp mincd        ;-
  2510.         jp nz,alu6
  2511.         push de
  2512.         ex de,hl
  2513.         ld h,b
  2514.         ld l,c
  2515.         call cmh
  2516.         add hl,de
  2517.         pop de
  2518.         ret
  2519.  
  2520. alu6:   cp 0b0h ;<<
  2521.         jp nz,alu7
  2522. alu6a:  ld a,b
  2523.         or c
  2524.         ret z
  2525.         add hl,hl
  2526.         dec bc
  2527.         jp alu6a
  2528.  
  2529. alu7:   cp 0b1h ;>>
  2530.         jp nz,alu8
  2531. alu7a:  ld a,b
  2532.         or c
  2533.         ret z
  2534.         ld a,h
  2535.         rra    
  2536.         ld h,a 
  2537.         ld a,l
  2538.         rra
  2539.         ld l,a
  2540.         dec bc 
  2541.         jp alu7a
  2542.  
  2543. alu8:   cp 0bah         ;<
  2544.         jp nz,alu9
  2545. alu8a:  ld a,h
  2546.         cp b
  2547.         ld a,l
  2548.         ld hl,1
  2549.         ret c
  2550.         dec hl
  2551.         ret nz
  2552.         cp c
  2553.         ret nc
  2554.         inc l
  2555.         ret
  2556.  
  2557. alu9:   cp 0b9h ;>
  2558.         jp nz,alu10
  2559. alu9a:  ld a,b
  2560.         cp h
  2561.         ld b,l
  2562.         ld hl,1
  2563.         ret c
  2564.         dec hl
  2565.         ret nz
  2566.         ld a,c
  2567.         cp b
  2568.         ret nc
  2569.         inc l
  2570.         ret
  2571.  
  2572. alu10:  cp 0aeh ;<=
  2573.         jp nz,alu11
  2574.         call alu9a
  2575. alu10a: ld a,h
  2576.         or l
  2577.         dec hl
  2578.         ret nz
  2579.         inc hl
  2580.         inc hl
  2581.         ret
  2582.  
  2583. alu11:  cp 0afh ;>=
  2584.         jp nz,alu12
  2585.         call alu8a
  2586.         jp alu10a
  2587.  
  2588. alu12:  cp ancd
  2589.         jp nz,alu13
  2590.         ld a,h
  2591.         and b
  2592.         ld h,a
  2593.         ld a,l
  2594.         and c
  2595.         ld l,a
  2596.         ret
  2597.  
  2598. alu13:  cp 0bch ;^
  2599.         jp nz,alu14
  2600.         ld a,h
  2601.         xor b
  2602.         ld h,a
  2603.         ld a,l
  2604.         xor c
  2605.         ld l,a
  2606.         ret
  2607.  
  2608. alu14:  cp 0bdh ;|
  2609.         jp nz,alu15
  2610.         ld a,h
  2611.         or b
  2612.         ld h,a
  2613.         ld a,l
  2614.         or c
  2615.         ld l,a 
  2616.         ret
  2617.  
  2618.  
  2619. alu15:  cp 0aah ;==
  2620.         jp nz,alu16
  2621.         ld a,h
  2622.         cp b
  2623.         jp nz,fals
  2624.         ld a,l
  2625.         cp c
  2626.         jp nz,fals
  2627. tru:    ld hl,1
  2628.         ret
  2629.  
  2630. alu16:  ld a,h          ;<not>=
  2631.         cp b
  2632.         jp nz,tru
  2633.         ld a,l
  2634.         cp c
  2635.         jp nz,tru
  2636. fals:   ld hl,0
  2637.         ret
  2638.  
  2639.  
  2640. ;
  2641. ; Table of hash addresses for each of the 16
  2642. ; keyword sub-tables:
  2643. ;
  2644.  
  2645. khasht: dw tbl0,tbl1,tbl2,tbl3
  2646.         dw tbl4,tbl5,tbl6,tbl7
  2647.         dw tbl8,tbl9,tbla,tblb
  2648.         dw tblc,tbld,tble,tblf
  2649.  
  2650. p:      equ 80h
  2651.  
  2652. tbl0:   db ' '+p,0ffh   ;spaces turn into FF's
  2653.         db  255
  2654.                
  2655.  
  2656. tbl1:   db '!','='+p,0abh
  2657.         db '!'+p,0bfh
  2658.         db 255
  2659.  
  2660. tbl2:   db 'RETUR','N'+p,8eh
  2661.         db 'BREA','K'+p,90h
  2662.         db 'REGISTE','R'+p,9eh
  2663.         db 'BEGI','N'+p,9bh
  2664.         db 255
  2665.  
  2666. tbl3:   db 'CHA','R'+p,80h
  2667.         db 'CONTINU','E'+p,91h
  2668.         db 'CAS','E'+p,98h
  2669.         db 'STRUC','T'+p,8bh
  2670.         db 'SWITC','H'+p,97h
  2671.         db 'SIZEO','F'+p,8fh
  2672.         db 'SHOR','T'+p,9fh
  2673.         db 255
  2674.  
  2675. tbl4:   db 'D','O'+p,95h
  2676.         db 'DEFAUL','T'+p,99h
  2677.         db 255
  2678.  
  2679. tbl5:   db 'ELS','E'+p,93h
  2680.         db '%','='+p,0a4h
  2681.         db '%'+p,0b8h
  2682.         db 'UNSIGNE','D'+p,82h
  2683.         db 'UNIO','N'+p,8ch
  2684.         db 'EN','D'+p,9ch
  2685.         db 255
  2686.  
  2687. tbl6:   db '&','&'+p,0ach
  2688.         db '&','='+p,0a7h
  2689.         db 'FO','R'+p,94h
  2690.         db '&'+p,0bbh
  2691.         db 'VOI','D'+p,81h              ;synonym for "int"
  2692.         db 255
  2693.  
  2694. tbl7:   db 'WHIL','E'+p,96h
  2695.         db 'GOT','O'+p,8dh      ;boo-hissssss
  2696.         db 255
  2697.  
  2698. tbl8:   db '('+p,0c2h
  2699.         db 255
  2700.  
  2701. tbl9:   db ht+p,0ffh
  2702.         db ')'+p,0c3h
  2703.         db 'I','F'+p,92h
  2704.         db 'IN','T'+p,81h
  2705.         db 255
  2706.  
  2707. tbla:   db ':'+p,0cah
  2708.         db '*','='+p,0a2h
  2709.         db '*'+p,0b6h
  2710.         db 255
  2711.  
  2712. tblb:   db ';'+p,0c6h
  2713.         db '{'+p,9bh
  2714.         db '['+p,0c8h
  2715.         db '+','+'+p,0b2h
  2716.         db '+','='+p,0a0h
  2717.         db '+'+p,0c4h
  2718.         db 255
  2719.  
  2720. tblc:   db ','+p,0c7h
  2721.         db '|','|'+p,0adh
  2722.         db '|','='+p,0a9h
  2723.         db '|'+p,0bdh
  2724.         db '<<','='+p,0a6h
  2725.         db '<','='+p,0aeh
  2726.         db '<','<'+p,0b0h
  2727.         db '<'+p,0bah
  2728.         db 255
  2729.  
  2730. tbld:   db cr+p,nlcd
  2731.         db ']'+p,0c9h
  2732.         db '}'+p,9ch
  2733.         db '=','='+p,0aah
  2734.         db '='+p,0beh
  2735.         db '-','>'+p,0b4h
  2736.         db '-','-'+p,0b3h
  2737.         db '-','='+p,0a1h
  2738.         db '-'+p,0b5h
  2739.         db 255
  2740.  
  2741. tble:   db '>>','='+p,0a5h
  2742.         db '>','='+p,0afh
  2743.         db '>','>'+p,0b1h
  2744.         db '>'+p,0b9h
  2745.         db '^','='+p,0a8h
  2746.         db '.'+p,0c5h
  2747.         db '^'+p,0bch
  2748.         db '~'+p,0cbh
  2749.         db 255
  2750.  
  2751. tblf:   db '?'+p,0c0h
  2752.         db '/','='+p,0a3h
  2753.         db '/'+p,0b7h
  2754.         db 255
  2755.  
  2756.