1 (* PCSymBuild.mod pass C symbol creation.
3 Copyright (C) 2001-2023 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Modula-2; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. *)
22 IMPLEMENTATION MODULE PCSymBuild ;
25 FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
26 FROM NameKey IMPORT Name, WriteKey, MakeKey, NulName ;
27 FROM StrIO IMPORT WriteString, WriteLn ;
28 FROM NumberIO IMPORT WriteCard ;
29 FROM M2Debug IMPORT Assert, WriteDebug ;
30 FROM M2Error IMPORT WriteFormat0, WriteFormat1, WriteFormat2, FlushErrors, InternalError, NewError, ErrorFormat0 ;
31 FROM M2MetaError IMPORT MetaError1, MetaErrorT1 ;
32 FROM M2LexBuf IMPORT GetTokenNo ;
33 FROM M2Reserved IMPORT NulTok, ImportTok ;
34 FROM M2Const IMPORT constType ;
35 FROM Indexing IMPORT Index, InitIndex, GetIndice, PutIndice, InBounds, IncludeIndiceIntoIndex, HighIndice ;
37 FROM M2Quads IMPORT PushT, PopT, OperandT, PopN, PopTF, PushTF, IsAutoPushOn,
38 PopNothing, PushTFn, PopTFn, PushTtok, PopTtok, PushTFtok, PopTFtok, OperandTok ;
40 FROM M2Options IMPORT Iso ;
41 FROM StdIO IMPORT Write ;
42 FROM M2System IMPORT IsPseudoSystemFunctionConstExpression ;
44 FROM M2Base IMPORT MixTypes,
45 ZType, RType, Char, Boolean, Val, Max, Min, Convert,
46 IsPseudoBaseFunction, IsRealType, IsComplexType, IsOrdinalType ;
48 FROM M2Reserved IMPORT PlusTok, MinusTok, TimesTok, DivTok, ModTok,
50 OrTok, AndTok, AmbersandTok,
51 EqualTok, LessEqualTok, GreaterEqualTok,
52 LessTok, GreaterTok, HashTok, LessGreaterTok,
55 FROM SymbolTable IMPORT NulSym, ModeOfAddr,
56 StartScope, EndScope, GetScope, GetCurrentScope,
58 SetCurrentModule, GetCurrentModule, SetFileModule,
62 IsProcedure, PutOptArgInit, IsEnumeration,
63 CheckForUnknownInModule,
65 CheckForEnumerationInCurrentModule,
66 GetMode, PutVariableAtAddress, ModeOfAddr, SkipType,
68 IsConst, IsConstructor, PutConst, PutConstructor,
70 MakeTemporary, PutVar,
78 IsParameterVar, PutProcTypeParam,
79 PutProcTypeVarParam, IsParameterUnbounded,
80 PutFunction, PutProcTypeParam,
82 IsAModula2Type, GetDeclaredMod ;
84 FROM M2Batch IMPORT MakeDefinitionSource,
85 MakeImplementationSource,
87 LookupModule, LookupOuterModule ;
89 FROM M2Comp IMPORT CompilingDefinitionModule,
90 CompilingImplementationModule,
91 CompilingProgramModule ;
93 FROM M2StackAddress IMPORT StackOfAddress, InitStackAddress, KillStackAddress,
94 PushAddress, PopAddress, PeepAddress,
95 IsEmptyAddress, NoOfItemsInStackAddress ;
97 FROM M2StackWord IMPORT StackOfWord, InitStackWord, KillStackWord,
98 PushWord, PopWord, PeepWord,
99 IsEmptyWord, NoOfItemsInStackWord ;
108 tagType = (leaf, unary, binary, designator, expr, convert, function) ;
110 exprNode = POINTER TO eNode ;
165 designator: edes : eDes |
166 leaf : eleaf : eLeaf |
167 unary : eunary : eUnary |
168 binary : ebinary : eBinary |
169 expr : eexpr : eExpr |
170 function : efunction: eFunction |
171 convert : econvert : eConvert
178 exprStack : StackOfAddress ;
180 constToken : CARDINAL ;
181 desStack : StackOfWord ;
182 inDesignator: BOOLEAN ;
189 PROCEDURE GetSkippedType (sym: CARDINAL) : CARDINAL ;
191 RETURN( SkipType(GetType(sym)) )
196 StartBuildDefinitionModule - Creates a definition module and starts
199 The Stack is expected:
204 +------------+ +-----------+
205 | NameStart | | NameStart |
206 |------------| |-----------|
210 PROCEDURE PCStartBuildDefModule ;
214 ModuleSym: CARDINAL ;
217 ModuleSym := MakeDefinitionSource(tok, name) ;
218 SetCurrentModule(ModuleSym) ;
219 SetFileModule(ModuleSym) ;
220 StartScope(ModuleSym) ;
221 Assert(IsDefImp(ModuleSym)) ;
222 Assert(CompilingDefinitionModule()) ;
224 M2Error.EnterDefinitionScope (name)
225 END PCStartBuildDefModule ;
229 EndBuildDefinitionModule - Destroys the definition module scope and
230 checks for correct name.
232 The Stack is expected:
237 +------------+ +-----------+
239 |------------| |-----------|
240 | NameStart | | | <- Ptr
241 |------------| |-----------|
244 PROCEDURE PCEndBuildDefModule ;
249 Assert(CompilingDefinitionModule()) ;
250 CheckForUnknownInModule ;
256 WriteFormat2('inconsistant definition module was named (%a) and concluded as (%a)',
259 M2Error.LeaveErrorScope
260 END PCEndBuildDefModule ;
264 StartBuildImplementationModule - Creates an implementation module and starts
267 The Stack is expected:
272 +------------+ +-----------+
273 | NameStart | | NameStart |
274 |------------| |-----------|
278 PROCEDURE PCStartBuildImpModule ;
282 ModuleSym: CARDINAL ;
285 ModuleSym := MakeImplementationSource(tok, name) ;
286 SetCurrentModule(ModuleSym) ;
287 SetFileModule(ModuleSym) ;
288 StartScope(ModuleSym) ;
289 Assert(IsDefImp(ModuleSym)) ;
290 Assert(CompilingImplementationModule()) ;
291 PushTtok(name, tok) ;
292 M2Error.EnterImplementationScope (name)
293 END PCStartBuildImpModule ;
297 EndBuildImplementationModule - Destroys the implementation module scope and
298 checks for correct name.
300 The Stack is expected:
305 +------------+ +-----------+
307 |------------| |-----------|
308 | NameStart | | | <- Ptr
309 |------------| |-----------|
312 PROCEDURE PCEndBuildImpModule ;
317 Assert(CompilingImplementationModule()) ;
318 CheckForUnknownInModule ;
324 (* we dont issue an error based around incorrect module names as this is done in P1 and P2.
325 If we get here then something has gone wrong with our error recovery in PC, so we bail out.
327 WriteFormat0('too many errors in pass 3') ;
330 M2Error.LeaveErrorScope
331 END PCEndBuildImpModule ;
335 StartBuildProgramModule - Creates a program module and starts
338 The Stack is expected:
343 +------------+ +-----------+
344 | NameStart | | NameStart |
345 |------------| |-----------|
349 PROCEDURE PCStartBuildProgModule ;
353 ModuleSym: CARDINAL ;
355 (* WriteString('StartBuildProgramModule') ; WriteLn ; *)
357 ModuleSym := MakeProgramSource(tok, name) ;
358 SetCurrentModule(ModuleSym) ;
359 SetFileModule(ModuleSym) ;
360 (* WriteString('MODULE - ') ; WriteKey(GetSymName(ModuleSym)) ; WriteLn ; *)
361 StartScope(ModuleSym) ;
362 Assert(CompilingProgramModule()) ;
363 Assert(NOT IsDefImp(ModuleSym)) ;
364 PushTtok(name, tok) ;
365 M2Error.EnterProgramScope (name)
366 END PCStartBuildProgModule ;
370 EndBuildProgramModule - Destroys the program module scope and
371 checks for correct name.
373 The Stack is expected:
378 +------------+ +-----------+
380 |------------| |-----------|
381 | NameStart | | | <- Ptr
382 |------------| |-----------|
385 PROCEDURE PCEndBuildProgModule ;
390 Assert(CompilingProgramModule()) ;
391 CheckForUnknownInModule ;
397 (* we dont issue an error based around incorrect module names this would be done in P1 and P2.
398 If we get here then something has gone wrong with our error recovery in PC, so we bail out.
400 WriteFormat0('too many errors in pass 3') ;
403 M2Error.LeaveErrorScope
404 END PCEndBuildProgModule ;
408 StartBuildInnerModule - Creates an Inner module and starts
411 The Stack is expected:
416 +------------+ +-----------+
417 | NameStart | | NameStart |
418 |------------| |-----------|
422 PROCEDURE PCStartBuildInnerModule ;
426 ModuleSym: CARDINAL ;
429 ModuleSym := RequestSym(tok, name) ;
430 Assert(IsModule(ModuleSym)) ;
431 StartScope(ModuleSym) ;
432 Assert(NOT IsDefImp(ModuleSym)) ;
433 SetCurrentModule(ModuleSym) ;
434 PushTtok(name, tok) ;
435 M2Error.EnterModuleScope (name)
436 END PCStartBuildInnerModule ;
440 EndBuildInnerModule - Destroys the Inner module scope and
441 checks for correct name.
443 The Stack is expected:
448 +------------+ +-----------+
450 |------------| |-----------|
451 | NameStart | | | <- Ptr
452 |------------| |-----------|
455 PROCEDURE PCEndBuildInnerModule ;
460 CheckForUnknownInModule ;
466 (* we dont issue an error based around incorrect module names this would be done in P1 and P2.
467 If we get here then something has gone wrong with our error recovery in PC, so we bail out.
469 WriteFormat0('too many errors in pass 3') ;
472 SetCurrentModule(GetModuleScope(GetCurrentModule())) ;
473 M2Error.LeaveErrorScope
474 END PCEndBuildInnerModule ;
478 BuildImportOuterModule - Builds imported identifiers into an outer module
479 from a definition module.
481 The Stack is expected:
486 +------------+ +-----------+
488 |------------| |-----------|
490 |------------| |-----------|
494 |------------| |-----------|
496 |------------| |-----------|
497 | ImportTok | | Ident |
498 |------------| |-----------|
500 IMPORT Id1, .. Id# ; FROM Ident IMPORT Id1 .. Id# ;
505 All above stack discarded
508 PROCEDURE PCBuildImportOuterModule ;
513 PopT (n) ; (* n = # of the Ident List *)
514 IF OperandT (n+1) # ImportTok
516 (* Ident List contains list of objects imported from ModSym *)
517 ModSym := LookupModule (OperandTok (n+1), OperandT (n+1)) ;
520 Sym := GetExported (OperandTok (i), ModSym, OperandT (i)) ;
521 CheckForEnumerationInCurrentModule (Sym) ;
525 PopN (n+1) (* clear stack *)
526 END PCBuildImportOuterModule ;
530 BuildImportInnerModule - Builds imported identifiers into an inner module
531 from the last level of module.
533 The Stack is expected:
538 +------------+ +-----------+
540 |------------| |-----------|
542 |------------| |-----------|
546 |------------| |-----------|
548 |------------| |-----------|
549 | ImportTok | | Ident |
550 |------------| |-----------|
552 IMPORT Id1, .. Id# ; FROM Ident IMPORT Id1 .. Id# ;
556 All above stack discarded
559 PROCEDURE PCBuildImportInnerModule ;
564 PopT (n) ; (* i = # of the Ident List *)
565 IF OperandT (n+1) = ImportTok
567 (* Ident List contains list of objects *)
570 Sym := GetFromOuterModule (OperandTok (i), OperandT (i)) ;
571 CheckForEnumerationInCurrentModule (Sym) ;
575 (* Ident List contains list of objects imported from ModSym *)
576 ModSym := LookupOuterModule (OperandTok (n+1), OperandT (n+1)) ;
579 Sym := GetExported (OperandTok (i), ModSym, OperandT (i)) ;
580 CheckForEnumerationInCurrentModule (Sym) ;
584 PopN (n+1) (* Clear Stack *)
585 END PCBuildImportInnerModule ;
589 StartBuildProcedure - Builds a Procedure.
598 +------------+ |------------|
600 |------------| |------------|
603 PROCEDURE PCStartBuildProcedure ;
610 PushTtok(name, tok) ; (* Name saved for the EndBuildProcedure name check *)
611 ProcSym := RequestSym (tok, name) ;
612 Assert (IsProcedure (ProcSym)) ;
613 PushTtok (ProcSym, tok) ;
614 StartScope (ProcSym) ;
615 M2Error.EnterProcedureScope (name)
616 END PCStartBuildProcedure ;
620 EndBuildProcedure - Ends building a Procedure.
621 It checks the start procedure name matches the end
626 (Procedure Not Defined in definition module)
641 PROCEDURE PCEndBuildProcedure ;
652 (* we dont issue an error based around incorrect module names this would be done in P1 and P2.
653 If we get here then something has gone wrong with our error recovery in PC, so we bail out.
655 WriteFormat0('too many errors in pass 3') ;
659 M2Error.LeaveErrorScope
660 END PCEndBuildProcedure ;
664 BuildProcedureHeading - Builds a procedure heading for the definition
667 Operation only performed if compiling a
684 PROCEDURE PCBuildProcedureHeading ;
689 IF CompilingDefinitionModule ()
695 END PCBuildProcedureHeading ;
699 BuildNulName - Pushes a NulKey onto the top of the stack.
711 PROCEDURE BuildNulName ;
718 BuildConst - builds a constant.
724 +------------+ +------------+
726 |------------+ |------------|
729 PROCEDURE BuildConst ;
735 PopTtok (name, tok) ;
736 Sym := RequestSym (tok, name) ;
742 BuildVarAtAddress - updates the symbol table entry of, variable sym, to be declared
751 | Expr | EType | <- Ptr
752 |--------------+ +--------------+
753 | name | SType | | name | SType |
754 |--------------+ |--------------|
758 PROCEDURE BuildVarAtAddress ;
762 Exp, EType: CARDINAL ;
763 etok, ntok: CARDINAL ;
765 PopTFtok (Exp, EType, etok) ;
766 PopTFtok (name, SType, ntok) ;
767 PushTFtok (name, SType, ntok) ;
768 Sym := RequestSym (ntok, name) ;
769 IF GetMode(Sym)=LeftValue
771 PutVariableAtAddress(Sym, Exp)
773 InternalError ('expecting lvalue for this variable which is declared at an explicit address')
775 END BuildVarAtAddress ;
780 BuildOptArgInitializer - assigns the constant value symbol, const, to be the
781 initial value of the optional parameter should it be
787 |------------| <- Ptr
791 PROCEDURE BuildOptArgInitializer ;
796 PutOptArgInit(GetCurrentScope(), const)
797 END BuildOptArgInitializer ;
805 PROCEDURE InitDesExpr (des: CARDINAL) ;
814 designator: WITH edes DO
824 PushAddress (exprStack, e)
832 PROCEDURE DebugNode (d: exprNode) ;
834 IF Debugging AND (d#NIL)
839 designator: DebugDes(d) |
840 expr : DebugExpr(d) |
841 leaf : DebugLeaf(d) |
842 unary : DebugUnary(d) |
843 binary : DebugBinary(d) |
844 function : DebugFunction(d) |
845 convert : DebugConvert(d)
857 PROCEDURE DebugDes (d: exprNode) ;
861 DebugSym(sym) ; Write(':') ; DebugMeta(meta) ; Write(':') ; DebugType(type) ;
874 PROCEDURE DebugSym (sym: CARDINAL) ;
878 n := GetSymName(sym) ;
883 Write(':') ; WriteCard(sym, 0)
891 PROCEDURE DebugMeta (m: constType) ;
895 unknown : WriteString('unknown') |
896 set : WriteString('set') |
897 str : WriteString('str') |
898 constructor: WriteString('constructor') |
899 array : WriteString('array') |
900 cast : WriteString('cast') |
901 boolean : WriteString('boolean') |
902 ztype : WriteString('ztype') |
903 rtype : WriteString('rtype') |
904 ctype : WriteString('ctype') |
905 procedure : WriteString('procedure') |
906 char : WriteString('ctype')
916 PROCEDURE DebugType (type: CARDINAL) ;
920 WriteString('[type:') ;
923 WriteString('<nulsym>')
925 n := GetSymName(type) ;
930 Write(':') ; WriteCard(type, 0)
940 PROCEDURE DebugExpr (e: exprNode) ;
943 WriteString('expr (') ;
944 DebugType(type) ; Write(':') ;
945 DebugMeta(meta) ; Write(' ') ;
956 PROCEDURE DebugFunction (f: exprNode) ;
959 WriteKey(GetSymName(func)) ;
983 PROCEDURE DebugConvert (f: exprNode) ;
998 PROCEDURE DebugLeaf (l: exprNode) ;
1001 WriteString('leaf (') ;
1002 DebugType(type) ; Write(':') ;
1003 DebugMeta(meta) ; Write(':') ;
1014 PROCEDURE DebugUnary (l: exprNode) ;
1017 WriteString('unary (') ;
1018 DebugType(type) ; Write(':') ;
1019 DebugMeta(meta) ; Write(' ') ;
1020 DebugOp(op) ; Write(' ') ;
1031 PROCEDURE DebugBinary (l: exprNode) ;
1034 WriteString('unary (') ;
1035 DebugType(type) ; Write(':') ;
1036 DebugMeta(meta) ; Write(' ') ;
1038 DebugOp(op) ; Write(' ') ;
1049 PROCEDURE DebugOp (op: Name) ;
1059 PROCEDURE PushInConstructor ;
1061 PushWord(desStack, inDesignator) ;
1062 inDesignator := FALSE
1063 END PushInConstructor ;
1070 PROCEDURE PopInConstructor ;
1072 inDesignator := PopWord(desStack)
1073 END PopInConstructor ;
1080 PROCEDURE StartDesConst ;
1085 inDesignator := TRUE ;
1086 exprStack := KillStackAddress (exprStack) ;
1087 exprStack := InitStackAddress () ;
1088 PopTtok (name, tok) ;
1089 InitDesExpr (RequestSym (tok, name))
1097 PROCEDURE EndDesConst ;
1101 e := PopAddress (exprStack) ;
1102 d := PopAddress (exprStack) ;
1103 Assert(d^.tag=designator) ;
1105 IncludeIndiceIntoIndex(constList, d) ;
1106 inDesignator := FALSE
1111 fixupProcedureType - creates a proctype from a procedure.
1114 PROCEDURE fixupProcedureType (p: CARDINAL) : CARDINAL ;
1123 tok := GetTokenNo () ;
1124 t := MakeProcType (tok, CheckAnonymous (NulName)) ;
1128 par := GetParam (p, i) ;
1129 IF IsParameterVar (par)
1131 PutProcTypeVarParam (t, GetType (par), IsParameterUnbounded (par))
1133 PutProcTypeParam (t, GetType (par), IsParameterUnbounded (par))
1137 IF GetType (p) # NulSym
1139 PutFunction (t, GetType (p))
1143 InternalError ('expecting a procedure')
1146 END fixupProcedureType ;
1153 PROCEDURE InitFunction (m: constType; p, t: CARDINAL; f, s: exprNode; more: BOOLEAN) ;
1162 function: WITH efunction DO
1173 PushAddress(exprStack, n)
1181 PROCEDURE InitConvert (m: constType; t: CARDINAL; to, e: exprNode) ;
1190 convert: WITH econvert DO
1199 PushAddress(exprStack, n)
1207 PROCEDURE InitLeaf (m: constType; s, t: CARDINAL) ;
1224 PushAddress(exprStack, l)
1232 PROCEDURE InitProcedure (s: CARDINAL) ;
1234 InitLeaf(procedure, s, fixupProcedureType(s))
1242 PROCEDURE InitCharType (s: CARDINAL) ;
1244 InitLeaf(char, s, Char)
1252 PROCEDURE InitZType (s: CARDINAL) ;
1254 InitLeaf(ztype, s, ZType)
1262 PROCEDURE InitRType (s: CARDINAL) ;
1264 InitLeaf(rtype, s, RType)
1272 PROCEDURE InitUnknown (s: CARDINAL) ;
1274 InitLeaf(unknown, s, NulSym)
1282 PROCEDURE InitBooleanType (s: CARDINAL) ;
1284 InitLeaf(boolean, s, Boolean)
1285 END InitBooleanType ;
1289 PushConstType - pushes a constant to the expression stack.
1292 PROCEDURE PushConstType ;
1302 WriteFormat0('module or symbol in qualident is not known') ;
1305 ELSIF IsProcedure(c)
1308 ELSIF GetSkippedType(c)=RType
1311 ELSIF GetSkippedType(c)=ZType
1314 ELSIF GetSkippedType(c)=Boolean
1325 PushConstructorCastType -
1328 PROCEDURE PushConstructorCastType ;
1332 InitConvert (cast, OperandT (1), NIL, NIL)
1334 END PushConstructorCastType ;
1341 PROCEDURE TypeToMeta (type: CARDINAL) : constType ;
1349 ELSIF IsRealType(type)
1352 ELSIF IsComplexType(type)
1355 ELSIF IsOrdinalType(type)
1365 buildConstFunction - we are only concerned about resolving the return type o
1366 a function, so we can ignore all parameters - except
1367 the first one in the case of VAL(type, foo).
1368 buildConstFunction uses a unary exprNode to represent
1372 PROCEDURE buildConstFunction (func: CARDINAL; n: CARDINAL) ;
1381 f := PopAddress(exprStack)
1386 s := PopAddress(exprStack) ;
1390 s := PopAddress(exprStack) ;
1391 f := PopAddress(exprStack)
1395 InitConvert(cast, NulSym, f, s)
1396 ELSIF (func=Max) OR (func=Min)
1398 InitFunction(unknown, func, NulSym, f, s, FALSE)
1400 InitFunction(TypeToMeta(GetSkippedType(func)), func, GetSkippedType(func), f, s, n>2)
1402 END buildConstFunction ;
1406 PushConstFunctionType -
1409 PROCEDURE PushConstFunctionType ;
1416 PopTtok (func, functok) ;
1419 IF (func#Convert) AND
1420 (IsPseudoBaseFunction(func) OR
1421 IsPseudoSystemFunctionConstExpression(func) OR
1422 (IsProcedure(func) AND IsProcedureBuiltin(func)))
1424 buildConstFunction (func, n)
1425 ELSIF IsAModula2Type(func)
1429 (* the top element on the expression stack is the first and only parameter to the cast *)
1430 InitUnary(cast, func, GetSymName(func))
1432 WriteFormat0('a constant type conversion can only have one argument')
1437 MetaErrorT1 (functok,
1438 'the only functions permissible in a constant expression are: CAP, CHR, CMPLX, FLOAT, HIGH, IM, LENGTH, MAX, MIN, ODD, ORD, RE, SIZE, TSIZE, TRUNC, VAL and gcc builtins, but not {%1Ead}',
1441 MetaErrorT1 (functok,
1442 '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}',
1447 PushTtok (func, functok)
1448 END PushConstFunctionType ;
1455 PROCEDURE PushIntegerType ;
1463 m := TypeToMeta(GetSkippedType(sym)) ;
1471 END PushIntegerType ;
1478 PROCEDURE PushRType ;
1494 PROCEDURE PushStringType ;
1501 InitLeaf(str, sym, NulSym)
1503 END PushStringType ;
1510 PROCEDURE InitBinary (m: constType; t: CARDINAL; o: Name) ;
1514 r := PopAddress(exprStack) ;
1515 l := PopAddress(exprStack) ;
1521 binary: WITH ebinary DO
1530 PushAddress(exprStack, b)
1535 BuildRelationConst - builds a relationship binary operation.
1538 PROCEDURE BuildRelationConst ;
1545 InitBinary(boolean, Boolean, op)
1547 END BuildRelationConst ;
1551 BuildBinaryConst - builds a binary operator node.
1554 PROCEDURE BuildBinaryConst ;
1561 InitBinary(unknown, NulSym, op)
1563 END BuildBinaryConst ;
1570 PROCEDURE InitUnary (m: constType; t: CARDINAL; o: Name) ;
1574 l := PopAddress(exprStack) ;
1580 unary: WITH eunary DO
1589 PushAddress(exprStack, b)
1594 BuildUnaryConst - builds a unary operator node.
1597 PROCEDURE BuildUnaryConst ;
1604 InitUnary(unknown, NulSym, op)
1606 END BuildUnaryConst ;
1613 PROCEDURE isTypeResolved (e: exprNode) : BOOLEAN ;
1618 leaf : RETURN( (eleaf.type#NulSym) OR (eleaf.meta=str) ) |
1619 unary : RETURN( (eunary.type#NulSym) OR (eunary.meta=str) ) |
1620 binary : RETURN( (ebinary.type#NulSym) OR (ebinary.meta=str) ) |
1621 designator: RETURN( (edes.type#NulSym) OR (edes.meta=str) ) |
1622 expr : RETURN( (eexpr.type#NulSym) OR (eexpr.meta=str) ) |
1623 convert : RETURN( (econvert.type#NulSym) OR (econvert.meta=str) ) |
1624 function : RETURN( (efunction.type#NulSym) OR (efunction.meta=str) )
1628 END isTypeResolved ;
1635 PROCEDURE getEtype (e: exprNode) : CARDINAL ;
1640 leaf : RETURN( eleaf.type ) |
1641 unary : RETURN( eunary.type ) |
1642 binary : RETURN( ebinary.type ) |
1643 designator: RETURN( edes.type ) |
1644 expr : RETURN( eexpr.type ) |
1645 convert : RETURN( econvert.type ) |
1646 function : RETURN( efunction.type )
1657 PROCEDURE getEmeta (e: exprNode) : constType ;
1662 leaf : RETURN( eleaf.meta ) |
1663 unary : RETURN( eunary.meta ) |
1664 binary : RETURN( ebinary.meta ) |
1665 designator: RETURN( edes.meta ) |
1666 expr : RETURN( eexpr.meta ) |
1667 convert : RETURN( econvert.meta ) |
1668 function : RETURN( efunction.meta )
1679 PROCEDURE assignTM (VAR td: CARDINAL; VAR md: constType; te: CARDINAL; me: constType) ;
1690 PROCEDURE assignType (d, e: exprNode) ;
1700 leaf : assignTM(eleaf.type, eleaf.meta, t, m) |
1701 unary : assignTM(eunary.type, eunary.meta, t, m) |
1702 binary : assignTM(ebinary.type, ebinary.meta, t, m) |
1703 designator: assignTM(edes.type, edes.meta, t, m) |
1704 expr : assignTM(eexpr.type, eexpr.meta, t, m) |
1705 convert : assignTM(econvert.type, econvert.meta, t, m) |
1706 function : assignTM(efunction.type, efunction.meta, t, m)
1714 deduceTypes - works out the type and metatype given, l, and, r.
1717 PROCEDURE deduceTypes (VAR t: CARDINAL;
1719 l, r: exprNode; op: Name) ;
1723 (* function or cast *)
1726 ELSIF (op=EqualTok) OR (op=HashTok) OR (op=LessGreaterTok) OR
1727 (op=LessTok) OR (op=LessEqualTok) OR (op=GreaterTok) OR
1728 (op=GreaterEqualTok) OR (op=InTok) OR (op=OrTok) OR
1729 (op=AndTok) OR (op=NotTok) OR (op=AmbersandTok)
1733 ELSIF (op=PlusTok) OR (op=MinusTok) OR (op=TimesTok) OR (op=ModTok) OR
1734 (op=DivTok) OR (op=RemTok) OR (op=DivideTok)
1736 t := MixTypes(getEtype(l), getEtype(r), constToken) ;
1741 ELSIF (getEmeta(r)#unknown) AND (m#getEmeta(r))
1743 ErrorFormat0(NewError(constToken),
1744 'the operands to a binary constant expression have different types')
1747 InternalError ('unexpected operator')
1756 PROCEDURE WalkConvert (e: exprNode) : BOOLEAN ;
1758 IF isTypeResolved(e)
1763 IF isTypeResolved(totype)
1765 assignType(e, totype) ;
1768 RETURN( doWalkNode(totype) )
1778 PROCEDURE WalkFunctionParam (func: CARDINAL; e: exprNode) : BOOLEAN ;
1780 IF isTypeResolved(e)
1787 IF (sym#NulSym) AND (type=NulSym)
1789 IF (func=Min) OR (func=Max)
1791 IF IsEnumeration(sym) OR IsSet(sym)
1793 type := SkipType(GetType(sym))
1795 (* sym is the type required for MAX, MIN and VAL *)
1802 meta := TypeToMeta(sym) ;
1809 END WalkFunctionParam ;
1816 PROCEDURE WalkFunction (e: exprNode) : BOOLEAN ;
1818 IF isTypeResolved(e)
1822 WITH e^.efunction DO
1823 IF (func=Max) OR (func=Min) OR (func=Val)
1825 IF isTypeResolved(first)
1827 IF getEmeta(first)=str
1829 MetaError1('a string parameter cannot be passed to function {%1Dad}', func) ;
1832 type := getEtype(first) ;
1835 RETURN( WalkFunctionParam(func, first) )
1837 MetaError1('not expecting this function inside a constant expression {%1Dad}', func)
1848 PROCEDURE doWalkNode (e: exprNode) : BOOLEAN ;
1853 expr : RETURN( WalkExpr(e) ) |
1854 leaf : RETURN( WalkLeaf(e) ) |
1855 unary : RETURN( WalkUnary(e) ) |
1856 binary : RETURN( WalkBinary(e) ) |
1857 convert : RETURN( WalkConvert(e) ) |
1858 function: RETURN( WalkFunction(e) )
1861 InternalError ('unexpected tag value')
1872 PROCEDURE WalkLeaf (e: exprNode) : BOOLEAN ;
1876 IF isTypeResolved(e)
1881 IF IsConst(sym) AND (GetType(sym)#NulSym)
1883 type := GetSkippedType(sym) ;
1886 IF IsAModula2Type(sym)
1891 c := findConstDes(sym) ;
1892 IF (c#NIL) AND isTypeResolved(c)
1907 PROCEDURE WalkUnary (e: exprNode) : BOOLEAN ;
1909 IF isTypeResolved(e)
1914 IF isTypeResolved(left)
1916 deduceTypes(type, meta, left, left, op) ;
1919 RETURN( doWalkNode(left) )
1929 PROCEDURE WalkBinary (e: exprNode) : BOOLEAN ;
1933 IF isTypeResolved(e)
1938 IF isTypeResolved(left) AND isTypeResolved(right)
1940 deduceTypes(type, meta, left, right, op) ;
1943 changed := doWalkNode(left) ;
1944 RETURN( doWalkNode(right) OR changed )
1954 PROCEDURE WalkExpr (e: exprNode) : BOOLEAN ;
1956 IF isTypeResolved(e)
1961 IF isTypeResolved(left)
1963 assignType(e, left) ;
1966 RETURN( doWalkNode(left) )
1973 doWalkDesExpr - returns TRUE if the expression trees, d, or, e, are changed.
1976 PROCEDURE doWalkDesExpr (d, e: exprNode) : BOOLEAN ;
1978 IF isTypeResolved(e)
1981 type := getEtype(e) ;
1984 meta := getEmeta(e) ;
1987 (* PutConstString(sym, getString(e)) *)
1995 RETURN( doWalkNode(e) )
2000 doWalkDes - return TRUE if expression, e, is changed.
2003 PROCEDURE doWalkDes (d: exprNode) : BOOLEAN ;
2005 IF isTypeResolved(d)
2012 designator: WITH edes DO
2013 constToken := GetDeclaredMod(sym) ;
2014 RETURN( doWalkDesExpr(d, left) )
2018 InternalError ('unexpected tag value')
2029 PROCEDURE findConstDes (sym: CARDINAL) : exprNode ;
2035 WHILE i<=HighIndice(constList) DO
2036 e := GetIndice(constList, i) ;
2040 designator: IF edes.sym=sym
2055 WalkDes - return TRUE if expression, e, is changed.
2058 PROCEDURE WalkDes (d: exprNode) : BOOLEAN ;
2064 RETURN( doWalkDes(d) )
2070 WalkConst - returns TRUE if the constant tree associated with, sym,
2075 PROCEDURE WalkConst (sym: CARDINAL) : BOOLEAN ;
2077 RETURN( WalkDes(findConstDes(sym)) )
2083 WalkConsts - walk over the constant trees and return TRUE if any tree was changed.
2084 (As a result of a type resolution).
2087 PROCEDURE WalkConsts () : BOOLEAN ;
2094 WHILE i<=HighIndice(constList) DO
2095 IF WalkDes(GetIndice(constList, i))
2109 PROCEDURE DebugNodes ;
2114 WHILE i<=HighIndice(constList) DO
2115 IF isTypeResolved(GetIndice(constList, i))
2117 WriteString('resolved ')
2119 WriteString('unresolved ')
2121 DebugNode(GetIndice(constList, i)) ; WriteLn ;
2131 PROCEDURE findAlias (sym: CARDINAL; e: exprNode) : CARDINAL ;
2135 designator: RETURN( findAlias(sym, e^.edes.left) ) |
2136 leaf : RETURN( e^.eleaf.sym ) |
2137 expr : RETURN( findAlias(sym, e^.eexpr.left) ) |
2139 binary : RETURN( sym )
2142 InternalError ('not expecting this tag value')
2148 SkipConst - returns an alias to constant, sym, if one exists.
2149 Otherwise sym is returned.
2152 PROCEDURE SkipConst (sym: CARDINAL) : CARDINAL ;
2158 WHILE i<=HighIndice(constList) DO
2159 e := GetIndice(constList, i) ;
2160 IF (e^.tag=designator) AND (e^.edes.sym=sym)
2162 RETURN( findAlias(sym, e) )
2171 PushConstAttributeType -
2174 PROCEDURE PushConstAttributeType ;
2181 IF (n=MakeKey('BITS_PER_UNIT')) OR (n=MakeKey('BITS_PER_WORD')) OR
2182 (n=MakeKey('BITS_PER_CHAR')) OR (n=MakeKey('UNITS_PER_WORD'))
2186 WriteFormat1("unknown constant attribute value '%a'", n)
2188 END PushConstAttributeType ;
2192 PushConstAttributePairType -
2195 PROCEDURE PushConstAttributePairType ;
2203 IF (n=MakeKey('IEC559')) OR (n=MakeKey('LIA1')) OR (n=MakeKey('IEEE')) OR
2204 (n=MakeKey('ISO')) OR (n=MakeKey('rounds')) OR (n=MakeKey('gUnderflow')) OR
2205 (n=MakeKey('exception')) OR (n=MakeKey('extend'))
2207 InitBooleanType(NulSym)
2208 ELSIF (n=MakeKey('radix')) OR (n=MakeKey('places')) OR (n=MakeKey('expoMin')) OR
2209 (n=MakeKey('expoMax')) OR (n=MakeKey('nModes'))
2212 ELSIF (n=MakeKey('large')) OR (n=MakeKey('small'))
2216 WriteFormat1("unknown constant attribute value '%a'", n) ;
2219 END PushConstAttributePairType ;
2226 PROCEDURE CheckConsts ;
2232 WHILE i<=HighIndice(constList) DO
2233 e := GetIndice(constList, i) ;
2234 IF NOT isTypeResolved(e)
2239 designator: MetaError1('the type of the constant declaration {%1Dad} cannot be determined', edes.sym)
2251 ResolveConstTypes - resolves the types of all designator declared constants.
2254 PROCEDURE ResolveConstTypes ;
2258 WriteString('initially') ; WriteLn ;
2261 WHILE WalkConsts() DO
2264 WriteString('iteration') ; WriteLn ;
2270 WriteString('finally') ; WriteLn ;
2274 END ResolveConstTypes ;
2283 exprStack := InitStackAddress () ;
2284 constList := InitIndex (1) ;
2285 desStack := InitStackWord () ;
2286 inDesignator := FALSE