{============================================================================} {= =} {= 'PSyms.Pas' =} {= =} {= Pascal compiler parser symbol table routines. =} {= =} {= 12/15/86 - Bruce Tomlin =} {= =} {============================================================================} {$R+} { Turn on range checking in this module } UNIT PSyms; INTERFACE USES MacDefs, Files, Error, { Error is needed for 'Pause' } SymTab; VAR intSym: SymPtr; { Pointer to entry for INTEGER type } realSym: SymPtr; { Pointer to entry for REAL type } wrtIntSym: SymPtr; { Pointer to entry for WRITEINT procedure } wrtRealSym: SymPtr; { Pointer to entry for WRITEREAL procedure } FUNCTION AddRealConst(name: Str255; value: REAL): SymPtr; FUNCTION AddIntConst(name: Str255; value: INTEGER): SymPtr; FUNCTION AddVar(name: Str255): SymPtr; FUNCTION AddType(name: Str255): SymPtr; PROCEDURE CopyType(dest: SymPtr; src: SymPtr); FUNCTION AddProc(name: Str255): SymPtr; PROCEDURE MakeFunc(sp: Symptr; typePtr: Symptr); PROCEDURE AddParm(procPtr: SymPtr; parmName: Str255; typePtr: SymPtr; varParm: BOOLEAN); PROCEDURE MakeEnum(entry: symPtr); PROCEDURE AddEnum(enumPtr: SymPtr; symName: Str255; value: INTEGER); PROCEDURE MakeSubrange(entry: Symptr; lBound,hBound: INTEGER); FUNCTION MakeArray(entry: SymPtr): SymPtr; PROCEDURE AddDimension(VAR sp,elemTyp: SymPtr); PROCEDURE MakeRecord(entry: SymPtr); FUNCTION AddRecord(entry: SymPtr; fieldName: Str255): SymPtr; FUNCTION FindRecord(recPtr: SymPtr; name: Str255): SymPtr; PROCEDURE StdTypes; FUNCTION AlreadyDeclared(sp: SymPtr): BOOLEAN; PROCEDURE EnterParms(procPtr: SymPtr); PROCEDURE VarOffset(procPtr: SymPtr; sp: SymPtr); PROCEDURE HashStats(symTab: SymTabPtr); PROCEDURE DumpSymTab(symTab: SymTabPtr); IMPLEMENTATION {============================================================================} {= =} {= ADDREALCONST =} {= =} {= Adds a new entry to the symbol table for a real number constant =} {= =} {= Parameters =} {= =} {= NAME The name of the new symbol =} {= VALUE The constant value of the symbol =} {= =} {= Returns a pointer to the new symbol table entry. =} {= =} {============================================================================} FUNCTION AddRealConst(name: Str255; value: REAL): SymPtr; VAR sp: SymPtr; BEGIN sp := AddSym(name,tCONST); WITH sp^ DO BEGIN idTyp := tREAL; size := realSize; realValue := value; nextEnum := NIL; { Can't have real number enums anyway! } eParent := NIL; END; AddRealConst := sp; END; {============================================================================} {= =} {= ADDINTCONST =} {= =} {= Adds a new entry to the symbol table for an integer constant. =} {= =} {= Parameters =} {= =} {= NAME The name of the new symbol =} {= VALUE The constant value of the symbol =} {= =} {= Returns a pointer to the new symbol table entry. =} {= =} {============================================================================} FUNCTION AddIntConst(name: Str255; value: INTEGER): SymPtr; VAR sp: SymPtr; BEGIN sp := AddSym(name,tCONST); WITH sp^ DO BEGIN idTyp := tINT; size := realSize; intValue := value; nextEnum := NIL; eParent := NIL; END; AddIntConst := sp; END; {============================================================================} {= =} {= ADDVAR =} {= =} {= Adds a new entry to the symbol table for a variable. =} {= =} {= Parameters =} {= =} {= NAME The name of the new symbol =} {= =} {= Returns a pointer to the new symbol table entry. =} {= =} {============================================================================} FUNCTION AddVar(name: Str255): SymPtr; VAR sp: SymPtr; BEGIN sp := AddSym(name,tVAR); WITH sp^ DO BEGIN idTyp := tNoType; varParm := FALSE; END; AddVar := sp; END; {============================================================================} {= =} {= ADDTYPE =} {= =} {= Adds a new entry to the symbol table for a type. =} {= =} {= Parameters =} {= =} {= NAME The name of the new symbol =} {= =} {= Returns a pointer to the new symbol table entry. =} {= =} {============================================================================} FUNCTION AddType(name: Str255): SymPtr; VAR sp: SymPtr; BEGIN sp := AddSym(name,tTYPE); WITH sp^ DO BEGIN idTyp := tNoType; END; AddType := sp; END; {============================================================================} {= =} {= COPYTYPE =} {= =} {= Copies the type of one symbol to another. =} {= =} {= Parameters =} {= =} {= DEST The symbol to receive the copied type =} {= SRC The symbol containing the type to be copied =} {= =} {============================================================================} PROCEDURE CopyType(dest: SymPtr; src: SymPtr); VAR sp: SymPtr; BEGIN WITH dest^ DO BEGIN idTyp := src^.idTyp; size := src^.size; CASE src^.idTyp OF tRECORD: BEGIN rDetached := FALSE; firstElem := src^.firstElem; END; tARRAY: BEGIN loBound := src^.loBound; hiBound := src^.hiBound; aDetached := FALSE; arrayTyp := src^.arrayTyp; END; tSubrange: BEGIN loVal := src^.loVal; hiVal := src^.hiVal; END; tEnum: BEGIN hiEnum := src^.hiEnum; consts := src^.consts; END; END; END; END; {============================================================================} {= =} {= ADDPROC =} {= =} {= Adds a new entry to the symbol table for a procedure. =} {= =} {= Parameters =} {= =} {= NAME The name of the new symbol =} {= =} {= Returns a pointer to the new symbol table entry. =} {= =} {============================================================================} FUNCTION AddProc(name: Str255): SymPtr; VAR sp: SymPtr; BEGIN sp := AddSym(name,tPROC); WITH sp^ DO BEGIN idTyp := tNoType; parms := NIL; parmSize := 8; { 8 = 4 for frame link + 4 for return address } { Subprocedure will have 4 more for static link } varSize := 0; END; AddProc := sp; END; {============================================================================} {= =} {= MAKEFUNC =} {= =} {= Turns a procedure symbol table entry into a function entry. =} {= =} {= Parameters =} {= =} {= SP A pointer to the procedure symbol table entry =} {= TYPEPTR A pointer to the type that the function will return =} {= =} {============================================================================} PROCEDURE MakeFunc(sp: Symptr; typePtr: Symptr); BEGIN WITH sp^ DO BEGIN typ := tFUNC; funcType := typePtr; END; END; {============================================================================} {= =} {= ADDPARM =} {= =} {= Adds a parameter to a procedure or function symbol table entry. =} {= =} {= Parameters =} {= =} {= PROCPTR A pointer to the procedure or function symbol =} {= PARMNAME The name of the parameter =} {= TYPEPTR A pointer to the type of the parameter =} {= VARPARM TRUE if the parameter is a VAR parameter =} {= =} {============================================================================} PROCEDURE AddParm(procPtr: SymPtr; parmName: Str255; typePtr: SymPtr; varParm: BOOLEAN); VAR pp: ParamPtr; p: ParamPtr; q: ParamPtr; BEGIN New(pp); WITH pp^ DO BEGIN next := NIL; name := HeapString(parmName); typ := typePtr; isVar := varParm; q := NIL; p := procPtr^.parms; WHILE p<>NIL DO BEGIN q := p; p := p^.next; END; IF q=NIL THEN procPtr^.parms := pp ELSE q^.next := pp; END; END; {============================================================================} {= =} {= MAKEENUM =} {= =} {= Makes the symbol an enumerated type. =} {= =} {= Parameters =} {= =} {= ENTRY A pointer to the symbol to be made enumerated =} {= =} {============================================================================} PROCEDURE MakeEnum(entry: symPtr); BEGIN WITH entry^ DO BEGIN idTyp := tEnum; hiEnum := 0; { Filled in later } consts := NIL; { Filled in later } END; END; {============================================================================} {= =} {= ADDENUM =} {= =} {= Adds a new constant to an enumerated type. =} {= =} {= Parameters =} {= =} {= ENUMPTR A pointer to the enumerated type entry =} {= SYMNAME The name of the new constant =} {= VALUE The value of the new constant =} {= =} {============================================================================} PROCEDURE AddEnum(enumPtr: SymPtr; symName: Str255; value: INTEGER); VAR sp: SymPtr; BEGIN sp := AddIntConst(symName,value); WITH sp^ DO BEGIN sp^.eParent := enumPtr; sp^.nextEnum := enumPtr^.consts; END; enumPtr^.consts := sp; END; {============================================================================} {= =} {= MAKESUBRANGE =} {= =} {= Makes the symbol a subrange type. =} {= =} {= Parameters =} {= =} {= ENTRY A pointer to the symbol to be made a subrange =} {= LBOUND The lower bound of the subrange =} {= HBOUND The higher bound of the subrange =} {= =} {============================================================================} PROCEDURE MakeSubrange(entry: Symptr; lBound,hBound: INTEGER); BEGIN WITH entry^ DO BEGIN size := intSize; idTyp := tSubrange; loVal := lBound; hiVal := hBound; END; END; {============================================================================} {= =} {= MAKEARRAY =} {= =} {= Makes the symbol an array type. =} {= =} {= Parameters =} {= =} {= ENTRY A pointer to the symbol to be made an array =} {= =} {============================================================================} FUNCTION MakeArray(entry: SymPtr): SymPtr; VAR sp: SymPtr; BEGIN New(sp); WITH sp^ DO BEGIN typ := tArrayTyp; idTyp := tNoType; size := 0; offset := 0; parent := NIL; END; WITH entry^ DO BEGIN idTyp := tARRAY; loBound := 0; hiBound := 0; arrayTyp := sp; aDetached := TRUE; END; MakeArray := sp; END; {============================================================================} {= =} {= ADDDIMENSION =} {= =} {= Adds a dimension to an array. =} {= =} {= Parameters =} {= =} {= SP A pointer to the array entry =} {= ELEMTYP A pointer to the array's type entry =} {= =} {= Returns pointers to a new array and type entry in the parameters. =} {= =} {============================================================================} PROCEDURE AddDimension(VAR sp,elemTyp: SymPtr); BEGIN sp := elemTyp; elemTyp := MakeArray(elemTyp); END; {============================================================================} {= =} {= MAKERECORD =} {= =} {= Makes the symbol a record type. =} {= =} {= Parameters =} {= =} {= ENTRY A pointer to the symbol to be made a record =} {= =} {============================================================================} PROCEDURE MakeRecord(entry: SymPtr); BEGIN WITH entry^ DO BEGIN idTyp := tRECORD; size := 0; firstElem := NIL; END; END; {============================================================================} {= =} {= ADDRECORD =} {= =} {= Adds a new record to a record type. =} {= =} {= Parameters =} {= =} {= ENTRY A pointer to the record's symbol table entry =} {= FIELDNAME The name of the new field =} {= =} {= Returns a pointer to the new field. =} {= =} {============================================================================} FUNCTION AddRecord(entry: SymPtr; fieldName: Str255): SymPtr; VAR sp: SymPtr; BEGIN New(sp); WITH sp^ DO BEGIN name := HeapString(fieldName); typ := tRecElem; idTyp := tNoType; size := 0; offset := 0; parent := NIL; { Make the offset of this element be the offset of the previous } { element plus the size of the previous element } IF entry^.firstElem<>NIL THEN WITH entry^.firstElem^ DO sp^.offset := offset+size; { Attach the new field to the record's symbol table entry } next := entry^.firstElem; entry^.firstElem := sp; END; AddRecord := sp; END; {============================================================================} {= =} {= FINDRECORD =} {= =} {= Finds a field in a record. =} {= =} {= Parameters =} {= =} {= RECPTR A pointer to the record to search =} {= NAME The name of the field to find =} {= =} {= Returns a pointer to the field or NIL if not found. =} {= =} {============================================================================} FUNCTION FindRecord(recPtr: SymPtr; name: Str255): SymPtr; VAR p: SymPtr; found: BOOLEAN; BEGIN FindRecord := NIL; found := FALSE; p := recPtr^.firstElem; WHILE (p<>NIL) AND NOT found DO BEGIN IF p^.name^=name THEN BEGIN found := TRUE; FindRecord := p; END ELSE p := p^.next; END; END; {============================================================================} {= =} {= STDTYPES =} {= =} {= Adds the standard types INTEGER and REAL and the procedures =} {= WRITEINT, WRITEREAL, and WRITELN to the symbol table. =} {= =} {============================================================================} PROCEDURE StdTypes; BEGIN { Initialize the standard types INTEGER and REAL } intSym := AddType('INTEGER'); WITH intSym^ DO BEGIN idTyp := tINT; size := intSize; END; realSym := AddType('REAL'); WITH realSym^ DO BEGIN idTyp := tREAL; size := realSize; END; wrtIntSym := AddProc('WRITEINT'); AddParm(wrtIntSym,'AN_INTEGER',intSym,FALSE); wrtIntSym^.parmSize := 10; wrtRealSym := AddProc('WRITEREAL'); AddParm(wrtRealSym,'A_REAL_NUM',realSym,FALSE); wrtRealSym^.parmSize := 10; END; {============================================================================} {= =} {= ADDTYPE =} {= =} {= Checks if a symbol has already been declared on this level. =} {= =} {= Parameters =} {= =} {= SP Pointer to the symbol to check =} {= =} {= Returns TRUE if the symbol has already been declared on this level. =} {= =} {============================================================================} FUNCTION AlreadyDeclared(sp: SymPtr): BOOLEAN; BEGIN AlreadyDeclared := FALSE; IF sp<>NIL THEN AlreadyDeclared := (sp^.parent=symTab); END; {============================================================================} {= =} {= ENTERPARMS =} {= =} {= Enters the parameters of a procedure or function into the =} {= symbol table. =} {= =} {= Parameters =} {= =} {= PROCPTR A pointer to the procedure or function symbol entry =} {= =} {============================================================================} PROCEDURE EnterParms(procPtr: SymPtr); {========================================================================} {= =} {= ENTERPARM =} {= =} {= Enters the parameters of a procedure or function into the =} {= symbol table. This function recursively enters the parameters =} {= into the symbol table in reverse order of declaration. =} {= =} {= Parameters =} {= =} {= PARM A pointer to the parameter =} {= =} {========================================================================} PROCEDURE EnterParm(parm: ParamPtr); VAR sp: SymPtr; BEGIN IF parm<>NIL THEN WITH procPtr^,parm^ DO BEGIN EnterParm(next); sp := AddVar(name^); CopyType(sp,typ); sp^.varParm := isVar; sp^.offset := parmSize; IF isVar OR (sp^.size>4) THEN parmSize := parmSize + 4 ELSE parmSize := parmSize + sp^.size; END; END; BEGIN { of EnterParms } EnterParm(procPtr^.parms); END; {============================================================================} {= =} {= VAROFFSET =} {= =} {= Computes the offset field for a variable's symbol table entry. =} {= =} {= Parameters =} {= =} {= PROCPTR A pointer to the procedure or function symbol entry =} {= SP A pointer to the var to compute the offset of =} {= =} {============================================================================} PROCEDURE VarOffset(procPtr: SymPtr; sp: SymPtr); BEGIN WITH procPtr^ DO BEGIN varSize := varSize - sp^.size; sp^.offset := varSize; END; END; {============================================================================} {= =} {= HASHSTATS =} {= =} {= Print out the hashing statistics. =} {= =} {= SYMTAB The symbol table to print the hashing statistics for =} {= =} {============================================================================} PROCEDURE HashStats(symTab: SymTabPtr); BEGIN IF symTab<>NIL THEN WITH symTab^ DO BEGIN WriteLn(outFile,'Hashing statistics:'); WriteLn(outFile,' symTabSiz = ',symTabSiz); WriteLn(outFile,' dcl level = ',level); WriteLn(outFile,' hashHits = ',hashHits); WriteLn(outFile,' numSyms = ',numSyms); END; END; {============================================================================} {= =} {= IDENTSTR =} {= =} {= Makes an identifier string for DumpSymTab. =} {= =} {= Parameters =} {= =} {= NAME The identifier name =} {= INDENT The number of spaces to indent =} {= MAXWIDTH The maximum width of the output string =} {= STR The output string =} {= =} {============================================================================} PROCEDURE IdentStr(name: Str255; indent,maxWidth: INTEGER; VAR str: Str255); VAR i: INTEGER; BEGIN str[0] := CHR(maxWidth); FOR i := 1 TO maxWidth DO str[i] := ' '; Insert(name,str,indent+1); str := Copy(str,1,maxWidth); END; {============================================================================} {= =} {= SYMTYPESTR =} {= =} {= Returns the name of symbol type. =} {= =} {= Parameters =} {= =} {= TYP The symbol type to get the name of =} {= STR The symbol type name is returned in this string =} {= =} {============================================================================} PROCEDURE SymTypeStr(typ: SymType; VAR str: Str255); BEGIN CASE typ OF tKeyword: str := 'tKeyword '; tCONST: str := 'tCONST '; tTYPE: str := 'tTYPE '; tVAR: str := 'tVAR '; tPROC: str := 'tPROC '; tFUNC: str := 'tFUNC '; tRecElem: str := 'tRecElem '; tArrayTyp: str := 'tArrayTyp'; OTHERWISE str := '?????????'; END; END; {============================================================================} {= =} {= IDTYPESTR =} {= =} {= Returns the name of an identifier type. =} {= =} {= Parameters =} {= =} {= IDTYP The identifier type to get the name of =} {= STR The identifier type name is returned in this string =} {= =} {============================================================================} PROCEDURE IDTypeStr(idTyp: IDType; VAR str: Str255); BEGIN CASE idTyp OF tNoType: str := 'tNoType '; tINT: str := 'tINT '; tREAL: str := 'tREAL '; tRECORD: str := 'tRECORD '; tARRAY: str := 'tARRAY '; tSubrange: str := 'tSubrange'; tEnum: str := 'tEnum '; OTHERWISE str := '?????????'; END; END; {============================================================================} {= =} {= DUMPTYPE =} {= =} {= Prints out the type of a symbol. =} {= =} {= Parameters =} {= =} {= SYM The symbol to print out the type of =} {= LEVEL The symbol number of spaces to indent identifiers =} {= =} {============================================================================} PROCEDURE DumpType(sym: SymPtr; level: INTEGER); VAR str: Str255; sp: SymPtr; pp: ParamPtr; BEGIN WITH sym^ DO BEGIN SymTypeStr(typ,str); Write(outFile,' ',str,' '); IF typ=tKeyword THEN Write(outFile,'#',ORD(kwSym)) ELSE BEGIN IDTypeStr(idTyp,str); Write(outFile,str,size:5,offset:7); CASE typ OF tCONST: BEGIN CASE idTyp OF tINT: Write(outFile,' ',intValue); tREAL: Write(outFile,' ',realValue); END; IF eParent<>NIL THEN BEGIN Write(outFile,' eParent -> ',eParent^.name^); Write(outFile,' nextEnum -> '); IF nextEnum=NIL THEN Write(outFile,'NIL') ELSE Write(outFile,nextEnum^.name^); END; END; tVAR: IF varParm THEN Write(outFile,' varParm'); tPROC, tFUNC: BEGIN Write(outFile,' varSize=',varSize); Write(outFile,' parmSize=',parmSize); IF typ=tFUNC THEN Write(outFile,' funcType -> ', funcType^.name^); pp := sym^.parms; WHILE pp<>NIL DO WITH pp^ DO BEGIN WriteLn(outFile); IdentStr(name^,level+2,15,str); Write(outFile,str); Write(outFile,' typ -> ',typ^.name^); IF isVar THEN Write(outFile,' isVar'); pp := next; END; END; END; CASE idTyp OF tRECORD: BEGIN sp := sym^.firstElem; WHILE sp<>NIL DO WITH sp^ DO BEGIN WriteLn(outFile); IdentStr(name^,level+2,15,str); Write(outFile,str); DumpType(sp,level+2); sp := next; END; END; tARRAY: BEGIN sp := sym; WHILE sp^.idTyp=tARRAY DO WITH sp^ DO BEGIN Write(outFile,' ',loBound,'..',hiBound); sp := arrayTyp; END; WriteLn(outFile); Write(outFile,'':15); DumpType(sp,level); END; tSubrange: Write(outFile,' ',loVal,'..',hiVal); tEnum: BEGIN Write(outFile,' ',hiEnum,' consts -> '); IF consts=NIL THEN Write(outFile,'NIL') ELSE Write(outFile,consts^.name^); END; END; END; END; END; {============================================================================} {= =} {= DUMPSYM =} {= =} {= Prints out the contents of a symbol table entry. =} {= =} {= Parameters =} {= =} {= SYM The symbol to print out =} {= =} {============================================================================} PROCEDURE DumpSym(sym: SymPtr); VAR str: Str255; BEGIN IdentStr(sym^.name^,0,15,str); Write(outFile,str); DumpType(sym,0); Pause; WriteLn(outFile); END; {============================================================================} {= =} {= DUMPSYMTAB =} {= =} {= Prints out the contents of a symbol table. =} {= =} {= SYMTAB The symbol table to dump =} {= =} {============================================================================} PROCEDURE DumpSymTab(symTab: SymTabPtr); VAR sp: SymPtr; i: INTEGER; found: BOOLEAN; BEGIN IF symTab<>NIL THEN BEGIN WriteLn(outFile); HashStats(symTab); FOR i := 1 TO symTabSiz DO BEGIN sp := symTab^.entry[i]; IF (sp<>NIL) AND NOT found THEN BEGIN WriteLn(outFile); WriteLn(outFile,' name^ typ idTyp size offset'); WriteLn(outFile,'--------------- --------- --------- ---- ------'); found := TRUE; END; WHILE sp<>NIL DO BEGIN DumpSym(sp); sp := sp^.next; END; END; IF NOT found THEN WriteLn(outFile,'No symbols declared in this symbol table.'); { If outputting to the screen, wait for a key or a click } IF screenOut THEN Wait; WriteLn(outFile); END; END; END.