{$optimize 7} {---------------------------------------------------------------} { } { Symbol Table } { } { Handle the symbol table. } { } { External Subroutines: } { } { CheckStaticFunctions - check for undefined functions } { CompTypes - Determine if the two types are compatible } { DoGlobals - declare the ~globals and ~arrays segments } { FindSymbol - locate a symbol in the symbol table } { GenParameters - Generate labels and space for the parameters } { GenSymbols - generate a symbol table for the debugger } { InitSymbol - initialize the symbol table handler } { NewSymbol - insert a new symbol in the symbol table } { PopTable - Pop a symbol table (remove definitions local to a } { block) } { PushTable - Create a new symbol table, pushing the old one } { ResolveForwardReference - resolve a forward reference } { } { External Variables: } { } { table - current symbol table } { } { charPtr - pointer to the base type for char } { sCharPtr - pointer to the base type for signed char } { uCharPtr - pointer to the base type for unsigned char } { shortPtr - pointer to the base type for short } { uShortPtr - pointer to the base type for unsigned short } { intPtr - pointer to the base type for int } { uIntPtr - pointer to the base type for unsigned int } { int32Ptr - pointer to the base type for 32-bit int } { uInt32Ptr - pointer to the base type for 32-bit unsigned int } { longPtr - pointer to the base type for long } { uLongPtr - pointer to the base type for unsigned long } { longLongPtr - pointer to the base type for long long } { uLongLongPtr - pointer to base type for unsigned long long } { floatPtr - pointer to the base type for float } { doublePtr - pointer to the base type for double } { compPtr - pointer to the base type for comp } { extendedPtr - pointer to the base type for extended } { boolPtr - pointer to the base type for _Bool } { voidPtr - pointer to the base type for void } { voidPtrPtr - typeless pointer, for some type casting } { charPtrPtr - pointer to type record for char * } { vaInfoPtr - pointer to type record for internal va info type } { stringTypePtr - pointer to the base type for string literals } { utf16StringTypePtr - pointer to the base type for UTF-16 } { string literals } { utf32StringTypePtr - pointer to the base type for UTF-32 } { string literals } { constCharPtr - pointer to the type const char } { defaultStruct - default for structures with errors } { } {---------------------------------------------------------------} unit Symbol; {$LibPrefix '0/obj/'} interface uses CCommon, CGI, MM, Scanner; {$segment 'CC'} {---------------------------------------------------------------} const staticNumLen = 5; {length of staticNum name prefix} type symbolTablePtr = ^symbolTable; symbolTable = record {a symbol table} {NOTE: the array of buckets must come first in the record!} buckets: array[0..hashSize2] of identPtr; {hash buckets} next: symbolTablePtr; {next symbol table} isEmpty: boolean; {is the pool empty (nothing in buckets)?} case noStatics: boolean of {no statics/staticNum for this table?} false: (staticNum: packed array[1..6] of char); {staticNum for this table} true: (); end; var table: symbolTablePtr; {current symbol table} globalTable: symbolTablePtr; {global symbol table} functionTable: symbolTablePtr; {table for top level of current function} {output from GenParameters} lastParameterLLN: integer; {label number of last parameter (0 if none)} lastParameterSize: integer; {size of last parameter} {base types} charPtr,sCharPtr,uCharPtr,shortPtr,uShortPtr,intPtr,uIntPtr,int32Ptr, uInt32Ptr,longPtr,uLongPtr,longLongPtr,uLongLongPtr,boolPtr, floatPtr,doublePtr,compPtr,extendedPtr,stringTypePtr,utf16StringTypePtr, utf32StringTypePtr,voidPtr,voidPtrPtr,charPtrPtr,vaInfoPtr,constCharPtr, defaultStruct: typePtr; {---------------------------------------------------------------} procedure CheckStaticFunctions; { check for undefined functions } procedure CheckUnused (tPtr: symbolTablePtr); { check for unused variables in symbol table } function CompTypes (t1, t2: typePtr): boolean; { Determine if the two types are compatible } function StrictCompTypes (t1, t2: typePtr): boolean; { Determine if the two types are compatible, strictly following } { C standard rules. } procedure DoGlobals; { declare the ~globals and ~arrays segments } function FindSymbol (var tk: tokenType; class: spaceType; oneLevel: boolean; staticAllowed: boolean): identPtr; { locate a symbol in the symbol table } { } { parameters: } { tk - token record for the identifier to find } { class - the kind of variable space to search } { oneLevel - search one level only? (used to check for } { duplicate symbols) } { staticAllowed - can we check for static variables? } { } { returns: } { A pointer to the symbol table entry is returned. If } { there is no entry, nil is returned. } procedure GenParameters (pp: parameterPtr); { Generate labels and space for the parameters } { } { parameters: } { pp - pointer to first parameter } { } { variables: } { lastParameterLLN - label number of last parameter } { lastParameterSize - size of last parameter } procedure GenSymbols (sym: symbolTablePtr; doGlobals: boolean); { generate a symbol table for the debugger } { } { parameters: } { sym - symbol table to generate } { doGlobals - include global symbols in the table } { } { outputs: } { symLength - length of debug symbol table } procedure InitSymbol; { Initialize the symbol table module } function IsVoid (tp: typePtr): boolean; { Check to see if a type is void } { } { Parameters: } { tp - type to check } { } { Returns: True if the type is void, else false } function LabelToDisp (lab: integer): integer; extern; { convert a local label number to a stack frame displacement } { } { parameters: } { lab - label number } function MakePascalType (origType: typePtr): typePtr; { make a version of a type with the pascal qualifier applied } { } { parameters: } { origType - the original type } { } { returns: pointer to the pascal-qualified type } function MakePointerTo (pType: typePtr): typePtr; { make a pointer type } { } { parameters: } { pType - the type pointed to } { } { returns: the pointer type } function MakeCompositeType (t1, t2: typePtr): typePtr; { Make the composite type of two compatible types. } { See C17 section 6.2.7. } { } { parameters: } { t1,t2 - the input types (must be compatible) } { } { returns: pointer to the composite type } function MakeQualifiedType (origType: typePtr; qualifiers: typeQualifierSet): typePtr; { make a qualified version of a type } { } { parameters: } { origType - the original type } { qualifiers - the type qualifier(s) to add } { } { returns: pointer to the qualified type } function Unqualify (tp: typePtr): typePtr; { returns the unqualified version of a type } { } { parameters: } { tp - the original type } { } { returns: pointer to the unqualified type } function NewSymbol (name: stringPtr; itype: typePtr; class: tokenEnum; space: spaceType; state: stateKind; isInline: boolean): identPtr; { insert a new symbol in the symbol table } { } { parameters: } { name - pointer to the symbol name } { itype - pointer to the symbol type } { class - storage class } { space - the kind of variable space to put the } { identifier in } { state - variable declaration state } { } { returns: pointer to the inserted symbol } procedure PopTable; { Pop a symbol table (remove definitions local to a block) } {procedure PrintOneSymbol (ip: identPtr); {debug} { Print a symbol } { } { Parameters: } { ip - identifier to print } {procedure PrintTable (sym: symbolTablePtr); {debug} { print a symbol table } { } { parameters: } { sym - symbol table to print } procedure PushTable; { Create a new symbol table, pushing the old one } procedure ResolveForwardReference (iPtr: identPtr); { resolve a forward reference } { } { parameters: } { iPtr - ptr to the forward declared identifier } function StringType(prefix: charStrPrefixEnum): typePtr; { returns the type of a string literal with specified prefix } { } { parameters: } { prefix - the prefix } {---------------------------------------------------------------} implementation type {From CGC.pas} realrec = record {used to convert from real to in-SANE} itsReal: extended; inCOMP: packed array[1..8] of byte; end; var staticNum: packed array[1..6] of char; {static variable number} tablePool: symbolTablePtr; {pool of reusable empty symbol tables} tablePoolSize: 0..maxint; {number of tables in pool} tablePoolMaxSize: 0..maxint; {max number of tables in pool} {- Imported from CGC.pas ---------------------------------------} procedure CnvSC (rec: realrec); extern; { convert a real number to SANE comp format } { } { parameters: } { rec - record containing the value to convert; also } { has space for the result } {---------------------------------------------------------------} procedure CnOut (i: integer); extern; { write a byte to the constant buffer } { } { parameters: } { i - byte to write } procedure CnOut2 (i: integer); extern; { write a word to the constant buffer } { } { parameters: } { i - word to write } procedure Out (b: integer); extern; { write a byte to the output file } { } { parameters: } { b - byte to write } procedure Out2 (w: integer); extern; { write a word to the output file } { } { parameters: } { w - word to write } procedure RefName (lab: stringPtr; disp, len, shift: integer); extern; { handle a reference to a named label } { } { parameters: } { lab - label name } { disp - displacement past the label } { len - number of bytes in the reference } { shift - shift factor } procedure LabelSearch (lab: integer; len, shift, disp: integer); extern; { resolve a label reference } { } { parameters: } { lab - label number } { len - # bytes for the generated code } { shift - shift factor } { disp - disp past the label } { } { Note 1: maxlabel is reserved for use as the start of the } { string space } { Note 2: negative length indicates relative branch } { Note 3: zero length indicates 2 byte addr -1 } procedure Purge; extern; { write any constant bytes to the output buffer } {- Imported from IIGS Memory Manager ---------------------------} function MaxBlock: longint; tool ($02, $1C); {---------------------------------------------------------------} procedure ClearTable (table: symbolTable); extern; { clear the symbol table to all zeros } procedure SaveBF (addr: ptr; bitdisp, bitsize: integer; val: longint); extern; { save a value to a bit-field } { } { parameters: } { addr - address to copy to } { bitdisp - displacement past the address } { bitsize - number of bits } { val - value to copy } {---------------------------------------------------------------} procedure CheckStaticFunctions; { check for undefined functions } var i: 0..hashSize; {loop variable} sp: identPtr; {pointer to a symbol table entry} msg: stringPtr; {error message ptr} begin {CheckStaticFunctions} for i := 0 to hashSize do begin sp := globalTable^.buckets[i]; while sp <> nil do begin if sp^.storage = private then if sp^.itype^.kind = functionType then if sp^.state <> defined then if sp^.used then begin numErrors := numErrors+1; new(msg); msg^ := concat('The static function ', sp^.name^, ' was used but never defined.'); writeln('*** ', msg^); if terminalErrors then begin if enterEditor then ExitToEditor(msg, ord4(firstPtr)-ord4(bofPtr)) else TermError(0); end; {if} liDCBGS.merrf := 16; end; {if} sp := sp^.next; end; {while} end; {for} end; {CheckStaticFunctions} procedure CheckUnused {tPtr: symbolTablePtr}; { check for unused variables in symbol table } var i: integer; {loop variable} ip: identPtr; {current symbol} nameStr: stringPtr; begin {CheckUnused} if not tPtr^.isEmpty or not tPtr^.noStatics then for i := 0 to hashSize do begin {loop over all hash buckets} if not tPtr^.isEmpty then begin ip := tPtr^.buckets[i]; {trace through non-static symbols} while ip <> nil do begin if not ip^.used then if ip^.itype <> nil then if not (ip^.itype^.kind in [functionType,enumConst]) then if ip^.storage in [stackFrame,private] then if not (ip^.name^[1] in ['~','@']) then begin new(nameStr); nameStr^ := ip^.name^; ErrorWithExtraString(185, nameStr); end; {if} ip := ip^.next; end; {while} end; {if} if not tPtr^.noStatics then begin ip := globalTable^.buckets[i]; {trace through static symbols} while ip <> nil do begin if not ip^.used then if ip^.itype <> nil then if not (ip^.itype^.kind in [functionType,enumConst]) then if ip^.storage = private then if copy(ip^.name^,1,staticNumLen) = tPtr^.staticNum then if not (ip^.name^[staticNumLen+1] in ['~','@']) then begin new(nameStr); nameStr^ := copy(ip^.name^, staticNumLen+1, maxint); ErrorWithExtraString(185, nameStr); end; {if} ip := ip^.next; end; {while} end; {if} end; {for} end; {CheckUnused} function CompTypes {t1, t2: typePtr): boolean}; { Determine if the two types are compatible } label 1; var el1,el2: longint; {array sizes} kind1,kind2: typeKind; {temp variables (for speed)} begin {CompTypes} CompTypes := false; {assume the types are not compatible} kind1 := t1^.kind; {get these for efficiency} kind2 := t2^.kind; if kind2 = definedType then {scan past type definitions} CompTypes := CompTypes(t1, t2^.dType) else if kind1 = definedType then CompTypes := CompTypes(t1^.dType, t2) else case kind1 of scalarType: if kind2 = scalarType then begin CompTypes := t1^.baseType = t2^.baseType; if t1^.cType <> t2^.cType then if (not looseTypeChecks) or (t1^.cType = ctBool) or (t2^.cType = ctBool) then CompTypes := false; end {if} else if kind2 = enumType then CompTypes := (t1^.baseType = cgWord) and (t1^.cType = ctInt); arrayType: if kind2 = arrayType then begin el1 := t1^.elements; el2 := t2^.elements; if el1 = 0 then el1 := el2 else if el2 = 0 then el2 := el1; if el1 = el2 then CompTypes := CompTypes(t1^.atype, t2^.atype); end; {if} functionType: if kind2 = functionType then begin if looseTypeChecks or (t1^.prototyped <> t2^.prototyped) then CompTypes := CompTypes(t1^.ftype,t2^.ftype) else CompTypes := StrictCompTypes(t1, t2); end {if} else if kind2 = pointerType then if t2^.ptype^.kind = functionType then CompTypes := CompTypes(t1, t2^.ptype); pointerType: begin if IsVoid(t1^.ptype) or IsVoid(t2^.ptype) then begin CompTypes := true; goto 1; end; {if} if kind2 = pointertype then CompTypes := CompTypes(t1^.ptype, t2^.ptype) else if kind2 = functionType then CompTypes := CompTypes(t1^.ptype, t2); end; enumType: if kind2 = scalarType then CompTypes := (t2^.baseType = cgWord) and (t2^.cType = ctInt) else if kind2 = enumType then CompTypes := true; structType,unionType: CompTypes := t1 = t2; otherwise: ; end; {case t1^.kind} 1: end; {CompTypes} function StrictCompTypes {t1, t2: typePtr): boolean}; { Determine if the two types are compatible, strictly following } { C standard rules. } label 1; var el1,el2: longint; {array sizes} kind1,kind2: typeKind; {temp variables (for speed)} p1, p2: parameterPtr; {for tracing parameter lists} tp1,tp2: typeRecord; {temporary types used in comparison} begin {StrictCompTypes} if t1 = t2 then begin {shortcut} StrictCompTypes := true; goto 1; end; {if} StrictCompTypes := false; {assume the types are not compatible} if t1^.qualifiers <> t2^.qualifiers then {qualifiers must be the same} goto 1; while t1^.kind = definedType do {scan past type definitions} t1 := t1^.dType; while t2^.kind = definedType do t2 := t2^.dType; kind1 := t1^.kind; {get these for efficiency} kind2 := t2^.kind; case kind1 of scalarType: if kind2 = scalarType then begin StrictCompTypes := (t1^.baseType = t2^.baseType) and (t1^.cType = t2^.cType); end {if} else if kind2 = enumType then StrictCompTypes := (t1^.baseType = cgWord) and (t1^.cType = ctInt); arrayType: if kind2 = arrayType then begin el1 := t1^.elements; el2 := t2^.elements; if el1 = 0 then el1 := el2 else if el2 = 0 then el2 := el1; if el1 = el2 then StrictCompTypes := StrictCompTypes(t1^.atype, t2^.atype); end; {if} functionType: if kind2 = functionType then begin if not StrictCompTypes(t1^.ftype, t2^.ftype) then goto 1; if t1^.varargs <> t2^.varargs then goto 1; if t1^.prototyped and t2^.prototyped then begin p1 := t1^.parameterList; p2 := t2^.parameterList; while (p1 <> nil) and (p2 <> nil) do begin tp1 := p1^.parameterType^; tp2 := p2^.parameterType^; if p1^.parameterType = p2^.parameterType then {these parameters are compatible} else begin tp1.qualifiers := []; tp2.qualifiers := []; if tp1.kind = arrayType then tp1.kind := pointerType else if tp1.kind = functionType then begin tp1.size := cgPointerSize; tp1.qualifiers := []; tp1.saveDisp := 0; tp1.kind := pointerType; tp1.pType := p1^.parameterType; end; {else if} if tp2.kind = arrayType then tp2.kind := pointerType else if tp2.kind = functionType then begin tp2.size := cgPointerSize; tp2.qualifiers := []; tp2.saveDisp := 0; tp2.kind := pointerType; tp2.pType := p2^.parameterType; end; {else if} if not StrictCompTypes(@tp1, @tp2) then goto 1; end; {else} p1 := p1^.next; p2 := p2^.next; end; {while} if p1 <> p2 then goto 1; end {if} else if t1^.prototyped then begin p1 := t1^.parameterList; while p1 <> nil do begin if p1^.parameterType^.kind = scalarType then if p1^.parameterType^.cType in [ctChar,ctSChar,ctUChar, ctShort,ctUShort,ctFloat,ctBool] then goto 1; p1 := p1^.next; end; {while} end {else if} else if t2^.prototyped then begin p2 := t2^.parameterList; while p2 <> nil do begin if p2^.parameterType^.kind = scalarType then if p2^.parameterType^.cType in [ctChar,ctSChar,ctUChar, ctShort,ctUShort,ctFloat,ctBool] then goto 1; p2 := p2^.next; end; {while} end; {else if} StrictCompTypes := true; end; {if} pointerType: if kind2 = pointertype then StrictCompTypes := StrictCompTypes(t1^.ptype, t2^.ptype); enumType: if kind2 = scalarType then StrictCompTypes := (t2^.baseType = cgWord) and (t2^.cType = ctInt) else if kind2 = enumType then StrictCompTypes := true; structType,unionType: StrictCompTypes := t1 = t2; otherwise: ; end; {case} 1: end; {StrictCompTypes} procedure DoGlobals; { declare the ~globals and ~arrays segments } procedure FreeTablePool; { free the symbol table pool } var tPtr: symbolTablePtr; begin {FreeTablePool} while tablePool <> nil do begin tPtr := tablePool; tablePool := tPtr^.next; dispose(tPtr); end; end; {FreeTablePool} procedure StaticInit (variable: identPtr); { statically initialize a variable } type {record of pointer initializers} relocPtr = ^relocationRecord; relocationRecord = record next: relocPtr; {next record} initializer: initializerPtr; {the initializer} disp: longint; {disp in overall data structure} end; {pointers to each type} bytePtr = ^byte; wordPtr = ^integer; longPtr = ^longint; quadPtr = ^longlong; realPtr = ^real; doublePtr = ^double; extendedPtr = ^extended; var buffPtr: ptr; {pointer to data buffer} count: integer; {# of duplicate records} disp: longint; {disp into buffer (for output)} endDisp: longint; {ending disp for current chunk} i: integer; {loop counter} ip: initializerPtr; {used to trace initializer lists} lastReloc, nextReloc: relocPtr; {for reversing relocs list} realVal: realRec; {used for extended-to-comp conversion} relocs: relocPtr; {list of records needing relocation} {pointers used to write data} bp: bytePtr; wp: wordPtr; lp: longPtr; qp: quadPtr; rp: realPtr; dp: doublePtr; ep: extendedPtr; procedure UpdateRelocs; { update relocation records to account for an initializer } var disp: longint; {disp of current initializer} done: boolean; {done with loop?} endDisp: longint; {disp at end of current initializer} last: ^relocPtr; {the pointer referring to rp} rp: relocPtr; {reloc record being processed} begin {UpdateRelocs} disp := ip^.disp; if ip^.bitsize <> 0 then begin endDisp := disp + (ip^.bitdisp + ip^.bitsize + 7) div 8; disp := disp + ip^.bitdisp div 8; end {if} else if ip^.basetype = cgString then endDisp := disp + ip^.sVal^.length else endDisp := disp + TypeSize(ip^.baseType); last := @relocs; rp := relocs; done := false; while (rp <> nil) and not done do begin if rp^.disp + cgPointerSize <= disp then begin {initializer is entirely after this reloc: no conflicts} done := true; end {if} else if endDisp <= rp^.disp then begin {initializer is entirely before this reloc} last := @rp^.next; rp := rp^.next; end {else if} else begin {conflict: remove the conflicting reloc record} last^ := rp^.next; lp := pointer(ord4(buffPtr) + rp^.disp); lp^ := 0; dispose(rp); rp := last^; end; {else} end; {while} if ip^.basetype = ccPointer then begin new(rp); rp^.next := last^; last^ := rp; rp^.disp := ip^.disp; rp^.initializer := ip; end; {if} end; {UpdateRelocs} begin {StaticInit} {allocate buffer} {(+3 for possible bitfield overhang)} buffPtr := GLongMalloc(variable^.itype^.size+3); relocs := nil; {evaluate initializers} ip := variable^.iPtr; while ip <> nil do begin count := 0; while count < ip^.count do begin UpdateRelocs; if ip^.bitsize <> 0 then begin bp := pointer(ord4(buffPtr) + ip^.disp + count); SaveBF(bp, ip^.bitdisp, ip^.bitsize, ip^.iVal); end {if} else case ip^.basetype of cgByte,cgUByte: begin bp := pointer(ord4(buffPtr) + ip^.disp + count); bp^ := ord(ip^.iVal) & $ff; end; cgWord,cgUWord: begin wp := pointer(ord4(buffPtr) + ip^.disp + count); wp^ := ord(ip^.iVal); end; cgLong,cgULong: begin lp := pointer(ord4(buffPtr) + ip^.disp + count); lp^ := ip^.iVal; end; cgQuad,cgUQuad: begin qp := pointer(ord4(buffPtr) + ip^.disp + count); qp^ := ip^.qVal; end; cgReal: begin rp := pointer(ord4(buffPtr) + ip^.disp + count); rp^ := ip^.rVal; end; cgDouble: begin dp := pointer(ord4(buffPtr) + ip^.disp + count); dp^ := ip^.rVal; end; cgExtended: begin ep := pointer(ord4(buffPtr) + ip^.disp + count); ep^ := ip^.rVal; end; cgComp: begin realVal.itsReal := ip^.rVal; CnvSC(realVal); for i := 1 to 8 do begin bp := pointer(ord4(buffPtr) + ip^.disp + count + i-1); bp^ := realVal.inCOMP[i]; end; {for} end; cgString: begin for i := 1 to ip^.sVal^.length do begin bp := pointer(ord4(buffPtr) + ip^.disp + count + i-1); bp^ := ord(ip^.sVal^.str[i]); end; {for} end; ccPointer: ; {handled by UpdateRelocs} cgVoid: Error(57); end; {case} count := count + 1; {assumes count > 1 only for bytes} end; {while} ip := ip^.next; end; {while} lastReloc := nil; {reverse the relocs list} while relocs <> nil do begin nextReloc := relocs^.next; relocs^.next := lastReloc; lastReloc := relocs; relocs := nextReloc; end; {while} relocs := lastReloc; disp := 0; {generate the initialization data} while disp < variable^.itype^.size do begin if relocs = nil then endDisp := variable^.itype^.size else endDisp := relocs^.disp; if disp <> endDisp then begin GenBS(dc_cns, pointer(ord4(buffPtr) + disp), endDisp - disp); disp := endDisp; end; {if} if relocs <> nil then begin code^.optype := ccPointer; code^.r := ord(relocs^.initializer^.pPlus); code^.q := 1; code^.pVal := relocs^.initializer^.pVal; if relocs^.initializer^.isName then begin code^.lab := relocs^.initializer^.pName; code^.pstr := nil; end {if} else code^.pstr := relocs^.initializer^.pstr; Gen0(dc_cns); lastReloc := relocs; relocs := relocs^.next; dispose(lastReloc); disp := disp + cgPointerSize; end; {if} end; {while} end; {StaticInit} procedure GenArrays; { define global arrays } var didOne: boolean; {have we found an array yet?} i: 0..hashSize; {loop variable} ip: initializerPtr; {used to trace initializer lists} lval: longint; {for converting types} size: longint; {size of the array} sp: identPtr; {pointer to a symbol table entry} tPtr: typePtr; {type of global array/struct/union} msg: stringPtr; {error message ptr} begin {GenArrays} didOne := false; for i := 0 to hashSize do begin sp := table^.buckets[i]; while sp <> nil do begin if sp^.storage in [global,private] then begin tPtr := sp^.itype; while tPtr^.kind = definedType do tPtr := tPtr^.dType; if tPtr^.kind in [arrayType,structType,unionType] then begin if not didOne then begin if smallMemoryModel then currentSegment := ' ' else currentSegment := '~ARRAYS '; segmentKind := 0; {this segment is not dynamic!} Gen2Name(dc_str, $4000, 1, @'~ARRAYS'); didOne := true; end; {if} if sp^.state = initialized then begin Gen2Name(dc_glb, 0, ord(sp^.storage = private), sp^.name); StaticInit(sp); end {if} else begin size := sp^.itype^.size; if size = 0 then begin if sp^.itype^.kind = arrayType then begin {implicitly initialize with one element} size := sp^.itype^.aType^.size; end {if} else begin numErrors := numErrors+1; new(msg); msg^ := concat('The struct or union ''', sp^.name^, ''' has incomplete type that was never completed.'); writeln('*** ', msg^); if terminalErrors then begin if enterEditor then ExitToEditor(msg, ord4(firstPtr)-ord4(bofPtr)) else TermError(0); end; {if} liDCBGS.merrf := 16; end; {else} end; {if} Gen2Name(dc_glb, long(size).lsw & $7FFF, ord(sp^.storage = private), sp^.name); size := size & $FFFF8000; while size <> 0 do begin Gen1(dc_dst, 16384); size := size-16384; end; {while} end; {else} end; {if} end; {if} sp := sp^.next; end; {while} end; {for} if didOne then Gen0(dc_enp); end; {GenArrays} procedure GenGlobals; { define non-array global variables } var i: 0..hashSize; {loop variable} ip: initializerPtr; {used to trace initializer lists} lval: longint; {for extracting lsw} sp: identPtr; {pointer to a symbol table entry} begin {GenGlobals} Gen2t(dc_cns, 0, 1, cgByte); for i := 0 to hashSize do begin sp := table^.buckets[i]; while sp <> nil do begin if sp^.storage in [global,private] then if sp^.itype^.kind in [scalarType,pointerType] then begin if sp^.state = initialized then begin Gen2Name(dc_glb, 0, ord(sp^.storage = private), sp^.name); ip := sp^.iPtr; case ip^.basetype of cgByte,cgUByte,cgWord,cgUWord: begin lval := ip^.ival; Gen2t(dc_cns, long(lval).lsw, 1, ip^.basetype); end; cgLong,cgULong: GenL1(dc_cns, ip^.ival, 1); cgQuad,cgUQuad: GenQ1(dc_cns, ip^.qval, 1); cgReal,cgDouble,cgComp,cgExtended: GenR1t(dc_cns, ip^.rval, 1, ip^.basetype); cgString: GenS(dc_cns, ip^.sval); ccPointer: begin code^.optype := ccPointer; code^.q := 1; code^.r := ord(ip^.pPlus); code^.pVal := ip^.pVal; if ip^.isName then begin code^.lab := ip^.pName; code^.pstr := nil; end {if} else code^.pstr := ip^.pstr; Gen0(dc_cns); end; otherwise: Error(57); end; {case} end {if} {else if sp^.itype^.size = 0 then begin Error(57); end {else if} else Gen2Name(dc_glb, ord(sp^.itype^.size), ord(sp^.storage = private), sp^.name); end; sp := sp^.next; end; {while} end; {for} end; {GenGlobals} begin {DoGlobals} {print the global symbol table} {if printSymbols then {debug} { PrintTable(globalTable); {debug} FreeTablePool; {dispose of unneeded symbol tables} {declare the ~globals segment, which holds non-array data types} if smallMemoryModel then currentSegment := ' ' else currentSegment := '~GLOBALS '; segmentKind := 0; {this segment is not dynamic!} Gen2Name(dc_str, $4000, 0, @'~GLOBALS'); GenGlobals; Gen0(dc_enp); {declare the ~arrays segment, which holds global arrays} GenArrays; end; {DoGlobals} function FindSymbol {var tk: tokenType; class: spaceType; oneLevel: boolean; staticAllowed: boolean): identPtr}; { locate a symbol in the symbol table } { } { parameters: } { tk - token record for the identifier to find } { class - the kind of variable space to search } { oneLevel - search one level only? (used to check for } { duplicate symbols) } { staticAllowed - can we check for static variables? } { } { returns: } { A pointer to the symbol table entry is returned. If } { there is no entry, nil is returned. } label 1,2; var hashDisp: longint; {disp into the hash table} i: integer; {loop variable} iHandle: ^identPtr; {pointer to start of hash bucket} iPtr: identPtr; {pointer to the current symbol} name: stringPtr; {name to search for} np: stringPtr; {for searching for static variables} sPtr: symbolTablePtr; {^ to current symbol table} begin {FindSymbol} {get ready to search} staticAllowed := staticAllowed and (staticNum <> '~0000'); name := tk.name; {use a local variable} hashDisp := Hash(name); {get the disp into the symbol table} np := nil; {no string buffer, yet} {check for the variable} 2: sPtr := table; {initialize the address of the sym. tbl} while sPtr <> nil do begin iHandle := pointer(hashDisp+ord4(sPtr)); if class = tagSpace then iHandle := pointer(ord4(iHandle) + (hashSize+1)*4); iPtr := iHandle^; {scan the hash bucket for a global or auto variable} while iPtr <> nil do begin if iPtr^.name^ = name^ then begin FindSymbol := iPtr; if iPtr^.isForwardDeclared then ResolveForwardReference(iPtr); tk.symbolPtr := iPtr; goto 1; end; {if} iPtr := iPtr^.next; end; {while} {rescan for a static variable} if staticAllowed and not sPtr^.noStatics then begin if np = nil then begin {form the static name} if length(name^) < 251 then begin new(np); np^[0] := chr(5+length(name^)); for i := 1 to 5 do np^[i] := sPtr^.staticNum[i]; for i := 1 to length(name^) do np^[i+5] := name^[i]; end; {if} end {if} else for i := 2 to 5 do np^[i] := sPtr^.StaticNum[i]; {scan the hash bucket for the identifier} iHandle := pointer(hashDisp+ord4(globalTable)); if class = tagSpace then iHandle := pointer(ord4(iHandle) + (hashSize+1)*4); iPtr := iHandle^; while iPtr <> nil do begin if iPtr^.name^ = np^ then begin FindSymbol := iPtr; if iPtr^.isForwardDeclared then ResolveForwardReference(iPtr); tk.symbolPtr := iPtr; goto 1; end; {if} iPtr := iPtr^.next; end; {while} end; {if staticAllowed} if oneLevel then sPtr := nil else sPtr := sPtr^.next; end; {while} {we only get here if a symbol was not found} if class = allSpaces then begin class := tagSpace; goto 2; end; {if} FindSymbol := nil; 1: if np <> nil then dispose(np); end; {FindSymbol} procedure GenParameters {pp: parameterPtr}; { Generate labels and space for the parameters } { } { parameters: } { pp - pointer to first parameter } { } { variables: } { lastParameterLLN - label number of last parameter } { lastParameterSize - size of last parameter } var i: 0..hashSize; {loop variable} pln: integer; {label number} size: integer; {size of the parameter} sp: identPtr; {symbol pointer} tk: tokenType; {symbol name token} first: boolean; {first iteration of loop over params?} begin {GenParameters} first := true; if pp <> nil then begin {prototyped parameters} tk.kind := ident; tk.numString := nil; tk.class := identifier; while pp <> nil do begin pln := GetLocalLabel; tk.name := pp^.parameter^.name; tk.symbolPtr := nil; sp := FindSymbol(tk, variableSpace, true, false); if sp = nil then sp := pp^.parameter; if sp^.itype^.kind = arrayType then begin size := cgPointerSize; Gen3(dc_prm, pln, cgPointerSize, sp^.pdisp); end {if} else begin size := long(sp^.itype^.size).lsw; if (size = 1) and (sp^.itype^.kind = scalarType) then size := 2; if sp^.itype^.kind = scalarType then if sp^.itype^.baseType in [cgReal,cgDouble,cgComp] then begin {convert floating-point parameters to declared type} Gen1t(pc_fix, pln, sp^.itype^.baseType); size := cgExtendedSize; end; {if} Gen3(dc_prm, pln, size, sp^.pdisp); end; {else} sp^.pln := pln; if first then begin first := false; lastParameterLLN := pln; lastParameterSize := size; end; {if} pp := pp^.next; end; {while} end {if} else begin {K&R parameters} for i := 0 to hashSize do begin sp := table^.buckets[i]; while sp <> nil do begin if sp^.storage = parameter then begin pln := GetLocalLabel; sp^.pln := pln; if sp^.itype^.kind = arrayType then begin size := cgPointerSize; Gen3(dc_prm, sp^.lln, cgPointerSize, sp^.pdisp); end {if} else begin size := long(sp^.itype^.size).lsw; if (size = 1) and (sp^.itype^.kind = scalarType) then size := 2; if sp^.itype^.kind = scalarType then if sp^.itype^.baseType in [cgReal,cgDouble,cgComp] then begin {convert floating-point parameters to declared type} Gen1t(pc_fix, pln, sp^.itype^.baseType); size := cgExtendedSize; end; {if} Gen3(dc_prm, sp^.lln, size, sp^.pdisp); end; {else} if first then begin first := false; lastParameterLLN := pln; lastParameterSize := size; end; {if} end; {if} sp := sp^.next; end; {while} end; {for} if first then begin lastParameterLLN := 0; lastParameterSize := 0; end; {if} end; {else} end; {GenParameters} procedure GenSymbols {sym: symbolTablePtr; doGlobals: boolean}; { generate a symbol table for the debugger } { } { parameters: } { sym - symbol table to generate } { doGlobals - include global symbols in the table } { } { outputs: } { symLength - length of debug symbol table } const noDisp = -1; {disp returned by GetTypeDisp if the type was not found} type tpPtr = ^tpRecord; {type list displacements} tpRecord = record next: tpPtr; tp: typePtr; disp: integer; end; var i: 0..hashSize; {loop/index variable} ip: identPtr; {used to trace identifier lists} tpList,tp2: tpPtr; {type displacement list} function GetTypeDisp (tp: typePtr): integer; { Look for an existing entry for this type } { } { Parameters: } { tp - type to look for } { } { Returns: Disp to a variable of the same type, or noDisp if } { there is no such entry. } { } { Notes: If the type is not in the type list, it is entered } { in the list by this call. } var tp1, tp2: tpPtr; {used to manipulate type list} begin {GetTypeDisp} tp1 := tpList; {look for the type} tp2 := nil; while tp1 <> nil do if tp1^.tp = tp then begin tp2 := tp1; tp1 := nil; end {if} else tp1 := tp1^.next; if tp2 <> nil then GetTypeDisp := tp2^.disp {return disp to entry} else begin GetTypeDisp := noDisp; {no entry} new(tp1); {create a new entry} tp1^.next := tpList; tpList := tp1; tp1^.tp := tp; tp1^.disp := symLength-12; end; {else} end; {GetTypeDisp} procedure GenSymbol (ip: identPtr; storage: storageType); { Generate a single symbol or struct field } { } { parameters: } { ip - identifier to generate } { storage - storage type; none for struct/union fields } var disp: integer; {disp to symbol of same type} tPtr: typePtr; procedure WriteAddress (ip: identPtr); { Write the address and DP flag } { } { parameters: } { ip - identifier } var size: longint; {used to break apart longints} begin {WriteAddress} if storage in [external,global,private] then begin RefName(ip^.name, 0, 4, 0); CnOut(1); end {if} else if storage = none then begin size := ip^.disp; CnOut2(long(size).lsw); CnOut2(long(size).msw); CnOut(ord(ip^.next <> nil)); end {else if} else begin CnOut2(LabelToDisp(ip^.lln)); CnOut2(0); CnOut(0); end; {else} end; {WriteAddress} procedure WriteName (ip: identPtr); { Write the name field for an identifier } { } { parameters: } { ip - identifier } var len: 0..maxint; {string length} j: 0..maxint; {loop/index variable} begin {WriteName} Purge; {generate the address of the variable } Out(235); Out(4); { name } LabelSearch(maxLabel, 4, 0, 0); if stringsize <> 0 then begin Out(129); Out2(stringsize); Out2(0); Out(1); end; {if} Out(0); len := length(ip^.name^); {place the name in the string buffer} if maxstring-stringsize >= len+1 then begin stringspace^[stringsize+1] := chr(len); for j := 1 to len do stringspace^[j+stringsize+1] := ip^.name^[j]; stringsize := stringsize+len+1; end {if} else Error(60); end; {WriteName} procedure WriteScalarType (tp: typePtr; modifiers, subscripts: integer); { Write a scalar type and subscript field } { } { parameters: } { tp - type pointer } { modifiers - value to or with the type code } { subscripts - number of subscripts } var val: integer; {type value} begin {WriteScalarType} case tp^.baseType of cgByte: val := $40; cgUByte: val := $00; cgWord: if tp^.cType = ctBool then val := $09 else val := $01; cgUWord: val := $41; cgLong: val := $02; cgULong: val := $42; cgReal: val := $03; cgDouble: val := $04; cgComp: val := $0A; cgExtended: val := $05; cgQuad: val := $0A; {same as comp} cgUQuad: val := $4A; otherwise: val := $01; end; {case} CnOut(val | modifiers); {write the format byte} CnOut2(subscripts); {write the # of subscripts} end; {WriteScalarType} procedure WritePointerType (tp: typePtr; subscripts: integer); { write a pointer type field } { } { parameters: } { tp - pointer type } { subscripts - number of subscript fields } begin {WritePointerType} tp := tp^.ptype; while tp^.kind = definedType do tp := tp^.dType; case tp^.kind of scalarType: WriteScalarType(tp, $80, subscripts); enumType, functionType: WriteScalarType(intPtr, $80, subscripts); otherwise: begin CnOut(11); CnOut2(subscripts); end; end; {case} end; {WritePointerType} procedure ExpandPointerType (tp: typePtr); forward; procedure ExpandStructType (tp: typePtr); { write the type entries for a struct or union } { } { parameters: } { tp - struct/union type } var ip: identPtr; {used to trace the field list} begin {ExpandStructType} ip := tp^.fieldList; { fieldList is nil if this is a forward declared struct. } if ip = nil then ip := defaultStruct^.fieldList; while ip <> nil do begin if ip^.name^[1] <> '~' then GenSymbol(ip, none); ip := ip^.next; end; {while} end; {ExpandStructType} procedure WriteArrays (tp: typePtr); { handle an array type } { } { parameters: } { tp - array type } var count: 0..maxint; {# of subscripts} size: longint; {for converting long numbers} tp2: typePtr; {used to trace array type list} begin {WriteArrays} count := 0; {count the subscripts} tp2 := tp; while tp2^.kind = arrayType do begin count := count+1; tp2 := tp2^.aType; end; {while} while tp2^.kind = definedType do tp2 := tp2^.dType; if tp2^.kind = scalarType then {write the type code} if tp2^.baseType in [cgByte,cgUByte] then begin count := count-1; CnOut(6); CnOut2(count); end {if} else WriteScalarType(tp2, 0, count) else if tp2^.kind = enumType then WriteScalarType(intPtr, 0, count) else if tp2^.kind = pointerType then WritePointerType(tp2, count) else begin CnOut(12); CnOut2(count); end; {else if} while count <> 0 do begin {write the subscript entries} CnOut2(0); CnOut2(0); if tp^.elements = 0 then size := $00FFFFFF else size := tp^.elements-1; CnOut2(long(size).lsw); CnOut2(long(size).msw); size := tp^.aType^.size; CnOut2(long(size).lsw); CnOut2(long(size).msw); symLength := symLength+12; tp := tp^.aType; count := count-1; end; {while} if tp2^.kind = pointerType then {expand complex types} ExpandPointerType(tp2) else if tp2^.kind in [structtype,uniontype] then ExpandStructType(tp2); end; {WriteArrays} procedure ExpandPointerType {tp: typePtr}; { write the type entries for complex pointer types } { } { parameters: } { tp - pointer type } var disp: integer; {disp to symbol of same type} begin {ExpandPointerType} tp := tp^.ptype; while tp^.kind = definedType do tp := tp^.dType; if tp^.kind in [pointerType,arrayType,structType,unionType] then begin symLength := symLength+12; CnOut2(0); CnOut2(0); CnOut2(0); CnOut2(0); CnOut(0); case tp^.kind of pointerType: begin WritePointerType(tp, 0); ExpandPointerType(tp); end; arrayType: WriteArrays(tp); structType, unionType: begin disp := GetTypeDisp(tp); if disp = noDisp then begin CnOut(12); CnOut2(0); ExpandStructType(tp); end {if} else begin CnOut(13); CnOut2(disp); end; {else} end; end; {case} end; {if} end; {ExpandPointerType} begin {GenSymbol} tPtr := ip^.itype; while tPtr^.kind = definedType do tPtr := tPtr^.dType; if tPtr^.kind in [scalarType,arrayType,pointerType,enumType,structType,unionType] then begin symLength := symLength+12; {update length of symbol table} WriteName(ip); {write the name field} WriteAddress(ip); {write the address field} case tPtr^.kind of scalarType: WriteScalarType(tPtr, 0, 0); enumType: WriteScalarType(intPtr, 0, 0); pointerType: begin WritePointerType(tPtr, 0); ExpandPointerType(tPtr); end; arrayType: WriteArrays(tPtr); structType, unionType: begin disp := GetTypeDisp(tPtr); if disp = noDisp then begin CnOut(12); CnOut2(0); ExpandStructType(tPtr); end {if} else begin CnOut(13); CnOut2(disp); end; {else} end; end; {case} end; {if} end; {GenSymbol} begin {GenSymbols} tpList := nil; {no types so far} if sym <> nil then for i := 0 to hashSize do begin {loop over all hash buckets} ip := sym^.buckets[i]; {trace through all symbols in this bucket} while ip <> nil do begin if ip^.storage <> none then GenSymbol(ip, ip^.storage); ip := ip^.next; {next symbol} end; {while} end; {for} while tpList <> nil do begin {dispose of type list} tp2 := tpList; tpList := tp2^.next; dispose(tp2); end; {while} if doGlobals then {do globals} GenSymbols(globalTable, false); end; {GenSymbols} procedure InitSymbol; { Initialize the symbol table module } var i: 0..hashSize; {loop variable} begin {InitSymbol} staticNum := '~0000'; {no functions processed} table := nil; {initialize the global symbol table} tablePool := nil; {table pool is initially empty} tablePoolSize := 0; tablePoolMaxSize := ord(MaxBlock div 150000); {limit size of pool based on RAM} PushTable; globalTable := table; globalTable^.isEmpty := false; {global table is never treated as empty} functionTable := nil; {declare base types} new(sCharPtr); {signed char} with sCharPtr^ do begin size := cgByteSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgByte; cType := ctSChar; end; {with} new(charPtr); {char} with charPtr^ do begin size := cgByteSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgUByte; cType := ctChar; end; {with} new(uCharPtr); {unsigned char} with uCharPtr^ do begin size := cgByteSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgUByte; cType := ctUChar; end; {with} new(shortPtr); {short} with shortPtr^ do begin size := cgWordSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgWord; cType := ctShort; end; {with} new(uShortPtr); {unsigned short} with uShortPtr^ do begin size := cgWordSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgUWord; cType := ctUShort; end; {with} new(intPtr); {int} with intPtr^ do begin size := cgWordSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgWord; cType := ctInt; end; {with} new(uIntPtr); {unsigned int} with uIntPtr^ do begin size := cgWordSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgUWord; cType := ctUInt; end; {with} new(int32Ptr); {int (32-bit)} with int32Ptr^ do begin size := cgLongSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgLong; cType := ctInt32; end; {with} new(uInt32Ptr); {unsigned int (32-bit)} with uInt32Ptr^ do begin size := cgLongSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgULong; cType := ctUInt32; end; {with} new(longPtr); {long} with longPtr^ do begin size := cgLongSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgLong; cType := ctLong; end; {with} new(uLongPtr); {unsigned long} with uLongPtr^ do begin size := cgLongSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgULong; cType := ctULong; end; {with} new(longLongPtr); {long long} with longLongPtr^ do begin size := cgQuadSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgQuad; cType := ctLongLong; end; {with} new(uLongLongPtr); {unsigned long long} with uLongLongPtr^ do begin size := cgQuadSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgUQuad; cType := ctULongLong; end; {with} new(floatPtr); {real} with floatPtr^ do begin size := cgRealSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgReal; cType := ctFloat; end; {with} new(doublePtr); {double} with doublePtr^ do begin size := cgDoubleSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgDouble; cType := ctDouble; end; {with} new(compPtr); {comp} with compPtr^ do begin size := cgCompSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgComp; cType := ctComp; end; {with} new(extendedPtr); {extended, aka long double} with extendedPtr^ do begin size := cgExtendedSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgExtended; cType := ctLongDouble; end; {with} new(boolPtr); {_Bool} with boolPtr^ do begin size := cgWordSize; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgWord; cType := ctBool; end; {with} new(stringTypePtr); {string constant type} with stringTypePtr^ do begin size := 0; saveDisp := 0; qualifiers := []; kind := arrayType; aType := charPtr; elements := 0; end; {with} new(utf16StringTypePtr); {UTF-16 string constant type} with utf16StringTypePtr^ do begin size := 0; saveDisp := 0; qualifiers := []; kind := arrayType; aType := uShortPtr; elements := 0; end; {with} new(utf32StringTypePtr); {UTF-32 string constant type} with utf32StringTypePtr^ do begin size := 0; saveDisp := 0; qualifiers := []; kind := arrayType; aType := uLongPtr; elements := 0; end; {with} new(voidPtr); {void} with voidPtr^ do begin size := 0; saveDisp := 0; qualifiers := []; kind := scalarType; baseType := cgVoid; cType := ctVoid; end; {with} new(voidPtrPtr); {typeless pointer} with voidPtrPtr^ do begin size := cgPointerSize; saveDisp := 0; qualifiers := []; kind := pointerType; pType := voidPtr; end; {with} new(charPtrPtr); {char *} with charPtrPtr^ do begin size := cgPointerSize; saveDisp := 0; qualifiers := []; kind := pointerType; pType := charPtr; end; {with} new(vaInfoPtr); {internal varargs info type (char*[2])} with vaInfoPtr^ do begin size := cgPointerSize*2; saveDisp := 0; qualifiers := []; kind := arrayType; aType := charPtrPtr; elements := 2; end; {with} new(defaultStruct); {default structure} with defaultStruct^ do begin {(for structures with errors)} size := cgWordSize; saveDisp := 0; qualifiers := []; kind := structType; sName := nil; constMember := false; flexibleArrayMember := false; new(fieldList); with fieldlist^ do begin next := nil; name := @'field'; itype := intPtr; class := ident; state := declared; disp := 0; bitdisp := 0; end; {with} end; {with} new(constCharPtr); {const char} constCharPtr^ := charPtr^; constCharPtr^.qualifiers := [tqConst]; end; {InitSymbol} function IsVoid {tp: typePtr): boolean}; { Check to see if a type is void } { } { Parameters: } { tp - type to check } { } { Returns: True if the type is void, else false } begin {IsVoid} IsVoid := false; if tp = voidPtr then IsVoid := true else if tp^.kind = scalarType then if tp^.baseType = cgVoid then IsVoid := true; end; {IsVoid} function CopyType (tp: typePtr): typePtr; { Make a new copy of a type, so it can be modified. } { } { Parameters: } { tp - type to copy } { } { Returns: The new copy of the type } var tType: typePtr; {the new copy of the type} p1,p2: parameterPtr; {parameter ptrs for copying prototypes} pPtr: ^parameterPtr; {temp for copying prototypes} begin {CopyType} if tp^.kind in [structType,unionType] then Error(57); tType := pointer(Malloc(sizeof(typeRecord))); tType^ := tp^; {copy type record} tType^.saveDisp := 0; if tp^.kind = functionType then {copy prototype parameter list} if tp^.prototyped then begin p1 := tp^.parameterList; pPtr := @tType^.parameterList; while p1 <> nil do begin p2 := pointer(Malloc(sizeof(parameterRecord))); p2^ := p1^; pPtr^ := p2; pPtr := @p2^.next; p1 := p1^.next; end; {while} end; {if} CopyType := tType; end; {CopyType} function MakeCompositeType {t1, t2: typePtr): typePtr}; { Make the composite type of two compatible types. } { See C17 section 6.2.7. } { } { parameters: } { t1,t2 - the input types (should be compatible) } { } { returns: pointer to the composite type } var compType: typePtr; {the composite type} tType: typePtr; {temp type} p1,p2: parameterPtr; {parameter ptrs for handling prototypes} begin {MakeCompositeType} compType := t2; {default to t2} if t1 <> t2 then if t1^.kind = t2^.kind then begin if t2^.kind = functionType then {switch fn types if only t1 is prototyped} if not t2^.prototyped then if t1^.prototyped then begin compType := t1; t1 := t2; t2 := compType; end; {if} {apply recursively for derived types} if t2^.kind in [arrayType,pointerType,functionType] then begin tType := MakeCompositeType(t1^.aType,t2^.aType); if tType <> t2^.aType then begin compType := CopyType(compType); compType^.aType := tType; end; {if} end; {if} if t2^.kind = arrayType then {get array size from t1 if needed} if t2^.size = 0 then if t1^.size <> 0 then if t1^.aType^.size = t2^.aType^.size then begin if compType = t2 then compType := CopyType(t2); CompType^.size := t1^.size; CompType^.elements := t1^.elements; end; {if} if t2^.kind = functionType then {compose function parameter types} if t1^.prototyped and t2^.prototyped then begin if compType = t2 then compType := CopyType(t2); p1 := t1^.parameterList; p2 := compType^.parameterList; while (p1 <> nil) and (p2 <> nil) do begin p2^.parameterType := MakeCompositeType(p1^.parameterType,p2^.parameterType); p1 := p1^.next; p2 := p2^.next; end; {while} end; end; {if} MakeCompositeType := compType; end; {MakeCompositeType} function MakePascalType {origType: typePtr): typePtr}; { make a version of a type with the pascal qualifier applied } { } { parameters: } { origType - the original type } { } { returns: pointer to the pascal-qualified type } var pascalType: typePtr; {the modified type} tp,tp2: typePtr; {work pointers} p1,p2,p3: parameterPtr; {for reversing prototyped parameters} begin {MakePascalType} pascalType := pointer(Malloc(sizeof(typeRecord))); pascalType^ := origType^; MakePascalType := pascalType; tp := pascalType; while tp <> nil do case tp^.kind of arrayType, pointerType: begin tp2 := pointer(Malloc(sizeof(typeRecord))); tp2^ := tp^.pType^; tp^.pType := tp2; tp := tp2; end; functionType: begin if not tp^.isPascal then begin {reverse the parameter list} p1 := tp^.parameterList; if p1 <> nil then begin p2 := nil; while p1 <> nil do begin p3 := pointer(Malloc(sizeof(parameterRecord))); p3^ := p1^; p1 := p1^.next; p3^.next := p2; p2 := p3; end; {while} tp^.parameterList := p2; end; {if} tp^.isPascal := true; end; {if} tp := nil; end; otherwise: begin Error(94); MakePascalType := origType; tp := nil; end; end; {case} end; {MakePascalType} function MakePointerTo {pType: typePtr): typePtr}; { make a pointer type } { } { parameters: } { pType - the type pointed to } { } { returns: the pointer type } var tp: typePtr; {the pointer type} begin {MakePointerTo} tp := pointer(Malloc(sizeof(typeRecord))); tp^.size := cgPointerSize; tp^.saveDisp := 0; tp^.qualifiers := []; tp^.kind := pointerType; tp^.pType := pType; MakePointerTo := tp; end; {MakePointerTo} function MakeQualifiedType {origType: typePtr; qualifiers: typeQualifierSet): typePtr}; { make a qualified version of a type } { } { parameters: } { origType - the original type } { qualifiers - the type qualifier(s) to add } { } { returns: pointer to the qualified type } var tp: typePtr; {the qualified type} elemType: typePtr; {array element type} begin {MakeQualifiedType} if qualifiers <> [] then begin {make qualified version of type} tp := pointer(Malloc(sizeof(typeRecord))); if origType^.kind in [structType,unionType] then begin tp^.size := origType^.size; tp^.kind := definedType; tp^.dType := origType; tp^.saveDisp := 0; tp^.qualifiers := qualifiers; end {if} else begin tp^ := origType^; tp^.qualifiers := tp^.qualifiers + qualifiers; end; {else} MakeQualifiedType := tp; {move array type quals to element type} while tp^.kind = arrayType do begin elemType := pointer(Malloc(sizeof(typeRecord))); if tp^.aType^.kind in [structType,unionType] then begin elemType^.size := tp^.aType^.size; elemType^.kind := definedType; elemType^.dType := tp^.aType; elemType^.saveDisp := 0; elemType^.qualifiers := qualifiers; end {if} else begin elemType^ := tp^.aType^; elemType^.qualifiers := elemType^.qualifiers + qualifiers; end; {else} tp^.aType := elemType; tp^.qualifiers := []; {remove for C23} tp := elemType; end; {if} end {if} else MakeQualifiedType := origType; end; {MakeQualifiedType} function Unqualify {tp: typePtr): typePtr}; { returns the unqualified version of a type } { } { parameters: } { tp - the original type } { } { returns: pointer to the unqualified type } var tp2: typePtr; {unqualified type} begin {Unqualify} while tp^.kind = definedType do tp := tp^.dType; Unqualify := tp; if tp^.qualifiers <> [] then if not (tp^.kind in [structType,unionType]) then begin tp2 := pointer(Malloc(sizeof(typeRecord))); tp2^ := tp^; tp2^.qualifiers := []; Unqualify := tp2; end; end; {Unqualify} function NewSymbol {name: stringPtr; itype: typePtr; class: tokenEnum; space: spaceType; state: stateKind; isInline: boolean): identPtr}; { insert a new symbol in the symbol table } { } { parameters: } { name - pointer to the symbol name } { itype - pointer to the symbol type } { class - storage class } { space - the kind of variable space to put the } { identifier in } { state - variable declaration state } { } { returns: pointer to the inserted symbol } var cs: identPtr; {current symbol} hashPtr: ^identPtr; {pointer to hash bucket in symbol table} i: integer; {loop variable} isFunction: boolean; {is this the symbol for a function?} isGlobal: boolean; {are we using the global table?} lUseGlobalPool: boolean; {use the global symbol pool?} needSymbol: boolean; {do we need to declare it?} np: stringPtr; {for forming static name} p: identPtr; {work pointer} tk: tokenType; {fake token; for FindSymbol} procedure AllocateStaticNum; { Allocate a staticNum value for the current table. } var done: boolean; {loop termination} i: integer; {loop index} begin {AllocateStaticNum} i := 5; {increment the static var number} repeat staticNum[i] := succ(staticNum[i]); done := staticNum[i] <> succ('9'); if not done then begin staticNum[i] := '0'; i := i-1; done := i = 1; end; {if} until done; table^.staticNum := staticNum; {record the static symbol table number} end; {AllocateStaticNum} procedure UnInline; { Generate a non-inline definition for a function previously } { defined with an (apparent) inline definition. } var fName: stringPtr; {name of function} i: integer; {loop variable} begin {UnInline} if cs^.iType^.isPascal then begin fName := pointer(Malloc(length(name^)+1)); CopyString(pointer(fName), pointer(name)); for i := 1 to length(fName^) do if fName^[i] in ['a'..'z'] then fName^[i] := chr(ord(fName^[i]) & $5F); end {if} else fName := name; Gen2Name(dc_str, 0, 0, fName); code^.s := m_jml; code^.q := 0; code^.r := ord(longabsolute); new(code^.lab); code^.lab^ := concat('~inline~',name^); Gen0(pc_nat); Gen0(dc_enp); end; {UnInline} begin {NewSymbol} needSymbol := true; {assume we need a symbol} isGlobal := false; {set up defaults} isFunction := false; lUseGlobalPool := useGlobalPool; tk.name := name; tk.symbolPtr := nil; if space <> fieldListSpace then begin {are we defining a function?} if (itype <> nil) and (itype^.kind = functionType) then begin isFunction := true; if class in [autosy, ident] then class := externsy else {If explicit storage class is given,} isInline := false; {this is not an inline definition. } end {if} else if (itype <> nil) and (itype^.kind in [structType,unionType]) and (itype^.fieldList = nil) and doingParameters then begin useGlobalPool := true; end; {else if} cs := FindSymbol(tk, space, true, true); {check for duplicates} if cs <> nil then begin if ((itype = nil) or (cs^.itype = nil) or (not CompTypes(cs^.itype, itype)) or ((cs^.state = initialized) and (state = initialized)) or ((class = typedefsy) <> (cs^.class = typedefsy)) or ((globalTable <> table) and (not (class in [externsy,typedefsy]) or not (cs^.class in [externsy,typedefsy])))) and ((not doingParameters) or (cs^.state <> declared)) then Error(42) else begin itype := MakeCompositeType(cs^.itype, itype); if class = externsy then if cs^.class = staticsy then class := staticsy; if cs^.storage = external then if isInline then isInline := cs^.inlineDefinition else if cs^.inlineDefinition then if iType^.kind = functionType then if cs^.state = defined then if table = globalTable then UnInline; p := cs; needSymbol := false; end; {else} end {if} else if class = externsy then {check for outer decl of same object/fn} if table <> globalTable then begin cs := FindSymbol(tk, space, false, true); if cs <> nil then if cs^.name^[1] <> '~' then {exclude block-scope statics} if cs^.storage in [global,external,private] then begin if not CompTypes(cs^.itype, itype) then Error(47); itype := MakeCompositeType(cs^.itype, itype); end; {if} end; {if} end; {if} if needSymbol then begin if class = staticsy then {statics go in the global symbol table} if not isFunction then if globalTable <> table then begin isGlobal := true; {note that we will use the global table} useGlobalPool := true; if table^.noStatics then begin table^.noStatics := false; AllocateStaticNum; end; {if} np := pointer(GMalloc(length(name^)+6)); {form static name} np^[0] := chr(5+length(name^)); for i := 1 to 5 do np^[i] := table^.staticNum[i]; for i := 1 to length(name^) do np^[i+5] := name^[i]; name := np; end; {if} p := pointer(Calloc(sizeof(identRecord))); {get space for the record} {p^.iPtr := nil;} {no initializers, yet} {p^.saved := 0;} {not saved} p^.state := state; {set the state} {p^.isForwardDeclared := false;} {assume no forward declarations are used} p^.name := name; {record the name} {p^.next := nil;} {p^.used := false;} {unused for now} if space <> fieldListSpace then {insert the symbol in the hash bucket} begin if (itype = nil) or not isGlobal then begin hashPtr := pointer(ord4(table)+Hash(name)); table^.isEmpty := false; end {if} else hashPtr := pointer(ord4(globalTable)+Hash(name)); if space = tagSpace then hashPtr := pointer(ord4(hashPtr) + 4*(hashSize+1)); p^.next := hashPtr^; hashPtr^ := p; end; {if} end; {if} if space = fieldListSpace then {check and set the storage class} p^.storage := none else if class in [autosy,registersy] then begin if doingFunction or doingParameters then begin p^.storage := stackFrame; class := ident; end {if} else begin p^.storage := global; Error(62); end; {else} end {if} else if class = ident then begin if doingFunction then begin p^.storage := stackFrame; class := autosy; end {if} else p^.storage := global; end {else if} else if class = externsy then begin p^.storage := external; p^.inlineDefinition := isInline; end {else if} else if class = staticsy then p^.storage := private else p^.storage := none; p^.class := class; p^.itype := itype; {set the symbol field values} NewSymbol := p; {return a pointer to the new entry} useGlobalPool := lUseGlobalPool; {restore the useGlobalPool variable} end; {NewSymbol} procedure PopTable; { Pop a symbol table (remove definitions local to a block) } var tPtr: symbolTablePtr; {work pointer} begin {PopTable} tPtr := table; {if printSymbols then {debug} { PrintTable(tPtr); {debug} if (lint & lintUnused) <> 0 then CheckUnused(tPtr); if tPtr^.next <> nil then begin table := table^.next; if not tPtr^.isEmpty then begin dispose(tPtr); if token.kind = ident then if FindSymbol(token,variableSpace,false,false) <> nil then if token.symbolPtr^.class = typedefsy then token.kind := typedef; end {if} else if (tablePoolSize = tablePoolMaxSize) then dispose(tPtr) else begin tPtr^.next := tablePool; tablePool := tPtr; tablePoolSize := tablePoolSize + 1; end; {else} end; {if} end; {PopTable} { copy 'symbol.print'} {debug} procedure PushTable; { Create a new symbol table, pushing the old one } var tPtr: symbolTablePtr; {work pointer} begin {PushTable} if tablePool <> nil then begin {use existing empty table if available} tPtr := tablePool; tablePool := tPtr^.next; tablePoolSize := tablePoolSize - 1; end {if} else begin new(tPtr); {...or create a new symbol table} ClearTable(tPtr^); tPtr^.isEmpty := true; end; {else} tPtr^.next := table; table := tPtr; tPtr^.noStatics := true; end; {PushTable} procedure ResolveForwardReference {iPtr: identPtr}; { resolve a forward reference } { } { parameters: } { iPtr - ptr to the forward declared identifier } var fl: identPtr; {for tracing field lists} ltk: tokenType; {for searching for forward refs} sym: identPtr; {for finding forward refs} lPtr,tPtr: typePtr; {for tracing forward declared types} begin {ResolveForwardReference} iPtr^.isForwardDeclared := false; {we will succeed or flag an error...} tPtr := iPtr^.itype; {skip to the struct/union type} lPtr := nil; while tPtr^.kind in [pointerType,arrayType,functionType,definedType] do begin lPtr := tPtr; tPtr := tPtr^.pType; end; if tPtr^.sName <> nil then begin {resolve the forward reference} ltk.name := tPtr^.sName; ltk.symbolPtr := nil; sym := FindSymbol(ltk,tagSpace,false,true); if sym <> nil then begin if sym^.itype^.kind <> tPtr^.kind then Error(107) else begin if sym^.itype = tPtr then tPtr^.sName := nil else begin tPtr := sym^.itype; if lPtr <> nil then lPtr^.ptype := tPtr; end; {else} end; {else} end; {if} end; {if} if lPtr <> nil then tPtr := lPtr^.pType; {check the field list for other fwd refs} while tPtr^.kind in [pointerType,arrayType,functionType,definedType] do tPtr := tPtr^.pType; if tPtr^.kind in [structType,unionType] then begin fl := tPtr^.fieldList; while fl <> nil do begin if fl^.isForwardDeclared then ResolveForwardReference(fl); fl := fl^.next; end; {while} end; {if} end; {ResolveForwardReference} function StringType{prefix: charStrPrefixEnum): typePtr}; { returns the type of a string literal with specified prefix } { } { parameters: } { prefix - the prefix } begin {StringType} if prefix in [prefix_none,prefix_u8] then StringType := stringTypePtr else if prefix in [prefix_u16,prefix_L] then StringType := utf16StringTypePtr else StringType := utf32StringTypePtr; end; {StringType} end. {$append 'symbol.asm'}