;
; cc2c.asm:
;
; This is the binary expression special case list interpreter
; for version 1.4:
;
spcash: push af
call spcs2
pop af
ret
spcs2: lhld svv1 ;if INFO1 is the constant:
shld sr0 ;<constant value> into sr0
call cmh
shld sr2 ;-<constant value> into sr2
dec hl
shld sr4 ;-<constant value + 1> into sr4
lda sval2
sta ssval
call tcnst2
jp nz,spcs2a
lhld svv2 ;if INFO2 is the constant:
shld sr0 ;<constant value> into sr0
shld svv1
call cmh
shld sr2 ;-<constant value> into sr2
dec hl
shld sr4 ;-<constant value + 1> into sr4
lda sval1
sta ssval
spcs2a: ex de,hl
spcs3: ld a,(hl)
or a
ret z
sta key
ld b,a
inc hl
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ld c,0
and 7
cp 7
jp nz,spcs3a
push hl
call spcs2 ;perform a recursive list evaluation
pop hl
jp z,spcs3 ;if not match found in subordinate list, resume search
ret ;else a match was found - done.
spcs3a: ex de,hl
shld spval
ex de,hl
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ex de,hl
shld spmac
ex de,hl
and 7
dec a ;key = 1?
jp nz,sptst2
sptry1: call tcnst1 ;yes.
jp z,sptr1a ;fit template?
inc c ;no-commutative?
ld a,b
and 20h
jp nz,sptry3 ;if so, go try key=3 case
jp spcs3 ;else no match yet
sptr1a: lda sval2 ;fits key=1 template if info2 in HL
and 0c0h
jp nz,spcs3
jp spfnd
sptst2: dec a ;key = 2?
jp nz,sptst3
sptry2: call tcnst1 ;yes.
jp z,sptr2a ;fit template?
inc c ;no. commutative?
ld a,b
and 20h
jp nz,sptry4 ;if so, try key=4
jp spcs3 ;else no match
sptr2a: lda sval2 ;fits key=2 template if info2 in HL
and 0c0h
jp z,spcs3
jp spfnd
sptst3: dec a ;key = 3?
jp nz,sptst4
sptry3: call tcnst2 ;yes
jp nz,spcs3 ;no good unless info2 a constant
sptr3a: lda sval1 ;OK, good only if info1 in HL
and 0c0h
jp nz,spcs3
jp spfnd
sptst4: dec a ;key = 4?
jp nz,sptst5
sptry4: call tcnst2 ;yes
jp nz,spcs3 ;good only if info2 is a constant
sptr4a: lda sval1 ;OK, good only if info1 in DE
and 0c0h
jp z,spcs3
jp spfnd
sptst5: push hl ;set "constant value doesn't matter" flag
ld hl,5500h
shld spval ;this is so no auto-lxi is done
pop hl
dec a
jp nz,sptst6 ;key = 5?
call tcnst1 ;yes. check to make sure there are no constants
jp z,spcs3
call tcnst2
jp z,spcs3
ld a,b ;commutative?
and 20h
jp nz,spfnd ;if so, we know enough to match
jp sptr3a ;else go check to make sure info1 is in HL
sptst6: dec a ;key = 6?
call nz,ierror ;better be!
call tcnst1 ;make sure we have no constants
jp z,spcs3
call tcnst2
jp z,spcs3
jp sptr4a ;if OK, make sure info1 is in DE
spfnd: push hl
lhld spval
ld a,h
cp 55h ;wild card constant test?
jp z,spgo ;if so, don't bother to compare constant values
ex de,hl ;no. must match value
lhld svv1
ld a,h
cp d
jp nz,spfnd1
ld a,l
cp e ;all 16 bits match?
jp z,spgo ;if so, go do the special case!
spfnd1: pop hl ;no good. go for more list searching
jp spcs3
spgo: ld a,l ;do we need to do an auto-lxi?
cp 55h
jp nz,spgo1 ;if not 55h, we DO NOT want to do it; else
ld de,mac04 ;yes. do either ld hl,sr0 or ld de,sr0
lda ssval
and 0c0h
jp nz,spgo0
ld de,mac4a
spgo0: call mcrog
spgo1: pop hl
lhld spmac ;get the macro
ex de,hl
call mcrog ;do it
ld b,0 ;now set all the resultant infox attributes
lda key ;register B will accumulate new sval1 value
ld c,a
and 8 ;result in a register?
jp z,spgo2
ld a,c ;yes. if in DE, set b6 of reg B accordingly
or a
jp p,spgo2
ld b,40h
spgo2: ld a,c
and 10h ;result a flag?
jp z,spgo3
ld a,c ;yes. set bmap1 and reg B (sval1) accordingly
rlca
rlca
and 3
sta sbmap1
ld b,4 ;this becomes sval1--a flag setting.
spgo2a: xor a
sta indc1
sta typ1
spgo3: ld a,c ;result a constant?
and 18h
jp nz,spgo4
ld a,c ;yes. FFFF?
and 0c0h
ld hl,0ffffh
cp 0c0h
jp z,spgo3a ;if so, go set
inc hl ;0000?
or a
jp z,spgo3a ;if so, go set that
inc hl
cp 40h ;0001?
call nz,ierror ;if not, something's screwy in the state of confusion
spgo3a: shld svv1
ld b,1
spgo4: ld a,b ;set new sval1
sta sval1
xor a ;clear Z bit so we'll know we're done if this
inc a ;is a recursive call to spcash
ret
;
; The list structures representing all possible special cases of
; binary operators:
;
;
; First define some common constant values:
;
r: equ 8h ;result in a register (key bit flag)
f: equ 10h ;result is a flag (key bit flag)
con0: equ 0 ;result is constant value of 0
con1: equ 40h ;result is constant value of 1
conff: equ 0c0h ;result is constant value of FFFFh
fz: equ f+000h ;result is Z flag set on true (Z true)
fnz: equ f+040h ;result is Z flag reset on true (NZ true)
fc: equ f+080h ;result is C flag set on true (C true)
fnc: equ f+0c0h ;result is C flag reset on true (NC true)
k: equ 20h ;operator is commutative
rd: equ r+80h ;result in DE
rh: equ r+00h ;result in HL
endlst: equ 0 ;end of list or sub-list
;wild-card constant value entries:
dolxi: equ 05555h ;do auto-lxi of constant value into free register
nolxi: equ 05500h ;wild card value, but no lxi
smadd: db 1+rh+k
dw 0,mnul ; + operator
db 2+rd+k
dw 0,mnul
db 1+rh
dw 1,macih1
db 1+rh
dw 2,macih2
db 1+rh
dw 3,macih3
db 1+rh
dw 4,macih4
db 1+rh
dw -1,macdh1
db 1+rh
dw -2,macdh2
db 1+rh
dw -3,macdh3
db 1+rh
dw -4,macdh4
db 2+rd
dw 1,macid1
db 2+rd
dw 2,macid2
db 2+rd
dw 3,macid3
db 2+rd
dw 4,macid4
db 2+rd
dw -1,macdd1
db 2+rd
dw -2,macdd2
db 2+rd
dw -3,macdd3
db 2+rd
dw -4,macdd4
db 1+rh+k
dw dolxi,mac0ca
db 2+rh+k
dw dolxi,mac0ca
db 5+rh+k
dw nolxi,mac0ca
db endlst
smsub: db 1+rh
dw 0,mnul ; - operator
db 2+rd
dw 0,mnul
db 3+rh
dw 0,maccom
db 4+rd
dw 0,maccmd
db 1+rh
dw 1,macdh1
db 1+rh
dw 2,macdh2
db 1+rh
dw 3,macdh3
db 1+rh
dw 4,macdh4
db 1+rh
dw -1,macih1
db 1+rh
dw -2,macih2
db 1+rh
dw -3,macih3
db 1+rh
dw -4,macih4
db 2+rd
dw 1,macdd1
db 2+rd
dw 2,macdd2
db 2+rd
dw 3,macdd3
db 2+rd
dw 4,macdd4
db 2+rd
dw -1,macid1
db 2+rd
dw -2,macid2
db 2+rd
dw -3,macid3
db 2+rd
dw -4,macid4
db 1+rh
dw nolxi,macsb1
db 2+rh
dw nolxi,macsb2
db 3+rh
dw dolxi,macsb3
db 4+rh
dw dolxi,macsb4
db 5+rh
dw nolxi,mcssbh
db 6+rh
dw nolxi,mcssbd
db endlst
smmul: db 1+con0+k
dw 0,mnul ;common cases for both
db 2+con0+k
dw 0,mnul ;signed and unsigned
db 1+rh+k
dw 1,mnul ;multiplication
db 2+rd+k
dw 1,mnul
db 1+rh+k
dw -1,maccom
db 2+rd+k
dw -1,maccmd
db 1+rh+k
dw 2,mcddh1
db 1+rh+k
dw 4,mcddh2
db 1+rh+k
dw 8,mcddh3
db 1+rh+k
dw 16,mcddh4
db 2+rh+k
dw 2,mcddd1
db 2+rh+k
dw 4,mcddd2
db 2+rh+k
dw 8,mcddd3
db 2+rh+k
dw 16,mcddd4
db endlst
smmulu: db 7
dw smmul ;unsigned *
db 1+rh+k
dw dolxi,mcumul
db 2+rh+k
dw dolxi,mcumul
db 5+rh+k
dw nolxi,mcumul
db endlst
smmuls: db 7
dw smmul ;signed *
db 1+rh+k
dw dolxi,mcsmul
db 2+rh+k
dw dolxi,mcsmul
db 5+rh+k
dw nolxi,mcsmul
db endlst
smdiv: db 1+con0+k
dw 0,mnul ;common cases for both
db 2+con0+k
dw 0,mnul ;signed and unsigned
db 1+rh
dw 1,mnul ;division
db 2+rd
dw 1,mnul
db 1+rh
dw -1,maccom
db 1+rd
dw -1,maccmd
db endlst
smdivu: db 7
dw smdiv ; unsigned / operator
db 1+rh
dw dolxi,mcdiv5
db 2+rh
dw dolxi,mcudiv
db 3+rh
dw dolxi,mcudiv
db 4+rh
dw dolxi,mcdiv5
db 5+rh
dw nolxi,mcudiv
db 6+rh
dw nolxi,mcdiv5
db endlst
smdivs: db 7
dw smdiv ;signed / operator
db 1+rh
dw dolxi,mcdiv7
db 2+rh
dw dolxi,mcsdiv
db 3+rh
dw dolxi,mcsdiv
db 4+rh
dw dolxi,mcdiv7
db 5+rh
dw nolxi,mcsdiv
db 6+rh
dw nolxi,mcdiv7
db endlst
smmod: db 1+con0+k
dw 0,mnul ;common % operator cases
db 2+con0+k
dw 0,mnul
db endlst
smmodu: db 7
dw smmod ;unsigned % operator
db 1+con0
dw 1,mnul
db 2+con0
dw 1,mnul
db 1+rh
dw dolxi,mcmod5
db 2+rh
dw dolxi,mcumod
db 3+rh
dw dolxi,mcumod
db 4+rh
dw dolxi,mcmod5
db 5+rh
dw nolxi,mcumod
db 6+rh
dw nolxi,mcmod5
db endlst
smmods: db 7
dw smmod ;signed % operator
db 1+rh
dw dolxi,mcmod7
db 2+rh
dw dolxi,mcsmod
db 3+rh
dw dolxi,mcsmod
db 4+rh
dw dolxi,mcmod7
db 5+rh
dw nolxi,mcsmod
db 6+rh
dw nolxi,mcmod7
db endlst
smsr: db 1+rh
dw 0,mnul ; >> operator
db 2+rd
dw 0,mnul
db 1+rh
dw dolxi,macsrh
db 2+rh
dw dolxi,macsrd
db 3+rh
dw dolxi,macsrd
db 4+rh
dw dolxi,macsrh
db 5+rh
dw nolxi,macsrd
db 6+rh
dw nolxi,macsrh
db endlst
smsl: db 1+rh
dw 0,mnul ; << operator
db 2+rd
dw 0,mnul
db 1+rh
dw 1,mcddh1
db 1+rh
dw 2,mcddh2
db 1+rh
dw 3,mcddh3
db 1+rh
dw 4,mcddh4
db 1+rh
dw 5,mcddh5
db 2+rh
dw 1,mcddd1
db 2+rh
dw 2,mcddd2
db 2+rh
dw 3,mcddd3
db 2+rh
dw 4,mcddd4
db 2+rh
dw 5,mcddd5
db 1+rh
dw dolxi,macslh
db 2+rh
dw dolxi,macsld
db 3+rh
dw dolxi,macsld
db 4+rh
dw dolxi,macslh
db 5+rh
dw nolxi,macsld
db 6+rh
dw nolxi,macslh
db endlst
smgtu: db 1+fnz
dw 0,mcn10 ; unsigned ">" operator
db 2+fnz
dw 0,macde0
db 3+con0
dw 0,mnul
db 4+con0
dw 0,mnul
db 1+fc
dw nolxi,macsb5
db 2+fc
dw nolxi,macsb6
db 3+fnc
dw nolxi,macsb1
db 4+fnc
dw nolxi,macsb2
db 5+fc
dw nolxi,mcagbu
db 6+fc
dw nolxi,mcbgau
db endlst
smgts: db 1+fnc ;signed ">" operator
dw -1,macrhl
db 2+fnc
dw -1,macrdl
db 3+fc
dw 0,macrhl
db 4+fc
dw 0,macrdl
db 1+fc
dw dolxi,mcbgas
db 2+fc
dw dolxi,mcagbs
db 3+fc
dw dolxi,mcagbs
db 4+fc
dw dolxi,mcbgas
db 5+fc
dw nolxi,mcagbs
db 6+fc
dw nolxi,mcbgas
db endlst
smltu: db 1+con0 ;unsigned "<" operator
dw 0,mnul
db 2+con0
dw 0,mnul
db 3+fnz
dw 0,mcn10
db 4+fnz
dw 0,macde0
db 1+fnc
dw nolxi,macsb1
db 2+fnc
dw nolxi,macsb2
db 3+fc
dw nolxi,macsb5
db 4+fc
dw nolxi,macsb6
db 5+fc
dw nolxi,mcalbu
db 6+fc
dw nolxi,mcblau
db endlst
smlts: db 1+fc ;signed "<" operator
dw 0,macrhl
db 2+fc
dw 0,macrdl
db 3+fnc
dw -1,macrhl
db 4+fnc
dw -1,macrdl
db 1+fc
dw dolxi,mcblas
db 2+fc
dw dolxi,mcalbs
db 3+fc
dw dolxi,mcalbs
db 4+fc
dw dolxi,mcblas
db 5+fc
dw nolxi,mcalbs
db 6+fc
dw nolxi,mcblas
db endlst
smeq: db 1+fz+k
dw 0,mcn10 ; == operator
db 2+fz+k
dw 0,macde0
db 1+fz+k
dw 1,mache1
db 1+fz+k
dw 2,mache2
db 1+fz+k
dw 3,mache3
db 1+fz+k
dw 4,mache4
db 2+fz+k
dw 1,macde1
db 2+fz+k
dw 2,macde2
db 2+fz+k
dw 3,macde3
db 2+fz+k
dw 4,macde4
db 1+fz+k
dw -1,mchen1
db 1+fz+k
dw -2,mchen2
db 1+fz+k
dw -3,mchen3
db 2+fz+k
dw -1,mcden1
db 2+fz+k
dw -2,mcden2
db 2+fz+k
dw -3,mcden3
db 1+fz+k
dw nolxi,mcsb1a
db 2+fz+k
dw nolxi,mcsb1b
db 5+fz+k
dw nolxi,mceq
db endlst
smand: db 1+con0+k
dw 0,mnul ; & operator
db 2+con0+k
dw 0,mnul
db 1+rh+k
dw -1,mnul
db 2+rd+k
dw -1,mnul
db 1+rh+k
dw dolxi,mcand
db 2+rh+k
dw dolxi,mcand
db 5+rh+k
dw nolxi,mcand
db endlst
smor: db 1+rh+k
dw 0,mnul ; | operator
db 2+rd+k
dw 0,mnul
db 1+conff+k
dw -1,mnul
db 2+conff+k
dw -1,mnul
db 1+rh+k
dw dolxi,mcor
db 2+rh+k
dw dolxi,mcor
db 5+rh+k
dw nolxi,mcor
db endlst
smxor: db 1+rh+k
dw 0,mnul
db 2+rd+k
dw 0,mnul
db 1+rh+k
dw dolxi,mcxor
db 2+rh+k
dw dolxi,mcxor
db 5+rh+k
dw nolxi,mcxor
db endlst
;
; This routine returns Z true if both operands are chars,
; else returns not Z and clears the high order byte of
; any of the two operands which aren't chars:
;
chradj: call tschr ;first operand a char?
jp nz,chrdj2
call tschr2 ;yes. 2nd?
ret z ;if so, return Z true
ld de,mac61 ;else clear hi byte of HL
chrdj1: call mcrog
xor a
inc a ;and return Z false
ret
chrdj2: call tschr2 ;2nd operand char?
ret nz ;if not, done
ld de,mac62 ;if so, clear hi byte of DE
jp chrdj1
parerr: ld de,stg18
jp perr
unsadj: call tptr
jp z,unsdj2
call tptr2
jp z,unsdj2
call tsval
ret nz
call tsval2
ret nz
lda typ1
cp 2
ret z
lda typ2
cp 2
ret nz
sta typ1
ret
unsdj2: xor a
ret
;
; Routine to "pass over" a simple expression in text:
;
sexpas: call igsht
inc hl
cp mulcd ;check for unary ops
jp z,sexpas
cp ancd
jp z,sexpas
cp mincd
jp z,sexpas
cp notcd
jp z,sexpas
cp circum
jp z,sexpas
cp pplus
jp z,sexpas
cp mmin
jp z,sexpas
cp sizcd
jp z,sexpas
dec hl ;else pass primary expr
call ppas
ret
ppas: call sppas ;pass simple primary expr
ret c ;abort if error
ppas2: call igsht ;check for primary ops
cp open
jp nz,ppas3
ppas2a: call mtchp
jp ppas2
ppas3: cp openb
jp nz,ppas4
call mtchb
jp ppas2
ppas4: inc hl
cp arrow
jp z,ppas5
cp period
jp z,ppas5
cp pplus
jp z,ppas2
cp mmin
jp z,ppas2
dec hl ;all done.
scf
ccf
ret
ppas5: call igsht
cp varcd
jp nz,ppase
ppas6: inc hl
inc hl
inc hl
jp ppas2
sppas: cp open
jp z,ppas2a
cp strcd
jp z,ppas6
cp varcd
jp z,ppas6
cp concd
jp z,ppas6
ppase: ld de,stg10
call perrsv
scf
ret
;
; Routine to "look ahead" past the current text, and
; return the next non-space character, restoring old
; text pointer and line count:
;
looka: push hl
lhld nlcnt
ex (sp),hl
push hl
inc hl
call igsht
pop hl
ex (sp),hl
shld nlcnt
pop hl
ret
domac: ld a,c
add a
add a
add a
add b
add b
push hl
ld hl,mact
ld e,a
ld d,0
add hl,de
ld e,(hl)
inc hl
ld d,(hl)
call mcrog
pop hl
ret
aluadj: ld a,l
or a
ret nz
ld a,h
or a
ret nz
ld h,1
ret
mult: push bc
push de
ld b,h
ld c,l
lhld subval
ex de,hl
ld hl,0
mult1: ld a,b
or c
jp z,mult2
add hl,de
dec bc
jp mult1
mult2: shld subval
pop de
pop bc
ret
maddd: ld a,d
or a
jp nz,maddd2
ld a,e
cp 4
jp nc,maddd2
maddd1: ld a,d
or e
ret z
ld a,23h
call genb
dec de
jp maddd1
maddd2: ex de,hl
shld sr0
ex de,hl
ld de,mac0c
call mcrog
ret
;
; Return Z set if keyword in A is a binary operator:
;
binop: ld b,15
cp 0b6h
ret z
cp 0b7h
ret z
cp 0b8h
ret z
dec b
cp 0c4h
ret z
cp 0b5h
ret z
dec b
cp 0b0h
ret z
cp 0b1h
ret z
dec b
cp 0bah
ret z
cp 0b9h
ret z
cp 0afh
ret z
cp 0aeh
ret z
dec b
cp 0aah
ret z
cp 0abh
ret z
dec b
cp 0bbh
ret z
dec b
cp 0bch
ret z
dec b
cp 0bdh
ret z
dec b
cp 0ach
ret z
dec b
cp 0adh
ret
;
; Return Z if keyword in A is logical binary op (&& or ||):
;
lbinop: cp oror
ret z
cp andand
ret
;
; Return Z if keyword is ++ or --:
;
ppormm: cp pplus
ret z
cp mmin
ret
;
; Return Z if keyword in A is asignment operator:
;
asgnop: cp 0beh
ret z
cp 0a0h
ret c
cp 0ach
ccf
ret
cnvsop: sub 0a0h
push hl
push de
ld hl,sopt
ld e,a
ld d,0
add hl,de
ld a,(hl)
pop de
pop hl
ret
sopt: db 0c4h,0b5h,0b6h,0b7h,0b8h
db 0b1h,0b0h,0bbh,0bch,0bdh
primop: cp open
ret z
cp openb
ret z
cp arrow
ret z
cp period
ret
prmop2: call primop
ret z
cp pplus
ret z
cp mmin
ret
;
; Handle a binary expression, with HL pointing to the first arg:
;
lcflag: ds 1 ;controls optimizing for constant logical subexpr.
;=10h when no lbinop activity,
;=20h when pending next (noted) lbinop result
;b6 hi when abs logical value of binexp determined
;if b6 true, b7 is: 1 for TRUE, 0 for FALSE
lflag: ds 1 ;true if &&/|| expression
bexpr: lda codflg
push af
lda arith
push af
ld a,10h ;initialize lcflag to: "no activity"
sta lcflag
xor a
sta arith
sta lflag
bxpr00: call rpshp
bxpr0: xor a
call oppsh
call sexpasl
push hl
lhld ltabp
cp andand ; Do special ltab hackery if NEXT operator is || or &&
jp nz,bxpr0a ;&& operator?
push hl ;yes. propogate last false branch table label,
dec hl ;add new true label
dec hl
ld d,(hl)
dec hl
ld e,(hl)
pop hl
push de
ex de,hl
call glbl
ex de,hl
ld (hl),e
inc hl
ld (hl),d
inc hl
pop de
jp bxpr0b
bxpr0a: cp oror
jp nz,bxpr0c ;|| operator?
push hl ;yes. propogate last true branch table label,
ld de,-5 ;add new false label.
add hl,de
ld e,(hl)
inc hl
ld d,(hl)
pop hl
ld (hl),e
inc hl
ld (hl),d
inc hl
ex de,hl
call glbl
ex de,hl
bxpr0b: ld (hl),e
inc hl
ld (hl),d
inc hl
inc hl
shld ltabp
lda lcflag ;first activity?
cp 10h
jp nz,bxpr0c ;if not, don't change this here
ld a,20h ;if not, prime for some activity
sta lcflag
bxpr0c: pop hl
lda value
push af
lda arith
push af
or a ;was arith set?
call nz,ltabmp ;if so, bump ltable to keep branches local...
lda lcflag ;save logical constant flag
push af
lda lflag ;save logical expression flag
push af
xor a
call sgenv ;evaluate the operand.
pop af
sta lflag ;restore logical expr flag
pop af ;get old lcflag in A
ld b,a ;save in B
or a ;was old lcflag cleared?
jp z,lchck1 ;if so, keep it that way.
and 30h ;was it primed or inactive?
ld a,b
jp nz,lchck2 ;if so, let newer one be propogated
;else...
lchck1: sta lcflag ;restore logical constant flag
lchck2: pop af
sta arith
pop af
or a
jp z,bxpr1
sta value ;logical `or' "value" with old "value"
bxpr1: lda arith ;was last term preceded by arith operator?
or a
jp z,bxpr1a ;if not, don't clean up
xor a ;yes; reset arith flag
sta arith
call ltabtd ;define all possible branches as here
call ltabfd
call ltabpp ;clean up branch table
pop af ;and restore old value of val
sta val
bxpr1a: call oppops
bxpr2: ld a,(hl)
call binop ;next thing in text a binary op?
jp z,bxpr4
bxpr3: call tstops ;no. any old ops on stack?
jp z,bxpr9
;yes. generate operations.
call ppshp
call oppop
call ppn2
call alugen
jp bxpr3
bxpr4: call tstops ;ok, we have a new binop to process.
jp nz,bxpr7 ;any old stuff on stack?
ld a,(hl) ;no. Let's handle && and || specially...
cp andand ; && operator?
jp nz,bxpr5
sta lflag ;set, set logical expression flag
call ppshp
lda lcflag ;see if it's OK to check for constants
and 0f0h
jp z,bxpr4a ;only test for constants if lcflag cooperates.
call tcnst1 ;was arg a constant?
jp z,bxpr40
lda lcflag ;if not, clear lcflag if not already finalized
and 0c0h
sta lcflag
jp bxpr4a
bxpr40: lda lcflag ;was lcflag primed?
cp 20h
jp nz,bxpr41
ld a,10h ;if so, un-prime in case we don't score the right
sta lcflag ;polarity on this constant.
bxpr41: call tcnsz ;we have a constant. zero?
jp nz,bxpr4b ;if not, skip the cond'l jump, but keep evaluating
bxpr42: xor a ;yes...
sta codflg ; don't bother generating any more code for the bexpr
ld a,40h
sta lcflag ;set logical constant flag to "yes, false"
jp bxpr4b
bxpr4a: lda val
cp 81h ;if must force value, do it:
call z,lv01th ; get 0 or 1 into HL, no matter WHAT.
call gncjf ;generate conditional jump on false
bxpr4b: call ltabtd
call ltabfo
jp bxpr5c
bxpr5: cp oror
jp nz,bxpr6 ; || operator?
sta lflag ;yes, set logical expression flag
call ppshp
lda lcflag ;see if it's OK to check for constants
and 0f0h
jp z,bxpr5a ;only test for constants if lcflag cooperates.
call tcnst1 ;was arg a constant?
jp z,bxpr50
lda lcflag ;if not, clear lcflag if not already finalized
and 0c0h
sta lcflag
jp bxpr5a
bxpr50: lda lcflag ;was lcflag primed?
cp 20h
jp nz,bxpr51
ld a,10h ;if so, un-prime in case we don't score the right
sta lcflag ;polarity on this constant.
bxpr51: call tcnsz ;we have a constant. zero?
jp z,bxpr5b ;if so, skip the cond'l jump, but keep evaluating
xor a ;no...thus true, so
sta codflg ;don't bother generating any more code for the bexpr
ld a,0c0h ;set logical constant flag to "yes, true"
sta lcflag
jp bxpr5b
bxpr5a: lda val
cp 81h ;if must force value, do it:
call z,lv01th ; get 0 or 1 in HL no matter WHAT.
call gncjt ;generate conditional jump on true
bxpr5b: call ltabfd
call ltabto
bxpr5c: call ltabpp
inc hl
jp bxpr00
tcnsz: lda sval1 ;set Z flag if constant value of zero
and 1
jp z,invrt ;if not absolute constant, not value of zero
push hl ;save text pointer
lhld svv1
ld a,h
or l
pop hl ;now Z set if zero value
ret
bxpr6: lda sval1 ;if logical bit set, turn it into actual value here
and 4 ;so stuff like: " <Bang>kbhit() & a<5 " works.
call nz,cvtlvh
lda val
cp 81h ;if must force value, do it:
call z,cvtlvh ; make sure flag settings turn into values in HL
call tcnst1
call nz,spshp
call z,rpshp
call pshn1
ld a,(hl)
call oppsh
inc hl
call igsht ;next term a complex expression in parens?
cp open
jp nz,bxpr0
lda val ;if so, assume it needs complete evaluation
push af
ld a,81h ;force value result
sta val
ld a,1 ;set arith mode while evaluating
sta arith ; next operand of binary op,
jp bxpr0 ;and go evaluate next arg
bxpr7: call oppop
call oppsh
ld c,b
call binop
push de
ld de,stgbbo
call nz,perrab ;no other operators; better be '|'
pop de
ld a,c
cp b
jp z,bxpr8
jp nc,bxpr6
bxpr8: call ppshp
call oppop
call ppn2
call alugen
jp bxpr2
bxpr9: call ppshp
lda val ;absolutely need a value?
cp 81h
jp nz,bxpr90
lda lflag ;was it a logical expression (with && and ||) ?
or a
jp z,bxpr91
call lv01th ;if so, go convert into 0 or 1 in HL, no matter WHAT
jp bxpr90
bxpr91: call cvtlvh ;else just flush logical flag values into HL
bxpr90: pop af
sta arith ;restore arith flag
pop af
sta codflg ;restore code flag.
lda lcflag ;result a logical constant?
and 0c0h
jp z,bxpr9b ;if not, don't create constant return value
or a ;set Z flag if constant of 0
ld a,1
sta sval1 ;yes--set constant flag
push hl
ld hl,0 ;constant value of zero?
jp p,bxpr9a ;if so, go store
inc hl ;else make it 1
bxpr9a: shld svv1
pop hl
bxpr9b: pop af
cp 2
ret nz
ld de,stg8
jp perr
;
; This makes sure that the result of the current
; expression is a hard value of 0 or 1 in HL, no matter WHAT.
;
lv01th: lda sval1 ;logical flag?
and 4
jp nz,cvtlvh ;if so, go convert
lda sval1
and 1 ;constant?
jp z,lv01b
push hl ;yes. turn into 0 or 1 in HL
lhld svv1
ld a,h
or l
lv01d: ld hl,0
jp z,lv01a
inc hl
lv01a: shld svv1
pop hl
call flshh1 ;flush constant into HL
ret
lv01b: lda sval1 ;not abs constant-is it rel lv?
and 2
jp z,lv01c
ld a,1 ;if so, turn into constant equal to 0
sta sval1
push hl
xor a ;set Z to force constant value of 0
jp lv01d ;and go wrap up
lv01c: lda sval1 ;not any kind of constant, so must be val in reg
and 0c0h ;in DE?
jp z,lv01e
ld de,macde0 ;yes. char?
call tschr
call nz,mcrog ;if not, do 16-bit test
ld de,mcn12
call z,mcrog ;else do 8-bit test
jp lv01f ;and go convert into HL value
lv01e: ld de,mache0 ;value in HL. char?
call tschr
call nz,mcrog ;if not, do 16-bit test
ld de,mcn11
call z,mcrog ;else do 8-bit test
lv01f: ld de,macf2 ;now convert NZ flag state into HL value
call mcrog
ld a,24h ;set flag and value result
sta sval1
ld a,1 ;set flag value of NZ true
sta sbmap1
ret
;
; Process assignment expression, given HL -> left
; element of assignment. This might be either a simple
; assignment or an op= type assignment:
;
aexpr: call igsht ;check for leading & or ++ or --, so that
cp ancd ;some common invalid lvalues that can't be
jp z,badlv ;detected by analyz can be diagnosed properly.
call ppormm ;is it ++ or --?
jp z,badlv ;if so, bad lvalue
cp varcd ;a variable name?
jp nz,aexpr0 ;if not, all done checking for special cases
inc hl
inc hl
inc hl
ld a,(hl)
call ppormm ;is it an expr of form foo++ or foo-- ?
dec hl
dec hl
dec hl
jp nz,aexpr0
badlv: ld de,stg8b
call perr
aexpr0: call rpshp
ld a,2 ;generate address of left arg
call sgenv
call ppshp
cp letcd ; simple '=' assignment?
jp z,aexpl ;if so, go do it.
call cnvsop ;convert op= to just op
push af ;and save the op for later
lda sval1 ;no. abs const lvalue?
and 1
jp z,aexp0
call glvcv ;yes. get value of left operand
call pshn1 ;save info on lvalue before it was indirected
xor a
sta sval1 ;after indirection, it's a simple value
jp aexp2a
aexp0: call flshh1 ;not abs const lvalue. flush into HL
call pshn1
call gpushh ;gen. push instr. to save address of left arg
call tsclv ;test for char value. Is it?
jp z,aexp2 ;if so, go do single byte indirection
call maca0c ;else do double byte indirection, perhaps RST'ed
jp aexp2a
aexp2: ld de,mac6e ;if a char, just do "ld l,(hl)"
call mcrog
aexp2a: call tslv ;was left arg a simple lvalue?
jp nz,aexp2b
lda indc1 ;if so, de-bump indirection count
dec a ; (corresponding to the just-done indirection)
sta indc1
aexp2b: call pshn1 ;save info on the left arg
inc hl
call spshp
call evala
call ppshp
call ppn2 ;pop info on left arg
pop af ;get back the operator code
call alugen ;now perform the operation
aexp3: call ppn2 ;peek at original lvalue info
call pshn2
lda sval2 ;was lvalue an abs lv const?
and 10h
jp nz,aexp3b ;if so, don't pop or do ANYTHING messy.
aexp3a: call pn1ind ;else make sure the alugen result is in DE
call gpoph ;gen 'pop hl' to get addr of left arg back in HL
aexp3b: call mvn12 ;and put the info on the left and right args into
call ppn1 ; info1 and info2, respectively
jp letgen ;and go generate the assignment code
aexpl: call pshn1 ;come here to handle simple '=' operator
inc hl
lda sval1
push af ;save info1 optimization byte
call tcnst1
call nz,spshp
call z,rpshp
call evala ;evaluate rvalue
call ppshp
call tpshd
jp nz,aexpl2
pop af
jp aexp3a
aexpl2: lda sval1
and 2
jp nz,aexpl3
pop af
jp aexp3b
aexpl3: pop af
ld b,a ;save left operand into in B
and 3 ;left operand in a register?
jp z,aexpl4
call flshd1 ;no...flush right operand into DE
jp aexp3b ;and go process assignment
aexpl4: ld a,b ;left operand in a register.
and 0c0h ;push the appropriate register on stack
call z,gpushh
call nz,gpushd
call flshd1 ;evaluate right operand into DE
call gpoph ;pop left operand into HL
call mvn12 ;set up for assignment processor
call ppn1
lda sval1 ;but force left operand data to indicate in HL
and 3fh
sta sval1
jp letgen
evala: lda val
push af
ld a,81h
sta val
call ltabmp ;bump logical table to make sure we stay in this
xor a ;statement no matter what the (maybe) logical value is
call expr2v
call ltabtd ;come here if true
call ltabfd ;and come here if false, too.
call ltabpp ;and pop ltab entry
pop af
sta val
ret
letgen: call analyz ;ok to assign to the lvalue given?
lda asnokf
or a
jp nz,lg2
letbad: ld de,stg8b ;no. error.
call perr
pop af
ret
lg2: push hl ;yup. abs lvalue constant?
lda sval1
and 11h
jp nz,palvc ;if so, go handle
lda sval1 ;no. relative lvalue constant?
and 2
jp nz,prlvc ;if so, go handle that.
lda sval2 ;OK, we have lvalue in HL, rvalue somewhere
and 1 ;rvalue a constant?
jp z,lgncon ;if not, go handle
call flshh1 ;OK, put lvalue into HL if it is in DE
lg3: lda val ;yes, rvalue is constant.
or a
jp nz,lg5 ;need result?
call tsclv
jp nz,lg4b ;8 bit value?
ld a,36h ;yes. do "ld (hl),vaue"
call genb
lda svv2
call genb
jp lgdone
lg4b: lhld svv2 ;16-bit value.
ld a,h
or l ;zero special case?
jp nz,lg4c
ld de,macac1 ;yes.
call mcrog
jp lgdone
lg4c: ld a,36h
call genb
lda svv2
call genb
ld a,23h
call genb
ld a,36h
call genb
lda svv2+1
call genb
jp lgdone
lg5: lhld svv2 ;we need value result.
shld sr0
call tsclv
jp nz,lg5b
ld a,1eh
call genb
lda svv2
call genb
ld a,73h
call genb
lg5a: ld a,40h ;set result in DE flag
sta sval1
jp lgdone
lg5b: ld de,macac3
call mcrog
jp lg5a
;
; Come here after all assignments have been done
;
lgdone: call tslv
jp nz,lgdn2
lda indc1
dec a
sta indc1
lgdn2: pop hl
pop af
call ckvok
ret
;
; Handle assignment of value in DE to lvalue in HL:
;
lgncon: call tsclv
jp nz,lgnc5 ;char lvalue?
ld a,73h ;yes.
call genb
jp lg5a
lgnc5: call tschr2 ;no. char rvalue?
jp nz,lgnc6
ld de,macac4 ;yes--so we're assigning a char to an int lvalue.
lda val ;need value result?
or a
jp z,lgnc5a
ld de,macac5 ;if so, make sure high-order byte is zeroed in result
lgnc5a: call mcrog
jp lg5a
lgnc6: lda optimf
and 8
jp z,lgnc7
ld a,0e7h ;rst 4: ld (hl),e inc hl ld (hl),d
call genb
jp lg5a
lgnc7: ld de,maca1
call mcrog
jp lg5a
;
; Assign to absolute lvalue constant location:
;
palvc: lhld svv1
shld sr0
lhld svv2
shld sr1
lda sval2 ;rvalue a constant?
and 1
jp z,palvcc
lda val ;yes.
or a
jp nz,palv3 ;need value result?
call tsclv ;no.
jp nz,palv2 ;8-bit object?
ld a,3eh ;yes.
call genb
lda svv2
call genb
ld de,macacb
call mcrog
jp lgdone
palv2: ld de,macacc ;16-bit object.
palv2a: call mcrog
xor a
sta sval1 ;result in HL (if needed)
jp lgdone
palv3: call tsclv ;need value result.
jp nz,palv2
ld a,1eh
call genb
lda svv2
call genb
palv4: ld a,7bh
call genb
ld de,macacb
call mcrog
jp lg5a
palvcc: call tsclv ;rvalue is in a register.
jp nz,plvc2 ;simple char lvalue?
lda sval2 ;yes.
and 0c0h
jp nz,palv4 ;in HL?
ld a,7dh ;yes.
call genb
ld de,macacb
jp palv2a
plvc2: lda sval2 ;16-bit value. in HL?
and 0c0h
call nz,gexdehl ;go "ex de,hl" if not, to get value into HL
call tschr2 ;simple char rvalue?
jp nz,plvc3 ;if not, do 16-bit assignment normally
ld a,26h ;else clear H before assigning
call genb
xor a
call genb
plvc3: ld de,mac09 ;go perform assignment
jp palv2a
;
; Assign to a relative lvalue (external or local) location:
;
prlvc: lda sval2
and 1
jp z,prlv2 ;constant rvalue?
prlv1: call flshh1 ;yes. get value in HL
jp lg3
prlv2: lda sval1 ;no; rvalue in a reg. local lvalue?
and 8
jp nz,prlv3
call pn2ind ;yes. get value in DE
call flshh1
jp lgncon
prlv3: lda sval2 ;must be external.
and 0c0h
ld a,0e5h ;push rvalue.
jp z,prlv4
ld a,0d5h
prlv4: call genb
call flshh1 ;generate lvalue in HL
ld a,0d1h ;get back rvalue in DE
call genb
ld a,40h ;result in DE
sta sval2
jp lgncon ;go perform assignment.
glvcv: push hl
lhld svv1
shld sr0
pop hl
ld de,mac40
call mcrog
lda sval1
and 0feh ;no longer a simple lvalue constant
or 10h ;now a "has been" !
sta sval1
ret
;
; Gen code to multiply HL by value passed here in HL:
;
gnmulh: shld sr0 ;save the value
ld a,h
or a ;is it very big?
jp nz,mulhbg ;if so, go do brutal ld de,val- call mult- etc.
ld a,l ;yes.
or a
jp nz,gnmh2
ld de,mac04 ;trivial case: ld hl,0
call mcrog
ret
gnmh2: ld b,6 ;find out if we have an easy power of two.
push af ;push value
gnmh2a: pop af ;pop value
rra ;rotate right along with carry
push af ;and immediately save to preserve carry bit
or a ;did we just rotate the only 1 bit into the carry?
jp z,gnmh3 ;if so, we've got a power of 2 and can do "add hl,hl"'s
dec b ;else keep rotating
jp nz,gnmh2a
pop af ;clean up stack...
mulhbg: ld de,mac0a ;no simple power of two. use brute force.
call mcrog
ret
gnmh3: pop af
ld a,7 ;ok, we can use add hl,hl's. find out how many
sub b ;are needed.
ld b,a ;save 1+n in B.
gnmh4: dec b
ret z
ld a,29h ;and spit 'em out till done.
call genb
jp gnmh4
;
; process e1 ? e2 : e3
; (upon entry, HL -> "?")
;
; New for v1.45 (fixing a bug...)
; Take special care in the case of mixed character and non-character
; values for e2 and e3, so 16 bit values don't get their high order
; bytes chopped off.
;
qexpr: inc hl ;get HL -> e2
call gncjf ;gen cond'l jump-on-false to e3
call ltabtd ;define $ as true branch of pre-? expr
; (fixes bug found by D. Greenlaw)
pop af
push af
call rpshp
call expr1
call ppshp
call flshh1
call igsht
cp colon ;followed by colon?
jp z,qxpr2
call ltabpp
qxpr1: ld de,stg14 ;if not, bad news.
call perr
pop de
ret
qxpr2: inc hl ;colon found OK.
call tschr ;set Z if e2 is a character value
pop bc ;get item on top of stack
push af ;save result of tschr test for later
push bc ;put top item back on the stack
jp nz,qxpr2a ;if e2 wasn't a char, don't bother clearing H
ld de,mac61
call mcrog ;clear H if e2 is a char expression
qxpr2a: pop af
call gfjp ;generate forward jump to after e3.
push af
call ltabfd ;define false ltab branch
call ltabpp ;and pop off ltab entry
call rpshp
pop af
; call expr1 ;evaluate e3 ;??? why comment out???
push af ;like the call above, except comma operator
call expr2 ;recognition is not allowed due to precedence
pop af ;rules. This fixes a Dan Grayson bug.
call ppshp
call flshh1 ;get result in HL
pop bc ;get top item off stack (label code for plvdl)
pop af ;get back Z flag, set iff e2 was a char value
push bc ;put label code back onto stack
jp z,qxpr3 ;if e2 was a char, we don't care if e3 is a char
;otherwise we might have to promote e3, so let's check:
call tschr ;was e3 a char value?
jp nz,qxpr3 ;if not, we don't have to worry about e2 being demoted
ld de,mac61 ;else promote e3 to an int so that e2 won't be demoted
call mcrog ; since e2 was a 16-bit value and e3 is a char.
ld a,1 ;and make the overall result an int
sta typ1
qxpr3: call plvdl ;and pop and define after-e3 label
ret
;IF LASM
;link cc2d
;ENDIF