;
; CC1: the first pass of the C compiler...
; MARC-generalized version
;
; 7/17/82: added -w to write debugger info file and insert restarts
; 7/18/82: changed -w to -k<n> (for Kirkland), taking n as the restart
; vector to use (1-7), defaults to 6.
; 8/22/82: Fixed mvtxt to not overflow stack in recursion
; 9/9/82: Added search path mechandsm to cc2.com auto-load, made FF def.
; disk and user use "current" as default
; 10/6/82: added auto-".c" on main file feature
; 11/85: Added -z option to use RST 1 - RST 5 for value-fetch optimization
; 12/85: Added RED logic to write out PROGERRS.$$$ error file
;
;
IF NOT LASM AND NOT SLRMAC
maclib cc
ENDIF
jp cc1
db cr,lf
db 'Copyright (c) 1982, 83, 84 by Leor Zolman'
db cr,lf,lf
db 'Please don''t rip me off.'
db cr,lf,lf,1ah
patch0: db 0,0,0,0,0,0,0,0 ;space to expand message
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Configuration block area:
;
defdsk: db 0ffh ;default library disk drive
defusr: db 0ffh ;default library user area
defsub: db 00h ;default disk to find submit file on
conpol: db 1 ;true to poll the console for interrupts
wboote: db 0 ;true to always do warm-boot on exit
;zenvf: ds 1 ;true if Z environment
; ;new for v1.51:
pstrip: db 1 ;true to strip parity when reading source file
IF ALPHA
nouser: db 1 ;true to disable all user-area operations performed
ENDIF ; by CC, for special kinds of systems that like it
IF NOT ALPHA
nouser: db 0 ;false to allow user area changes
ENDIF
werrs: db 0 ;write errors flag, for RED interface
optim: db 80h ;0: optimize for speed, use all long code sequences
;b7 true: optimize for space, in general
;b0-b6 true: use RST1-RST7 (respectively)
; for -Z optimization through restart vectors
krst: db 6 ;default CDB restart vector
zenvf: ds 1 ;true if Z environment
;
; End Configuration Block
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
patch: dw 0,0,0,0,0,0,0,0 ;patch space
patch2: dw 0,0,0,0,0,0,0,0
patch3: dw 0,0,0,0,0,0,0
;
; Beginning of compiler code:
;
cc1:
;OS_HIDEFROMPARENT
;ld e,6 ;textmode
;OS_SETGFX
call initstdio
;shld zenvad ;TODO remove ;save Z environment pointer
;ld hl,0 ;save current SP for possible use in returning to CCP
;add hl,sp
;shld spsav
;ld sp,stack ;set up private stack
call ccinit ;perform general initializations
IF CPM AND NOT ALPHA
call chkusr ;check for user number on main filename
ENDIF
call comlin ;process command line options
call readf ;read in file(s), strip comments
call prep ;process #define lines
call pitext ;print out intermediate text if specified
call pass1 ;convert keywords,constants,strings
call lblpr ;process labels and references
call passx ;proccess constant expressions
call bst ;build symbol table
call passc ;process control structure
call fixt ;purge FF's and stuff from text
call mkfnt ;make function name table
call wst4db ;write symbol table for debugger
call chopst ;chop off 1st 8 bytes of st entries
call mvfnt ;lde func name table adj to text
call errwrp ;wrap up error handling
call usage ;print out memory usage diagnostic
call writf ;write out file
jp exit ;all done
;
; Static data area:
;
IF CPM
;spsav: ds 2 ;save stack pointer for non-booting return
ccpok: ds 1 ;true if CCP still intact
erasub: ds 1 ;true if erasing submit files
curusr: ds 1 ;current disk (CP/M)
origusr: ds 1
curdsk: ds 1 ;current user area (CP/M)
origdsk: ds 1
cc2dsk: ds 1 ;default disk to search for cc2
cc2usr: ds 1 ;default user area to search for cc2
dodotc: ds 1 ;true to try ".C" if no ext given and file not found
ENDIF
curtop: ds 2 ;end of availlable TPA memory
preflag:ds 1 ;true when still pre-processing
pflag: ds 1 ;print intermediate text flag ("p" option)
sdisk: ds 1 ;disk # where source came from
chainf: ds 1 ;true if we want to chain to CC2
loadad: ds 2 ;load address
eflag: ds 1 ;true if -e option given
exaddr: ds 2 ;value given to -e option
cnflag: ds 1 ;true if comments nest
okflag: ds 1 ; "readm" routine success flag
mapucv: ds 1 ;no upper case mapping in "stcmp" routine flag
IF CPM
cfcb: db 0,'CC2 COM',0,0,0,0
subfile: db 1,'$$$ SUB',0,0,0,0
redfcb: db 0,'PROGERRS$$$',0,0,0,0
ds 17 ;rest of fcb for RED error file
redbuf: ds 128 ;text buffer for RED error file
redbp: ds 2 ;pointer into text buffer
errsin: ds 1 ;true if RED output is active
nomore: ds 1 ;true if future red error output is disabled
ENDIF
modstk: ds (fnlen + 2) * (nestmax + 1)
modstp: ds 2 ;pointer to currently active filename
modstc: ds 1 ;counter
casoff: ds 1 ;case overflow flag
esctmp: ds 1
errad: ds 2
eradf: ds 1
scc: ds 1 ;string character count for psstg
stgcct: ds 2 ;points to where length byte goes for psstg
nlflag: ds 2 ;used in the pitext routine for something or other
nltmp2: ds 1
nltmp: ds 2
modaf: ds 1 ;whether to modify st ptrs after wrapup or not
inadsv: ds 2 ;some more kludgery to allow multiple struct
;elements to have same name in separate structs
stsiz: ds 2
coda: ds 2
fndtmp: ds 1
mvtmp: ds 1
errf: ds 1
cmntf: ds 1
udiag: ds 1
stgf: ds 1
csf: ds 1
sf: ds 1
flev: ds 1
fixfl: ds 1
pdfd: ds 1 ;previously declared func. def. flag
pdfdno: ds 2 ;symbol # for above
stor: ds 2
strsz: ds 2
mxsiz: ds 2
tmplf: ds 2
tmpbs: ds 1
tmpsu: ds 1
fbufp: ds 2
opena: ds 2
stno: ds 2
fntp: ds 2
fnts: ds 2
fnc: ds 2
lbln: ds 2
eofad: ds 2
meofad: ds 2 ;max eofad for elbowroom announcement
nlcnt: ds 2
nlcnts: ds 2 ;save nlcnt when in #include file
ptfnf: ds 1
type: ds 1
stelf: ds 1
forml: ds 1
what: ds 1
lind: ds 1
clev: ds 1
clevb: ds 1
clevt: ds 1
unflg: ds 1
newid: ds 1 ;used for flagging undefined structure identifiers
adrs: ds 2
size: ds 2
dmsiz: ds 2
tempd: ds 2
tempdp: ds 2
tmpa: ds 2
savsta: ds 2
tmpfr: ds 2
fndad: ds 2
extsa: ds 2
stp: ds 2
mtpln: ds 2
symno: ds 2
funcf: ds 2
z80f: ds 1
frmrf: ds 1
esadr: ds 2
lcnt: ds 1 ;used by parameterized #define preprocessor
operad: ds 2 ;where option error begins
odisk: ds 1 ;output disk designation
semiok: ds 1
nlfnd: ds 1 ;used by decf routine
kflg: ds 1 ;true if "-k" option given to write CDB file
signm: ds 1 ;used by "passx", put here just to be safe...
cpyend: ds 2 ;parameter to "copy" routine showing end address
bcnstf: ds 1 ; (readf, pass1) true when bad char constants must
; be flagged as an error
ascb: ds 4
db ': ',0
ds 10
;stkchk: ds 2 ;if this ever gets clobbered, stack has overflowed
; ds 320
;stack: equ $
stg2: db 'Close error+'
stg3: db 'File output error; dir or disk full?+'
stgoer: db '": option error+'
stg10: db 'Encountered EOF unexpectedly',cr,lf
db ' (check curly-brace balance)+'
stg12: db 'Unmatched right brace+'
stg14: db 'Undeclared identifier: ',0
stg15: db 'Illegal external statement+'
stg16: db 'Bad declaration syntax+'
stg17: db 'Missing legal identifier+'
stg19: db 'Function definition not external+'
stg20: db 'Need explicit dimension size+'
stg21: db 'Too many dimensions+'
stg22: db 'Bad dimension value+'
stg23: db 'Bad parameter list element+'
stg24: db 'Redeclaration of: ',0
stg25: db 'Missing semicolon+'
stg27: db 'Expecting "{" in struct or union def+'
stg28: db 'Illegal structure or union id+'
stgbft: db 'Bad function type+'
stg28a: db 'Undefined structure id+'
stgdu: db '*Unnamed'
stg40: db 'Expecting "("+'
stgbp: db 'Unmatched left parenthesis+'
stgstk: db 'Stack Overflow: ' ; keep these two together
stgov: db 'Sorry; out of memory+'
stgtc: db 'I''m totally confused. '
db 'Check your control structure!+'
stgom: db 'Out of symbol table space; specify more...+'
stgtmf: db 'Too many functions (63 max)',0
stgmq: db 'String too long (or missing quote)+'
stgbsd: db 'Attribute mismatch from previous declaration+'
stgelb: db 'elbowroom',cr,lf,0;cr,0
stgunu: db 'unused',cr,lf,0;cr,0
oshit: db 'Internal Error...Call BDS+'
stgcce: db cr,lf
IF CPM
db 'Can''t find CC2.COM; writing CCI file to disk'
ENDIF
db cr,lf,0
stgiep: db 'Include @',0
stgilc: db 'Illegal "{" encountered externally',0
stgtmi: db 'Declaration too complex+'
stgbfd: db 'Missing from formal parameter list: ',0
stgabo: db 'Compilation aborted by ^C+'
stgeri: db cr,lf,'RED error output initiated+',0
;
; passc error messages:
;
stgc1: db 'Mismatched control structure',cr,lf,0
stgc2: db 'Expecting "while"',cr,lf,0
stgc7: db 'Illegal break or continue',cr,lf,0
stgc6: db 'Bad "for" syntax',cr,lf,0
stgc8: db 'Expecting "{" in switch statement',cr,lf,0
stgc9: db 'Bad "case" constant',cr,lf,0
stgc10: db 'Illegal statement',cr,lf,0
stgcof: db 'Too many cases (200 max per switch)',cr,lf,0
stgddf: db 'Can''t have more than one `default:''',cr,lf,0
;
; Initialize compiler flags and variables:
;
ccinit: call zsetup
lhld protm ;0 there!!! who must write there???
shld curtop
lhld errbyt
ld (hl),0 ;no error by default
ld hl,stg0 ;print sign-on message
call pstgco ;print to console only
;ld c,gdisk ;get current disk and user area
;call bdos
xor a ;TODO getpath
sta curdsk ;store current disk
sta origdsk ;and save as original disk upon invokation of CC
IF NOT ALPHA
;ld c,sguser ;set/get user area
;ld e,0ffh
;lda nouser
;or a
;call z, bdos
xor a
sta curusr ;store current user area
sta origusr ;and save as original user area upon invoking CC
ENDIF
lda defdsk ;set cc2 search path
inc a ;first set disk
sta cc2dsk
lda defusr
cp 0ffh ;and user area. default to current?
jp nz,cc2
lda curusr ;if so, set to current user area
cc2: sta cc2usr
lda defsub
inc a ;if FF, make current; else, make explicit disk code
jp nz,cc3 ;if not set to find submit files on current disk, don't
lda curdsk ;else set current disk as explicit disk byte in SUB.$$$
inc a ; fcb in case we abort in the middle of file read
cc3: sta subfile ;set disk to find $$$.SUB on
lda pstrip ;does user want parity stripped on input file?
or a
jp nz,cc3a ;if so, do nothing (strips by default)
IF IMPURE
ld a,0 ;IMPURE CODE: *** NOP ***
sta stripp
ld a,0b7h ;IMPURE CODE: *** or A ***
sta stripp+1
ENDIF
cc3a:
IF CPM ;initialize some CP/M-only parameters
lda fcb ;get source disk #
sta sdisk ;save it
sta odisk
ld de,tbuff ;set tbuff explicitly, to facilitate debugging
ld c,sdma ;of the 4200h version on my 0-based system
call bdos
ENDIF
xor a ;initialize following flags to FALSE:
sta kflg ;no debugger features by default
sta eflag ;no -e option yet
sta errf ;error ocurred flag
sta eradf
sta mapucv ;no-upper-case-mapping on string-compare flag
sta pflag
sta z80f ;false for 8080, true for Z80
sta semiok
sta nomore ;allow RED output for starters
IF CPM
sta cfcb
sta erasub ;don't bother erasing SUBMIT files unless -x given
sta errsin ;no RED error file active yet
ENDIF
inc a ;initialize following flags to TRUE:
sta preflag
sta chainf
IF CPM
sta cnflag ;assume comments nest for starters
sta ccpok ;CCP intact at first under CP/M
ENDIF
ld a,2 ;find out if we're on Z80 or 8080
inc a
jp pe,cc1z ;if on Z80,
sta z80f ;will come here to set z80 flag.
cc1z: ld hl,dfstsz ;default symbol table size
shld stsiz
ld hl,tpa ;default load address for generated code
shld loadad
ld hl,0a55ah ;for stack overflow check
shld stkchk
ld hl,0 ;reset label counter
shld lbln
ret
IF CPM AND NOT ALPHA
chkusr:
ld de,fcb+1 ;check to see if user area given on filename
call gdec ;number?
ret c ;if not, no problem
ld a,(de)
cp '/' ;user area prefix character?
ret nz
ld hl,stgnua ;can't give user area
jp pstgab
ENDIF
zsetup: xor a
sta zenvf ;not z environment by default
ld hl,errdum
shld errbyt ;dummy error byte by default
ld a,1
sta oktort ;ok to return to ccp, despite ccpok for now
lhld zenvad ;TODO remove
push hl
ld de,1bh
add hl,de
ld e,(hl)
inc hl
ld d,(hl) ;get reflexive env addr from env
pop hl ;original Z env value
call cmphd ;save as reflexive address?
jp nz,setp2a ;if not z system, set top of memory
ld a,1
sta zenvf ;Z system.
push hl ;save env pointer
ld de,3fh ;get potential ccp address
add hl,de
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
shld ccpad
pop hl ;get env pointer
push hl
ld de,22h
add hl,de
ld a,(hl)
inc hl
ld h,(hl)
ld l,a ;HL -> message buffer
ld de,6 ;get address of error byte
add hl,de
shld errbyt ;save the address
pop hl
ld de,8 ;get type
add hl,de
ld a,(hl)
sta envtyp
and 80h ;b7 hi?
lhld ccpad
jp nz,setup3 ;if so, use ccpad as ccp address
setp2a: lhld ram+1 ;else calculate the old way
ld de,-1603h
add hl,de
setup3: xor a ;clear 'ccp volatile' flag
sta ccpok ;and CCP INTACT flag
ex de,hl ;put ccp address in DE
ld hl,NEDOOSMEMTOP;lhld bdosp
ld l,0 ;zero out low-order byte
call cmphd ;set Cy if [BASE+6,7] < CCP
jp c,setup4 ;if BASE+6 < CCP, use BASE+6 as end of prot mem
ex de,hl ;else use CCP as end of prot. mem.
ld a,1 ;and set ccp volatile flag
sta ccpok ;and set ccpok
xor a ;NOT ok to return to ccp despite ccpok
sta oktort
setup4: shld protm
ret
envtyp: ds 1
;zenvf ;is after wboote
zenvad: ds 2 ;address of Z3 environment block
ccpad: ds 2 ;address of CCP for type 80h ZCPR3
protm: ds 2 ;start of protected memory
oktort: ds 1 ;ok to return to ccp despite ccpok flag?i
errbyt: ds 2 ;message buffer error byte address
errdum: ds 1 ;in case we're NOT under ZCPR3...
;
; Process command line options:
;
comlin:
ld hl,st ;init symbol table free space pointer
shld stp
IF CPM
;lda tbuff
;add a,81h
;ld l,a
;ld h,tbuff/100h
;ld (hl),0 ;place 00 at end of command line
ld de,tbuff;+1 ;DE will be text pointer as we process
;call igsp ;find source file name ;skip spaces in (de) (z=end of line, nz=text found)
call fspac ;skip word in (de) (z=end of line, nz=text found)
ld hl,stg1 ;is it there?
jp z,pstgab ;if not, error.
ld (filenameaddr),de
call fspac ;pass it, and any blanks after it.
ENDIF
IF CPM
cc11: call igsp ;done processing line?
ex de,hl
shld operad ;save in case of error
ex de,hl
ENDIF
cc111: ret z ;if so, go compile
cp '-' ;dash?
jp nz,operr ;if not, operand error
inc de ;get option character
ld a,(de)
call mapuc ;convert to upper case
inc de ;advance pointer past option character
cc12a:
IF NOT ALPHA
cp 'K'
jp nz,cc12d
call gdec ;get optional restart param
jp nc,cc12b ;param given?
lda krst ;if not, use default value
jp cc12c ;if not, make it 6
cc12b: cp 8
jp nc,operr ;if >=8, error...else OK
cc12c: sta kflg ;set debugging mode with restart value
jp cc11
cc12d: cp 'W' ;flip error file activity?
jp nz,cc12
lda werrs ;get write error flag
xor 1 ;logically invert
sta werrs ;and save it back
jp cc11
ENDIF
cc12: cp 'O' ;optimize for speed flag?
jp nz,cc13
xor a ;if so, no longer optimizing for space
sta optim
jp cc11
cc13: cp 'Z' ;RST optimization flag?
jp nz,cc13z
ld a,(de)
call legdd ;any parameters given?
jp nc,cc13c ;if not, assume full optimization
ld a,0bfh ;if not, assume we're using all RST locations
sta optim
jp cc11
cc13c: ld b,a
ld a,80h ;paramters supplied. Activate only
sta optim ;those optimizations with supplied parameters
ld a,b
cc13a: or a ;check for range between 1-7
jp z,operr
cp 8
jp nc,operr
ld b,a ;save rst code in B
ld c,80h ;start walking bit at left, to be rotated into low bit
cc13b: ld a,c ;shift bit left
rlca
ld c,a
dec b
jp nz,cc13b ;loop till done shifting
lda optim
or c
or 80h ;set space optimization bit, just in case
sta optim
inc de
ld a,(de) ;any more vector specifications?
call legdd
jp nc,cc13a
jp cc11 ;else all done
cc13z: cp 'P' ;print flag?
jp nz,cc14
sta pflag
jp cc11
cc14: cp 'R' ;symbol reservation option?
jp nz,cc15
call gdec ;get A=decimal number, 0-19
cp 7
jp c,operr ;if < 7 or >19 then error.
cp 20
jp nc,operr
add a
add a
ld h,a
ld l,0
shld stsiz ;set symbol table size to nK
jp cc11
cc15:
IF CPM
cp 'A' ;auto-load option? (CP/M only)
jp nz,cc16
call gdskc ;get disk code, 1-16, or 0 for 'Z'
sta cfcb ;set disk field of cc2 fcb
sta chainf ;if 0, this prevents auto-chaining
sta cc2dsk ;set default cc2 search disk
call gdec ;user number given?
jp c,cc11
sta cc2usr ;if so, set default cc2 search search area
jp cc11
ENDIF
IF CPM
cc16: cp 'D' ;output disk specification?
jp nz,cc16a ;if not, check for other options
call gdskc ;get disk letter
or a
jp z,operr ;don't allow 'Z'
sta odisk
jp cc11
ENDIF
IF CPM
cc16a: cp 'X'
jp nz,cc17
ld a,1
sta erasub ;erase submit files
jp cc11
ENDIF
cc17:
IF NOT ALPHA
cp 'M' ;load address specifier?
jp nz,cc18
call ghxarg ;get hex arg in HL
jp c,operr
shld loadad
jp cc11
ENDIF
cc18: cp 'E' ;set external address?
jp nz,cc19 ;if not, illegal option
sta eflag ;set external address specified flag
call ghxarg ;get value
jp c,operr
shld exaddr
jp cc11
cc19: cp 'C'
jp nz,operr
IF CPM
xor a
ENDIF
sta cnflag ;now comments don't nest under CPM, and DO
jp cc11 ; nest under MARC
ghxarg: call igsp ;yes. check for hex arg
scf
ret z ;return error (c set) if no arg
call leghd
ret c ;if not legal hex digit, error
ld hl,0 ;else prepare to accumulate value in HL
cc17a: ld a,(de)
call leghd
jp nc,cc17b ;end of value text?
xor a
ret ;yes. clear carry and return value in HL
cc17b: add hl,hl ;no. multiply accumulator by 16
add hl,hl
add hl,hl
add hl,hl
ld c,a ;and add new digit
ld b,0
add hl,bc
inc de ;and go to next character
jp cc17a
operr: ld a,'"'
call outch
lhld operad
operr1: ld a,(hl)
or a
jp z,operr2
call outch
inc hl
ld a,l
dec a
cp e
jp nz,operr1
operr2: ld hl,stgoer ;op error string
jp pstgab
IF CPM
gdskc: call igsp
jp z,operr
sub 'A'-1
cp 27
jp nc,operr
inc de ;bump past the char
cp 26 ;change 'Z' to zero
ret nz
xor a
ret
ENDIF
;skip spaces in (de) (z=end of line, nz=text found)
igsp: ld a,(de)
or a
ret z
call mapuc
cp ' '
ret nz
inc de
jp igsp
IF CPM
;skip word in (de) (z=end of line, nz=text found)
fspac: ld a,(de)
or a
ret z
inc de
cp ' '
jp nz,fspac
jp igsp
ENDIF
gdec: ld b,0
call igsp
call legdd
ld a,0
ret c
gdec1: ld a,(de)
call legdd
ld a,b
ccf
ret nc
add a ;get A = 10 * B
add a ;(*4)
add a ;(*8)
add b ;(*9)
add b ;(*10)
add c ;now add new digit value in C
ld b,a ;put into B
inc de
jp gdec1 ;and go for more
;
; Check for legal decimal digit, return Cy set if illegal,
; else the binary value of the digit in A:
;
legdd: call mapuc
sub '0'
ld c,a
ret c
cp 10
ccf
ret
;
; Check for legal hex digit:
;
leghd: call legdd
ret nc
cp 11h
ret c
cp 17h
ccf
ret c
sub 7
ret
usage: ld hl,ascb+4
ld (hl),'K'
IF CPM
ld hl,NEDOOSMEMTOP;lhld bdosp ;get pointer to top of memory
ld l,0
ENDIF
ex de,hl ;into DE
lhld meofad ;get highest addr used
call cmh ;negate
add hl,de ;and add to top of mem to give free ram
ld a,h ;divide by 1K
rra
rra
and 3fh
ld l,a
ld h,0
dec hl
xor a
call prhcs ;print out
ld hl,stgelb ;"elbowroom"
lda lbln
and 0fh ;little hack here!
jp nz,cc1b
ld hl,stgunu ;"unused"
cc1b: call pstg
ret
; Wrap up error handling, exit if there were errors:
errwrp: lda errsin ;error output initialized?
or a
jp z,errwr3 ;if not, don't try to close RED output file
ld e,1ah ;ascii end-of-file
call redout
lhld redbp
ld a,l
cp redbuf and 0ffh ;has buffer just been flushed?
call nz,redwrt ;if not, write buffer one last time
ld de,redfcb
call close2 ;close RED output buffer
errwr3: lda errf ;if there were real errors (not just warnings)
or a ;then exit
jp nz,errab2
inc a
sta nomore ;no more RED output
ret ;else return
;
; Set up environment for a pass through the text (DE becomes
; text pointer)
;
initps: ld hl,0
shld nlcnt
; shld lbln ;arghh. WHY did this WORK for so LONG?
;(after lblpr, mustn't reset lbln anymore)
ld hl,modstk
shld modstp
xor a
sta clev
sta modstc ;at very top level
lhld coda
ex de,hl
ret
;
;
; Passc: control structure processor:
; This pass preprocesses control statements (like while, do,
; if...else, etc.) and twists them into a form much easier to digest
; by cc2. E.g., All the `case' statments are relded from a `switch'
; construct and a table of constants and `symbolic labels' is formed.
; If...else statments are turned into simple `if' statments (using some
; added braces and goto's...One may be able to get away from goto's
; in a C program, but it's a bit harder to avoid them at the compiler-
; design level!
;
; Note that at this point, all declarations have been purged from
; the text, leaving only the function definitions. If we ever finish
; up with a function and find something other than another function
; or EOF after it, somethings really screwed up...
;
passc: call initps ;initialize general pass procecure variables
ld hl,cntt ;init control table pointer (this is where
shld cntp ; the "break" and "continue" labels are stored)
ld hl,fbuf
shld fbufp
xor a
sta clev
dec de
pasc1: inc de
pasc2: call igsht ;done with text?
jp nz,pasc3
lda clev ;yes. at top level?
or a
ret z ;if so, OK
pasc2a: ld hl,stg10 ;==ERROR==
jp fatal ;probably mismatched {}s
pasc3: cp varcd ;a variable? (i.e., function definition?)
jp z,pasc4
pasc3a: call fsemi
jp pasc1
; ld hl,stgtc ;if not, somethings screwy
; jp fatal
pasc4: inc de ;ok, we found a function
inc de
inc de
call mtchp ;pass over the arg list
call state ;process the body as a statment
jp pasc2 ;and go back for another function
;
; Here it is, the routine to process a statment...
;
state: call ckabrt ;check for user typing control-C
call chkstk ;and check for stack overflow
call igsht
jp z,pasc2a ;if expecting a statement and get EOF, error
call cdtst ;if it starts with a code, ignore the code
jp c,state0
inc de ;ignore it, since its probably a label
inc de ;code or something trivial.
inc de
jp state
state0: inc de ;now, does it start with a `{'?
cp lbrcd
jp nz,state2
state1: call igsht ;yes. do each statment inside the compound.
cp rbrcd ;hit the `}' yet?
inc de
ret z ;if so, all done
dec de ;else just another statment
call state
jp state1 ;and keep a 'goin
state2: cp ifcd ;now we hit the real statements. IF?
jp z,sif
cp whlcd ;WHILE?
jp z,swhl
cp docd ;DO?
jp z,sdo
cp forcd ;FOR?
jp z,sfor
cp swtcd ;SWITCH?
jp z,sswt
cp brkcd ;BREAK?
jp z,sbrk
cp cntcd ;CONTINUE?
jp z,scnt
cp rencd ;RETURN?
jp z,state3
cp gotcd ;GOTO?
jp z,state3
cp cascd ;CASE? if so, bad news!
jp z,sterr ; Only the SWITCH processor should see these!
cp elscd ;while only the IF processor should see ELSEs
jp z,sterr
cp defcd ;and only the SWITCH processor, again, should
jp z,sterr ;see DEFAULTs
dec de ;at this point we assume we have an expression
state3: ld a,1 ;statment (or a really screwy error.)
sta eradf
lhld nlcnt
shld errad
call fsemi ;this phase can ignore expression statements.
xor a
sta eradf
inc de
call igsht
ret
sterr: ld hl,stgc10 ;seeing a CASE outside of a SWITCH, and other stuff
jp fatal ;like that, are good enough reasons to abort.
;
; routine to pass over a statement, I guess because I need to
; look ahead sometimes to figure out what's going on. Geez,
; I can't remember what the hell I used this for...
;
; (In case you're wondering, these comments are being written about
; 11 months after the code. I just now got WORDMASTER going on my
; bee-YOU-tea-full H19 terminal, and need no longer get uptight over
; the chilling prospect of documenting 150K of source using ED...)
;
passt: call igsht
jp z,pasc2a
call cdtst ;ignore labels and such
jp c,past0
inc de
inc de
inc de
jp passt
past0: cp lbrcd ;left brace?
jp nz,past2
inc de
past1: call igsht
cp rbrcd
jp nz,past1a
inc de
call igsht
ret
past1a: call passt ;yes; pass statement
jp past1
past2: cp ifcd
jp nz,past3 ;if statement?
inc de ;yes.
call mtchp ;pass expr
call passt ;pass statement
cp elscd ;else?
ret nz
inc de ;yes. pass statement
call passt
ret
past3: cp whlcd ;while?
jp z,pst5b
cp cascd ;case?
jp z,past3a
cp defcd ;default?
jp nz,past4
past3a: ld a,colon ;yes; find a colon
call findc
inc de ;pass it
call passt ;pass next statement
call igsht
ret
past4: cp docd
jp nz,past5 ;do statement?
inc de ;yes.
call passt ;pass statement
cp whlcd ;while?
jp z,pst4a
ld hl,stgc2 ;if not, error
call perr
pst4a: inc de ;pass expr
call mtchp
cp semi
call nz,insrts ;if no semi, insert one automagically.
inc de
call igsht
ret
past5: cp forcd ;for statement?
jp nz,past6
sta semiok ;yes. allow semis in text for now.
pst5b: inc de
call mtchp ;pass expr(s)
xor a
sta semiok
call passt ;pass statment
ret
past6: cp swtcd ;switch?
jp z,pst5b
or a ;no. EOF?
jp z,pasc2a
call fsemi ;no. go search for a semicolon
inc de
call igsht
ret
;
; push continue-break data stack, adding two new labels:
;
cnpsh: push de
ex de,hl
lhld cntp
ld (hl),e
inc hl
ld (hl),d
inc hl
inc de
ld (hl),e
inc hl
ld (hl),d
inc hl
shld cntp
lda clev
inc a
sta clev
ex de,hl
dec hl
pop de
ret
;
; Pop continue-break data stack:
;
cnpop: lhld cntp
dec hl
dec hl
dec hl
dec hl
shld cntp
lda clev
dec a
sta clev
ret
cklev: lda clev
or a
ret nz
ld hl,stgc7
call perr
pop hl
jp sbrk3
;
; Define a symbolic label given in HL at current location in text:
;
insll: ld a,-3 and 255
call mvtxt
insls: ld a,lblcd
jp insr2
;
; Install a symbolic label REFERENCE to label in HL at
; current location in text:
;
inslr: ld a,-3 and 255
call mvtxt
insrs: ld a,labrc
insr2: ld (de),a
inc de
ld a,l
ld (de),a
inc de
ld a,h
ld (de),a
inc de
ret
;
; Install a new label definition at current location in text:
;
lblni: call glbl
jp insll
;
; Install a new label reference at current place in text:
;
lblri: call glbl
jp inslr
;
; Get a new label value in HL:
;
glbl: lhld lbln
inc hl
shld lbln
dec hl
ret
;
; Process a "for" statement:
;
sfor: dec de
ld a,lbrcd ;left curly-brace to delimit entire for statement
ld (de),a
inc de
call igsht
cp open
jp z,sfor2
ld hl,stgc6
call perr
sfor2: ld a,0ffh
ld (de),a
call chsbp
call passt
ld a,-5 and 255
call mvtxt
ld a,whlcd
ld (de),a
inc de
call glbl ;get lbl z (object of the goto later)
push hl
call insls
call glbl ;get lbl x
call cnpsh
push hl ;push lbl x
ld a,open
ld (de),a
inc de
call igsht
cp semi
jp nz,sfor3
ld a,-3 and 255
call mvtxt
ld a,concd
ld (de),a
inc de
ld a,1
ld (de),a
inc de
ld a,0
ld (de),a
inc de
jp sfor4
sfor3: call chsbp
call fsemi
sfor4: ld a,close
ld (de),a
inc de
call glbl ;get lbl y
ex (sp),hl ;HL = lbl x, stack = lbly
push hl ;push lbl x
push de
ld a,negone
call mvtxt
ld a,open
ld (de),a
push de
inc de
lhld nlcnt
shld nltmp
call igsht
cp close
jp z,sfor4a
pop de
jp sfor4b
sfor4a: ld a,-3 and 255
call mvtxt
ld a,concd
ld (de),a
inc de
ld a,1
ld (de),a
inc de
xor a
ld (de),a
pop de
sfor4b: call mtchp
lhld nlcnt
push de
ex de,hl
lhld nltmp
call cmh
add hl,de
pop de
ld a,l
sta nltmp2
sfor5: pop hl
push hl
push hl
call cmh
add hl,de
pop de
shld tmplf
lhld fbufp
ld b,h
ld c,l
ex (sp),hl
push hl
lhld tmplf
ld h,l
sfor6: ld a,(de)
ld (bc),a
inc de
inc bc
dec l
jp nz,sfor6
push hl
ld h,b
ld l,c
shld fbufp
pop hl
pop de
ld a,lbrcd
ld (de),a
inc de
ld a,h
push af
push af
dec a
call mvtxt
lda nltmp2
push af
cpl
inc a
call mvtxt
pop af
sf6a: or a
jp z,sf6b
push af
ld a,nlcd
ld (de),a
inc de
pop af
dec a
jp sf6a
sf6b: call state
call cnpop
pop af
cpl
sub 14
call mvtxt
ld a,semi
ld (de),a
inc de
pop af
pop hl
ld b,h
ld c,l
shld fbufp
pop hl ;get lbl x
push af
push bc
call insls ;define lbl x here
pop bc
pop af
ld h,a
sfor7: ld a,(bc) ;now copy the saved increment portion
cp nlcd ;back into the text
jp nz,sfor7a ;but watch out for newlines
dec de ;and especially FAKE newlines (a la Somos)
ld a,(de)
inc de ;if a newline found, make sure it isn't
call cdtst ;just the operand of a 3-byte code
ld a,(bc)
jp nc,sfor7a ;if it is, leave it as it is
ld a,0ffh ;it isn't, so turn it into a garbage space
sfor7a: ld (de),a
inc de
inc bc
dec h
jp nz,sfor7
ld a,semi
ld (de),a
inc de
ld a,rbrcd
ld (de),a
inc de
pop hl ;get lbl y
ex (sp),hl
ld a,gotcd ;put in the kludge "goto" to go with the "while"
ld (de),a
inc de
call insrs
ld a,semi
ld (de),a
inc de
pop hl
call insls
ld a,rbrcd
ld (de),a
inc de
ret
chsbp: push de
lhld nlcnt
push hl
chsbp1: call pascd
cp semi
jp z,chsok
cp open
jp z,chsbpp
cp close
jp nz,chsbp2
pop hl
shld nlcnt
ld hl,stgc6
jp perrab
chsok: pop hl
shld nlcnt
pop de
ret
chsbp2: inc de
jp chsbp1
chsbpp: call mtchp
jp chsbp1
;
; Process a "switch" statement:
;
sswt: call mtchp
push de
lhld cntp
push hl
dec hl
dec hl
dec hl
ld b,(hl)
dec hl
ld c,(hl)
pop hl
ld (hl),c
inc hl
ld (hl),b
inc hl
ex de,hl
call glbl
shld defp ;set "default" default label
push af
xor a
sta defflg ;haven't encountered default: yet
pop af
ex de,hl
ld (hl),e
inc hl
ld (hl),d
inc hl
shld cntp
pop de
lhld defp
push hl
push de
cp lbrcd
jp z,ssw0
ld hl,stgc8
call perr
call fsemi
pop hl
pop hl
ret
ssw0: lhld nlcnt
shld tmpnl
xor a
sta swtc
sta casoff
ld hl,swtt
shld swtp
ld hl,clev
inc (hl)
inc de
ssw0a: call igsht
ssw1: ld a,(de)
cp lblcd
jp nz,ssw1a
inc de
inc de
inc de
jp ssw0a
ssw1a: cp cascd
jp z,sscas
cp defcd
jp z,ssdef
cp rbrcd
jp z,ssdon
ssw2: call passt
jp ssw1
sscas: inc de
push de
call pasff
cp concd
jp z,ccas2
pop de
ld hl,stgc9
ccas1: call perr
jp ssw2
ccas2: inc de
lhld swtp
ld a,(de)
ld (hl),a
inc de
inc hl
ld a,(de)
ld (hl),a
inc hl
inc de
pasloop:
ld b,c
call pasff
push af
ld a,b
add c
ld c,a
pop af
cp nlcd
jp nz,ccas2a
ld a,c
or 80h
ld c,a
inc de
jp pasloop
ccas2a:
cp colon
jp z,ccas3
ccas4: ld hl,stgc9
jp ccas1
ccas3: ex de,hl
call glbl
ex de,hl
ld (hl),e
inc hl
ld (hl),d
inc hl
lda casoff
or a
jp nz,ccas3a
shld swtp
ccas3a: ex de,hl
pop de
dec de
ld a,c
add a,2
jp p,ccas3c
and 7fh
ld c,a
ld a,nlcd
ld (de),a
inc de
ld a,c
ccas3c: call mvtxt
call insls
lda casoff
or a
jp nz,ccas3b
ld hl,swtc
inc (hl)
ld a,(hl)
cp 201
jp c,ccas3b
sta casoff
dec (hl)
ld hl,stgcof
call perr
ccas3b: jp ssw0a
pasff: ld c,0
pasff1: ld a,(de)
cp 0ffh
ret nz
inc c
inc de
jp pasff1
ssdef: push de
inc de
call pasff
cp colon
pop de
jp nz,ccas4
ld a,2
add c
call mvtxt
call lblni
shld defp
lda defflg ;default previously defined?
or a ;set NZ if so
ld a,1
sta defflg ;it is now, anyway
ld hl,stgddf ;duplicate default message
call nz,perr ;if default previously defined, bitch
jp ssw0a
ssdon: pop de
lda swtc
ld l,a
ld h,0
add hl,hl
add hl,hl
push hl
inc hl
inc hl
inc hl
inc hl
call bexp
ld a,swtbc
ld (de),a
inc de
lda swtc
ld (de),a
inc de
ld hl,swtt
pop bc
ssdn1: ld a,b
or c
jp z,ssdn2
ld a,(hl)
ld (de),a
inc de
inc hl
dec bc
jp ssdn1
ssdn2: lhld defp
ld a,l
ld (de),a
inc de
ld a,h
ld (de),a
inc de
lhld tmpnl
shld nlcnt
call state
pop hl
call insll
call cnpop
ret
;
; Process IF statement:
;
sif: call mtchp
call state
call igsht
cp elscd
ret nz
inc de
call state
ret
;
; Process a "while" statement:
;
swhl: call lblni
push hl
call cnpsh
call mtchp
call glbl
push hl
call state
pop hl
ex (sp),hl
ld a,-5 and 255
call mvtxt ;insert a forced "goto" to before the condition
ld a,gotcd ;test, so that things don't get messed up when
ld (de),a ;single-statement control structure is nested in
inc de ;a very peculiar way.
call insrs
ld a,semi
ld (de),a
inc de
pop hl
call insll
call cnpop
ret
;
; Process "do" statement:
;
sdo: call lblni
inc hl
call cnpsh
push hl
inc hl
inc hl
shld lbln
call state
call igsht
cp whlcd
jp z,sdo2
ld hl,stgc2
call perr
sdo2: inc de
pop hl
call insll
call mtchp
push hl
call esemi
inc de
pop hl
inc hl
call insll
call cnpop
ret
;
; Process "break" statement:
;
sbrk: call cklev
dec de
ld a,gotcd
ld (de),a
inc de
lhld cntp
sbrk2: dec hl
ld a,(hl)
dec hl
ld l,(hl)
ld h,a
call inslr
sbrk3: lhld nlcnt
shld esadr
call esemi
inc de
call igsht
ret
;
; Process "continue" statement:
;
scnt: call cklev
dec de
ld a,gotcd
ld (de),a
inc de
lhld cntp
dec hl
dec hl
jp sbrk2
IF LASM
link ccb
ENDIF