| (* PCSymBuild.mod pass C symbol creation. |
| |
| Copyright (C) 2001-2026 Free Software Foundation, Inc. |
| Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. |
| |
| This file is part of GNU Modula-2. |
| |
| GNU Modula-2 is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GNU Modula-2 is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Modula-2; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. *) |
| |
| IMPLEMENTATION MODULE PCSymBuild ; |
| |
| |
| FROM Storage IMPORT ALLOCATE, DEALLOCATE ; |
| FROM NameKey IMPORT Name, WriteKey, MakeKey, NulName ; |
| FROM StrIO IMPORT WriteString, WriteLn ; |
| FROM NumberIO IMPORT WriteCard ; |
| FROM M2Debug IMPORT Assert, WriteDebug ; |
| FROM M2Error IMPORT WriteFormat0, WriteFormat1, WriteFormat2, FlushErrors, InternalError, NewError, ErrorFormat0 ; |
| FROM M2MetaError IMPORT MetaError1, MetaErrorT1 ; |
| FROM M2LexBuf IMPORT GetTokenNo ; |
| FROM M2Reserved IMPORT NulTok, ImportTok ; |
| FROM M2Const IMPORT constType ; |
| FROM Indexing IMPORT Index, InitIndex, GetIndice, PutIndice, InBounds, IncludeIndiceIntoIndex, HighIndice ; |
| |
| FROM M2Quads IMPORT PushT, PopT, OperandT, PopN, PopTF, PushTF, IsAutoPushOn, |
| PopNothing, PushTFn, PopTFn, PushTtok, PopTtok, PushTFtok, PopTFtok, OperandTok ; |
| |
| FROM M2Options IMPORT Iso ; |
| FROM StdIO IMPORT Write ; |
| FROM M2System IMPORT Cast, IsPseudoSystemFunctionConstExpression ; |
| |
| FROM M2Base IMPORT MixTypes, |
| ZType, RType, Char, Boolean, Val, Max, Min, Convert, |
| IsPseudoBaseFunction, IsRealType, IsComplexType, IsOrdinalType ; |
| |
| FROM M2Reserved IMPORT PlusTok, MinusTok, TimesTok, DivTok, ModTok, |
| DivideTok, RemTok, |
| OrTok, AndTok, AmbersandTok, |
| EqualTok, LessEqualTok, GreaterEqualTok, |
| LessTok, GreaterTok, HashTok, LessGreaterTok, |
| InTok, NotTok ; |
| |
| FROM SymbolTable IMPORT NulSym, ModeOfAddr, ProcedureKind, |
| StartScope, EndScope, GetScope, GetCurrentScope, |
| GetModuleScope, |
| SetCurrentModule, GetCurrentModule, SetFileModule, |
| GetExported, |
| IsDefImp, IsModule, |
| RequestSym, |
| IsProcedure, PutOptArgInit, IsEnumeration, |
| CheckForUnknownInModule, |
| GetFromOuterModule, |
| CheckForEnumerationInCurrentModule, |
| GetMode, PutVariableAtAddress, ModeOfAddr, SkipType, |
| IsSet, PutConstSet, IsType, |
| IsConst, IsConstructor, PutConst, PutConstructor, |
| PopValue, PushValue, |
| MakeTemporary, PutVar, |
| PutSubrange, |
| GetSymName, |
| CheckAnonymous, |
| IsProcedureBuiltin, |
| MakeProcType, |
| NoOfParamAny, |
| GetParam, |
| IsParameterVar, PutProcTypeParam, |
| PutProcTypeVarParam, IsParameterUnbounded, |
| PutFunction, PutProcTypeParam, |
| GetType, IsVar, |
| IsAModula2Type, GetDeclaredMod ; |
| |
| FROM M2Batch IMPORT MakeDefinitionSource, |
| MakeImplementationSource, |
| MakeProgramSource, |
| LookupModule, LookupOuterModule ; |
| |
| FROM M2Comp IMPORT CompilingDefinitionModule, |
| CompilingImplementationModule, |
| CompilingProgramModule ; |
| |
| FROM M2StackAddress IMPORT StackOfAddress, InitStackAddress, KillStackAddress, |
| PushAddress, PopAddress, PeepAddress, |
| IsEmptyAddress, NoOfItemsInStackAddress ; |
| |
| FROM M2StackWord IMPORT StackOfWord, InitStackWord, KillStackWord, |
| PushWord, PopWord, PeepWord, |
| IsEmptyWord, NoOfItemsInStackWord ; |
| |
| IMPORT M2Error ; |
| |
| |
| CONST |
| Debugging = FALSE ; |
| |
| TYPE |
| tagType = (leaf, unary, binary, designator, expr, convert, function) ; |
| |
| exprNode = POINTER TO eNode ; |
| |
| eDes = RECORD |
| type: CARDINAL ; |
| meta: constType ; |
| sym : CARDINAL ; |
| left: exprNode ; |
| END ; |
| |
| eLeaf = RECORD |
| type: CARDINAL ; |
| meta: constType ; |
| sym: CARDINAL ; |
| END ; |
| |
| eUnary = RECORD |
| type: CARDINAL ; |
| meta: constType ; |
| left: exprNode ; |
| op : Name ; |
| END ; |
| |
| eBinary = RECORD |
| type: CARDINAL ; |
| meta: constType ; |
| left, |
| right: exprNode ; |
| op : Name ; |
| END ; |
| |
| eExpr = RECORD |
| type: CARDINAL ; |
| meta: constType ; |
| left: exprNode ; |
| END ; |
| |
| eFunction = RECORD |
| type : CARDINAL ; |
| meta : constType ; |
| func : CARDINAL ; |
| first, |
| second: exprNode ; |
| third : BOOLEAN ; |
| END ; |
| |
| eConvert = RECORD |
| type : CARDINAL ; |
| meta : constType ; |
| totype: exprNode ; |
| expr : exprNode ; |
| END ; |
| |
| eNode = RECORD |
| CASE tag: tagType OF |
| |
| designator: edes : eDes | |
| leaf : eleaf : eLeaf | |
| unary : eunary : eUnary | |
| binary : ebinary : eBinary | |
| expr : eexpr : eExpr | |
| function : efunction: eFunction | |
| convert : econvert : eConvert |
| |
| END |
| END ; |
| |
| |
| VAR |
| exprStack : StackOfAddress ; |
| constList : Index ; |
| constToken : CARDINAL ; |
| desStack : StackOfWord ; |
| inDesignator: BOOLEAN ; |
| |
| |
| (* |
| GetSkippedType - |
| *) |
| |
| PROCEDURE GetSkippedType (sym: CARDINAL) : CARDINAL ; |
| BEGIN |
| RETURN( SkipType(GetType(sym)) ) |
| END GetSkippedType ; |
| |
| |
| (* |
| CheckNotVar - checks to see that the top of stack is not a variable. |
| *) |
| |
| PROCEDURE CheckNotVar (tok: CARDINAL) ; |
| VAR |
| const: CARDINAL ; |
| BEGIN |
| const := OperandT (1) ; |
| IF (const # NulSym) AND IsVar (const) |
| THEN |
| MetaErrorT1 (tok, 'not expecting a variable {%Aad} as a term in a constant expression', const) |
| END |
| END CheckNotVar ; |
| |
| |
| (* |
| StartBuildDefinitionModule - Creates a definition module and starts |
| a new scope. |
| |
| The Stack is expected: |
| |
| Entry Exit |
| |
| Ptr -> <- Ptr |
| +------------+ +-----------+ |
| | NameStart | | NameStart | |
| |------------| |-----------| |
| |
| *) |
| |
| PROCEDURE PCStartBuildDefModule ; |
| VAR |
| tok : CARDINAL ; |
| name : Name ; |
| ModuleSym: CARDINAL ; |
| BEGIN |
| PopTtok(name, tok) ; |
| ModuleSym := MakeDefinitionSource(tok, name) ; |
| SetCurrentModule(ModuleSym) ; |
| SetFileModule(ModuleSym) ; |
| StartScope(ModuleSym) ; |
| Assert(IsDefImp(ModuleSym)) ; |
| Assert(CompilingDefinitionModule()) ; |
| PushT(name) ; |
| M2Error.EnterDefinitionScope (name) |
| END PCStartBuildDefModule ; |
| |
| |
| (* |
| EndBuildDefinitionModule - Destroys the definition module scope and |
| checks for correct name. |
| |
| The Stack is expected: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ +-----------+ |
| | NameEnd | | | |
| |------------| |-----------| |
| | NameStart | | | <- Ptr |
| |------------| |-----------| |
| *) |
| |
| PROCEDURE PCEndBuildDefModule (tokno: CARDINAL) ; |
| VAR |
| NameStart, |
| NameEnd : CARDINAL ; |
| BEGIN |
| Assert(CompilingDefinitionModule()) ; |
| CheckForUnknownInModule (tokno) ; |
| EndScope ; |
| PopT(NameEnd) ; |
| PopT(NameStart) ; |
| IF NameStart#NameEnd |
| THEN |
| WriteFormat2('inconsistent definition module was named (%a) and concluded as (%a)', |
| NameStart, NameEnd) |
| END ; |
| M2Error.LeaveErrorScope |
| END PCEndBuildDefModule ; |
| |
| |
| (* |
| StartBuildImplementationModule - Creates an implementation module and starts |
| a new scope. |
| |
| The Stack is expected: |
| |
| Entry Exit |
| |
| Ptr -> <- Ptr |
| +------------+ +-----------+ |
| | NameStart | | NameStart | |
| |------------| |-----------| |
| |
| *) |
| |
| PROCEDURE PCStartBuildImpModule ; |
| VAR |
| tok : CARDINAL ; |
| name : Name ; |
| ModuleSym: CARDINAL ; |
| BEGIN |
| PopTtok(name, tok) ; |
| ModuleSym := MakeImplementationSource(tok, name) ; |
| SetCurrentModule(ModuleSym) ; |
| SetFileModule(ModuleSym) ; |
| StartScope(ModuleSym) ; |
| Assert(IsDefImp(ModuleSym)) ; |
| Assert(CompilingImplementationModule()) ; |
| PushTtok(name, tok) ; |
| M2Error.EnterImplementationScope (name) |
| END PCStartBuildImpModule ; |
| |
| |
| (* |
| EndBuildImplementationModule - Destroys the implementation module scope and |
| checks for correct name. |
| |
| The Stack is expected: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ +-----------+ |
| | NameEnd | | | |
| |------------| |-----------| |
| | NameStart | | | <- Ptr |
| |------------| |-----------| |
| *) |
| |
| PROCEDURE PCEndBuildImpModule (tokno: CARDINAL) ; |
| VAR |
| NameStart, |
| NameEnd : Name ; |
| BEGIN |
| Assert(CompilingImplementationModule()) ; |
| CheckForUnknownInModule (tokno) ; |
| EndScope ; |
| PopT(NameEnd) ; |
| PopT(NameStart) ; |
| IF NameStart#NameEnd |
| THEN |
| (* we dont issue an error based around incorrect module names as this is done in P1 and P2. |
| If we get here then something has gone wrong with our error recovery in PC, so we bail out. |
| *) |
| WriteFormat0('too many errors in pass 3') ; |
| FlushErrors |
| END ; |
| M2Error.LeaveErrorScope |
| END PCEndBuildImpModule ; |
| |
| |
| (* |
| StartBuildProgramModule - Creates a program module and starts |
| a new scope. |
| |
| The Stack is expected: |
| |
| Entry Exit |
| |
| Ptr -> <- Ptr |
| +------------+ +-----------+ |
| | NameStart | | NameStart | |
| |------------| |-----------| |
| |
| *) |
| |
| PROCEDURE PCStartBuildProgModule ; |
| VAR |
| tok : CARDINAL ; |
| name : Name ; |
| ModuleSym: CARDINAL ; |
| BEGIN |
| (* WriteString('StartBuildProgramModule') ; WriteLn ; *) |
| PopTtok(name, tok) ; |
| ModuleSym := MakeProgramSource(tok, name) ; |
| SetCurrentModule(ModuleSym) ; |
| SetFileModule(ModuleSym) ; |
| (* WriteString('MODULE - ') ; WriteKey(GetSymName(ModuleSym)) ; WriteLn ; *) |
| StartScope(ModuleSym) ; |
| Assert(CompilingProgramModule()) ; |
| Assert(NOT IsDefImp(ModuleSym)) ; |
| PushTtok(name, tok) ; |
| M2Error.EnterProgramScope (name) |
| END PCStartBuildProgModule ; |
| |
| |
| (* |
| EndBuildProgramModule - Destroys the program module scope and |
| checks for correct name. |
| |
| The Stack is expected: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ +-----------+ |
| | NameEnd | | | |
| |------------| |-----------| |
| | NameStart | | | <- Ptr |
| |------------| |-----------| |
| *) |
| |
| PROCEDURE PCEndBuildProgModule (tokno: CARDINAL) ; |
| VAR |
| NameStart, |
| NameEnd : Name ; |
| BEGIN |
| Assert(CompilingProgramModule()) ; |
| CheckForUnknownInModule (tokno) ; |
| EndScope ; |
| PopT(NameEnd) ; |
| PopT(NameStart) ; |
| IF NameStart#NameEnd |
| THEN |
| (* we dont issue an error based around incorrect module names this would be done in P1 and P2. |
| If we get here then something has gone wrong with our error recovery in PC, so we bail out. |
| *) |
| WriteFormat0('too many errors in pass 3') ; |
| FlushErrors |
| END ; |
| M2Error.LeaveErrorScope |
| END PCEndBuildProgModule ; |
| |
| |
| (* |
| StartBuildInnerModule - Creates an Inner module and starts |
| a new scope. |
| |
| The Stack is expected: |
| |
| Entry Exit |
| |
| Ptr -> <- Ptr |
| +------------+ +-----------+ |
| | NameStart | | NameStart | |
| |------------| |-----------| |
| |
| *) |
| |
| PROCEDURE PCStartBuildInnerModule ; |
| VAR |
| name : Name ; |
| tok : CARDINAL ; |
| ModuleSym: CARDINAL ; |
| BEGIN |
| PopTtok(name, tok) ; |
| ModuleSym := RequestSym(tok, name) ; |
| Assert(IsModule(ModuleSym)) ; |
| StartScope(ModuleSym) ; |
| Assert(NOT IsDefImp(ModuleSym)) ; |
| SetCurrentModule(ModuleSym) ; |
| PushTtok(name, tok) ; |
| M2Error.EnterModuleScope (name) |
| END PCStartBuildInnerModule ; |
| |
| |
| (* |
| EndBuildInnerModule - Destroys the Inner module scope and |
| checks for correct name. |
| |
| The Stack is expected: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ +-----------+ |
| | NameEnd | | | |
| |------------| |-----------| |
| | NameStart | | | <- Ptr |
| |------------| |-----------| |
| *) |
| |
| PROCEDURE PCEndBuildInnerModule (tokno: CARDINAL) ; |
| VAR |
| NameStart, |
| NameEnd : Name ; |
| BEGIN |
| CheckForUnknownInModule (tokno) ; |
| EndScope ; |
| PopT(NameEnd) ; |
| PopT(NameStart) ; |
| IF NameStart#NameEnd |
| THEN |
| (* we dont issue an error based around incorrect module names this would be done in P1 and P2. |
| If we get here then something has gone wrong with our error recovery in PC, so we bail out. |
| *) |
| WriteFormat0('too many errors in pass 3') ; |
| FlushErrors |
| END ; |
| SetCurrentModule(GetModuleScope(GetCurrentModule())) ; |
| M2Error.LeaveErrorScope |
| END PCEndBuildInnerModule ; |
| |
| |
| (* |
| BuildImportOuterModule - Builds imported identifiers into an outer module |
| from a definition module. |
| |
| The Stack is expected: |
| |
| Entry OR Entry |
| |
| Ptr -> Ptr -> |
| +------------+ +-----------+ |
| | # | | # | |
| |------------| |-----------| |
| | Id1 | | Id1 | |
| |------------| |-----------| |
| . . . . |
| . . . . |
| . . . . |
| |------------| |-----------| |
| | Id# | | Id# | |
| |------------| |-----------| |
| | ImportTok | | Ident | |
| |------------| |-----------| |
| |
| IMPORT Id1, .. Id# ; FROM Ident IMPORT Id1 .. Id# ; |
| |
| |
| Exit |
| |
| All above stack discarded |
| *) |
| |
| PROCEDURE PCBuildImportOuterModule ; |
| VAR |
| Sym, ModSym, |
| i, n : CARDINAL ; |
| BEGIN |
| PopT (n) ; (* n = # of the Ident List *) |
| IF OperandT (n+1) # ImportTok |
| THEN |
| (* Ident List contains list of objects imported from ModSym *) |
| ModSym := LookupModule (OperandTok (n+1), OperandT (n+1)) ; |
| i := 1 ; |
| WHILE i<=n DO |
| Sym := GetExported (OperandTok (i), ModSym, OperandT (i)) ; |
| CheckForEnumerationInCurrentModule (Sym) ; |
| INC (i) |
| END |
| END ; |
| PopN (n+1) (* clear stack *) |
| END PCBuildImportOuterModule ; |
| |
| |
| (* |
| BuildImportInnerModule - Builds imported identifiers into an inner module |
| from the last level of module. |
| |
| The Stack is expected: |
| |
| Entry OR Entry |
| |
| Ptr -> Ptr -> |
| +------------+ +-----------+ |
| | # | | # | |
| |------------| |-----------| |
| | Id1 | | Id1 | |
| |------------| |-----------| |
| . . . . |
| . . . . |
| . . . . |
| |------------| |-----------| |
| | Id# | | Id# | |
| |------------| |-----------| |
| | ImportTok | | Ident | |
| |------------| |-----------| |
| |
| IMPORT Id1, .. Id# ; FROM Ident IMPORT Id1 .. Id# ; |
| |
| Exit |
| |
| All above stack discarded |
| *) |
| |
| PROCEDURE PCBuildImportInnerModule ; |
| VAR |
| Sym, ModSym, |
| n, i : CARDINAL ; |
| BEGIN |
| PopT (n) ; (* i = # of the Ident List *) |
| IF OperandT (n+1) = ImportTok |
| THEN |
| (* Ident List contains list of objects *) |
| i := 1 ; |
| WHILE i<=n DO |
| Sym := GetFromOuterModule (OperandTok (i), OperandT (i)) ; |
| CheckForEnumerationInCurrentModule (Sym) ; |
| INC (i) |
| END |
| ELSE |
| (* Ident List contains list of objects imported from ModSym *) |
| ModSym := LookupOuterModule (OperandTok (n+1), OperandT (n+1)) ; |
| i := 1 ; |
| WHILE i<=n DO |
| Sym := GetExported (OperandTok (i), ModSym, OperandT (i)) ; |
| CheckForEnumerationInCurrentModule (Sym) ; |
| INC (i) |
| END |
| END ; |
| PopN (n+1) (* Clear Stack *) |
| END PCBuildImportInnerModule ; |
| |
| |
| (* |
| StartBuildProcedure - Builds a Procedure. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| <- Ptr |
| +------------+ |
| Ptr -> | ProcSym | |
| +------------+ |------------| |
| | Name | | Name | |
| |------------| |------------| |
| *) |
| |
| PROCEDURE PCStartBuildProcedure ; |
| VAR |
| name : Name ; |
| ProcSym : CARDINAL ; |
| tok : CARDINAL ; |
| BEGIN |
| PopTtok(name, tok) ; |
| PushTtok(name, tok) ; (* Name saved for the EndBuildProcedure name check *) |
| ProcSym := RequestSym (tok, name) ; |
| Assert (IsProcedure (ProcSym)) ; |
| PushTtok (ProcSym, tok) ; |
| StartScope (ProcSym) ; |
| M2Error.EnterProcedureScope (name) |
| END PCStartBuildProcedure ; |
| |
| |
| (* |
| EndBuildProcedure - Ends building a Procedure. |
| It checks the start procedure name matches the end |
| procedure name. |
| |
| The Stack: |
| |
| (Procedure Not Defined in definition module) |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | NameEnd | |
| |------------| |
| | ProcSym | |
| |------------| |
| | NameStart | |
| |------------| |
| Empty |
| *) |
| |
| PROCEDURE PCEndBuildProcedure ; |
| VAR |
| ProcSym : CARDINAL ; |
| NameEnd, |
| NameStart: Name ; |
| BEGIN |
| PopT(NameEnd) ; |
| PopT(ProcSym) ; |
| PopT(NameStart) ; |
| IF NameEnd#NameStart |
| THEN |
| (* we dont issue an error based around incorrect module names this would be done in P1 and P2. |
| If we get here then something has gone wrong with our error recovery in PC, so we bail out. |
| *) |
| WriteFormat0('too many errors in pass 3') ; |
| FlushErrors |
| END ; |
| EndScope ; |
| M2Error.LeaveErrorScope |
| END PCEndBuildProcedure ; |
| |
| |
| (* |
| EndBuildForward - Ends building a forward declaration. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | ProcSym | |
| |------------| |
| | NameStart | |
| |------------| |
| Empty |
| *) |
| |
| PROCEDURE PCEndBuildForward ; |
| BEGIN |
| PopN (2) |
| END PCEndBuildForward ; |
| |
| |
| (* |
| BuildProcedureHeading - Builds a procedure heading for the definition |
| module procedures. |
| |
| Operation only performed if compiling a |
| definition module. |
| |
| The Stack: |
| |
| Entry Exit |
| |
| Ptr -> |
| +------------+ |
| | ProcSym | |
| |------------| |
| | NameStart | |
| |------------| |
| Empty |
| |
| *) |
| |
| PROCEDURE PCBuildProcedureHeading ; |
| VAR |
| ProcSym : CARDINAL ; |
| NameStart: Name ; |
| BEGIN |
| IF CompilingDefinitionModule () |
| THEN |
| PopT (ProcSym) ; |
| PopT (NameStart) ; |
| EndScope |
| END |
| END PCBuildProcedureHeading ; |
| |
| |
| (* |
| BuildNulName - Pushes a NulKey onto the top of the stack. |
| The Stack: |
| |
| |
| Entry Exit |
| |
| <- Ptr |
| Empty +------------+ |
| | NulKey | |
| |------------| |
| *) |
| |
| PROCEDURE BuildNulName ; |
| BEGIN |
| PushT (NulName) |
| END BuildNulName ; |
| |
| |
| (* |
| BuildConst - builds a constant. |
| Stack |
| |
| Entry Exit |
| |
| Ptr -> <- Ptr |
| +------------+ +------------+ |
| | Name | | Sym | |
| |------------+ |------------| |
| *) |
| |
| PROCEDURE BuildConst ; |
| VAR |
| name: Name ; |
| tok : CARDINAL ; |
| Sym : CARDINAL ; |
| BEGIN |
| PopTtok (name, tok) ; |
| Sym := RequestSym (tok, name) ; |
| PushTtok (Sym, tok) |
| END BuildConst ; |
| |
| |
| (* |
| BuildVarAtAddress - updates the symbol table entry of, variable sym, to be declared |
| at address, address. |
| |
| Stack |
| |
| Entry Exit |
| |
| Ptr -> |
| +--------------+ |
| | Expr | EType | <- Ptr |
| |--------------+ +--------------+ |
| | name | SType | | name | SType | |
| |--------------+ |--------------| |
| *) |
| |
| (* |
| PROCEDURE BuildVarAtAddress ; |
| VAR |
| name : Name ; |
| Sym, SType, |
| Exp, EType: CARDINAL ; |
| etok, ntok: CARDINAL ; |
| BEGIN |
| PopTFtok (Exp, EType, etok) ; |
| PopTFtok (name, SType, ntok) ; |
| PushTFtok (name, SType, ntok) ; |
| Sym := RequestSym (ntok, name) ; |
| IF GetMode(Sym)=LeftValue |
| THEN |
| PutVariableAtAddress(Sym, Exp) |
| ELSE |
| InternalError ('expecting lvalue for this variable which is declared at an explicit address') |
| END |
| END BuildVarAtAddress ; |
| *) |
| |
| |
| (* |
| BuildOptArgInitializer - assigns the constant value symbol, const, to be the |
| initial value of the optional parameter should it be |
| absent. |
| |
| Ptr -> |
| +------------+ |
| | const | |
| |------------| <- Ptr |
| *) |
| |
| (* |
| PROCEDURE BuildOptArgInitializer ; |
| VAR |
| const: CARDINAL ; |
| BEGIN |
| PopT(const) ; |
| PutOptArgInit(GetCurrentScope(), const) |
| END BuildOptArgInitializer ; |
| *) |
| |
| |
| (* |
| InitDesExpr - |
| *) |
| |
| PROCEDURE InitDesExpr (des: CARDINAL) ; |
| VAR |
| e: exprNode ; |
| BEGIN |
| NEW (e) ; |
| WITH e^ DO |
| tag := designator ; |
| CASE tag OF |
| |
| designator: WITH edes DO |
| type := NulSym ; |
| meta := unknown ; |
| tag := designator ; |
| sym := des ; |
| left := NIL |
| END |
| |
| ELSE |
| InternalError ('expecting designator') |
| END |
| END ; |
| PushAddress (exprStack, e) |
| END InitDesExpr ; |
| |
| |
| (* |
| DebugNode - |
| *) |
| |
| PROCEDURE DebugNode (d: exprNode) ; |
| BEGIN |
| IF Debugging AND (d#NIL) |
| THEN |
| WITH d^ DO |
| CASE tag OF |
| |
| designator: DebugDes(d) | |
| expr : DebugExpr(d) | |
| leaf : DebugLeaf(d) | |
| unary : DebugUnary(d) | |
| binary : DebugBinary(d) | |
| function : DebugFunction(d) | |
| convert : DebugConvert(d) |
| |
| END |
| END |
| END |
| END DebugNode ; |
| |
| |
| (* |
| DebugDes - |
| *) |
| |
| PROCEDURE DebugDes (d: exprNode) ; |
| BEGIN |
| WITH d^ DO |
| WITH edes DO |
| DebugSym(sym) ; Write(':') ; DebugMeta(meta) ; Write(':') ; DebugType(type) ; |
| WriteString(' = ') ; |
| DebugNode(left) ; |
| WriteLn |
| END |
| END |
| END DebugDes ; |
| |
| |
| (* |
| DebugSym - |
| *) |
| |
| PROCEDURE DebugSym (sym: CARDINAL) ; |
| VAR |
| n: Name ; |
| BEGIN |
| n := GetSymName(sym) ; |
| IF n#NulName |
| THEN |
| WriteKey(n) |
| END ; |
| Write(':') ; WriteCard(sym, 0) |
| END DebugSym ; |
| |
| |
| (* |
| DebugMeta - |
| *) |
| |
| PROCEDURE DebugMeta (m: constType) ; |
| BEGIN |
| CASE m OF |
| |
| unknown : WriteString('unknown') | |
| set : WriteString('set') | |
| str : WriteString('str') | |
| constructor: WriteString('constructor') | |
| array : WriteString('array') | |
| cast : WriteString('cast') | |
| boolean : WriteString('boolean') | |
| ztype : WriteString('ztype') | |
| rtype : WriteString('rtype') | |
| ctype : WriteString('ctype') | |
| procedure : WriteString('procedure') | |
| char : WriteString('ctype') |
| |
| END |
| END DebugMeta ; |
| |
| |
| (* |
| DebugType - |
| *) |
| |
| PROCEDURE DebugType (type: CARDINAL) ; |
| VAR |
| n: Name ; |
| BEGIN |
| WriteString('[type:') ; |
| IF type=NulSym |
| THEN |
| WriteString('<nulsym>') |
| ELSE |
| n := GetSymName(type) ; |
| IF n#NulSym |
| THEN |
| WriteKey(n) |
| END ; |
| Write(':') ; WriteCard(type, 0) |
| END ; |
| Write(']') |
| END DebugType ; |
| |
| |
| (* |
| DebugExpr - |
| *) |
| |
| PROCEDURE DebugExpr (e: exprNode) ; |
| BEGIN |
| WITH e^.eexpr DO |
| WriteString('expr (') ; |
| DebugType(type) ; Write(':') ; |
| DebugMeta(meta) ; Write(' ') ; |
| DebugNode(left) ; |
| WriteString(') ') |
| END |
| END DebugExpr ; |
| |
| |
| (* |
| DebugFunction - |
| *) |
| |
| PROCEDURE DebugFunction (f: exprNode) ; |
| BEGIN |
| WITH f^.efunction DO |
| WriteKey(GetSymName(func)) ; |
| Write('(') ; |
| IF first#NIL |
| THEN |
| DebugNode(first) ; |
| IF second#NIL |
| THEN |
| WriteString(', ') ; |
| DebugNode(second) ; |
| IF third |
| THEN |
| WriteString(', ...') |
| END |
| END |
| END ; |
| Write(')') |
| END |
| END DebugFunction ; |
| |
| |
| (* |
| DebugConvert - |
| *) |
| |
| PROCEDURE DebugConvert (f: exprNode) ; |
| BEGIN |
| WITH f^.econvert DO |
| DebugNode(totype) ; |
| Write('(') ; |
| DebugNode(expr) ; |
| Write(')') |
| END |
| END DebugConvert ; |
| |
| |
| (* |
| DebugLeaf - |
| *) |
| |
| PROCEDURE DebugLeaf (l: exprNode) ; |
| BEGIN |
| WITH l^.eleaf DO |
| WriteString('leaf (') ; |
| DebugType(type) ; Write(':') ; |
| DebugMeta(meta) ; Write(':') ; |
| DebugSym(sym) ; |
| WriteString(') ') |
| END |
| END DebugLeaf ; |
| |
| |
| (* |
| DebugUnary - |
| *) |
| |
| PROCEDURE DebugUnary (l: exprNode) ; |
| BEGIN |
| WITH l^.eunary DO |
| WriteString('unary (') ; |
| DebugType(type) ; Write(':') ; |
| DebugMeta(meta) ; Write(' ') ; |
| DebugOp(op) ; Write(' ') ; |
| DebugNode(left) ; |
| WriteString(') ') |
| END |
| END DebugUnary ; |
| |
| |
| (* |
| DebugBinary - |
| *) |
| |
| PROCEDURE DebugBinary (l: exprNode) ; |
| BEGIN |
| WITH l^.ebinary DO |
| WriteString('unary (') ; |
| DebugType(type) ; Write(':') ; |
| DebugMeta(meta) ; Write(' ') ; |
| DebugNode(left) ; |
| DebugOp(op) ; Write(' ') ; |
| DebugNode(right) ; |
| WriteString(') ') |
| END |
| END DebugBinary ; |
| |
| |
| (* |
| DebugOp - |
| *) |
| |
| PROCEDURE DebugOp (op: Name) ; |
| BEGIN |
| WriteKey(op) |
| END DebugOp ; |
| |
| |
| (* |
| PushInConstructor - |
| *) |
| |
| PROCEDURE PushInConstructor ; |
| BEGIN |
| PushWord(desStack, inDesignator) ; |
| inDesignator := FALSE |
| END PushInConstructor ; |
| |
| |
| (* |
| PopInConstructor - |
| *) |
| |
| PROCEDURE PopInConstructor ; |
| BEGIN |
| inDesignator := PopWord(desStack) |
| END PopInConstructor ; |
| |
| |
| (* |
| StartDesConst - |
| *) |
| |
| PROCEDURE StartDesConst ; |
| VAR |
| name: Name ; |
| tok : CARDINAL ; |
| BEGIN |
| inDesignator := TRUE ; |
| exprStack := KillStackAddress (exprStack) ; |
| exprStack := InitStackAddress () ; |
| PopTtok (name, tok) ; |
| InitDesExpr (RequestSym (tok, name)) |
| END StartDesConst ; |
| |
| |
| (* |
| EndDesConst - |
| *) |
| |
| PROCEDURE EndDesConst ; |
| VAR |
| d, e: exprNode ; |
| BEGIN |
| e := PopAddress (exprStack) ; |
| d := PopAddress (exprStack) ; |
| Assert(d^.tag=designator) ; |
| d^.edes.left := e ; |
| IncludeIndiceIntoIndex(constList, d) ; |
| inDesignator := FALSE |
| END EndDesConst ; |
| |
| |
| (* |
| fixupProcedureType - creates a proctype from a procedure. |
| *) |
| |
| PROCEDURE fixupProcedureType (p: CARDINAL) : CARDINAL ; |
| VAR |
| tok : CARDINAL ; |
| par, |
| t : CARDINAL ; |
| n, i: CARDINAL ; |
| BEGIN |
| IF IsProcedure(p) |
| THEN |
| tok := GetTokenNo () ; |
| t := MakeProcType (tok, CheckAnonymous (NulName)) ; |
| i := 1 ; |
| n := NoOfParamAny (p) ; |
| WHILE i<=n DO |
| par := GetParam (p, i) ; |
| IF IsParameterVar (par) |
| THEN |
| PutProcTypeVarParam (tok, t, GetType (par), IsParameterUnbounded (par)) |
| ELSE |
| PutProcTypeParam (tok, t, GetType (par), IsParameterUnbounded (par)) |
| END ; |
| INC(i) |
| END ; |
| IF GetType (p) # NulSym |
| THEN |
| PutFunction (tok, t, ProperProcedure, GetType (p)) |
| END ; |
| RETURN( t ) |
| ELSE |
| InternalError ('expecting a procedure') |
| END ; |
| RETURN( NulSym ) |
| END fixupProcedureType ; |
| |
| |
| (* |
| InitFunction - |
| *) |
| |
| PROCEDURE InitFunction (m: constType; p, t: CARDINAL; f, s: exprNode; more: BOOLEAN) ; |
| VAR |
| n: exprNode ; |
| BEGIN |
| NEW (n) ; |
| WITH n^ DO |
| tag := function ; |
| CASE tag OF |
| |
| function: WITH efunction DO |
| meta := m ; |
| type := t ; |
| func := p ; |
| first := f ; |
| second := s ; |
| third := more |
| END |
| |
| ELSE |
| InternalError ('expecting function') |
| END |
| END ; |
| PushAddress (exprStack, n) |
| END InitFunction ; |
| |
| |
| (* |
| InitConvert - |
| *) |
| |
| PROCEDURE InitConvert (m: constType; t: CARDINAL; to, e: exprNode) ; |
| VAR |
| n: exprNode ; |
| BEGIN |
| NEW(n) ; |
| WITH n^ DO |
| tag := convert ; |
| CASE tag OF |
| |
| convert: WITH econvert DO |
| type := t ; |
| meta := m ; |
| totype := to ; |
| expr := e |
| END |
| |
| ELSE |
| InternalError ('expecting convert') |
| END |
| END ; |
| PushAddress(exprStack, n) |
| END InitConvert ; |
| |
| |
| (* |
| InitLeaf - |
| *) |
| |
| PROCEDURE InitLeaf (m: constType; s, t: CARDINAL) ; |
| VAR |
| l: exprNode ; |
| BEGIN |
| NEW (l) ; |
| WITH l^ DO |
| tag := leaf ; |
| CASE tag OF |
| |
| leaf: WITH eleaf DO |
| type := t ; |
| meta := m ; |
| sym := s |
| END |
| |
| ELSE |
| InternalError ('expecting leaf') |
| END |
| END ; |
| PushAddress (exprStack, l) |
| END InitLeaf ; |
| |
| |
| (* |
| InitProcedure - |
| *) |
| |
| PROCEDURE InitProcedure (s: CARDINAL) ; |
| BEGIN |
| InitLeaf(procedure, s, fixupProcedureType(s)) |
| END InitProcedure ; |
| |
| |
| (* |
| InitCharType - |
| *) |
| |
| PROCEDURE InitCharType (s: CARDINAL) ; |
| BEGIN |
| InitLeaf(char, s, Char) |
| END InitCharType ; |
| |
| |
| (* |
| InitZType - |
| *) |
| |
| PROCEDURE InitZType (s: CARDINAL) ; |
| BEGIN |
| InitLeaf(ztype, s, ZType) |
| END InitZType ; |
| |
| |
| (* |
| InitRType - |
| *) |
| |
| PROCEDURE InitRType (s: CARDINAL) ; |
| BEGIN |
| InitLeaf(rtype, s, RType) |
| END InitRType ; |
| |
| |
| (* |
| InitUnknown - |
| *) |
| |
| PROCEDURE InitUnknown (s: CARDINAL) ; |
| BEGIN |
| InitLeaf(unknown, s, NulSym) |
| END InitUnknown ; |
| |
| |
| (* |
| InitBooleanType - |
| *) |
| |
| PROCEDURE InitBooleanType (s: CARDINAL) ; |
| BEGIN |
| InitLeaf(boolean, s, Boolean) |
| END InitBooleanType ; |
| |
| |
| (* |
| PushConstType - pushes a constant to the expression stack. |
| *) |
| |
| PROCEDURE PushConstType ; |
| VAR |
| c: CARDINAL ; |
| BEGIN |
| PopT(c) ; |
| PushT(c) ; |
| IF inDesignator |
| THEN |
| IF c=NulSym |
| THEN |
| WriteFormat0('module or symbol in qualident is not known') ; |
| FlushErrors ; |
| InitUnknown(c) |
| ELSIF IsProcedure(c) |
| THEN |
| InitProcedure(c) |
| ELSIF GetSkippedType(c)=RType |
| THEN |
| InitRType(c) |
| ELSIF GetSkippedType(c)=ZType |
| THEN |
| InitZType(c) |
| ELSIF GetSkippedType(c)=Boolean |
| THEN |
| InitBooleanType(c) |
| ELSE |
| InitUnknown(c) |
| END |
| END |
| END PushConstType ; |
| |
| |
| (* |
| PushConstructorCastType - |
| *) |
| |
| PROCEDURE PushConstructorCastType ; |
| BEGIN |
| IF inDesignator |
| THEN |
| InitConvert (cast, OperandT (1), NIL, NIL) |
| END |
| END PushConstructorCastType ; |
| |
| |
| (* |
| TypeToMeta - |
| *) |
| |
| PROCEDURE TypeToMeta (type: CARDINAL) : constType ; |
| BEGIN |
| IF type=Char |
| THEN |
| RETURN char |
| ELSIF type=Boolean |
| THEN |
| RETURN boolean |
| ELSIF IsRealType (type) |
| THEN |
| RETURN rtype |
| ELSIF IsComplexType (type) |
| THEN |
| RETURN ctype |
| ELSIF IsOrdinalType (type) |
| THEN |
| RETURN ztype |
| ELSE |
| RETURN unknown |
| END |
| END TypeToMeta ; |
| |
| |
| (* |
| buildConstFunction - we are only concerned about resolving the return type of |
| a function, so we can ignore all parameters - except |
| the first one in the case of VAL(type, foo) |
| and the type of bar in MIN (bar) and MAX (bar). |
| buildConstFunction uses a unary exprNode to represent |
| a function. |
| *) |
| |
| PROCEDURE buildConstFunction (func: CARDINAL; n: CARDINAL) ; |
| VAR |
| i : CARDINAL ; |
| first, |
| second: exprNode ; |
| BEGIN |
| first := NIL ; |
| second := NIL ; |
| IF n=1 |
| THEN |
| first := PopAddress (exprStack) |
| ELSIF n>=2 |
| THEN |
| i := n ; |
| WHILE i>2 DO |
| second := PopAddress (exprStack) ; |
| DISPOSE (second) ; |
| DEC (i) |
| END ; |
| second := PopAddress (exprStack) ; |
| first := PopAddress (exprStack) |
| END ; |
| IF (func=Val) OR (func=Cast) |
| THEN |
| InitConvert (cast, NulSym, first, second) |
| ELSIF (func=Max) OR (func=Min) |
| THEN |
| InitFunction (unknown, func, NulSym, first, second, FALSE) |
| ELSE |
| InitFunction (TypeToMeta(GetSkippedType(func)), func, GetSkippedType(func), |
| first, second, n>2) |
| END |
| END buildConstFunction ; |
| |
| |
| (* |
| ErrorConstFunction - generate an error message at functok using func in the |
| error message providing it is not NulSym. |
| *) |
| |
| PROCEDURE ErrorConstFunction (func: CARDINAL; functok: CARDINAL) ; |
| BEGIN |
| IF func = NulSym |
| THEN |
| IF Iso |
| THEN |
| ErrorFormat0 (NewError (functok), |
| 'the only functions permissible in a constant expression are: CAP, CAST, CHR, CMPLX, FLOAT, HIGH, IM, LENGTH, MAX, MIN, ODD, ORD, RE, SIZE, TSIZE, TRUNC, VAL and gcc builtins') |
| ELSE |
| ErrorFormat0 (NewError (functok), |
| 'the only functions permissible in a constant expression are: CAP, CHR, FLOAT, HIGH, MAX, MIN, ODD, ORD, SIZE, TSIZE, TRUNC, VAL and gcc builtins') |
| END |
| ELSE |
| IF Iso |
| THEN |
| MetaErrorT1 (functok, |
| 'the only functions permissible in a constant expression are: CAP, CAST, CHR, CMPLX, FLOAT, HIGH, IM, LENGTH, MAX, MIN, ODD, ORD, RE, SIZE, TSIZE, TRUNC, VAL and gcc builtins, but not {%1Ead}', |
| func) |
| ELSE |
| MetaErrorT1 (functok, |
| 'the only functions permissible in a constant expression are: CAP, CHR, FLOAT, HIGH, MAX, MIN, ODD, ORD, SIZE, TSIZE, TRUNC, VAL and gcc builtins, but not {%1Ead}', |
| func) |
| END |
| END |
| END ErrorConstFunction ; |
| |
| |
| (* |
| PushConstFunctionType - |
| *) |
| |
| PROCEDURE PushConstFunctionType ; |
| VAR |
| functok, |
| func : CARDINAL ; |
| n : CARDINAL ; |
| BEGIN |
| PopT (n) ; |
| PopTtok (func, functok) ; |
| IF inDesignator |
| THEN |
| IF func = NulSym |
| THEN |
| ErrorConstFunction (func, functok) |
| ELSIF (func#Convert) AND |
| (IsPseudoBaseFunction(func) OR |
| IsPseudoSystemFunctionConstExpression(func) OR |
| (IsProcedure(func) AND IsProcedureBuiltin(func))) |
| THEN |
| buildConstFunction (func, n) |
| ELSIF IsAModula2Type(func) |
| THEN |
| IF n=1 |
| THEN |
| (* the top element on the expression stack is the first and only parameter to the cast *) |
| InitUnary(cast, func, GetSymName(func)) |
| ELSE |
| WriteFormat0('a constant type conversion can only have one argument') |
| END |
| ELSE |
| ErrorConstFunction (func, functok) |
| END |
| END ; |
| PushTtok (func, functok) |
| END PushConstFunctionType ; |
| |
| |
| (* |
| PushIntegerType - |
| *) |
| |
| PROCEDURE PushIntegerType ; |
| VAR |
| sym: CARDINAL ; |
| m : constType ; |
| BEGIN |
| PopT(sym) ; |
| IF inDesignator |
| THEN |
| m := TypeToMeta(GetSkippedType(sym)) ; |
| IF m=char |
| THEN |
| InitCharType(sym) |
| ELSE |
| InitZType(sym) |
| END |
| END |
| END PushIntegerType ; |
| |
| |
| (* |
| PushRType - |
| *) |
| |
| PROCEDURE PushRType ; |
| VAR |
| sym: CARDINAL ; |
| BEGIN |
| PopT(sym) ; |
| IF inDesignator |
| THEN |
| InitRType(sym) |
| END |
| END PushRType ; |
| |
| |
| (* |
| PushStringType - |
| *) |
| |
| PROCEDURE PushStringType ; |
| VAR |
| sym: CARDINAL ; |
| BEGIN |
| PopT(sym) ; |
| IF inDesignator |
| THEN |
| InitLeaf(str, sym, NulSym) |
| END |
| END PushStringType ; |
| |
| |
| (* |
| InitBinary - |
| *) |
| |
| PROCEDURE InitBinary (m: constType; t: CARDINAL; o: Name) ; |
| VAR |
| l, r, b: exprNode ; |
| BEGIN |
| r := PopAddress (exprStack) ; |
| l := PopAddress (exprStack) ; |
| NEW (b) ; |
| WITH b^ DO |
| tag := binary ; |
| CASE tag OF |
| |
| binary: WITH ebinary DO |
| meta := m ; |
| type := t ; |
| left := l ; |
| right := r ; |
| op := o |
| END |
| ELSE |
| InternalError ('expecting binary') |
| END |
| END ; |
| PushAddress (exprStack, b) |
| END InitBinary ; |
| |
| |
| (* |
| BuildRelationConst - builds a relationship binary operation. |
| *) |
| |
| PROCEDURE BuildRelationConst ; |
| VAR |
| op: Name ; |
| BEGIN |
| PopT (op) ; |
| IF inDesignator |
| THEN |
| InitBinary (boolean, Boolean, op) |
| END |
| END BuildRelationConst ; |
| |
| |
| (* |
| BuildBinaryConst - builds a binary operator node. |
| *) |
| |
| PROCEDURE BuildBinaryConst ; |
| VAR |
| op: Name ; |
| BEGIN |
| PopT (op) ; |
| IF inDesignator |
| THEN |
| InitBinary (unknown, NulSym, op) |
| END |
| END BuildBinaryConst ; |
| |
| |
| (* |
| InitUnary - |
| *) |
| |
| PROCEDURE InitUnary (m: constType; t: CARDINAL; o: Name) ; |
| VAR |
| l, b: exprNode ; |
| BEGIN |
| l := PopAddress(exprStack) ; |
| NEW(b) ; |
| WITH b^ DO |
| tag := unary ; |
| CASE tag OF |
| |
| unary: WITH eunary DO |
| meta := m ; |
| type := t ; |
| left := l ; |
| op := o |
| END |
| |
| ELSE |
| InternalError ('expecting unary') |
| END |
| END ; |
| PushAddress(exprStack, b) |
| END InitUnary ; |
| |
| |
| (* |
| BuildUnaryConst - builds a unary operator node. |
| *) |
| |
| PROCEDURE BuildUnaryConst ; |
| VAR |
| op: Name ; |
| BEGIN |
| PopT(op) ; |
| IF inDesignator |
| THEN |
| InitUnary(unknown, NulSym, op) |
| END |
| END BuildUnaryConst ; |
| |
| |
| (* |
| isTypeResolved - |
| *) |
| |
| PROCEDURE isTypeResolved (e: exprNode) : BOOLEAN ; |
| BEGIN |
| WITH e^ DO |
| CASE tag OF |
| |
| leaf : RETURN( (eleaf.type#NulSym) OR (eleaf.meta=str) ) | |
| unary : RETURN( (eunary.type#NulSym) OR (eunary.meta=str) ) | |
| binary : RETURN( (ebinary.type#NulSym) OR (ebinary.meta=str) ) | |
| designator: RETURN( (edes.type#NulSym) OR (edes.meta=str) ) | |
| expr : RETURN( (eexpr.type#NulSym) OR (eexpr.meta=str) ) | |
| convert : RETURN( (econvert.type#NulSym) OR (econvert.meta=str) ) | |
| function : RETURN( (efunction.type#NulSym) OR (efunction.meta=str) ) |
| |
| END |
| END |
| END isTypeResolved ; |
| |
| |
| (* |
| getEtype - |
| *) |
| |
| PROCEDURE getEtype (e: exprNode) : CARDINAL ; |
| BEGIN |
| WITH e^ DO |
| CASE tag OF |
| |
| leaf : RETURN( eleaf.type ) | |
| unary : RETURN( eunary.type ) | |
| binary : RETURN( ebinary.type ) | |
| designator: RETURN( edes.type ) | |
| expr : RETURN( eexpr.type ) | |
| convert : RETURN( econvert.type ) | |
| function : RETURN( efunction.type ) |
| |
| END |
| END |
| END getEtype ; |
| |
| |
| (* |
| getEmeta - |
| *) |
| |
| PROCEDURE getEmeta (e: exprNode) : constType ; |
| BEGIN |
| WITH e^ DO |
| CASE tag OF |
| |
| leaf : RETURN( eleaf.meta ) | |
| unary : RETURN( eunary.meta ) | |
| binary : RETURN( ebinary.meta ) | |
| designator: RETURN( edes.meta ) | |
| expr : RETURN( eexpr.meta ) | |
| convert : RETURN( econvert.meta ) | |
| function : RETURN( efunction.meta ) |
| |
| END |
| END |
| END getEmeta ; |
| |
| |
| (* |
| assignTM - |
| *) |
| |
| PROCEDURE assignTM (VAR td: CARDINAL; VAR md: constType; te: CARDINAL; me: constType) ; |
| BEGIN |
| md := me ; |
| td := te |
| END assignTM ; |
| |
| |
| (* |
| assignType - |
| *) |
| |
| PROCEDURE assignType (d, e: exprNode) ; |
| VAR |
| t: CARDINAL ; |
| m: constType ; |
| BEGIN |
| m := getEmeta(e) ; |
| t := getEtype(e) ; |
| WITH d^ DO |
| CASE tag OF |
| |
| leaf : assignTM(eleaf.type, eleaf.meta, t, m) | |
| unary : assignTM(eunary.type, eunary.meta, t, m) | |
| binary : assignTM(ebinary.type, ebinary.meta, t, m) | |
| designator: assignTM(edes.type, edes.meta, t, m) | |
| expr : assignTM(eexpr.type, eexpr.meta, t, m) | |
| convert : assignTM(econvert.type, econvert.meta, t, m) | |
| function : assignTM(efunction.type, efunction.meta, t, m) |
| |
| END |
| END |
| END assignType ; |
| |
| |
| (* |
| deduceTypes - works out the type and metatype given, l, and, r. |
| *) |
| |
| PROCEDURE deduceTypes (VAR t: CARDINAL; |
| VAR m: constType; |
| l, r: exprNode; op: Name) ; |
| BEGIN |
| IF r=NIL |
| THEN |
| (* function or cast *) |
| t := getEtype(l) ; |
| m := getEmeta(l) |
| ELSIF (op=EqualTok) OR (op=HashTok) OR (op=LessGreaterTok) OR |
| (op=LessTok) OR (op=LessEqualTok) OR (op=GreaterTok) OR |
| (op=GreaterEqualTok) OR (op=InTok) OR (op=OrTok) OR |
| (op=AndTok) OR (op=NotTok) OR (op=AmbersandTok) |
| THEN |
| t := Boolean ; |
| m := boolean |
| ELSIF (op=PlusTok) OR (op=MinusTok) OR (op=TimesTok) OR (op=ModTok) OR |
| (op=DivTok) OR (op=RemTok) OR (op=DivideTok) |
| THEN |
| t := MixTypes(getEtype(l), getEtype(r), constToken) ; |
| m := getEmeta(l) ; |
| IF m=unknown |
| THEN |
| m := getEmeta(r) |
| ELSIF (getEmeta(r)#unknown) AND (m#getEmeta(r)) |
| THEN |
| ErrorFormat0(NewError(constToken), |
| 'the operands to a binary constant expression have different types') |
| END |
| ELSE |
| InternalError ('unexpected operator') |
| END |
| END deduceTypes ; |
| |
| |
| (* |
| WalkConvert - |
| *) |
| |
| PROCEDURE WalkConvert (e: exprNode) : BOOLEAN ; |
| BEGIN |
| IF isTypeResolved(e) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| WITH e^.econvert DO |
| IF isTypeResolved(totype) |
| THEN |
| assignType(e, totype) ; |
| RETURN( TRUE ) |
| END ; |
| RETURN( doWalkNode(totype) ) |
| END |
| END |
| END WalkConvert ; |
| |
| |
| (* |
| WalkFunctionParam - |
| *) |
| |
| PROCEDURE WalkFunctionParam (func: CARDINAL; e: exprNode) : BOOLEAN ; |
| BEGIN |
| IF isTypeResolved(e) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| IF e^.tag=leaf |
| THEN |
| WITH e^.eleaf DO |
| IF (sym#NulSym) AND (type=NulSym) |
| THEN |
| IF (func=Min) OR (func=Max) |
| THEN |
| IF IsSet (sym) OR (IsType (sym) AND IsSet (SkipType (sym))) |
| THEN |
| type := GetType (SkipType (sym)) |
| ELSE |
| (* sym is the type required for MAX, MIN and VAL. *) |
| type := sym |
| END |
| ELSE |
| Assert(func=Val) ; |
| type := sym |
| END ; |
| meta := TypeToMeta(sym) ; |
| RETURN( TRUE ) |
| END |
| END |
| END |
| END ; |
| RETURN( FALSE ) |
| END WalkFunctionParam ; |
| |
| |
| (* |
| WalkFunction - |
| *) |
| |
| PROCEDURE WalkFunction (e: exprNode) : BOOLEAN ; |
| BEGIN |
| IF isTypeResolved(e) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| WITH e^.efunction DO |
| IF (func=Max) OR (func=Min) OR (func=Val) |
| THEN |
| IF isTypeResolved(first) |
| THEN |
| IF getEmeta(first)=str |
| THEN |
| MetaError1('a string parameter cannot be passed to function {%1Dad}', func) ; |
| RETURN( FALSE ) |
| END ; |
| type := getEtype(first) ; |
| RETURN( TRUE ) |
| END ; |
| RETURN WalkFunctionParam (func, first) |
| ELSE |
| MetaError1('not expecting this function inside a constant expression {%1Dad}', func) |
| END |
| END ; |
| RETURN( TRUE ) |
| END |
| END WalkFunction ; |
| |
| |
| (* |
| doWalkNode - |
| *) |
| |
| PROCEDURE doWalkNode (e: exprNode) : BOOLEAN ; |
| BEGIN |
| WITH e^ DO |
| CASE tag OF |
| |
| expr : RETURN( WalkExpr(e) ) | |
| leaf : RETURN( WalkLeaf(e) ) | |
| unary : RETURN( WalkUnary(e) ) | |
| binary : RETURN( WalkBinary(e) ) | |
| convert : RETURN( WalkConvert(e) ) | |
| function: RETURN( WalkFunction(e) ) |
| |
| ELSE |
| InternalError ('unexpected tag value') |
| END |
| END ; |
| RETURN( FALSE ) |
| END doWalkNode ; |
| |
| |
| (* |
| WalkLeaf - |
| *) |
| |
| PROCEDURE WalkLeaf (e: exprNode) : BOOLEAN ; |
| VAR |
| c: exprNode ; |
| BEGIN |
| IF isTypeResolved(e) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| WITH e^.eleaf DO |
| IF IsConst(sym) AND (GetType(sym)#NulSym) |
| THEN |
| type := GetSkippedType(sym) ; |
| RETURN( TRUE ) |
| END ; |
| IF IsAModula2Type(sym) |
| THEN |
| type := sym ; |
| RETURN( TRUE ) |
| END ; |
| c := findConstDes(sym) ; |
| IF (c#NIL) AND isTypeResolved(c) |
| THEN |
| assignType(e, c) ; |
| RETURN( TRUE ) |
| END |
| END |
| END ; |
| RETURN( FALSE ) |
| END WalkLeaf ; |
| |
| |
| (* |
| WalkUnary - |
| *) |
| |
| PROCEDURE WalkUnary (e: exprNode) : BOOLEAN ; |
| BEGIN |
| IF isTypeResolved(e) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| WITH e^.eunary DO |
| IF isTypeResolved(left) |
| THEN |
| deduceTypes(type, meta, left, left, op) ; |
| RETURN( TRUE ) |
| END ; |
| RETURN( doWalkNode(left) ) |
| END |
| END |
| END WalkUnary ; |
| |
| |
| (* |
| WalkBinary - |
| *) |
| |
| PROCEDURE WalkBinary (e: exprNode) : BOOLEAN ; |
| VAR |
| changed: BOOLEAN ; |
| BEGIN |
| IF isTypeResolved(e) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| WITH e^.ebinary DO |
| IF isTypeResolved(left) AND isTypeResolved(right) |
| THEN |
| deduceTypes(type, meta, left, right, op) ; |
| RETURN( TRUE ) |
| END ; |
| changed := doWalkNode(left) ; |
| RETURN( doWalkNode(right) OR changed ) |
| END |
| END |
| END WalkBinary ; |
| |
| |
| (* |
| WalkExpr - |
| *) |
| |
| PROCEDURE WalkExpr (e: exprNode) : BOOLEAN ; |
| BEGIN |
| IF isTypeResolved(e) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| WITH e^.eexpr DO |
| IF isTypeResolved(left) |
| THEN |
| assignType(e, left) ; |
| RETURN( TRUE ) |
| END ; |
| RETURN( doWalkNode(left) ) |
| END |
| END |
| END WalkExpr ; |
| |
| |
| (* |
| doWalkDesExpr - returns TRUE if the expression trees, d, or, e, are changed. |
| *) |
| |
| PROCEDURE doWalkDesExpr (d, e: exprNode) : BOOLEAN ; |
| BEGIN |
| IF isTypeResolved(e) |
| THEN |
| WITH d^.edes DO |
| type := getEtype(e) ; |
| IF type=NulSym |
| THEN |
| meta := getEmeta(e) ; |
| IF meta=str |
| THEN |
| (* PutConstString(sym, getString(e)) *) |
| END |
| ELSE |
| PutConst(sym, type) |
| END ; |
| RETURN( TRUE ) |
| END |
| END ; |
| RETURN( doWalkNode(e) ) |
| END doWalkDesExpr ; |
| |
| |
| (* |
| doWalkDes - return TRUE if expression, e, is changed. |
| *) |
| |
| PROCEDURE doWalkDes (d: exprNode) : BOOLEAN ; |
| BEGIN |
| IF isTypeResolved(d) |
| THEN |
| RETURN( FALSE ) |
| ELSE |
| WITH d^ DO |
| CASE tag OF |
| |
| designator: WITH edes DO |
| constToken := GetDeclaredMod(sym) ; |
| RETURN( doWalkDesExpr(d, left) ) |
| END |
| |
| ELSE |
| InternalError ('unexpected tag value') |
| END |
| END |
| END |
| END doWalkDes ; |
| |
| |
| (* |
| findConstDes - |
| *) |
| |
| PROCEDURE findConstDes (sym: CARDINAL) : exprNode ; |
| VAR |
| i: CARDINAL ; |
| e: exprNode ; |
| BEGIN |
| i := 1 ; |
| WHILE i<=HighIndice(constList) DO |
| e := GetIndice(constList, i) ; |
| WITH e^ DO |
| CASE tag OF |
| |
| designator: IF edes.sym=sym |
| THEN |
| RETURN( e ) |
| END |
| |
| ELSE |
| END |
| END ; |
| INC(i) |
| END ; |
| RETURN( NIL ) |
| END findConstDes ; |
| |
| |
| (* |
| WalkDes - return TRUE if expression, e, is changed. |
| *) |
| |
| PROCEDURE WalkDes (d: exprNode) : BOOLEAN ; |
| BEGIN |
| IF d=NIL |
| THEN |
| RETURN FALSE |
| ELSE |
| IF Debugging |
| THEN |
| DebugDes (d) |
| END ; |
| RETURN doWalkDes (d) |
| END |
| END WalkDes ; |
| |
| |
| (* |
| WalkConst - returns TRUE if the constant tree associated with, sym, |
| is changed. |
| *) |
| |
| (* |
| PROCEDURE WalkConst (sym: CARDINAL) : BOOLEAN ; |
| BEGIN |
| RETURN( WalkDes(findConstDes(sym)) ) |
| END WalkConst ; |
| *) |
| |
| |
| (* |
| WalkConsts - walk over the constant trees and return TRUE if any tree was changed. |
| (As a result of a type resolution). |
| *) |
| |
| PROCEDURE WalkConsts () : BOOLEAN ; |
| VAR |
| changed: BOOLEAN ; |
| i : CARDINAL ; |
| BEGIN |
| changed := FALSE ; |
| i := 1 ; |
| WHILE i<=HighIndice(constList) DO |
| IF WalkDes(GetIndice(constList, i)) |
| THEN |
| changed := TRUE |
| END ; |
| INC(i) |
| END ; |
| RETURN( changed ) |
| END WalkConsts ; |
| |
| |
| (* |
| DebugNodes - |
| *) |
| |
| PROCEDURE DebugNodes ; |
| VAR |
| i: CARDINAL ; |
| BEGIN |
| i := 1 ; |
| WHILE i<=HighIndice(constList) DO |
| IF isTypeResolved(GetIndice(constList, i)) |
| THEN |
| WriteString('resolved ') |
| ELSE |
| WriteString('unresolved ') |
| END ; |
| DebugNode(GetIndice(constList, i)) ; WriteLn ; |
| INC(i) |
| END |
| END DebugNodes ; |
| |
| |
| (* |
| findAlias - |
| *) |
| |
| PROCEDURE findAlias (sym: CARDINAL; e: exprNode) : CARDINAL ; |
| BEGIN |
| CASE e^.tag OF |
| |
| designator: RETURN( findAlias(sym, e^.edes.left) ) | |
| leaf : RETURN( e^.eleaf.sym ) | |
| expr : RETURN( findAlias(sym, e^.eexpr.left) ) | |
| unary, |
| binary : RETURN( sym ) |
| |
| ELSE |
| InternalError ('not expecting this tag value') |
| END |
| END findAlias ; |
| |
| |
| (* |
| SkipConst - returns an alias to constant, sym, if one exists. |
| Otherwise sym is returned. |
| *) |
| |
| PROCEDURE SkipConst (sym: CARDINAL) : CARDINAL ; |
| VAR |
| i: CARDINAL ; |
| e: exprNode ; |
| BEGIN |
| i := 1 ; |
| WHILE i<=HighIndice(constList) DO |
| e := GetIndice(constList, i) ; |
| IF (e^.tag=designator) AND (e^.edes.sym=sym) |
| THEN |
| RETURN( findAlias(sym, e) ) |
| END ; |
| INC(i) |
| END ; |
| RETURN( sym ) |
| END SkipConst ; |
| |
| |
| (* |
| PushConstAttributeType - |
| *) |
| |
| PROCEDURE PushConstAttributeType ; |
| VAR |
| n: Name ; |
| BEGIN |
| PopT(n) ; |
| PushT(n) ; |
| InitZType(NulSym) ; |
| IF (n=MakeKey('BITS_PER_UNIT')) OR (n=MakeKey('BITS_PER_WORD')) OR |
| (n=MakeKey('BITS_PER_CHAR')) OR (n=MakeKey('UNITS_PER_WORD')) |
| THEN |
| (* all ok *) |
| ELSE |
| WriteFormat1("unknown constant attribute value '%a'", n) |
| END |
| END PushConstAttributeType ; |
| |
| |
| (* |
| PushConstAttributePairType - |
| *) |
| |
| PROCEDURE PushConstAttributePairType ; |
| VAR |
| q, n: Name ; |
| BEGIN |
| PopT(n) ; |
| PopT(q) ; |
| PushT(q) ; |
| PushT(n) ; |
| IF (n=MakeKey('IEC559')) OR (n=MakeKey('LIA1')) OR (n=MakeKey('IEEE')) OR |
| (n=MakeKey('ISO')) OR (n=MakeKey('rounds')) OR (n=MakeKey('gUnderflow')) OR |
| (n=MakeKey('exception')) OR (n=MakeKey('extend')) |
| THEN |
| InitBooleanType(NulSym) |
| ELSIF (n=MakeKey('radix')) OR (n=MakeKey('places')) OR (n=MakeKey('expoMin')) OR |
| (n=MakeKey('expoMax')) OR (n=MakeKey('nModes')) |
| THEN |
| InitZType(NulSym) |
| ELSIF (n=MakeKey('large')) OR (n=MakeKey('small')) |
| THEN |
| InitRType(NulSym) |
| ELSE |
| WriteFormat1("unknown constant attribute value '%a'", n) ; |
| InitUnknown(NulSym) |
| END |
| END PushConstAttributePairType ; |
| |
| |
| (* |
| CheckConsts - |
| *) |
| |
| PROCEDURE CheckConsts ; |
| VAR |
| i: CARDINAL ; |
| e: exprNode ; |
| BEGIN |
| i := 1 ; |
| WHILE i<=HighIndice(constList) DO |
| e := GetIndice(constList, i) ; |
| IF NOT isTypeResolved(e) |
| THEN |
| WITH e^ DO |
| CASE tag OF |
| |
| designator: MetaError1('the type of the constant declaration {%1Dad} cannot be determined', edes.sym) |
| |
| ELSE |
| END |
| END |
| END ; |
| INC(i) |
| END |
| END CheckConsts ; |
| |
| |
| (* |
| ResolveConstTypes - resolves the types of all designator declared constants. |
| *) |
| |
| PROCEDURE ResolveConstTypes ; |
| BEGIN |
| IF Debugging |
| THEN |
| WriteString('initially') ; WriteLn ; |
| DebugNodes |
| END ; |
| WHILE WalkConsts() DO |
| IF Debugging |
| THEN |
| WriteString('iteration') ; WriteLn ; |
| DebugNodes |
| END |
| END ; |
| IF Debugging |
| THEN |
| WriteString('finally') ; WriteLn ; |
| DebugNodes |
| END ; |
| CheckConsts |
| END ResolveConstTypes ; |
| |
| |
| (* |
| Init - |
| *) |
| |
| PROCEDURE Init ; |
| BEGIN |
| exprStack := InitStackAddress () ; |
| constList := InitIndex (1) ; |
| desStack := InitStackWord () ; |
| inDesignator := FALSE |
| END Init ; |
| |
| |
| BEGIN |
| Init |
| END PCSymBuild. |