blob: 860a89ac8b0c6be29ee46dc7ddb71e9883d2f7bb [file] [log] [blame]
(* M2GCCDeclare.mod declares Modula-2 types to GCC.
Copyright (C) 2001-2025 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 M2GCCDeclare ;
(*
Title : M2GCCDeclare
Author : Gaius Mulley
System : UNIX (gm2)
Date : Fri Jul 16 20:10:55 1999
Description: declares Modula-2 types to GCC, it attempts
to only declare a type once all subcomponents are known.
*)
FROM SYSTEM IMPORT ADDRESS, ADR, WORD ;
FROM ASCII IMPORT nul ;
FROM Storage IMPORT ALLOCATE ;
FROM M2Debug IMPORT Assert ;
FROM M2Quads IMPORT DisplayQuadRange ;
FROM m2pp IMPORT DumpGimpleFd ;
IMPORT FIO ;
FROM M2Options IMPORT GenerateDebugging, GenerateLineDebug, Iso, Optimizing, WholeProgram,
ScaffoldStatic, GetRuntimeModuleOverride ;
FROM M2AsmUtil IMPORT GetFullSymName, GetFullScopeAsmName ;
FROM M2Batch IMPORT MakeDefinitionSource ;
FROM NameKey IMPORT Name, MakeKey, NulName, KeyToCharStar, makekey ;
FROM M2FileName IMPORT CalculateFileName ;
FROM DynamicStrings IMPORT String, string, InitString, KillString, InitStringCharStar, InitStringChar, Mark ;
FROM M2LexBuf IMPORT TokenToLineNo, FindFileNameFromToken, TokenToLocation, UnknownTokenNo, BuiltinTokenNo ;
FROM M2MetaError IMPORT MetaError1, MetaError2, MetaError3 ;
FROM M2Error IMPORT FlushErrors, InternalError ;
FROM M2LangDump IMPORT GetDumpFile ;
FROM M2Printf IMPORT printf0, printf1, printf2, printf3,
fprintf0, fprintf1, fprintf2, fprintf3 ;
FROM Indexing IMPORT Index, InitIndex, PutIndice, GetIndice, InBounds,
IncludeIndiceIntoIndex, HighIndice,
DebugIndex ;
FROM Lists IMPORT List, InitList, IncludeItemIntoList,
PutItemIntoList, GetItemFromList,
RemoveItemFromList, ForeachItemInListDo,
IsItemInList, NoOfItemsInList, KillList ;
FROM Sets IMPORT Set, InitSet, KillSet,
IncludeElementIntoSet, ExcludeElementFromSet,
NoOfElementsInSet, IsElementInSet, ForeachElementInSetDo,
DuplicateSet, EqualSet ;
FROM M2BasicBlock IMPORT BasicBlock, InitBasicBlocks, KillBasicBlocks, ForeachBasicBlockDo ;
FROM SymbolTable IMPORT NulSym,
ModeOfAddr, ProcedureKind,
GetProcedureKindDesc,
GetProcedureParametersDefined,
GetMode,
GetScope,
GetNth, SkipType, GetVarBackEndType,
GetSType, GetLType, GetDType,
MakeType, PutType, GetLowestType,
GetSubrange, PutSubrange, GetArraySubscript,
NoOfParamAny, GetNthParamAny,
PushValue, PopValue, PopSize,
IsTemporary, IsUnbounded, IsPartialUnbounded,
IsEnumeration, IsVar,
IsSubrange, IsPointer, IsRecord, IsArray,
IsFieldEnumeration,
IsProcedure, IsProcedureNested, IsModule,
IsDefImp,
IsSubscript, IsVarient, IsFieldVarient,
IsType, IsProcType, IsSet, IsSetPacked,
IsConst, IsConstSet, IsConstructor,
IsFieldEnumeration,
IsExported, IsImported,
IsVarParamAny, IsRecordField, IsUnboundedParam,
IsValueSolved,
IsDefinitionForC, IsHiddenTypeDeclared,
IsInnerModule, IsUnknown,
IsProcedureReachable, IsParameter, IsConstLit,
IsDummy, IsVarAParam, IsProcedureVariable,
IsGnuAsm, IsGnuAsmVolatile, IsObject, IsTuple,
IsError, IsHiddenType, IsVarHeap,
IsComponent, IsPublic, IsExtern, IsCtor,
IsImport, IsImportStatement, IsConstStringKnown,
IsUnboundedParamAny,
GetMainModule, GetBaseModule, GetModule, GetLocalSym,
PutModuleFinallyFunction,
GetProcedureScope, GetProcedureQuads,
NoOfParam, IsVarParam, GetNthParam, GetType,
IsRecordFieldAVarientTag, IsEmptyFieldVarient,
GetVarient, GetUnbounded, PutArrayLarge,
IsAModula2Type, UsesVarArgs,
GetSymName, GetParent,
GetDeclaredMod, GetVarBackEndType,
GetProcedureBeginEnd, IsProcedureAnyNoReturn,
GetString, GetStringLength, IsConstString,
IsConstStringM2, IsConstStringC, IsConstStringM2nul, IsConstStringCnul,
GetAlignment, IsDeclaredPacked, PutDeclaredPacked,
GetDefaultRecordFieldAlignment, IsDeclaredPackedResolved,
GetPackedEquivalent,
GetParameterShadowVar,
GetUnboundedRecordType,
GetModuleCtors, GetProcedureProcType,
MakeSubrange, MakeConstVar, MakeConstLit,
PutConst,
ForeachOAFamily, GetOAFamily,
IsModuleWithinProcedure, IsVariableSSA,
IsVariableAtAddress, IsConstructorConstant,
ForeachLocalSymDo,
ForeachProcedureDo, ForeachModuleDo,
ForeachInnerModuleDo, ForeachImportedDo,
ForeachExportedDo, PrintInitialized,
FinalSymbol ;
FROM M2Base IMPORT IsPseudoBaseProcedure, IsPseudoBaseFunction,
GetBaseTypeMinMax, MixTypes,
Cardinal, Char, Proc, Integer,
LongInt, LongCard, ShortCard, ShortInt,
Real, LongReal, ShortReal, ZType, RType,
CType, Complex, LongComplex, ShortComplex,
Boolean, True, False, Nil,
IsRealType, IsNeededAtRunTime, IsComplexType ;
FROM M2System IMPORT IsPseudoSystemFunction, IsSystemType, IsRealN,
GetSystemTypeMinMax, Address, Word, Byte, Loc,
System, IntegerN, CardinalN, WordN, RealN, SetN, ComplexN,
CSizeT, CSSizeT, COffT ;
FROM M2Bitset IMPORT Bitset, Bitnum ;
FROM SymbolConversion IMPORT AddModGcc, Mod2Gcc, GccKnowsAbout, Poison, RemoveMod2Gcc ;
FROM M2GenGCC IMPORT ResolveConstantExpressions ;
FROM M2Scope IMPORT ScopeBlock, InitScopeBlock, KillScopeBlock, ForeachScopeBlockDo3 ;
FROM M2ALU IMPORT Addn, Sub, Equ, GreEqu, Gre, Less, PushInt, PushCard, ConvertToType,
PushIntegerTree, PopIntegerTree, PopRealTree, ConvertToInt, PopSetTree,
PopChar,
DivTrunc,
IsConstructorDependants, WalkConstructorDependants,
PopConstructorTree, PopComplexTree, PutConstructorSolved,
ChangeToConstructor, EvaluateValue, TryEvaluateValue ;
FROM M2Batch IMPORT IsSourceSeen, GetModuleFile, IsModuleSeen, LookupModule ;
FROM gcctypes IMPORT location_t, tree ;
FROM m2linemap IMPORT BuiltinsLocation ;
FROM m2decl IMPORT BuildIntegerConstant, BuildStringConstant, BuildCStringConstant,
BuildStartFunctionDeclaration,
BuildParameterDeclaration, BuildEndFunctionDeclaration,
DeclareKnownVariable, GetBitsPerBitset, BuildPtrToTypeString ;
FROM m2type IMPORT MarkFunctionReferenced, BuildStartRecord, BuildStartVarient, BuildStartFunctionType,
BuildStartFieldVarient, BuildStartVarient, BuildStartType, BuildStartArrayType,
PutArrayType, BuildPointerType, BuildEndType, BuildCharConstant,
BuildTypeDeclaration, GetDefaultType, GetBooleanType, GetBooleanTrue,
GetBooleanFalse, BuildSubrangeType, GetM2ZType, GetM2RType, GetM2CType,
GetM2CardinalType, GetM2IntegerType, GetM2CharType, GetISOLocType, GetIntegerType,
GetISOByteType, GetISOWordType, GetByteType, GetWordType, GetProcType, GetPointerType,
GetM2LongIntType, GetM2LongCardType, GetM2ShortIntType, GetM2ShortCardType,
GetM2LongRealType, GetM2ShortRealType, GetM2RealType, GetBitnumType, GetBitsetType,
GetM2ComplexType, GetM2ComplexType, GetM2LongComplexType, GetM2ShortComplexType,
GetM2Integer8, GetM2Integer16, GetM2Integer32, GetM2Integer64, GetM2Cardinal8,
GetM2Cardinal16, GetM2Cardinal32, GetM2Cardinal64, GetM2Word16, GetM2Word32,
GetM2Word64, GetM2Bitset8, GetM2Bitset16, GetM2Bitset32, GetM2Real32, GetM2Real64,
GetM2Real96, GetM2Real128, GetM2Complex32, GetM2Complex64, GetM2Complex96,
GetM2Complex128, GetCSizeTType, GetCSSizeTType, GetCOffTType,
GetPackedBooleanType, BuildConstPointerType,
BuildPointerType, BuildEnumerator, BuildStartEnumeration, BuildEndEnumeration,
SetAlignment, SetTypePacked, SetDeclPacked, BuildSmallestTypeRange,
SetRecordFieldOffset, ChainOn, BuildEndRecord, BuildFieldRecord,
BuildEndFieldVarient, BuildArrayIndexType, BuildEndFunctionType,
BuildSetType, BuildEndVarient, BuildEndArrayType, InitFunctionTypeParameters,
BuildProcTypeParameterDeclaration, DeclareKnownType,
ValueOutOfTypeRange, ExceedsTypeRange,
GetMaxFrom, GetMinFrom ;
FROM m2convert IMPORT BuildConvert ;
FROM m2expr IMPORT BuildSub, BuildLSL, BuildTBitSize, BuildAdd, BuildDivTrunc, BuildModTrunc,
BuildSize, TreeOverflow, AreConstantsEqual, CompareTrees,
GetPointerZero, GetIntegerZero, GetIntegerOne ;
FROM m2block IMPORT RememberType, pushGlobalScope, popGlobalScope,
pushFunctionScope, popFunctionScope,
finishFunctionDecl, RememberConstant, GetGlobalContext ;
TYPE
StartProcedure = PROCEDURE (location_t, ADDRESS) : tree ;
ListType = (fullydeclared, partiallydeclared, niltypedarrays,
heldbyalignment, finishedalignment, todolist,
tobesolvedbyquads, finishedsetarray) ;
doDeclareProcedure = PROCEDURE (CARDINAL, CARDINAL) ;
CONST
Debugging = FALSE ;
Progress = FALSE ;
EnableSSA = FALSE ;
EnableWatch = TRUE ;
TraceQuadruples = FALSE ;
TYPE
Group = POINTER TO RECORD
ToBeSolvedByQuads, (* Constants which must be solved *)
(* by processing the quadruples. *)
FinishedSetArray, (* Sets which have had their set *)
(* array created. *)
NilTypedArrays, (* Arrays which have NIL as their *)
(* type. *)
FullyDeclared, (* Those symbols which have been *)
(* fully declared. *)
PartiallyDeclared, (* Those types which have need to *)
(* be finished (but already *)
(* started: records, function *)
(* and array type). *)
HeldByAlignment, (* Types which have a user *)
(* specified alignment constant. *)
FinishedAlignment, (* Records for which we know *)
(* their alignment value. *)
ToDoList : Set ; (* Contains a set of all *)
(* outstanding types that need to *)
(* be declared to GCC once *)
(* its dependants have *)
(* been written. *)
Next : Group ;
END ;
VAR
FreeGroup,
GlobalGroup : Group ; (* The global group of all sets. *)
ErrorDepList, (* The set of symbols with dependency errors. *)
VisitedList,
ChainedList : Set ;
HaveInitDefaultTypes: BOOLEAN ; (* Have we initialized them yet? *)
WatchList : Set ; (* Set of symbols being watched. *)
EnumerationIndex : Index ;
action : IsAction ;
ConstantResolved,
enumDeps : BOOLEAN ;
(* *************************************************** *)
(*
PrintNum -
*)
PROCEDURE PrintNum (sym: WORD) ;
BEGIN
printf1 ('%d, ', sym)
END PrintNum ;
(*
DebugSet -
*)
PROCEDURE DebugSet (a: ARRAY OF CHAR; l: Set) ;
BEGIN
printf0 (a) ;
printf0 (' {') ;
ForeachElementInSetDo (l, PrintNum) ;
printf0 ('}\n')
END DebugSet ;
(*
DebugSets -
*)
PROCEDURE DebugSets ;
BEGIN
DebugSet ('ToDoList', GlobalGroup^.ToDoList) ;
DebugSet ('HeldByAlignment', GlobalGroup^.HeldByAlignment) ;
DebugSet ('FinishedAlignment', GlobalGroup^.FinishedAlignment) ;
DebugSet ('PartiallyDeclared', GlobalGroup^.PartiallyDeclared) ;
DebugSet ('FullyDeclared', GlobalGroup^.FullyDeclared) ;
DebugSet ('NilTypedArrays', GlobalGroup^.NilTypedArrays) ;
DebugSet ('ToBeSolvedByQuads', GlobalGroup^.ToBeSolvedByQuads) ;
DebugSet ('FinishedSetArray', GlobalGroup^.FinishedSetArray)
END DebugSets ;
(* ************************************************ *)
(*
DebugNumber -
*)
PROCEDURE DebugNumber (a: ARRAY OF CHAR; s: Set) ;
VAR
n: CARDINAL ;
BEGIN
n := NoOfElementsInSet (s) ;
printf1 (a, n) ;
FIO.FlushBuffer (FIO.StdOut)
END DebugNumber ;
(*
DebugSets -
*)
PROCEDURE DebugSetNumbers ;
BEGIN
DebugNumber ('ToDoList : %d\n', GlobalGroup^.ToDoList) ;
DebugNumber ('HeldByAlignment : %d\n', GlobalGroup^.HeldByAlignment) ;
DebugNumber ('PartiallyDeclared : %d\n', GlobalGroup^.PartiallyDeclared) ;
DebugNumber ('FullyDeclared : %d\n', GlobalGroup^.FullyDeclared) ;
DebugNumber ('NilTypedArrays : %d\n', GlobalGroup^.NilTypedArrays) ;
DebugNumber ('ToBeSolvedByQuads : %d\n', GlobalGroup^.ToBeSolvedByQuads) ;
DebugNumber ('FinishedSetArray : %d\n', GlobalGroup^.FinishedSetArray)
END DebugSetNumbers ;
(*
AddSymToWatch - adds symbol, sym, to the list of symbols
to watch and annotate their movement between
lists.
*)
PROCEDURE AddSymToWatch (sym: WORD) ;
BEGIN
IF (sym # NulSym) AND (NOT IsElementInSet (WatchList, sym))
THEN
IncludeElementIntoSet (WatchList, sym) ;
WalkDependants (sym, AddSymToWatch) ;
fprintf1 (GetDumpFile (), "%d, ", sym)
END
END AddSymToWatch ;
(*
TryFindSymbol -
*)
(*
PROCEDURE TryFindSymbol (module, symname: ARRAY OF CHAR) : CARDINAL ;
VAR
mn, sn: Name ;
mod : CARDINAL ;
BEGIN
mn := MakeKey(module) ;
sn := MakeKey(symname) ;
IF IsModuleSeen(mn)
THEN
mod := LookupModule (UnknownTokenNo, mn) ;
RETURN( GetLocalSym(mod, sn) )
ELSE
RETURN( NulSym )
END
END TryFindSymbol ;
*)
(*
doInclude -
*)
PROCEDURE doInclude (l: Set; a: ARRAY OF CHAR; sym: CARDINAL) ;
BEGIN
IF NOT IsElementInSet(l, sym)
THEN
fprintf0 (GetDumpFile (), 'rule: ') ;
WriteRule ;
fprintf0 (GetDumpFile (), ' ') ;
fprintf1 (GetDumpFile (), a, sym) ;
IncludeElementIntoSet (l, sym)
END
END doInclude ;
(*
WatchIncludeList - include a symbol onto the set first checking
whether it is already on the set and
displaying a debug message if the set is
changed.
*)
PROCEDURE WatchIncludeList (sym: CARDINAL; lt: ListType) ;
BEGIN
IF IsElementInSet (WatchList, sym)
THEN
CASE lt OF
tobesolvedbyquads : doInclude (GlobalGroup^.ToBeSolvedByQuads, "symbol %d -> ToBeSolvedByQuads\n", sym) |
fullydeclared : doInclude (GlobalGroup^.FullyDeclared, "symbol %d -> FullyDeclared\n", sym) |
partiallydeclared : doInclude (GlobalGroup^.PartiallyDeclared, "symbol %d -> PartiallyDeclared\n", sym) |
heldbyalignment : doInclude (GlobalGroup^.HeldByAlignment, "symbol %d -> HeldByAlignment\n", sym) |
finishedalignment : doInclude (GlobalGroup^.FinishedAlignment, "symbol %d -> FinishedAlignment\n", sym) |
todolist : doInclude (GlobalGroup^.ToDoList, "symbol %d -> ToDoList\n", sym) |
niltypedarrays : doInclude (GlobalGroup^.NilTypedArrays, "symbol %d -> NilTypedArrays\n", sym) |
finishedsetarray : doInclude (GlobalGroup^.FinishedSetArray, "symbol %d -> FinishedSetArray\n", sym)
ELSE
InternalError ('unknown list')
END
ELSE
CASE lt OF
tobesolvedbyquads : IncludeElementIntoSet (GlobalGroup^.ToBeSolvedByQuads, sym) |
fullydeclared : IncludeElementIntoSet (GlobalGroup^.FullyDeclared, sym) |
partiallydeclared : IncludeElementIntoSet (GlobalGroup^.PartiallyDeclared, sym) |
heldbyalignment : IncludeElementIntoSet (GlobalGroup^.HeldByAlignment, sym) |
finishedalignment : IncludeElementIntoSet (GlobalGroup^.FinishedAlignment, sym) |
todolist : IncludeElementIntoSet (GlobalGroup^.ToDoList, sym) |
niltypedarrays : IncludeElementIntoSet (GlobalGroup^.NilTypedArrays, sym) |
finishedsetarray : IncludeElementIntoSet (GlobalGroup^.FinishedSetArray, sym)
ELSE
InternalError ('unknown list')
END
END
END WatchIncludeList ;
(*
doExclude -
*)
PROCEDURE doExclude (l: Set; a: ARRAY OF CHAR; sym: CARDINAL) ;
BEGIN
IF IsElementInSet (l, sym)
THEN
fprintf0 (GetDumpFile (), 'rule: ') ;
WriteRule ;
fprintf0 (GetDumpFile (), ' ') ;
fprintf1 (GetDumpFile (), a, sym) ;
ExcludeElementFromSet (l, sym)
END
END doExclude ;
(*
WatchRemoveList - remove a symbol onto the list first checking
whether it is already on the list and
displaying a debug message if the list is
changed.
*)
PROCEDURE WatchRemoveList (sym: CARDINAL; lt: ListType) ;
BEGIN
IF IsElementInSet (WatchList, sym)
THEN
CASE lt OF
tobesolvedbyquads : doExclude (GlobalGroup^.ToBeSolvedByQuads, "symbol %d off ToBeSolvedByQuads\n", sym) |
fullydeclared : doExclude (GlobalGroup^.FullyDeclared, "symbol %d off FullyDeclared\n", sym) |
partiallydeclared : doExclude (GlobalGroup^.PartiallyDeclared, "symbol %d off PartiallyDeclared\n", sym) |
heldbyalignment : doExclude (GlobalGroup^.HeldByAlignment, "symbol %d -> HeldByAlignment\n", sym) |
finishedalignment : doExclude (GlobalGroup^.FinishedAlignment, "symbol %d -> FinishedAlignment\n", sym) |
todolist : doExclude (GlobalGroup^.ToDoList, "symbol %d off ToDoList\n", sym) |
niltypedarrays : doExclude (GlobalGroup^.NilTypedArrays, "symbol %d off NilTypedArrays\n", sym) |
finishedsetarray : doExclude (GlobalGroup^.FinishedSetArray, "symbol %d off FinishedSetArray\n", sym) |
ELSE
InternalError ('unknown list')
END
ELSE
CASE lt OF
tobesolvedbyquads : ExcludeElementFromSet (GlobalGroup^.ToBeSolvedByQuads, sym) |
fullydeclared : ExcludeElementFromSet (GlobalGroup^.FullyDeclared, sym) |
partiallydeclared : ExcludeElementFromSet (GlobalGroup^.PartiallyDeclared, sym) |
heldbyalignment : ExcludeElementFromSet (GlobalGroup^.HeldByAlignment, sym) |
finishedalignment : ExcludeElementFromSet (GlobalGroup^.FinishedAlignment, sym) |
todolist : ExcludeElementFromSet (GlobalGroup^.ToDoList, sym) |
niltypedarrays : ExcludeElementFromSet (GlobalGroup^.NilTypedArrays, sym) |
finishedsetarray : ExcludeElementFromSet (GlobalGroup^.FinishedSetArray, sym) |
ELSE
InternalError ('unknown list')
END
END
END WatchRemoveList ;
(*
NewGroup -
*)
PROCEDURE NewGroup (VAR g: Group) ;
BEGIN
IF FreeGroup = NIL
THEN
NEW (g)
ELSE
g := FreeGroup ;
FreeGroup := FreeGroup^.Next
END
END NewGroup ;
(*
DisposeGroup -
*)
PROCEDURE DisposeGroup (VAR g: Group) ;
BEGIN
g^.Next := FreeGroup ;
FreeGroup := g ;
g := NIL
END DisposeGroup ;
(*
InitGroup - initialize all sets in group and return the group.
*)
PROCEDURE InitGroup () : Group ;
VAR
g: Group ;
BEGIN
NewGroup (g) ;
(* Initialize all sets in group. *)
WITH g^ DO
FinishedSetArray := InitSet (1) ;
ToDoList := InitSet (1) ;
FullyDeclared := InitSet (1) ;
PartiallyDeclared := InitSet (1) ;
NilTypedArrays := InitSet (1) ;
HeldByAlignment := InitSet (1) ;
FinishedAlignment := InitSet (1) ;
ToBeSolvedByQuads := InitSet (1) ;
Next := NIL
END ;
RETURN g
END InitGroup ;
(*
KillGroup - delete all sets in group and deallocate g.
*)
PROCEDURE KillGroup (VAR g: Group) ;
BEGIN
(* Delete all sets in group. *)
IF g # NIL
THEN
WITH g^ DO
FinishedSetArray := KillSet (FinishedSetArray) ;
ToDoList := KillSet (ToDoList) ;
FullyDeclared := KillSet (FullyDeclared) ;
PartiallyDeclared := KillSet (PartiallyDeclared) ;
NilTypedArrays := KillSet (NilTypedArrays) ;
HeldByAlignment := KillSet (HeldByAlignment) ;
FinishedAlignment := KillSet (FinishedAlignment) ;
ToBeSolvedByQuads := KillSet (ToBeSolvedByQuads) ;
Next := NIL
END ;
DisposeGroup (g)
END
END KillGroup ;
(*
DupGroup - If g is not NIL then destroy g.
Return a duplicate of GlobalGroup.
*)
PROCEDURE DupGroup (g: Group) : Group ;
BEGIN
IF g # NIL
THEN
(* Kill old group. *)
KillGroup (g)
END ;
NewGroup (g) ;
WITH g^ DO
(* Copy all sets. *)
FinishedSetArray := DuplicateSet (GlobalGroup^.FinishedSetArray) ;
ToDoList := DuplicateSet (GlobalGroup^.ToDoList) ;
FullyDeclared := DuplicateSet (GlobalGroup^.FullyDeclared) ;
PartiallyDeclared := DuplicateSet (GlobalGroup^.PartiallyDeclared) ;
NilTypedArrays := DuplicateSet (GlobalGroup^.NilTypedArrays) ;
HeldByAlignment := DuplicateSet (GlobalGroup^.HeldByAlignment) ;
FinishedAlignment := DuplicateSet (GlobalGroup^.FinishedAlignment) ;
ToBeSolvedByQuads := DuplicateSet (GlobalGroup^.ToBeSolvedByQuads) ;
Next := NIL
END ;
RETURN g
END DupGroup ;
(*
EqualGroup - return TRUE if group left = right.
*)
PROCEDURE EqualGroup (left, right: Group) : BOOLEAN ;
BEGIN
RETURN ((left = right) OR
(EqualSet (left^.FullyDeclared, right^.FullyDeclared) AND
EqualSet (left^.PartiallyDeclared, right^.PartiallyDeclared) AND
EqualSet (left^.NilTypedArrays, right^.NilTypedArrays) AND
EqualSet (left^.HeldByAlignment, right^.HeldByAlignment) AND
EqualSet (left^.FinishedAlignment, right^.FinishedAlignment) AND
EqualSet (left^.ToDoList, right^.ToDoList) AND
EqualSet (left^.ToBeSolvedByQuads, right^.ToBeSolvedByQuads) AND
EqualSet (left^.FinishedSetArray, right^.FinishedSetArray)))
END EqualGroup ;
(*
LookupSet -
*)
PROCEDURE LookupSet (listtype: ListType) : Set ;
BEGIN
CASE listtype OF
fullydeclared : RETURN GlobalGroup^.FullyDeclared |
partiallydeclared : RETURN GlobalGroup^.PartiallyDeclared |
niltypedarrays : RETURN GlobalGroup^.NilTypedArrays |
heldbyalignment : RETURN GlobalGroup^.HeldByAlignment |
finishedalignment : RETURN GlobalGroup^.FinishedAlignment |
todolist : RETURN GlobalGroup^.ToDoList |
tobesolvedbyquads : RETURN GlobalGroup^.ToBeSolvedByQuads |
finishedsetarray : RETURN GlobalGroup^.FinishedSetArray
ELSE
InternalError ('unknown ListType')
END ;
RETURN NIL
END LookupSet ;
(*
GetEnumList -
*)
PROCEDURE GetEnumList (sym: CARDINAL) : tree ;
BEGIN
IF InBounds(EnumerationIndex, sym)
THEN
RETURN( tree (GetIndice(EnumerationIndex, sym)) )
ELSE
RETURN( NIL )
END
END GetEnumList ;
(*
PutEnumList -
*)
PROCEDURE PutEnumList (sym: CARDINAL; enumlist: tree) ;
BEGIN
PutIndice(EnumerationIndex, sym, enumlist)
END PutEnumList ;
(*
MarkExported - tell GCC to mark all exported procedures in module sym.
*)
PROCEDURE MarkExported (sym: CARDINAL) ;
BEGIN
IF Optimizing
THEN
MarkFunctionReferenced(Mod2Gcc(sym)) ;
IF IsDefImp(sym) OR IsModule(sym)
THEN
ForeachExportedDo(sym, MarkExported)
END
END
END MarkExported ;
(*
Chained - checks to see that, sym, has not already been placed on a chain.
It returns the symbol, sym.
*)
PROCEDURE Chained (sym: CARDINAL) : CARDINAL ;
BEGIN
IF IsElementInSet(ChainedList, sym)
THEN
InternalError ('symbol has already been chained onto a previous list')
END ;
IncludeElementIntoSet(ChainedList, sym) ;
RETURN( sym )
END Chained ;
(*
DoStartDeclaration - returns a tree representing a symbol which has
not yet been finished. Used when declaring
recursive types.
*)
PROCEDURE DoStartDeclaration (sym: CARDINAL; p: StartProcedure) : tree ;
VAR
location: location_t ;
BEGIN
IF NOT GccKnowsAbout (sym)
THEN
location := TokenToLocation (GetDeclaredMod (sym)) ;
PreAddModGcc(sym, p (location, KeyToCharStar (GetFullSymName (sym))))
END ;
RETURN Mod2Gcc (sym)
END DoStartDeclaration ;
(*
ArrayComponentsDeclared - returns TRUE if array, sym,
subscripts and type are known.
*)
PROCEDURE ArrayComponentsDeclared (sym: CARDINAL) : BOOLEAN ;
VAR
Subscript : CARDINAL ;
Type, High, Low: CARDINAL ;
BEGIN
Subscript := GetArraySubscript(sym) ;
Assert(IsSubscript(Subscript)) ;
Type := GetDType(Subscript) ;
Low := GetTypeMin(Type) ;
High := GetTypeMax(Type) ;
RETURN( IsFullyDeclared(Type) AND
IsFullyDeclared(Low) AND
IsFullyDeclared(High) )
END ArrayComponentsDeclared ;
(*
GetRecordOfVarient -
*)
PROCEDURE GetRecordOfVarient (sym: CARDINAL) : CARDINAL ;
BEGIN
IF IsVarient(sym) OR IsFieldVarient(sym)
THEN
REPEAT
sym := GetParent(sym)
UNTIL IsRecord(sym)
END ;
RETURN( sym )
END GetRecordOfVarient ;
(*
CanDeclareRecordKind -
*)
PROCEDURE CanDeclareRecordKind (sym: CARDINAL) : BOOLEAN ;
BEGIN
sym := GetRecordOfVarient(sym) ;
RETURN( IsRecord(sym) AND
((GetDefaultRecordFieldAlignment(sym)=NulSym) OR
IsFullyDeclared(GetDefaultRecordFieldAlignment(sym))) )
END CanDeclareRecordKind ;
(*
DeclareRecordKind - works out whether record, sym, is packed or not.
*)
PROCEDURE DeclareRecordKind (sym: CARDINAL) ;
BEGIN
IF IsRecord(sym)
THEN
DetermineIfRecordPacked(sym)
END ;
WatchIncludeList(sym, todolist) ;
WatchRemoveList(sym, heldbyalignment) ;
WatchIncludeList(sym, finishedalignment) ;
IF AllDependantsFullyDeclared(sym)
THEN
(* All good and ready to be solved. *)
END
END DeclareRecordKind ;
(*
CanDeclareRecord -
*)
PROCEDURE CanDeclareRecord (sym: CARDINAL) : BOOLEAN ;
BEGIN
TraverseDependants(sym) ;
IF AllDependantsFullyDeclared(sym)
THEN
RETURN TRUE
ELSE
WatchIncludeList(sym, finishedalignment) ;
RETURN FALSE
END
END CanDeclareRecord ;
(*
FinishDeclareRecord -
*)
PROCEDURE FinishDeclareRecord (sym: CARDINAL) ;
BEGIN
DeclareTypeConstFully(sym) ;
WatchRemoveList(sym, heldbyalignment) ;
WatchRemoveList(sym, finishedalignment) ;
WatchRemoveList(sym, todolist) ;
WatchIncludeList(sym, fullydeclared)
END FinishDeclareRecord ;
(*
CanDeclareTypePartially - return TRUE if we are able to make a
gcc partially created type.
*)
PROCEDURE CanDeclareTypePartially (sym: CARDINAL) : BOOLEAN ;
VAR
type: CARDINAL ;
BEGIN
IF IsElementInSet(GlobalGroup^.PartiallyDeclared, sym)
THEN
RETURN( FALSE )
ELSIF IsProcType(sym) OR IsRecord(sym) OR IsVarient(sym) OR IsFieldVarient(sym)
THEN
RETURN( TRUE )
ELSIF IsType(sym)
THEN
type := GetSType(sym) ;
IF (type#NulSym) AND IsNilTypedArrays(type)
THEN
RETURN( TRUE )
END
END ;
RETURN( FALSE )
END CanDeclareTypePartially ;
(*
DeclareTypePartially - create the gcc partial type symbol from, sym.
*)
PROCEDURE DeclareTypePartially (sym: CARDINAL) ;
VAR
location: location_t ;
BEGIN
(* check to see if we have already partially declared the symbol *)
IF NOT IsElementInSet(GlobalGroup^.PartiallyDeclared, sym)
THEN
IF IsRecord(sym)
THEN
Assert (NOT IsElementInSet (GlobalGroup^.HeldByAlignment, sym)) ;
Assert (DoStartDeclaration (sym, BuildStartRecord) # NIL) ;
WatchIncludeList (sym, heldbyalignment)
ELSIF IsVarient (sym)
THEN
Assert(NOT IsElementInSet(GlobalGroup^.HeldByAlignment, sym)) ;
Assert (DoStartDeclaration(sym, BuildStartVarient) # NIL) ;
WatchIncludeList(sym, heldbyalignment)
ELSIF IsFieldVarient(sym)
THEN
Assert(NOT IsElementInSet(GlobalGroup^.HeldByAlignment, sym)) ;
Assert (DoStartDeclaration(sym, BuildStartFieldVarient) # NIL) ;
WatchIncludeList(sym, heldbyalignment)
ELSIF IsProcType(sym)
THEN
Assert (DoStartDeclaration(sym, BuildStartFunctionType) # NIL) ;
ELSIF IsType(sym)
THEN
IF NOT GccKnowsAbout(sym)
THEN
location := TokenToLocation(GetDeclaredMod(sym)) ;
PreAddModGcc(sym, BuildStartType(location,
KeyToCharStar(GetFullSymName(sym)),
Mod2Gcc(GetSType(sym))))
END
ELSE
InternalError ('do not know how to create a partial type from this symbol')
END ;
WatchIncludeList(sym, partiallydeclared) ;
TraverseDependants(sym)
END
END DeclareTypePartially ;
(*
CanDeclareArrayAsNil -
*)
PROCEDURE CanDeclareArrayAsNil (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsArray(sym) AND ArrayComponentsDeclared(sym) )
END CanDeclareArrayAsNil ;
(*
DeclareArrayAsNil -
*)
PROCEDURE DeclareArrayAsNil (sym: CARDINAL) ;
BEGIN
PreAddModGcc(sym, BuildStartArrayType(BuildIndex(GetDeclaredMod(sym), sym), NIL, GetDType(sym))) ;
WatchIncludeList(sym, niltypedarrays)
END DeclareArrayAsNil ;
(*
CanDeclareArrayPartially -
*)
PROCEDURE CanDeclareArrayPartially (sym: CARDINAL) : BOOLEAN ;
VAR
type: CARDINAL ;
BEGIN
IF IsArray(sym)
THEN
type := GetSType(sym) ;
IF IsPartiallyOrFullyDeclared(type) OR
(IsPointer(type) AND IsNilTypedArrays(type))
THEN
RETURN( TRUE )
END
END ;
RETURN( FALSE )
END CanDeclareArrayPartially ;
(*
DeclareArrayPartially -
*)
PROCEDURE DeclareArrayPartially (sym: CARDINAL) ;
BEGIN
Assert(IsArray(sym) AND GccKnowsAbout(sym)) ;
PutArrayType(Mod2Gcc(sym), Mod2Gcc(GetSType(sym))) ;
WatchIncludeList(sym, partiallydeclared)
END DeclareArrayPartially ;
(*
CanDeclarePointerToNilArray -
*)
PROCEDURE CanDeclarePointerToNilArray (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsPointer(sym) AND IsNilTypedArrays(GetSType(sym)) )
END CanDeclarePointerToNilArray ;
(*
DeclarePointerToNilArray -
*)
PROCEDURE DeclarePointerToNilArray (sym: CARDINAL) ;
BEGIN
PreAddModGcc(sym, BuildPointerType(Mod2Gcc(GetSType(sym)))) ;
WatchIncludeList(sym, niltypedarrays)
END DeclarePointerToNilArray ;
(*
CanPromotePointerFully -
*)
PROCEDURE CanPromotePointerFully (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsPointer(sym) AND IsPartiallyOrFullyDeclared(GetSType(sym)) )
END CanPromotePointerFully ;
(*
PromotePointerFully -
*)
PROCEDURE PromotePointerFully (sym: CARDINAL) ;
BEGIN
WatchIncludeList(sym, fullydeclared)
END PromotePointerFully ;
(*
CompletelyResolved - returns TRUE if a symbols has been completely resolved
and is not partically declared (such as a record).
*)
PROCEDURE CompletelyResolved (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsElementInSet(GlobalGroup^.FullyDeclared, sym) )
END CompletelyResolved ;
(*
IsTypeQ - returns TRUE if all q(dependants) of, sym,
return TRUE.
*)
PROCEDURE IsTypeQ (sym: CARDINAL; q: IsAction) : BOOLEAN ;
BEGIN
IF IsVar(sym)
THEN
RETURN( IsVarDependants(sym, q) )
ELSIF IsEnumeration(sym)
THEN
RETURN( IsEnumerationDependants(sym, q) )
ELSIF IsFieldEnumeration(sym)
THEN
RETURN( TRUE )
ELSIF IsSubrange(sym)
THEN
RETURN( IsSubrangeDependants(sym, q) )
ELSIF IsPointer(sym)
THEN
RETURN( IsPointerDependants(sym, q) )
ELSIF IsRecord(sym)
THEN
RETURN( IsRecordDependants(sym, q) )
ELSIF IsRecordField(sym)
THEN
RETURN( IsRecordFieldDependants(sym, q) )
ELSIF IsVarient(sym)
THEN
RETURN( IsVarientDependants(sym, q) )
ELSIF IsFieldVarient(sym)
THEN
RETURN( IsVarientFieldDependants(sym, q) )
ELSIF IsArray(sym)
THEN
RETURN( IsArrayDependants(sym, q) )
ELSIF IsProcType(sym)
THEN
RETURN( IsProcTypeDependants(sym, q) )
ELSIF IsUnbounded(sym)
THEN
RETURN( IsUnboundedDependants(sym, q) )
ELSIF IsPartialUnbounded(sym)
THEN
InternalError ('should not be declaring a partial unbounded symbol')
ELSIF IsSet(sym)
THEN
RETURN( IsSetDependants(sym, q) )
ELSIF IsType(sym)
THEN
RETURN( IsTypeDependants(sym, q) )
ELSIF IsConst(sym)
THEN
RETURN( IsConstDependants(sym, q) )
ELSIF IsConstructor(sym) OR IsConstSet(sym)
THEN
(* sym can be a constructor, but at present we have not resolved whether
all dependants are constants.
*)
RETURN( IsConstructorDependants(sym, q) )
ELSIF IsProcedure(sym)
THEN
RETURN( IsProcedureDependants(sym, q) )
ELSE
RETURN( TRUE )
END
END IsTypeQ ;
(*
IsNilTypedArrays - returns TRUE if, sym, is dependant upon a NIL typed array
*)
PROCEDURE IsNilTypedArrays (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsElementInSet(GlobalGroup^.NilTypedArrays, sym) )
END IsNilTypedArrays ;
(*
IsFullyDeclared - returns TRUE if, sym, is fully declared.
*)
PROCEDURE IsFullyDeclared (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsElementInSet(GlobalGroup^.FullyDeclared, sym) )
END IsFullyDeclared ;
(*
AllDependantsFullyDeclared - returns TRUE if all dependants of,
sym, are declared.
*)
PROCEDURE AllDependantsFullyDeclared (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsTypeQ(sym, IsFullyDeclared) )
END AllDependantsFullyDeclared ;
(*
NotAllDependantsFullyDeclared - returns TRUE if any dependants of,
sym, are not declared.
*)
PROCEDURE NotAllDependantsFullyDeclared (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( NOT IsTypeQ(sym, IsFullyDeclared) )
END NotAllDependantsFullyDeclared ;
(*
IsPartiallyDeclared - returns TRUE if, sym, is partially declared.
*)
PROCEDURE IsPartiallyDeclared (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsElementInSet(GlobalGroup^.PartiallyDeclared, sym) )
END IsPartiallyDeclared ;
(*
AllDependantsPartiallyDeclared - returns TRUE if all dependants of,
sym, are partially declared.
*)
PROCEDURE AllDependantsPartiallyDeclared (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsTypeQ(sym, IsPartiallyDeclared) )
END AllDependantsPartiallyDeclared ;
(*
NotAllDependantsPartiallyDeclared - returns TRUE if any dependants of,
sym, are not partially declared.
*)
PROCEDURE NotAllDependantsPartiallyDeclared (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( NOT IsTypeQ(sym, IsPartiallyDeclared) )
END NotAllDependantsPartiallyDeclared ;
(*
IsPartiallyOrFullyDeclared - returns TRUE if, sym, is partially or fully declared.
*)
PROCEDURE IsPartiallyOrFullyDeclared (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsElementInSet(GlobalGroup^.PartiallyDeclared, sym) OR
IsElementInSet(GlobalGroup^.FullyDeclared, sym) )
END IsPartiallyOrFullyDeclared ;
(*
AllDependantsPartiallyOrFullyDeclared - returns TRUE if all dependants of,
sym, are partially or fully declared.
*)
PROCEDURE AllDependantsPartiallyOrFullyDeclared (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsTypeQ(sym, IsPartiallyOrFullyDeclared) )
END AllDependantsPartiallyOrFullyDeclared ;
(*
NotAllDependantsPartiallyOrFullyDeclared - returns TRUE if all dependants of,
sym, are not partially and not fully
declared.
*)
(*
PROCEDURE NotAllDependantsPartiallyOrFullyDeclared (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsTypeQ(sym, IsPartiallyOrFullyDeclared) )
END NotAllDependantsPartiallyOrFullyDeclared ;
*)
(*
TypeConstDependantsFullyDeclared - returns TRUE if sym is a constant or
type and its dependants are fully
declared.
*)
PROCEDURE TypeConstDependantsFullyDeclared (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( (NOT IsVar(sym)) AND
(NOT IsRecord(sym)) AND
(NOT IsParameter(sym)) AND
AllDependantsFullyDeclared(sym) )
END TypeConstDependantsFullyDeclared ;
(*
CanBeDeclaredViaPartialDependants - returns TRUE if this symbol
can be declared by partial
dependants. Such a symbol must
be a record, proctype or
an array.
*)
PROCEDURE CanBeDeclaredViaPartialDependants (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( (IsPointer(sym) OR IsProcType(sym)) AND
AllDependantsPartiallyOrFullyDeclared(sym) )
END CanBeDeclaredViaPartialDependants ;
(*
DeclareConstFully - will add, sym, to the fully declared list and
also remove it from the to do list. This is
called indirectly from M2GenGCC as it calculates
constants during quadruple processing.
*)
PROCEDURE DeclareConstFully (sym: CARDINAL) ;
BEGIN
WatchIncludeList(sym, fullydeclared) ;
WatchRemoveList(sym, todolist) ;
WatchRemoveList(sym, partiallydeclared) ;
WatchRemoveList(sym, tobesolvedbyquads)
END DeclareConstFully ;
(*
PutToBeSolvedByQuads - places, sym, to this list and returns,
sym.
*)
PROCEDURE PutToBeSolvedByQuads (sym: CARDINAL) ;
BEGIN
WatchIncludeList(sym, tobesolvedbyquads)
END PutToBeSolvedByQuads ;
(*
DeclareTypeConstFully - declare the GCC type and add the double
book keeping entry.
*)
PROCEDURE DeclareTypeConstFully (sym: CARDINAL) ;
VAR
t: tree ;
BEGIN
IF NOT IsElementInSet(GlobalGroup^.ToBeSolvedByQuads, sym)
THEN
IF IsModule(sym) OR IsDefImp(sym)
THEN
WatchIncludeList(sym, fullydeclared) ;
WatchRemoveList(sym, partiallydeclared) ;
WatchRemoveList(sym, todolist)
ELSIF IsProcedure(sym)
THEN
DeclareProcedureToGcc(sym) ;
WatchIncludeList(sym, fullydeclared) ;
WatchRemoveList(sym, partiallydeclared) ;
WatchRemoveList(sym, todolist)
ELSE
t := TypeConstFullyDeclared(sym) ;
IF t#NIL
THEN
(* add relationship between gccsym and sym *)
PreAddModGcc(sym, t) ;
WatchIncludeList(sym, fullydeclared) ;
WatchRemoveList(sym, partiallydeclared) ;
WatchRemoveList(sym, heldbyalignment) ;
WatchRemoveList(sym, finishedalignment) ;
WatchRemoveList(sym, todolist)
END
END
END
END DeclareTypeConstFully ;
(*
DeclareTypeFromPartial - declare the full GCC type from a partial type
and add the double book keeping entry.
*)
PROCEDURE DeclareTypeFromPartial (sym: CARDINAL) ;
VAR
t: tree ;
BEGIN
t := CompleteDeclarationOf(sym) ;
IF t=NIL
THEN
InternalError ('expecting to be able to create a gcc type')
ELSE
AddModGcc(sym, t) ;
WatchIncludeList(sym, fullydeclared) ;
WatchRemoveList(sym, partiallydeclared)
END
END DeclareTypeFromPartial ;
(*
CanBeDeclaredPartiallyViaPartialDependants - returns TRUE if, sym,
can be partially declared via
another partially declared type.
*)
PROCEDURE CanBeDeclaredPartiallyViaPartialDependants (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( IsType(sym) AND AllDependantsPartiallyDeclared(sym) )
END CanBeDeclaredPartiallyViaPartialDependants ;
(*
EmitCircularDependencyError - issue a dependency error.
*)
PROCEDURE EmitCircularDependencyError (sym: CARDINAL) ;
BEGIN
(* Ensure we only issue one dependency message per symbol for this
error classification. *)
IF NOT IsElementInSet (ErrorDepList, sym)
THEN
IncludeElementIntoSet (ErrorDepList, sym) ;
IF IsVar (sym) OR IsParameter (sym)
THEN
MetaError1 ('circular dependency error found when trying to resolve {%1Had}',
sym)
ELSE
MetaError1 ('circular dependency error found when trying to resolve {%1Dad}',
sym)
END
END
END EmitCircularDependencyError ;
TYPE
Rule = (norule, partialtype, arraynil, pointernilarray, arraypartial,
pointerfully, recordkind, recordfully, typeconstfully,
pointerfrompartial, typefrompartial, partialfrompartial,
partialtofully, circulartodo, circularpartial, circularniltyped) ;
VAR
bodyp : WalkAction ;
bodyq : IsAction ;
bodyt : ListType ;
bodyr : Rule ;
recursionCaught,
oneResolved,
noMoreWritten : BOOLEAN ;
(*
WriteRule - writes out the name of the rule.
*)
PROCEDURE WriteRule ;
BEGIN
IF Debugging
THEN
CASE bodyr OF
norule : printf0('norule') |
partialtype : printf0('partialtype') |
arraynil : printf0('arraynil') |
pointernilarray : printf0('pointernilarray') |
arraypartial : printf0('arraypartial') |
pointerfully : printf0('pointerfully') |
recordkind : printf0('recordkind') |
recordfully : printf0('recordfully') |
typeconstfully : printf0('typeconstfully') |
pointerfrompartial: printf0('pointerfrompartial') |
typefrompartial : printf0('typefrompartial') |
partialfrompartial: printf0('partialfrompartial') |
partialtofully : printf0('partialtofully') |
circulartodo : printf0('circulartodo') |
circularpartial : printf0('circularpartial') |
circularniltyped : printf0('circularniltyped')
ELSE
InternalError ('unknown rule')
END
END
END WriteRule ;
(*
Body -
*)
PROCEDURE Body (sym: CARDINAL) ;
BEGIN
IF bodyq (sym)
THEN
WatchRemoveList (sym, bodyt) ;
bodyp (sym) ;
(* The bodyp (sym) procedure function might have replaced sym into the set. *)
IF NOT IsElementInSet (LookupSet (bodyt), sym)
THEN
noMoreWritten := FALSE ;
oneResolved := TRUE
END
END
END Body ;
(*
ForeachTryDeclare - while q (of one sym in set t) is true
for each symbol in set t,
if q (sym)
then
p (sym)
end
end
end
*)
PROCEDURE ForeachTryDeclare (t: ListType; r: Rule;
q: IsAction; p: WalkAction) : BOOLEAN ;
BEGIN
IF recursionCaught
THEN
InternalError ('caught recursive cycle in ForeachTryDeclare')
END ;
bodyt := t ;
bodyq := q ;
bodyp := p ;
bodyr := r ;
recursionCaught := TRUE ;
oneResolved := FALSE ;
REPEAT
noMoreWritten := TRUE ;
ForeachElementInSetDo (LookupSet (t), Body)
UNTIL noMoreWritten ;
bodyr := norule ;
recursionCaught := FALSE ;
RETURN( oneResolved )
END ForeachTryDeclare ;
(*
DeclaredOutandingTypes - writes out any types that have their
dependants solved. It returns TRUE if
all outstanding types have been written.
*)
PROCEDURE DeclaredOutstandingTypes (ForceComplete: BOOLEAN) : BOOLEAN ;
VAR
finished: BOOLEAN ;
copy : Group ;
BEGIN
copy := NIL ;
finished := FALSE ;
REPEAT
IF Progress AND (copy # NIL)
THEN
IF NOT EqualGroup (copy, GlobalGroup)
THEN
DebugSetNumbers ;
DebugSets
END
END ;
copy := DupGroup (copy) ;
IF ForeachTryDeclare (todolist,
partialtype,
CanDeclareTypePartially,
DeclareTypePartially)
THEN
(* continue looping *)
ELSIF ForeachTryDeclare (todolist,
arraynil,
CanDeclareArrayAsNil,
DeclareArrayAsNil)
THEN
(* continue looping *)
ELSIF ForeachTryDeclare (todolist,
pointernilarray,
CanDeclarePointerToNilArray,
DeclarePointerToNilArray)
THEN
(* continue looping *)
ELSIF ForeachTryDeclare (niltypedarrays,
arraypartial,
CanDeclareArrayPartially,
DeclareArrayPartially)
THEN
(* continue looping *)
ELSIF ForeachTryDeclare (niltypedarrays,
pointerfully,
CanPromotePointerFully,
PromotePointerFully)
THEN
(* continue looping *)
ELSIF ForeachTryDeclare (heldbyalignment,
recordkind,
CanDeclareRecordKind,
DeclareRecordKind)
THEN
(* continue looping *)
ELSIF ForeachTryDeclare (finishedalignment,
recordfully,
CanDeclareRecord,
FinishDeclareRecord)
THEN
(* continue looping *)
ELSIF ForeachTryDeclare (todolist,
typeconstfully,
TypeConstDependantsFullyDeclared,
DeclareTypeConstFully)
THEN
(* Continue looping. *)
ELSIF ForeachTryDeclare (todolist,
typefrompartial,
CanBeDeclaredViaPartialDependants,
DeclareTypeFromPartial)
THEN
(* Continue looping. *)
ELSIF ForeachTryDeclare (partiallydeclared,
partialfrompartial,
CanBeDeclaredPartiallyViaPartialDependants,
DeclareTypePartially)
THEN
(* Continue looping. *)
ELSIF ForeachTryDeclare (partiallydeclared,
partialtofully,
TypeConstDependantsFullyDeclared,
DeclareTypeConstFully)
THEN
(* Continue looping. *)
ELSE
(* Nothing left to do (and constants are resolved elsewhere). *)
finished := TRUE
END
UNTIL finished ;
KillGroup (copy) ;
IF ForceComplete
THEN
IF ForeachTryDeclare (todolist,
circulartodo,
NotAllDependantsFullyDeclared,
EmitCircularDependencyError)
THEN
ELSIF ForeachTryDeclare (partiallydeclared,
circularpartial,
NotAllDependantsPartiallyDeclared,
EmitCircularDependencyError)
THEN
ELSIF ForeachTryDeclare (niltypedarrays,
circularniltyped,
NotAllDependantsPartiallyDeclared,
EmitCircularDependencyError)
THEN
END
END ;
RETURN NoOfElementsInSet (GlobalGroup^.ToDoList) = 0
END DeclaredOutstandingTypes ;
(*
CompleteDeclarationOf - returns the GCC Tree for, sym, if it can
be created from partially or fully declared
dependents.
*)
PROCEDURE CompleteDeclarationOf (sym: CARDINAL) : tree ;
BEGIN
IF IsArray(sym)
THEN
RETURN( DeclareArray(sym) )
ELSIF IsProcType(sym)
THEN
RETURN( DeclareProcType(sym) )
ELSIF IsRecordField(sym)
THEN
RETURN( DeclareRecordField(sym) )
ELSIF IsPointer(sym)
THEN
RETURN( DeclarePointer(sym) )
ELSE
RETURN( NIL )
END
END CompleteDeclarationOf ;
(*
DeclareType - here a type has been created via TYPE foo = bar,
we must tell GCC about it.
*)
PROCEDURE DeclareType (sym: CARDINAL) : tree ;
VAR
t : tree ;
location: location_t ;
BEGIN
IF GetSType(sym)=NulSym
THEN
MetaError1('base type {%1Ua} not understood', sym) ;
InternalError ('base type should have been declared')
ELSE
IF GetSymName(sym)=NulName
THEN
RETURN( tree(Mod2Gcc(GetSType(sym))) )
ELSE
location := TokenToLocation(GetDeclaredMod(sym)) ;
IF GccKnowsAbout(sym)
THEN
t := Mod2Gcc(sym)
ELSE
(* not partially declared therefore start it *)
t := BuildStartType(location,
KeyToCharStar(GetFullSymName(sym)), Mod2Gcc(GetSType(sym)))
END ;
t := BuildEndType(location, t) ; (* now finish it *)
RETURN( t )
END
END
END DeclareType ;
(*
DeclareIntegerConstant - declares an integer constant.
*)
(*
PROCEDURE DeclareIntegerConstant (sym: CARDINAL; value: INTEGER) ;
BEGIN
PreAddModGcc(sym, BuildIntegerConstant(value)) ;
WatchRemoveList(sym, todolist) ;
WatchIncludeList(sym, fullydeclared)
END DeclareIntegerConstant ;
*)
(*
DeclareIntegerFromTree - declares an integer constant from a Tree, value.
*)
PROCEDURE DeclareConstantFromTree (sym: CARDINAL; value: tree) ;
BEGIN
PreAddModGcc(sym, value) ;
WatchRemoveList(sym, todolist) ;
WatchIncludeList(sym, fullydeclared)
END DeclareConstantFromTree ;
(*
DeclareCharConstant - declares a character constant.
*)
PROCEDURE DeclareCharConstant (tokenno: CARDINAL; sym: CARDINAL) ;
VAR
location: location_t ;
BEGIN
Assert (IsConstStringKnown (sym)) ;
location := TokenToLocation(tokenno) ;
PreAddModGcc(sym, BuildCharConstant(location, KeyToCharStar(GetString(sym)))) ;
WatchRemoveList(sym, todolist) ;
WatchIncludeList(sym, fullydeclared)
END DeclareCharConstant ;
(*
DeclareStringConstant - declares a string constant the sym will be known.
*)
PROCEDURE DeclareStringConstant (tokenno: CARDINAL; sym: CARDINAL) ;
VAR
symtree : tree ;
BEGIN
Assert (IsConstStringKnown (sym)) ;
IF IsConstStringM2nul (sym) OR IsConstStringCnul (sym)
THEN
(* in either case the string needs a nul terminator. If the string
is a C variant it will already have had any escape characters applied.
The BuildCStringConstant only adds the nul terminator. *)
symtree := BuildCStringConstant (KeyToCharStar (GetString (sym)),
GetStringLength (tokenno, sym))
ELSE
symtree := BuildStringConstant (KeyToCharStar (GetString (sym)),
GetStringLength (tokenno, sym))
END ;
PreAddModGcc (sym, symtree) ;
WatchRemoveList (sym, todolist) ;
WatchIncludeList (sym, fullydeclared)
END DeclareStringConstant ;
(*
PromoteToString - declare, sym, and then promote it to a string.
Note that if sym is a single character we do
*not* record it as a string
but as a char however we always
return a string constant.
*)
PROCEDURE PromoteToString (tokenno: CARDINAL; sym: CARDINAL) : tree ;
VAR
size: CARDINAL ;
ch : CHAR ;
BEGIN
DeclareConstant (tokenno, sym) ;
IF IsConst (sym) AND (GetSType (sym) = Char)
THEN
PushValue (sym) ;
ch := PopChar (tokenno) ;
RETURN BuildCStringConstant (string (InitStringChar (ch)), 1)
ELSE
Assert (IsConstStringKnown (sym)) ;
size := GetStringLength (tokenno, sym) ;
IF size > 1
THEN
(* It will be already be declared as a string, so return it. *)
RETURN tree (Mod2Gcc (sym))
ELSE
RETURN BuildStringConstant (KeyToCharStar (GetString (sym)),
GetStringLength (tokenno, sym))
END
END
END PromoteToString ;
(*
PromoteToCString - declare, sym, and then promote it to a string.
Note that if sym is a single character we do
*not* record it as a string
but as a char however we always
return a string constant.
*)
PROCEDURE PromoteToCString (tokenno: CARDINAL; sym: CARDINAL) : tree ;
VAR
size: CARDINAL ;
ch : CHAR ;
BEGIN
DeclareConstant (tokenno, sym) ;
Assert (IsConstStringKnown (sym)) ;
IF IsConst (sym) AND (GetSType (sym) = Char)
THEN
PushValue (sym) ;
ch := PopChar (tokenno) ;
RETURN BuildCStringConstant (string (InitStringChar (ch)), 1)
ELSE
size := GetStringLength (tokenno, sym) ;
RETURN BuildCStringConstant (KeyToCharStar (GetString (sym)),
size)
END
END PromoteToCString ;
(*
WalkConstructor - walks all dependants of, sym.
*)
PROCEDURE WalkConstructor (sym: CARDINAL; p: WalkAction) ;
VAR
type: CARDINAL ;
BEGIN
type := GetSType(sym) ;
IF type#NulSym
THEN
WalkDependants(type, p) ;
WalkConstructorDependants(sym, p)
END
END WalkConstructor ;
(*
DeclareConstructor - declares a constructor.
*)
PROCEDURE DeclareConstructor (tokenno: CARDINAL; quad: CARDINAL; sym: CARDINAL) ;
BEGIN
IF sym=NulSym
THEN
InternalError ('trying to declare the NulSym')
END ;
IF IsConstructor (sym) AND (NOT GccKnowsAbout (sym))
THEN
WalkConstructor (sym, TraverseDependants) ;
DeclareTypesConstantsProceduresInRange (GetScope (sym), quad, quad) ;
Assert (IsConstructorDependants (sym, IsFullyDeclared)) ;
PushValue (sym) ;
DeclareConstantFromTree (sym, PopConstructorTree (tokenno))
END
END DeclareConstructor ;
(*
TryDeclareConstructor - try and declare a constructor. If, sym, is a
constructor try and declare it, if we cannot
then enter it into the to do list.
*)
PROCEDURE TryDeclareConstructor (tokenno: CARDINAL; sym: CARDINAL) ;
BEGIN
IF sym#NulSym
THEN
IF IsConstructor(sym) AND (NOT GccKnowsAbout(sym))
THEN
WalkConstructor(sym, TraverseDependants) ;
IF NOT IsElementInSet(GlobalGroup^.ToBeSolvedByQuads, sym)
THEN
TryEvaluateValue(sym) ;
IF IsConstructorDependants(sym, IsFullyDeclared)
THEN
PushValue(sym) ;
DeclareConstantFromTree(sym, PopConstructorTree(tokenno))
END
END
END
END
END TryDeclareConstructor ;
(*
WalkConst - walks all dependants of, sym.
*)
PROCEDURE WalkConst (sym: CARDINAL; p: WalkAction) ;
VAR
type: CARDINAL ;
BEGIN
Assert (IsConst (sym)) ;
type := GetSType (sym) ;
IF type # NulSym
THEN
p (type)
END ;
IF IsConstSet (sym) OR IsConstructor (sym)
THEN
WalkConstructor (sym, p)
END
END WalkConst ;
(*
IsConstDependants - returns TRUE if the symbol, sym,
q(dependants) all return TRUE.
*)
PROCEDURE IsConstDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
type: CARDINAL ;
BEGIN
Assert (IsConst (sym)) ;
type := GetSType (sym) ;
IF type # NulSym
THEN
IF NOT q (type)
THEN
RETURN FALSE
END
END ;
IF IsConstSet (sym) OR IsConstructor (sym)
THEN
RETURN IsConstructorDependants (sym, q)
END ;
RETURN IsValueSolved (sym)
END IsConstDependants ;
(*
TryDeclareConstant - try and declare a constant. If, sym, is a
constant try and declare it, if we cannot
then enter it into the to do list.
*)
PROCEDURE TryDeclareConstant (tokenno: CARDINAL; sym: CARDINAL) ;
VAR
type: CARDINAL ;
BEGIN
TryDeclareConstructor(tokenno, sym) ;
IF IsConst(sym)
THEN
TraverseDependants(sym) ;
type := GetSType(sym) ;
IF (type#NulSym) AND (NOT CompletelyResolved(type))
THEN
TraverseDependants(sym) ;
RETURN
END ;
IF IsConstructor(sym) AND (NOT IsConstructorConstant(sym))
THEN
TraverseDependants(sym) ;
RETURN
END ;
IF (IsConstructor(sym) OR IsConstSet(sym)) AND (type=NulSym)
THEN
TraverseDependants(sym) ;
RETURN
END ;
IF IsElementInSet(GlobalGroup^.ToBeSolvedByQuads, sym)
THEN
(* we allow the above rules to be executed even if it is fully declared
so to ensure that types of compiler builtin constants (BitsetSize
etc) are fully declared.
However at this point if, sym, is fully declared we return
*)
IF IsFullyDeclared(sym)
THEN
RETURN
END ;
TraverseDependants(sym)
ELSE
TryDeclareConst(tokenno, sym)
END
END
END TryDeclareConstant ;
(*
IsAnyType - return TRUE if sym is any Modula-2 type.
*)
PROCEDURE IsAnyType (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN (IsRecord(sym) OR IsType(sym) OR IsRecordField(sym) OR
IsPointer(sym) OR IsArray(sym) OR IsSet (sym) OR IsEnumeration (sym) OR
IsPointer (sym))
END IsAnyType ;
(*
TryDeclareType - try and declare a type. If sym is a
type try and declare it, if we cannot
then enter it into the to do list.
*)
PROCEDURE TryDeclareType (type: CARDINAL) ;
BEGIN
IF (type#NulSym) AND IsAnyType (type)
THEN
TraverseDependants (type)
END
END TryDeclareType ;
(*
DeclareConstant - checks to see whether, sym, is a constant and
declares the constant to gcc.
*)
PROCEDURE DeclareConstant (tokenno: CARDINAL; sym: CARDINAL) ;
VAR
type: CARDINAL ;
t : tree ;
BEGIN
IF IsConst(sym)
THEN
TraverseDependants(sym) ;
type := GetSType(sym) ;
Assert((type=NulSym) OR CompletelyResolved(type)) ;
Assert((NOT IsConstructor(sym)) OR IsConstructorConstant(sym)) ;
Assert((type#NulSym) OR (NOT (IsConstructor(sym) OR IsConstSet(sym)))) ;
t := DeclareConst(tokenno, sym) ;
Assert(t#NIL)
END
END DeclareConstant ;
(*
DeclareConstString -
*)
PROCEDURE DeclareConstString (tokenno: CARDINAL; sym: CARDINAL) : BOOLEAN ;
VAR
size: CARDINAL ;
BEGIN
IF IsConstStringKnown (sym)
THEN
size := GetStringLength (tokenno, sym) ;
IF size = 1
THEN
DeclareCharConstant (tokenno, sym)
ELSE
DeclareStringConstant (tokenno, sym)
END ;
RETURN TRUE
END ;
RETURN FALSE
END DeclareConstString ;
(*
TryDeclareConst - try to declare a const to gcc. If it cannot
declare the symbol it places it into the
todolist.
*)
PROCEDURE TryDeclareConst (tokenno: CARDINAL; sym: CARDINAL) ;
VAR
type: CARDINAL ;
BEGIN
IF NOT GccKnowsAbout(sym)
THEN
IF IsConstructor(sym) OR IsConstSet(sym)
THEN
WalkConstructorDependants(sym, TraverseDependants) ;
TryEvaluateValue(sym) ;
IF NOT IsConstructorDependants(sym, IsFullyDeclared)
THEN
TraverseDependants(sym) ;
RETURN
END ;
IF NOT IsConstructorConstant(sym)
THEN
RETURN
END
END ;
IF IsConstString(sym) AND IsConstStringKnown (sym)
THEN
IF DeclareConstString (tokenno, sym)
THEN
END
ELSIF IsValueSolved(sym)
THEN
PushValue(sym) ;
IF IsConstSet(sym)
THEN
DeclareConstantFromTree(sym, PopSetTree(tokenno))
ELSIF IsConstructor(sym)
THEN
DeclareConstantFromTree(sym, PopConstructorTree(tokenno))
ELSIF IsRealType (GetDType (sym)) OR IsRealN (GetDType (sym))
THEN
type := GetDType(sym) ;
DeclareConstantFromTree(sym, BuildConvert(TokenToLocation(tokenno), Mod2Gcc(type), PopRealTree(), TRUE))
ELSIF IsComplexType(GetDType(sym))
THEN
type := GetDType(sym) ;
DeclareConstantFromTree(sym, BuildConvert(TokenToLocation(tokenno), Mod2Gcc(type), PopComplexTree(), TRUE))
ELSE
IF GetSType(sym)=NulSym
THEN
type := ZType
ELSE
type := GetDType(sym)
END ;
DeclareConstantFromTree(sym, BuildConvert(TokenToLocation(tokenno), Mod2Gcc(type), PopIntegerTree(), TRUE))
END
ELSE
TraverseDependants(sym)
END
END
END TryDeclareConst ;
(*
DeclareConst - declares a const to gcc and returns a Tree.
*)
PROCEDURE DeclareConst (tokenno: CARDINAL; sym: CARDINAL) : tree ;
VAR
type: CARDINAL ;
BEGIN
IF GccKnowsAbout(sym)
THEN
RETURN( Mod2Gcc(sym) )
END ;
IF IsConstructor(sym) OR IsConstSet(sym)
THEN
EvaluateValue(sym)
END ;
IF IsConstString(sym)
THEN
IF DeclareConstString (tokenno, sym)
THEN
END
ELSIF IsValueSolved(sym)
THEN
PushValue(sym) ;
IF IsConstSet(sym)
THEN
DeclareConstantFromTree(sym, PopSetTree(tokenno))
ELSIF IsConstructor(sym)
THEN
DeclareConstantFromTree(sym, PopConstructorTree(tokenno))
ELSIF IsRealType(GetDType(sym))
THEN
type := GetDType(sym) ;
DeclareConstantFromTree(sym, BuildConvert(TokenToLocation(tokenno), Mod2Gcc(type), PopRealTree(), TRUE))
ELSIF IsComplexType(GetDType(sym))
THEN
type := GetDType(sym) ;
DeclareConstantFromTree(sym, BuildConvert(TokenToLocation(tokenno), Mod2Gcc(type), PopComplexTree(), TRUE))
ELSE
IF GetSType(sym)=NulSym
THEN
type := ZType
ELSE
type := GetDType(sym)
END ;
DeclareConstantFromTree(sym, BuildConvert(TokenToLocation(tokenno), Mod2Gcc(type), PopIntegerTree(), TRUE))
END
END ;
IF GccKnowsAbout(sym)
THEN
RETURN( Mod2Gcc(sym) )
ELSE
RETURN( NIL )
END
END DeclareConst ;
(*
DeclareParameters -
*)
PROCEDURE DeclareParameters (sym: CARDINAL) ;
BEGIN
DeclareUnboundedProcedureParameters(sym)
END DeclareParameters ;
VAR
unboundedp: WalkAction ;
(*
WalkFamilyOfUnbounded -
*)
PROCEDURE WalkFamilyOfUnbounded (oaf: CARDINAL <* unused *> ; dim: CARDINAL <* unused *> ; unbounded: CARDINAL) ;
BEGIN
IF unbounded # NulSym
THEN
unboundedp (unbounded)
END
END WalkFamilyOfUnbounded ;
(*
WalkAssociatedUnbounded -
*)
PROCEDURE WalkAssociatedUnbounded (sym: CARDINAL; p: WalkAction) ;
VAR
oaf: CARDINAL ;
o : WalkAction ;
BEGIN
oaf := GetOAFamily(sym) ;
o := unboundedp ;
unboundedp := p ;
ForeachOAFamily (oaf, WalkFamilyOfUnbounded) ;
unboundedp := o
END WalkAssociatedUnbounded ;
(*
WalkDependants - walks through all dependants of, Sym,
calling, p, for each dependant.
*)
PROCEDURE WalkDependants (sym: CARDINAL; p: WalkAction) ;
BEGIN
WalkAssociatedUnbounded(sym, p) ;
IF IsComponent(sym)
THEN
WalkComponentDependants(sym, p)
ELSIF IsEnumeration(sym)
THEN
WalkEnumerationDependants(sym, p)
ELSIF IsSubrange(sym)
THEN
WalkSubrangeDependants(sym, p)
ELSIF IsPointer(sym)
THEN
WalkPointerDependants(sym, p)
ELSIF IsRecord(sym)
THEN
WalkRecordDependants(sym, p)
ELSIF IsVarient(sym)
THEN
WalkVarientDependants(sym, p)
ELSIF IsRecordField(sym)
THEN
WalkRecordFieldDependants(sym, p)
ELSIF IsFieldVarient(sym)
THEN
WalkVarientFieldDependants(sym, p)
ELSIF IsArray(sym)
THEN
WalkArrayDependants(sym, p)
ELSIF IsProcType(sym)
THEN
WalkProcTypeDependants(sym, p)
ELSIF IsUnbounded(sym)
THEN
WalkUnboundedDependants(sym, p)
ELSIF IsSet(sym)
THEN
WalkSetDependants(sym, p)
ELSIF IsType(sym)
THEN
WalkTypeDependants(sym, p)
ELSIF IsConst(sym)
THEN
WalkConst(sym, p)
ELSIF IsVar(sym)
THEN
WalkVarDependants(sym, p)
ELSIF IsProcedure(sym)
THEN
WalkProcedureDependants(sym, p)
END
END WalkDependants ;
(*
TraverseDependantsInner -
*)
PROCEDURE TraverseDependantsInner (sym: WORD) ;
BEGIN
IF (NOT IsElementInSet(GlobalGroup^.FullyDeclared, sym)) AND
(NOT IsElementInSet(GlobalGroup^.ToDoList, sym))
THEN
WatchIncludeList(sym, todolist)
END ;
IF NOT IsElementInSet(VisitedList, sym)
THEN
IncludeElementIntoSet(VisitedList, sym) ;
WalkDependants(sym, TraverseDependantsInner)
END
END TraverseDependantsInner ;
(*
TraverseDependants - walks, sym, dependants. But it checks
to see that, sym, is not on the
FullyDeclared and not on the ToDoList.
*)
PROCEDURE TraverseDependants (sym: WORD) ;
BEGIN
IF VisitedList=NIL
THEN
VisitedList := InitSet(1) ;
TraverseDependantsInner(sym) ;
VisitedList := KillSet(VisitedList)
ELSE
InternalError ('recursive call to TraverseDependants caught')
END
END TraverseDependants ;
(*
WalkTypeInfo - walks type, sym, and its dependants.
*)
PROCEDURE WalkTypeInfo (sym: WORD) ;
BEGIN
IF IsVarient(sym)
THEN
InternalError ('why have we reached here?')
ELSIF IsVar(sym)
THEN
WalkTypeInfo(GetSType(sym)) ;
IF GetVarBackEndType(sym)#NulSym
THEN
WalkTypeInfo(GetVarBackEndType(sym))
END
ELSIF IsAModula2Type(sym)
THEN
TraverseDependants(sym)
END
END WalkTypeInfo ;
(*
DeclareUnboundedProcedureParameters -
*)
PROCEDURE DeclareUnboundedProcedureParameters (sym: WORD) ;
VAR
param,
type,
p, i : CARDINAL ;
location : location_t ;
BEGIN
IF IsProcedure(sym)
THEN
p := NoOfParamAny (sym) ;
i := p ;
WHILE i>0 DO
IF IsUnboundedParamAny (sym, i)
THEN
param := GetNthParamAny (sym, i) ;
type := GetSType(param) ;
TraverseDependants(type) ;
IF GccKnowsAbout(type)
THEN
location := TokenToLocation(GetDeclaredMod(type)) ;
BuildTypeDeclaration(location, Mod2Gcc(type))
END
ELSE
param := GetNth(sym, i) ;
type := GetSType(param) ;
TraverseDependants(type)
END ;
DEC(i)
END
END
END DeclareUnboundedProcedureParameters ;
(*
WalkUnboundedProcedureParameters -
*)
PROCEDURE WalkUnboundedProcedureParameters (sym: WORD) ;
VAR
param,
type,
p, i: CARDINAL ;
BEGIN
IF IsProcedure (sym)
THEN
p := NoOfParamAny (sym) ;
i := p ;
WHILE i>0 DO
IF IsUnboundedParamAny (sym, i)
THEN
param := GetNthParamAny (sym, i)
ELSE
param := GetNth (sym, i)
END ;
type := GetSType (param) ;
WalkTypeInfo (type) ;
DEC (i)
END
END
END WalkUnboundedProcedureParameters ;
(*
WalkTypesInProcedure - walk all types in procedure, Sym.
*)
PROCEDURE WalkTypesInProcedure (sym: WORD) ;
BEGIN
ForeachLocalSymDo(sym, TraverseDependants)
END WalkTypesInProcedure ;
(*
WalkTypesInModule - declare all types in module, Sym, to GCC.
*)
PROCEDURE WalkTypesInModule (sym: WORD) ;
VAR
n: Name ;
BEGIN
IF Debugging
THEN
n := GetSymName(sym) ;
printf1('Declaring types in MODULE %a\n', n)
END ;
ForeachLocalSymDo(sym, WalkTypeInfo) ;
ForeachLocalSymDo(sym, WalkUnboundedProcedureParameters) ;
ForeachInnerModuleDo(sym, WalkTypesInModule)
END WalkTypesInModule ;
(*
IsRecordFieldDependants - returns TRUE if the record field
symbol, sym, p(dependants) all return TRUE.
*)
PROCEDURE IsRecordFieldDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
align: CARDINAL ;
final: BOOLEAN ;
BEGIN
final := TRUE ;
IF NOT q(GetSType(sym))
THEN
final := FALSE
END ;
align := GetAlignment(sym) ;
IF (align#NulSym) AND (NOT q(align))
THEN
final := FALSE
END ;
RETURN( final )
END IsRecordFieldDependants ;
(*
GetModuleWhereDeclared - returns the module where, Sym, was created.
*)
PROCEDURE GetModuleWhereDeclared (sym: CARDINAL) : CARDINAL ;
VAR
s: CARDINAL ;
BEGIN
s := GetScope(sym) ;
IF (s=NulSym) OR IsDefImp(s) OR
(IsModule(s) AND (GetScope(s)=NulSym))
THEN
RETURN( s )
ELSE
RETURN( GetModuleWhereDeclared(s) )
END
END GetModuleWhereDeclared ;
(*
IsPseudoProcFunc - returns TRUE if Sym is a pseudo function or procedure.
*)
PROCEDURE IsPseudoProcFunc (Sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN(
IsPseudoBaseProcedure(Sym) OR IsPseudoBaseFunction(Sym) OR
IsPseudoSystemFunction(Sym)
)
END IsPseudoProcFunc ;
(*
IsProcedureGccNested - returns TRUE if procedure, sym, will be considered
as nested by GCC.
This will occur if either its outer defining scope
is a procedure or is a module which is inside a
procedure.
*)
PROCEDURE IsProcedureGccNested (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN(
IsProcedureNested(sym) OR
(IsModule(GetScope(sym)) AND IsModuleWithinProcedure(GetScope(sym)))
)
END IsProcedureGccNested ;
(*
IsExternal -
*)
PROCEDURE IsExternal (sym: CARDINAL) : BOOLEAN ;
VAR
mod: CARDINAL ;
BEGIN
Assert (NOT IsDefImp (sym)) ;
IF IsProcedure (sym) AND IsExtern (sym)
THEN
RETURN TRUE
END ;
mod := GetScope(sym) ;
REPEAT
IF mod=NulSym
THEN
RETURN( FALSE )
ELSIF IsDefImp(mod)
THEN
RETURN( mod#GetMainModule() )
END ;
mod := GetScope(mod)
UNTIL mod=NulSym ;
RETURN( FALSE )
END IsExternal ;
(*
IsExternalToWholeProgram - return TRUE if the symbol, sym, is external to the
sources that we have parsed.
*)
PROCEDURE IsExternalToWholeProgram (sym: CARDINAL) : BOOLEAN ;
VAR
mod: CARDINAL ;
BEGIN
mod := GetScope(sym) ;
REPEAT
IF mod=NulSym
THEN
RETURN( FALSE )
ELSIF IsDefImp(mod)
THEN
(* return TRUE if we have no source file. *)
RETURN( GetModuleFile(mod)=NIL )
END ;
mod := GetScope(mod)
UNTIL mod=NulSym ;
RETURN( FALSE )
END IsExternalToWholeProgram ;
(*
DeclareProcedureToGccWholeProgram -
*)
PROCEDURE DeclareProcedureToGccWholeProgram (Sym: CARDINAL) ;
VAR
returnType,
GccParam : tree ;
scope,
Variable,
p, i : CARDINAL ;
b, e : CARDINAL ;
begin, end,
location : location_t ;
BEGIN
IF (NOT GccKnowsAbout(Sym)) AND (NOT IsPseudoProcFunc(Sym))
THEN
BuildStartFunctionDeclaration(UsesVarArgs(Sym)) ;
p := NoOfParamAny (Sym) ;
i := p ;
WHILE i>0 DO
(* note we dont use GetNthParamAny as we want the parameter that is seen by the procedure block
remember that this is treated exactly the same as a variable, just its position on
the activation record is special (ie a parameter)
*)
Variable := GetNth(Sym, i) ;
location := TokenToLocation(GetDeclaredMod(Variable)) ;
IF IsUnboundedParamAny (Sym, i)
THEN
GccParam := BuildParameterDeclaration(location,
KeyToCharStar(GetSymName(Variable)),
Mod2Gcc(GetLType(Variable)),
FALSE)
ELSE
GccParam := BuildParameterDeclaration(location,
KeyToCharStar(GetSymName(Variable)),
Mod2Gcc(GetLType(Variable)),
IsVarParamAny (Sym, i))
END ;
PreAddModGcc(Variable, GccParam) ;
WatchRemoveList(Variable, todolist) ;
WatchIncludeList(Variable, fullydeclared) ;
DEC(i)
END ;
GetProcedureBeginEnd(Sym, b, e) ;
begin := TokenToLocation(b) ;
end := TokenToLocation(e) ;
scope := GetScope(Sym) ;
PushBinding(scope) ;
IF GetSType(Sym)=NulSym
THEN
returnType := NIL
ELSE
returnType := Mod2Gcc(GetSType(Sym))
END ;
PreAddModGcc(Sym, BuildEndFunctionDeclaration(begin, end,
KeyToCharStar(GetFullSymName(Sym)),
returnType,
IsExternalToWholeProgram(Sym),
IsProcedureGccNested(Sym),
IsExported(GetModuleWhereDeclared(Sym), Sym),
IsProcedureAnyNoReturn(Sym))) ;
PopBinding(scope) ;
WatchRemoveList(Sym, todolist) ;
WatchIncludeList(Sym, fullydeclared)
END
END DeclareProcedureToGccWholeProgram ;
(*
DeclareProcedureToGccSeparateProgram -
*)
PROCEDURE DeclareProcedureToGccSeparateProgram (Sym: CARDINAL) ;
VAR
returnType,
GccParam : tree ;
scope,
Variable,
p, i : CARDINAL ;
b, e : CARDINAL ;
begin, end,
location : location_t ;
tok : CARDINAL ;
BEGIN
tok := GetDeclaredMod(Sym) ;
IF (NOT GccKnowsAbout(Sym)) AND (NOT IsPseudoProcFunc(Sym)) AND
(IsEffectivelyImported(GetMainModule(), Sym) OR
(GetModuleWhereDeclared (Sym) = GetMainModule()) OR
IsNeededAtRunTime (tok, Sym) OR
IsImported (GetBaseModule (), Sym) OR
IsExported(GetModuleWhereDeclared (Sym), Sym) OR
IsExtern (Sym))
THEN
BuildStartFunctionDeclaration(UsesVarArgs(Sym)) ;
p := NoOfParamAny (Sym) ;
i := p ;
WHILE i>0 DO
(* Note we dont use GetNthParamAny as we want the parameter that is seen by
the procedure block remember that this is treated exactly the same as
a variable, just its position on the activation record is special (ie
a parameter). *)
Variable := GetNth(Sym, i) ;
location := TokenToLocation(GetDeclaredMod(Variable)) ;
IF IsUnboundedParamAny (Sym, i)
THEN
GccParam := BuildParameterDeclaration(location,
KeyToCharStar(GetSymName(Variable)),
Mod2Gcc(GetLType(Variable)),
FALSE)
ELSE
GccParam := BuildParameterDeclaration(location,
KeyToCharStar(GetSymName(Variable)),
Mod2Gcc(GetLType(Variable)),
IsVarParamAny (Sym, i))
END ;
PreAddModGcc(Variable, GccParam) ;
WatchRemoveList(Variable, todolist) ;
WatchIncludeList(Variable, fullydeclared) ;
DEC(i)
END ;
GetProcedureBeginEnd(Sym, b, e) ;
begin := TokenToLocation(b) ;
end := TokenToLocation(e) ;
scope := GetScope(Sym) ;
PushBinding(scope) ;
IF GetSType(Sym)=NulSym
THEN
returnType := NIL
ELSE
returnType := Mod2Gcc(GetSType(Sym))
END ;
PreAddModGcc (Sym, BuildEndFunctionDeclaration (begin, end,
KeyToCharStar (GetFullSymName (Sym)),
returnType,
IsExternal (Sym), (* Extern relative to the main module. *)
IsProcedureGccNested (Sym),
(* Exported from the module where it was declared. *)
IsExported (GetModuleWhereDeclared (Sym), Sym) OR IsExtern (Sym),
IsProcedureAnyNoReturn(Sym))) ;
PopBinding(scope) ;
WatchRemoveList(Sym, todolist) ;
WatchIncludeList(Sym, fullydeclared)
END
END DeclareProcedureToGccSeparateProgram ;
(*
DeclareProcedureToGcc - traverses all parameters and interfaces to gm2gcc.
*)
PROCEDURE DeclareProcedureToGcc (sym: CARDINAL) ;
BEGIN
IF sym # NulSym
THEN
IF WholeProgram
THEN
DeclareProcedureToGccWholeProgram (sym)
ELSE
DeclareProcedureToGccSeparateProgram (sym)
END
END
END DeclareProcedureToGcc ;
(*
DeclareProcedure - declares procedure, sym, or all procedures inside
module sym.
*)
PROCEDURE DeclareProcedure (sym: WORD) ;
BEGIN
IF IsProcedure(sym)
THEN
DeclareProcedureToGcc(sym)
ELSIF IsModule(sym) OR IsDefImp(sym)
THEN
ForeachProcedureDo(sym, DeclareProcedure)
ELSE
InternalError ('expecting procedure')
END
END DeclareProcedure ;
(*
FoldConstants - a wrapper for ResolveConstantExpressions.
*)
PROCEDURE FoldConstants (bb: BasicBlock) ;
BEGIN
IF ResolveConstantExpressions (DeclareConstFully, bb)
THEN
ConstantResolved := TRUE
END
END FoldConstants ;
(*
ActivateWatch - activate a watch for any symbol (lista xor listb).
*)
PROCEDURE ActivateWatch (lista, listb: Set) ;
VAR
smallest,
largest : Set ;
n, sym : CARDINAL ;
BEGIN
IF NoOfElementsInSet (lista) # NoOfElementsInSet (listb)
THEN
IF NoOfElementsInSet (lista) > NoOfElementsInSet (listb)
THEN
largest := lista ;
smallest := listb
ELSE
largest := listb ;
smallest := lista
END ;
printf0 ("adding the following symbols to the watch list as the declarator has detected an internal bug: ") ;
sym := 1 ;
n := FinalSymbol () ;
WHILE sym <= n DO
IF (IsElementInSet (largest, sym) AND (NOT IsElementInSet (smallest, sym))) OR
((NOT IsElementInSet (largest, sym)) AND IsElementInSet (smallest, sym))
THEN
AddSymToWatch (sym) ;
printf1 ("%d ", sym)
END ;
INC (sym)
END ;
printf0 ("\n")
END
END ActivateWatch ;
(*
DeclareTypesConstantsProceduresInRange -
*)
PROCEDURE DeclareTypesConstantsProceduresInRange (scope, start, end: CARDINAL) ;
CONST
DebugLoop = 1000 ;
VAR
copy: Group ;
loop: CARDINAL ;
sb : ScopeBlock ;
bb : BasicBlock ;
BEGIN
IF TraceQuadruples
THEN
DisplayQuadRange (scope, start, end)
END ;
loop := 0 ;
copy := NIL ;
sb := InitScopeBlock (scope) ;
REPEAT
(* Throw away any unreachable quad. *)
bb := InitBasicBlocks (sb) ;
KillBasicBlocks (bb) ;
(* Now iterate over remaining quads in scope attempting to resolve constants. *)
copy := DupGroup (copy) ;
bb := InitBasicBlocks (sb) ;
ConstantResolved := FALSE ;
ForeachBasicBlockDo (bb, FoldConstants) ;
KillBasicBlocks (bb) ;
(* And now types. *)
IF DeclaredOutstandingTypes (FALSE)
THEN
END ;
IF loop = DebugLoop
THEN
IF TraceQuadruples
THEN
DisplayQuadRange (scope, start, end)
END ;
ActivateWatch (copy^.ToDoList, GlobalGroup^.ToDoList) ;
loop := 0
END ;
INC (loop)
UNTIL (NOT ConstantResolved) AND EqualGroup (copy, GlobalGroup) ;
KillGroup (copy) ;
bb := InitBasicBlocks (sb) ;
KillBasicBlocks (bb) ;
KillScopeBlock (sb)
END DeclareTypesConstantsProceduresInRange ;
(*
SkipModuleScope - skips all module scopes for, scope.
It returns either NulSym or a procedure sym.
*)
PROCEDURE SkipModuleScope (scope: CARDINAL) : CARDINAL ;
BEGIN
IF (scope=NulSym) OR IsProcedure(scope)
THEN
RETURN( scope )
ELSE
RETURN( SkipModuleScope(GetScope(scope)) )
END
END SkipModuleScope ;
(*
PushBinding -
*)
PROCEDURE PushBinding (scope: CARDINAL) ;
BEGIN
scope := SkipModuleScope(scope) ;
IF scope=NulSym
THEN
pushGlobalScope
ELSE
pushFunctionScope(Mod2Gcc(scope))
END
END PushBinding ;
(*
PopBinding -
*)
PROCEDURE PopBinding (scope: CARDINAL) ;
BEGIN
scope := SkipModuleScope(scope) ;
IF scope=NulSym
THEN
popGlobalScope
ELSE
Assert(IsProcedure(scope)) ;
finishFunctionDecl(TokenToLocation(GetDeclaredMod(scope)), Mod2Gcc(scope)) ;
Assert (popFunctionScope () # NIL)
END
END PopBinding ;
(*
DeclareTypesConstantsProcedures -
*)
PROCEDURE DeclareTypesConstantsProcedures (scope: CARDINAL) ;
VAR
copy: Group ;
sb : ScopeBlock ;
BEGIN
IF Debugging
THEN
printf0 ("declaring types constants in: ") ; PrintTerse (scope)
END ;
copy := NIL ;
sb := InitScopeBlock (scope) ;
PushBinding (scope) ;
REPEAT
copy := DupGroup (copy) ;
ForeachScopeBlockDo3 (sb, DeclareTypesConstantsProceduresInRange)
UNTIL EqualGroup (copy, GlobalGroup) ;
KillGroup (copy) ;
PopBinding (scope) ;
KillScopeBlock (sb)
END DeclareTypesConstantsProcedures ;
(*
AssertAllTypesDeclared - asserts that all types for variables are declared in, scope.
*)
PROCEDURE AssertAllTypesDeclared (scope: CARDINAL) ;
VAR
n, Var: CARDINAL ;
failed: BOOLEAN ;
BEGIN
failed := FALSE ;
n := 1 ;
Var := GetNth(scope, n) ;
WHILE Var#NulSym DO
IF NOT TypeDependentsDeclared (Var, TRUE)
THEN
failed := TRUE
END ;
INC(n) ;
Var := GetNth(scope, n)
END ;
IF failed
THEN
FlushErrors
END
END AssertAllTypesDeclared ;
(*
DeclareModuleInit - declare all the ctor related functions within
a module.
*)
PROCEDURE DeclareModuleInit (moduleSym: WORD) ;
VAR
ctor, init, fini, dep: CARDINAL ;
BEGIN
GetModuleCtors (moduleSym, ctor, init, fini, dep) ;
DeclareProcedureToGcc (ctor) ;
DeclareProcedureToGcc (init) ;
DeclareProcedureToGcc (fini) ;
DeclareProcedureToGcc (dep)
END DeclareModuleInit ;
(*
StartDeclareProcedureScope -
*)
PROCEDURE StartDeclareProcedureScope (scope: CARDINAL) ;
BEGIN
WalkTypesInProcedure(scope) ;
DeclareProcedure(scope) ;
ForeachInnerModuleDo(scope, WalkTypesInModule) ;
DeclareTypesConstantsProcedures (scope) ;
ForeachInnerModuleDo(scope, DeclareTypesConstantsProcedures) ;
DeclareLocalVariables(scope) ;
ForeachInnerModuleDo(scope, DeclareModuleVariables) ;
AssertAllTypesDeclared(scope) ;
ForeachProcedureDo(scope, DeclareProcedure) ;
ForeachInnerModuleDo(scope, StartDeclareScope)
END StartDeclareProcedureScope ;
(*
StartDeclareModuleScopeSeparate -
*)
PROCEDURE StartDeclareModuleScopeSeparate (scope: CARDINAL) ;
BEGIN
IF scope=GetMainModule()
THEN
ForeachModuleDo(WalkTypesInModule) ; (* will populate the TYPE and CONST ToDo list *)
DeclareTypesConstantsProcedures(scope) ; (* will resolved TYPEs and CONSTs on the ToDo *)
(* lists. *)
ForeachModuleDo(DeclareProcedure) ;
(* Now that all types have been resolved it is safe to declare
variables. *)
AssertAllTypesDeclared(scope) ;
DeclareGlobalVariables(scope) ;
ForeachImportedDo(scope, DeclareImportedVariables) ;
(* Now it is safe to declare all procedures. *)
ForeachProcedureDo(scope, DeclareProcedure) ;
ForeachInnerModuleDo(scope, WalkTypesInModule) ;
ForeachInnerModuleDo(scope, DeclareTypesConstantsProcedures) ;
ForeachInnerModuleDo(scope, StartDeclareScope) ;
DeclareModuleInit(scope)
ELSE
DeclareTypesConstantsProcedures(scope) ;
AssertAllTypesDeclared(scope) ;
ForeachProcedureDo(scope, DeclareProcedure) ;
DeclareModuleInit(scope) ;
ForeachInnerModuleDo(scope, StartDeclareScope)
END
END StartDeclareModuleScopeSeparate ;
(*
StartDeclareModuleScopeWholeProgram -
*)
PROCEDURE StartDeclareModuleScopeWholeProgram (scope: CARDINAL) ;
BEGIN
IF IsSourceSeen(scope)
THEN
ForeachModuleDo(WalkTypesInModule) ; (* will populate the TYPE and CONST ToDo list *)
DeclareTypesConstantsProcedures(scope) ; (* will resolved TYPEs and CONSTs on the ToDo *)
(* lists. *)
ForeachModuleDo(DeclareProcedure) ;
ForeachModuleDo(DeclareModuleInit) ;
(* Now that all types have been resolved it is safe to declare
variables. *)
AssertAllTypesDeclared(scope) ;
DeclareGlobalVariablesWholeProgram(scope) ;
ForeachImportedDo(scope, DeclareImportedVariablesWholeProgram) ;
(* Now it is safe to declare all procedures. *)
ForeachProcedureDo(scope, DeclareProcedure) ;
ForeachInnerModuleDo(scope, WalkTypesInModule) ;
ForeachInnerModuleDo(scope, DeclareTypesConstantsProcedures) ;
ForeachInnerModuleDo(scope, StartDeclareScope) ;
DeclareModuleInit(scope)
ELSE
DeclareTypesConstantsProcedures(scope) ;
AssertAllTypesDeclared(scope) ;
ForeachProcedureDo(scope, DeclareProcedure) ;
DeclareModuleInit(scope) ;
ForeachInnerModuleDo(scope, StartDeclareScope)
END
END StartDeclareModuleScopeWholeProgram ;
(*
StartDeclareModuleScope -
*)
PROCEDURE StartDeclareModuleScope (scope: CARDINAL) ;
BEGIN
IF WholeProgram
THEN
StartDeclareModuleScopeWholeProgram(scope)
ELSE
StartDeclareModuleScopeSeparate(scope)
END
END StartDeclareModuleScope ;
(*
StartDeclareScope - declares types, variables associated with this scope.
*)
PROCEDURE StartDeclareScope (scope: CARDINAL) ;
VAR
n: Name ;
BEGIN
IF Debugging
THEN
n := GetSymName (scope) ;
printf1 ('declaring symbols in BLOCK %a\n', n)
END ;
IF IsProcedure (scope)
THEN
StartDeclareProcedureScope (scope)
ELSE
StartDeclareModuleScope (scope)
END ;
IF Debugging
THEN
n := GetSymName (scope) ;
printf1('\nEND declaring symbols in BLOCK %a\n', n)
END
END StartDeclareScope ;
(*
EndDeclareScope -
*)
PROCEDURE EndDeclareScope ;
BEGIN
(* no need to do anything *)
END EndDeclareScope ;
(*
IncludeDumpSymbol - include sym into the watch list and all syms dependants.
*)
PROCEDURE IncludeDumpSymbol (sym: CARDINAL) ;
BEGIN
IF sym # NulSym
THEN
AddSymToWatch (sym)
(*
fprintf0 (GetDumpFile (), "\n") ;
PrintVerbose (sym) ;
fprintf0 (GetDumpFile (), "\n")
*)
END
END IncludeDumpSymbol ;
(*
DumpResolver - dumps the m2 representation of sym.
*)
PROCEDURE DumpResolver (sym: CARDINAL) ;
BEGIN
fprintf1 (GetDumpFile (), "dump filtered symbol %d and dependants\n", sym) ;
PrintVerbose (sym) ;
END DumpResolver ;
(*
DumpFilteredResolver - dumps the gimple or tree representation of all watched symbols.
*)
PROCEDURE DumpFilteredResolver ;
BEGIN
ForeachElementInSetDo (WatchList, DumpResolver)
END DumpFilteredResolver ;
(*
DumpDefinitive - dumps the m2 and m2 gimple representation of sym.
*)
PROCEDURE DumpDefinitive (sym: CARDINAL) ;
VAR
fd: INTEGER ;
BEGIN
fprintf1 (GetDumpFile (), "\nm2 symbol synopsis: %d\n", sym) ;
PrintVerbose (sym) ;
IF GccKnowsAbout (sym)
THEN
fprintf1 (GetDumpFile (), "\nm2 gimple: %d", sym) ;
FIO.FlushBuffer (GetDumpFile ()) ;
fd := FIO.GetUnixFileDescriptor (GetDumpFile ()) ;
DumpGimpleFd (fd, Mod2Gcc (sym))
ELSE
fprintf1 (GetDumpFile (), "\nno m2 gimple for %d\n", sym)
END
END DumpDefinitive ;
(*
DumpFilteredDefinitive - dumps the gimple or tree representation of all watched symbols.
*)
PROCEDURE DumpFilteredDefinitive ;
BEGIN
ForeachElementInSetDo (WatchList, DumpDefinitive)
END DumpFilteredDefinitive ;
(*
PreAddModGcc - adds a relationship between sym and tree.
*)
PROCEDURE PreAddModGcc (sym: CARDINAL; tree: tree) ;
BEGIN
AddModGcc (sym, tree)
END PreAddModGcc ;
(*
DeclareDefaultType - declares a default type, sym, with, name.
*)
PROCEDURE DeclareDefaultType (sym: CARDINAL; name: ARRAY OF CHAR; gcctype: tree) ;
VAR
t : tree ;
high, low: CARDINAL ;
location : location_t ;
BEGIN
(* DeclareDefaultType will declare a new identifier as a type of, gcctype, if it has not already been
declared by gccgm2.c *)
location := BuiltinsLocation () ;
t := GetDefaultType(location, KeyToCharStar(MakeKey(name)), gcctype) ;
AddModGcc(sym, t) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, sym) ;
WalkAssociatedUnbounded(sym, TraverseDependants) ;
(*
this is very simplistic and assumes that the caller only uses Subranges, Sets and GCC types.
We need to declare any constants with the types so that AllDependantsFullyDeclared works.
*)
IF IsSubrange(sym)
THEN
GetSubrange(sym, high, low) ;
DeclareConstant(GetDeclaredMod(sym), high) ;
DeclareConstant(GetDeclaredMod(sym), low)
ELSIF IsSet(sym)
THEN
IF IsSubrange(GetSType(sym))
THEN
IF NOT GccKnowsAbout(GetSType(sym))
THEN
(* only true for internal types of course *)
InternalError ('subrange type within the set type must be declared before the set type')
END ;
GetSubrange(GetSType(sym), high, low) ;
DeclareConstant(GetDeclaredMod(sym), high) ;
DeclareConstant(GetDeclaredMod(sym), low)
ELSIF IsEnumeration(GetSType(sym))
THEN
IF NOT GccKnowsAbout(GetSType(sym))
THEN
(* only true for internal types of course *)
InternalError ('enumeration type within the set type must be declared before the set type')
END
END
END
END DeclareDefaultType ;
(*
DeclareBoolean - declares the Boolean type together with true and false.
*)
PROCEDURE DeclareBoolean ;
BEGIN
AddModGcc(Boolean, GetBooleanType()) ;
AddModGcc(True, GetBooleanTrue()) ;
AddModGcc(False, GetBooleanFalse()) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, Boolean) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, True) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, False) ;
WalkAssociatedUnbounded(Boolean, TraverseDependants)
END DeclareBoolean ;
(*
DeclareFixedSizedType - declares the GNU Modula-2 fixed types
(if the back end support such a type).
*)
PROCEDURE DeclareFixedSizedType (name: ARRAY OF CHAR; type: CARDINAL; t: tree) ;
VAR
location : location_t ;
typetype,
low, high: CARDINAL ;
BEGIN
IF type#NulSym
THEN
IF IsSet(type) AND (NOT GccKnowsAbout(GetSType(type)))
THEN
typetype := GetSType(type) ;
GetSubrange(typetype, high, low) ;
DeclareConstant(GetDeclaredMod(type), high) ;
DeclareConstant(GetDeclaredMod(type), low) ;
location := TokenToLocation(GetDeclaredMod(typetype)) ;
PreAddModGcc(typetype, BuildSubrangeType(location,
KeyToCharStar(GetFullSymName(typetype)),
Mod2Gcc(GetSType(typetype)),
Mod2Gcc(low), Mod2Gcc(high))) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, typetype) ;
WalkAssociatedUnbounded(typetype, TraverseDependants)
END ;
(* gcc back end supports, type *)
DeclareDefaultType(type, name, t)
END
END DeclareFixedSizedType ;
(*
DeclareDefaultSimpleTypes - declares the simple types.
*)
PROCEDURE DeclareDefaultSimpleTypes ;
BEGIN
AddModGcc(ZType, GetM2ZType()) ;
AddModGcc(RType, GetM2RType()) ;
AddModGcc(CType, GetM2CType()) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, ZType) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, RType) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, CType) ;
DeclareDefaultType(Cardinal , "CARDINAL" , GetM2CardinalType()) ;
DeclareDefaultType(Integer , "INTEGER" , GetM2IntegerType()) ;
DeclareDefaultType(Char , "CHAR" , GetM2CharType()) ;
DeclareDefaultType(Loc , "LOC" , GetISOLocType()) ;
IF Iso
THEN
DeclareDefaultType(Byte , "BYTE" , GetISOByteType()) ;
DeclareDefaultType(Word , "WORD" , GetISOWordType())
ELSE
DeclareDefaultType(Byte , "BYTE" , GetByteType()) ;
DeclareDefaultType(Word , "WORD" , GetWordType())
END ;
DeclareDefaultType(Proc , "PROC" , GetProcType()) ;
DeclareDefaultType(Address , "ADDRESS" , GetPointerType()) ;
DeclareDefaultType(LongInt , "LONGINT" , GetM2LongIntType()) ;
DeclareDefaultType(LongCard , "LONGCARD" , GetM2LongCardType()) ;
DeclareDefaultType(ShortInt , "SHORTINT" , GetM2ShortIntType()) ;
DeclareDefaultType(ShortCard , "SHORTCARD" , GetM2ShortCardType()) ;
DeclareDefaultType(ShortReal , "SHORTREAL" , GetM2ShortRealType()) ;
DeclareDefaultType(Real , "REAL" , GetM2RealType()) ;
DeclareDefaultType(LongReal , "LONGREAL" , GetM2LongRealType()) ;
DeclareDefaultType(Bitnum , "BITNUM" , GetBitnumType()) ;
DeclareDefaultType(Bitset , "BITSET" , GetBitsetType()) ;
DeclareDefaultType(Complex , "COMPLEX" , GetM2ComplexType()) ;
DeclareDefaultType(LongComplex , "LONGCOMPLEX" , GetM2LongComplexType()) ;
DeclareDefaultType(ShortComplex, "SHORTCOMPLEX", GetM2ShortComplexType()) ;
DeclareDefaultType(CSizeT , "CSIZE_T" , GetCSizeTType()) ;
DeclareDefaultType(CSSizeT , "CSSIZE_T" , GetCSSizeTType()) ;
DeclareDefaultType(COffT , "COFF_T" , GetCOffTType()) ;
DeclareBoolean ;
DeclareFixedSizedType("INTEGER8" , IntegerN(8) , GetM2Integer8()) ;
DeclareFixedSizedType("INTEGER16" , IntegerN(16) , GetM2Integer16()) ;
DeclareFixedSizedType("INTEGER32" , IntegerN(32) , GetM2Integer32()) ;
DeclareFixedSizedType("INTEGER64" , IntegerN(64) , GetM2Integer64()) ;
DeclareFixedSizedType("CARDINAL8" , CardinalN(8) , GetM2Cardinal8()) ;
DeclareFixedSizedType("CARDINAL16", CardinalN(16), GetM2Cardinal16()) ;
DeclareFixedSizedType("CARDINAL32", CardinalN(32), GetM2Cardinal32()) ;
DeclareFixedSizedType("CARDINAL64", CardinalN(64), GetM2Cardinal64()) ;
DeclareFixedSizedType("WORD16" , WordN(16) , GetM2Word16()) ;
DeclareFixedSizedType("WORD32" , WordN(32) , GetM2Word32()) ;
DeclareFixedSizedType("WORD64" , WordN(64) , GetM2Word64()) ;
DeclareFixedSizedType("BITSET8" , SetN(8) , GetM2Bitset8()) ;
DeclareFixedSizedType("BITSET16" , SetN(16) , GetM2Bitset16()) ;
DeclareFixedSizedType("BITSET32" , SetN(32) , GetM2Bitset32()) ;
DeclareFixedSizedType("REAL32" , RealN(32) , GetM2Real32()) ;
DeclareFixedSizedType("REAL64" , RealN(64) , GetM2Real64()) ;
DeclareFixedSizedType("REAL96" , RealN(96) , GetM2Real96()) ;
DeclareFixedSizedType("REAL128" , RealN(128) , GetM2Real128()) ;
DeclareFixedSizedType("COMPLEX32" , ComplexN(32) , GetM2Complex32()) ;
DeclareFixedSizedType("COMPLEX64" , ComplexN(64) , GetM2Complex64()) ;
DeclareFixedSizedType("COMPLEX96" , ComplexN(96) , GetM2Complex96()) ;
DeclareFixedSizedType("COMPLEX128", ComplexN(128), GetM2Complex128())
END DeclareDefaultSimpleTypes ;
(*
DeclarePackedBoolean -
*)
PROCEDURE DeclarePackedBoolean ;
VAR
e: CARDINAL ;
BEGIN
e := GetPackedEquivalent(Boolean) ;
AddModGcc(e, GetPackedBooleanType()) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, e)
END DeclarePackedBoolean ;
(*
DeclarePackedDefaultSimpleTypes -
*)
PROCEDURE DeclarePackedDefaultSimpleTypes ;
BEGIN
DeclarePackedBoolean
END DeclarePackedDefaultSimpleTypes ;
(*
DeclareDefaultTypes - makes default types known to GCC
*)
PROCEDURE DeclareDefaultTypes ;
BEGIN
IF NOT HaveInitDefaultTypes
THEN
HaveInitDefaultTypes := TRUE ;
pushGlobalScope ;
DeclareDefaultSimpleTypes ;
DeclarePackedDefaultSimpleTypes ;
popGlobalScope
END
END DeclareDefaultTypes ;
(*
DeclareDefaultConstants - make default constants known to GCC
*)
PROCEDURE DeclareDefaultConstants ;
BEGIN
AddModGcc(Nil, GetPointerZero(BuiltinsLocation ())) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, Nil)
END DeclareDefaultConstants ;
(*
FindContext - returns the scope where the symbol
should be created.
Symbols created in a module will
return the global context tree, but symbols created
in a module which is declared inside
a procedure will return the procedure Tree.
*)
PROCEDURE FindContext (sym: CARDINAL) : tree ;
BEGIN
sym := GetProcedureScope(sym) ;
IF sym=NulSym
THEN
RETURN( GetGlobalContext() )
ELSE
RETURN( Mod2Gcc(sym) )
END
END FindContext ;
(*
IsEffectivelyImported - returns TRUE if symbol, Sym, was
effectively imported into ModSym.
*)
PROCEDURE IsEffectivelyImported (ModSym, sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN(
IsImported(ModSym, sym) OR
(IsImported(ModSym, GetModuleWhereDeclared(sym)) AND
IsExported(GetModuleWhereDeclared(sym), sym))
)
END IsEffectivelyImported ;
(*
FindOuterModule - returns the out most module where, sym,
was declared. It returns NulSym if the
symbol or the module was declared inside
a procedure.
*)
PROCEDURE FindOuterModule (sym: CARDINAL) : CARDINAL ;
BEGIN
sym := GetScope(sym) ;
WHILE (NOT IsDefImp(sym)) DO
IF IsModule(sym)
THEN
IF GetScope(sym)=NulSym
THEN
RETURN( sym )
ELSE
sym := GetScope(sym)
END
ELSIF IsProcedure(sym)
THEN
sym := GetScope(sym)
END
END ;
RETURN( sym )
END FindOuterModule ;
(*
DoVariableDeclaration - create a corresponding gcc variable and add the association
between the front end symbol var and the gcc tree.
*)
PROCEDURE DoVariableDeclaration (var: CARDINAL; name: ADDRESS;
isImported, isExported,
isTemporary, isGlobal: BOOLEAN;
scope: tree) ;
BEGIN
IF NOT (IsComponent (var) OR IsVarHeap (var))
THEN
IF TypeDependentsDeclared (var, TRUE)
THEN
PrepareGCCVarDeclaration (var, name, isImported, isExported,
isTemporary, isGlobal, scope)
END
END
END DoVariableDeclaration ;
(*
TypeDependentsDeclared - return TRUE if all type dependents of variable
have been declared.
*)
PROCEDURE TypeDependentsDeclared (variable: CARDINAL; errorMessage: BOOLEAN) : BOOLEAN ;
VAR
type: CARDINAL ;
BEGIN
type := GetSType (variable) ;
IF AllDependantsFullyDeclared (type)
THEN
RETURN TRUE
ELSE
IF errorMessage
THEN
EmitCircularDependencyError (variable) ;
ForeachElementInSetDo (GlobalGroup^.ToDoList, EmitCircularDependencyError)
END
END ;
RETURN FALSE
END TypeDependentsDeclared ;
(*
PrepareGCCVarDeclaration -
*)
PROCEDURE PrepareGCCVarDeclaration (var: CARDINAL; name: ADDRESS;
isImported, isExported,
isTemporary, isGlobal: BOOLEAN;
scope: tree) ;
VAR
type : tree ;
varType : CARDINAL ;
location: location_t ;
BEGIN
IF GetMode (var) = LeftValue
THEN
(*
There are two issues to deal with:
(i) LeftValue is really a pointer to GetSType (var), which is built
here.
(ii) Front end might have specified the back end use a particular
data type, in which case we use the specified type.
We do not add an extra pointer if this is the case.
*)
varType := SkipType (GetVarBackEndType (var)) ;
IF varType=NulSym
THEN
(* We have not explicity told back end the type, so build it. *)
varType := GetSType (var) ;
IF IsVariableAtAddress (var)
THEN
type := BuildConstPointerType (Mod2Gcc (varType))
ELSE
type := BuildPointerType (Mod2Gcc (varType))
END
ELSE
(* We have been requested to use varType. *)
type := Mod2Gcc (varType)
END ;
Assert (AllDependantsFullyDeclared (varType))
ELSE
type := Mod2Gcc (GetDType (var))
END ;
location := TokenToLocation (GetDeclaredMod (var)) ;
PreAddModGcc (var, DeclareKnownVariable (location,
name, type,
isExported, isImported, isTemporary,
isGlobal, scope, NIL)) ;
WatchRemoveList (var, todolist) ;
WatchIncludeList (var, fullydeclared)
END PrepareGCCVarDeclaration ;
(*
IsGlobal - is the variable not in a procedure scope.
*)
PROCEDURE IsGlobal (sym: CARDINAL) : BOOLEAN ;
VAR
s: CARDINAL ;
BEGIN
s := GetScope(sym) ;
WHILE (s#NulSym) AND (NOT IsDefImp (s)) AND (NOT IsModule (s)) DO
IF IsProcedure (s)
THEN
RETURN FALSE
END ;
s := GetScope (s)
END ;
RETURN TRUE
END IsGlobal ;
(*
DeclareVariable - declares a global variable to GCC.
*)
PROCEDURE DeclareVariable (ModSym, variable: CARDINAL) ;
VAR
scope: tree ;
decl : CARDINAL ;
BEGIN
IF NOT GccKnowsAbout (variable)
THEN
scope := FindContext (ModSym) ;
decl := FindOuterModule (variable) ;
PushBinding (ModSym) ;
DoVariableDeclaration (variable,
KeyToCharStar (GetFullSymName (variable)),
(* in Modula-2 we are allowed to import from ourselves, but we do not present this to GCC *)
IsEffectivelyImported(ModSym, variable) AND (GetMainModule () # decl),
IsExported(ModSym, variable),
IsTemporary (variable),
IsGlobal (variable),
scope) ;
PopBinding (ModSym)
END
END DeclareVariable ;
(*
DeclareVariableWholeProgram - declares a global variable to GCC when using -fm2-whole-program.
*)
PROCEDURE DeclareVariableWholeProgram (mainModule, variable: CARDINAL) ;
VAR
scope: tree ;
decl : CARDINAL ;
BEGIN
IF NOT GccKnowsAbout (variable)
THEN
scope := FindContext (mainModule) ;
decl := FindOuterModule (variable) ;
PushBinding (mainModule) ;
DoVariableDeclaration (variable,
KeyToCharStar (GetFullSymName (variable)),
(NOT IsSourceSeen (decl)) AND
IsEffectivelyImported (mainModule, variable) AND (GetMainModule () # decl),
IsExported (mainModule, variable),
IsTemporary (variable),
IsGlobal (variable),
scope) ;
PopBinding (mainModule)
END
END DeclareVariableWholeProgram ;
(*
DeclareGlobalVariablesWholeProgram -
*)
PROCEDURE DeclareGlobalVariablesWholeProgram (ModSym: CARDINAL) ;
VAR
n, Variable: CARDINAL ;
BEGIN
n := 1 ;
Variable := GetNth (ModSym, n) ;
WHILE Variable # NulSym DO
DeclareVariableWholeProgram (ModSym, Variable) ;
INC (n) ;
Variable := GetNth (ModSym, n)
END ;
ForeachInnerModuleDo(ModSym, DeclareGlobalVariablesWholeProgram)
END DeclareGlobalVariablesWholeProgram ;
(*
DeclareGlobalVariables - lists the Global variables for
Module ModSym together with their offset.
*)
PROCEDURE DeclareGlobalVariables (ModSym: CARDINAL) ;
VAR
n, Variable: CARDINAL ;
BEGIN
n := 1 ;
Variable := GetNth (ModSym, n) ;
WHILE Variable # NulSym DO
DeclareVariable (ModSym, Variable) ;
INC (n) ;
Variable := GetNth (ModSym, n)
END ;
ForeachInnerModuleDo (ModSym, DeclareGlobalVariables)
END DeclareGlobalVariables ;
(*
DeclareImportedVariables - declares all imported variables to GM2.
*)
PROCEDURE DeclareImportedVariables (sym: WORD) ;
BEGIN
IF IsVar (sym)
THEN
DeclareVariable (GetMainModule (), sym)
ELSIF IsDefImp (sym)
THEN
ForeachExportedDo (sym, DeclareImportedVariables)
END
END DeclareImportedVariables ;
(*
DeclareImportedVariablesWholeProgram - declares all imported variables.
*)
PROCEDURE DeclareImportedVariablesWholeProgram (sym: WORD) ;
BEGIN
IF IsVar (sym)
THEN
IF NOT IsSourceSeen (FindOuterModule (sym))
THEN
(* import is necessary, even for -fm2-whole-program as we
cannot see the source. *)
DeclareVariableWholeProgram (GetMainModule (), sym)
END
ELSIF IsDefImp (sym)
THEN
ForeachExportedDo (sym, DeclareImportedVariablesWholeProgram)
END
END DeclareImportedVariablesWholeProgram ;
(*
DeclareLocalVariable - declare a local variable var.
*)
PROCEDURE DeclareLocalVariable (var: CARDINAL) ;
BEGIN
DoVariableDeclaration (var,
KeyToCharStar (GetFullSymName (var)),
FALSE, (* local variables cannot be imported *)
FALSE, (* or exported *)
IsTemporary (var),
FALSE, (* and are not global *)
Mod2Gcc (GetScope (var)))
END DeclareLocalVariable ;
(*
DeclareLocalVariables - declares Local variables for procedure.
*)
PROCEDURE DeclareLocalVariables (procedure: CARDINAL) ;
VAR
i, var: CARDINAL ;
BEGIN
i := NoOfParamAny (procedure) + 1 ;
var := GetNth (procedure, i) ;
WHILE var # NulSym DO
Assert (procedure = GetScope (var)) ;
DeclareLocalVariable (var) ;
INC (i) ;
var := GetNth (procedure, i)
END
END DeclareLocalVariables ;
(*
DeclareModuleVariables - declares Module variables for a module
which was declared inside a procedure.
*)
PROCEDURE DeclareModuleVariables (sym: CARDINAL) ;
VAR
scope : tree ;
i, Var: CARDINAL ;
BEGIN
i := 1 ;
scope := Mod2Gcc (GetProcedureScope (sym)) ;
Var := GetNth (sym, i) ;
WHILE Var # NulSym DO
DoVariableDeclaration (Var,
KeyToCharStar (GetFullSymName (Var)),
FALSE, (* inner module variables cannot be imported *)
FALSE, (* or exported (as far as GCC is concerned) *)
IsTemporary (Var),
FALSE, (* and are not global *)
scope) ;
INC (i) ;
Var := GetNth (sym, i)
END
END DeclareModuleVariables ;
(*
DeclareFieldValue -
*)
PROCEDURE DeclareFieldValue (sym: CARDINAL; value: tree; VAR list: tree) : tree ;
VAR
location: location_t ;
BEGIN
location := TokenToLocation(GetDeclaredMod(sym)) ;
IF (GetModuleWhereDeclared(sym)=NulSym) OR
(GetModuleWhereDeclared(sym)=GetMainModule())
THEN
RETURN( BuildEnumerator(location, KeyToCharStar(GetSymName(sym)), value, list) )
ELSE
RETURN( BuildEnumerator(location, KeyToCharStar(GetFullScopeAsmName(sym)), value, list) )
END
END DeclareFieldValue ;
(*
DeclareFieldEnumeration - declares an enumerator within the current enumeration type.
*)
PROCEDURE DeclareFieldEnumeration (sym: WORD) : tree ;
VAR
type : CARDINAL ;
field,
enumlist: tree ;
BEGIN
(* add relationship between gccSym and sym *)
type := GetSType (sym) ;
enumlist := GetEnumList (type) ;
PushValue (sym) ;
field := DeclareFieldValue (sym, PopIntegerTree (), enumlist) ;
PutEnumList (type, enumlist) ;
RETURN field
END DeclareFieldEnumeration ;
(*
DeclareEnumeration - declare an enumerated type.
*)
PROCEDURE DeclareEnumeration (sym: WORD) : tree ;
VAR
enumlist,
gccenum : tree ;
location: location_t ;
BEGIN
location := TokenToLocation (GetDeclaredMod (sym)) ;
gccenum := BuildStartEnumeration (location, KeyToCharStar (GetFullSymName (sym)), FALSE) ;
enumlist := GetEnumList (sym) ;
RETURN BuildEndEnumeration (location, gccenum, enumlist)
END DeclareEnumeration ;
(*
DeclareSubrangeNarrow - will return cardinal, integer, or type depending on whether
low..high fits in the C data type.
*)
PROCEDURE DeclareSubrangeNarrow (location: location_t;
high, low: CARDINAL; type: tree) : tree ;
VAR
m2low, m2high,
lowtree,
hightree : tree ;
BEGIN
(* No zero alignment, therefore the front end will prioritize subranges to match
unsigned int, int, or ZTYPE assuming the low..high range fits. *)
lowtree := Mod2Gcc (low) ;
hightree := Mod2Gcc (high) ;
IF CompareTrees (lowtree, GetIntegerZero (location)) >= 0
THEN
(* low..high is always positive, can we use unsigned int? *)
m2high := GetMaxFrom (location, GetM2CardinalType ()) ;
IF CompareTrees (hightree, m2high) <= 0
THEN
RETURN GetM2CardinalType ()
END
ELSE
(* Must be a signed subrange base, can we use int? *)
m2high := GetMaxFrom (location, GetM2IntegerType ()) ;
m2low := GetMinFrom (location, GetM2IntegerType ()) ;
IF (CompareTrees (lowtree, m2low) >= 0) AND (CompareTrees (hightree, m2high) <= 0)
THEN
RETURN GetM2IntegerType ()
END
END ;
(* Fall back to the ZType. *)
RETURN type
END DeclareSubrangeNarrow ;
(*
DeclareSubrange - declare a subrange type.
*)
PROCEDURE DeclareSubrange (sym: CARDINAL) : tree ;
VAR
type,
gccsym : tree ;
align,
high, low: CARDINAL ;
location: location_t ;
BEGIN
location := TokenToLocation (GetDeclaredMod (sym)) ;
GetSubrange (sym, high, low) ;
align := GetAlignment (sym) ;
type := Mod2Gcc (GetSType (sym)) ;
IF align # NulSym
THEN
IF AreConstantsEqual (GetIntegerZero (location), Mod2Gcc (align))
THEN
type := BuildSmallestTypeRange (location, Mod2Gcc (low), Mod2Gcc (high))
ELSE
MetaError1 ('a non-zero alignment in a subrange type {%1Wa} is currently not implemented and will be ignored',
sym)
END
ELSIF GetSType (sym) = ZType
THEN
(* Can we narrow the ZType subrange to CARDINAL or INTEGER? *)
type := DeclareSubrangeNarrow (location, high, low, type)
END ;
gccsym := BuildSubrangeType (location,
KeyToCharStar (GetFullSymName (sym)),
type, Mod2Gcc (low), Mod2Gcc (high)) ;
RETURN gccsym
END DeclareSubrange ;
(*
IncludeGetNth -
*)
PROCEDURE IncludeGetNth (l: List; sym: CARDINAL) ;
VAR
i: CARDINAL ;
BEGIN
fprintf0 (GetDumpFile (), ' ListOfFields [') ;
i := 1 ;
WHILE GetNth (sym, i) # NulSym DO
IF i>1
THEN
fprintf0 (GetDumpFile (), ', ')
END ;
IncludeItemIntoList (l, GetNth(sym, i)) ;
PrintTerse (GetNth (sym, i)) ;
INC (i)
END ;
fprintf0 (GetDumpFile (), ']')
END IncludeGetNth ;
(*
IncludeType -
*)
PROCEDURE IncludeType (l: List; sym: CARDINAL) ;
VAR
t: CARDINAL ;
BEGIN
t := GetSType(sym) ;
IF t#NulSym
THEN
fprintf0 (GetDumpFile(), ' type [') ;
PrintTerse(t) ;
IncludeItemIntoList(l, t) ;
fprintf0 (GetDumpFile(), ']') ;
t := GetVarBackEndType(sym) ;
IF t#NulSym
THEN
fprintf0 (GetDumpFile(), ' gcc type [') ;
PrintTerse(t) ;
IncludeItemIntoList(l, t) ;
fprintf0 (GetDumpFile(), ']')
END
END
END IncludeType ;
(*
IncludeSubscript -
*)
PROCEDURE IncludeSubscript (l: List; sym: CARDINAL) ;
VAR
t: CARDINAL ;
BEGIN
t := GetArraySubscript(sym) ;
IF t#NulSym
THEN
fprintf0 (GetDumpFile(), ' subrange [') ;
PrintTerse(t) ;
IncludeItemIntoList(l, t) ;
fprintf0 (GetDumpFile(), ']') ;
END
END IncludeSubscript ;
(*
PrintLocalSymbol -
*)
PROCEDURE PrintLocalSymbol (sym: CARDINAL) ;
BEGIN
PrintTerse(sym) ; fprintf0 (GetDumpFile(), ', ')
END PrintLocalSymbol ;
(*
PrintLocalSymbols -
*)
PROCEDURE PrintLocalSymbols (sym: CARDINAL) ;
BEGIN
fprintf0 (GetDumpFile(), 'Local Symbols {') ;
ForeachLocalSymDo(sym, PrintLocalSymbol) ;
fprintf0 (GetDumpFile(), '}')
END PrintLocalSymbols ;
(*
IncludeGetVarient -
*)
PROCEDURE IncludeGetVarient (l: List; sym: CARDINAL) ;
BEGIN
IF GetVarient(sym)#NulSym
THEN
fprintf0 (GetDumpFile(), ' Varient [') ;
PrintTerse(GetVarient(sym)) ;
fprintf0 (GetDumpFile(), ']') ;
IncludeItemIntoList(l, GetVarient(sym))
END
END IncludeGetVarient ;
(*
IncludeUnbounded - includes the record component of an unbounded type.
*)
PROCEDURE IncludeUnbounded (l: List; sym: CARDINAL) ;
BEGIN
IF GetUnboundedRecordType(sym)#NulSym
THEN
IncludeItemIntoList(l, GetUnboundedRecordType(sym))
END
END IncludeUnbounded ;
(*
IncludePartialUnbounded - includes the type component of a partial unbounded symbol.
*)
PROCEDURE IncludePartialUnbounded (l: List; sym: CARDINAL) ;
BEGIN
IF GetSType(sym)#NulSym
THEN
IncludeItemIntoList(l, GetSType(sym))
END
END IncludePartialUnbounded ;
(*
PrintDeclared - prints out where, sym, was declared.
*)
PROCEDURE PrintDeclared (sym: CARDINAL) ;
VAR
filename: String ;
lineno,
tokenno : CARDINAL ;
BEGIN
tokenno := GetDeclaredMod(sym) ;
filename := FindFileNameFromToken(tokenno, 0) ;
lineno := TokenToLineNo(tokenno, 0) ;
fprintf2 (GetDumpFile (), " declared in %s:%d", filename, lineno)
END PrintDeclared ;
(*
PrintAlignment -
*)
PROCEDURE PrintAlignment (sym: CARDINAL) ;
VAR
align: CARDINAL ;
BEGIN
IF IsRecord(sym) OR IsType(sym) OR IsRecordField(sym) OR IsPointer(sym) OR IsArray(sym)
THEN
align := GetAlignment(sym) ;
IF align#NulSym
THEN
fprintf1 (GetDumpFile(), " aligned [%d]", align)
END
END
END PrintAlignment ;
(*
IncludeGetParent -
*)
PROCEDURE IncludeGetParent (l: List; sym: CARDINAL) ;
BEGIN
fprintf0 (GetDumpFile(), ' Parent [') ;
IncludeItemIntoList(l, GetParent(sym)) ;
PrintTerse(GetParent(sym)) ;
fprintf0 (GetDumpFile(), ']')
END IncludeGetParent ;
(*
PrintDecl -
*)
PROCEDURE PrintDecl (sym: CARDINAL) ;
BEGIN
IF IsDeclaredPackedResolved(sym)
THEN
IF IsDeclaredPacked(sym)
THEN
fprintf0 (GetDumpFile(), ' packed')
ELSE
fprintf0 (GetDumpFile(), ' unpacked')
END
ELSE
fprintf0 (GetDumpFile(), ' unknown if packed')
END
END PrintDecl ;
(*
PrintScope - displays the scope and line number of declaration of symbol, sym.
*)
PROCEDURE PrintScope (sym: CARDINAL) ;
VAR
name : Name ;
scope,
line : CARDINAL ;
BEGIN
line := TokenToLineNo (GetDeclaredMod (sym), 0) ;
scope := GetScope (sym) ;
name := GetSymName (scope) ;
fprintf3 (GetDumpFile (), ' scope %a:%d %d', name, line, scope)
END PrintScope ;
(*
PrintKind -
*)
PROCEDURE PrintKind (kind: ProcedureKind) ;
VAR
s: String ;
BEGIN
s := GetProcedureKindDesc (kind) ;
fprintf1 (GetDumpFile (), "%s", s) ;
s := KillString (s)
END PrintKind ;
(*
PrintProcedureParameters -
*)
PROCEDURE PrintProcedureParameters (sym: CARDINAL; kind: ProcedureKind) ;
VAR
typeName,
paramName: Name ;
p, i, n,
type : CARDINAL ;
BEGIN
fprintf0 (GetDumpFile (), ' (') ;
n := NoOfParam (sym, kind) ;
i := 1 ;
WHILE i <= n DO
IF i > 1
THEN
fprintf0 (GetDumpFile (), '; ')
END ;
IF IsVarParam (sym, kind, i)
THEN
fprintf0 (GetDumpFile (), 'VAR ')
END ;
p := GetNthParam (sym, kind, i) ;
paramName := GetSymName (p) ;
type := GetType (p) ;
typeName := GetSymName (type) ;
IF IsUnboundedParam (sym, kind, i)
THEN
fprintf2 (GetDumpFile (), '%a: ARRAY OF %a', paramName, typeName)
ELSE
fprintf2 (GetDumpFile (), '%a: %a', paramName, typeName)
END ;
INC (i)
END ;
fprintf0 (GetDumpFile (), ')')
END PrintProcedureParameters ;
(*
PrintProcedureReturnType -
*)
PROCEDURE PrintProcedureReturnType (sym: CARDINAL) ;
VAR
typeName: Name ;
BEGIN
IF GetType (sym) # NulSym
THEN
typeName := GetSymName (GetType (sym)) ;
fprintf1 (GetDumpFile (), ' : %a', typeName)
END ;
fprintf0 (GetDumpFile (), ' ;')
END PrintProcedureReturnType ;
(*
PrintProcedure -
*)
PROCEDURE PrintProcedure (sym: CARDINAL) ;
VAR
n : Name ;
kind: ProcedureKind ;
BEGIN
n := GetSymName (sym) ;
fprintf2 (GetDumpFile (), 'sym %d IsProcedure (%a)', sym, n);
IF IsProcedureReachable(sym)
THEN
fprintf0 (GetDumpFile(), ' IsProcedureReachable')
END ;
PrintScope (sym) ;
IF IsExtern (sym)
THEN
fprintf0 (GetDumpFile (), ' extern')
END ;
IF IsPublic (sym)
THEN
fprintf0 (GetDumpFile (), ' public')
END ;
IF IsCtor (sym)
THEN
fprintf0 (GetDumpFile (), ' ctor')
END ;
PrintDeclared (sym) ;
fprintf0 (GetDumpFile (), '\n') ;
FOR kind := MIN (ProcedureKind) TO MAX (ProcedureKind) DO
fprintf0 (GetDumpFile (), 'parameters ') ;
PrintKind (kind) ;
IF GetProcedureParametersDefined (sym, kind)
THEN
fprintf0 (GetDumpFile (), ' defined') ;
PrintProcedureParameters (sym, kind) ;
PrintProcedureReturnType (sym)
ELSE
fprintf0 (GetDumpFile (), ' undefined')
END ;
fprintf0 (GetDumpFile (), '\n')
END ;
fprintf0 (GetDumpFile (), ' Associated proctype: ') ;
PrintProcType (GetProcedureProcType (sym))
END PrintProcedure ;
(*
PrintProcTypeParameters -
*)
PROCEDURE PrintProcTypeParameters (sym: CARDINAL) ;
VAR
typeName : Name ;
p, i, n,
type : CARDINAL ;
BEGIN
fprintf0 (GetDumpFile (), ' (') ;
n := NoOfParam (sym, ProperProcedure) ;
i := 1 ;
WHILE i <= n DO
IF i > 1
THEN
fprintf0 (GetDumpFile (), '; ')
END ;
IF IsVarParam (sym, ProperProcedure, i)
THEN
fprintf0 (GetDumpFile (), 'VAR ')
END ;
p := GetNthParam (sym, ProperProcedure, i) ;
type := GetType (p) ;
typeName := GetSymName (type) ;
IF IsUnboundedParam (sym, ProperProcedure, i)
THEN
fprintf1 (GetDumpFile (), 'ARRAY OF %a', typeName)
ELSE
fprintf1 (GetDumpFile (), '%a', typeName)
END ;
INC (i)
END ;
fprintf0 (GetDumpFile (), ')')
END PrintProcTypeParameters ;
(*
PrintProcType -
*)
PROCEDURE PrintProcType (sym: CARDINAL) ;
VAR
n: Name ;
BEGIN
n := GetSymName (sym) ;
fprintf2 (GetDumpFile (), 'sym %d IsProcType (%a)', sym, n);
PrintScope (sym) ;
PrintDeclared (sym) ;
fprintf0 (GetDumpFile (), '\n') ;
fprintf0 (GetDumpFile (), 'parameters ') ;
PrintProcTypeParameters (sym) ;
PrintProcedureReturnType (sym) ;
fprintf0 (GetDumpFile (), '\n')
END PrintProcType ;
(*
PrintString -
*)
PROCEDURE PrintString (sym: CARDINAL) ;
VAR
len : CARDINAL ;
tokenno: CARDINAL ;
BEGIN
IF IsConstStringKnown (sym)
THEN
IF IsConstStringM2 (sym)
THEN
fprintf0 (GetDumpFile (), 'a Modula-2 string')
ELSIF IsConstStringC (sym)
THEN
fprintf0 (GetDumpFile (), ' a C string')
ELSIF IsConstStringM2nul (sym)
THEN
fprintf0 (GetDumpFile (), ' a nul terminated Modula-2 string')
ELSIF IsConstStringCnul (sym)
THEN
fprintf0 (GetDumpFile (), ' a nul terminated C string')
END ;
tokenno := GetDeclaredMod (sym) ;
len := GetStringLength (tokenno, sym) ;
fprintf1 (GetDumpFile (), ' length %d', len)
ELSE
fprintf0 (GetDumpFile (), 'is not currently known')
END
END PrintString ;
(*
PrintVerboseFromList - prints the, i, th element in the list, l.
*)
PROCEDURE PrintVerboseFromList (l: List; i: CARDINAL) ;
VAR
type,
low,
high,
sym : CARDINAL ;
n, n2 : Name ;
BEGIN
sym := GetItemFromList(l, i) ;
n := GetSymName(sym) ;
IF IsError(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsError (%a)', sym, n)
ELSIF IsDefImp(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsDefImp (%a)', sym, n) ;
IF IsDefinitionForC(sym)
THEN
fprintf0 (GetDumpFile(), 'and IsDefinitionForC')
END ;
IF IsHiddenTypeDeclared(sym)
THEN
fprintf0 (GetDumpFile(), ' IsHiddenTypeDeclared')
END ;
ForeachProcedureDo (sym, PrintProcedure)
ELSIF IsModule(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsModule (%a)', sym, n) ;
IF IsModuleWithinProcedure(sym)
THEN
fprintf0 (GetDumpFile(), ' and IsModuleWithinProcedure')
END
ELSIF IsInnerModule(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsInnerModule (%a)', sym, n)
ELSIF IsUnknown(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsUnknown (%a)', sym, n)
ELSIF IsType(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsType (%a)', sym, n) ;
IncludeType(l, sym) ;
PrintAlignment(sym)
ELSIF IsProcedure(sym)
THEN
PrintProcedure (sym)
ELSIF IsParameter(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsParameter (%a)', sym, n) ;
IF GetParameterShadowVar(sym)=NulSym
THEN
fprintf0 (GetDumpFile(), ' no shadow local variable')
ELSE
fprintf0 (GetDumpFile(), ' shadow ') ;
IncludeType(l, GetParameterShadowVar(sym))
(* PrintVerboseFromList(l, GetParameterShadowVar(sym)) *)
END ;
IncludeType(l, sym)
ELSIF IsPointer(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsPointer (%a)', sym, n) ;
IncludeType(l, sym) ;
PrintAlignment(sym)
ELSIF IsRecord(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsRecord (%a)', sym, n) ;
PrintLocalSymbols(sym) ;
IncludeGetNth(l, sym) ;
PrintAlignment(sym) ;
PrintDecl(sym)
ELSIF IsVarient(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsVarient (%a)', sym, n) ;
PrintDecl(sym) ;
IncludeGetNth(l, sym) ;
IncludeGetVarient(l, sym) ;
IncludeGetParent(l, sym)
ELSIF IsFieldVarient(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsFieldVarient (%a)', sym, n) ;
PrintDecl(sym) ;
IncludeGetNth(l, sym) ;
IncludeGetVarient(l, sym) ;
IncludeGetParent(l, sym)
ELSIF IsFieldEnumeration(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsFieldEnumeration (%a)', sym, n)
ELSIF IsArray(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsArray (%a)', sym, n) ;
IncludeSubscript(l, sym) ;
IncludeType(l, sym) ;
PrintAlignment(sym)
ELSIF IsEnumeration(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsEnumeration (%a)', sym, n)
ELSIF IsSet(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsSet (%a)', sym, n) ;
IncludeType(l, sym)
ELSIF IsUnbounded(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsUnbounded (%a)', sym, n) ;
IncludeUnbounded(l, sym)
ELSIF IsPartialUnbounded(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsPartialUnbounded (%a)', sym, n) ;
IncludePartialUnbounded(l, sym)
ELSIF IsRecordField(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsRecordField (%a)', sym, n) ;
IF IsRecordFieldAVarientTag(sym)
THEN
fprintf0 (GetDumpFile(), ' variant tag')
END ;
IncludeType(l, sym) ;
IncludeGetVarient(l, sym) ;
IncludeGetParent(l, sym) ;
PrintAlignment(sym) ;
PrintDecl(sym)
ELSIF IsProcType(sym)
THEN
PrintProcType (sym)
ELSIF IsVar(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsVar (%a) declared in ', sym, n) ;
PrintScope (sym) ;
fprintf0 (GetDumpFile (), 'mode ') ;
CASE GetMode(sym) OF
LeftValue : fprintf0 (GetDumpFile(), 'l ') |
RightValue : fprintf0 (GetDumpFile(), 'r ') |
ImmediateValue: fprintf0 (GetDumpFile(), 'i ') |
NoValue : fprintf0 (GetDumpFile(), 'n ')
END ;
IF IsTemporary(sym)
THEN
fprintf0 (GetDumpFile(), 'temporary ')
END ;
IF IsComponent(sym)
THEN
fprintf0 (GetDumpFile(), 'component ')
END ;
IF IsVarHeap (sym)
THEN
fprintf0 (GetDumpFile(), 'heap ')
END ;
fprintf0 (GetDumpFile (), '\n') ;
PrintInitialized (sym) ;
IncludeType(l, sym)
ELSIF IsConst(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsConst (%a)', sym, n) ;
IF IsConstString(sym)
THEN
fprintf1 (GetDumpFile(), ' also IsConstString (%a)', n) ;
PrintString (sym)
ELSIF IsConstructor(sym)
THEN
fprintf0 (GetDumpFile(), ' constant constructor ') ;
IncludeType(l, sym)
ELSIF IsConstSet(sym)
THEN
fprintf0 (GetDumpFile(), ' constant constructor set ') ;
IncludeType(l, sym)
ELSE
IncludeType(l, sym)
END
ELSIF IsConstructor(sym)
THEN
fprintf2 (GetDumpFile(), 'sym %d IsConstructor (non constant) (%a)', sym, n) ;
IncludeType(l, sym)
ELSIF IsConstLit(sym)
THEN
fprintf2 (GetDumpFile(), 'sym %d IsConstLit (%a)', sym, n)
ELSIF IsDummy(sym)
THEN
fprintf2 (GetDumpFile(), 'sym %d IsDummy (%a)', sym, n)
ELSIF IsTemporary(sym)
THEN
fprintf2 (GetDumpFile(), 'sym %d IsTemporary (%a)', sym, n)
ELSIF IsVarAParam(sym)
THEN
fprintf2 (GetDumpFile(), 'sym %d IsVarAParam (%a)', sym, n)
ELSIF IsSubscript(sym)
THEN
fprintf2 (GetDumpFile(), 'sym %d IsSubscript (%a)', sym, n)
ELSIF IsSubrange(sym)
THEN
GetSubrange(sym, high, low) ;
fprintf2 (GetDumpFile(), 'sym %d IsSubrange (%a)', sym, n) ;
IF (low#NulSym) AND (high#NulSym)
THEN
type := GetSType(sym) ;
IF type#NulSym
THEN
IncludeType(l, sym) ;
n := GetSymName(type) ;
fprintf1 (GetDumpFile(), ' %a', n)
END ;
n := GetSymName(low) ;
n2 := GetSymName(high) ;
fprintf2 (GetDumpFile (), '[%a..%a]', n, n2)
END
ELSIF IsProcedureVariable(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsProcedureVariable (%a)', sym, n)
ELSIF IsProcedureNested(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsProcedureNested (%a)', sym, n)
ELSIF IsAModula2Type(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsAModula2Type (%a)', sym, n)
ELSIF IsObject(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsObject (%a)', sym, n)
ELSIF IsTuple(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsTuple (%a)', sym, n) ;
low := GetNth(sym, 1) ;
high := GetNth(sym, 2) ;
fprintf2 (GetDumpFile (), '%d, %d\n', low, high)
ELSIF IsGnuAsm(sym)
THEN
IF IsGnuAsmVolatile(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsGnuAsmVolatile (%a)', sym, n)
ELSE
fprintf2 (GetDumpFile (), 'sym %d IsGnuAsm (%a)', sym, n)
END
ELSIF IsComponent(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsComponent (%a) ', sym, n) ;
i := 1 ;
REPEAT
type := GetNth(sym, i) ;
IF type#NulSym
THEN
IncludeItemIntoList(l, type) ;
n := GetSymName(type) ;
fprintf2 (GetDumpFile (), "[%a %d] ", n, type) ;
INC(i)
END ;
UNTIL type=NulSym
END ;
IF IsHiddenType(sym)
THEN
fprintf0 (GetDumpFile(), ' IsHiddenType')
END ;
fprintf0 (GetDumpFile(), '\n')
END PrintVerboseFromList ;
(*
PrintVerbose - prints limited information about a symbol.
*)
PROCEDURE PrintVerbose (sym: CARDINAL) ;
VAR
l: List ;
i: CARDINAL ;
BEGIN
InitList (l) ;
IncludeItemIntoList (l, sym) ;
i := 1 ;
WHILE i<=NoOfItemsInList (l) DO
PrintVerboseFromList (l, i) ;
INC (i)
END ;
KillList (l)
END PrintVerbose ;
(*
PrintSym - prints limited information about a symbol.
This procedure is externally visible.
*)
PROCEDURE PrintSym (sym: CARDINAL) ;
BEGIN
printf1 ('information about symbol: %d\n', sym) ;
fprintf0 (GetDumpFile (), '==============================\n') ;
PrintVerbose (sym)
END PrintSym ;
(* ********************************
(*
PrintSymbol - prints limited information about a symbol.
*)
PROCEDURE PrintSymbol (sym: CARDINAL) ;
BEGIN
PrintTerse(sym) ;
fprintf0 (GetDumpFile(), '\n')
END PrintSymbol ;
******************************************* *)
(*
PrintTerse -
*)
PROCEDURE PrintTerse (sym: CARDINAL) ;
VAR
n: Name ;
BEGIN
n := GetSymName(sym) ;
IF IsError(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsError (%a)', sym, n)
ELSIF IsDefImp(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsDefImp (%a)', sym, n) ;
IF IsDefinitionForC(sym)
THEN
fprintf0 (GetDumpFile(), 'and IsDefinitionForC')
END ;
IF IsHiddenTypeDeclared(sym)
THEN
fprintf0 (GetDumpFile(), ' IsHiddenTypeDeclared')
END
ELSIF IsModule(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsModule (%a)', sym, n) ;
IF IsModuleWithinProcedure(sym)
THEN
fprintf0 (GetDumpFile(), ' and IsModuleWithinProcedure')
END
ELSIF IsInnerModule(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsInnerModule (%a)', sym, n)
ELSIF IsUnknown(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsUnknown (%a)', sym, n)
ELSIF IsType(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsType (%a)', sym, n)
ELSIF IsProcedure(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsProcedure (%a)', sym, n);
IF IsProcedureReachable(sym)
THEN
fprintf0 (GetDumpFile(), ' and IsProcedureReachable')
END
ELSIF IsParameter(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsParameter (%a)', sym, n)
ELSIF IsPointer(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsPointer (%a)', sym, n)
ELSIF IsRecord(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsRecord (%a)', sym, n)
ELSIF IsVarient(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsVarient (%a)', sym, n)
ELSIF IsFieldVarient(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsFieldVarient (%a)', sym, n)
ELSIF IsFieldEnumeration(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsFieldEnumeration (%a)', sym, n)
ELSIF IsArray(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsArray (%a)', sym, n)
ELSIF IsEnumeration(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsEnumeration (%a)', sym, n)
ELSIF IsSet(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsSet (%a)', sym, n)
ELSIF IsUnbounded(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsUnbounded (%a)', sym, n)
ELSIF IsRecordField(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsRecordField (%a)', sym, n)
ELSIF IsProcType(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsProcType (%a)', sym, n)
ELSIF IsVar(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsVar (%a)', sym, n)
ELSIF IsConstString(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsConstString (%a)', sym, n)
ELSIF IsConst(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsConst (%a)', sym, n)
ELSIF IsConstLit(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsConstLit (%a)', sym, n)
ELSIF IsDummy(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsDummy (%a)', sym, n)
ELSIF IsTemporary(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsTemporary (%a)', sym, n)
ELSIF IsVarAParam(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsVarAParam (%a)', sym, n)
ELSIF IsSubscript(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsSubscript (%a)', sym, n)
ELSIF IsSubrange(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsSubrange (%a)', sym, n)
ELSIF IsProcedureVariable(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsProcedureVariable (%a)', sym, n)
ELSIF IsProcedureNested(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsProcedureNested (%a)', sym, n)
ELSIF IsAModula2Type(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsAModula2Type (%a)', sym, n)
ELSIF IsGnuAsm(sym)
THEN
fprintf2 (GetDumpFile (), 'sym %d IsGnuAsm (%a)', sym, n)
ELSIF IsImport (sym)
THEN
fprintf1 (GetDumpFile(), 'sym %d IsImport', sym)
ELSIF IsImportStatement (sym)
THEN
fprintf1 (GetDumpFile(), 'sym %d IsImportStatement', sym)
END ;
IF IsHiddenType(sym)
THEN
fprintf0 (GetDumpFile(), ' IsHiddenType')
END
END PrintTerse ;
(*
CheckAlignment -
*)
PROCEDURE CheckAlignment (type: tree; sym: CARDINAL) : tree ;
VAR
align: CARDINAL ;
BEGIN
align := GetAlignment(sym) ;
IF align#NulSym
THEN
PushInt(0) ;
PushValue(align) ;
IF NOT Equ(GetDeclaredMod(sym))
THEN
RETURN( SetAlignment(type, Mod2Gcc(GetAlignment(sym))) )
END
END ;
RETURN( type )
END CheckAlignment ;
(*
CheckPragma -
*)
PROCEDURE CheckPragma (type: tree; sym: CARDINAL) : tree ;
BEGIN
IF IsDeclaredPacked (sym)
THEN
IF IsRecordField (sym) OR IsFieldVarient (sym)
THEN
type := SetDeclPacked (type)
ELSIF IsRecord (sym) OR IsVarient (sym)
THEN
type := SetTypePacked (type)
END
END ;
RETURN CheckAlignment (type, sym)
END CheckPragma ;
(*
IsZero - returns TRUE if symbol, sym, is zero.
*)
PROCEDURE IsZero (sym: CARDINAL) : BOOLEAN ;
BEGIN
PushIntegerTree(Mod2Gcc(sym)) ;
PushInt(0) ;
RETURN( Equ(GetDeclaredMod(sym)) )
END IsZero ;
(*
SetFieldPacked - sets Varient, VarientField and RecordField symbols
as packed.
*)
PROCEDURE SetFieldPacked (field: CARDINAL) ;
BEGIN
IF IsVarient(field) OR IsFieldVarient(field) OR IsRecordField(field)
THEN
PutDeclaredPacked(field, TRUE)
END
END SetFieldPacked ;
(*
RecordPacked - indicates that record, sym, and its fields
are all packed.
*)
PROCEDURE RecordPacked (sym: CARDINAL) ;
BEGIN
PutDeclaredPacked(sym, TRUE) ;
WalkRecordDependants(sym, SetFieldPacked)
END RecordPacked ;
(*
SetFieldNotPacked - sets Varient, VarientField and RecordField symbols
as not packed.
*)
PROCEDURE SetFieldNotPacked (field: CARDINAL) ;
BEGIN
IF IsVarient(field) OR IsFieldVarient(field) OR IsRecordField(field)
THEN
PutDeclaredPacked(field, FALSE)
END
END SetFieldNotPacked ;
(*
RecordNotPacked - indicates that record, sym, and its fields
are all not packed.
*)
PROCEDURE RecordNotPacked (sym: CARDINAL) ;
BEGIN
PutDeclaredPacked(sym, FALSE) ;
WalkRecordDependants(sym, SetFieldNotPacked)
END RecordNotPacked ;
(*
DetermineIfRecordPacked -
*)
PROCEDURE DetermineIfRecordPacked (sym: CARDINAL) ;
VAR
defaultAlignment: CARDINAL ;
BEGIN
defaultAlignment := GetDefaultRecordFieldAlignment(sym) ;
IF (defaultAlignment#NulSym) AND IsZero(defaultAlignment)
THEN
RecordPacked(sym)
ELSE
RecordNotPacked(sym)
END
END DetermineIfRecordPacked ;
(*
DeclarePackedSubrange -
*)
PROCEDURE DeclarePackedSubrange (equiv, sym: CARDINAL) ;
VAR
type,
gccsym : tree ;
high, low: CARDINAL ;
location : location_t ;
BEGIN
location := TokenToLocation(GetDeclaredMod(sym)) ;
GetSubrange(sym, high, low) ;
type := BuildSmallestTypeRange(location, Mod2Gcc(low), Mod2Gcc(high)) ;
gccsym := BuildSubrangeType(location, KeyToCharStar(GetFullSymName(sym)),
type, Mod2Gcc(low), Mod2Gcc(high)) ;
AddModGcc(equiv, gccsym)
END DeclarePackedSubrange ;
(*
DeclarePackedSet -
*)
PROCEDURE DeclarePackedSet (equiv, sym: CARDINAL) ;
VAR
highLimit,
range,
gccsym : tree ;
type,
high, low: CARDINAL ;
location: location_t ;
BEGIN
location := TokenToLocation(GetDeclaredMod(sym)) ;
Assert(IsSet(sym)) ;
type := GetDType(sym) ;
low := GetTypeMin(type) ;
high := GetTypeMax(type) ;
highLimit := BuildSub(location, Mod2Gcc(high), Mod2Gcc(low), FALSE) ;
(* --fixme-- we need to check that low <= WORDLENGTH. *)
highLimit := BuildLSL(location, GetIntegerOne(location), highLimit, FALSE) ;
range := BuildSmallestTypeRange(location, GetIntegerZero(location), highLimit) ;
gccsym := BuildSubrangeType(location, KeyToCharStar(GetFullSymName(sym)),
range, GetIntegerZero(location), highLimit) ;
AddModGcc(equiv, gccsym)
END DeclarePackedSet ;
(*
DeclareFieldEnumeration - declares an enumerator within the current enumeration type.
*)
PROCEDURE DeclarePackedFieldEnumeration (sym: WORD) ;
VAR
equiv,
type : CARDINAL ;
field,
enumlist: tree ;
BEGIN
(* add relationship between gccSym and sym *)
type := GetSType (sym) ;
equiv := GetPackedEquivalent (type) ;
enumlist := GetEnumList (equiv) ;
PushValue (sym) ;
field := DeclareFieldValue (sym, PopIntegerTree(), enumlist) ;
Assert (field # NIL) ;
PutEnumList (equiv, enumlist)
END DeclarePackedFieldEnumeration ;
(*
DeclarePackedEnumeration -
*)
PROCEDURE DeclarePackedEnumeration (equiv, sym: CARDINAL) ;
VAR
enumlist,
gccenum : tree ;
location: location_t ;
BEGIN
location := TokenToLocation(GetDeclaredMod(sym)) ;
gccenum := BuildStartEnumeration(location, KeyToCharStar(GetFullSymName(sym)), TRUE) ;
ForeachLocalSymDo(sym, DeclarePackedFieldEnumeration) ;
enumlist := GetEnumList(equiv) ;
gccenum := BuildEndEnumeration(location, gccenum, enumlist) ;
AddModGcc(equiv, gccenum)
END DeclarePackedEnumeration ;
(*
DeclarePackedType -
*)
PROCEDURE DeclarePackedType (equiv, sym: CARDINAL) ;
VAR
type: CARDINAL ;
BEGIN
type := GetSType(sym) ;
IF type=NulSym
THEN
IF sym=Boolean
THEN
AddModGcc(equiv, GetPackedBooleanType())
ELSE
AddModGcc(equiv, Mod2Gcc(sym))
END
ELSE
DeclarePackedType(GetPackedEquivalent(type), type) ;
AddModGcc(equiv, Mod2Gcc(GetPackedEquivalent(type)))
END
END DeclarePackedType ;
(*
doDeclareEquivalent -
*)
PROCEDURE doDeclareEquivalent (sym: CARDINAL; p: doDeclareProcedure) : tree ;
VAR
equiv: CARDINAL ;
BEGIN
equiv := GetPackedEquivalent(sym) ;
IF NOT GccKnowsAbout(equiv)
THEN
p(equiv, sym) ;
IncludeElementIntoSet(GlobalGroup^.FullyDeclared, equiv)
END ;
RETURN( Mod2Gcc(equiv) )
END doDeclareEquivalent ;
(*
PossiblyPacked -
*)
PROCEDURE PossiblyPacked (sym: CARDINAL; isPacked: BOOLEAN) : tree ;
BEGIN
IF isPacked
THEN
IF IsSubrange(sym)
THEN
RETURN( doDeclareEquivalent(sym, DeclarePackedSubrange) )
ELSIF IsType(sym)
THEN
RETURN( doDeclareEquivalent(sym, DeclarePackedType) )
ELSIF IsEnumeration(sym)
THEN
RETURN( doDeclareEquivalent(sym, DeclarePackedEnumeration) )
ELSIF IsSet(sym)
THEN
RETURN( doDeclareEquivalent(sym, DeclarePackedSet) )
END
END ;
RETURN( Mod2Gcc(sym) )
END PossiblyPacked ;
(*
GetPackedType - returns a possibly packed type for field.
*)
PROCEDURE GetPackedType (sym: CARDINAL) : tree ;
BEGIN
IF IsSubrange(sym)
THEN
RETURN( doDeclareEquivalent(sym, DeclarePackedSubrange) )
ELSIF IsType(sym)
THEN
RETURN( doDeclareEquivalent(sym, DeclarePackedType) )
ELSIF IsEnumeration(sym)
THEN
RETURN( doDeclareEquivalent(sym, DeclarePackedEnumeration) )
END ;
RETURN( Mod2Gcc(sym) )
END GetPackedType ;
(*
MaybeAlignField - checks to see whether, field, is packed or aligned and it updates
the offsets if appropriate.
*)
PROCEDURE MaybeAlignField (field: CARDINAL; VAR byteOffset, bitOffset: tree) : tree ;
VAR
f, ftype,
nbits : tree ;
location: location_t ;
BEGIN
f := Mod2Gcc(field) ;
IF IsDeclaredPacked(field)
THEN
location := TokenToLocation(GetDeclaredMod(field)) ;
f := SetDeclPacked(f) ;
ftype := GetPackedType(GetSType(field)) ;
nbits := BuildTBitSize(location, ftype) ;
f := SetRecordFieldOffset(f, byteOffset, bitOffset, ftype, nbits) ;
bitOffset := BuildAdd(location, bitOffset, nbits, FALSE) ;
RETURN( f )
ELSE
RETURN( CheckAlignment(f, field) )
END
END MaybeAlignField ;
(*
DeclareRecord - declares a record and its fields to gcc.
The final gcc record type is returned.
*)
PROCEDURE DeclareRecord (Sym: CARDINAL) : tree ;
VAR
Field : CARDINAL ;
i : CARDINAL ;
nbits,
ftype,
field,
byteOffset,
bitOffset,
FieldList,
RecordType: tree ;
location : location_t ;
BEGIN
i := 1 ;
FieldList := tree(NIL) ;
RecordType := DoStartDeclaration(Sym, BuildStartRecord) ;
location := TokenToLocation(GetDeclaredMod(Sym)) ;
byteOffset := GetIntegerZero(location) ;
bitOffset := GetIntegerZero(location) ;
REPEAT
Field := GetNth(Sym, i) ;
IF Field#NulSym
THEN
IF IsRecordField(Field) AND IsRecordFieldAVarientTag(Field) AND (GetSymName(Field)=NulName)
THEN
(* do not include a nameless tag into the C struct *)
ELSIF IsVarient(Field)
THEN
Field := Chained(Field) ;
field := Mod2Gcc(Field) ;
IF IsDeclaredPacked(Field)
THEN
location := TokenToLocation(GetDeclaredMod(Field)) ;
field := SetDeclPacked(field) ;
ftype := GetPackedType(GetSType(Field)) ;
nbits := BuildTBitSize(location, ftype) ;
field := SetRecordFieldOffset(field, byteOffset, bitOffset, ftype, nbits) ;
bitOffset := BuildAdd(location, bitOffset, nbits, FALSE) ;
byteOffset := BuildAdd(location, byteOffset,
BuildDivTrunc(location, bitOffset, BuildIntegerConstant(8), FALSE),
FALSE) ;
bitOffset := BuildModTrunc(location, bitOffset, BuildIntegerConstant(8), FALSE)
END ;
FieldList := ChainOn(FieldList, field)
ELSE
IF Debugging
THEN
printf0('chaining ') ; PrintTerse(Field) ; printf0('\n')
END ;
FieldList := ChainOn(FieldList, MaybeAlignField(Chained(Field), byteOffset, bitOffset))
END
END ;
INC(i)
UNTIL Field=NulSym ;
WatchRemoveList(Sym, partiallydeclared) ;
WatchRemoveList(Sym, heldbyalignment) ;
WatchRemoveList(Sym, finishedalignment) ;
location := TokenToLocation(GetDeclaredMod(Sym)) ;
RETURN( BuildEndRecord(location, RecordType, FieldList, IsDeclaredPacked(Sym)) )
END DeclareRecord ;
(*
DeclareRecordField -
*)
PROCEDURE DeclareRecordField (sym: CARDINAL) : tree ;
VAR
field,
GccFieldType: tree ;
location : location_t ;
BEGIN
location := TokenToLocation(GetDeclaredMod(sym)) ;
GccFieldType := PossiblyPacked(GetSType(sym), IsDeclaredPacked(sym)) ;
field := BuildFieldRecord(location, KeyToCharStar(GetFullSymName(sym)), GccFieldType) ;
RETURN( field )
END DeclareRecordField ;
(*
DeclareVarient - declares a record and its fields to gcc.
The final gcc record type is returned.
*)
PROCEDURE DeclareVarient (sym: CARDINAL) : tree ;
VAR
Field : CARDINAL ;
i : CARDINAL ;
byteOffset,
bitOffset,
FieldList,
VarientType : tree ;
location : location_t ;
BEGIN
i := 1 ;
FieldList := tree(NIL) ;
VarientType := DoStartDeclaration(sym, BuildStartVarient) ;
location := TokenToLocation(GetDeclaredMod(sym)) ;
byteOffset := GetIntegerZero(location) ;
bitOffset := GetIntegerZero(location) ;
WHILE GetNth(sym, i)#NulSym DO
Field := GetNth(sym, i) ;
IF IsRecordField(Field) AND IsRecordFieldAVarientTag(Field) AND (GetSymName(Field)=NulName)
THEN
(* do not include a nameless tag into the C struct *)
ELSE
IF Debugging
THEN
printf0('chaining ') ; PrintTerse(Field) ; printf0('\n')
END ;
FieldList := ChainOn(FieldList, MaybeAlignField(Chained(Field), byteOffset, bitOffset))
END ;
INC(i)
END ;
WatchRemoveList(sym, partiallydeclared) ;
WatchRemoveList(sym, heldbyalignment) ;
WatchRemoveList(sym, finishedalignment) ;
VarientType := BuildEndVarient(location, VarientType, FieldList, IsDeclaredPacked(sym)) ;
RETURN( VarientType )
END DeclareVarient ;
(*
DeclareFieldVarient -
*)
PROCEDURE DeclareFieldVarient (sym: CARDINAL) : tree ;
VAR
i, f : CARDINAL ;
VarientList,
VarientType,
byteOffset,
bitOffset,
GccFieldType: tree ;
location : location_t ;
BEGIN
location := TokenToLocation(GetDeclaredMod(sym)) ;
i := 1 ;
VarientList := tree(NIL) ;
VarientType := DoStartDeclaration(sym, BuildStartFieldVarient) ;
(* no need to store the [sym, RecordType] tuple as it is stored by DeclareRecord which calls us *)
byteOffset := GetIntegerZero(location) ;
bitOffset := GetIntegerZero(location) ;
WHILE GetNth(sym, i)#NulSym DO
f := GetNth(sym, i) ;
IF IsFieldVarient(f) AND IsEmptyFieldVarient(f)
THEN
(* do not include empty varient fields (created via 'else end' in variant records *)
ELSE
IF Debugging
THEN
printf0('chaining ') ; PrintTerse(f) ; printf0('\n')
END ;
VarientList := ChainOn(VarientList, MaybeAlignField(Chained(f), byteOffset, bitOffset))
END ;
INC(i)
END ;
WatchRemoveList(sym, partiallydeclared) ;
GccFieldType := BuildEndFieldVarient(location, VarientType, VarientList, IsDeclaredPacked(sym)) ;
RETURN( GccFieldType )
END DeclareFieldVarient ;
(*
DeclarePointer - declares a pointer type to gcc and returns the Tree.
*)
PROCEDURE DeclarePointer (sym: CARDINAL) : tree ;
BEGIN
RETURN( BuildPointerType(Mod2Gcc(GetSType(sym))) )
END DeclarePointer ;
(*
DeclareUnbounded - builds an unbounded type and returns the gcc tree.
*)
PROCEDURE DeclareUnbounded (sym: CARDINAL) : tree ;
VAR
record: CARDINAL ;
BEGIN
Assert(IsUnbounded(sym)) ;
IF GccKnowsAbout(sym)
THEN
RETURN( Mod2Gcc(sym) )
ELSE
record := GetUnboundedRecordType(sym) ;
Assert(IsRecord(record)) ;
Assert(AllDependantsFullyDeclared(record)) ;
IF (NOT GccKnowsAbout(record))
THEN
DeclareTypeConstFully(record) ;
WatchRemoveList(record, todolist)
END ;
RETURN( Mod2Gcc(record) )
END
END DeclareUnbounded ;
(*
BuildIndex -
*)
PROCEDURE BuildIndex (tokenno: CARDINAL; array: CARDINAL) : tree ;
VAR
Subscript: CARDINAL ;
Type,
High, Low: CARDINAL ;
n,
low, high: tree ;
location : location_t ;
BEGIN
location := TokenToLocation(tokenno) ;
Subscript := GetArraySubscript (array) ;
Assert (IsSubscript (Subscript)) ;
Type := GetDType (Subscript) ;
Low := GetTypeMin (Type) ;
High := GetTypeMax (Type) ;
DeclareConstant (tokenno, Low) ;
DeclareConstant (tokenno, High) ;
low := Mod2Gcc (Low) ;
high := Mod2Gcc (High) ;
IF ExceedsTypeRange (GetIntegerType (), low, high)
THEN
location := TokenToLocation (tokenno) ;
n := BuildConvert (location, GetIntegerType (), BuildSub (location, high, low, FALSE), FALSE) ;
IF TreeOverflow(n) OR ValueOutOfTypeRange (GetIntegerType (), n)
THEN
MetaError3('implementation restriction, array is too large {%1EDM}, the range {%2ad}..{%3ad} exceeds the integer range',
array, Low, High) ;
RETURN BuildArrayIndexType (GetIntegerZero (location), GetIntegerZero (location))
ELSE
PutArrayLarge (array) ;
RETURN BuildArrayIndexType (GetIntegerZero (location), n)
END
ELSE
low := BuildConvert (location, GetIntegerType (), low, FALSE) ;
high := BuildConvert (location, GetIntegerType (), high, FALSE) ;
RETURN BuildArrayIndexType (low, high)
END
END BuildIndex ;
(*
DeclareArray - declares an array to gcc and returns the gcc tree.
*)
PROCEDURE DeclareArray (Sym: CARDINAL) : tree ;
VAR
typeOfArray: CARDINAL ;
ArrayType,
GccArray,
GccIndex : tree ;
Subscript : CARDINAL ;
tokenno : CARDINAL ;
location : location_t ;
BEGIN
Assert(IsArray(Sym)) ;
tokenno := GetDeclaredMod(Sym) ;
location := TokenToLocation(tokenno) ;
Subscript := GetArraySubscript(Sym) ;
typeOfArray := GetDType(Sym) ;
GccArray := Mod2Gcc(typeOfArray) ;
GccIndex := BuildIndex(tokenno, Sym) ;
IF GccKnowsAbout(Sym)
THEN
ArrayType := Mod2Gcc(Sym)
ELSE
ArrayType := BuildStartArrayType(GccIndex, GccArray, typeOfArray) ;
PreAddModGcc(Sym, ArrayType)
END ;
PreAddModGcc(Subscript, GccArray) ; (* we save the type of this array as the subscript *)
PushIntegerTree(BuildSize(location, GccArray, FALSE)) ; (* and the size of this array so far *)
PopSize(Subscript) ;
GccArray := BuildEndArrayType(ArrayType, GccArray, GccIndex, typeOfArray) ;
Assert(GccArray=ArrayType) ;
RETURN( GccArray )
END DeclareArray ;
(*
DeclareProcType - declares a procedure type to gcc and returns the gcc type tree.
*)
PROCEDURE DeclareProcType (Sym: CARDINAL) : tree ;
VAR
i, p,
Parameter,
ReturnType: CARDINAL ;
func,
GccParam : tree ;
location : location_t ;
BEGIN
ReturnType := GetSType(Sym) ;
func := DoStartDeclaration(Sym, BuildStartFunctionType) ;
InitFunctionTypeParameters ;
p := NoOfParamAny (Sym) ;
i := p ;
WHILE i > 0 DO
Parameter := GetNthParamAny (Sym, i) ;
location := TokenToLocation (GetDeclaredMod (Parameter)) ;
GccParam := BuildProcTypeParameterDeclaration (location, Mod2Gcc (GetSType (Parameter)), IsVarParamAny (Sym, i)) ;
PreAddModGcc(Parameter, GccParam) ;
DEC(i)
END ;
IF ReturnType = NulSym
THEN
RETURN( BuildEndFunctionType (func, NIL, UsesVarArgs(Sym)) )
ELSE
RETURN( BuildEndFunctionType (func, Mod2Gcc(ReturnType), UsesVarArgs(Sym)) )
END
END DeclareProcType ;
VAR
MaxEnumerationField,
MinEnumerationField: CARDINAL ;
(*
FindMinMaxEnum - finds the minimum and maximum enumeration fields.
*)
PROCEDURE FindMinMaxEnum (field: WORD) ;
BEGIN
IF MaxEnumerationField=NulSym
THEN
MaxEnumerationField := field
ELSE
PushValue(field) ;
PushValue(MaxEnumerationField) ;
IF Gre(GetDeclaredMod(field))
THEN
MaxEnumerationField := field
END
END ;
IF MinEnumerationField=NulSym
THEN
MinEnumerationField := field
ELSE
PushValue(field) ;
PushValue(MinEnumerationField) ;
IF Less(GetDeclaredMod(field))
THEN
MinEnumerationField := field
END
END
END FindMinMaxEnum ;
(*
GetTypeMin -
*)
PROCEDURE GetTypeMin (type: CARDINAL) : CARDINAL ;
VAR
min, max: CARDINAL ;
BEGIN
IF IsSubrange(type)
THEN
GetSubrange(type, max, min) ;
RETURN( min )
ELSIF IsSet(type)
THEN
RETURN( GetTypeMin(GetSType(type)) )
ELSIF IsEnumeration(type)
THEN
MinEnumerationField := NulSym ;
MaxEnumerationField := NulSym ;
ForeachLocalSymDo (type, FindMinMaxEnum) ;
RETURN( MinEnumerationField )
ELSIF IsBaseType(type)
THEN
GetBaseTypeMinMax(type, min, max) ;
RETURN( min )
ELSIF IsSystemType(type)
THEN
GetSystemTypeMinMax(type, min, max) ;
RETURN( min )
ELSIF GetSType(type)=NulSym
THEN
MetaError1('unable to obtain the MIN value for type {%1as}', type) ;
RETURN NulSym
ELSE
RETURN( GetTypeMin(GetSType(type)) )
END
END GetTypeMin ;
(*
GetTypeMax -
*)
PROCEDURE GetTypeMax (type: CARDINAL) : CARDINAL ;
VAR
min, max: CARDINAL ;
BEGIN
IF IsSubrange(type)
THEN
GetSubrange(type, max, min) ;
RETURN( max )
ELSIF IsSet(type)
THEN
RETURN( GetTypeMax(GetSType(type)) )
ELSIF IsEnumeration(type)
THEN
MinEnumerationField := NulSym ;
MaxEnumerationField := NulSym ;
ForeachLocalSymDo (type, FindMinMaxEnum) ;
RETURN( MaxEnumerationField )
ELSIF IsBaseType(type)
THEN
GetBaseTypeMinMax(type, min, max) ;
RETURN( max )
ELSIF IsSystemType(type)
THEN
GetSystemTypeMinMax(type, min, max) ;
RETURN( max )
ELSIF GetSType(type)=NulSym
THEN
MetaError1('unable to obtain the MAX value for type {%1as}', type) ;
RETURN NulSym
ELSE
RETURN( GetTypeMax(GetSType(type)) )
END
END GetTypeMax ;
(*
PushNoOfBits - pushes the integer value of the number of bits required
to maintain a set of type.
*)
PROCEDURE PushNoOfBits (type: CARDINAL; low, high: CARDINAL) ;
BEGIN
PushValue(high) ;
ConvertToType(type) ;
PushValue(low) ;
ConvertToType(type) ;
Sub ;
ConvertToType(Cardinal)
END PushNoOfBits ;
(*
DeclareLargeSet - n is the name of the set.
type is the subrange type (or simple type)
low and high are the limits of the subrange.
*)
PROCEDURE DeclareLargeSet (n: Name; type: CARDINAL; low, high: CARDINAL) : tree ;
VAR
lowtree,
hightree,
BitsInSet,
RecordType,
GccField,
FieldList : tree ;
bpw : CARDINAL ;
location : location_t ;
BEGIN
location := TokenToLocation(GetDeclaredMod(type)) ;
bpw := GetBitsPerBitset() ;
PushValue(low) ;
lowtree := PopIntegerTree() ;
PushValue(high) ;
hightree := PopIntegerTree() ;
FieldList := tree(NIL) ;
RecordType := BuildStartRecord(location, KeyToCharStar(n)) ; (* no problem with recursive types here *)
PushNoOfBits(type, low, high) ;
PushCard(1) ;
Addn ;
BitsInSet := PopIntegerTree() ;
PushIntegerTree(BitsInSet) ;
PushCard(0) ;
WHILE Gre(GetDeclaredMod(type)) DO
PushIntegerTree(BitsInSet) ;
PushCard(bpw-1) ;
IF GreEqu(GetDeclaredMod(type))
THEN
PushIntegerTree(lowtree) ;
PushCard(bpw-1) ;
Addn ;
GccField := BuildFieldRecord(location, NIL, BuildSetType(location, NIL, Mod2Gcc(type), lowtree, PopIntegerTree(), FALSE)) ;
PushIntegerTree(lowtree) ;
PushCard(bpw) ;
Addn ;
lowtree := PopIntegerTree() ;
PushIntegerTree(BitsInSet) ;
PushCard(bpw) ;
Sub ;
BitsInSet := PopIntegerTree()
ELSE
(* printf2('range is %a..%a\n', GetSymName(low), GetSymName(high)) ; *)
GccField := BuildFieldRecord(location, NIL, BuildSetType(location, NIL, Mod2Gcc(type), lowtree, hightree, FALSE)) ;
PushCard(0) ;
BitsInSet := PopIntegerTree()
END ;
FieldList := ChainOn(FieldList, GccField) ;
PushIntegerTree(BitsInSet) ;
PushCard(0)
END ;
RETURN( BuildEndRecord(location, RecordType, FieldList, FALSE) )
END DeclareLargeSet ;
(*
DeclareLargeOrSmallSet - works out whether the set will exceed TSIZE(WORD). If it does
we manufacture a set using:
settype = RECORD
w1: SET OF [...]
w2: SET OF [...]
END
We do this as GCC and GDB (stabs) only knows about WORD sized sets.
If the set will fit into a WORD then we call gccgm2 directly.
*)
PROCEDURE DeclareLargeOrSmallSet (sym: CARDINAL;
n: Name; type: CARDINAL; low, high: CARDINAL) : tree ;
VAR
location: location_t ;
packed : BOOLEAN ;
BEGIN
PushNoOfBits(type, low, high) ;
PushCard(GetBitsPerBitset()) ;
packed := IsSetPacked (sym) ;
IF Less(GetDeclaredMod(type))
THEN
location := TokenToLocation(GetDeclaredMod(sym)) ;
(* small set *)
(* PutSetSmall(sym) ; *)
RETURN BuildSetType (location, KeyToCharStar(n),
Mod2Gcc(type), Mod2Gcc(low), Mod2Gcc(high), packed)
ELSE
(* PutSetLarge(sym) ; *)
RETURN DeclareLargeSet (n, type, low, high) (* --fixme-- finish packed here as well. *)
END
END DeclareLargeOrSmallSet ;
(*
DeclareSet - declares a set type to gcc and returns a Tree.
*)
PROCEDURE DeclareSet (sym: CARDINAL) : tree ;
VAR
gccsym : tree ;
type,
high, low: CARDINAL ;
BEGIN
type := GetDType(sym) ;
IF IsSubrange(type)
THEN
GetSubrange(type, high, low) ;
gccsym := DeclareLargeOrSmallSet(sym, GetFullSymName(sym), GetSType(type), low, high)
ELSE
gccsym := DeclareLargeOrSmallSet(sym, GetFullSymName(sym), type, GetTypeMin(type), GetTypeMax(type))
END ;
RETURN( gccsym )
END DeclareSet ;
(*
CheckResolveSubrange - checks to see whether we can determine
the subrange type. We are able to do
this once low, high and the type are known.
*)
PROCEDURE CheckResolveSubrange (sym: CARDINAL) ;
VAR
tokenno : CARDINAL;
size, high, low, type: CARDINAL ;
BEGIN
GetSubrange(sym, high, low) ;
tokenno := GetDeclaredMod (sym) ;
type := GetSType(sym) ;
IF type=NulSym
THEN
IF GccKnowsAbout(low) AND GccKnowsAbout(high)
THEN
IF IsConstString (low) AND IsConstStringKnown (low)
THEN
size := GetStringLength (tokenno, low) ;
IF size <= 1
THEN
PutSubrange(sym, low, high, Char)
ELSE
MetaError1 ('cannot have a subrange of a string type {%1Uad}',
sym)
END
ELSIF IsFieldEnumeration(low)
THEN
IF GetSType(low)=GetSType(high)
THEN
PutSubrange(sym, low, high, GetSType(low))
ELSE
MetaError1('subrange limits must be of the same type {%1Uad}', sym)
END
ELSIF IsValueSolved(low)
THEN
IF GetSType(low)=LongReal
THEN
MetaError1('cannot have a subrange of a SHORTREAL, REAL or LONGREAL type {%1Uad}', sym)
ELSE
PutSubrange(sym, low, high, MixTypes(GetSType(low), GetSType(high), GetDeclaredMod(sym)))
END
END
END
END
END CheckResolveSubrange ;
(*
TypeConstFullyDeclared - all, sym, dependents are declared, so create and
return the GCC Tree equivalent.
*)
PROCEDURE TypeConstFullyDeclared (sym: CARDINAL) : tree ;
VAR
t: tree ;
BEGIN
IF IsEnumeration(sym)
THEN
t := DeclareEnumeration(sym)
ELSIF IsFieldEnumeration(sym)
THEN
t := DeclareFieldEnumeration(sym)
ELSIF IsSubrange(sym)
THEN
t := DeclareSubrange(sym)
ELSIF IsRecord(sym)
THEN
t := CheckPragma(DeclareRecord(sym), sym)
ELSIF IsRecordField(sym)
THEN
t := CheckPragma(DeclareRecordField(sym), sym)
ELSIF IsFieldVarient(sym)
THEN
t := DeclareFieldVarient(sym)
ELSIF IsVarient(sym)
THEN
t := DeclareVarient(sym)
ELSIF IsPointer(sym)
THEN
t := CheckAlignment(DeclarePointer(sym), sym)
ELSIF IsUnbounded(sym)
THEN
t := DeclareUnbounded(sym)
ELSIF IsArray(sym)
THEN
t := CheckAlignment(DeclareArray(sym), sym)
ELSIF IsProcType(sym)
THEN
t := DeclareProcType(sym)
ELSIF IsSet(sym)
THEN
t := DeclareSet(sym)
ELSIF IsConst(sym)
THEN
IF IsConstructor(sym)
THEN
PushValue(sym) ;
ChangeToConstructor(GetDeclaredMod(sym), GetSType(sym)) ;
PopValue(sym) ;
EvaluateValue(sym) ;
PutConstructorSolved(sym) ;
ELSIF IsConstSet(sym)
THEN
EvaluateValue(sym)
END ;
IF NOT IsValueSolved(sym)
THEN
RETURN( NIL )
END ;
t := DeclareConst(GetDeclaredMod(sym), sym) ;
Assert(t#NIL)
ELSIF IsConstructor(sym)
THEN
(* not yet known as a constant *)
RETURN( NIL )
ELSE
t := DeclareType(sym) ;
IF IsType(sym)
THEN
t := CheckAlignment(t, sym)
END
END ;
RETURN RememberType (t)
END TypeConstFullyDeclared ;
(*
IsBaseType - returns true if a type, Sym, is a base type and
we use predefined GDB information to represent this
type.
*)
PROCEDURE IsBaseType (Sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN( (Sym=Cardinal) OR (Sym=Integer) OR
(Sym=Char) OR (Sym=Proc) )
END IsBaseType ;
(*
IsFieldEnumerationDependants - sets enumDeps to FALSE if action(Sym)
is also FALSE.
*)
PROCEDURE IsFieldEnumerationDependants (Sym: WORD) ;
BEGIN
IF NOT action(Sym)
THEN
enumDeps := FALSE
END
END IsFieldEnumerationDependants ;
(*
IsEnumerationDependants - returns true if the enumeration
p(dependants) all return true.
*)
PROCEDURE IsEnumerationDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
BEGIN
action := q ;
enumDeps := TRUE ;
ForeachLocalSymDo (sym, IsFieldEnumerationDependants) ;
RETURN( enumDeps )
END IsEnumerationDependants ;
(*
WalkEnumerationDependants - returns walks all dependants of Sym.
*)
PROCEDURE WalkEnumerationDependants (sym: CARDINAL; p: WalkAction) ;
BEGIN
ForeachLocalSymDo (sym, p)
END WalkEnumerationDependants ;
(*
WalkSubrangeDependants - calls p(dependants) for each dependant of, sym.
*)
PROCEDURE WalkSubrangeDependants (sym: CARDINAL; p: WalkAction) ;
VAR
type, align,
high, low : CARDINAL ;
BEGIN
GetSubrange(sym, high, low) ;
CheckResolveSubrange (sym) ;
type := GetSType(sym) ;
IF type#NulSym
THEN
p(type)
END ;
(* low and high are not types but constants and they are resolved by M2GenGCC *)
p(low) ;
p(high) ;
align := GetAlignment (sym) ;
IF align # NulSym
THEN
p(align)
END
END WalkSubrangeDependants ;
(*
IsSubrangeDependants - returns TRUE if the subrange
q(dependants) all return TRUE.
*)
PROCEDURE IsSubrangeDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
result : BOOLEAN ;
align,
type,
high, low: CARDINAL ;
BEGIN
GetSubrange(sym, high, low) ;
(* low and high are not types but constants and they are resolved by M2GenGCC *)
CheckResolveSubrange(sym) ;
result := TRUE ;
type := GetSType(sym) ;
IF (type=NulSym) OR (NOT q(type))
THEN
result := FALSE
END ;
IF NOT q(low)
THEN
result := FALSE
END ;
IF NOT q(high)
THEN
result := FALSE
END ;
align := GetAlignment(sym) ;
IF (align#NulSym) AND (NOT q(align))
THEN
result := FALSE
END ;
RETURN( result )
END IsSubrangeDependants ;
(*
WalkComponentDependants -
*)
PROCEDURE WalkComponentDependants (sym: CARDINAL; p: WalkAction) ;
VAR
i : CARDINAL ;
type: CARDINAL ;
BEGIN
(* need to walk record and field *)
i := 1 ;
REPEAT
type := GetNth(sym, i) ;
IF type#NulSym
THEN
IF IsVar(type)
THEN
p(GetSType(type))
ELSE
p(type)
END ;
INC(i)
END
UNTIL type=NulSym
END WalkComponentDependants ;
(*
IsComponentDependants -
*)
PROCEDURE IsComponentDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
type : CARDINAL ;
i : CARDINAL ;
result: BOOLEAN ;
BEGIN
(* need to check record is completely resolved *)
result := TRUE ;
i := 1 ;
REPEAT
type := GetNth(sym, i) ;
IF type#NulSym
THEN
IF IsVar(type)
THEN
type := GetSType(type)
END ;
IF NOT q(type)
THEN
result := FALSE
END ;
INC(i)
END
UNTIL type=NulSym ;
RETURN( result )
END IsComponentDependants ;
(*
WalkVarDependants - walks all dependants of sym.
*)
PROCEDURE WalkVarDependants (sym: CARDINAL; p: WalkAction) ;
VAR
type: CARDINAL ;
BEGIN
p(GetSType(sym)) ;
IF IsComponent(sym)
THEN
WalkComponentDependants(sym, p)
END ;
type := GetVarBackEndType(sym) ;
IF type#NulSym
THEN
p(type)
END
END WalkVarDependants ;
(*
IsVarDependants - returns TRUE if the pointer symbol, sym,
p(dependants) all return TRUE.
*)
PROCEDURE IsVarDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
type : CARDINAL ;
result: BOOLEAN ;
BEGIN
result := TRUE ;
IF NOT q(GetSType(sym))
THEN
result := FALSE
END ;
IF IsComponent(sym)
THEN
IF NOT IsComponentDependants(sym, q)
THEN
result := FALSE
END
END ;
type := GetVarBackEndType(sym) ;
IF type#NulSym
THEN
IF NOT q(type)
THEN
result := FALSE
END
END ;
RETURN( result )
END IsVarDependants ;
(*
WalkPointerDependants - walks all dependants of sym.
*)
PROCEDURE WalkPointerDependants (sym: CARDINAL; p: WalkAction) ;
VAR
align: CARDINAL ;
BEGIN
p(GetSType(sym)) ;
align := GetAlignment(sym) ;
IF align#NulSym
THEN
p(align)
END
END WalkPointerDependants ;
(*
IsPointerDependants - returns TRUE if the pointer symbol, sym,
p(dependants) all return TRUE.
*)
PROCEDURE IsPointerDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
align: CARDINAL ;
final: BOOLEAN ;
BEGIN
final := TRUE ;
IF NOT q(GetSType(sym))
THEN
final := FALSE
END ;
align := GetAlignment (sym) ;
IF final AND (align # NulSym)
THEN
IF NOT q(align)
THEN
final := FALSE
END
END ;
RETURN final
END IsPointerDependants ;
(*
IsRecordAlignment -
*)
PROCEDURE IsRecordAlignment (sym: CARDINAL; q: IsAction) : BOOLEAN ;
BEGIN
IF GetDefaultRecordFieldAlignment(sym)#NulSym
THEN
IF NOT q(GetDefaultRecordFieldAlignment(sym))
THEN
RETURN( FALSE )
END
END ;
RETURN( TRUE )
END IsRecordAlignment ;
(*
IsRecordDependants - returns TRUE if the symbol, sym,
q(dependants) all return TRUE.
*)
PROCEDURE IsRecordDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
result: BOOLEAN ;
i : CARDINAL ;
field : CARDINAL ;
BEGIN
result := IsRecordAlignment(sym, q) ;
i := 1 ;
REPEAT
field := GetNth(sym, i) ;
IF field#NulSym
THEN
IF IsRecordField(field)
THEN
IF (NOT IsRecordFieldAVarientTag(field)) OR (GetSymName(field)#NulName)
THEN
IF NOT q(field)
THEN
result := FALSE
END
END
ELSIF IsVarient(field)
THEN
IF NOT q(field)
THEN
result := FALSE
END
ELSIF IsFieldVarient(field)
THEN
InternalError ('should not see a field varient')
ELSE
InternalError ('unknown symbol in record')
END
END ;
INC(i)
UNTIL field=NulSym ;
RETURN( result )
END IsRecordDependants ;
(*
WalkRecordAlignment - walks the alignment constant associated with
record, sym.
*)
PROCEDURE WalkRecordAlignment (sym: CARDINAL; p: WalkAction) ;
BEGIN
IF GetDefaultRecordFieldAlignment(sym)#NulSym
THEN
p(GetDefaultRecordFieldAlignment(sym))
END
END WalkRecordAlignment ;
(*
WalkRecordDependants - walks symbol, sym, dependants. It only
walks the fields if the alignment is
unused or fully declared.
*)
PROCEDURE WalkRecordDependants (sym: CARDINAL; p: WalkAction) ;
BEGIN
WalkRecordAlignment(sym, p) ;
WalkRecordDependants2(sym, p)
END WalkRecordDependants ;
(*
WalkRecordFieldDependants -
*)
PROCEDURE WalkRecordFieldDependants (sym: CARDINAL; p: WalkAction) ;
VAR
v : CARDINAL ;
align: CARDINAL ;
BEGIN
Assert(IsRecordField(sym)) ;
p(GetSType(sym)) ;
v := GetVarient(sym) ;
IF v#NulSym
THEN
p(v)
END ;
align := GetAlignment(sym) ;
IF align#NulSym
THEN
p(align)
END
END WalkRecordFieldDependants ;
(*
WalkRecordDependants2 - walks the fields of record, sym, calling
p on every dependant.
*)
PROCEDURE WalkRecordDependants2 (sym: CARDINAL; p: WalkAction) ;
VAR
i : CARDINAL ;
Field: CARDINAL ;
BEGIN
i := 1 ;
WHILE GetNth(sym, i)#NulSym DO
Field := GetNth(sym, i) ;
p(Field) ;
IF IsRecordField(Field)
THEN
WalkRecordFieldDependants(Field, p)
ELSIF IsVarient(Field)
THEN
WalkVarientDependants(Field, p)
ELSIF IsFieldVarient(Field)
THEN
InternalError ('should not see a field varient')
ELSE
InternalError ('unknown symbol in record')
END ;
INC(i)
END
END WalkRecordDependants2 ;
(*
IsVarientAlignment -
*)
PROCEDURE IsVarientAlignment (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
align: CARDINAL ;
BEGIN
sym := GetRecordOfVarient(sym) ;
align := GetDefaultRecordFieldAlignment(sym) ;
IF (align#NulSym) AND (NOT q(align))
THEN
RETURN( FALSE )
END ;
RETURN( TRUE )
END IsVarientAlignment ;
(*
IsVarientDependants - returns TRUE if the symbol, sym,
q(dependants) all return TRUE.
*)
PROCEDURE IsVarientDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
result: BOOLEAN ;
i : CARDINAL ;
Field : CARDINAL ;
BEGIN
result := IsVarientAlignment(sym, q) ;
i := 1 ;
WHILE GetNth(sym, i)#NulSym DO
Field := GetNth(sym, i) ;
Assert(IsFieldVarient(Field)) ;
IF NOT q(Field)
THEN
result := FALSE
END ;
INC(i)
END ;
RETURN( result )
END IsVarientDependants ;
(*
WalkVarientAlignment -
*)
PROCEDURE WalkVarientAlignment (sym: CARDINAL; p: WalkAction) ;
VAR
align: CARDINAL ;
BEGIN
sym := GetRecordOfVarient(sym) ;
align := GetDefaultRecordFieldAlignment(sym) ;
IF align#NulSym
THEN
p(align)
END
END WalkVarientAlignment ;
(*
WalkVarientDependants - walks symbol, sym, dependants.
*)
PROCEDURE WalkVarientDependants (sym: CARDINAL; p: WalkAction) ;
VAR
i : CARDINAL ;
v,
Field: CARDINAL ;
BEGIN
WalkVarientAlignment(sym, p) ;
IF GetSType(sym)#NulSym
THEN
p(GetSType(sym))
END ;
v := GetVarient(sym) ;
IF v#NulSym
THEN
p(v)
END ;
i := 1 ;
WHILE GetNth(sym, i)#NulSym DO
Field := GetNth(sym, i) ;
Assert(IsFieldVarient(Field)) ; (* field varients do _not_ have a type *)
p(Field) ;
WalkVarientFieldDependants(Field, p) ;
INC(i)
END
END WalkVarientDependants ;
(*
IsVarientFieldDependants - returns TRUE if the symbol, sym,
q(dependants) all return TRUE.
*)
PROCEDURE IsVarientFieldDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
i : CARDINAL ;
type,
Field : CARDINAL ;
result: BOOLEAN ;
BEGIN
i := 1 ;
result := IsVarientAlignment(sym, q) ;
WHILE GetNth(sym, i)#NulSym DO
Field := GetNth(sym, i) ;
IF NOT q(Field)
THEN
result := FALSE
END ;
type := GetSType(Field) ;
IF type#NulSym
THEN
IF NOT q(type)
THEN
result := FALSE
END
END ;
INC(i)
END ;
RETURN( result )
END IsVarientFieldDependants ;
(*
WalkVarientFieldDependants -
*)
PROCEDURE WalkVarientFieldDependants (sym: CARDINAL; p: WalkAction) ;
VAR
i : CARDINAL ;
type,
Field: CARDINAL ;
BEGIN
WalkVarientAlignment(sym, p) ;
i := 1 ;
WHILE GetNth(sym, i)#NulSym DO
Field := GetNth(sym, i) ;
p(Field) ;
type := GetSType(Field) ;
IF type#NulSym
THEN
p(type)
END ;
INC(i)
END
END WalkVarientFieldDependants ;
(*
IsArrayDependants - returns TRUE if the symbol, sym,
q(dependants) all return TRUE.
*)
PROCEDURE IsArrayDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
result : BOOLEAN ;
align : CARDINAL ;
subscript: CARDINAL ;
high, low: CARDINAL ;
type : CARDINAL ;
BEGIN
result := TRUE ;
Assert(IsArray(sym)) ;
type := GetSType(sym) ;
IF NOT q(type)
THEN
result := FALSE
END ;
subscript := GetArraySubscript(sym) ;
IF subscript#NulSym
THEN
Assert(IsSubscript(subscript)) ;
type := GetSType(subscript) ;
IF NOT q(type)
THEN
result := FALSE
END ;
type := SkipType(type) ;
(* the array might be declared as ARRAY type OF foo *)
low := GetTypeMin(type) ;
high := GetTypeMax(type) ;
IF NOT q(low)
THEN
result := FALSE
END ;
IF NOT q(high)
THEN
result := FALSE
END ;
align := GetAlignment(sym) ;
IF (align#NulSym) AND (NOT q(align))
THEN
result := FALSE
END
END ;
RETURN( result )
END IsArrayDependants ;
(*
WalkArrayDependants - walks symbol, sym, dependants.
*)
PROCEDURE WalkArrayDependants (sym: CARDINAL; p: WalkAction) ;
VAR
align : CARDINAL ;
subscript: CARDINAL ;
high, low: CARDINAL ;
type : CARDINAL ;
BEGIN
Assert(IsArray(sym)) ;
type := GetSType(sym) ;
p(type) ;
subscript := GetArraySubscript(sym) ;
IF subscript#NulSym
THEN
Assert(IsSubscript(subscript)) ;
type := GetSType(subscript) ;
p(type) ;
type := SkipType(type) ;
(* the array might be declared as ARRAY type OF foo *)
low := GetTypeMin(type) ;
high := GetTypeMax(type) ;
p(low) ;
p(high) ;
align := GetAlignment (sym) ;
IF align#NulSym
THEN
p(align)
END
END
END WalkArrayDependants ;
(*
IsSetDependants - returns TRUE if the symbol, sym,
q(dependants) all return TRUE.
*)
PROCEDURE IsSetDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
result : BOOLEAN ;
type, low, high: CARDINAL ;
BEGIN
result := TRUE ;
Assert(IsSet(sym)) ;
type := GetDType(sym) ;
IF NOT q(type)
THEN
result := FALSE
END ;
low := GetTypeMin(type) ;
high := GetTypeMax(type) ;
IF NOT q(low)
THEN
result := FALSE
END ;
IF NOT q(high)
THEN
result := FALSE
END ;
RETURN( result )
END IsSetDependants ;
(*
WalkSetDependants - walks dependants, sym.
*)
PROCEDURE WalkSetDependants (sym: CARDINAL; p: WalkAction) ;
VAR
type, low, high: CARDINAL ;
BEGIN
Assert(IsSet(sym)) ;
type := GetDType(sym) ;
p(type) ;
low := GetTypeMin(type) ;
p(low) ;
high := GetTypeMax(type) ;
p(high)
END WalkSetDependants ;
(*
IsProcTypeDependants -
*)
PROCEDURE IsProcTypeDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
i, p, son : CARDINAL ;
ParamType,
ReturnType: CARDINAL ;
result : BOOLEAN ;
BEGIN
result := TRUE ;
Assert(IsProcType(sym)) ;
i := 1 ;
ReturnType := GetSType(sym) ;
p := NoOfParamAny (sym) ;
WHILE i<=p DO
son := GetNthParamAny (sym, i) ;
ParamType := GetSType(son) ;
IF NOT q(ParamType)
THEN
result := FALSE
END ;
INC(i)
END ;
IF (ReturnType=NulSym) OR q(ReturnType)
THEN
RETURN( result )
ELSE
RETURN( FALSE )
END
END IsProcTypeDependants ;
(*
WalkProcTypeDependants - walks dependants, sym.
*)
PROCEDURE WalkProcTypeDependants (sym: CARDINAL; p: WalkAction) ;
VAR
i, n, son : CARDINAL ;
ParamType,
ReturnType: CARDINAL ;
BEGIN
Assert(IsProcType(sym)) ;
i := 1 ;
ReturnType := GetSType(sym) ;
n := NoOfParamAny (sym) ;
WHILE i<=n DO
son := GetNthParamAny (sym, i) ;
ParamType := GetSType(son) ;
p(ParamType) ;
INC(i)
END ;
IF ReturnType#NulSym
THEN
p(ReturnType)
END
END WalkProcTypeDependants ;
(*
IsProcedureDependants -
*)
PROCEDURE IsProcedureDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
i, son : CARDINAL ;
type,
ReturnType: CARDINAL ;
result : BOOLEAN ;
BEGIN
result := TRUE ;
Assert(IsProcedure(sym)) ;
i := 1 ;
ReturnType := GetSType(sym) ;
WHILE GetNth(sym, i)#NulSym DO
son := GetNth(sym, i) ;
type := GetSType(son) ;
IF NOT q(type)
THEN
result := FALSE
END ;
INC(i)
END ;
IF (ReturnType=NulSym) OR q(ReturnType)
THEN
RETURN( result )
ELSE
RETURN( FALSE )
END
END IsProcedureDependants ;
(*
WalkProcedureDependants - walks dependants, sym.
*)
PROCEDURE WalkProcedureDependants (sym: CARDINAL; p: WalkAction) ;
VAR
i, son : CARDINAL ;
type,
ReturnType: CARDINAL ;
BEGIN
Assert(IsProcedure(sym)) ;
i := 1 ;
ReturnType := GetSType(sym) ;
WHILE GetNth(sym, i)#NulSym DO
son := GetNth(sym, i) ;
type := GetSType(son) ;
p(type) ;
INC(i)
END ;
IF ReturnType#NulSym
THEN
p(ReturnType)
END
END WalkProcedureDependants ;
(*
IsUnboundedDependants - returns TRUE if the symbol, sym,
q(dependants) all return TRUE.
*)
PROCEDURE IsUnboundedDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
result: BOOLEAN ;
BEGIN
result := TRUE ;
IF NOT q(GetUnboundedRecordType(sym))
THEN
result := FALSE
END ;
IF NOT q(Cardinal)
THEN
result := FALSE
END ;
IF NOT q(GetSType(sym))
THEN
result := FALSE
END ;
RETURN( result )
END IsUnboundedDependants ;
(*
WalkUnboundedDependants - walks the dependants of, sym.
*)
PROCEDURE WalkUnboundedDependants (sym: CARDINAL; p: WalkAction) ;
BEGIN
p(GetUnboundedRecordType(sym)) ;
p(Cardinal) ;
p(GetSType(sym))
END WalkUnboundedDependants ;
(*
IsTypeDependants - returns TRUE if all q(dependants) return
TRUE.
*)
PROCEDURE IsTypeDependants (sym: CARDINAL; q: IsAction) : BOOLEAN ;
VAR
align: CARDINAL ;
type : CARDINAL ;
final: BOOLEAN ;
BEGIN
type := GetSType(sym) ;
final := TRUE ;
IF (type#NulSym) AND (NOT q(type))
THEN
final := FALSE
END ;
align := GetAlignment(sym) ;
IF (align#NulSym) AND (NOT q(align))
THEN
final := FALSE
END ;
RETURN( final )
END IsTypeDependants ;
(*
WalkTypeDependants - walks all dependants of, sym.
*)
PROCEDURE WalkTypeDependants (sym: CARDINAL; p: WalkAction) ;
VAR
align: CARDINAL ;
type : CARDINAL ;
BEGIN
type := GetSType(sym) ;
IF type#NulSym
THEN
p(type)
END ;
align := GetAlignment(sym) ;
IF align#NulSym
THEN
p(align)
END
END WalkTypeDependants ;
(*
PoisonSymbols - poisons all gcc symbols from procedure, sym.
A debugging aid.
*)
PROCEDURE PoisonSymbols (sym: CARDINAL) ;
BEGIN
IF IsProcedure(sym)
THEN
ForeachLocalSymDo(sym, Poison)
END
END PoisonSymbols ;
(*
ConstantKnownAndUsed -
*)
PROCEDURE ConstantKnownAndUsed (sym: CARDINAL; t: tree) ;
BEGIN
DeclareConstantFromTree(sym, RememberConstant(t))
END ConstantKnownAndUsed ;
(*
InitDeclarations - initializes default types and the source filename.
*)
PROCEDURE InitDeclarations ;
BEGIN
DeclareDefaultTypes ;
DeclareDefaultConstants
END InitDeclarations ;
BEGIN
FreeGroup := NIL ;
GlobalGroup := InitGroup () ;
ErrorDepList := InitSet (1) ;
ChainedList := InitSet(1) ;
WatchList := InitSet(1) ;
VisitedList := NIL ;
EnumerationIndex := InitIndex(1) ;
HaveInitDefaultTypes := FALSE ;
recursionCaught := FALSE
END M2GCCDeclare.