Linker/symbol.asm
Stephen Heumann 9f232e883a Avoid spurious errors when evaluating EQU/GEQU expressions.
Shifting is now prohibited only for relocatable expressions. It is fine if a shift operator is used with constant operands, simply producing another constant.

Also, spurious errors about using multiple load segments in an expression are no longer reported just because of the load segment "containing" the EQU/GEQU record. Since it does not actually translate to anything in the load file, that segment does not matter.
2022-09-25 21:49:01 -05:00

1592 lines
29 KiB
NASM

keep obj/symbol
mcopy symbol.mac
****************************************************************
*
* Symbol Tables
*
* This module contains the subroutines used to create, search
* and manipulate the symbol table.
*
****************************************************************
copy directPage
****************************************************************
*
* SymbolCommon - global data for the symbol table module
*
****************************************************************
*
SymbolCommon privdata
;
; Symbol table entry
;
symNext equ 0 pointer to the next symbol
symAlpha equ 4 alphabetized list pointer
symVal equ 8 value of the label (or ptr to expression)
symSeg equ 12 segment number
symFile equ 14 file number
symData equ 16 data area number
symExp equ 18 is the value an expression?
symFlag equ 20 pass 1/2 resolved flags
symPriv equ 22 is the symbol private?
symLength equ 24 length attribute
symType equ 26 type attribute
symName equ 28 symbol name (p-string)
symSize equ 28 size of a symbol, sans symbol name
;
; Constants
;
hashSize equ 877 number of hash buckets
blockSize equ 4096 symbol table blocking factor
;
; Symbol table variables
;
alpha ds 4 head of alphabetized list
hashDisp ds 2 disp in hash table; saved for efficiency
poolPtr ds 4 ptr to next byte in symbol table pool
poolSize ds 2 # of bytes left in the current pool
table ds hashSize*4 symbol table
end
****************************************************************
*
* AllocatePool - allocate a new symbol table pool
*
* Outputs:
* poolPtr - pointer to the first byte of the pool
* poolSize - size of the block, in bytes
*
****************************************************************
*
AllocatePool private
using SymbolCommon
ph4 #blockSize
jsr MLalloc
sta poolPtr
stx poolPtr+2
lda #blockSize
sta poolSize
rts
end
****************************************************************
*
* AlphaInsert - insert the symbol in the alphabetized list
*
* Inputs:
* sym - pointer to the new symbol
* alpha - head of the alphabetized list
*
****************************************************************
*
AlphaInsert private
using SymbolCommon
p1 equ 1 work pointers
p2 equ 5
p3 equ 9
sub (4:sym),12
lda alpha if alpha = nil then
ora alpha+2
bne lb1
move4 sym,alpha alpha = sym
ldy #symAlpha sym^.alpha = nil
lda #0
sta [sym],Y
iny
iny
sta [sym],Y
brl lb8 return
lb1 move4 alpha,p1 p1 = alpha
stz p2 p2 = nil
stz p2+2
add4 sym,#symName while sym^.symName >= p1^.symName do
lda [sym]
and #$00FF
sta len1
lb2 add4 p1,#symName,p3
lda len1
sta lens
lda [p3]
and #$00FF
sta len2
cmp lens
bge lb3
sta lens
lb3 short M
ldy #1
lb4 lda [sym],Y
cmp [p3],Y
bne lb5
iny
dec lens
bne lb4
lda len1
cmp len2
lb5 long M
blt lb6
move4 p1,p2 p2 = p1
ldy #symAlpha p1 = p2^.symAlpha
lda [p2],Y
sta p1
iny
iny
lda [p2],Y
sta p1+2
ora p1 quit if at the end of the list
bne lb2 endwhile
lb6 sub4 sym,#symName fix sym
ldy #symAlpha sym^.symAlpha = p1
lda p1
sta [sym],Y
iny
iny
lda p1+2
sta [sym],Y
lda p2 if p2 = nil then
ora p2+2
bne lb7
move4 sym,alpha alpha = sym
bra lb8 return
lb7 ldy #symAlpha p2^.symAlpha = sym
lda sym
sta [p2],Y
iny
iny
lda sym+2
sta [p2],Y
lb8 ret
;
; Local data
;
lens ds 2 shortest string length
len1 ds 2 length(sym^.symName)
len2 ds 2 length(p1^.symName)
end
****************************************************************
*
* CreateSymbol - create a new symbol table entry
*
* Inputs:
* name - name of the new entry
* hashDisp - disp in hash table for the entry
*
* Outputs:
* returns a pointer to the new symbol table entry
*
****************************************************************
*
CreateSymbol private
using Common
using OutCommon
using SymbolCommon
entryLength equ 1 length of the symbol table entry
sym equ 3 ptr to symbol table entry
p1 equ 7 work pointer
sub (4:name),10
lda [name] no match - create a symbol table entry
and #$00FF
sec
adc #symSize
sta entryLength
cmp poolSize
ble cs2
jsr AllocatePool no room - get a new pool
cs2 sub2 poolSize,entryLength subtract the space we need
clc update the pool pointer and get a copy
lda poolPtr
sta sym
adc entryLength
sta poolPtr
lda poolPtr+2
sta sym+2
adc #0
sta poolPtr+2
ldx hashDisp place the record in the hash list
ldy #2
lda table,X
sta [sym]
lda table+2,X
sta [sym],Y
lda sym
sta table,X
lda sym+2
sta table+2,X
ldy #symSeg record our load segment number
lda loadNumber
sta [sym],Y
ldy #symFile record our file number
lda fileNumber
sta [sym],Y
ldy #symFlag the value is not resolved
lda #0
sta [sym],Y
ldy #symPriv the symbol is not private
sta [sym],Y
add4 sym,#symName,p1 record the symbol name
lda [name]
and #$00FF
tay
short M
cs3 lda [name],Y
sta [p1],Y
dey
bpl cs3
long M
lda symbols if the symbol table will be printed then
beq cs4
ph4 sym insert in alphabetical list
jsr AlphaInsert
cs4 ret 4:sym
end
****************************************************************
*
* Define - define a symbol
*
* Inputs:
* name - ptr to the symbol name
* length - length attribute
* type - type attribute
* private - is the symbol private?
* global - is the symbol global? (or local)
* expression - is the value an expression? (or a constant)
* value - symbol value, or pointer to the expression
* isData - is the symbol a data area name?
* isSegment - is the symbol a segment name?
*
****************************************************************
*
Define start
using Common
using SymbolCommon
using ExpCommon
using OutCommon
sym equ 1 pointer to symbol table entry
sub (4:name,2:length,2:type,2:private,2:global,2:expression,4:value,2:isData,2:isSegment),4
lda global if the symbol is local then
bne fs1
lda dataNumber if dataNumber = 0 then
jeq lb2 return {don't define the symbol!}
! {get a symbol to define}
fs1 ph4 name if ((sym = FindSymbol(name)) != NULL) {
jsr FindSymbol
sta sym
stx sym+2
ora sym+2
beq fs5
ldy #symFile if (sym->symFile == fileNumber)
lda [sym],Y
cmp fileNumber
beq fs6 goto fs6;
fs2 ldy #symFile while (sym->symFile != fileNumber) {
lda [sym],Y
cmp fileNumber
beq fs4
fs3 ldy #2 sym = sym->symNext;
lda [sym]
tax
lda [sym],Y
sta sym+2
stx sym
ora sym if (sym == NULL)
beq fs5 goto fs5;
bra fs2 }
fs4 clc if (!Match(& sym->symName,name)) {
lda sym
adc #symName
tax
lda sym+2
adc #^symName
pha
phx
ph4 name
jsr Match
tax
beq fs6
bra fs3 sym = sym->symNext;
! if (sym == NULL)
! goto fs5;
! goto fs2;
! }
! }
bra fs6 else
fs5 ph4 name sym = CreateSymbol(name);
jsr CreateSymbol
sta sym
stx sym+2
fs6 anop
lda expression if the value is an expression then
beq ex1
ph4 value copy the expression
jsr CopyExpression
ldy #symVal
sta [sym],Y
ldy #symVal+2
txa
sta [sym],Y
ldy #symExp set the expression flag
lda copiedExpression
sta [sym],Y
bne ex2 if a constant was returned then
ldy #symFlag set the constant flag
lda #isConstant
ora [sym],Y
sta [sym],Y
bra ex2 else
ex1 ldy #symVal save the symbol value
lda value
sta [sym],Y
ldy #symVal+2
lda value+2
sta [sym],Y
ldy #symExp clear expression flag
lda #0
sta [sym],Y
ex2 anop endif
ldy #symLength set the length attribute
lda length
sta [sym],Y
ldy #symType set the type attribute
lda type
sta [sym],Y
ldy #symPriv set the private flag
lda private
sta [sym],Y
ldy #symData set the data area number
lda dataNumber
ldx global
beq ex3
ldx isData
bne ex3
lda #0
ex3 sta [sym],Y
ldy #symFile set the file number
lda fileNumber
sta [sym],Y
ldy #symSeg set the load segment number
lda loadNumber
sta [sym],Y
ldy #symFlag set the "resolved on pass 1" flag
lda [sym],Y
ora #pass1Resolved+pass1Requested
sta [sym],Y
lda isData if isData then
beq lb2
! ldy #symFlag set the data area flag
lda [sym],Y
ora #isDataArea
sta [sym],Y
lb2 lda isSegment if isSegment then
beq lb3
! ldy #symFlag set the segment flag
lda [sym],Y
ora #isSegmentFlag
sta [sym],Y
lb3 ret
end
****************************************************************
*
* Define2 - note that the symbol is resolved on pass 2
*
* Inputs:
* name - ptr to the symbol name
* global - is the symbol global?
* value - value, or 0 if the value does not need to be checked
*
****************************************************************
*
Define2 start
using Common
using SymbolCommon
sym equ 1 pointer to symbol table entry
p1 equ 5 copy of sym; used for duplicate check
sub (4:name,2:global,4:value),8
lda global if the symbol is local then
bne lb1
lda dataNumber if dataNumber = 0 then
jeq lb10 return {don't define the symbol!}
! /* find the correct symbol */
lb1 ph4 name sym = FindSymbol(name);
jsr FindSymbol p1 = sym;
sta sym
sta p1
stx sym+2
stx p1+2
ldy #symFile if (sym->symFile != fileNumber) {
lda [sym],Y
cmp fileNumber
beq lb5
lb2 ldy #symFile while (sym->symFile != fileNumber)
lda [sym],Y
cmp fileNumber
beq lb4
lb3 ldy #2 sym = sym->symNext;
lda [sym],Y
tax
lda [sym]
sta sym
stx sym+2
bra lb2
lb4 clc if (!Match(& sym->symName,name) {
lda sym
adc #symName
tax
lda sym+2
adc #^symName
pha
phx
ph4 name
jsr Match
tax
bne lb3
! sym = sym->symNext;
! goto lb2;
! }
! }
! /* check for duplicates in this file */
lb5 ldy #symFlag if (sym->symFlag & pass2Resolved)
lda [sym],Y
and #pass2Resolved
bne lb7
! Error(DUPLICATE_SYMBOL);
! /* check for duplicate globals in */
! /* two different files */
ldy #symPriv else if ((global) && (!sym^.symPriv)){
lda [sym],Y
bne lb9
lb6 lda p1 while (p1 != NULL) {
ora p1+2
beq lb9
cmpl p1,sym if (p1 != sym)
beq lb8
clc if (Match(p1->symName,name))
lda p1
adc #symName
tax
lda p1+2
adc #^symName
pha
phx
ph4 name
jsr Match
tax
bne lb8
ldy #symPriv if (!p1->symPriv) {
lda [p1],Y
bne lb8
ldy #symFlag if (p1->symFlag & pass2Resolved)
lda [p1],Y
and #pass2Resolved
beq lb8
lb7 ph4 name Error(DUPLICATE_SYMBOL);
ph2 #1
jsr Error
bra lb9 goto lb9;
! }
lb8 ldy #2 p1 = p1->symNext;
lda [p1],Y
tax
lda [p1]
sta p1
stx p1+2
bra lb6 }
! }
lb9 anop
ldy #symFlag set the "resolved on pass 2" flag
lda [sym],Y
ora #pass2Resolved+pass2Requested
sta [sym],Y
ldy #symExp if the symbol is an expression then
lda [sym],Y
beq lb9a
ldy #symVal+2 make sure all needed symbols are
lda [sym],Y available
; and #$FF00 debug
; beq db1 debug
; brk $33 debug
;b1 lda [sym],Y debug
pha
dey
dey
lda [sym],Y
pha
jsr Evaluate
lb9a lda value if value <> 0 then
ora value+2
beq lb10
ldy #symVal if value <> sym^.symVal then
lda [sym],Y
cmp value
bne lb9b
iny
iny
lda [sym],Y
cmp value+2
beq lb10
lb9b ph4 name addressing error
ph2 #7
jsr Error
lb10 ret
end
****************************************************************
*
* FindFirstSymbol - find the alphabetically smallest symbol
*
* Inputs:
* r12 - head of the symbol table
*
* Outputs:
* r0 - pointer to the first symbol
* r12 - pointer to the remaining symbols
* C - set if a symbol was found, else clear
*
* Notes:
* Only symbols resolved on pass 2 are returned.
*
****************************************************************
*
FindFirstSymbol private
using Common
using SymbolCommon
lb0 lda r12 if r12 = nil then
ora r14
bne lb1 return false
clc
rts
lb1 move4 r12,r0 r0 = r12
ldy #symAlpha r12 = r0^.symAlpha
lda [r0],Y
sta r12
iny
iny
lda [r0],Y
sta r14
ldy #symFlag if the symbol was not resolved then
lda [r0],Y
and #pass2Resolved
beq lb0 skip this one
sec return true
rts
end
****************************************************************
*
* FindSymbol - find a symbol
*
* Inputs:
* name - pointer to the symbol name
*
* Outputs:
* A-X - address of the symbol table entry; nil for none
* hashDisp - hash table displacement
*
* Notes:
* There may be several symbols with the same name. In
* that case, this subroutine returns the first one in
* the hash bucked. You can scan forward from sym^.next
* to find the others.
*
****************************************************************
*
FindSymbol private
using SymbolCommon
sym equ 1 symbol table pointer
sub (4:name),4
ph4 name get the address of the proper hash bucket
jsr Hash
sta hashDisp
tax
lda table,X
sta sym
lda table+2,X
sta sym+2
ora sym branch if it is empty
beq lb2
lb1 clc if the names match then
lda sym
adc #symName
tax
lda sym+2
adc #0
pha
phx
ph4 name
jsr Match
tax
beq lb2 return
ldy #2 next symbol
lda [sym],Y
tax
lda [sym]
sta sym
stx sym+2
ora sym+2
bne lb1
lb2 ret 4:sym
end
****************************************************************
*
* GetSymbolMemory - get memory from the symbol table pool
*
* Inputs:
* size - number of bytes to reserve
*
* Outputs:
* returns a pointer to the memory
*
****************************************************************
*
GetSymbolMemory start
using SymbolCommon
ptr equ 1 pointer to the memory
sub (2:size),4
lda size if there isn't enough room then
cmp poolSize
ble lb2
cmp #blockSize if the request is bigger than
blt lb1 blockSize then
pea 0 get the memory from MLalloc
pha
jsr MLAlloc
sta ptr
stx ptr+2
bra lb3 return
lb1 jsr AllocatePool no room - get a new pool
lb2 sub2 poolSize,size subtract the space we need
clc update the pool pointer and get a copy
lda poolPtr
sta ptr
adc size
sta poolPtr
lda poolPtr+2
sta ptr+2
adc #0
sta poolPtr+2
lb3 ret 4:ptr
end
****************************************************************
*
* GetSymbolValue - get the value of a symbol; for Evaluate only!
*
* Inputs:
* name - name of the symbol
* strong - strong reference? (or weak)
* fileNumber - current file number
* expSegment - segment for the current expression
*
* Outputs:
* symbolValue - symbol value
* symbolRelocatable - is the symbol relocatable?
* symbolLength - length attribute
* symbolCount - count attribute
* symbolType - type attribute
* symbolFlag - symbol flags
* symbolData - data area number
*
****************************************************************
*
GetSymbolValue start
using Common
using OutCommon
using SymbolCommon
using ExpCommon
sym equ 1 pointer to the symbol
p1 equ 5 work pointer
sub (4:name,2:strong),8
;
; Find the symbol in the hash table
;
ph4 name find the symbol
jsr FindSymbol
sta sym
sta p1
stx sym+2
stx p1+2
ora p1+2
beq nosym
;
; Find the private version of the symbol. Use it if it is resolved.
;
ldy #symFile if p1^.symFile <> fileNumber then
lda [p1],Y
cmp fileNumber
beq lb4
lb1 ldy #symFile while p1^.symFile <> fileNumber do
lda [p1],Y
cmp fileNumber
beq lb3
lb2 ldy #2 p1 := p1^.next;
lda [p1],Y
tax
lda [p1]
sta p1
stx p1+2
ora p1+2
beq gb1
bra lb1
lb3 clc if not Match(p1^.symName,name) then
lda #symName
adc p1
tax
lda #^symName
adc p1+2
pha
phx
ph4 name
jsr Match
tax
bne lb2 p1 := p1^.next;
! goto 1;
! endif
lb4 anop endif
ldy #symFlag if the private symbol is resolved then
lda [p1],Y
and #pass1Resolved
beq gb1
move4 p1,sym use it
bra sv1
;
; Find the global version of the symbol.
;
gb1 ldy #symFlag while not (sym^.symFlag & pass1Resolved) do
lda [sym],Y
and #pass1Resolved
bne gb3
gb2 ldy #2 sym := sym^.next;
lda [sym],Y
tax
lda [sym]
sta sym
stx sym+2
ora sym+2 if sym = nil then
bne gb1
nosym stz symbolValue symbolValue = 0
stz symbolValue+2
stz symbolRelocatable symbolRelocatable = false
stz symbolLength symbolLength = 0
stz symbolCount symbolCount = 0
stz symbolType symbolType = 0
stz symbolFlag symbolFlag = 0
stz symbolData symbolData = 0
stz symbolFile symbolFile = 0
lda strong if the reference is strong then
jeq rt1
ph4 name flag the error
ph2 #6
jsr Error
brl rt1 return
gb3 ldy #symPriv if sym^.symPriv then
lda [sym],Y
bne gb2 sym := sym^.next;
! goto 1;
! endif
clc if not Match(sym^.symName,name) then
lda #symName
adc sym
tax
lda #^symName
adc sym+2
pha
phx
ph4 name
jsr Match
tax
bne gb2 sym := sym^.next;
! goto 1;
! endif
! endif
;
; Set the symbol values
;
sv1 ldy #symExp if the value is an expression then
lda [sym],Y
jeq sv2
ph2 copiedExpression save volatile variables
ph4 shiftCount
ph2 shiftFlag
ph4 shiftValue
ldy #symVal+2 evaluate the expression
lda [sym],Y
pha
dey
dey
lda [sym],Y
pha
jsr Evaluate
sta symbolValue save the value
stx symbolValue+2
sv1a lda symbolRelocatable if the symbol is relocatable then
beq sv1c
lda shiftFlag if the value is shifted then
beq sv1c
ph4 name flag the error
ph2 #2
jsr Error
sv1c pl4 shiftValue restore volatile variables
pl2 shiftFlag
pl4 shiftCount
pl2 copiedExpression
bra sv3 else
sv2 ldy #symVal set the value
lda [sym],Y
sta symbolValue
iny
iny
lda [sym],Y
sta symbolValue+2
stz symbolRelocatable set the relocation flag
ldy #symFlag
lda [sym],Y
and #isConstant
bne sv3
inc symbolRelocatable if relocatable then
jsr CheckSegment check for cross-file errors
ldy #symSeg set the expression file
lda [sym],Y
sta expSegment
sv3 anop endif
lda #1 count attribute is 1
sta symbolCount
ldy #symLength set the length attribute
lda [sym],Y
sta symbolLength
ldy #symType set the type attribute
lda [sym],Y
sta symbolType
ldy #symFlag set the flags
lda [sym],Y
sta symbolFlag
ldy #symFile set the file
lda [sym],Y
sta symbolFile
ldy #symData set the data area number
lda [sym],Y
sta symbolData
beq rt1 if symbolData <> 0 then
lda symbolFlag if not symbolFlag & isDataArea then
and #isDataArea
bne rt1
ldx symbolData if not dataAreas[symbolData] then
lda dataAreas,X
and #$00FF
bne rt1
lda strong if the reference is strong then
beq rt1
ph4 name flag unresolved reference
ph2 #6
jsr Error
rt1 ret
;
; CheckSegment - check for cross-file expressions
;
CheckSegment anop
lda expSegment if the expression is file-sensitive
beq cf1 then
ldy #symSeg verify that the files match
cmp [sym],Y
beq cf1
clc nope -> flag the error
lda sym
adc #symName
tax
lda sym+2
adc #^symName
pha
phx
ph2 #24
jsr Error
cf1 rts
end
****************************************************************
*
* Hash - find the hash tabe displacement for a symbol
*
* Inputs:
* ptr - pointer to the symbol name
*
* Outputs:
* returns the displacement into table
*
****************************************************************
*
Hash private
using SymbolCommon
disp equ 1 hash displacement
temp equ 3 temp value; for forming char pairs
sub (4:ptr),4
! {get ready for the sum loop}
lda [ptr] get the # of characters
and #$00FF
lsr A X = numChars div 2
tax
bcc lb1 if odd(numChars) then
lda [ptr] disp = ch[1] & $3F
xba
and #$003F
sta disp
ldy #2 Y = 2
bra lb2 else
lb1 stz disp disp = 0
ldy #1 y = 1
lb2 anop endif
! {add pairs of characters to the sum}
txa quit now if there was 1 character
beq lb4
lb3 lda [ptr],Y fetch a character pair
and #$003F compact it to 12 bits
sta temp
lda [ptr],Y
and #$3F00
lsr A
lsr A
ora temp
adc disp add the result to disp
sta disp
iny next pair
iny
dex
bne lb3
! {create a hash table displacement}
lb4 lda disp mod result with # of buckets
lb5 cmp #hashSize
blt lb6
sec
sbc #hashSize
bra lb5
lb6 asl A convert to a displacement
asl A
sta disp
ret 2:disp
end
****************************************************************
*
* InitSymbol - initialize the symbol table module
*
* Outputs:
* poolSize - set to 0
* table - all pointers set to nil
*
****************************************************************
*
InitSymbol start
using SymbolCommon
stz alpha alpha = nil
stz alpha+2
stz poolSize no bytes in the symbol pool
move #0,table,#hashSize*4 zero the hash table
rts
end
****************************************************************
*
* Match - see if two names match
*
* Inputs:
* p1,p2 - pointers to the two names
*
* Outputs:
* A - 0 if the names match, 1 if they do not
*
* Notes:
* This subroutine assumes that the names are not null
* strings.
*
****************************************************************
*
Match private
res equ 1 do the names match?
sub (4:p1,4:p2),2
lda #1 assume they do not match
sta res
lda [p1] check the length & first char
cmp [p2]
bne mt2
and #$00FF check the characters
tay
short M
mt1 lda [p1],Y
cmp [p2],Y
bne mt2
dey
bne mt1
long M
stz res the strings match
mt2 long M
ret 2:res
end
****************************************************************
*
* NeedSegment - do we need this symbol from the library?
*
* Inputs:
* name - pointer to the symbol name
* priv - private flag
* fileNumber - symbol's file number
* pass - pass number
*
* Outputs:
* A - 1 if we need it, 0 if we don't
*
****************************************************************
*
NeedSegment start
using Common
using SymbolCommon
need equ 1 do we need it?
sp equ 3 symbol pointer
maybe equ 7 we may need this symbol
sub (4:name,2:priv),8
stz need assume we don't need it
stz maybe so far, we have no need
ph4 name if the symbol is not found then
jsr FindSymbol
sta sp
stx sp+2
ora sp+2
jeq lb10 we don't need it
lda priv if the library symbol is private then
beq lb4
ldy #symFile if (sp->symFile != fileNumber) {
lda [sp],Y
cmp fileNumber
beq lb3
lb1 ldy #symFile while (sp->symFile != fileNumber) {
lda [sp],Y
cmp fileNumber
beq lb2a
lb2 ldy #2 sp = sp->symNext;
lda [sp],Y
tax
lda [sp]
sta sp
stx sp+2
ora sp+2 if (sp == NULL)
jeq lb10 return false;
bra lb1 }
lb2a clc if (!Match(sp->symName,sp)) {
lda sp
adc #symName
tax
lda sp+2
adc #^symName
pha
phx
ph4 name
jsr Match
tax
bne lb2
! sp = sp->symNext;
! goto lb1;
lb3 anop }
jsr CheckSymbol check the symbol
bcc lb10
inc need
bra lb10
lb4 anop else {if library symbol is global then}
lda sp while (sp != NULL)
ora sp+2
beq lb7
ldy #symPriv if (!sp->symPriv)
lda [sp],Y
bne lb6
clc if (Match(sp->symName,name))
lda sp
adc #symName
tax
lda sp+2
adc #^symName
pha
phx
ph4 name
jsr Match
tax
bne lb6
lda pass if the symbol is resolved then
cmp #1
bne lb5
lda #pass1Resolved
bra lb5a
lb5 lda #pass2Resolved
lb5a ldy #symFlag
and [sp],Y
bne lb10 we don't need this segment
lda pass if the symbol is requested then
cmp #1
bne lb5b
lda #pass1Requested
bra lb5c
lb5b lda #pass2Requested
lb5c ldy #symFlag
and [sp],Y
beq lb6
inc maybe we may need this segment
lb6 ldy #2 sp = sp->symNext;
lda [sp],Y
tax
lda [sp]
sta sp
stx sp+2
bra lb4
lb7 lda maybe if maybe then
beq lb10
inc need we need this symbol
lb10 ret 2:need
;
; Check the symbol
;
CheckSymbol anop
lda pass if (pass == 1) {
cmp #1
bne cs1
ldy #symFlag if (sp->symFlag & pass1Requested)
lda [sp],Y
bit #pass1Requested
beq cs2
bit #pass1Resolved if (!(sp->symFlag & pass1Resolved)
bne cs2
sec return true;
rts
! }
! else {pass == 2}
cs1 ldy #symFlag if (sp->symFlag & pass2Requested)
lda [sp],Y
bit #pass2Requested
beq cs2
bit #pass2Resolved if (!(sp->symFlag & pass2Resolved)
bne cs2
sec return true;
rts
! }
cs2 clc return false
rts
end
****************************************************************
*
* PrintSymbol - print one symbol
*
* Inputs:
* r0 - pointer to the symbol table entry
*
****************************************************************
*
PrintSymbol private
using Common
using SymbolCommon
ldy #symVal+2 push the symbol value
lda [r0],Y
pha
dey
dey
lda [r0],Y
pha
ldy #symExp if the symbol is an expression then
lda [r0],Y
beq lb0
jsr Evaluate evaluate the expression
phx
pha
lb0 ph2 #8 print the symbol value
ph2 #0
jsr PrintHex
ldy #symPriv print the global/private flag
lda [r0],Y
beq lb1
puts #' P '
bra lb2
lb1 puts #' G '
lb2 ldy #symSeg print the load segment number
lda [r0],Y
ldx kflag
beq lb3
ldx express
beq lb3
inc A
lb3 pea 0
pha
ph2 #2
ph2 #0
jsr PrintHex
putc #' '
ldy #symData print the data area number
lda [r0],Y
pea 0
pha
ph2 #2
ph2 #0
jsr PrintHex
putc #' '
add4 r0,#symName-1,r4 print the symbol name
puts [r4]
rts
end
****************************************************************
*
* PrintSymbols - print the symbol table
*
* Inputs:
* symbols - print symbols flag
*
****************************************************************
*
PrintSymbols start
using SymbolCommon
using Common
;
; Write the header
;
lda symbols quit if the symbol flag is off
bne lb1
rts
lb1 lda list write the header
bne lb2
putcr
putcr
lb2 puts #'Global symbol table:',cr=t
putcr
;
; Initialize the symbol list pointer
;
move4 alpha,r12
;
; Print the symbols
;
stz col2 not doing column 2
ps1 jsr FindFirstSymbol find the next symbol to print
bcc ps5
jsr PrintSymbol print it
lda col2 if this one is in column 1 then
bne ps4
inc col2 col2 = true
ldy #symName get the length of the name
lda [r0],Y
and #$00FF
sta r4
sec print the proper number of spaces
lda #27
sbc r4
sta r4
beq ps2
bpl ps3
ps2 lda #1
sta r4
ps3 putc #' '
dec r4
bne ps3
bra ps1 else
ps4 stz col2 col2 = false
putcr write a CR
jsr CheckForPause check for early exit
bra ps1 next symbol
ps5 lda col2 if in column 1 then
bne ps6
putcr write the CR
ps6 putcr
lda list
beq ps7
putcr
putcr
ps7 rts
;
; Local data
;
col2 ds 2
end
****************************************************************
*
* Reference - make a reference to a symbol
*
* Inputs:
* sp - pointer to the symbol name to reference
*
****************************************************************
*
Reference start
using Common
using SymbolCommon
! {get a symbol to define}
fs1 ph4 sp if ((r0 = FindSymbol(sp)) != NULL) {
jsr FindSymbol
sta r0
stx r0+2
ora r0+2
beq fs5
ldy #symFile if (r0->symFile == fileNumber)
lda [r0],Y
cmp fileNumber
beq fs6 goto fs6;
fs2 ldy #symFile while (r0->symFile != fileNumber) {
lda [r0],Y
cmp fileNumber
beq fs4
fs3 ldy #2 r0 = r0->symNext;
lda [r0]
tax
lda [r0],Y
sta r2
stx r0
ora r0 if (r0 == NULL)
beq fs5 goto fs5;
bra fs2 }
fs4 clc if (!Match(r0->symName,sp)) {
lda r0
adc #symName
tax
lda r2
adc #^symName
pha
phx
ph4 sp
jsr Match
tax
bne fs3
rts r0 = r0->symNext;
! if (r0 == NULL)
! goto fs5;
! goto fs2;
! }
! }
! else
fs5 ph4 sp CreateSymbol(sp);
jsr CreateSymbol
sta r0
stx r2
fs6 ldy #symFlag set the pass 1 requested flag
lda [r0],Y
ora #pass1Requested
sta [r0],Y
rts
end
****************************************************************
*
* Reference2 - note that pass2 has requested a symbol
*
* Inputs:
* sp - pointer to the symbol name to reference
*
****************************************************************
*
Reference2 start
using Common
using SymbolCommon
ph4 sp r0 = FindSymbol(sp);
jsr FindSymbol
sta r0
stx r2
ldy #symFile if (r0->symFile != fileNumber) {
lda [r0],Y
cmp fileNumber
beq lb3
lb1 ldy #symFile while (r0->symFile != fileNumber) {
lda [r0],Y
cmp fileNumber
beq lb2a
lb2 ldy #2 r0 = r0->symNext;
lda [r0],Y
tax
lda [r0]
sta r0
stx r2
bra lb1
lb2a clc if (!Match(r0->symName,sp)) {
lda r0
adc #symName
tax
lda r2
adc #^symName
pha
phx
ph4 sp
jsr Match
tax
bne lb2
! r0 = r0->symNext;
! goto lb1;
lb3 anop }
ldy #symFlag set the pass 2 requested flag
lda [r0],Y
ora #pass2Requested
sta [r0],Y
rts
end
****************************************************************
*
* Unresolved - are there unresolved references?
*
* Inputs:
* pass - pass number
*
* Outputs:
* C - set if there are unresolved references, else clear
*
****************************************************************
*
Unresolved start
using SymbolCommon
using Common
lda pass if pass1 then
cmp #1
bne lb1
lda #pass1Resolved resolved = pass1Resolved
ldx #pass1Requested requested = pass1Requested
bra lb2 else
lb1 lda #pass2Resolved resolved = pass2Resolved
ldx #pass2Requested requested = pass2Requested
lb2 sta resolved endif
stx requested
la index,hashSize*4-4 for each hash bucket do
lb3 ldx index for each symbol in the bucket do
lda table,X
sta r0
sta r4
lda table+2,X
sta r2
sta r6
ora r2
beq lb7
lb4 ldy #symFlag if r0^.symFlag & requested then
lda [r0],Y
bit requested
beq lb6
bit resolved if not (r0^.symFlag & resolved) then
bne lb6
ldy #symPriv if r0^.symPriv then
lda [r0]
beq lb5
jsr GlobalExists if GlobalExists then
bcs lb6 skip request
lb5 sec return true
rts
lb6 ldy #2 r0 = r0^.symNext
lda [r0],Y
tax
lda [r0]
sta r0
stx r2
ora r2 next symbol in bucket
bne lb4
lb7 sec next bucket
lda index
sbc #4
sta index
bpl lb3
clc no symbols needed
rts
;
; GlobalExists - see if a global symbol by the name of r0^.symName exists
;
GlobalExists anop
move4 r4,r8 r8 = first sym in bucket
add4 r0,#symName,r12 r12 = @r0^.symName
ge1 ldy #symPriv for each symbol do
lda [r8],Y if the symbol is global then
bne ge2
clc if Match(r8^.symName,r12) then
lda r8
adc #symName
tax
lda r10
adc #^symName
pha
phx
ph4 r12
jsr Match
tax
bne ge2
sec return true
rts
ge2 ldy #2 next symbol
lda [r8],Y
tax
lda [r8]
sta r8
stx r10
ora r10
bne ge1
clc return false
rts
;
; Local data
;
index ds 2 index into the hash table
resolved ds 2 resolved mask for this pass
requested ds 2 requested mask for this pass
end