blob: 3550fd606a5ee4cbff7b9686a00d2946b6aa1e03 [file] [log] [blame]
(* decl.mod declaration nodes used to create the AST.
Copyright (C) 2015-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius@glam.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 decl ; (*!m2pim*)
FROM ASCII IMPORT lf, tab ;
FROM symbolKey IMPORT NulKey, symbolTree, initTree, getSymKey, putSymKey, foreachNodeDo ;
FROM mcDebug IMPORT assert ;
FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
FROM nameKey IMPORT NulName, makeKey, lengthKey, makekey, keyToCharStar ;
FROM SFIO IMPORT OpenToWrite, WriteS ;
FROM FIO IMPORT File, Close, FlushBuffer, StdOut, WriteLine, WriteChar ;
FROM DynamicStrings IMPORT String, InitString, EqualArray, InitStringCharStar, KillString, ConCat, Mark, RemoveWhitePostfix, RemoveWhitePrefix ;
FROM StringConvert IMPORT CardinalToString, ostoc ;
FROM mcOptions IMPORT getOutputFile, getDebugTopological, getHPrefix, getIgnoreFQ, getExtendedOpaque, writeGPLheader, getGccConfigSystem, getScaffoldDynamic, getScaffoldMain ;
FROM FormatStrings IMPORT Sprintf0, Sprintf1, Sprintf2, Sprintf3 ;
FROM libc IMPORT printf, memset ;
FROM mcMetaError IMPORT metaError1, metaError2, metaError3, metaErrors1, metaErrors2 ;
FROM mcError IMPORT errorAbort0, flushErrors ;
FROM mcLexBuf IMPORT findFileNameFromToken, tokenToLineNo, tokenToColumnNo,
getProcedureComment, getBodyComment, getAfterComment,
lastcomment ;
FROM mcComment IMPORT commentDesc, isProcedureComment, isAfterComment, isBodyComment, getContent, initComment, addText ;
FROM StrLib IMPORT StrEqual, StrLen ;
FROM mcPretty IMPORT pretty, initPretty, dupPretty, killPretty, print, prints, raw,
setNeedSpace, noSpace, setindent, getindent, getcurpos,
getseekpos, getcurline,
pushPretty, popPretty ;
FROM Indexing IMPORT Index, InitIndex, ForeachIndiceInIndexDo,
IncludeIndiceIntoIndex, IsIndiceInIndex,
HighIndice, LowIndice, GetIndice, RemoveIndiceFromIndex,
PutIndice, InBounds ;
IMPORT DynamicStrings ;
IMPORT alists, wlists ;
IMPORT keyc ;
IMPORT mcStream ;
FROM alists IMPORT alist ;
FROM wlists IMPORT wlist ;
CONST
indentation = 3 ;
indentationC = 2 ;
debugScopes = FALSE ;
debugDecl = FALSE ;
caseException = TRUE ;
returnException = TRUE ;
(* this is a work around to avoid ever having to handle dangling else. *)
forceCompoundStatement = TRUE ; (* TRUE will avoid dangling else, by always using {}. *)
enableDefForCStrings = FALSE ; (* currently disabled. *)
enableMemsetOnAllocation = TRUE ; (* Should we memset (..., 0, ...) the allocated mem? *)
forceQualified = TRUE ;
TYPE
language = (ansiC, ansiCP, pim4) ;
nodeT = (explist, funccall,
exit, return, stmtseq, comment, halt,
new, dispose, inc, dec, incl, excl,
length,
(* base constants. *)
nil, true, false,
(* system types. *)
address, loc, byte, word,
csizet, cssizet,
(* base types. *)
char,
cardinal, longcard, shortcard,
integer, longint, shortint,
real, longreal, shortreal,
bitset, boolean, proc,
ztype, rtype,
complex, longcomplex, shortcomplex,
(* language features and compound type attributes. *)
type, record, varient, var, enumeration,
subrange, array, subscript,
string, const, literal, varparam, param, varargs, optarg,
pointer, recordfield, varientfield, enumerationfield,
set, proctype,
(* blocks. *)
procedure, def, imp, module,
(* statements. *)
loop, while, for, repeat,
case, caselabellist, caselist, range,
assignment,
if, elsif,
(* expressions. *)
constexp,
neg,
cast, val,
plus, sub, div, mod, mult, divide, in,
adr, size, tsize, ord, float, trunc, chr, abs, cap,
high, throw, unreachable,
cmplx, re, im,
min, max,
componentref, pointerref, arrayref, deref,
equal, notequal, less, greater, greequal, lessequal,
lsl, lsr, lor, land, lnot, lxor,
and, or, not, identlist, vardecl, setvalue) ;
node = POINTER TO nodeRec ;
nodeRec = RECORD
CASE kind: nodeT OF
unreachable,
throw,
new,
dispose,
inc,
dec,
incl,
excl,
halt : intrinsicF: intrinsicT |
explist : explistF: explistT |
exit : exitF : exitT |
return : returnF : returnT |
stmtseq : stmtF : stmtT |
comment : commentF: commentT |
(* base constants. *)
nil,
true,
false,
(* system types. *)
address,
loc,
byte,
word,
csizet,
cssizet : |
(* base types. *)
boolean,
proc,
char,
integer,
cardinal,
longcard,
shortcard,
longint,
shortint,
real,
longreal,
shortreal,
bitset,
ztype,
rtype,
complex,
longcomplex,
shortcomplex : |
(* language features and compound type attributes. *)
type : typeF : typeT |
record : recordF : recordT |
varient : varientF : varientT |
var : varF : varT |
enumeration : enumerationF : enumerationT |
subrange : subrangeF : subrangeT |
subscript : subscriptF : subscriptT |
array : arrayF : arrayT |
string : stringF : stringT |
const : constF : constT |
literal : literalF : literalT |
varparam : varparamF : varparamT |
param : paramF : paramT |
varargs : varargsF : varargsT |
optarg : optargF : optargT |
pointer : pointerF : pointerT |
recordfield : recordfieldF : recordfieldT |
varientfield : varientfieldF : varientfieldT |
enumerationfield: enumerationfieldF: enumerationfieldT |
set : setF : setT |
proctype : proctypeF : proctypeT |
(* blocks. *)
procedure : procedureF : procedureT |
def : defF : defT |
imp : impF : impT |
module : moduleF : moduleT |
(* statements. *)
loop : loopF : loopT |
while : whileF : whileT |
for : forF : forT |
repeat : repeatF : repeatT |
case : caseF : caseT |
caselabellist : caselabellistF : caselabellistT |
caselist : caselistF : caselistT |
range : rangeF : rangeT |
if : ifF : ifT |
elsif : elsifF : elsifT |
assignment : assignmentF : assignmentT |
(* expressions. *)
arrayref : arrayrefF : arrayrefT |
pointerref : pointerrefF : pointerrefT |
componentref : componentrefF : componentrefT |
cmplx,
and,
or,
equal,
notequal,
less,
greater,
greequal,
lessequal,
val,
cast,
plus,
sub,
div,
mod,
mult,
divide,
in : binaryF : binaryT |
constexp,
deref,
abs,
chr,
cap,
high,
ord,
float,
trunc,
re,
im,
not,
neg,
adr,
size,
tsize,
min,
max : unaryF : unaryT |
identlist : identlistF : identlistT |
vardecl : vardeclF : vardeclT |
funccall : funccallF : funccallT |
setvalue : setvalueF : setvalueT
END ;
at: where ;
END ;
intrinsicT = RECORD
args : node ;
noArgs : CARDINAL ;
type : node ;
intrinsicComment: commentPair ;
postUnreachable : BOOLEAN ;
END ;
fixupInfo = RECORD
count: CARDINAL ;
info : Index ;
END ;
explistT = RECORD
exp: Index ;
END ;
setvalueT = RECORD
type: node ;
values: Index ;
END ;
identlistT = RECORD
names : wlist ;
cnamed: BOOLEAN ;
END ;
funccallT = RECORD
function : node ;
args : node ;
type : node ;
funccallComment: commentPair ;
END ;
commentT = RECORD
content: commentDesc ;
END ;
stmtT = RECORD
statements: Index ;
END ;
returnT = RECORD
exp : node ;
scope : node ;
returnComment: commentPair ;
END ;
exitT = RECORD
loop: node ;
END ;
vardeclT = RECORD
names: wlist ;
type : node ;
scope: node ;
END ;
typeT = RECORD
name : Name ;
type : node ;
scope : node ;
isHidden,
isInternal: BOOLEAN ;
END ;
recordT = RECORD
localSymbols: symbolTree ;
listOfSons : Index ;
scope : node ;
END ;
varientT = RECORD
listOfSons: Index ;
varient : node ;
tag : node ;
scope : node ;
END ;
varT = RECORD
name : Name ;
type : node ;
decl : node ;
scope : node ;
isInitialised,
isParameter,
isVarParameter,
isUsed : BOOLEAN ;
cname : cnameT ;
END ;
enumerationT = RECORD
noOfElements: CARDINAL ;
localSymbols: symbolTree ;
listOfSons : Index ;
low, high : node ;
scope : node ;
END ;
subrangeT = RECORD
low,
high : node ;
type : node ;
scope: node ;
END ;
subscriptT = RECORD
type: node ;
expr: node ;
END ;
arrayT = RECORD
subr : node ;
type,
scope : node ;
isUnbounded: BOOLEAN ;
END ;
stringT = RECORD
name : Name ;
length : CARDINAL ;
isCharCompatible: BOOLEAN ;
cstring : String ;
clength : CARDINAL ;
cchar : String ;
END ;
literalT = RECORD
name : Name ;
type : node ;
END ;
constT = RECORD
name : Name ;
type : node ;
value: node ;
scope: node ;
END ;
varparamT = RECORD
namelist : node ;
type : node ;
scope : node ;
isUnbounded: BOOLEAN ;
isForC : BOOLEAN ;
isUsed : BOOLEAN ;
END ;
paramT = RECORD
namelist : node ;
type : node ;
scope : node ;
isUnbounded: BOOLEAN ;
isForC : BOOLEAN ;
isUsed : BOOLEAN ;
END ;
varargsT = RECORD
scope : node ;
END ;
optargT = RECORD
namelist : node ;
type : node ;
scope : node ;
init : node ;
END ;
pointerT = RECORD
type : node ;
scope: node ;
END ;
recordfieldT = RECORD
name : Name ;
type : node ;
tag : BOOLEAN ;
parent : node ;
varient: node ;
scope : node ;
cname : cnameT ;
END ;
varientfieldT = RECORD
name : Name ;
parent : node ;
varient : node ;
simple : BOOLEAN ;
listOfSons: Index ;
scope : node ;
END ;
enumerationfieldT = RECORD
name : Name ;
type : node ;
scope: node ;
value: CARDINAL ;
cname: cnameT ;
END ;
setT = RECORD
type : node ;
scope: node ;
END ;
componentrefT = RECORD
rec : node ;
field : node ;
resultType: node ;
END ;
pointerrefT = RECORD
ptr : node ;
field : node ;
resultType: node ;
END ;
arrayrefT = RECORD
array : node ;
index : node ;
resultType: node ;
END ;
commentPair = RECORD
after,
body : node ;
END ;
assignmentT = RECORD
des,
expr : node ;
assignComment: commentPair ;
END ;
ifT = RECORD
expr,
elsif, (* either else or elsif must be NIL. *)
then,
else : node ;
ifComment,
elseComment, (* used for else or elsif *)
endComment : commentPair ;
END ;
elsifT = RECORD
expr,
elsif, (* either else or elsif must be NIL. *)
then,
else : node ;
elseComment: commentPair ; (* used for else or elsif *)
END ;
loopT = RECORD
statements: node ;
labelno : CARDINAL ; (* 0 means no label. *)
END ;
whileT = RECORD
expr,
statements: node ;
doComment,
endComment: commentPair ;
END ;
repeatT = RECORD
expr,
statements : node ;
repeatComment,
untilComment : commentPair ;
END ;
caseT = RECORD
expression : node ;
caseLabelList: Index ;
else : node ;
END ;
caselabellistT = RECORD
caseList : node ;
statements: node ;
END ;
caselistT = RECORD
rangePairs: Index ;
END ;
rangeT = RECORD
lo,
hi: node ;
END ;
forT = RECORD
des,
start,
end,
increment,
statements: node ;
END ;
statementT = RECORD
sequence: Index ;
END ;
scopeT = RECORD
symbols : symbolTree ;
constants,
types,
procedures,
variables : Index ;
END ;
procedureT = RECORD
name : Name ;
decls : scopeT ;
scope : node ;
parameters : Index ;
isForC,
built,
checking,
returnopt,
vararg,
noreturnused,
noreturn : BOOLEAN ;
paramcount : CARDINAL ;
optarg : node ;
returnType : node ;
beginStatements: node ;
cname : cnameT ;
defComment,
modComment : commentDesc ;
END ;
proctypeT = RECORD
parameters: Index ;
returnopt,
vararg : BOOLEAN ;
optarg : node ;
scope : node ;
returnType: node ;
END ;
binaryT = RECORD
left,
right,
resultType: node ;
END ;
unaryT = RECORD
arg,
resultType: node ;
END ;
moduleT = RECORD
name : Name ;
source : Name ;
importedModules : Index ;
constFixup,
enumFixup : fixupInfo ;
decls : scopeT ;
beginStatements,
finallyStatements: node ;
enumsComplete,
constsComplete,
visited : BOOLEAN ;
com : commentPair ;
END ;
defT = RECORD
name : Name ;
source : Name ;
hasHidden,
forC : BOOLEAN ;
exported,
importedModules : Index ;
constFixup,
enumFixup : fixupInfo ;
decls : scopeT ;
enumsComplete,
constsComplete,
visited : BOOLEAN ;
com : commentPair ;
END ;
impT = RECORD
name : Name ;
source : Name ;
importedModules : Index ;
constFixup,
enumFixup : fixupInfo ;
beginStatements,
finallyStatements: node ;
definitionModule : node ;
decls : scopeT ;
enumsComplete,
constsComplete,
visited : BOOLEAN ;
com : commentPair ;
END ;
where = RECORD
defDeclared,
modDeclared,
firstUsed : CARDINAL ;
END ;
outputStates = (text, punct, space) ;
nodeProcedure = PROCEDURE (node) ;
dependentState = (completed, blocked, partial, recursive) ;
cnameT = RECORD
name : Name ;
init : BOOLEAN ;
END ;
VAR
outputFile : File ;
lang : language ;
bitsperunitN,
bitsperwordN,
bitspercharN,
unitsperwordN,
mainModule,
currentModule,
defModule,
systemN,
addressN,
locN,
byteN,
wordN,
csizetN,
cssizetN,
adrN,
sizeN,
tsizeN,
newN,
disposeN,
lengthN,
incN,
decN,
inclN,
exclN,
highN,
m2rtsN,
haltN,
throwN,
chrN,
capN,
absN,
floatN,
truncN,
ordN,
valN,
minN,
maxN,
booleanN,
procN,
charN,
integerN,
cardinalN,
longcardN,
shortcardN,
longintN,
shortintN,
bitsetN,
bitnumN,
ztypeN,
rtypeN,
complexN,
longcomplexN,
shortcomplexN,
cmplxN,
reN,
imN,
realN,
longrealN,
shortrealN,
nilN,
trueN,
falseN : node ;
scopeStack,
defUniverseI,
modUniverseI : Index ;
modUniverse,
defUniverse : symbolTree ;
baseSymbols : symbolTree ;
outputState : outputStates ;
doP : pretty ;
todoQ,
partialQ,
doneQ : alist ;
mustVisitScope,
simplified : BOOLEAN ;
tempCount : CARDINAL ;
(*
newNode - create and return a new node of kind k.
*)
PROCEDURE newNode (k: nodeT) : node ;
VAR
d: node ;
BEGIN
NEW (d) ;
IF enableMemsetOnAllocation
THEN
d := memset (d, 0, SIZE (d^))
END ;
IF d=NIL
THEN
HALT
ELSE
d^.kind := k ;
d^.at.defDeclared := 0 ;
d^.at.modDeclared := 0 ;
d^.at.firstUsed := 0 ;
RETURN d
END
END newNode ;
(*
disposeNode - dispose node, n.
*)
PROCEDURE disposeNode (VAR n: node) ;
BEGIN
DISPOSE (n) ;
n := NIL
END disposeNode ;
(*
getDeclaredDef - returns the token number associated with the nodes declaration
in the definition module.
*)
PROCEDURE getDeclaredDef (n: node) : CARDINAL ;
BEGIN
RETURN n^.at.defDeclared
END getDeclaredDef ;
(*
getDeclaredMod - returns the token number associated with the nodes declaration
in the implementation or program module.
*)
PROCEDURE getDeclaredMod (n: node) : CARDINAL ;
BEGIN
RETURN n^.at.modDeclared
END getDeclaredMod ;
(*
getFirstUsed - returns the token number associated with the first use of
node, n.
*)
PROCEDURE getFirstUsed (n: node) : CARDINAL ;
BEGIN
RETURN n^.at.firstUsed
END getFirstUsed ;
(*
setVisited - set the visited flag on a def/imp/module node.
*)
PROCEDURE setVisited (n: node) ;
BEGIN
CASE n^.kind OF
def : n^.defF.visited := TRUE |
imp : n^.impF.visited := TRUE |
module: n^.moduleF.visited := TRUE
END
END setVisited ;
(*
unsetVisited - unset the visited flag on a def/imp/module node.
*)
PROCEDURE unsetVisited (n: node) ;
BEGIN
CASE n^.kind OF
def : n^.defF.visited := FALSE |
imp : n^.impF.visited := FALSE |
module: n^.moduleF.visited := FALSE
END
END unsetVisited ;
(*
isVisited - returns TRUE if the node was visited.
*)
PROCEDURE isVisited (n: node) : BOOLEAN ;
BEGIN
CASE n^.kind OF
def : RETURN n^.defF.visited |
imp : RETURN n^.impF.visited |
module: RETURN n^.moduleF.visited
END
END isVisited ;
(*
isDef - return TRUE if node, n, is a definition module.
*)
PROCEDURE isDef (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
RETURN n^.kind = def
END isDef ;
(*
isImp - return TRUE if node, n, is an implementation module.
*)
PROCEDURE isImp (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
RETURN n^.kind = imp
END isImp ;
(*
isModule - return TRUE if node, n, is a program module.
*)
PROCEDURE isModule (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
RETURN n^.kind = module
END isModule ;
(*
isImpOrModule - returns TRUE if, n, is a program module or implementation module.
*)
PROCEDURE isImpOrModule (n: node) : BOOLEAN ;
BEGIN
RETURN isImp (n) OR isModule (n)
END isImpOrModule ;
(*
isProcedure - returns TRUE if node, n, is a procedure.
*)
PROCEDURE isProcedure (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
RETURN n^.kind = procedure
END isProcedure ;
(*
isConst - returns TRUE if node, n, is a const.
*)
PROCEDURE isConst (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
RETURN n^.kind = const
END isConst ;
(*
isType - returns TRUE if node, n, is a type.
*)
PROCEDURE isType (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
RETURN n^.kind = type
END isType ;
(*
isVar - returns TRUE if node, n, is a type.
*)
PROCEDURE isVar (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
RETURN n^.kind = var
END isVar ;
(*
isTemporary - returns TRUE if node, n, is a variable and temporary.
*)
PROCEDURE isTemporary (n: node) : BOOLEAN ;
BEGIN
RETURN FALSE
END isTemporary ;
(*
isExported - returns TRUE if symbol, n, is exported from
the definition module.
*)
PROCEDURE isExported (n: node) : BOOLEAN ;
VAR
s: node ;
BEGIN
s := getScope (n) ;
IF s#NIL
THEN
CASE s^.kind OF
def: RETURN IsIndiceInIndex (s^.defF.exported, n)
ELSE
RETURN FALSE
END
END ;
RETURN FALSE
END isExported ;
(*
isLocal - returns TRUE if symbol, n, is locally declared in a procedure.
*)
PROCEDURE isLocal (n: node) : BOOLEAN ;
VAR
s: node ;
BEGIN
s := getScope (n) ;
IF s#NIL
THEN
RETURN isProcedure (s)
END ;
RETURN FALSE
END isLocal ;
(*
lookupExported - attempts to lookup a node named, i, from definition
module, n. The node is returned if found.
NIL is returned if not found.
*)
PROCEDURE lookupExported (n: node; i: Name) : node ;
VAR
r: node ;
BEGIN
assert (isDef (n)) ;
r := getSymKey (n^.defF.decls.symbols, i) ;
IF (r#NIL) AND isExported (r)
THEN
RETURN r
END ;
RETURN NIL
END lookupExported ;
(*
importEnumFields - if, n, is an enumeration type import the all fields into module, m.
*)
PROCEDURE importEnumFields (m, n: node) ;
VAR
r, e: node ;
i, h: CARDINAL ;
BEGIN
assert (isDef (m) OR isModule (m) OR isImp (m)) ;
n := skipType (n) ;
IF (n#NIL) AND isEnumeration (n)
THEN
i := LowIndice (n^.enumerationF.listOfSons) ;
h := HighIndice (n^.enumerationF.listOfSons) ;
WHILE i<=h DO
e := GetIndice (n^.enumerationF.listOfSons, i) ;
r := import (m, e) ;
IF e#r
THEN
metaError2 ('enumeration field {%1ad} cannot be imported implicitly into {%2d} due to a name clash',
e, m)
END ;
INC (i)
END
END
END importEnumFields ;
(*
import - attempts to add node, n, into the scope of module, m.
It might fail due to a name clash in which case the
previous named symbol is returned. On success, n,
is returned.
*)
PROCEDURE import (m, n: node) : node ;
VAR
name: Name ;
r : node ;
BEGIN
assert (isDef (m) OR isModule (m) OR isImp (m)) ;
name := getSymName (n) ;
r := lookupInScope (m, name) ;
IF r=NIL
THEN
CASE m^.kind OF
def : putSymKey (m^.defF.decls.symbols, name, n) |
imp : putSymKey (m^.impF.decls.symbols, name, n) |
module: putSymKey (m^.moduleF.decls.symbols, name, n)
END ;
importEnumFields (m, n) ;
RETURN n
END ;
RETURN r
END import ;
(*
isZtype - returns TRUE if, n, is the Z type.
*)
PROCEDURE isZtype (n: node) : BOOLEAN ;
BEGIN
RETURN n = ztypeN
END isZtype ;
(*
isRtype - returns TRUE if, n, is the R type.
*)
PROCEDURE isRtype (n: node) : BOOLEAN ;
BEGIN
RETURN n = rtypeN
END isRtype ;
(*
isComplex - returns TRUE if, n, is the complex type.
*)
PROCEDURE isComplex (n: node) : BOOLEAN ;
BEGIN
RETURN n = complexN
END isComplex ;
(*
isLongComplex - returns TRUE if, n, is the longcomplex type.
*)
PROCEDURE isLongComplex (n: node) : BOOLEAN ;
BEGIN
RETURN n = longcomplexN
END isLongComplex ;
(*
isShortComplex - returns TRUE if, n, is the shortcomplex type.
*)
PROCEDURE isShortComplex (n: node) : BOOLEAN ;
BEGIN
RETURN n = shortcomplexN
END isShortComplex ;
(*
isLiteral - returns TRUE if, n, is a literal.
*)
PROCEDURE isLiteral (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = literal
END isLiteral ;
(*
isConstSet - returns TRUE if, n, is a constant set.
*)
PROCEDURE isConstSet (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
IF isLiteral (n) OR isConst (n)
THEN
RETURN isSet (skipType (getType (n)))
END ;
RETURN FALSE
END isConstSet ;
(*
isEnumerationField - returns TRUE if, n, is an enumeration field.
*)
PROCEDURE isEnumerationField (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = enumerationfield
END isEnumerationField ;
(*
isUnbounded - returns TRUE if, n, is an unbounded array.
*)
PROCEDURE isUnbounded (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN (n^.kind = array) AND (n^.arrayF.isUnbounded)
END isUnbounded ;
(*
isParameter - returns TRUE if, n, is a parameter.
*)
PROCEDURE isParameter (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN (n^.kind = param) OR (n^.kind = varparam)
END isParameter ;
(*
isVarParam - returns TRUE if, n, is a var parameter.
*)
PROCEDURE isVarParam (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = varparam
END isVarParam ;
(*
isParam - returns TRUE if, n, is a non var parameter.
*)
PROCEDURE isParam (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = param
END isParam ;
(*
isNonVarParam - is an alias to isParam.
*)
PROCEDURE isNonVarParam (n: node) : BOOLEAN ;
BEGIN
RETURN isParam (n)
END isNonVarParam ;
(*
isRecord - returns TRUE if, n, is a record.
*)
PROCEDURE isRecord (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = record
END isRecord ;
(*
isRecordField - returns TRUE if, n, is a record field.
*)
PROCEDURE isRecordField (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = recordfield
END isRecordField ;
(*
isArray - returns TRUE if, n, is an array.
*)
PROCEDURE isArray (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = array
END isArray ;
(*
isProcType - returns TRUE if, n, is a procedure type.
*)
PROCEDURE isProcType (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = proctype
END isProcType ;
(*
isAProcType - returns TRUE if, n, is a proctype or proc node.
*)
PROCEDURE isAProcType (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN isProcType (n) OR (n = procN)
END isAProcType ;
(*
isProcedure - returns TRUE if, n, is a procedure.
*)
PROCEDURE isProcedure (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = procedure
END isProcedure ;
(*
isPointer - returns TRUE if, n, is a pointer.
*)
PROCEDURE isPointer (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = pointer
END isPointer ;
(*
isVarient - returns TRUE if, n, is a varient record.
*)
PROCEDURE isVarient (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = varient
END isVarient ;
(*
isVarientField - returns TRUE if, n, is a varient field.
*)
PROCEDURE isVarientField (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = varientfield
END isVarientField ;
(*
isSet - returns TRUE if, n, is a set type.
*)
PROCEDURE isSet (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = set
END isSet ;
(*
isSubrange - returns TRUE if, n, is a subrange type.
*)
PROCEDURE isSubrange (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = subrange
END isSubrange ;
(*
isMainModule - return TRUE if node, n, is the main module specified
by the source file. This might be a definition,
implementation or program module.
*)
PROCEDURE isMainModule (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
RETURN n = mainModule
END isMainModule ;
(*
setMainModule - sets node, n, as the main module to be compiled.
*)
PROCEDURE setMainModule (n: node) ;
BEGIN
assert (n#NIL) ;
mainModule := n
END setMainModule ;
(*
getMainModule - returns the main module node.
*)
PROCEDURE getMainModule () : node ;
BEGIN
RETURN mainModule
END getMainModule ;
(*
setCurrentModule - sets node, n, as the current module being compiled.
*)
PROCEDURE setCurrentModule (n: node) ;
BEGIN
assert (n#NIL) ;
currentModule := n
END setCurrentModule ;
(*
getCurrentModule - returns the current module being compiled.
*)
PROCEDURE getCurrentModule () : node ;
BEGIN
RETURN currentModule
END getCurrentModule ;
(*
initFixupInfo - initialize the fixupInfo record.
*)
PROCEDURE initFixupInfo () : fixupInfo ;
VAR
f: fixupInfo ;
BEGIN
f.count := 0 ;
f.info := InitIndex (1) ;
RETURN f
END initFixupInfo ;
(*
makeDef - returns a definition module node named, n.
*)
PROCEDURE makeDef (n: Name) : node ;
VAR
d: node ;
BEGIN
d := newNode (def) ;
WITH d^ DO
defF.name := n ;
defF.source := NulName ;
defF.hasHidden := FALSE ;
defF.forC := FALSE ;
defF.exported := InitIndex (1) ;
defF.importedModules := InitIndex (1) ;
defF.constFixup := initFixupInfo () ;
defF.enumFixup := initFixupInfo () ;
initDecls (defF.decls) ;
defF.enumsComplete := FALSE ;
defF.constsComplete := FALSE ;
defF.visited := FALSE ;
initPair (defF.com)
END ;
RETURN d
END makeDef ;
(*
makeImp - returns an implementation module node named, n.
*)
PROCEDURE makeImp (n: Name) : node ;
VAR
d: node ;
BEGIN
d := newNode (imp) ;
WITH d^ DO
impF.name := n ;
impF.source := NulName ;
impF.importedModules := InitIndex (1) ;
impF.constFixup := initFixupInfo () ;
impF.enumFixup := initFixupInfo () ;
initDecls (impF.decls) ;
impF.beginStatements := NIL ;
impF.finallyStatements := NIL ;
impF.definitionModule := NIL ;
impF.enumsComplete := FALSE ;
impF.constsComplete := FALSE ;
impF.visited := FALSE ;
initPair (impF.com)
END ;
RETURN d
END makeImp ;
(*
makeModule - returns a module node named, n.
*)
PROCEDURE makeModule (n: Name) : node ;
VAR
d: node ;
BEGIN
d := newNode (module) ;
WITH d^ DO
moduleF.name := n ;
moduleF.source := NulName ;
moduleF.importedModules := InitIndex (1) ;
moduleF.constFixup := initFixupInfo () ;
moduleF.enumFixup := initFixupInfo () ;
initDecls (moduleF.decls) ;
moduleF.beginStatements := NIL ;
moduleF.finallyStatements := NIL ;
moduleF.enumsComplete := FALSE ;
moduleF.constsComplete := FALSE ;
moduleF.visited := FALSE ;
initPair (moduleF.com)
END ;
RETURN d
END makeModule ;
(*
putDefForC - the definition module was defined FOR "C".
*)
PROCEDURE putDefForC (n: node) ;
BEGIN
assert (isDef (n)) ;
n^.defF.forC := TRUE
END putDefForC ;
(*
isDefForC - returns TRUE if the definition module was defined FOR "C".
*)
PROCEDURE isDefForC (n: node) : BOOLEAN ;
BEGIN
RETURN isDef (n) AND n^.defF.forC
END isDefForC ;
(*
lookupDef - returns a definition module node named, n.
*)
PROCEDURE lookupDef (n: Name) : node ;
VAR
d: node ;
BEGIN
d := getSymKey (defUniverse, n) ;
IF d=NIL
THEN
d := makeDef (n) ;
putSymKey (defUniverse, n, d) ;
IncludeIndiceIntoIndex (defUniverseI, d)
END ;
RETURN d
END lookupDef ;
(*
lookupImp - returns an implementation module node named, n.
*)
PROCEDURE lookupImp (n: Name) : node ;
VAR
m: node ;
BEGIN
m := getSymKey (modUniverse, n) ;
IF m=NIL
THEN
m := makeImp (n) ;
putSymKey (modUniverse, n, m) ;
IncludeIndiceIntoIndex (modUniverseI, m)
END ;
assert (NOT isModule (m)) ;
RETURN m
END lookupImp ;
(*
lookupModule - returns a module node named, n.
*)
PROCEDURE lookupModule (n: Name) : node ;
VAR
m: node ;
BEGIN
m := getSymKey (modUniverse, n) ;
IF m=NIL
THEN
m := makeModule (n) ;
putSymKey (modUniverse, n, m) ;
IncludeIndiceIntoIndex (modUniverseI, m)
END ;
assert (NOT isImp (m)) ;
RETURN m
END lookupModule ;
(*
setSource - sets the source filename for module, n, to s.
*)
PROCEDURE setSource (n: node; s: Name) ;
BEGIN
WITH n^ DO
CASE kind OF
def : defF.source := s |
module: moduleF.source := s |
imp : impF.source := s
END
END
END setSource ;
(*
getSource - returns the source filename for module, n.
*)
PROCEDURE getSource (n: node) : Name ;
BEGIN
WITH n^ DO
CASE kind OF
def : RETURN defF.source |
module: RETURN moduleF.source |
imp : RETURN impF.source
END
END
END getSource ;
(*
initDecls - initialize the decls, scopeT.
*)
PROCEDURE initDecls (VAR decls: scopeT) ;
BEGIN
decls.symbols := initTree () ;
decls.constants := InitIndex (1) ;
decls.types := InitIndex (1) ;
decls.procedures := InitIndex (1) ;
decls.variables := InitIndex (1)
END initDecls ;
(*
enterScope - pushes symbol, n, to the scope stack.
*)
PROCEDURE enterScope (n: node) ;
BEGIN
IF IsIndiceInIndex (scopeStack, n)
THEN
HALT
ELSE
IncludeIndiceIntoIndex (scopeStack, n)
END ;
IF debugScopes
THEN
printf ("enter scope\n") ;
dumpScopes
END
END enterScope ;
(*
leaveScope - removes the top level scope.
*)
PROCEDURE leaveScope ;
VAR
i: CARDINAL ;
n: node ;
BEGIN
i := HighIndice (scopeStack) ;
n := GetIndice (scopeStack, i) ;
RemoveIndiceFromIndex (scopeStack, n) ;
IF debugScopes
THEN
printf ("leave scope\n") ;
dumpScopes
END
END leaveScope ;
(*
getDeclScope - returns the node representing the
current declaration scope.
*)
PROCEDURE getDeclScope () : node ;
VAR
i: CARDINAL ;
BEGIN
i := HighIndice (scopeStack) ;
RETURN GetIndice (scopeStack, i)
END getDeclScope ;
(*
addTo - adds node, d, to scope decls and returns, d.
It stores, d, in the symbols tree associated with decls.
*)
PROCEDURE addTo (VAR decls: scopeT; d: node) : node ;
VAR
n: Name ;
BEGIN
n := getSymName (d) ;
IF n#NulName
THEN
IF getSymKey (decls.symbols, n)=NIL
THEN
putSymKey (decls.symbols, n, d)
ELSE
metaError1 ('{%1DMad} was declared', d) ;
metaError1 ('{%1k} and is being declared again', n)
END
END ;
IF isConst (d)
THEN
IncludeIndiceIntoIndex (decls.constants, d)
ELSIF isVar (d)
THEN
IncludeIndiceIntoIndex (decls.variables, d)
ELSIF isType (d)
THEN
IncludeIndiceIntoIndex (decls.types, d)
ELSIF isProcedure (d)
THEN
IncludeIndiceIntoIndex (decls.procedures, d) ;
IF debugDecl
THEN
printf ("%d procedures on the dynamic array\n",
HighIndice (decls.procedures))
END
END ;
RETURN d
END addTo ;
(*
export - export node, n, from definition module, d.
*)
PROCEDURE export (d, n: node) ;
BEGIN
assert (isDef (d)) ;
IncludeIndiceIntoIndex (d^.defF.exported, n)
END export ;
(*
addToScope - adds node, n, to the current scope and returns, n.
*)
PROCEDURE addToScope (n: node) : node ;
VAR
s: node ;
i: CARDINAL ;
BEGIN
i := HighIndice (scopeStack) ;
s := GetIndice (scopeStack, i) ;
IF isProcedure (s)
THEN
IF debugDecl
THEN
outText (doP, "adding ") ;
doNameC (doP, n) ;
outText (doP, " to procedure\n")
END ;
RETURN addTo (s^.procedureF.decls, n)
ELSIF isModule (s)
THEN
IF debugDecl
THEN
outText (doP, "adding ") ;
doNameC (doP, n) ;
outText (doP, " to module\n")
END ;
RETURN addTo (s^.moduleF.decls, n)
ELSIF isDef (s)
THEN
IF debugDecl
THEN
outText (doP, "adding ") ;
doNameC (doP, n) ;
outText (doP, " to definition module\n")
END ;
export (s, n) ;
RETURN addTo (s^.defF.decls, n)
ELSIF isImp (s)
THEN
IF debugDecl
THEN
outText (doP, "adding ") ;
doNameC (doP, n) ;
outText (doP, " to implementation module\n")
END ;
RETURN addTo (s^.impF.decls, n)
END ;
HALT
END addToScope ;
(*
addModuleToScope - adds module, i, to module, m, scope.
*)
PROCEDURE addModuleToScope (m, i: node) ;
BEGIN
assert (getDeclScope () = m) ;
IF lookupSym (getSymName (i))=NIL
THEN
i := addToScope (i)
END
END addModuleToScope ;
(*
addImportedModule - add module, i, to be imported by, m.
If scoped then module, i, is added to the
module, m, scope.
*)
PROCEDURE addImportedModule (m, i: node; scoped: BOOLEAN) ;
BEGIN
assert (isDef (i) OR isModule (i)) ;
IF isDef (m)
THEN
IncludeIndiceIntoIndex (m^.defF.importedModules, i)
ELSIF isImp (m)
THEN
IncludeIndiceIntoIndex (m^.impF.importedModules, i)
ELSIF isModule (m)
THEN
IncludeIndiceIntoIndex (m^.moduleF.importedModules, i)
ELSE
HALT
END ;
IF scoped
THEN
addModuleToScope (m, i)
END
END addImportedModule ;
(*
completedEnum - assign boolean enumsComplete to TRUE if a definition,
implementation or module symbol.
*)
PROCEDURE completedEnum (n: node) ;
BEGIN
assert (isDef (n) OR isImp (n) OR isModule (n)) ;
IF isDef (n)
THEN
n^.defF.enumsComplete := TRUE
ELSIF isImp (n)
THEN
n^.impF.enumsComplete := TRUE
ELSIF isModule (n)
THEN
n^.moduleF.enumsComplete := TRUE
END
END completedEnum ;
(*
setUnary - sets a unary node to contain, arg, a, and type, t.
*)
PROCEDURE setUnary (u: node; k: nodeT; a, t: node) ;
BEGIN
CASE k OF
constexp,
deref,
chr,
cap,
abs,
float,
trunc,
ord,
high,
throw,
re,
im,
not,
neg,
adr,
size,
tsize,
min,
max : u^.kind := k ;
u^.unaryF.arg := a ;
u^.unaryF.resultType := t
END
END setUnary ;
(*
makeConst - create, initialise and return a const node.
*)
PROCEDURE makeConst (n: Name) : node ;
VAR
d: node ;
BEGIN
d := newNode (const) ;
WITH d^ DO
constF.name := n ;
constF.type := NIL ;
constF.scope := getDeclScope () ;
constF.value := NIL
END ;
RETURN addToScope (d)
END makeConst ;
(*
makeType - create, initialise and return a type node.
*)
PROCEDURE makeType (n: Name) : node ;
VAR
d: node ;
BEGIN
d := newNode (type) ;
WITH d^ DO
typeF.name := n ;
typeF.type := NIL ;
typeF.scope := getDeclScope () ;
typeF.isHidden := FALSE ;
typeF.isInternal := FALSE
END ;
RETURN addToScope (d)
END makeType ;
(*
makeTypeImp - lookup a type in the definition module
and return it. Otherwise create a new type.
*)
PROCEDURE makeTypeImp (n: Name) : node ;
VAR
d: node ;
BEGIN
d := lookupSym (n) ;
IF d#NIL
THEN
d^.typeF.isHidden := FALSE ;
RETURN addToScope (d)
ELSE
d := newNode (type) ;
WITH d^ DO
typeF.name := n ;
typeF.type := NIL ;
typeF.scope := getDeclScope () ;
typeF.isHidden := FALSE
END ;
RETURN addToScope (d)
END
END makeTypeImp ;
(*
makeVar - create, initialise and return a var node.
*)
PROCEDURE makeVar (n: Name) : node ;
VAR
d: node ;
BEGIN
d := newNode (var) ;
WITH d^ DO
varF.name := n ;
varF.type := NIL ;
varF.decl := NIL ;
varF.scope := getDeclScope () ;
varF.isInitialised := FALSE ;
varF.isParameter := FALSE ;
varF.isVarParameter := FALSE ;
initCname (varF.cname)
END ;
RETURN addToScope (d)
END makeVar ;
(*
putVar - places, type, as the type for var.
*)
PROCEDURE putVar (var, type, decl: node) ;
BEGIN
assert (var#NIL) ;
assert (isVar (var)) ;
var^.varF.type := type ;
var^.varF.decl := decl
END putVar ;
(*
putVarBool - assigns the four booleans associated with a variable.
*)
PROCEDURE putVarBool (v: node; init, param, isvar, isused: BOOLEAN) ;
BEGIN
assert (isVar (v)) ;
v^.varF.isInitialised := init ;
v^.varF.isParameter := param ;
v^.varF.isVarParameter := isvar ;
v^.varF.isUsed := isused
END putVarBool ;
(*
checkPtr - in C++ we need to create a typedef for a pointer
in case we need to use reinterpret_cast.
*)
PROCEDURE checkPtr (n: node) : node ;
VAR
s: String ;
p: node ;
BEGIN
IF lang = ansiCP
THEN
IF isPointer (n)
THEN
s := tempName () ;
p := makeType (makekey (DynamicStrings.string (s))) ;
putType (p, n) ;
s := KillString (s) ;
RETURN p
END
END ;
RETURN n
END checkPtr ;
(*
makeVarDecl - create a vardecl node and create a shadow variable in the
current scope.
*)
PROCEDURE makeVarDecl (i: node; type: node) : node ;
VAR
d, v: node ;
j, n: CARDINAL ;
BEGIN
type := checkPtr (type) ;
d := newNode (vardecl) ;
WITH d^ DO
vardeclF.names := i^.identlistF.names ;
vardeclF.type := type ;
vardeclF.scope := getDeclScope ()
END ;
n := wlists.noOfItemsInList (d^.vardeclF.names) ;
j := 1 ;
WHILE j<=n DO
v := lookupSym (wlists.getItemFromList (d^.vardeclF.names, j)) ;
assert (isVar (v)) ;
putVar (v, type, d) ;
INC (j)
END ;
RETURN d
END makeVarDecl ;
(*
isVarDecl - returns TRUE if, n, is a vardecl node.
*)
PROCEDURE isVarDecl (n: node) : BOOLEAN ;
BEGIN
RETURN n^.kind = vardecl
END isVarDecl ;
(*
makeVariablesFromParameters - creates variables which are really parameters.
*)
PROCEDURE makeVariablesFromParameters (proc, id, type: node; isvar, isused: BOOLEAN) ;
VAR
v : node ;
i, n: CARDINAL ;
m : Name ;
s : String ;
BEGIN
assert (isProcedure (proc)) ;
assert (isIdentList (id)) ;
i := 1 ;
n := wlists.noOfItemsInList (id^.identlistF.names) ;
WHILE i<=n DO
m := wlists.getItemFromList (id^.identlistF.names, i) ;
v := makeVar (m) ;
putVar (v, type, NIL) ;
putVarBool (v, TRUE, TRUE, isvar, isused) ;
IF debugScopes
THEN
printf ("adding parameter variable into top scope\n") ;
dumpScopes ;
printf (" variable name is: ") ;
s := InitStringCharStar (keyToCharStar (m)) ;
IF KillString (WriteS (StdOut, s))=NIL
THEN
END ;
printf ("\n")
END ;
INC (i)
END
END makeVariablesFromParameters ;
(*
addProcedureToScope - add a procedure name n and node d to the
current scope.
*)
PROCEDURE addProcedureToScope (d: node; n: Name) : node ;
VAR
m: node ;
i: CARDINAL ;
BEGIN
i := HighIndice (scopeStack) ;
m := GetIndice (scopeStack, i) ;
IF isDef (m) AND
(getSymName (m) = makeKey ('M2RTS')) AND
(getSymName (d) = makeKey ('HALT'))
THEN
haltN := d ;
putSymKey (baseSymbols, n, haltN)
END ;
RETURN addToScope (d)
END addProcedureToScope ;
(*
makeProcedure - create, initialise and return a procedure node.
*)
PROCEDURE makeProcedure (n: Name) : node ;
VAR
d: node ;
BEGIN
d := lookupSym (n) ;
IF d=NIL
THEN
d := newNode (procedure) ;
WITH d^ DO
procedureF.name := n ;
initDecls (procedureF.decls) ;
procedureF.scope := getDeclScope () ;
procedureF.parameters := InitIndex (1) ;
procedureF.isForC := isDefForCNode (getDeclScope ()) ;
procedureF.built := FALSE ;
procedureF.returnopt := FALSE ;
procedureF.optarg := NIL ;
procedureF.noreturnused := FALSE ;
procedureF.noreturn := FALSE ;
procedureF.vararg := FALSE ;
procedureF.checking := FALSE ;
procedureF.paramcount := 0 ;
procedureF.returnType := NIL ;
procedureF.beginStatements := NIL ;
initCname (procedureF.cname) ;
procedureF.defComment := NIL ;
procedureF.modComment := NIL ;
END
END ;
RETURN addProcedureToScope (d, n)
END makeProcedure ;
(*
putCommentDefProcedure - remembers the procedure comment (if it exists) as a
definition module procedure heading. NIL is placed
if there is no procedure comment available.
*)
PROCEDURE putCommentDefProcedure (n: node) ;
BEGIN
assert (isProcedure (n)) ;
IF isProcedureComment (lastcomment)
THEN
n^.procedureF.defComment := lastcomment
END
END putCommentDefProcedure ;
(*
putCommentModProcedure - remembers the procedure comment (if it exists) as an
implementation/program module procedure heading. NIL is placed
if there is no procedure comment available.
*)
PROCEDURE putCommentModProcedure (n: node) ;
BEGIN
assert (isProcedure (n)) ;
IF isProcedureComment (lastcomment)
THEN
n^.procedureF.modComment := lastcomment
END
END putCommentModProcedure ;
(*
paramEnter - reset the parameter count.
*)
PROCEDURE paramEnter (n: node) ;
BEGIN
assert (isProcedure (n)) ;
n^.procedureF.paramcount := 0
END paramEnter ;
(*
paramLeave - set paramater checking to TRUE from now onwards.
*)
PROCEDURE paramLeave (n: node) ;
BEGIN
assert (isProcedure (n)) ;
n^.procedureF.checking := TRUE ;
IF isImp (currentModule) OR isModule (currentModule)
THEN
n^.procedureF.built := TRUE
END
END paramLeave ;
(*
putReturnType - sets the return type of procedure or proctype, proc, to, type.
*)
PROCEDURE putReturnType (proc, type: node) ;
BEGIN
assert (isProcedure (proc) OR isProcType (proc)) ;
IF isProcedure (proc)
THEN
proc^.procedureF.returnType := type
ELSE
proc^.proctypeF.returnType := type
END
END putReturnType ;
(*
putOptReturn - sets, proctype or procedure, proc, to have an optional return type.
*)
PROCEDURE putOptReturn (proc: node) ;
BEGIN
assert (isProcedure (proc) OR isProcType (proc)) ;
IF isProcedure (proc)
THEN
proc^.procedureF.returnopt := TRUE
ELSE
proc^.proctypeF.returnopt := TRUE
END
END putOptReturn ;
(*
makeProcType - returns a proctype node.
*)
PROCEDURE makeProcType () : node ;
VAR
d: node ;
BEGIN
d := newNode (proctype) ;
WITH d^ DO
proctypeF.scope := getDeclScope () ;
proctypeF.parameters := InitIndex (1) ;
proctypeF.returnopt := FALSE ;
proctypeF.optarg := NIL ;
proctypeF.vararg := FALSE ;
proctypeF.returnType := NIL
END ;
RETURN d
END makeProcType ;
(*
putProcTypeReturn - sets the return type of, proc, to, type.
*)
PROCEDURE putProcTypeReturn (proc, type: node) ;
BEGIN
assert (isProcType (proc)) ;
proc^.proctypeF.returnType := type
END putProcTypeReturn ;
(*
putProcTypeOptReturn - sets, proc, to have an optional return type.
*)
PROCEDURE putProcTypeOptReturn (proc: node) ;
BEGIN
assert (isProcType (proc)) ;
proc^.proctypeF.returnopt := TRUE
END putProcTypeOptReturn ;
(*
makeNonVarParameter - returns a non var parameter node with, name: type.
*)
PROCEDURE makeNonVarParameter (l: node; type, proc: node; isused: BOOLEAN) : node ;
VAR
d: node ;
BEGIN
assert ((l=NIL) OR isIdentList (l)) ;
d := newNode (param) ;
d^.paramF.namelist := l ;
d^.paramF.type := type ;
d^.paramF.scope := proc ;
d^.paramF.isUnbounded := FALSE ;
d^.paramF.isForC := isDefForCNode (proc) ;
d^.paramF.isUsed := isused ;
RETURN d
END makeNonVarParameter ;
(*
makeVarParameter - returns a var parameter node with, name: type.
*)
PROCEDURE makeVarParameter (l: node; type, proc: node; isused: BOOLEAN) : node ;
VAR
d: node ;
BEGIN
assert ((l=NIL) OR isIdentList (l)) ;
d := newNode (varparam) ;
d^.varparamF.namelist := l ;
d^.varparamF.type := type ;
d^.varparamF.scope := proc ;
d^.varparamF.isUnbounded := FALSE ;
d^.varparamF.isForC := isDefForCNode (proc) ;
d^.varparamF.isUsed := isused ;
RETURN d
END makeVarParameter ;
(*
makeVarargs - returns a varargs node.
*)
PROCEDURE makeVarargs () : node ;
VAR
d: node ;
BEGIN
d := newNode (varargs) ;
d^.varargsF.scope := NIL ;
RETURN d
END makeVarargs ;
(*
isVarargs - returns TRUE if, n, is a varargs node.
*)
PROCEDURE isVarargs (n: node) : BOOLEAN ;
BEGIN
RETURN n^.kind = varargs
END isVarargs ;
(*
addParameter - adds a parameter, param, to procedure or proctype, proc.
*)
PROCEDURE addParameter (proc, param: node) ;
BEGIN
assert (isVarargs (param) OR isParam (param) OR isVarParam (param) OR isOptarg (param)) ;
CASE proc^.kind OF
procedure: IncludeIndiceIntoIndex (proc^.procedureF.parameters, param) ;
IF isVarargs (param)
THEN
proc^.procedureF.vararg := TRUE
END ;
IF isOptarg (param)
THEN
proc^.procedureF.optarg := param
END |
proctype : IncludeIndiceIntoIndex (proc^.proctypeF.parameters, param) ;
IF isVarargs (param)
THEN
proc^.proctypeF.vararg := TRUE
END ;
IF isOptarg (param)
THEN
proc^.proctypeF.optarg := param
END
END
END addParameter ;
(*
isOptarg - returns TRUE if, n, is an optarg.
*)
PROCEDURE isOptarg (n: node) : BOOLEAN ;
BEGIN
RETURN n^.kind = optarg
END isOptarg ;
(*
makeOptParameter - creates and returns an optarg.
*)
PROCEDURE makeOptParameter (l, type, init: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (optarg) ;
n^.optargF.namelist := l ;
n^.optargF.type := type ;
n^.optargF.init := init ;
n^.optargF.scope := NIL ;
RETURN n
END makeOptParameter ;
(*
addOptParameter - returns an optarg which has been created and added to
procedure node, proc. It has a name, id, and, type,
and an initial value, init.
*)
PROCEDURE addOptParameter (proc: node; id: Name; type, init: node) : node ;
VAR
p, l: node ;
BEGIN
assert (isProcedure (proc)) ;
l := makeIdentList () ;
assert (putIdent (l, id)) ;
checkMakeVariables (proc, l, type, FALSE, TRUE) ;
IF NOT proc^.procedureF.checking
THEN
p := makeOptParameter (l, type, init) ;
addParameter (proc, p)
END ;
RETURN p
END addOptParameter ;
VAR
globalNode: node ;
(*
setwatch - assign the globalNode to n.
*)
PROCEDURE setwatch (n: node) : BOOLEAN ;
BEGIN
globalNode := n ;
RETURN TRUE
END setwatch ;
(*
runwatch - set the globalNode to an identlist.
*)
PROCEDURE runwatch () : BOOLEAN ;
BEGIN
RETURN globalNode^.kind = identlist
END runwatch ;
(*
makeIdentList - returns a node which will be used to maintain an ident list.
*)
PROCEDURE makeIdentList () : node ;
VAR
n: node ;
BEGIN
n := newNode (identlist) ;
n^.identlistF.names := wlists.initList () ;
n^.identlistF.cnamed := FALSE ;
RETURN n
END makeIdentList ;
(*
isIdentList - returns TRUE if, n, is an identlist.
*)
PROCEDURE isIdentList (n: node) : BOOLEAN ;
BEGIN
RETURN n^.kind = identlist
END isIdentList ;
(*
putIdent - places ident, i, into identlist, n. It returns TRUE if
ident, i, is unique.
*)
PROCEDURE putIdent (n: node; i: Name) : BOOLEAN ;
BEGIN
assert (isIdentList (n)) ;
IF wlists.isItemInList (n^.identlistF.names, i)
THEN
RETURN FALSE
ELSE
wlists.putItemIntoList (n^.identlistF.names, i) ;
RETURN TRUE
END
END putIdent ;
(*
identListLen - returns the length of identlist.
*)
PROCEDURE identListLen (n: node) : CARDINAL ;
BEGIN
IF n=NIL
THEN
RETURN 0
ELSE
assert (isIdentList (n)) ;
RETURN wlists.noOfItemsInList (n^.identlistF.names)
END
END identListLen ;
(*
checkParameters - placeholder for future parameter checking.
*)
PROCEDURE checkParameters (p: node; i: node; type: node; isvar, isused: BOOLEAN) ;
BEGIN
(* do check. *)
disposeNode (i)
END checkParameters ;
(*
(*
avoidCnames - checks each name in, n, against C reserved
keywords and macros.
*)
PROCEDURE avoidCnames (n: node) ;
VAR
i, j: CARDINAL ;
BEGIN
assert (isIdentList (n)) ;
IF NOT n^.identlistF.cnamed
THEN
n^.identlistF.cnamed := TRUE ;
j := wlists.noOfItemsInList (n^.identlistF.names) ;
i := 1 ;
WHILE i<=j DO
wlists.replaceItemInList (n^.identlistF.names,
i,
keyc.cnamen (wlists.getItemFromList (n^.identlistF.names, i), FALSE)) ;
INC (i)
END
END
END avoidCnames ;
*)
(*
checkMakeVariables - create shadow local variables for parameters providing that
procedure n has not already been built and we are compiling
a module or an implementation module.
*)
PROCEDURE checkMakeVariables (n, i, type: node; isvar, isused: BOOLEAN) ;
BEGIN
IF (isImp (currentModule) OR isModule (currentModule)) AND
(NOT n^.procedureF.built)
THEN
makeVariablesFromParameters (n, i, type, isvar, isused)
END ;
END checkMakeVariables ;
(*
addVarParameters - adds the identlist, i, of, type, to be VAR parameters
in procedure, n.
*)
PROCEDURE addVarParameters (n: node; i: node; type: node; isused: BOOLEAN) ;
VAR
p: node ;
BEGIN
assert (isIdentList (i)) ;
assert (isProcedure (n)) ;
checkMakeVariables (n, i, type, TRUE, isused) ;
IF n^.procedureF.checking
THEN
checkParameters (n, i, type, TRUE, isused) (* will destroy, i. *)
ELSE
p := makeVarParameter (i, type, n, isused) ;
IncludeIndiceIntoIndex (n^.procedureF.parameters, p) ;
END ;
END addVarParameters ;
(*
addNonVarParameters - adds the identlist, i, of, type, to be parameters
in procedure, n.
*)
PROCEDURE addNonVarParameters (n: node; i: node; type: node; isused: BOOLEAN) ;
VAR
p: node ;
BEGIN
assert (isIdentList (i)) ;
assert (isProcedure (n)) ;
checkMakeVariables (n, i, type, FALSE, isused) ;
IF n^.procedureF.checking
THEN
checkParameters (n, i, type, FALSE, isused) (* will destroy, i. *)
ELSE
p := makeNonVarParameter (i, type, n, isused) ;
IncludeIndiceIntoIndex (n^.procedureF.parameters, p)
END ;
END addNonVarParameters ;
(*
makeSubrange - returns a subrange node, built from range: low..high.
*)
PROCEDURE makeSubrange (low, high: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (subrange) ;
n^.subrangeF.low := low ;
n^.subrangeF.high := high ;
n^.subrangeF.type := NIL ;
n^.subrangeF.scope := getDeclScope () ;
RETURN n
END makeSubrange ;
(*
putSubrangeType - assigns, type, to the subrange type, sub.
*)
PROCEDURE putSubrangeType (sub, type: node) ;
BEGIN
assert (isSubrange (sub)) ;
sub^.subrangeF.type := type
END putSubrangeType ;
(*
makeSet - returns a set of, type, node.
*)
PROCEDURE makeSet (type: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (set) ;
n^.setF.type := type ;
n^.setF.scope := getDeclScope () ;
RETURN n
END makeSet ;
(*
makeSetValue - creates and returns a setvalue node.
*)
PROCEDURE makeSetValue () : node ;
VAR
n: node ;
BEGIN
n := newNode (setvalue) ;
n^.setvalueF.type := bitsetN ;
n^.setvalueF.values := InitIndex (1) ;
RETURN n
END makeSetValue ;
(*
isSetValue - returns TRUE if, n, is a setvalue node.
*)
PROCEDURE isSetValue (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = setvalue
END isSetValue ;
(*
putSetValue - assigns the type, t, to the set value, n. The
node, n, is returned.
*)
PROCEDURE putSetValue (n, t: node) : node ;
BEGIN
assert (isSetValue (n)) ;
n^.setvalueF.type := t ;
RETURN n
END putSetValue ;
(*
includeSetValue - includes the range l..h into the setvalue.
h might be NIL indicating that a single element
is to be included into the set.
n is returned.
*)
PROCEDURE includeSetValue (n: node; l, h: node) : node ;
BEGIN
assert (isSetValue (n)) ;
IncludeIndiceIntoIndex (n^.setvalueF.values, l) ;
RETURN n
END includeSetValue ;
(*
makePointer - returns a pointer of, type, node.
*)
PROCEDURE makePointer (type: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (pointer) ;
n^.pointerF.type := type ;
n^.pointerF.scope := getDeclScope () ;
RETURN n
END makePointer ;
(*
makeArray - returns a node representing ARRAY subr OF type.
*)
PROCEDURE makeArray (subr, type: node) : node ;
VAR
n, s: node ;
BEGIN
s := skipType (subr) ;
assert (isSubrange (s) OR isOrdinal (s) OR isEnumeration (s)) ;
n := newNode (array) ;
n^.arrayF.subr := subr ;
n^.arrayF.type := type ;
n^.arrayF.scope := getDeclScope () ;
n^.arrayF.isUnbounded := FALSE ;
RETURN n
END makeArray ;
(*
makeRecord - creates and returns a record node.
*)
PROCEDURE makeRecord () : node ;
VAR
n: node ;
BEGIN
n := newNode (record) ;
n^.recordF.localSymbols := initTree () ;
n^.recordF.listOfSons := InitIndex (1) ;
n^.recordF.scope := getDeclScope () ;
RETURN n
END makeRecord ;
(*
addFieldsToRecord - adds fields, i, of type, t, into a record, r.
It returns, r.
*)
PROCEDURE addFieldsToRecord (r, v, i, t: node) : node ;
VAR
p, fj: node ;
j, n : CARDINAL ;
fn : Name ;
BEGIN
IF isRecord (r)
THEN
p := r ;
v := NIL
ELSE
p := getRecord (getParent (r)) ;
assert (isVarientField (r)) ;
assert (isVarient (v)) ;
putFieldVarient (r, v)
END ;
n := wlists.noOfItemsInList (i^.identlistF.names) ;
j := 1 ;
WHILE j<=n DO
fn := wlists.getItemFromList (i^.identlistF.names, j) ;
fj := getSymKey (p^.recordF.localSymbols, n) ;
IF fj=NIL
THEN
fj := putFieldRecord (r, fn, t, v)
ELSE
metaErrors2 ('record field {%1ad} has already been declared inside a {%2Dd} {%2a}',
'attempting to declare a duplicate record field', fj, p)
END ;
INC (j)
END ;
RETURN r;
END addFieldsToRecord ;
(*
makeVarient - creates a new symbol, a varient symbol for record or varient field
symbol, r.
*)
PROCEDURE makeVarient (r: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (varient) ;
WITH n^ DO
varientF.listOfSons := InitIndex (1) ;
(* do we need to remember our parent (r) ? *)
(* if so use this n^.varientF.parent := r *)
IF isRecord (r)
THEN
varientF.varient := NIL
ELSE
varientF.varient := r
END ;
varientF.tag := NIL ;
varientF.scope := getDeclScope () ;
END ;
(* now add, n, to the record/varient, r, field list *)
WITH r^ DO
CASE kind OF
record : IncludeIndiceIntoIndex (recordF.listOfSons, n) |
varientfield: IncludeIndiceIntoIndex (varientfieldF.listOfSons, n)
END
END ;
RETURN n
END makeVarient ;
(*
buildVarientFieldRecord - builds a varient field into a varient symbol, v.
The varient field is returned.
*)
PROCEDURE buildVarientFieldRecord (v: node; p: node) : node ;
VAR
f: node ;
BEGIN
assert (isVarient (v)) ;
f := makeVarientField (v, p) ;
assert (isVarientField (f)) ;
putFieldVarient (f, v) ;
RETURN f
END buildVarientFieldRecord ;
(*
makeVarientField - create a varient field within varient, v,
The new varient field is returned.
*)
PROCEDURE makeVarientField (v: node; p: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (varientfield) ;
WITH n^.varientfieldF DO
name := NulName ;
parent := p ;
varient := v ;
simple := FALSE ;
listOfSons := InitIndex (1) ;
scope := getDeclScope ()
END ;
RETURN n
END makeVarientField ;
(*
putFieldVarient - places the field varient, f, as a brother to, the
varient symbol, v, and also tells, f, that its varient
parent is, v.
*)
PROCEDURE putFieldVarient (f, v: node) ;
BEGIN
assert (isVarient (v)) ;
assert (isVarientField (f)) ;
WITH v^ DO
CASE kind OF
varient: IncludeIndiceIntoIndex (varientF.listOfSons, f)
END
END ;
WITH f^ DO
CASE kind OF
varientfield: varientfieldF.varient := v
END
END
END putFieldVarient ;
(*
putFieldRecord - create a new recordfield and place it into record r.
The new field has a tagname and type and can have a
variant field v.
*)
PROCEDURE putFieldRecord (r: node; tag: Name; type, v: node) : node ;
VAR
f, n, p: node ;
BEGIN
n := newNode (recordfield) ;
WITH r^ DO
CASE kind OF
record: IncludeIndiceIntoIndex (recordF.listOfSons, n) ;
(* ensure that field, n, is in the parents Local Symbols. *)
IF tag#NulName
THEN
IF getSymKey (recordF.localSymbols, tag) = NulKey
THEN
putSymKey (recordF.localSymbols, tag, n)
ELSE
f := getSymKey (recordF.localSymbols, tag) ;
metaErrors1 ('field record {%1Dad} has already been declared',
'field record duplicate', f)
END
END |
varientfield: IncludeIndiceIntoIndex (varientfieldF.listOfSons, n) ;
p := getParent (r) ;
assert (p^.kind=record) ;
IF tag#NulName
THEN
putSymKey (p^.recordF.localSymbols, tag, n)
END
END
END ;
(* fill in, n. *)
n^.recordfieldF.type := type ;
n^.recordfieldF.name := tag ;
n^.recordfieldF.parent := r ;
n^.recordfieldF.varient := v ;
n^.recordfieldF.tag := FALSE ;
n^.recordfieldF.scope := NIL ;
initCname (n^.recordfieldF.cname) ;
(*
IF r^.kind=record
THEN
doRecordM2 (doP, r)
END ;
*)
RETURN n
END putFieldRecord ;
(*
buildVarientSelector - builds a field of name, tag, of, type onto:
record or varient field, r.
varient, v.
*)
PROCEDURE buildVarientSelector (r, v: node; tag: Name; type: node) ;
VAR
f: node ;
BEGIN
assert (isRecord (r) OR isVarientField (r)) ;
IF isRecord (r) OR isVarientField (r)
THEN
IF (type=NIL) AND (tag=NulName)
THEN
metaError1 ('expecting a tag field in the declaration of a varient record {%1Ua}', r)
ELSIF type=NIL
THEN
f := lookupSym (tag) ;
putVarientTag (v, f)
ELSE
f := putFieldRecord (r, tag, type, v) ;
assert (isRecordField (f)) ;
f^.recordfieldF.tag := TRUE ;
putVarientTag (v, f)
END
END
END buildVarientSelector ;
(*
ensureOrder - ensures that, a, and, b, exist in, i, and also
ensure that, a, is before, b.
*)
PROCEDURE ensureOrder (i: Index; a, b: node) ;
BEGIN
assert (IsIndiceInIndex (i, a)) ;
assert (IsIndiceInIndex (i, b)) ;
RemoveIndiceFromIndex (i, a) ;
RemoveIndiceFromIndex (i, b) ;
IncludeIndiceIntoIndex (i, a) ;
IncludeIndiceIntoIndex (i, b) ;
assert (IsIndiceInIndex (i, a)) ;
assert (IsIndiceInIndex (i, b))
END ensureOrder ;
(*
putVarientTag - places tag into variant v.
*)
PROCEDURE putVarientTag (v: node; tag: node) ;
VAR
p: node ;
BEGIN
assert (isVarient (v)) ;
CASE v^.kind OF
varient: v^.varientF.tag := tag
END
END putVarientTag ;
(*
getParent - returns the parent field of recordfield or varientfield symbol, n.
*)
PROCEDURE getParent (n: node) : node ;
BEGIN
CASE n^.kind OF
recordfield: RETURN n^.recordfieldF.parent |
varientfield: RETURN n^.varientfieldF.parent
END
END getParent ;
(*
getRecord - returns the record associated with node, n.
(Parental record).
*)
PROCEDURE getRecord (n: node) : node ;
BEGIN
assert (n^.kind # varient) ; (* if this fails then we need to add parent field to varient. *)
CASE n^.kind OF
record : RETURN n |
varientfield: RETURN getRecord (getParent (n))
END
END getRecord ;
(*
putUnbounded - sets array, n, as unbounded.
*)
PROCEDURE putUnbounded (n: node) ;
BEGIN
assert (n^.kind = array) ;
n^.arrayF.isUnbounded := TRUE
END putUnbounded ;
(*
isConstExp - return TRUE if the node kind is a constexp.
*)
PROCEDURE isConstExp (c: node) : BOOLEAN ;
BEGIN
assert (c#NIL) ;
RETURN c^.kind = constexp
END isConstExp ;
(*
addEnumToModule - adds enumeration type, e, into the list of enums
in module, m.
*)
PROCEDURE addEnumToModule (m, e: node) ;
BEGIN
assert (isEnumeration (e) OR isEnumerationField (e)) ;
assert (isModule (m) OR isDef (m) OR isImp (m)) ;
IF isModule (m)
THEN
IncludeIndiceIntoIndex (m^.moduleF.enumFixup.info, e)
ELSIF isDef (m)
THEN
IncludeIndiceIntoIndex (m^.defF.enumFixup.info, e)
ELSIF isImp (m)
THEN
IncludeIndiceIntoIndex (m^.impF.enumFixup.info, e)
END
END addEnumToModule ;
(*
getNextFixup - return the next fixup from from f.
*)
PROCEDURE getNextFixup (VAR f: fixupInfo) : node ;
BEGIN
INC (f.count) ;
RETURN GetIndice (f.info, f.count)
END getNextFixup ;
(*
getNextEnum - returns the next enumeration node.
*)
PROCEDURE getNextEnum () : node ;
VAR
n: node ;
BEGIN
n := NIL ;
assert (isDef (currentModule) OR isImp (currentModule) OR isModule (currentModule)) ;
WITH currentModule^ DO
IF isDef (currentModule)
THEN
n := getNextFixup (defF.enumFixup)
ELSIF isImp (currentModule)
THEN
n := getNextFixup (impF.enumFixup)
ELSIF isModule (currentModule)
THEN
n := getNextFixup (moduleF.enumFixup)
END
END ;
assert (n # NIL) ;
assert (isEnumeration (n) OR isEnumerationField (n)) ;
RETURN n
END getNextEnum ;
(*
resetEnumPos - resets the index into the saved list of enums inside
module, n.
*)
PROCEDURE resetEnumPos (n: node) ;
BEGIN
assert (isDef (n) OR isImp (n) OR isModule (n)) ;
IF isDef (n)
THEN
n^.defF.enumFixup.count := 0
ELSIF isImp (n)
THEN
n^.impF.enumFixup.count := 0
ELSIF isModule (n)
THEN
n^.moduleF.enumFixup.count := 0
END
END resetEnumPos ;
(*
getEnumsComplete - gets the field from the def or imp or module, n.
*)
PROCEDURE getEnumsComplete (n: node) : BOOLEAN ;
BEGIN
CASE n^.kind OF
def : RETURN n^.defF.enumsComplete |
imp : RETURN n^.impF.enumsComplete |
module: RETURN n^.moduleF.enumsComplete
END
END getEnumsComplete ;
(*
setEnumsComplete - sets the field inside the def or imp or module, n.
*)
PROCEDURE setEnumsComplete (n: node) ;
BEGIN
CASE n^.kind OF
def : n^.defF.enumsComplete := TRUE |
imp : n^.impF.enumsComplete := TRUE |
module: n^.moduleF.enumsComplete := TRUE
END
END setEnumsComplete ;
(*
doMakeEnum - create an enumeration type and add it to the current module.
*)
PROCEDURE doMakeEnum () : node ;
VAR
e: node ;
BEGIN
e := newNode (enumeration) ;
WITH e^ DO
enumerationF.noOfElements := 0 ;
enumerationF.localSymbols := initTree () ;
enumerationF.scope := getDeclScope () ;
enumerationF.listOfSons := InitIndex (1) ;
enumerationF.low := NIL ;
enumerationF.high := NIL ;
END ;
addEnumToModule (currentModule, e) ;
RETURN e
END doMakeEnum ;
(*
makeEnum - creates an enumerated type and returns the node.
*)
PROCEDURE makeEnum () : node ;
BEGIN
IF (currentModule#NIL) AND getEnumsComplete (currentModule)
THEN
RETURN getNextEnum ()
ELSE
RETURN doMakeEnum ()
END
END makeEnum ;
(*
doMakeEnumField - create an enumeration field name and add it to enumeration e.
Return the new field.
*)
PROCEDURE doMakeEnumField (e: node; n: Name) : node ;
VAR
f: node ;
BEGIN
assert (isEnumeration (e)) ;
f := lookupSym (n) ;
IF f=NIL
THEN
f := newNode (enumerationfield) ;
putSymKey (e^.enumerationF.localSymbols, n, f) ;
IncludeIndiceIntoIndex (e^.enumerationF.listOfSons, f) ;
WITH f^ DO
enumerationfieldF.name := n ;
enumerationfieldF.type := e ;
enumerationfieldF.scope := getDeclScope () ;
enumerationfieldF.value := e^.enumerationF.noOfElements ;
initCname (enumerationfieldF.cname)
END ;
INC (e^.enumerationF.noOfElements) ;
assert (GetIndice (e^.enumerationF.listOfSons, e^.enumerationF.noOfElements) = f) ;
addEnumToModule (currentModule, f) ;
IF e^.enumerationF.low = NIL
THEN
e^.enumerationF.low := f
END ;
e^.enumerationF.high := f ;
RETURN addToScope (f)
ELSE
metaErrors2 ('cannot create enumeration field {%1k} as the name is already in use',
'{%2DMad} was declared elsewhere', n, f)
END ;
RETURN f
END doMakeEnumField ;
(*
makeEnumField - returns an enumeration field, named, n.
*)
PROCEDURE makeEnumField (e: node; n: Name) : node ;
BEGIN
IF (currentModule#NIL) AND getEnumsComplete (currentModule)
THEN
RETURN getNextEnum ()
ELSE
RETURN doMakeEnumField (e, n)
END
END makeEnumField ;
(*
isEnumeration - returns TRUE if node, n, is an enumeration type.
*)
PROCEDURE isEnumeration (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
RETURN n^.kind = enumeration
END isEnumeration ;
(*
makeExpList - creates and returns an expList node.
*)
PROCEDURE makeExpList () : node ;
VAR
n: node ;
BEGIN
n := newNode (explist) ;
n^.explistF.exp := InitIndex (1) ;
RETURN n
END makeExpList ;
(*
isExpList - returns TRUE if, n, is an explist node.
*)
PROCEDURE isExpList (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = explist
END isExpList ;
(*
putExpList - places, expression, e, within the explist, n.
*)
PROCEDURE putExpList (n: node; e: node) ;
BEGIN
assert (n # NIL) ;
assert (isExpList (n)) ;
PutIndice (n^.explistF.exp, HighIndice (n^.explistF.exp) + 1, e)
END putExpList ;
(*
getExpList - returns the, n, th argument in an explist.
*)
PROCEDURE getExpList (p: node; n: CARDINAL) : node ;
BEGIN
assert (p#NIL) ;
assert (isExpList (p)) ;
assert (n <= HighIndice (p^.explistF.exp)) ;
RETURN GetIndice (p^.explistF.exp, n)
END getExpList ;
(*
expListLen - returns the length of explist, p.
*)
PROCEDURE expListLen (p: node) : CARDINAL ;
BEGIN
IF p = NIL
THEN
RETURN 0
ELSE
assert (isExpList (p)) ;
RETURN HighIndice (p^.explistF.exp)
END
END expListLen ;
(*
getConstExpComplete - gets the field from the def or imp or module, n.
*)
PROCEDURE getConstExpComplete (n: node) : BOOLEAN ;
BEGIN
CASE n^.kind OF
def : RETURN n^.defF.constsComplete |
imp : RETURN n^.impF.constsComplete |
module: RETURN n^.moduleF.constsComplete
END
END getConstExpComplete ;
(*
setConstExpComplete - sets the field inside the def or imp or module, n.
*)
PROCEDURE setConstExpComplete (n: node) ;
BEGIN
CASE n^.kind OF
def : n^.defF.constsComplete := TRUE |
imp : n^.impF.constsComplete := TRUE |
module: n^.moduleF.constsComplete := TRUE
END
END setConstExpComplete ;
(*
getNextConstExp - returns the next constexp node.
*)
PROCEDURE getNextConstExp () : node ;
VAR
n: node ;
BEGIN
assert (isDef (currentModule) OR isImp (currentModule) OR isModule (currentModule)) ;
WITH currentModule^ DO
IF isDef (currentModule)
THEN
RETURN getNextFixup (defF.constFixup)
ELSIF isImp (currentModule)
THEN
RETURN getNextFixup (impF.constFixup)
ELSIF isModule (currentModule)
THEN
RETURN getNextFixup (moduleF.constFixup)
END
END ;
RETURN n
END getNextConstExp ;
(*
resetConstExpPos - resets the index into the saved list of constexps inside
module, n.
*)
PROCEDURE resetConstExpPos (n: node) ;
BEGIN
assert (isDef (n) OR isImp (n) OR isModule (n)) ;
IF isDef (n)
THEN
n^.defF.constFixup.count := 0
ELSIF isImp (n)
THEN
n^.impF.constFixup.count := 0
ELSIF isModule (n)
THEN
n^.moduleF.constFixup.count := 0
END
END resetConstExpPos ;
(*
addConstToModule - adds const exp, e, into the list of constant
expressions in module, m.
*)
PROCEDURE addConstToModule (m, e: node) ;
BEGIN
assert (isModule (m) OR isDef (m) OR isImp (m)) ;
IF isModule (m)
THEN
IncludeIndiceIntoIndex (m^.moduleF.constFixup.info, e)
ELSIF isDef (m)
THEN
IncludeIndiceIntoIndex (m^.defF.constFixup.info, e)
ELSIF isImp (m)
THEN
IncludeIndiceIntoIndex (m^.impF.constFixup.info, e)
END
END addConstToModule ;
(*
doMakeConstExp - create a constexp node and add it to the current module.
*)
PROCEDURE doMakeConstExp () : node ;
VAR
c: node ;
BEGIN
c := makeUnary (constexp, NIL, NIL) ;
addConstToModule (currentModule, c) ;
RETURN c
END doMakeConstExp ;
(*
makeConstExp - returns a constexp node.
*)
PROCEDURE makeConstExp () : node ;
BEGIN
IF (currentModule#NIL) AND getConstExpComplete (currentModule)
THEN
RETURN getNextConstExp ()
ELSE
RETURN doMakeConstExp ()
END
END makeConstExp ;
(*
fixupConstExp - assign fixup expression, e, into the argument of, c.
*)
PROCEDURE fixupConstExp (c, e: node) : node ;
BEGIN
assert (isConstExp (c)) ;
c^.unaryF.arg := e ;
RETURN c
END fixupConstExp ;
(*
isAnyType - return TRUE if node n is any type kind.
*)
PROCEDURE isAnyType (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
CASE n^.kind OF
address,
loc,
byte,
word,
char,
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
complex,
longcomplex,
shortcomplex,
bitset,
boolean,
proc,
type : RETURN TRUE
ELSE
RETURN FALSE
END
END isAnyType ;
(*
makeVal - creates a VAL (type, expression) node.
*)
PROCEDURE makeVal (params: node) : node ;
BEGIN
assert (isExpList (params)) ;
IF expListLen (params) = 2
THEN
RETURN makeBinary (val,
getExpList (params, 1),
getExpList (params, 2),
getExpList (params, 1))
ELSE
HALT
END
END makeVal ;
(*
makeCast - creates a cast node TYPENAME (expr).
*)
PROCEDURE makeCast (c, p: node) : node ;
BEGIN
assert (isExpList (p)) ;
IF expListLen (p) = 1
THEN
RETURN makeBinary (cast, c, getExpList (p, 1), c)
ELSE
HALT
END
END makeCast ;
(*
makeIntrisicProc - create an intrinsic node.
*)
PROCEDURE makeIntrinsicProc (k: nodeT; noArgs: CARDINAL; p: node) : node ;
VAR
f: node ;
BEGIN
f := newNode (k) ;
f^.intrinsicF.args := p ;
f^.intrinsicF.noArgs := noArgs ;
f^.intrinsicF.type := NIL ;
f^.intrinsicF.postUnreachable := (k = halt) ;
initPair (f^.intrinsicF.intrinsicComment) ;
RETURN f
END makeIntrinsicProc ;
(*
makeIntrinsicUnaryType - create an intrisic unary type.
*)
PROCEDURE makeIntrinsicUnaryType (k: nodeT; paramList: node; returnType: node) : node ;
BEGIN
RETURN makeUnary (k, getExpList (paramList, 1), returnType)
END makeIntrinsicUnaryType ;
(*
makeIntrinsicBinaryType - create an intrisic binary type.
*)
PROCEDURE makeIntrinsicBinaryType (k: nodeT; paramList: node; returnType: node) : node ;
BEGIN
RETURN makeBinary (k, getExpList (paramList, 1), getExpList (paramList, 2), returnType)
END makeIntrinsicBinaryType ;
(*
checkIntrinsic - checks to see if the function call to, c, with
parameter list, n, is really an intrinic. If it
is an intrinic then an intrinic node is created
and returned. Otherwise NIL is returned.
*)
PROCEDURE checkIntrinsic (c, n: node) : node ;
BEGIN
IF isAnyType (c)
THEN
RETURN makeCast (c, n)
ELSIF c = maxN
THEN
RETURN makeIntrinsicUnaryType (max, n, NIL)
ELSIF c = minN
THEN
RETURN makeIntrinsicUnaryType (min, n, NIL)
ELSIF c = haltN
THEN
RETURN makeIntrinsicProc (halt, expListLen (n), n)
ELSIF c = valN
THEN
RETURN makeVal (n)
ELSIF c = adrN
THEN
RETURN makeIntrinsicUnaryType (adr, n, addressN)
ELSIF c = sizeN
THEN
RETURN makeIntrinsicUnaryType (size, n, cardinalN)
ELSIF c = tsizeN
THEN
RETURN makeIntrinsicUnaryType (tsize, n, cardinalN)
ELSIF c = floatN
THEN
RETURN makeIntrinsicUnaryType (float, n, realN)
ELSIF c = truncN
THEN
RETURN makeIntrinsicUnaryType (trunc, n, integerN)
ELSIF c = ordN
THEN
RETURN makeIntrinsicUnaryType (ord, n, cardinalN)
ELSIF c = chrN
THEN
RETURN makeIntrinsicUnaryType (chr, n, charN)
ELSIF c = capN
THEN
RETURN makeIntrinsicUnaryType (cap, n, charN)
ELSIF c = absN
THEN
RETURN makeIntrinsicUnaryType (abs, n, NIL)
ELSIF c = imN
THEN
RETURN makeIntrinsicUnaryType (im, n, NIL)
ELSIF c = reN
THEN
RETURN makeIntrinsicUnaryType (re, n, NIL)
ELSIF c = cmplxN
THEN
RETURN makeIntrinsicBinaryType (cmplx, n, NIL)
ELSIF c = highN
THEN
RETURN makeIntrinsicUnaryType (high, n, cardinalN)
ELSIF c = incN
THEN
RETURN makeIntrinsicProc (inc, expListLen (n), n)
ELSIF c = decN
THEN
RETURN makeIntrinsicProc (dec, expListLen (n), n)
ELSIF c = inclN
THEN
RETURN makeIntrinsicProc (incl, expListLen (n), n)
ELSIF c = exclN
THEN
RETURN makeIntrinsicProc (excl, expListLen (n), n)
ELSIF c = newN
THEN
RETURN makeIntrinsicProc (new, 1, n)
ELSIF c = disposeN
THEN
RETURN makeIntrinsicProc (dispose, 1, n)
ELSIF c = lengthN
THEN
RETURN makeIntrinsicUnaryType (length, n, cardinalN)
ELSIF c = throwN
THEN
keyc.useThrow ;
RETURN makeIntrinsicProc (throw, 1, n)
END ;
RETURN NIL
END checkIntrinsic ;
(*
checkCHeaders - check to see if the function is a C system function and
requires a header file included.
*)
PROCEDURE checkCHeaders (c: node) ;
VAR
name: Name ;
s : node ;
BEGIN
IF isProcedure (c)
THEN
s := getScope (c) ;
IF getSymName (s) = makeKey ('libc')
THEN
name := getSymName (c) ;
IF (name = makeKey ('read')) OR
(name = makeKey ('write')) OR
(name = makeKey ('open')) OR
(name = makeKey ('close'))
THEN
keyc.useUnistd
END
END
END
END checkCHeaders ;
(*
makeFuncCall - builds a function call to c with param list, n.
*)
PROCEDURE makeFuncCall (c, n: node) : node ;
VAR
f: node ;
BEGIN
assert ((n=NIL) OR isExpList (n)) ;
IF (c = haltN) AND
(getMainModule () # lookupDef (makeKey ('M2RTS'))) AND
(getMainModule () # lookupImp (makeKey ('M2RTS')))
THEN
addImportedModule (getMainModule (), lookupDef (makeKey ('M2RTS')), FALSE)
END ;
f := checkIntrinsic (c, n) ;
checkCHeaders (c) ;
IF f = NIL
THEN
f := newNode (funccall) ;
f^.funccallF.function := c ;
f^.funccallF.args := n ;
f^.funccallF.type := NIL ;
initPair (f^.funccallF.funccallComment)
END ;
RETURN f
END makeFuncCall ;
(*
isFuncCall - returns TRUE if, n, is a function/procedure call.
*)
PROCEDURE isFuncCall (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = funccall
END isFuncCall ;
(*
putType - places, exp, as the type alias to des.
TYPE des = exp ;
*)
PROCEDURE putType (des, exp: node) ;
BEGIN
assert (des#NIL) ;
assert (isType (des)) ;
des^.typeF.type := exp
END putType ;
(*
putTypeHidden - marks type, des, as being a hidden type.
TYPE des ;
*)
PROCEDURE putTypeHidden (des: node) ;
VAR
s: node ;
BEGIN
assert (des#NIL) ;
assert (isType (des)) ;
des^.typeF.isHidden := TRUE ;
s := getScope (des) ;
assert (isDef (s)) ;
s^.defF.hasHidden := TRUE
END putTypeHidden ;
(*
isTypeHidden - returns TRUE if type, n, is hidden.
*)
PROCEDURE isTypeHidden (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
assert (isType (n)) ;
RETURN n^.typeF.isHidden
END isTypeHidden ;
(*
hasHidden - returns TRUE if module, n, has a hidden type.
*)
PROCEDURE hasHidden (n: node) : BOOLEAN ;
BEGIN
assert (isDef (n)) ;
RETURN n^.defF.hasHidden
END hasHidden ;
(*
putTypeInternal - marks type, des, as being an internally generated type.
*)
PROCEDURE putTypeInternal (des: node) ;
BEGIN
assert (des#NIL) ;
assert (isType (des)) ;
des^.typeF.isInternal := TRUE
END putTypeInternal ;
(*
isTypeInternal - returns TRUE if type, n, is internal.
*)
PROCEDURE isTypeInternal (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
assert (isType (n)) ;
RETURN n^.typeF.isInternal
END isTypeInternal ;
(*
putConst - places value, v, into node, n.
*)
PROCEDURE putConst (n: node; v: node) ;
BEGIN
assert (isConst (n)) ;
n^.constF.value := v
END putConst ;
(*
makeLiteralInt - creates and returns a literal node based on an integer type.
*)
PROCEDURE makeLiteralInt (n: Name) : node ;
VAR
m: node ;
s: String ;
BEGIN
m := newNode (literal) ;
s := InitStringCharStar (keyToCharStar (n)) ;
WITH m^ DO
literalF.name := n ;
IF DynamicStrings.char (s, -1)='C'
THEN
literalF.type := charN
ELSE
literalF.type := ztypeN
END
END ;
s := KillString (s) ;
RETURN m
END makeLiteralInt ;
(*
makeLiteralReal - creates and returns a literal node based on a real type.
*)
PROCEDURE makeLiteralReal (n: Name) : node ;
VAR
m: node ;
BEGIN
m := newNode (literal) ;
WITH m^ DO
literalF.name := n ;
literalF.type := rtypeN
END ;
RETURN m
END makeLiteralReal ;
(*
makeString - creates and returns a node containing string, n.
*)
PROCEDURE makeString (n: Name) : node ;
VAR
m: node ;
BEGIN
m := newNode (string) ;
WITH m^ DO
stringF.name := n ;
stringF.length := lengthKey (n) ;
stringF.isCharCompatible := (stringF.length <= 3) ;
stringF.cstring := toCstring (n) ;
stringF.clength := lenCstring (stringF.cstring) ;
IF stringF.isCharCompatible
THEN
stringF.cchar := toCchar (n)
ELSE
stringF.cchar := NIL
END
END ;
RETURN m
END makeString ;
(*
getBuiltinConst - creates and returns a builtin const if available.
*)
PROCEDURE getBuiltinConst (n: Name) : node ;
BEGIN
IF n=makeKey ('BITS_PER_UNIT')
THEN
RETURN bitsperunitN
ELSIF n=makeKey ('BITS_PER_WORD')
THEN
RETURN bitsperwordN
ELSIF n=makeKey ('BITS_PER_CHAR')
THEN
RETURN bitspercharN
ELSIF n=makeKey ('UNITS_PER_WORD')
THEN
RETURN unitsperwordN
ELSE
RETURN NIL
END
END getBuiltinConst ;
(*
lookupInScope - looks up a symbol named, n, from, scope.
*)
PROCEDURE lookupInScope (scope: node; n: Name) : node ;
BEGIN
CASE scope^.kind OF
def : RETURN getSymKey (scope^.defF.decls.symbols, n) |
module : RETURN getSymKey (scope^.moduleF.decls.symbols, n) |
imp : RETURN getSymKey (scope^.impF.decls.symbols, n) |
procedure: RETURN getSymKey (scope^.procedureF.decls.symbols, n) |
record : RETURN getSymKey (scope^.recordF.localSymbols, n)
END
END lookupInScope ;
(*
lookupBase - return node named n from the base symbol scope.
*)
PROCEDURE lookupBase (n: Name) : node ;
VAR
m: node ;
BEGIN
m := getSymKey (baseSymbols, n) ;
IF m=procN
THEN
keyc.useProc
ELSIF (m=complexN) OR (m=longcomplexN) OR (m=shortcomplexN)
THEN
keyc.useComplex
END ;
RETURN m
END lookupBase ;
(*
dumpScopes - display the names of all the scopes stacked.
*)
PROCEDURE dumpScopes ;
VAR
h: CARDINAL ;
s: node ;
BEGIN
h := HighIndice (scopeStack) ;
printf ("total scopes stacked %d\n", h);
WHILE h>=1 DO
s := GetIndice (scopeStack, h) ;
out2 (" scope [%d] is %s\n", h, s) ;
DEC (h)
END
END dumpScopes ;
(*
out0 - write string a to StdOut.
*)
PROCEDURE out0 (a: ARRAY OF CHAR) ;
VAR
m: String ;
BEGIN
m := Sprintf0 (InitString (a)) ;
m := KillString (WriteS (StdOut, m))
END out0 ;
(*
out1 - write string a to StdOut using format specifier a.
*)
PROCEDURE out1 (a: ARRAY OF CHAR; s: node) ;
VAR
m: String ;
d: CARDINAL ;
BEGIN
m := getFQstring (s) ;
IF EqualArray (m, '')
THEN
d := VAL (CARDINAL, VAL (LONGCARD, s)) ;
m := KillString (m) ;
m := Sprintf1 (InitString ('[%d]'), d)
END ;
m := Sprintf1 (InitString (a), m) ;
m := KillString (WriteS (StdOut, m))
END out1 ;
(*
out2 - write string a to StdOut using format specifier a.
*)
PROCEDURE out2 (a: ARRAY OF CHAR; c: CARDINAL; s: node) ;
VAR
m, m1: String ;
BEGIN
m1 := getString (s) ;
m := Sprintf2 (InitString (a), c, m1) ;
m := KillString (WriteS (StdOut, m)) ;
m1 := KillString (m1)
END out2 ;
(*
out3 - write string a to StdOut using format specifier a.
*)
PROCEDURE out3 (a: ARRAY OF CHAR; l: CARDINAL; n: Name; s: node) ;
VAR
m, m1, m2: String ;
BEGIN
m1 := InitStringCharStar (keyToCharStar (n)) ;
m2 := getString (s) ;
m := Sprintf3 (InitString (a), l, m1, m2) ;
m := KillString (WriteS (StdOut, m)) ;
m1 := KillString (m1) ;
m2 := KillString (m2)
END out3 ;
(*
lookupSym - returns the symbol named, n, from the scope stack.
*)
PROCEDURE lookupSym (n: Name) : node ;
VAR
s, m: node ;
l, h: CARDINAL ;
BEGIN
l := LowIndice (scopeStack) ;
h := HighIndice (scopeStack) ;
WHILE h>=l DO
s := GetIndice (scopeStack, h) ;
m := lookupInScope (s, n) ;
IF debugScopes AND (m=NIL)
THEN
out3 (" [%d] search for symbol name %s in scope %s\n", h, n, s)
END ;
IF m#NIL
THEN
IF debugScopes
THEN
out3 (" [%d] search for symbol name %s in scope %s (found)\n", h, n, s)
END ;
RETURN m
END ;
DEC (h)
END ;
RETURN lookupBase (n)
END lookupSym ;
(*
getSymName - returns the name of symbol, n.
*)
PROCEDURE getSymName (n: node) : Name ;
BEGIN
WITH n^ DO
CASE kind OF
new : RETURN makeKey ('NEW') |
dispose : RETURN makeKey ('DISPOSE') |
length : RETURN makeKey ('LENGTH') |
inc : RETURN makeKey ('INC') |
dec : RETURN makeKey ('DEC') |
incl : RETURN makeKey ('INCL') |
excl : RETURN makeKey ('EXCL') |
nil : RETURN makeKey ('NIL') |
true : RETURN makeKey ('TRUE') |
false : RETURN makeKey ('FALSE') |
address : RETURN makeKey ('ADDRESS') |
loc : RETURN makeKey ('LOC') |
byte : RETURN makeKey ('BYTE') |
word : RETURN makeKey ('WORD') |
csizet : RETURN makeKey ('CSIZE_T') |
cssizet : RETURN makeKey ('CSSIZE_T') |
(* base types. *)
boolean : RETURN makeKey ('BOOLEAN') |
proc : RETURN makeKey ('PROC') |
char : RETURN makeKey ('CHAR') |
cardinal : RETURN makeKey ('CARDINAL') |
longcard : RETURN makeKey ('LONGCARD') |
shortcard : RETURN makeKey ('SHORTCARD') |
integer : RETURN makeKey ('INTEGER') |
longint : RETURN makeKey ('LONGINT') |
shortint : RETURN makeKey ('SHORTINT') |
real : RETURN makeKey ('REAL') |
longreal : RETURN makeKey ('LONGREAL') |
shortreal : RETURN makeKey ('SHORTREAL') |
bitset : RETURN makeKey ('BITSET') |
ztype : RETURN makeKey ('_ZTYPE') |
rtype : RETURN makeKey ('_RTYPE') |
complex : RETURN makeKey ('COMPLEX') |
longcomplex : RETURN makeKey ('LONGCOMPLEX') |
shortcomplex : RETURN makeKey ('SHORTCOMPLEX') |
(* language features and compound type attributes. *)
type : RETURN typeF.name |
record : RETURN NulName |
varient : RETURN NulName |
var : RETURN varF.name |
enumeration : RETURN NulName |
subrange : RETURN NulName |
pointer : RETURN NulName |
array : RETURN NulName |
string : RETURN stringF.name |
const : RETURN constF.name |
literal : RETURN literalF.name |
varparam : RETURN NulName |
param : RETURN NulName |
optarg : RETURN NulName |
recordfield : RETURN recordfieldF.name |
varientfield : RETURN varientfieldF.name |
enumerationfield: RETURN enumerationfieldF.name |
set : RETURN NulName |
proctype : RETURN NulName |
subscript : RETURN NulName |
(* blocks. *)
procedure : RETURN procedureF.name |
def : RETURN defF.name |
imp : RETURN impF.name |
module : RETURN moduleF.name |
(* statements. *)
loop,
while,
for,
repeat,
if,
elsif,
assignment : RETURN NulName |
(* expressions. *)
constexp,
deref,
arrayref,
componentref,
cast,
val,
plus,
sub,
div,
mod,
mult,
divide,
in,
neg,
equal,
notequal,
less,
greater,
greequal,
lessequal : RETURN NulName |
adr : RETURN makeKey ('ADR') |
size : RETURN makeKey ('SIZE') |
tsize : RETURN makeKey ('TSIZE') |
chr : RETURN makeKey ('CHR') |
abs : RETURN makeKey ('ABS') |
ord : RETURN makeKey ('ORD') |
float : RETURN makeKey ('FLOAT') |
trunc : RETURN makeKey ('TRUNC') |
high : RETURN makeKey ('HIGH') |
throw : RETURN makeKey ('THROW') |
unreachable : RETURN makeKey ('builtin_unreachable') |
cmplx : RETURN makeKey ('CMPLX') |
re : RETURN makeKey ('RE') |
im : RETURN makeKey ('IM') |
max : RETURN makeKey ('MAX') |
min : RETURN makeKey ('MIN') |
funccall : RETURN NulName |
identlist : RETURN NulName
ELSE
HALT
END
END
END getSymName ;
(*
isUnary - returns TRUE if, n, is an unary node.
*)
PROCEDURE isUnary (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
CASE n^.kind OF
length,
re,
im,
deref,
high,
chr,
cap,
abs,
ord,
float,
trunc,
constexp,
not,
neg,
adr,
size,
tsize,
min,
max : RETURN TRUE
ELSE
RETURN FALSE
END
END isUnary ;
(*
isBinary - returns TRUE if, n, is an binary node.
*)
PROCEDURE isBinary (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
CASE n^.kind OF
cmplx,
and,
or,
equal,
notequal,
less,
greater,
greequal,
lessequal,
val,
cast,
plus,
sub,
div,
mod,
mult,
divide,
in : RETURN TRUE
ELSE
RETURN FALSE
END
END isBinary ;
(*
makeUnary - create a unary expression node with, e, as the argument
and res as the return type.
*)
PROCEDURE makeUnary (k: nodeT; e: node; res: node) : node ;
VAR
n: node ;
BEGIN
IF k=plus
THEN
RETURN e
ELSE
n := newNode (k) ;
WITH n^ DO
CASE kind OF
min,
max,
throw,
re,
im,
deref,
high,
chr,
cap,
abs,
ord,
float,
trunc,
length,
constexp,
not,
neg,
adr,
size,
tsize: WITH unaryF DO
arg := e ;
resultType := res
END
END
END
END ;
RETURN n
END makeUnary ;
(*
isLeafString - returns TRUE if n is a leaf node which is a string constant.
*)
PROCEDURE isLeafString (n: node) : BOOLEAN ;
BEGIN
RETURN isString (n) OR
(isLiteral (n) AND (getType (n) = charN)) OR
(isConst (n) AND (getExprType (n) = charN))
END isLeafString ;
(*
getLiteralStringContents - return the contents of a literal node as a string.
*)
PROCEDURE getLiteralStringContents (n: node) : String ;
VAR
number,
content,
s : String ;
BEGIN
assert (n^.kind = literal) ;
s := InitStringCharStar (keyToCharStar (n^.literalF.name)) ;
content := NIL ;
IF n^.literalF.type = charN
THEN
IF DynamicStrings.char (s, -1) = 'C'
THEN
IF DynamicStrings.Length (s) > 1
THEN
number := DynamicStrings.Slice (s, 0, -1) ;
content := DynamicStrings.InitStringChar (VAL (CHAR, ostoc (number))) ;
number := DynamicStrings.KillString (number)
ELSE
content := DynamicStrings.InitStringChar ('C')
END
ELSE
content := DynamicStrings.Dup (s)
END
ELSE
metaError1 ('cannot obtain string contents from {%1k}', n^.literalF.name)
END ;
s := DynamicStrings.KillString (s) ;
RETURN content
END getLiteralStringContents ;
(*
getStringContents - return the string contents of a constant, literal,
string or a constexp node.
*)
PROCEDURE getStringContents (n: node) : String ;
BEGIN
IF isConst (n)
THEN
RETURN getStringContents (n^.constF.value)
ELSIF isLiteral (n)
THEN
RETURN getLiteralStringContents (n)
ELSIF isString (n)
THEN
RETURN getString (n)
ELSIF isConstExp (n)
THEN
RETURN getStringContents (n^.unaryF.arg)
END ;
HALT
END getStringContents ;
(*
addNames -
*)
PROCEDURE addNames (a, b: node) : Name ;
VAR
sa, sb: String ;
n : Name ;
BEGIN
sa := DynamicStrings.InitStringCharStar (keyToCharStar (getSymName (a))) ;
sb := DynamicStrings.InitStringCharStar (keyToCharStar (getSymName (b))) ;
sa := ConCat (sa, sb) ;
n := makekey (DynamicStrings.string (sa)) ;
sa := KillString (sa) ;
sb := KillString (sb) ;
RETURN n
END addNames ;
(*
resolveString -
*)
PROCEDURE resolveString (n: node) : node ;
BEGIN
WHILE isConst (n) OR isConstExp (n) DO
IF isConst (n)
THEN
n := n^.constF.value
ELSE
n := n^.unaryF.arg
END
END ;
IF n^.kind = plus
THEN
n := makeString (addNames (resolveString (n^.binaryF.left),
resolveString (n^.binaryF.right)))
END ;
RETURN n
END resolveString ;
(*
foldBinary -
*)
PROCEDURE foldBinary (k: nodeT; l, r: node; res: node) : node ;
VAR
n : node ;
ls,
rs: String ;
BEGIN
n := NIL ;
IF (k = plus) AND isLeafString (l) AND isLeafString (r)
THEN
ls := getStringContents (l) ;
rs := getStringContents (r) ;
ls := DynamicStrings.Add (ls, rs) ;
n := makeString (makekey (DynamicStrings.string (ls))) ;
ls := DynamicStrings.KillString (ls) ;
rs := DynamicStrings.KillString (rs)
END ;
RETURN n
END foldBinary ;
(*
makeBinary - create a binary node with left/right/result type: l, r and resultType.
*)
PROCEDURE makeBinary (k: nodeT; l, r: node; resultType: node) : node ;
VAR
n: node ;
BEGIN
n := foldBinary (k, l, r, resultType) ;
IF n = NIL
THEN
n := doMakeBinary (k, l, r, resultType)
END ;
RETURN n
END makeBinary ;
(*
doMakeBinary - returns a binary node containing left/right/result values
l, r, res, with a node operator, k.
*)
PROCEDURE doMakeBinary (k: nodeT; l, r: node; res: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (k) ;
WITH n^ DO
CASE kind OF
cmplx,
equal,
notequal,
less,
greater,
greequal,
lessequal,
and,
or,
cast,
val,
plus,
sub,
div,
mod,
mult,
divide,
in : WITH binaryF DO
left := l ;
right := r ;
resultType := res
END
END
END ;
RETURN n
END doMakeBinary ;
(*
doMakeComponentRef -
*)
PROCEDURE doMakeComponentRef (rec, field: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (componentref) ;
n^.componentrefF.rec := rec ;
n^.componentrefF.field := field ;
n^.componentrefF.resultType := getType (field) ;
RETURN n
END doMakeComponentRef ;
(*
makeComponentRef - build a componentref node which accesses, field,
within, record, rec.
*)
PROCEDURE makeComponentRef (rec, field: node) : node ;
VAR
n, a: node ;
BEGIN
(*
n := getLastOp (rec) ;
IF (n#NIL) AND (isDeref (n) OR isPointerRef (n)) AND
(skipType (getType (rec)) = skipType (getType (n)))
THEN
a := n^.unaryF.arg ;
n^.kind := pointerref ;
n^.pointerrefF.ptr := a ;
n^.pointerrefF.field := field ;
n^.pointerrefF.resultType := getType (field) ;
RETURN n
ELSE
RETURN doMakeComponentRef (rec, field)
END
*)
IF isDeref (rec)
THEN
a := rec^.unaryF.arg ;
rec^.kind := pointerref ;
rec^.pointerrefF.ptr := a ;
rec^.pointerrefF.field := field ;
rec^.pointerrefF.resultType := getType (field) ;
RETURN rec
ELSE
RETURN doMakeComponentRef (rec, field)
END
END makeComponentRef ;
(*
isComponentRef -
*)
PROCEDURE isComponentRef (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = componentref
END isComponentRef ;
(*
makePointerRef - build a pointerref node which accesses, field,
within, pointer to record, ptr.
*)
PROCEDURE makePointerRef (ptr, field: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (pointerref) ;
n^.pointerrefF.ptr := ptr ;
n^.pointerrefF.field := field ;
n^.pointerrefF.resultType := getType (field) ;
RETURN n
END makePointerRef ;
(*
isPointerRef - returns TRUE if, n, is a pointerref node.
*)
PROCEDURE isPointerRef (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = pointerref
END isPointerRef ;
(*
makeArrayRef - build an arrayref node which access element,
index, in, array. array is a variable/expression/constant
which has a type array.
*)
PROCEDURE makeArrayRef (array, index: node) : node ;
VAR
n, t: node ;
i, j: CARDINAL ;
BEGIN
n := newNode (arrayref) ;
n^.arrayrefF.array := array ;
n^.arrayrefF.index := index ;
t := array ;
j := expListLen (index) ;
i := 1 ;
t := skipType (getType (t)) ;
REPEAT
IF isArray (t)
THEN
t := skipType (getType (t))
ELSE
metaError2 ('cannot access {%1N} dimension of array {%2a}', i, t)
END ;
INC (i)
UNTIL i > j ;
n^.arrayrefF.resultType := t ;
RETURN n
END makeArrayRef ;
(*
isArrayRef - returns TRUE if the node was an arrayref.
*)
PROCEDURE isArrayRef (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = arrayref
END isArrayRef ;
(*
makeDeRef - dereferences the pointer defined by, n.
*)
PROCEDURE makeDeRef (n: node) : node ;
VAR
t: node ;
BEGIN
t := skipType (getType (n)) ;
assert (isPointer (t)) ;
RETURN makeUnary (deref, n, getType (t))
END makeDeRef ;
(*
isDeref - returns TRUE if, n, is a deref node.
*)
PROCEDURE isDeref (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = deref
END isDeref ;
(*
makeBase - create a base type or constant.
It only supports the base types and constants
enumerated below.
*)
PROCEDURE makeBase (k: nodeT) : node ;
VAR
n: node ;
BEGIN
n := newNode (k) ;
WITH n^ DO
CASE k OF
new,
dispose,
length,
inc,
dec,
incl,
excl,
nil,
true,
false,
address,
loc,
byte,
word,
csizet,
cssizet,
char,
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
real,
longreal,
shortreal,
bitset,
boolean,
proc,
ztype,
rtype,
complex,
longcomplex,
shortcomplex,
adr,
chr,
cap,
abs,
float,
trunc,
ord,
high,
throw,
re,
im,
cmplx,
size,
tsize,
val,
min,
max : (* legal kind. *) |
ELSE
HALT
END
END ;
RETURN n
END makeBase ;
(*
makeBinaryTok - creates and returns a boolean type node with,
l, and, r, nodes.
*)
PROCEDURE makeBinaryTok (op: toktype; l, r: node) : node ;
BEGIN
IF op=equaltok
THEN
RETURN makeBinary (equal, l, r, booleanN)
ELSIF (op=hashtok) OR (op=lessgreatertok)
THEN
RETURN makeBinary (notequal, l, r, booleanN)
ELSIF op=lesstok
THEN
RETURN makeBinary (less, l, r, booleanN)
ELSIF op=greatertok
THEN
RETURN makeBinary (greater, l, r, booleanN)
ELSIF op=greaterequaltok
THEN
RETURN makeBinary (greequal, l, r, booleanN)
ELSIF op=lessequaltok
THEN
RETURN makeBinary (lessequal, l, r, booleanN)
ELSIF op=andtok
THEN
RETURN makeBinary (and, l, r, booleanN)
ELSIF op=ortok
THEN
RETURN makeBinary (or, l, r, booleanN)
ELSIF op=plustok
THEN
RETURN makeBinary (plus, l, r, NIL)
ELSIF op=minustok
THEN
RETURN makeBinary (sub, l, r, NIL)
ELSIF op=divtok
THEN
RETURN makeBinary (div, l, r, NIL)
ELSIF op=timestok
THEN
RETURN makeBinary (mult, l, r, NIL)
ELSIF op=modtok
THEN
RETURN makeBinary (mod, l, r, NIL)
ELSIF op=intok
THEN
RETURN makeBinary (in, l, r, NIL)
ELSIF op=dividetok
THEN
RETURN makeBinary (divide, l, r, NIL)
ELSE
HALT (* most likely op needs a clause as above. *)
END
END makeBinaryTok ;
(*
makeUnaryTok - creates and returns a boolean type node with,
e, node.
*)
PROCEDURE makeUnaryTok (op: toktype; e: node) : node ;
BEGIN
IF op=nottok
THEN
RETURN makeUnary (not, e, booleanN)
ELSIF op=plustok
THEN
RETURN makeUnary (plus, e, NIL)
ELSIF op=minustok
THEN
RETURN makeUnary (neg, e, NIL)
ELSE
HALT (* most likely op needs a clause as above. *)
END
END makeUnaryTok ;
(*
isOrdinal - returns TRUE if, n, is an ordinal type.
*)
PROCEDURE isOrdinal (n: node) : BOOLEAN ;
BEGIN
CASE n^.kind OF
address,
loc,
byte,
word,
csizet,
cssizet,
char,
integer,
longint,
shortint,
cardinal,
longcard,
shortcard,
bitset : RETURN TRUE
ELSE
RETURN FALSE
END
END isOrdinal ;
(*
getType - returns the type associated with node, n.
*)
PROCEDURE getType (n: node) : node ;
BEGIN
WITH n^ DO
CASE kind OF
new,
dispose : RETURN NIL |
length : RETURN cardinalN |
inc,
dec,
incl,
excl : RETURN NIL |
nil : RETURN addressN |
true,
false : RETURN booleanN |
address : RETURN n |
loc : RETURN n |
byte : RETURN n |
word : RETURN n |
csizet : RETURN n |
cssizet : RETURN n |
(* base types. *)
boolean : RETURN n |
proc : RETURN n |
char : RETURN n |
cardinal : RETURN n |
longcard : RETURN n |
shortcard : RETURN n |
integer : RETURN n |
longint : RETURN n |
shortint : RETURN n |
real : RETURN n |
longreal : RETURN n |
shortreal : RETURN n |
bitset : RETURN n |
ztype : RETURN n |
rtype : RETURN n |
complex : RETURN n |
longcomplex : RETURN n |
shortcomplex : RETURN n |
(* language features and compound type attributes. *)
type : RETURN typeF.type |
record : RETURN n |
varient : RETURN n |
var : RETURN varF.type |
enumeration : RETURN n |
subrange : RETURN subrangeF.type |
array : RETURN arrayF.type |
string : RETURN charN |
const : RETURN constF.type |
literal : RETURN literalF.type |
varparam : RETURN varparamF.type |
param : RETURN paramF.type |
optarg : RETURN optargF.type |
pointer : RETURN pointerF.type |
recordfield : RETURN recordfieldF.type |
varientfield : RETURN n |
enumerationfield: RETURN enumerationfieldF.type |
set : RETURN setF.type |
proctype : RETURN proctypeF.returnType |
subscript : RETURN subscriptF.type |
(* blocks. *)
procedure : RETURN procedureF.returnType |
throw : RETURN NIL |
unreachable : RETURN NIL |
def,
imp,
module,
(* statements. *)
loop,
while,
for,
repeat,
if,
elsif,
assignment : HALT |
(* expressions. *)
cmplx,
cast,
val,
plus,
sub,
div,
mod,
mult,
divide : RETURN binaryF.resultType |
in : RETURN booleanN |
max,
min,
re,
im,
abs,
constexp,
deref,
neg,
adr,
size,
tsize : RETURN unaryF.resultType |
and,
or,
not,
equal,
notequal,
less,
greater,
greequal,
lessequal : RETURN booleanN |
trunc : RETURN integerN |
float : RETURN realN |
high : RETURN cardinalN |
ord : RETURN cardinalN |
chr : RETURN charN |
cap : RETURN charN |
arrayref : RETURN arrayrefF.resultType |
componentref : RETURN componentrefF.resultType |
pointerref : RETURN pointerrefF.resultType |
funccall : RETURN funccallF.type |
setvalue : RETURN setvalueF.type
END
END ;
HALT
END getType ;
(*
mixTypes -
*)
PROCEDURE mixTypes (a, b: node) : node ;
BEGIN
IF (a = addressN) OR (b = addressN)
THEN
RETURN addressN
END ;
RETURN a
END mixTypes ;
(*
doSetExprType -
*)
PROCEDURE doSetExprType (VAR t: node; n: node) : node ;
BEGIN
IF t = NIL
THEN
t := n
END ;
RETURN t
END doSetExprType ;
(*
getMaxMinType -
*)
PROCEDURE getMaxMinType (n: node) : node ;
BEGIN
IF isVar (n) OR isConst (n)
THEN
RETURN getType (n)
ELSIF isConstExp (n)
THEN
n := getExprType (n^.unaryF.arg) ;
IF n = bitsetN
THEN
RETURN ztypeN
ELSE
RETURN n
END
ELSE
RETURN n
END
END getMaxMinType ;
(*
doGetFuncType -
*)
PROCEDURE doGetFuncType (n: node) : node ;
BEGIN
assert (isFuncCall (n)) ;
RETURN doSetExprType (n^.funccallF.type, getType (n^.funccallF.function))
END doGetFuncType ;
(*
doGetExprType - works out the type which is associated with node, n.
*)
PROCEDURE doGetExprType (n: node) : node ;
BEGIN
WITH n^ DO
CASE kind OF
max,
min : RETURN getMaxMinType (n^.unaryF.arg) |
cast,
val : RETURN doSetExprType (n^.binaryF.resultType, n^.binaryF.left) |
halt,
new,
dispose : RETURN NIL |
inc,
dec,
incl,
excl : RETURN NIL |
nil : RETURN addressN |
true,
false : RETURN booleanN |
address : RETURN n |
loc : RETURN n |
byte : RETURN n |
word : RETURN n |
csizet : RETURN n |
cssizet : RETURN n |
(* base types. *)
boolean : RETURN n |
proc : RETURN n |
char : RETURN n |
cardinal : RETURN n |
longcard : RETURN n |
shortcard : RETURN n |
integer : RETURN n |
longint : RETURN n |
shortint : RETURN n |
real : RETURN n |
longreal : RETURN n |
shortreal : RETURN n |
bitset : RETURN n |
ztype : RETURN n |
rtype : RETURN n |
complex : RETURN n |
longcomplex : RETURN n |
shortcomplex : RETURN n |
(* language features and compound type attributes. *)
type : RETURN typeF.type |
record : RETURN n |
varient : RETURN n |
var : RETURN varF.type |
enumeration : RETURN n |
subrange : RETURN subrangeF.type |
array : RETURN arrayF.type |
string : RETURN charN |
const : RETURN doSetExprType (constF.type, getExprType (constF.value)) |
literal : RETURN literalF.type |
varparam : RETURN varparamF.type |
param : RETURN paramF.type |
optarg : RETURN optargF.type |
pointer : RETURN pointerF.type |
recordfield : RETURN recordfieldF.type |
varientfield : RETURN n |
enumerationfield: RETURN enumerationfieldF.type |
set : RETURN setF.type |
proctype : RETURN proctypeF.returnType |
subscript : RETURN subscriptF.type |
(* blocks. *)
procedure : RETURN procedureF.returnType |
throw : RETURN NIL |
unreachable : RETURN NIL |
def,
imp,
module,
(* statements. *)
loop,
while,
for,
repeat,
if,
elsif,
assignment : HALT |
(* expressions. *)
plus,
sub,
div,
mod,
mult,
divide : RETURN doSetExprType (binaryF.resultType, mixTypes (getExprType (binaryF.left), getExprType (binaryF.right))) |
in,
and,
or,
equal,
notequal,
less,
greater,
greequal,
lessequal : RETURN doSetExprType (binaryF.resultType, booleanN) |
cmplx : RETURN doSetExprType (binaryF.resultType, complexN) |
abs,
constexp,
deref,
neg : RETURN doSetExprType (unaryF.resultType, getExprType (unaryF.arg)) |
adr : RETURN doSetExprType (unaryF.resultType, addressN) |
size,
tsize : RETURN doSetExprType (unaryF.resultType, cardinalN) |
high,
ord : RETURN doSetExprType (unaryF.resultType, cardinalN) |
float : RETURN doSetExprType (unaryF.resultType, realN) |
trunc : RETURN doSetExprType (unaryF.resultType, integerN) |
chr : RETURN doSetExprType (unaryF.resultType, charN) |
cap : RETURN doSetExprType (unaryF.resultType, charN) |
not : RETURN doSetExprType (unaryF.resultType, booleanN) |
re : RETURN doSetExprType (unaryF.resultType, realN) |
im : RETURN doSetExprType (unaryF.resultType, realN) |
arrayref : RETURN arrayrefF.resultType |
componentref : RETURN componentrefF.resultType |
pointerref : RETURN pointerrefF.resultType |
funccall : RETURN doSetExprType (funccallF.type, doGetFuncType (n)) |
setvalue : RETURN setvalueF.type
END
END ;
HALT
END doGetExprType ;
(*
getExprType - return the expression type.
*)
PROCEDURE getExprType (n: node) : node ;
VAR
t: node ;
BEGIN
IF isFuncCall (n) AND (getType (n) # NIL) AND isProcType (skipType (getType (n)))
THEN
RETURN getType (skipType (getType (n)))
END ;
t := getType (n) ;
IF t = NIL
THEN
t := doGetExprType (n)
END ;
RETURN t
END getExprType ;
(*
skipType - skips over type aliases.
*)
PROCEDURE skipType (n: node) : node ;
BEGIN
WHILE (n#NIL) AND isType (n) DO
IF getType (n) = NIL
THEN
(* this will occur if, n, is an opaque type. *)
RETURN n
END ;
n := getType (n)
END ;
RETURN n
END skipType ;
(*
getScope - returns the scope associated with node, n.
*)
PROCEDURE getScope (n: node) : node ;
BEGIN
WITH n^ DO
CASE kind OF
stmtseq,
exit,
return,
comment,
identlist,
setvalue,
halt,
new,
dispose,
length,
inc,
dec,
incl,
excl,
nil,
true,
false : RETURN NIL |
address,
loc,
byte,
word,
csizet,
cssizet : RETURN systemN |
(* base types. *)
boolean,
proc,
char,
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
real,
longreal,
shortreal,
bitset,
ztype,
rtype,
complex,
longcomplex,
shortcomplex : RETURN NIL |
(* language features and compound type attributes. *)
type : RETURN typeF.scope |
record : RETURN recordF.scope |
varient : RETURN varientF.scope |
var : RETURN varF.scope |
enumeration : RETURN enumerationF.scope |
subrange : RETURN subrangeF.scope |
array : RETURN arrayF.scope |
string : RETURN NIL |
const : RETURN constF.scope |
literal : RETURN NIL |
varparam : RETURN varparamF.scope |
param : RETURN paramF.scope |
optarg : RETURN optargF.scope |
pointer : RETURN pointerF.scope |
recordfield : RETURN recordfieldF.scope |
varientfield : RETURN varientfieldF.scope |
enumerationfield: RETURN enumerationfieldF.scope |
set : RETURN setF.scope |
proctype : RETURN proctypeF.scope |
subscript : RETURN NIL |
(* blocks. *)
procedure : RETURN procedureF.scope |
def,
imp,
module,
(* statements. *)
case,
loop,
while,
for,
repeat,
if,
elsif,
assignment : RETURN NIL |
(* expressions. *)
componentref,
pointerref,
arrayref,
chr,
cap,
ord,
float,
trunc,
high,
cast,
val,
plus,
sub,
div,
mod,
mult,
divide,
in : RETURN NIL |
neg : RETURN NIL |
lsl,
lsr,
lor,
land,
lnot,
lxor,
and,
or,
not,
constexp,
deref,
equal,
notequal,
less,
greater,
greequal,
lessequal : RETURN NIL |
adr,
size,
tsize,
throw : RETURN systemN |
unreachable,
cmplx, re, im,
min,
max : RETURN NIL |
vardecl : RETURN vardeclF.scope |
funccall : RETURN NIL |
explist : RETURN NIL |
caselabellist : RETURN NIL |
caselist : RETURN NIL |
range : RETURN NIL |
varargs : RETURN varargsF.scope
END
END
END getScope ;
(*
foreachDefModuleDo - foreach definition node, n, in the module universe,
call p (n).
*)
PROCEDURE foreachDefModuleDo (p: performOperation) ;
BEGIN
ForeachIndiceInIndexDo (defUniverseI, p)
END foreachDefModuleDo ;
(*
foreachModModuleDo - foreach implementation or module node, n, in the module universe,
call p (n).
*)
PROCEDURE foreachModModuleDo (p: performOperation) ;
BEGIN
ForeachIndiceInIndexDo (modUniverseI, p)
END foreachModModuleDo ;
(*
openOutput -
*)
PROCEDURE openOutput ;
VAR
s: String ;
BEGIN
s := getOutputFile () ;
IF EqualArray (s, '-')
THEN
outputFile := StdOut
ELSE
outputFile := OpenToWrite (s)
END ;
mcStream.setDest (outputFile)
END openOutput ;
(*
closeOutput -
*)
PROCEDURE closeOutput ;
VAR
s: String ;
BEGIN
s := getOutputFile () ;
outputFile := mcStream.combine () ;
IF NOT EqualArray (s, '-')
THEN
Close (outputFile)
END
END closeOutput ;
(*
write - outputs a single char, ch.
*)
PROCEDURE write (ch: CHAR) ;
BEGIN
WriteChar (outputFile, ch) ;
FlushBuffer (outputFile)
END write ;
(*
writeln -
*)
PROCEDURE writeln ;
BEGIN
WriteLine (outputFile) ;
FlushBuffer (outputFile)
END writeln ;
(*
doIncludeC - include header file for definition module, n.
*)
PROCEDURE doIncludeC (n: node) ;
VAR
s: String ;
BEGIN
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
IF getExtendedOpaque ()
THEN
(* no include in this case. *)
ELSIF isDef (n)
THEN
print (doP, '# include "') ;
prints (doP, getHPrefix ()) ;
prints (doP, s) ;
print (doP, '.h"\n') ;
foreachNodeDo (n^.defF.decls.symbols, addDoneDef)
END ;
s := KillString (s)
END doIncludeC ;
(*
getSymScope - returns the scope where node, n, was declared.
*)
PROCEDURE getSymScope (n: node) : node ;
BEGIN
WITH n^ DO
CASE kind OF
const : RETURN constF.scope |
type : RETURN typeF.scope |
var : RETURN varF.scope |
procedure: RETURN procedureF.scope
END
END ;
HALT
END getSymScope ;
(*
isQualifiedForced - should the node be written with a module prefix?
*)
PROCEDURE isQualifiedForced (n: node) : BOOLEAN ;
BEGIN
RETURN (forceQualified AND
(isType (n) OR isRecord (n) OR isArray (n) OR isEnumeration (n) OR isEnumerationField (n)))
END isQualifiedForced ;
(*
getFQstring -
*)
PROCEDURE getFQstring (n: node) : String ;
VAR
i, s: String ;
BEGIN
IF getScope (n) = NIL
THEN
RETURN InitStringCharStar (keyToCharStar (getSymName (n)))
ELSIF isQualifiedForced (n)
THEN
i := InitStringCharStar (keyToCharStar (getSymName (n))) ;
s := InitStringCharStar (keyToCharStar (getSymName (getScope (n)))) ;
RETURN Sprintf2 (InitString ("%s_%s"), s, i)
ELSIF (NOT isExported (n)) OR getIgnoreFQ ()
THEN
RETURN InitStringCharStar (keyToCharStar (getSymName (n)))
ELSE
i := InitStringCharStar (keyToCharStar (getSymName (n))) ;
s := InitStringCharStar (keyToCharStar (getSymName (getScope (n)))) ;
RETURN Sprintf2 (InitString ("%s_%s"), s, i)
END
END getFQstring ;
(*
getFQDstring -
*)
PROCEDURE getFQDstring (n: node; scopes: BOOLEAN) : String ;
VAR
i, s: String ;
BEGIN
IF getScope (n) = NIL
THEN
RETURN InitStringCharStar (keyToCharStar (getDName (n, scopes)))
ELSIF isQualifiedForced (n)
THEN
(* we assume a qualified name will never conflict. *)
i := InitStringCharStar (keyToCharStar (getSymName (n))) ;
s := InitStringCharStar (keyToCharStar (getSymName (getScope (n)))) ;
RETURN Sprintf2 (InitString ("%s_%s"), s, i)
ELSIF (NOT isExported (n)) OR getIgnoreFQ ()
THEN
RETURN InitStringCharStar (keyToCharStar (getDName (n, scopes)))
ELSE
(* we assume a qualified name will never conflict. *)
i := InitStringCharStar (keyToCharStar (getSymName (n))) ;
s := InitStringCharStar (keyToCharStar (getSymName (getScope (n)))) ;
RETURN Sprintf2 (InitString ("%s_%s"), s, i)
END
END getFQDstring ;
(*
getString - returns the name as a string.
*)
PROCEDURE getString (n: node) : String ;
BEGIN
IF getSymName (n) = NulName
THEN
RETURN InitString ('')
ELSE
RETURN InitStringCharStar (keyToCharStar (getSymName (n)))
END
END getString ;
(*
getCardinal - returns the cardinal type node.
*)
PROCEDURE getCardinal () : node ;
BEGIN
RETURN cardinalN
END getCardinal ;
(*
doNone - call HALT.
*)
PROCEDURE doNone (n: node) ;
BEGIN
HALT
END doNone ;
(*
doNothing - does nothing!
*)
PROCEDURE doNothing (n: node) ;
BEGIN
END doNothing ;
(*
doConstC -
*)
PROCEDURE doConstC (n: node) ;
BEGIN
IF NOT alists.isItemInList (doneQ, n)
THEN
print (doP, "# define ") ;
doFQNameC (doP, n) ;
setNeedSpace (doP) ;
doExprC (doP, n^.constF.value) ;
print (doP, '\n') ;
alists.includeItemIntoList (doneQ, n)
END
END doConstC ;
(*
needsParen - returns TRUE if expression, n, needs to be enclosed in ().
*)
PROCEDURE needsParen (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
WITH n^ DO
CASE kind OF
nil,
true,
false : RETURN FALSE |
constexp : RETURN needsParen (unaryF.arg) |
neg : RETURN needsParen (unaryF.arg) |
not : RETURN needsParen (unaryF.arg) |
adr,
size,
tsize,
ord,
float,
trunc,
chr,
cap,
high : RETURN FALSE |
deref : RETURN FALSE |
equal,
notequal,
less,
greater,
greequal,
lessequal : RETURN TRUE |
componentref : RETURN FALSE |
pointerref : RETURN FALSE |
cast : RETURN TRUE |
val : RETURN TRUE |
abs : RETURN FALSE |
plus,
sub,
div,
mod,
mult,
divide,
in : RETURN TRUE |
literal,
const,
enumerationfield,
string : RETURN FALSE |
max : RETURN TRUE |
min : RETURN TRUE |
var : RETURN FALSE |
arrayref : RETURN FALSE |
and,
or : RETURN TRUE |
funccall : RETURN TRUE |
recordfield : RETURN FALSE |
loc,
byte,
word,
type,
char,
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
real,
longreal,
shortreal,
complex,
longcomplex,
shortcomplex,
bitset,
boolean,
proc : RETURN FALSE |
setvalue : RETURN FALSE |
address : RETURN TRUE |
procedure : RETURN FALSE |
length,
cmplx, re, im : RETURN TRUE
END
END ;
RETURN TRUE
END needsParen ;
(*
doUnary -
*)
PROCEDURE doUnary (p: pretty; op: ARRAY OF CHAR; expr, type: node; l, r: BOOLEAN) ;
BEGIN
IF l
THEN
setNeedSpace (p)
END ;
print (p, op) ;
IF r
THEN
setNeedSpace (p)
END ;
IF needsParen (expr)
THEN
outText (p, '(') ;
doExprC (p, expr) ;
outText (p, ')')
ELSE
doExprC (p, expr)
END
END doUnary ;
(*
doSetSub - perform l & (~ r)
*)
PROCEDURE doSetSub (p: pretty; left, right: node) ;
BEGIN
IF needsParen (left)
THEN
outText (p, '(') ;
doExprC (p, left) ;
outText (p, ')')
ELSE
doExprC (p, left)
END ;
setNeedSpace (p) ;
outText (p, '&') ;
setNeedSpace (p) ;
IF needsParen (right)
THEN
outText (p, '(~(') ;
doExprC (p, right) ;
outText (p, '))')
ELSE
outText (p, '(~') ;
doExprC (p, right) ;
outText (p, ')')
END
END doSetSub ;
(*
doPolyBinary -
*)
PROCEDURE doPolyBinary (p: pretty; op: nodeT; left, right: node; l, r: BOOLEAN) ;
VAR
lt, rt: node ;
BEGIN
lt := skipType (getExprType (left)) ;
rt := skipType (getExprType (right)) ;
IF ((lt # NIL) AND (isSet (lt) OR isBitset (lt))) OR
((rt # NIL) AND (isSet (rt) OR isBitset (rt)))
THEN
CASE op OF
plus : doBinary (p, '|', left, right, l, r, FALSE) |
sub : doSetSub (p, left, right) |
mult : doBinary (p, '&', left, right, l, r, FALSE) |
divide : doBinary (p, '^', left, right, l, r, FALSE)
END
ELSE
CASE op OF
plus : doBinary (p, '+', left, right, l, r, FALSE) |
sub : doBinary (p, '-', left, right, l, r, FALSE) |
mult : doBinary (p, '*', left, right, l, r, FALSE) |
divide : doBinary (p, '/', left, right, l, r, FALSE)
END
END
END doPolyBinary ;
(*
doBinary -
*)
PROCEDURE doBinary (p: pretty; op: ARRAY OF CHAR; left, right: node; l, r, unpackProc: BOOLEAN) ;
BEGIN
IF needsParen (left)
THEN
outText (p, '(') ;
doExprCup (p, left, unpackProc) ;
outText (p, ')')
ELSE
doExprCup (p, left, unpackProc)
END ;
IF l
THEN
setNeedSpace (p)
END ;
outText (p, op) ;
IF r
THEN
setNeedSpace (p)
END ;
IF needsParen (right)
THEN
outText (p, '(') ;
doExprCup (p, right, unpackProc) ;
outText (p, ')')
ELSE
doExprCup (p, right, unpackProc)
END
END doBinary ;
(*
doPostUnary -
*)
PROCEDURE doPostUnary (p: pretty; op: ARRAY OF CHAR; expr: node) ;
BEGIN
doExprC (p, expr) ;
outText (p, op)
END doPostUnary ;
(*
doDeRefC -
*)
PROCEDURE doDeRefC (p: pretty; expr: node) ;
BEGIN
outText (p, '(*') ;
doExprC (p, expr) ;
outText (p, ')')
END doDeRefC ;
(*
doGetLastOp - returns, a, if b is a terminal otherwise walk right.
*)
PROCEDURE doGetLastOp (a, b: node) : node ;
BEGIN
WITH b^ DO
CASE kind OF
nil : RETURN a |
true : RETURN a |
false : RETURN a |
constexp : RETURN doGetLastOp (b, unaryF.arg) |
neg : RETURN doGetLastOp (b, unaryF.arg) |
not : RETURN doGetLastOp (b, unaryF.arg) |
adr : RETURN doGetLastOp (b, unaryF.arg) |
size : RETURN doGetLastOp (b, unaryF.arg) |
tsize : RETURN doGetLastOp (b, unaryF.arg) |
ord : RETURN doGetLastOp (b, unaryF.arg) |
float,
trunc : RETURN doGetLastOp (b, unaryF.arg) |
chr : RETURN doGetLastOp (b, unaryF.arg) |
cap : RETURN doGetLastOp (b, unaryF.arg) |
high : RETURN doGetLastOp (b, unaryF.arg) |
deref : RETURN doGetLastOp (b, unaryF.arg) |
re,
im : RETURN doGetLastOp (b, unaryF.arg) |
equal : RETURN doGetLastOp (b, binaryF.right) |
notequal : RETURN doGetLastOp (b, binaryF.right) |
less : RETURN doGetLastOp (b, binaryF.right) |
greater : RETURN doGetLastOp (b, binaryF.right) |
greequal : RETURN doGetLastOp (b, binaryF.right) |
lessequal : RETURN doGetLastOp (b, binaryF.right) |
componentref : RETURN doGetLastOp (b, componentrefF.field) |
pointerref : RETURN doGetLastOp (b, pointerrefF.field) |
cast : RETURN doGetLastOp (b, binaryF.right) |
val : RETURN doGetLastOp (b, binaryF.right) |
plus : RETURN doGetLastOp (b, binaryF.right) |
sub : RETURN doGetLastOp (b, binaryF.right) |
div : RETURN doGetLastOp (b, binaryF.right) |
mod : RETURN doGetLastOp (b, binaryF.right) |
mult : RETURN doGetLastOp (b, binaryF.right) |
divide : RETURN doGetLastOp (b, binaryF.right) |
in : RETURN doGetLastOp (b, binaryF.right) |
and : RETURN doGetLastOp (b, binaryF.right) |
or : RETURN doGetLastOp (b, binaryF.right) |
cmplx : RETURN doGetLastOp (b, binaryF.right) |
literal : RETURN a |
const : RETURN a |
enumerationfield: RETURN a |
string : RETURN a |
max : RETURN doGetLastOp (b, unaryF.arg) |
min : RETURN doGetLastOp (b, unaryF.arg) |
var : RETURN a |
arrayref : RETURN a |
funccall : RETURN a |
procedure : RETURN a |
recordfield : RETURN a
END
END
END doGetLastOp ;
(*
getLastOp - return the right most non leaf node.
*)
PROCEDURE getLastOp (n: node) : node ;
BEGIN
RETURN doGetLastOp (n, n)
END getLastOp ;
(*
doComponentRefC -
*)
PROCEDURE doComponentRefC (p: pretty; l, r: node) ;
BEGIN
doExprC (p, l) ;
outText (p, '.') ;
doExprC (p, r)
END doComponentRefC ;
(*
doPointerRefC -
*)
PROCEDURE doPointerRefC (p: pretty; l, r: node) ;
BEGIN
doExprC (p, l) ;
outText (p, '->') ;
doExprC (p, r)
END doPointerRefC ;
(*
doPreBinary -
*)
PROCEDURE doPreBinary (p: pretty; op: ARRAY OF CHAR; left, right: node; l, r: BOOLEAN) ;
BEGIN
IF l
THEN
setNeedSpace (p)
END ;
outText (p, op) ;
IF r
THEN
setNeedSpace (p)
END ;
outText (p, '(') ;
doExprC (p, left) ;
outText (p, ',') ;
setNeedSpace (p) ;
doExprC (p, right) ;
outText (p, ')')
END doPreBinary ;
(*
doConstExpr -
*)
PROCEDURE doConstExpr (p: pretty; n: node) ;
BEGIN
doFQNameC (p, n)
END doConstExpr ;
(*
doEnumerationField -
*)
PROCEDURE doEnumerationField (p: pretty; n: node) ;
BEGIN
doFQDNameC (p, n, FALSE)
END doEnumerationField ;
(*
isZero - returns TRUE if node, n, is zero.
*)
PROCEDURE isZero (n: node) : BOOLEAN ;
BEGIN
IF isConstExp (n)
THEN
RETURN isZero (n^.unaryF.arg)
END ;
RETURN getSymName (n)=makeKey ('0')
END isZero ;
(*
doArrayRef -
*)
PROCEDURE doArrayRef (p: pretty; n: node) ;
VAR
t : node ;
i, c: CARDINAL ;
BEGIN
assert (n # NIL) ;
assert (isArrayRef (n)) ;
t := skipType (getType (n^.arrayrefF.array)) ;
IF isUnbounded (t)
THEN
outTextN (p, getSymName (n^.arrayrefF.array))
ELSE
doExprC (p, n^.arrayrefF.array) ;
assert (isArray (t)) ;
outText (p, '.array')
END ;
outText (p, '[') ;
i := 1 ;
c := expListLen (n^.arrayrefF.index) ;
WHILE i<=c DO
doExprC (p, getExpList (n^.arrayrefF.index, i)) ;
IF isUnbounded (t)
THEN
assert (c = 1)
ELSE
doSubtractC (p, getMin (t^.arrayF.subr)) ;
IF i<c
THEN
assert (isArray (t)) ;
outText (p, '].array[') ;
t := skipType (getType (t))
END
END ;
INC (i)
END ;
outText (p, ']')
END doArrayRef ;
(*
doProcedure -
*)
PROCEDURE doProcedure (p: pretty; n: node) ;
BEGIN
assert (isProcedure (n)) ;
doFQDNameC (p, n, TRUE)
END doProcedure ;
(*
doRecordfield -
*)
PROCEDURE doRecordfield (p: pretty; n: node) ;
BEGIN
doDNameC (p, n, FALSE)
END doRecordfield ;
(*
doCastC -
*)
PROCEDURE doCastC (p: pretty; t, e: node) ;
VAR
et: node ;
BEGIN
outText (p, '(') ;
doTypeNameC (p, t) ;
outText (p, ')') ;
setNeedSpace (p) ;
et := skipType (getType (e)) ;
IF (et # NIL) AND isAProcType (et) AND isAProcType (skipType (t))
THEN
outText (p, '{(') ;
doFQNameC (p, t) ;
outText (p, '_t)') ;
setNeedSpace (p) ;
doExprC (p, e) ;
outText (p, '.proc}')
ELSE
outText (p, '(') ;
doExprC (p, e) ;
outText (p, ')')
END
END doCastC ;
(*
doSetValueC -
*)
PROCEDURE doSetValueC (p: pretty; n: node) ;
VAR
lo : node ;
i, h: CARDINAL ;
BEGIN
assert (isSetValue (n)) ;
lo := getSetLow (n) ;
IF n^.setvalueF.type # NIL
THEN
outText (p, '(') ;
doTypeNameC (p, n^.setvalueF.type) ;
noSpace (p) ;
outText (p, ')') ;
setNeedSpace (p)
END ;
IF HighIndice (n^.setvalueF.values) = 0
THEN
outText (p, '0')
ELSE
i := LowIndice (n^.setvalueF.values) ;
h := HighIndice (n^.setvalueF.values) ;
outText (p, '(') ;
WHILE i<=h DO
outText (p, '(1') ;
setNeedSpace (p) ;
outText (p, '<<') ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, GetIndice (n^.setvalueF.values, i)) ;
doSubtractC (p, lo) ;
outText (p, ')') ;
outText (p, ')') ;
IF i<h
THEN
setNeedSpace (p) ;
outText (p, '|') ;
setNeedSpace (p)
END ;
INC (i)
END ;
outText (p, ')')
END
END doSetValueC ;
(*
getSetLow - returns the low value of the set type from
expression, n.
*)
PROCEDURE getSetLow (n: node) : node ;
VAR
type: node ;
BEGIN
IF getType (n) = NIL
THEN
RETURN makeLiteralInt (makeKey ('0'))
ELSE
type := skipType (getType (n)) ;
IF isSet (type)
THEN
RETURN getMin (skipType (getType (type)))
ELSE
RETURN makeLiteralInt (makeKey ('0'))
END
END
END getSetLow ;
(*
doInC - performs (((1 << (l)) & (r)) != 0)
*)
PROCEDURE doInC (p: pretty; l, r: node) ;
VAR
lo: node ;
BEGIN
lo := getSetLow (r) ;
outText (p, '(((1') ;
setNeedSpace (p) ;
outText (p, '<<') ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, l) ;
doSubtractC (p, lo) ;
outText (p, '))') ;
setNeedSpace (p) ;
outText (p, '&') ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, r) ;
outText (p, '))') ;
setNeedSpace (p) ;
outText (p, '!=') ;
setNeedSpace (p) ;
outText (p, '0)')
END doInC ;
(*
doThrowC -
*)
PROCEDURE doThrowC (p: pretty; n: node) ;
BEGIN
assert (isIntrinsic (n)) ;
outText (p, "throw") ;
setNeedSpace (p) ;
outText (p, '(') ;
IF expListLen (n^.intrinsicF.args) = 1
THEN
doExprC (p, getExpList (n^.intrinsicF.args, 1))
END ;
outText (p, ')')
END doThrowC ;
(*
doUnreachableC -
*)
PROCEDURE doUnreachableC (p: pretty; n: node) ;
BEGIN
assert (isIntrinsic (n)) ;
outText (p, "__builtin_unreachable") ;
setNeedSpace (p) ;
outText (p, '(') ;
assert (expListLen (n^.intrinsicF.args) = 0) ;
outText (p, ')')
END doUnreachableC ;
(*
outNull -
*)
PROCEDURE outNull (p: pretty) ;
BEGIN
keyc.useNull ;
outText (p, 'NULL')
END outNull ;
(*
outTrue -
*)
PROCEDURE outTrue (p: pretty) ;
BEGIN
keyc.useTrue ;
outText (p, 'TRUE')
END outTrue ;
(*
outFalse -
*)
PROCEDURE outFalse (p: pretty) ;
BEGIN
keyc.useFalse ;
outText (p, 'FALSE')
END outFalse ;
(*
doExprC -
*)
PROCEDURE doExprC (p: pretty; n: node) ;
VAR
t: node ;
BEGIN
assert (n#NIL) ;
t := getExprType (n) ;
WITH n^ DO
CASE kind OF
nil : outNull (p) |
true : outTrue (p) |
false : outFalse (p) |
constexp : doUnary (p, '', unaryF.arg, unaryF.resultType, FALSE, FALSE) |
neg : doUnary (p, '-', unaryF.arg, unaryF.resultType, FALSE, FALSE) |
not : doUnary (p, '!', unaryF.arg, unaryF.resultType, FALSE, TRUE) |
val : doValC (p, n) |
adr : doAdrC (p, n) |
size,
tsize : doSizeC (p, n) |
float : doConvertC (p, n, "(double)") |
trunc : doConvertC (p, n, "(int)") |
ord : doConvertC (p, n, "(unsigned int)") |
chr : doConvertC (p, n, "(char)") |
cap : doCapC (p, n) |
abs : doAbsC (p, n) |
high : doFuncHighC (p, n^.unaryF.arg) |
length : doLengthC (p, n) |
min : doMinC (p, n) |
max : doMaxC (p, n) |
throw : doThrowC (p, n) |
unreachable : doUnreachableC (p, n) |
re : doReC (p, n) |
im : doImC (p, n) |
cmplx : doCmplx (p, n) |
deref : doDeRefC (p, unaryF.arg) |
equal : doBinary (p, '==', binaryF.left, binaryF.right, TRUE, TRUE, TRUE) |
notequal : doBinary (p, '!=', binaryF.left, binaryF.right, TRUE, TRUE, TRUE) |
less : doBinary (p, '<', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
greater : doBinary (p, '>', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
greequal : doBinary (p, '>=', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
lessequal : doBinary (p, '<=', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
componentref : doComponentRefC (p, componentrefF.rec, componentrefF.field) |
pointerref : doPointerRefC (p, pointerrefF.ptr, pointerrefF.field) |
cast : doCastC (p, binaryF.left, binaryF.right) |
plus : doPolyBinary (p, plus, binaryF.left, binaryF.right, FALSE, FALSE) |
sub : doPolyBinary (p, sub, binaryF.left, binaryF.right, FALSE, FALSE) |
div : doBinary (p, '/', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
mod : doBinary (p, '%', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
mult : doPolyBinary (p, mult, binaryF.left, binaryF.right, FALSE, FALSE) |
divide : doPolyBinary (p, divide, binaryF.left, binaryF.right, FALSE, FALSE) |
in : doInC (p, binaryF.left, binaryF.right) |
and : doBinary (p, '&&', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
or : doBinary (p, '||', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
literal : doLiteralC (p, n) |
const : doConstExpr (p, n) |
enumerationfield: doEnumerationField (p, n) |
string : doStringC (p, n) |
var : doVar (p, n) |
arrayref : doArrayRef (p, n) |
funccall : doFuncExprC (p, n) |
procedure : doProcedure (p, n) |
recordfield : doRecordfield (p, n) |
setvalue : doSetValueC (p, n) |
char,
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
complex,
longcomplex,
shortcomplex,
real,
longreal,
shortreal,
bitset,
boolean,
proc : doBaseC (p, n) |
address,
loc,
byte,
word,
csizet,
cssizet : doSystemC (p, n) |
type : doTypeNameC (p, n) |
pointer : doTypeNameC (p, n)
END
END
END doExprC ;
(*
doExprCup -
*)
PROCEDURE doExprCup (p: pretty; n: node; unpackProc: BOOLEAN) ;
VAR
t: node ;
BEGIN
doExprC (p, n) ;
IF unpackProc
THEN
t := skipType (getExprType (n)) ;
IF (t # NIL) AND isAProcType (t)
THEN
outText (p, '.proc')
END
END
END doExprCup ;
(*
doExprM2 -
*)
PROCEDURE doExprM2 (p: pretty; n: node) ;
BEGIN
assert (n#NIL) ;
WITH n^ DO
CASE kind OF
nil : outText (p, 'NIL') |
true : outText (p, 'TRUE') |
false : outText (p, 'FALSE') |
constexp : doUnary (p, '', unaryF.arg, unaryF.resultType, FALSE, FALSE) |
neg : doUnary (p, '-', unaryF.arg, unaryF.resultType, FALSE, FALSE) |
not : doUnary (p, 'NOT', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
adr : doUnary (p, 'ADR', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
size : doUnary (p, 'SIZE', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
tsize : doUnary (p, 'TSIZE', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
float : doUnary (p, 'FLOAT', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
trunc : doUnary (p, 'TRUNC', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
ord : doUnary (p, 'ORD', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
chr : doUnary (p, 'CHR', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
cap : doUnary (p, 'CAP', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
high : doUnary (p, 'HIGH', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
re : doUnary (p, 'RE', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
im : doUnary (p, 'IM', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
deref : doPostUnary (p, '^', unaryF.arg) |
equal : doBinary (p, '=', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
notequal : doBinary (p, '#', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
less : doBinary (p, '<', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
greater : doBinary (p, '>', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
greequal : doBinary (p, '>=', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
lessequal : doBinary (p, '<=', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
componentref : doBinary (p, '.', componentrefF.rec, componentrefF.field, FALSE, FALSE, FALSE) |
pointerref : doBinary (p, '^.', pointerrefF.ptr, pointerrefF.field, FALSE, FALSE, FALSE) |
cast : doPreBinary (p, 'CAST', binaryF.left, binaryF.right, TRUE, TRUE) |
val : doPreBinary (p, 'VAL', binaryF.left, binaryF.right, TRUE, TRUE) |
cmplx : doPreBinary (p, 'CMPLX', binaryF.left, binaryF.right, TRUE, TRUE) |
plus : doBinary (p, '+', binaryF.left, binaryF.right, FALSE, FALSE, FALSE) |
sub : doBinary (p, '-', binaryF.left, binaryF.right, FALSE, FALSE, FALSE) |
div : doBinary (p, 'DIV', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
mod : doBinary (p, 'MOD', binaryF.left, binaryF.right, TRUE, TRUE, FALSE) |
mult : doBinary (p, '*', binaryF.left, binaryF.right, FALSE, FALSE, FALSE) |
divide : doBinary (p, '/', binaryF.left, binaryF.right, FALSE, FALSE, FALSE) |
literal : doLiteral (p, n) |
const : doConstExpr (p, n) |
enumerationfield: doEnumerationField (p, n) |
string : doString (p, n) |
max : doUnary (p, 'MAX', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
min : doUnary (p, 'MIN', unaryF.arg, unaryF.resultType, TRUE, TRUE) |
var : doVar (p, n)
END
END
END doExprM2 ;
(*
doVar -
*)
PROCEDURE doVar (p: pretty; n: node) ;
BEGIN
assert (isVar (n)) ;
IF n^.varF.isVarParameter
THEN
outText (p, '(*') ;
doFQDNameC (p, n, TRUE) ;
outText (p, ')')
ELSE
doFQDNameC (p, n, TRUE)
END
END doVar ;
(*
doLiteralC -
*)
PROCEDURE doLiteralC (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
assert (isLiteral (n)) ;
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
IF n^.literalF.type=charN
THEN
IF DynamicStrings.char (s, -1)='C'
THEN
s := DynamicStrings.Slice (DynamicStrings.Mark (s), 0, -1) ;
IF DynamicStrings.char (s, 0)#'0'
THEN
s := DynamicStrings.ConCat (InitString('0'), DynamicStrings.Mark (s))
END
END ;
outText (p, "(char)") ;
setNeedSpace (p)
ELSIF DynamicStrings.char (s, -1) = 'H'
THEN
outText (p, "0x") ;
s := DynamicStrings.Slice (DynamicStrings.Mark (s), 0, -1)
ELSIF DynamicStrings.char (s, -1) = 'B'
THEN
outText (p, "0") ;
s := DynamicStrings.Slice (DynamicStrings.Mark (s), 0, -1)
END ;
outTextS (p, s) ;
s := KillString (s)
END doLiteralC ;
(*
doLiteral -
*)
PROCEDURE doLiteral (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
assert (isLiteral (n)) ;
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
IF n^.literalF.type=charN
THEN
IF DynamicStrings.char (s, -1)='C'
THEN
s := DynamicStrings.Slice (DynamicStrings.Mark (s), 0, -1) ;
IF DynamicStrings.char (s, 0)#'0'
THEN
s := DynamicStrings.ConCat (InitString('0'), DynamicStrings.Mark (s))
END
END ;
outText (p, "(char)") ;
setNeedSpace (p)
END ;
outTextS (p, s) ;
s := KillString (s)
END doLiteral ;
(*
isString - returns TRUE if node, n, is a string.
*)
PROCEDURE isString (n: node) : BOOLEAN ;
BEGIN
assert (n#NIL) ;
RETURN n^.kind=string
END isString ;
(*
doString -
*)
PROCEDURE doString (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
assert (isString (n)) ;
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
outTextS (p, s) ;
s := KillString (s)
; HALT
(*
IF DynamicStrings.Index (s, '"', 0)=-1
THEN
outText (p, '"') ;
outTextS (p, s) ;
outText (p, '"')
ELSIF DynamicStrings.Index (s, "'", 0)=-1
THEN
outText (p, '"') ;
outTextS (p, s) ;
outText (p, '"')
ELSE
metaError1 ('illegal string {%1k}', n)
END
*)
END doString ;
(*
replaceChar - replace every occurance of, ch, by, a and return modified string, s.
*)
PROCEDURE replaceChar (s: String; ch: CHAR; a: ARRAY OF CHAR) : String ;
VAR
i: INTEGER ;
BEGIN
i := 0 ;
LOOP
i := DynamicStrings.Index (s, ch, i) ;
IF i = 0
THEN
s := ConCat (InitString (a), DynamicStrings.Slice (s, 1, 0)) ;
i := StrLen (a)
ELSIF i > 0
THEN
s := ConCat (ConCat (DynamicStrings.Slice (s, 0, i), Mark (InitString (a))), DynamicStrings.Slice (s, i+1, 0)) ;
INC (i, StrLen (a))
ELSE
RETURN s
END
END
END replaceChar ;
(*
toCstring - translates string, n, into a C string
and returns the new String.
*)
PROCEDURE toCstring (n: Name) : String ;
VAR
s: String ;
BEGIN
s := DynamicStrings.Slice (InitStringCharStar (keyToCharStar (n)), 1, -1) ;
RETURN replaceChar (replaceChar (s, '\', '\\'), '"', '\"')
END toCstring ;
(*
toCchar -
*)
PROCEDURE toCchar (n: Name) : String ;
VAR
s: String ;
BEGIN
s := DynamicStrings.Slice (InitStringCharStar (keyToCharStar (n)), 1, -1) ;
RETURN replaceChar (replaceChar (s, '\', '\\'), "'", "\'")
END toCchar ;
(*
countChar -
*)
PROCEDURE countChar (s: String; ch: CHAR) : CARDINAL ;
VAR
i: INTEGER ;
c: CARDINAL ;
BEGIN
c := 0 ;
i := 0 ;
LOOP
i := DynamicStrings.Index (s, ch, i) ;
IF i >= 0
THEN
INC (i) ;
INC (c)
ELSE
RETURN c
END
END
END countChar ;
(*
lenCstring -
*)
PROCEDURE lenCstring (s: String) : CARDINAL ;
BEGIN
RETURN DynamicStrings.Length (s) - countChar (s, '\')
END lenCstring ;
(*
outCstring -
*)
PROCEDURE outCstring (p: pretty; s: node; aString: BOOLEAN) ;
BEGIN
IF aString
THEN
outText (p, '"') ;
outRawS (p, s^.stringF.cstring) ;
outText (p, '"')
ELSE
outText (p, "'") ;
outRawS (p, s^.stringF.cchar) ;
outText (p, "'")
END
END outCstring ;
(*
doStringC -
*)
PROCEDURE doStringC (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
assert (isString (n)) ;
outCstring (p, n, NOT n^.stringF.isCharCompatible)
(*
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
IF DynamicStrings.Length (s)>3
THEN
IF DynamicStrings.Index (s, '"', 0)=-1
THEN
s := DynamicStrings.Slice (s, 1, -1) ;
outText (p, '"') ;
outCstring (p, s) ;
outText (p, '"')
ELSIF DynamicStrings.Index (s, "'", 0)=-1
THEN
s := DynamicStrings.Slice (s, 1, -1) ;
outText (p, '"') ;
outCstring (p, s) ;
outText (p, '"')
ELSE
metaError1 ('illegal string {%1k}', n)
END
ELSIF DynamicStrings.Length (s) = 3
THEN
s := DynamicStrings.Slice (s, 1, -1) ;
outText (p, "'") ;
IF DynamicStrings.char (s, 0) = "'"
THEN
outText (p, "\'")
ELSIF DynamicStrings.char (s, 0) = "\"
THEN
outText (p, "\\")
ELSE
outTextS (p, s)
END ;
outText (p, "'")
ELSE
outText (p, "'\0'")
END ;
s := KillString (s)
*)
END doStringC ;
(*
isPunct -
*)
PROCEDURE isPunct (ch: CHAR) : BOOLEAN ;
BEGIN
RETURN (ch = '.') OR (ch = '(') OR (ch = ')') OR
(ch = '^') OR (ch = ':') OR (ch = ';') OR
(ch = '{') OR (ch = '}') OR (ch = ',') OR
(ch = '*')
END isPunct ;
(*
isWhite -
*)
PROCEDURE isWhite (ch: CHAR) : BOOLEAN ;
BEGIN
RETURN (ch = ' ') OR (ch = tab) OR (ch = lf)
END isWhite ;
(*
outText -
*)
PROCEDURE outText (p: pretty; a: ARRAY OF CHAR) ;
VAR
s: String ;
BEGIN
s := InitString (a) ;
outTextS (p, s) ;
s := KillString (s)
END outText ;
(*
outRawS -
*)
PROCEDURE outRawS (p: pretty; s: String) ;
BEGIN
raw (p, s)
END outRawS ;
(*
outKm2 -
*)
PROCEDURE outKm2 (p: pretty; a: ARRAY OF CHAR) : pretty ;
VAR
i: CARDINAL ;
s: String ;
BEGIN
IF StrEqual (a, 'RECORD')
THEN
p := pushPretty (p) ;
i := getcurpos (p) ;
setindent (p, i) ;
outText (p, a) ;
p := pushPretty (p) ;
setindent (p, i + indentation)
ELSIF StrEqual (a, 'END')
THEN
p := popPretty (p) ;
outText (p, a) ;
p := popPretty (p)
END ;
RETURN p
END outKm2 ;
(*
outKc -
*)
PROCEDURE outKc (p: pretty; a: ARRAY OF CHAR) : pretty ;
VAR
i : INTEGER ;
c : CARDINAL ;
s, t: String ;
BEGIN
s := InitString (a) ;
i := DynamicStrings.Index (s, '\', 0) ;
IF i=-1
THEN
t := NIL
ELSE
t := DynamicStrings.Slice (s, i, 0) ;
s := DynamicStrings.Slice (Mark (s), 0, i)
END ;
IF DynamicStrings.char (s, 0)='{'
THEN
p := pushPretty (p) ;
c := getcurpos (p) ;
setindent (p, c) ;
outTextS (p, s) ;
p := pushPretty (p) ;
setindent (p, c + indentationC)
ELSIF DynamicStrings.char (s, 0)='}'
THEN
p := popPretty (p) ;
outTextS (p, s) ;
p := popPretty (p)
END ;
outTextS (p, t) ;
t := KillString (t) ;
s := KillString (s) ;
RETURN p
END outKc ;
(*
outTextS -
*)
PROCEDURE outTextS (p: pretty; s: String) ;
BEGIN
IF s # NIL
THEN
prints (p, s)
END
END outTextS ;
(*
outCard -
*)
PROCEDURE outCard (p: pretty; c: CARDINAL) ;
VAR
s: String ;
BEGIN
s := CardinalToString (c, 0, ' ', 10, FALSE) ;
outTextS (p, s) ;
s := KillString (s)
END outCard ;
(*
outTextN -
*)
PROCEDURE outTextN (p: pretty; n: Name) ;
VAR
s: String ;
BEGIN
s := InitStringCharStar (keyToCharStar (n)) ;
prints (p, s) ;
s := KillString (s)
END outTextN ;
(*
doTypeAliasC -
*)
PROCEDURE doTypeAliasC (p: pretty; n: node; VAR m: node) ;
BEGIN
print (p, "typedef") ; setNeedSpace (p) ;
IF isTypeHidden (n) AND (isDef (getMainModule ()) OR (getScope (n) # getMainModule ()))
THEN
outText (p, "void *")
ELSE
doTypeC (p, getType (n), m)
END ;
IF m#NIL
THEN
doFQNameC (p, m)
END ;
print (p, ';\n\n')
END doTypeAliasC ;
(*
doEnumerationC -
*)
PROCEDURE doEnumerationC (p: pretty; n: node) ;
VAR
i, h: CARDINAL ;
s : node ;
t : String ;
BEGIN
outText (p, "enum {") ;
i := LowIndice (n^.enumerationF.listOfSons) ;
h := HighIndice (n^.enumerationF.listOfSons) ;
WHILE i <= h DO
s := GetIndice (n^.enumerationF.listOfSons, i) ;
doFQDNameC (p, s, FALSE) ;
IF i < h
THEN
outText (p, ",") ; setNeedSpace (p)
END ;
INC (i)
END ;
outText (p, "}")
END doEnumerationC ;
(*
doNamesC -
*)
PROCEDURE doNamesC (p: pretty; n: Name) ;
VAR
s: String ;
BEGIN
s := InitStringCharStar (keyToCharStar (n)) ;
outTextS (p, s) ;
s := KillString (s)
END doNamesC ;
(*
doNameC -
*)
PROCEDURE doNameC (p: pretty; n: node) ;
BEGIN
IF (n#NIL) AND (getSymName (n)#NulName)
THEN
doNamesC (p, getSymName (n))
END
END doNameC ;
(*
initCname -
*)
PROCEDURE initCname (VAR c: cnameT) ;
BEGIN
c.init := FALSE
END initCname ;
(*
doCname -
*)
PROCEDURE doCname (n: Name; VAR c: cnameT; scopes: BOOLEAN) : Name ;
VAR
s: String ;
BEGIN
IF c.init
THEN
RETURN c.name
ELSE
c.init := TRUE ;
s := keyc.cname (n, scopes) ;
IF s=NIL
THEN
c.name := n
ELSE
c.name := makekey (DynamicStrings.string (s)) ;
s := KillString (s)
END ;
RETURN c.name
END
END doCname ;
(*
getDName -
*)
PROCEDURE getDName (n: node; scopes: BOOLEAN) : Name ;
VAR
m: Name ;
BEGIN
m := getSymName (n) ;
CASE n^.kind OF
procedure : RETURN doCname (m, n^.procedureF.cname, scopes) |
var : RETURN doCname (m, n^.varF.cname, scopes) |
recordfield : RETURN doCname (m, n^.recordfieldF.cname, scopes) |
enumerationfield: RETURN doCname (m, n^.enumerationfieldF.cname, scopes)
ELSE
END ;
RETURN m
END getDName ;
(*
doDNameC -
*)
PROCEDURE doDNameC (p: pretty; n: node; scopes: BOOLEAN) ;
BEGIN
IF (n#NIL) AND (getSymName (n)#NulName)
THEN
doNamesC (p, getDName (n, scopes))
END
END doDNameC ;
(*
doFQDNameC -
*)
PROCEDURE doFQDNameC (p: pretty; n: node; scopes: BOOLEAN) ;
VAR
s: String ;
BEGIN
s := getFQDstring (n, scopes) ;
outTextS (p, s) ;
s := KillString (s)
END doFQDNameC ;
(*
doFQNameC -
*)
PROCEDURE doFQNameC (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
s := getFQstring (n) ;
outTextS (p, s) ;
s := KillString (s)
END doFQNameC ;
(*
doNameM2 -
*)
PROCEDURE doNameM2 (p: pretty; n: node) ;
BEGIN
doNameC (p, n)
END doNameM2 ;
(*
doUsed -
*)
PROCEDURE doUsed (p: pretty; used: BOOLEAN) ;
BEGIN
IF NOT used
THEN
setNeedSpace (p) ;
outText (p, "__attribute__((unused))")
END
END doUsed ;
(*
doHighC -
*)
PROCEDURE doHighC (p: pretty; a: node; n: Name; isused: BOOLEAN) ;
BEGIN
IF isArray (a) AND isUnbounded (a)
THEN
(* need to display high. *)
print (p, ",") ; setNeedSpace (p) ;
doTypeNameC (p, cardinalN) ; setNeedSpace (p) ;
print (p, "_") ; outTextN (p, n) ; print (p, "_high") ;
doUsed (p, isused)
END
END doHighC ;
(*
doParamConstCast -
*)
PROCEDURE doParamConstCast (p: pretty; n: node) ;
VAR
ptype: node ;
BEGIN
ptype := getType (n) ;
IF isArray (ptype) AND isUnbounded (ptype) AND (lang = ansiCP)
THEN
outText (p, "const") ;
setNeedSpace (p)
END
END doParamConstCast ;
(*
getParameterVariable - returns the variable which shadows the parameter
named, m, in parameter block, n.
*)
PROCEDURE getParameterVariable (n: node; m: Name) : node ;
VAR
p: node ;
BEGIN
assert (isParam (n) OR isVarParam (n)) ;
IF isParam (n)
THEN
p := n^.paramF.scope
ELSE
p := n^.varparamF.scope
END ;
assert (isProcedure (p)) ;
RETURN lookupInScope (p, m)
END getParameterVariable ;
(*
doParamTypeEmit - emit parameter type for C/C++. It checks to see if the
parameter type is a procedure type and if it were declared
in a definition module for "C" and if so it uses the "C"
definition for a procedure type, rather than the mc
C++ version.
*)
PROCEDURE doParamTypeEmit (p: pretty; paramnode, paramtype: node) ;
BEGIN
assert (isParam (paramnode) OR isVarParam (paramnode)) ;
IF isForC (paramnode) AND isProcType (skipType (paramtype))
THEN
doFQNameC (p, paramtype) ;
outText (p, "_C")
ELSE
doTypeNameC (p, paramtype)
END
END doParamTypeEmit ;
(*
doParamC - emit parameter for C/C++.
*)
PROCEDURE doParamC (p: pretty; n: node) ;
VAR
v,
ptype: node ;
i : Name ;
c, t : CARDINAL ;
l : wlist ;
BEGIN
assert (isParam (n)) ;
ptype := getType (n) ;
IF n^.paramF.namelist = NIL
THEN
doParamConstCast (p, n) ;
doTypeNameC (p, ptype) ;
doUsed (p, n^.paramF.isUsed) ;
IF isArray (ptype) AND isUnbounded (ptype)
THEN
outText (p, ',') ; setNeedSpace (p) ;
outText (p, 'unsigned int')
END
ELSE
assert (isIdentList (n^.paramF.namelist)) ;
l := n^.paramF.namelist^.identlistF.names ;
IF l=NIL
THEN
doParamConstCast (p, n) ;
doParamTypeEmit (p, n, ptype) ;
IF isArray (ptype) AND isUnbounded (ptype)
THEN
doUsed (p, n^.paramF.isUsed) ;
outText (p, ',') ; setNeedSpace (p) ;
outText (p, 'unsigned int')
END
ELSE
t := wlists.noOfItemsInList (l) ;
c := 1 ;
WHILE c <= t DO
doParamConstCast (p, n) ;
doParamTypeEmit (p, n, ptype) ;
i := wlists.getItemFromList (l, c) ;
IF isArray (ptype) AND isUnbounded (ptype)
THEN
noSpace (p)
ELSE
setNeedSpace (p)
END ;
v := getParameterVariable (n, i) ;
IF v=NIL
THEN
doNamesC (p, keyc.cnamen (i, TRUE))
ELSE
doFQDNameC (p, v, TRUE)
END ;
IF isArray (ptype) AND isUnbounded (ptype)
THEN
outText (p, '_')
END ;
doUsed (p, n^.paramF.isUsed) ;
doHighC (p, ptype, i, n^.paramF.isUsed) ;
IF c<t
THEN
outText (p, ',') ; setNeedSpace (p)
END ;
INC (c)
END
END
END
END doParamC ;
(*
doVarParamC - emit a VAR parameter for C/C++.
*)
PROCEDURE doVarParamC (p: pretty; n: node) ;
VAR
v,
ptype: node ;
i : Name ;
c, t : CARDINAL ;
l : wlist ;
BEGIN
assert (isVarParam (n)) ;
ptype := getType (n) ;
IF n^.varparamF.namelist = NIL
THEN
doTypeNameC (p, ptype) ;
(* doTypeC (p, ptype, n) ; *)
IF NOT isArray (ptype)
THEN
setNeedSpace (p) ;
outText (p, "*")
END ;
doUsed (p, n^.varparamF.isUsed) ;
IF isArray (ptype) AND isUnbounded (ptype)
THEN
outText (p, ',') ; setNeedSpace (p) ;
outText (p, 'unsigned int')
END
ELSE
assert (isIdentList (n^.varparamF.namelist)) ;
l := n^.varparamF.namelist^.identlistF.names ;
IF l=NIL
THEN
doParamTypeEmit (p, n, ptype) ;
doUsed (p, n^.varparamF.isUsed)
ELSE
t := wlists.noOfItemsInList (l) ;
c := 1 ;
WHILE c <= t DO
doParamTypeEmit (p, n, ptype) ;
IF NOT isArray (ptype)
THEN
setNeedSpace (p) ;
outText (p, "*")
END ;
i := wlists.getItemFromList (l, c) ;
v := getParameterVariable (n, i) ;
IF v=NIL
THEN
doNamesC (p, keyc.cnamen (i, TRUE))
ELSE
doFQDNameC (p, v, TRUE)
END ;
doUsed (p, n^.varparamF.isUsed) ;
doHighC (p, ptype, i, n^.varparamF.isUsed) ;
IF c<t
THEN
outText (p, ',') ; setNeedSpace (p)
END ;
INC (c)
END
END
END
END doVarParamC ;
(*
doOptargC -
*)
PROCEDURE doOptargC (p: pretty; n: node) ;
VAR
ptype: node ;
i : Name ;
t : CARDINAL ;
l : wlist ;
BEGIN
assert (isOptarg (n)) ;
ptype := getType (n) ;
assert (n^.optargF.namelist # NIL) ;
assert (isIdentList (n^.paramF.namelist)) ;
l := n^.paramF.namelist^.identlistF.names ;
assert (l # NIL) ;
t := wlists.noOfItemsInList (l) ;
assert (t = 1) ;
doTypeNameC (p, ptype) ;
i := wlists.getItemFromList (l, 1) ;
setNeedSpace (p) ;
doNamesC (p, i)
END doOptargC ;
(*
doParameterC -
*)
PROCEDURE doParameterC (p: pretty; n: node) ;
BEGIN
IF isParam (n)
THEN
doParamC (p, n)
ELSIF isVarParam (n)
THEN
doVarParamC (p, n)
ELSIF isVarargs (n)
THEN
print (p, "...")
ELSIF isOptarg (n)
THEN
doOptargC (p, n)
END
END doParameterC ;
(*
doProcTypeC -
*)
PROCEDURE doProcTypeC (p: pretty; t, n: node) ;
BEGIN
assert (isType (t)) ;
outputPartial (t) ;
doCompletePartialProcType (p, t, n)
END doProcTypeC ;
(*
doTypesC -
*)
PROCEDURE doTypesC (n: node) ;
VAR
m: node ;
BEGIN
IF isType (n)
THEN
m := getType (n) ;
IF isProcType (m)
THEN
doProcTypeC (doP, n, m)
ELSIF isType (m) OR isPointer (m)
THEN
outText (doP, "typedef") ; setNeedSpace (doP) ;
doTypeC (doP, m, m) ;
IF isType (m)
THEN
setNeedSpace (doP)
END ;
doTypeNameC (doP, n) ;
outText (doP, ";\n\n")
ELSIF isEnumeration (m)
THEN
outText (doP, "typedef") ; setNeedSpace (doP) ;
doTypeC (doP, m, m) ;
setNeedSpace (doP) ;
doTypeNameC (doP, n) ;
outText (doP, ";\n\n")
ELSE
outText (doP, "typedef") ; setNeedSpace (doP) ;
doTypeC (doP, m, m) ;
IF isType (m)
THEN
setNeedSpace (doP)
END ;
doTypeNameC (doP, n) ;
outText (doP, ";\n\n")
END
END
END doTypesC ;
(*
doCompletePartialC -
*)
PROCEDURE doCompletePartialC (n: node) ;
VAR
m: node ;
BEGIN
IF isType (n)
THEN
m := getType (n) ;
IF isRecord (m)
THEN
doCompletePartialRecord (doP, n, m)
ELSIF isArray (m)
THEN
doCompletePartialArray (doP, n, m)
ELSIF isProcType (m)
THEN
doCompletePartialProcType (doP, n, m)
END
END
END doCompletePartialC ;
(*
doCompletePartialRecord -
*)
PROCEDURE doCompletePartialRecord (p: pretty; t, r: node) ;
VAR
i, h: CARDINAL ;
f : node ;
BEGIN
assert (isRecord (r)) ;
assert (isType (t)) ;
outText (p, "struct") ; setNeedSpace (p) ;
doFQNameC (p, t) ;
outText (p, "_r") ; setNeedSpace (p) ;
p := outKc (p, "{\n") ;
i := LowIndice (r^.recordF.listOfSons) ;
h := HighIndice (r^.recordF.listOfSons) ;
WHILE i<=h DO
f := GetIndice (r^.recordF.listOfSons, i) ;
IF isRecordField (f)
THEN
IF NOT f^.recordfieldF.tag
THEN
setNeedSpace (p) ;
doRecordFieldC (p, f) ;
outText (p, ";\n")
END
ELSIF isVarient (f)
THEN
doVarientC (p, f) ;
outText (p, ";\n")
ELSIF isVarientField (f)
THEN
doVarientFieldC (p, f)
END ;
INC (i)
END ;
p := outKc (p, "};\n\n")
END doCompletePartialRecord ;
(*
doCompletePartialArray -
*)
PROCEDURE doCompletePartialArray (p: pretty; t, r: node) ;
VAR
type, s: node ;
BEGIN
assert (isArray (r)) ;
type := r^.arrayF.type ;
s := NIL ;
outText (p, "struct") ; setNeedSpace (p) ;
doFQNameC (p, t) ;
outText (p, "_a {") ;
setNeedSpace (p) ;
doTypeC (p, type, s) ;
setNeedSpace (p) ;
outText (p, "array[") ;
doSubrC (p, r^.arrayF.subr) ;
outText (p, "];") ;
setNeedSpace (p) ;
outText (p, "};\n")
END doCompletePartialArray ;
(*
lookupConst -
*)
PROCEDURE lookupConst (type: node; n: Name) : node ;
BEGIN
RETURN makeLiteralInt (n)
END lookupConst ;
(*
doMin -
*)
PROCEDURE doMin (n: node) : node ;
BEGIN
IF n=booleanN
THEN
RETURN falseN
ELSIF n=integerN
THEN
keyc.useIntMin ;
RETURN lookupConst (integerN, makeKey ('INT_MIN'))
ELSIF n=cardinalN
THEN
keyc.useUIntMin ;
RETURN lookupConst (cardinalN, makeKey ('UINT_MIN'))
ELSIF n=longintN
THEN
keyc.useLongMin ;
RETURN lookupConst (longintN, makeKey ('LONG_MIN'))
ELSIF n=longcardN
THEN
keyc.useULongMin ;
RETURN lookupConst (longcardN, makeKey ('LONG_MIN'))
ELSIF n=charN
THEN
keyc.useCharMin ;
RETURN lookupConst (charN, makeKey ('CHAR_MIN'))
ELSIF n=bitsetN
THEN
assert (isSubrange (bitnumN)) ;
RETURN bitnumN^.subrangeF.low
ELSIF n=locN
THEN
keyc.useUCharMin ;
RETURN lookupConst (locN, makeKey ('UCHAR_MIN'))
ELSIF n=byteN
THEN
keyc.useUCharMin ;
RETURN lookupConst (byteN, makeKey ('UCHAR_MIN'))
ELSIF n=wordN
THEN
keyc.useUIntMin ;
RETURN lookupConst (wordN, makeKey ('UCHAR_MIN'))
ELSIF n=addressN
THEN
RETURN lookupConst (addressN, makeKey ('((void *) 0)'))
ELSE
HALT (* finish the cacading elsif statement. *)
END
END doMin ;
(*
doMax -
*)
PROCEDURE doMax (n: node) : node ;
BEGIN
IF n=booleanN
THEN
RETURN trueN
ELSIF n=integerN
THEN
keyc.useIntMax ;
RETURN lookupConst (integerN, makeKey ('INT_MAX'))
ELSIF n=cardinalN
THEN
keyc.useUIntMax ;
RETURN lookupConst (cardinalN, makeKey ('UINT_MAX'))
ELSIF n=longintN
THEN
keyc.useLongMax ;
RETURN lookupConst (longintN, makeKey ('LONG_MAX'))
ELSIF n=longcardN
THEN
keyc.useULongMax ;
RETURN lookupConst (longcardN, makeKey ('ULONG_MAX'))
ELSIF n=charN
THEN
keyc.useCharMax ;
RETURN lookupConst (charN, makeKey ('CHAR_MAX'))
ELSIF n=bitsetN
THEN
assert (isSubrange (bitnumN)) ;
RETURN bitnumN^.subrangeF.high
ELSIF n=locN
THEN
keyc.useUCharMax ;
RETURN lookupConst (locN, makeKey ('UCHAR_MAX'))
ELSIF n=byteN
THEN
keyc.useUCharMax ;
RETURN lookupConst (byteN, makeKey ('UCHAR_MAX'))
ELSIF n=wordN
THEN
keyc.useUIntMax ;
RETURN lookupConst (wordN, makeKey ('UINT_MAX'))
ELSIF n=addressN
THEN
metaError1 ('trying to obtain MAX ({%1ad}) is illegal', n) ;
RETURN NIL
ELSE
HALT (* finish the cacading elsif statement. *)
END
END doMax ;
(*
getMax -
*)
PROCEDURE getMax (n: node) : node ;
BEGIN
n := skipType (n) ;
IF isSubrange (n)
THEN
RETURN n^.subrangeF.high
ELSIF isEnumeration (n)
THEN
RETURN n^.enumerationF.high
ELSE
assert (isOrdinal (n)) ;
RETURN doMax (n)
END
END getMax ;
(*
getMin -
*)
PROCEDURE getMin (n: node) : node ;
BEGIN
n := skipType (n) ;
IF isSubrange (n)
THEN
RETURN n^.subrangeF.low
ELSIF isEnumeration (n)
THEN
RETURN n^.enumerationF.low
ELSE
assert (isOrdinal (n)) ;
RETURN doMin (n)
END
END getMin ;
(*
doSubtractC -
*)
PROCEDURE doSubtractC (p: pretty; s: node) ;
BEGIN
IF NOT isZero (s)
THEN
outText (p, "-") ;
doExprC (p, s)
END
END doSubtractC ;
(*
doSubrC -
*)
PROCEDURE doSubrC (p: pretty; s: node) ;
VAR
low, high: node ;
BEGIN
s := skipType (s) ;
IF isOrdinal (s)
THEN
low := getMin (s) ;
high := getMax (s) ;
doExprC (p, high) ;
doSubtractC (p, low) ;
outText (p, "+1")
ELSIF isEnumeration (s)
THEN
low := getMin (s) ;
high := getMax (s) ;
doExprC (p, high) ;
doSubtractC (p, low) ;
outText (p, "+1")
ELSE
assert (isSubrange (s)) ;
IF (s^.subrangeF.high = NIL) OR (s^.subrangeF.low = NIL)
THEN
doSubrC (p, getType (s))
ELSE
doExprC (p, s^.subrangeF.high) ;
doSubtractC (p, s^.subrangeF.low) ;
outText (p, "+1")
END
END
END doSubrC ;
(*
doCompletePartialProcType -
*)
PROCEDURE doCompletePartialProcType (p: pretty; t, n: node) ;
VAR
i, h: CARDINAL ;
v, u: node ;
BEGIN
assert (isProcType (n)) ;
u := NIL ;
outText (p, "typedef") ; setNeedSpace (p) ;
doTypeC (p, n^.proctypeF.returnType, u) ; setNeedSpace (p) ;
outText (p, "(*") ;
doFQNameC (p, t) ;
outText (p, "_t) (") ;
i := LowIndice (n^.proctypeF.parameters) ;
h := HighIndice (n^.proctypeF.parameters) ;
WHILE i <= h DO
v := GetIndice (n^.proctypeF.parameters, i) ;
doParameterC (p, v) ;
noSpace (p) ;
IF i < h
THEN
outText (p, ",") ; setNeedSpace (p)
END ;
INC (i)
END ;
IF h=0
THEN
outText (p, "void")
END ;
outText (p, ");\n") ;
IF isDefForCNode (n)
THEN
(* emit a C named type which differs from the m2 proctype. *)
outText (p, "typedef") ; setNeedSpace (p) ;
doFQNameC (p, t) ;
outText (p, "_t") ; setNeedSpace (p) ;
doFQNameC (p, t) ;
outText (p, "_C;\n\n")
END ;
outText (p, "struct") ; setNeedSpace (p) ;
doFQNameC (p, t) ;
outText (p, "_p {") ; setNeedSpace (p) ;
doFQNameC (p, t) ;
outText (p, "_t proc; };\n\n")
END doCompletePartialProcType ;
(*
isBase -
*)
PROCEDURE isBase (n: node) : BOOLEAN ;
BEGIN
CASE n^.kind OF
char,
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
complex,
longcomplex,
shortcomplex,
real,
longreal,
shortreal,
bitset,
boolean,
proc : RETURN TRUE
ELSE
RETURN FALSE
END
END isBase ;
(*
doBaseC -
*)
PROCEDURE doBaseC (p: pretty; n: node) ;
BEGIN
CASE n^.kind OF
char : outText (p, 'char') |
cardinal : outText (p, 'unsigned int') |
longcard : outText (p, 'long unsigned int') |
shortcard : outText (p, 'short unsigned int') |
integer : outText (p, 'int') |
longint : outText (p, 'long int') |
shortint : outText (p, 'short int') |
complex : outText (p, 'double complex') |
longcomplex : outText (p, 'long double complex') |
shortcomplex: outText (p, 'float complex') |
real : outText (p, 'double') |
longreal : outText (p, 'long double') |
shortreal : outText (p, 'float') |
bitset : outText (p, 'unsigned int') |
boolean : outText (p, 'unsigned int') |
proc : outText (p, 'PROC')
END ;
setNeedSpace (p)
END doBaseC ;
(*
isSystem -
*)
PROCEDURE isSystem (n: node) : BOOLEAN ;
BEGIN
CASE n^.kind OF
address: RETURN TRUE |
loc : RETURN TRUE |
byte : RETURN TRUE |
word : RETURN TRUE |
csizet : RETURN TRUE |
cssizet: RETURN TRUE
ELSE
RETURN FALSE
END
END isSystem ;
(*
doSystemC -
*)
PROCEDURE doSystemC (p: pretty; n: node) ;
BEGIN
CASE n^.kind OF
address: outText (p, 'void *') |
loc : outText (p, 'unsigned char') ; setNeedSpace (p) |
byte : outText (p, 'unsigned char') ; setNeedSpace (p) |
word : outText (p, 'unsigned int') ; setNeedSpace (p) |
csizet : outText (p, 'size_t') ; setNeedSpace (p) ; keyc.useSize_t |
cssizet: outText (p, 'ssize_t') ; setNeedSpace (p) ; keyc.useSSize_t
END
END doSystemC ;
(*
doArrayC -
*)
PROCEDURE doArrayC (p: pretty; n: node) ;
VAR
t, s, u: node ;
BEGIN
assert (isArray (n)) ;
t := n^.arrayF.type ;
s := n^.arrayF.subr ;
u := NIL ;
IF s=NIL
THEN
doTypeC (p, t, u) ;
setNeedSpace (p) ;
outText (p, "*")
ELSE
outText (p, "struct") ;
setNeedSpace (p) ;
outText (p, "{") ;
setNeedSpace (p) ;
doTypeC (p, t, u) ;
setNeedSpace (p) ;
outText (p, "array[") ;
IF isZero (getMin (s))
THEN
doExprC (p, getMax (s))
ELSE
doExprC (p, getMax (s)) ;
doSubtractC (p, getMin (s))
END ;
outText (p, "];") ;
setNeedSpace (p) ;
outText (p, "}") ;
setNeedSpace (p)
END
END doArrayC ;
(*
doPointerC -
*)
PROCEDURE doPointerC (p: pretty; n: node; VAR m: node) ;
VAR
t, s: node ;
BEGIN
t := n^.pointerF.type ;
s := NIL ;
doTypeC (p, t, s) ;
setNeedSpace (p) ;
outText (p, "*")
END doPointerC ;
(*
doRecordFieldC -
*)
PROCEDURE doRecordFieldC (p: pretty; f: node) ;
VAR
m: node ;
BEGIN
m := NIL ;
setNeedSpace (p) ;
doTypeC (p, f^.recordfieldF.type, m) ;
doDNameC (p, f, FALSE)
END doRecordFieldC ;
(*
doVarientFieldC -
*)
PROCEDURE doVarientFieldC (p: pretty; n: node) ;
VAR
i, t: CARDINAL ;
q : node ;
BEGIN
assert (isVarientField (n)) ;
IF NOT n^.varientfieldF.simple
THEN
outText (p, "struct") ; setNeedSpace (p) ;
p := outKc (p, "{\n")
END ;
i := LowIndice (n^.varientfieldF.listOfSons) ;
t := HighIndice (n^.varientfieldF.listOfSons) ;
WHILE i<=t DO
q := GetIndice (n^.varientfieldF.listOfSons, i) ;
IF isRecordField (q)
THEN
IF NOT q^.recordfieldF.tag
THEN
doRecordFieldC (p, q) ;
outText (p, ";\n")
END
ELSIF isVarient (q)
THEN
doVarientC (p, q) ;
outText (p, ";\n")
ELSE
HALT
END ;
INC (i)
END ;
IF NOT n^.varientfieldF.simple
THEN
p := outKc (p, "};\n")
END
END doVarientFieldC ;
(*
doVarientC -
*)
PROCEDURE doVarientC (p: pretty; n: node) ;
VAR
i, t: CARDINAL ;
q : node ;
BEGIN
assert (isVarient (n)) ;
IF n^.varientF.tag # NIL
THEN
IF isRecordField (n^.varientF.tag)
THEN
doRecordFieldC (p, n^.varientF.tag) ;
outText (p, "; /* case tag */\n")
ELSIF isVarientField (n^.varientF.tag)
THEN
HALT
(* doVarientFieldC (p, n^.varientF.tag) *)
ELSE
HALT
END
END ;
outText (p, "union") ;
setNeedSpace (p) ;
p := outKc (p, "{\n") ;
i := LowIndice (n^.varientF.listOfSons) ;
t := HighIndice (n^.varientF.listOfSons) ;
WHILE i<=t DO
q := GetIndice (n^.varientF.listOfSons, i) ;
IF isRecordField (q)
THEN
IF NOT q^.recordfieldF.tag
THEN
doRecordFieldC (p, q) ;
outText (p, ";\n")
END
ELSIF isVarientField (q)
THEN
doVarientFieldC (p, q)
ELSE
HALT
END ;
INC (i)
END ;
p := outKc (p, "}")
END doVarientC ;
(*
doRecordC -
*)
PROCEDURE doRecordC (p: pretty; n: node; VAR m: node) ;
VAR
i, h: CARDINAL ;
f : node ;
BEGIN
assert (isRecord (n)) ;
outText (p, "struct") ;
setNeedSpace (p) ;
p := outKc (p, "{") ;
i := LowIndice (n^.recordF.listOfSons) ;
h := HighIndice (n^.recordF.listOfSons) ;
setindent (p, getcurpos (p) + indentation) ;
outText (p, "\n") ;
WHILE i<=h DO
f := GetIndice (n^.recordF.listOfSons, i) ;
IF isRecordField (f)
THEN
IF NOT f^.recordfieldF.tag
THEN
doRecordFieldC (p, f) ;
outText (p, ";\n")
END
ELSIF isVarient (f)
THEN
doVarientC (p, f) ;
outText (p, ";\n")
ELSIF isVarientField (f)
THEN
doVarientFieldC (p, f)
END ;
INC (i)
END ;
p := outKc (p, "}") ;
setNeedSpace (p)
END doRecordC ;
(*
isBitset -
*)
PROCEDURE isBitset (n: node) : BOOLEAN ;
BEGIN
RETURN n = bitsetN
END isBitset ;
(*
isNegative - returns TRUE if expression, n, is negative.
*)
PROCEDURE isNegative (n: node) : BOOLEAN ;
BEGIN
(* --fixme-- needs to be completed. *)
RETURN FALSE
END isNegative ;
(*
doSubrangeC -
*)
PROCEDURE doSubrangeC (p: pretty; n: node) ;
BEGIN
assert (isSubrange (n)) ;
IF isNegative (n^.subrangeF.low)
THEN
outText (p, "int") ; setNeedSpace (p)
ELSE
outText (p, "unsigned int") ; setNeedSpace (p)
END
END doSubrangeC ;
(*
doSetC - generates a C type which holds the set.
Currently we only support sets of size WORD.
*)
PROCEDURE doSetC (p: pretty; n: node) ;
BEGIN
assert (isSet (n)) ;
outText (p, "unsigned int") ; setNeedSpace (p)
END doSetC ;
(*
doTypeC -
*)
PROCEDURE doTypeC (p: pretty; n: node; VAR m: node) ;
BEGIN
IF n=NIL
THEN
outText (p, "void")
ELSIF isBase (n)
THEN
doBaseC (p, n)
ELSIF isSystem (n)
THEN
doSystemC (p, n)
ELSIF isEnumeration (n)
THEN
doEnumerationC (p, n)
ELSIF isType (n)
THEN
doFQNameC (p, n) ;
setNeedSpace (p)
(* doTypeAliasC (p, n, n) *) (* type, n, has a name, so we choose this over, m. *)
(*
ELSIF isProcType (n) OR isArray (n) OR isRecord (n)
THEN
HALT (* n should have been simplified. *)
*)
ELSIF isProcType (n)
THEN
doProcTypeC (p, n, m)
ELSIF isArray (n)
THEN
doArrayC (p, n)
ELSIF isRecord (n)
THEN
doRecordC (p, n, m)
ELSIF isPointer (n)
THEN
doPointerC (p, n, m)
ELSIF isSubrange (n)
THEN
doSubrangeC (p, n)
ELSIF isSet (n)
THEN
doSetC (p, n)
ELSE
(* --fixme-- *)
print (p, "to do ... typedef etc etc ") ; doFQNameC (p, n) ; print (p, ";\n") ;
HALT
END
END doTypeC ;
(*
doArrayNameC - it displays the array declaration (it might be an unbounded).
*)
PROCEDURE doArrayNameC (p: pretty; n: node) ;
BEGIN
doTypeNameC (p, getType (n)) ; setNeedSpace (p) ; outText (p, "*")
END doArrayNameC ;
(*
doRecordNameC - emit the C/C++ record name <name of n>"_r".
*)
PROCEDURE doRecordNameC (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
s := getFQstring (n) ;
s := ConCat (s, Mark (InitString ("_r"))) ;
outTextS (p, s) ;
s := KillString (s)
END doRecordNameC ;
(*
doPointerNameC - emit the C/C++ pointer type <name of n>*.
*)
PROCEDURE doPointerNameC (p: pretty; n: node) ;
BEGIN
doTypeNameC (p, getType (n)) ; setNeedSpace (p) ; outText (p, "*")
END doPointerNameC ;
(*
doTypeNameC -
*)
PROCEDURE doTypeNameC (p: pretty; n: node) ;
VAR
t: String ;
BEGIN
IF n=NIL
THEN
outText (p, "void") ;
setNeedSpace (p)
ELSIF isBase (n)
THEN
doBaseC (p, n)
ELSIF isSystem (n)
THEN
doSystemC (p, n)
ELSIF isEnumeration (n)
THEN
print (p, "is enumeration type name required\n")
ELSIF isType (n)
THEN
doFQNameC (p, n) ;
ELSIF isProcType (n)
THEN
doFQNameC (p, n) ;
outText (p, "_t")
ELSIF isArray (n)
THEN
doArrayNameC (p, n)
ELSIF isRecord (n)
THEN
doRecordNameC (p, n)
ELSIF isPointer (n)
THEN
doPointerNameC (p, n)
ELSIF isSubrange (n)
THEN
doSubrangeC (p, n)
ELSE
print (p, "is type unknown required\n") ;
stop
END
END doTypeNameC ;
(*
isExternal - returns TRUE if symbol, n, was declared in another module.
*)
PROCEDURE isExternal (n: node) : BOOLEAN ;
VAR
s: node ;
BEGIN
s := getScope (n) ;
RETURN (s # NIL) AND isDef (s) AND
((isImp (getMainModule ()) AND (s # lookupDef (getSymName (getMainModule ())))) OR
isModule (getMainModule ()))
END isExternal ;
(*
doVarC -
*)
PROCEDURE doVarC (n: node) ;
VAR
s: node ;
BEGIN
IF isDef (getMainModule ())
THEN
print (doP, "EXTERN") ; setNeedSpace (doP)
ELSIF (NOT isExported (n)) AND (NOT isLocal (n))
THEN
print (doP, "static") ; setNeedSpace (doP)
ELSIF getExtendedOpaque ()
THEN
IF isExternal (n)
THEN
(* different module declared this variable, therefore it is extern. *)
print (doP, "extern") ; setNeedSpace (doP)
END
END ;
s := NIL ;
doTypeC (doP, getType (n), s) ;
setNeedSpace (doP) ;
doFQDNameC (doP, n, FALSE) ;
print (doP, ";\n")
END doVarC ;
(*
doExternCP -
*)
PROCEDURE doExternCP (p: pretty) ;
BEGIN
IF lang = ansiCP
THEN
outText (p, 'extern "C"') ; setNeedSpace (p)
END
END doExternCP ;
(*
doProcedureCommentText -
*)
PROCEDURE doProcedureCommentText (p: pretty; s: String) ;
BEGIN
(* remove \n from the start of the comment. *)
WHILE (DynamicStrings.Length (s) > 0) AND (DynamicStrings.char (s, 0) = lf) DO
s := DynamicStrings.Slice (s, 1, 0)
END ;
outTextS (p, s)
END doProcedureCommentText ;
(*
doProcedureComment -
*)
PROCEDURE doProcedureComment (p: pretty; s: String) ;
BEGIN
IF s # NIL
THEN
outText (p, '\n/*\n') ;
doProcedureCommentText (p, s) ;
outText (p, '*/\n\n')
END
END doProcedureComment ;
(*
doProcedureHeadingC -
*)
PROCEDURE doProcedureHeadingC (n: node; prototype: BOOLEAN) ;
VAR
i, h: CARDINAL ;
p, q: node ;
BEGIN
assert (isProcedure (n)) ;
noSpace (doP) ;
IF isDef (getMainModule ())
THEN
doProcedureComment (doP, getContent (n^.procedureF.defComment)) ;
outText (doP, "EXTERN") ; setNeedSpace (doP)
ELSIF isExported (n)
THEN
doProcedureComment (doP, getContent (n^.procedureF.modComment)) ;
doExternCP (doP)
ELSE
doProcedureComment (doP, getContent (n^.procedureF.modComment)) ;
outText (doP, "static") ; setNeedSpace (doP)
END ;
q := NIL ;
doTypeC (doP, n^.procedureF.returnType, q) ; setNeedSpace (doP) ;
doFQDNameC (doP, n, FALSE) ;
setNeedSpace (doP) ;
outText (doP, "(") ;
i := LowIndice (n^.procedureF.parameters) ;
h := HighIndice (n^.procedureF.parameters) ;
WHILE i <= h DO
p := GetIndice (n^.procedureF.parameters, i) ;
doParameterC (doP, p) ;
noSpace (doP) ;
IF i < h
THEN
print (doP, ",") ; setNeedSpace (doP)
END ;
INC (i)
END ;
IF h=0
THEN
outText (doP, "void")
END ;
print (doP, ")") ;
IF n^.procedureF.noreturn AND prototype
THEN
setNeedSpace (doP) ;
outText (doP, "__attribute__ ((noreturn))")
END
END doProcedureHeadingC ;
(*
checkDeclareUnboundedParamCopyC -
*)
PROCEDURE checkDeclareUnboundedParamCopyC (p: pretty; n: node) : BOOLEAN ;
VAR
t : node ;
i, c: CARDINAL ;
l : wlist ;
seen: BOOLEAN ;
BEGIN
seen := FALSE ;
t := getType (n) ;
l := n^.paramF.namelist^.identlistF.names ;
IF isArray (t) AND isUnbounded (t) AND (l#NIL)
THEN
t := getType (t) ;
c := wlists.noOfItemsInList (l) ;
i := 1 ;
WHILE i <= c DO
doTypeNameC (p, t) ;
setNeedSpace (p) ;
doNamesC (p, wlists.getItemFromList (l, i)) ;
outText (p, '[_');
doNamesC (p, wlists.getItemFromList (l, i)) ;
outText (p, '_high+1];\n');
seen := TRUE ;
INC (i)
END
END ;
RETURN seen
END checkDeclareUnboundedParamCopyC ;
(*
checkUnboundedParamCopyC -
*)
PROCEDURE checkUnboundedParamCopyC (p: pretty; n: node) ;
VAR
t, s: node ;
i, c: CARDINAL ;
l : wlist ;
BEGIN
t := getType (n) ;
l := n^.paramF.namelist^.identlistF.names ;
IF isArray (t) AND isUnbounded (t) AND (l#NIL)
THEN
c := wlists.noOfItemsInList (l) ;
i := 1 ;
t := getType (t) ;
s := skipType (t) ;
WHILE i <= c DO
keyc.useMemcpy ;
outText (p, 'memcpy (') ;
doNamesC (p, wlists.getItemFromList (l, i)) ;
outText (p, ',') ;
setNeedSpace (p) ;
doNamesC (p, wlists.getItemFromList (l, i)) ;
outText (p, '_, ') ;
IF (s = charN) OR (s = byteN) OR (s = locN)
THEN
outText (p, '_') ;
doNamesC (p, wlists.getItemFromList (l, i)) ;
outText (p, '_high+1);\n')
ELSE
outText (p, '(_') ;
doNamesC (p, wlists.getItemFromList (l, i)) ;
outText (p, '_high+1)') ;
setNeedSpace (p) ;
doMultiplyBySize (p, t) ;
outText (p, ');\n')
END ;
INC (i)
END
END
END checkUnboundedParamCopyC ;
(*
doUnboundedParamCopyC -
*)
PROCEDURE doUnboundedParamCopyC (p: pretty; n: node) ;
VAR
i, h: CARDINAL ;
q : node ;
seen: BOOLEAN ;
BEGIN
assert (isProcedure (n)) ;
i := LowIndice (n^.procedureF.parameters) ;
h := HighIndice (n^.procedureF.parameters) ;
seen := FALSE ;
WHILE i <= h DO
q := GetIndice (n^.procedureF.parameters, i) ;
IF isParam (q)
THEN
seen := checkDeclareUnboundedParamCopyC (p, q) OR seen
END ;
INC (i)
END ;
IF seen
THEN
outText (p, "\n") ;
outText (p, "/* make a local copy of each unbounded array. */\n") ;
i := LowIndice (n^.procedureF.parameters) ;
WHILE i <= h DO
q := GetIndice (n^.procedureF.parameters, i) ;
IF isParam (q)
THEN
checkUnboundedParamCopyC (p, q)
END ;
INC (i)
END
END
END doUnboundedParamCopyC ;
(*
doPrototypeC -
*)
PROCEDURE doPrototypeC (n: node) ;
BEGIN
IF NOT isExported (n)
THEN
keyc.enterScope (n) ;
doProcedureHeadingC (n, TRUE) ;
print (doP, ";\n") ;
keyc.leaveScope (n)
END
END doPrototypeC ;
(*
addTodo - adds, n, to the todo list.
*)
PROCEDURE addTodo (n: node) ;
BEGIN
IF (n#NIL) AND
(NOT alists.isItemInList (partialQ, n)) AND
(NOT alists.isItemInList (doneQ, n))
THEN
assert (NOT isVarient (n)) ;
assert (NOT isVarientField (n)) ;
assert (NOT isDef (n)) ;
alists.includeItemIntoList (todoQ, n)
END
END addTodo ;
(*
addVariablesTodo -
*)
PROCEDURE addVariablesTodo (n: node) ;
BEGIN
IF isVar (n)
THEN
IF n^.varF.isParameter OR n^.varF.isVarParameter
THEN
addDone (n) ;
addTodo (getType (n))
ELSE
addTodo (n)
END
END
END addVariablesTodo ;
(*
addTypesTodo -
*)
PROCEDURE addTypesTodo (n: node) ;
BEGIN
IF isUnbounded (n)
THEN
addDone (n)
ELSE
addTodo (n)
END
END addTypesTodo ;
(*
tempName -
*)
PROCEDURE tempName () : String ;
BEGIN
INC (tempCount) ;
RETURN Sprintf1 (InitString ("_T%d"), tempCount) ;
END tempName ;
(*
makeIntermediateType -
*)
PROCEDURE makeIntermediateType (s: String; p: node) : node ;
VAR
n: Name ;
o: node ;
BEGIN
n := makekey (DynamicStrings.string (s)) ;
enterScope (getScope (p)) ;
o := p ;
p := makeType (makekey (DynamicStrings.string (s))) ;
putType (p, o) ;
putTypeInternal (p) ;
leaveScope ;
RETURN p
END makeIntermediateType ;
(*
simplifyType -
*)
PROCEDURE simplifyType (l: alist; VAR p: node) ;
VAR
s: String ;
BEGIN
IF (p#NIL) AND (isRecord (p) OR isArray (p) OR isProcType (p)) AND (NOT isUnbounded (p))
THEN
s := tempName () ;
p := makeIntermediateType (s, p) ;
s := KillString (s) ;
simplified := FALSE
END ;
simplifyNode (l, p)
END simplifyType ;
(*
simplifyVar -
*)
PROCEDURE simplifyVar (l: alist; n: node) ;
VAR
i, t: CARDINAL ;
v,
d, o: node ;
BEGIN
assert (isVar (n)) ;
o := n^.varF.type ;
simplifyType (l, n^.varF.type) ;
IF o # n^.varF.type
THEN
(* simplification has occurred, make sure that all other variables of this type
use the new type. *)
d := n^.varF.decl ;
assert (isVarDecl (d)) ;
t := wlists.noOfItemsInList (d^.vardeclF.names) ;
i := 1 ;
WHILE i<=t DO
v := lookupInScope (n^.varF.scope, wlists.getItemFromList (d^.vardeclF.names, i)) ;
assert (isVar (v)) ;
v^.varF.type := n^.varF.type ;
INC (i)
END
END
END simplifyVar ;
(*
simplifyRecord -
*)
PROCEDURE simplifyRecord (l: alist; n: node) ;
VAR
i, t: CARDINAL ;
q : node ;
BEGIN
i := LowIndice (n^.recordF.listOfSons) ;
t := HighIndice (n^.recordF.listOfSons) ;
WHILE i<=t DO
q := GetIndice (n^.recordF.listOfSons, i) ;
simplifyNode (l, q) ;
INC (i)
END
END simplifyRecord ;
(*
simplifyVarient -
*)
PROCEDURE simplifyVarient (l: alist; n: node) ;
VAR
i, t: CARDINAL ;
q : node ;
BEGIN
simplifyNode (l, n^.varientF.tag) ;
i := LowIndice (n^.varientF.listOfSons) ;
t := HighIndice (n^.varientF.listOfSons) ;
WHILE i<=t DO
q := GetIndice (n^.varientF.listOfSons, i) ;
simplifyNode (l, q) ;
INC (i)
END
END simplifyVarient ;
(*
simplifyVarientField -
*)
PROCEDURE simplifyVarientField (l: alist; n: node) ;
VAR
i, t: CARDINAL ;
q : node ;
BEGIN
i := LowIndice (n^.varientfieldF.listOfSons) ;
t := HighIndice (n^.varientfieldF.listOfSons) ;
WHILE i<=t DO
q := GetIndice (n^.varientfieldF.listOfSons, i) ;
simplifyNode (l, q) ;
INC (i)
END
END simplifyVarientField ;
(*
doSimplifyNode -
*)
PROCEDURE doSimplifyNode (l: alist; n: node) ;
BEGIN
IF n=NIL
THEN
(* nothing. *)
ELSIF isType (n)
THEN
(* no need to simplify a type. *)
simplifyNode (l, getType (n))
ELSIF isVar (n)
THEN
simplifyVar (l, n)
ELSIF isRecord (n)
THEN
simplifyRecord (l, n)
ELSIF isRecordField (n)
THEN
simplifyType (l, n^.recordfieldF.type)
ELSIF isArray (n)
THEN
simplifyType (l, n^.arrayF.type)
ELSIF isVarient (n)
THEN
simplifyVarient (l, n)
ELSIF isVarientField (n)
THEN
simplifyVarientField (l, n)
ELSIF isPointer (n)
THEN
simplifyType (l, n^.pointerF.type)
END
END doSimplifyNode ;
(*
simplifyNode -
*)
PROCEDURE simplifyNode (l: alist; n: node) ;
BEGIN
IF NOT alists.isItemInList (l, n)
THEN
alists.includeItemIntoList (l, n) ;
doSimplifyNode (l, n)
END
END simplifyNode ;
(*
doSimplify -
*)
PROCEDURE doSimplify (n: node) ;
VAR
l: alist ;
BEGIN
l := alists.initList () ;
simplifyNode (l, n) ;
alists.killList (l)
END doSimplify ;
(*
simplifyTypes -
*)
PROCEDURE simplifyTypes (s: scopeT) ;
BEGIN
REPEAT
simplified := TRUE ;
ForeachIndiceInIndexDo (s.types, doSimplify) ;
ForeachIndiceInIndexDo (s.variables, doSimplify)
UNTIL simplified
END simplifyTypes ;
(*
outDeclsDefC -
*)
PROCEDURE outDeclsDefC (p: pretty; n: node) ;
VAR
s: scopeT ;
BEGIN
s := n^.defF.decls ;
simplifyTypes (s) ;
includeConstType (s) ;
doP := p ;
topologicallyOut (doConstC, doTypesC, doVarC,
outputPartial,
doNone, doCompletePartialC, doNone) ;
(* try and output types, constants before variables and procedures. *)
includeDefVarProcedure (n) ;
topologicallyOut (doConstC, doTypesC, doVarC,
outputPartial,
doNone, doCompletePartialC, doNone) ;
ForeachIndiceInIndexDo (s.procedures, doPrototypeC)
END outDeclsDefC ;
(*
includeConstType -
*)
PROCEDURE includeConstType (s: scopeT) ;
BEGIN
ForeachIndiceInIndexDo (s.constants, addTodo) ;
ForeachIndiceInIndexDo (s.types, addTypesTodo)
END includeConstType ;
(*
includeVarProcedure -
*)
PROCEDURE includeVarProcedure (s: scopeT) ;
BEGIN
ForeachIndiceInIndexDo (s.procedures, addTodo) ;
ForeachIndiceInIndexDo (s.variables, addVariablesTodo)
END includeVarProcedure ;
(*
includeVar -
*)
PROCEDURE includeVar (s: scopeT) ;
BEGIN
ForeachIndiceInIndexDo (s.variables, addTodo)
END includeVar ;
(*
includeExternals -
*)
PROCEDURE includeExternals (n: node) ;
VAR
l: alist ;
BEGIN
l := alists.initList () ;
visitNode (l, n, addExported) ;
alists.killList (l)
END includeExternals ;
(*
checkSystemInclude -
*)
PROCEDURE checkSystemInclude (n: node) ;
BEGIN
END checkSystemInclude ;
(*
addExported -
*)
PROCEDURE addExported (n: node) ;
VAR
s: node ;
BEGIN
s := getScope (n) ;
IF (s # NIL) AND isDef (s) AND (s # defModule)
THEN
IF isType (n) OR isVar (n) OR isConst (n)
THEN
addTodo (n)
END
END
END addExported ;
(*
addExternal - only adds, n, if this symbol is external to the
implementation module and is not a hidden type.
*)
PROCEDURE addExternal (n: node) ;
BEGIN
IF (getScope (n) = defModule) AND isType (n) AND
isTypeHidden (n) AND (NOT getExtendedOpaque ())
THEN
(* do nothing. *)
ELSIF NOT isDef (n)
THEN
addTodo (n)
END
END addExternal ;
(*
includeDefConstType -
*)
PROCEDURE includeDefConstType (n: node) ;
VAR
d: node ;
BEGIN
IF isImp (n)
THEN
defModule := lookupDef (getSymName (n)) ;
IF defModule#NIL
THEN
simplifyTypes (defModule^.defF.decls) ;
includeConstType (defModule^.defF.decls) ;
foreachNodeDo (defModule^.defF.decls.symbols, addExternal)
END
END
END includeDefConstType ;
(*
runIncludeDefConstType -
*)
PROCEDURE runIncludeDefConstType (n: node) ;
VAR
d: node ;
BEGIN
IF isDef (n)
THEN
simplifyTypes (n^.defF.decls) ;
includeConstType (n^.defF.decls) ;
foreachNodeDo (n^.defF.decls.symbols, addExternal)
END
END runIncludeDefConstType ;
(*
joinProcedures - copies procedures from definition module,
d, into implementation module, i.
*)
PROCEDURE joinProcedures (i, d: node) ;
VAR
h, j: CARDINAL ;
BEGIN
assert (isDef (d)) ;
assert (isImp (i)) ;
j := 1 ;
h := HighIndice (d^.defF.decls.procedures) ;
WHILE j<=h DO
IncludeIndiceIntoIndex (i^.impF.decls.procedures,
GetIndice (d^.defF.decls.procedures, j)) ;
INC (j)
END
END joinProcedures ;
(*
includeDefVarProcedure -
*)
PROCEDURE includeDefVarProcedure (n: node) ;
VAR
d: node ;
BEGIN
IF isImp (n)
THEN
defModule := lookupDef (getSymName (n)) ;
IF defModule#NIL
THEN
(*
includeVar (defModule^.defF.decls) ;
simplifyTypes (defModule^.defF.decls) ;
*)
joinProcedures (n, defModule)
END
ELSIF isDef (n)
THEN
includeVar (n^.defF.decls) ;
simplifyTypes (n^.defF.decls)
END
END includeDefVarProcedure ;
(*
foreachModuleDo -
*)
PROCEDURE foreachModuleDo (n: node; p: performOperation) ;
BEGIN
foreachDefModuleDo (p) ;
foreachModModuleDo (p)
END foreachModuleDo ;
(*
outDeclsImpC -
*)
PROCEDURE outDeclsImpC (p: pretty; s: scopeT) ;
BEGIN
simplifyTypes (s) ;
includeConstType (s) ;
doP := p ;
topologicallyOut (doConstC, doTypesC, doVarC,
outputPartial,
doNone, doCompletePartialC, doNone) ;
(* try and output types, constants before variables and procedures. *)
includeVarProcedure (s) ;
topologicallyOut (doConstC, doTypesC, doVarC,
outputPartial,
doNone, doCompletePartialC, doNone) ;
END outDeclsImpC ;
(*
doStatementSequenceC -
*)
PROCEDURE doStatementSequenceC (p: pretty; s: node) ;
VAR
i, h: CARDINAL ;
BEGIN
assert (isStatementSequence (s)) ;
h := HighIndice (s^.stmtF.statements) ;
i := 1 ;
WHILE i<=h DO
doStatementsC (p, GetIndice (s^.stmtF.statements, i)) ;
INC (i)
END
END doStatementSequenceC ;
(*
isStatementSequenceEmpty -
*)
PROCEDURE isStatementSequenceEmpty (s: node) : BOOLEAN ;
BEGIN
assert (isStatementSequence (s)) ;
RETURN HighIndice (s^.stmtF.statements) = 0
END isStatementSequenceEmpty ;
(*
isSingleStatement - returns TRUE if the statement sequence, s, has
only one statement.
*)
PROCEDURE isSingleStatement (s: node) : BOOLEAN ;
VAR
h: CARDINAL ;
BEGIN
assert (isStatementSequence (s)) ;
h := HighIndice (s^.stmtF.statements) ;
IF (h = 0) OR (h > 1)
THEN
RETURN FALSE
END ;
s := GetIndice (s^.stmtF.statements, 1) ;
RETURN (NOT isStatementSequence (s)) OR isSingleStatement (s)
END isSingleStatement ;
(*
doCommentC -
*)
PROCEDURE doCommentC (p: pretty; s: node) ;
VAR
c: String ;
BEGIN
IF s # NIL
THEN
assert (isComment (s)) ;
IF NOT isProcedureComment (s^.commentF.content)
THEN
IF isAfterComment (s^.commentF.content)
THEN
setNeedSpace (p) ;
outText (p, " /* ")
ELSE
outText (p, "/* ")
END ;
c := getContent (s^.commentF.content) ;
c := RemoveWhitePrefix (RemoveWhitePostfix (c)) ;
outTextS (p, c) ;
outText (p, " */\n")
END
END
END doCommentC ;
(*
doAfterCommentC - emit an after comment, c, or a newline if, c, is empty.
*)
PROCEDURE doAfterCommentC (p: pretty; c: node) ;
BEGIN
IF c = NIL
THEN
outText (p, "\n")
ELSE
doCommentC (p, c)
END
END doAfterCommentC ;
(*
doReturnC - issue a return statement and also place in an after comment if one exists.
*)
PROCEDURE doReturnC (p: pretty; s: node) ;
BEGIN
assert (isReturn (s)) ;
doCommentC (p, s^.returnF.returnComment.body) ;
outText (p, "return") ;
IF s^.returnF.scope#NIL
THEN
setNeedSpace (p) ;
IF (NOT isProcedure (s^.returnF.scope)) OR (getType (s^.returnF.scope)=NIL)
THEN
metaError1 ('{%1DMad} has no return type', s^.returnF.scope) ;
ELSE
doExprCastC (p, s^.returnF.exp, getType (s^.returnF.scope))
END
END ;
outText (p, ";") ;
doAfterCommentC (p, s^.returnF.returnComment.after)
END doReturnC ;
(*
isZtypeEquivalent -
*)
PROCEDURE isZtypeEquivalent (type: node) : BOOLEAN ;
BEGIN
CASE type^.kind OF
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
ztype : RETURN TRUE
ELSE
RETURN FALSE
END
END isZtypeEquivalent ;
(*
isEquivalentType - returns TRUE if type1 and type2 are equivalent.
*)
PROCEDURE isEquivalentType (type1, type2: node) : BOOLEAN ;
BEGIN
type1 := skipType (type1) ;
type2 := skipType (type2) ;
RETURN ((type1 = type2) OR
(isZtypeEquivalent (type1) AND isZtypeEquivalent (type2)))
END isEquivalentType ;
(*
doExprCastC - build a cast if necessary.
*)
PROCEDURE doExprCastC (p: pretty; e, type: node) ;
VAR
stype: node ;
BEGIN
stype := skipType (type) ;
IF (NOT isEquivalentType (type, getExprType (e))) AND
(NOT ((e^.kind = nil) AND (isPointer (stype) OR (stype^.kind = address))))
THEN
IF lang = ansiCP
THEN
(* potentially a cast is required. *)
IF isPointer (type) OR (type = addressN)
THEN
outText (p, 'reinterpret_cast<') ;
doTypeNameC (p, type) ;
noSpace (p) ;
outText (p, '> (') ;
doExprC (p, e) ;
outText (p, ')') ;
RETURN
ELSE
outText (p, 'static_cast<') ;
IF isProcType (skipType (type))
THEN
doTypeNameC (p, type) ;
outText (p, "_t")
ELSE
doTypeNameC (p, type)
END ;
noSpace (p) ;
outText (p, '> (') ;
doExprC (p, e) ;
outText (p, ')') ;
RETURN
END
END
END ;
doExprC (p, e)
END doExprCastC ;
(*
requiresUnpackProc - returns TRUE if either the expr is a procedure or the proctypes differ.
*)
PROCEDURE requiresUnpackProc (s: node) : BOOLEAN ;
BEGIN
assert (isAssignment (s)) ;
RETURN isProcedure (s^.assignmentF.expr) OR
(skipType (getType (s^.assignmentF.des)) # skipType (getType (s^.assignmentF.expr)))
END requiresUnpackProc ;
(*
doAssignmentC -
*)
PROCEDURE doAssignmentC (p: pretty; s: node) ;
BEGIN
assert (isAssignment (s)) ;
doCommentC (p, s^.assignmentF.assignComment.body) ;
doExprCup (p, s^.assignmentF.des, requiresUnpackProc (s)) ;
setNeedSpace (p) ;
outText (p, "=") ;
setNeedSpace (p) ;
doExprCastC (p, s^.assignmentF.expr, getType (s^.assignmentF.des)) ;
outText (p, ";") ;
doAfterCommentC (p, s^.assignmentF.assignComment.after)
END doAssignmentC ;
(*
containsStatement -
*)
PROCEDURE containsStatement (s: node) : BOOLEAN ;
BEGIN
RETURN (s # NIL) AND isStatementSequence (s) AND (NOT isStatementSequenceEmpty (s))
END containsStatement ;
(*
doCompoundStmt -
*)
PROCEDURE doCompoundStmt (p: pretty; s: node) ;
BEGIN
IF (s = NIL) OR (isStatementSequence (s) AND isStatementSequenceEmpty (s))
THEN
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
outText (p, "{} /* empty. */\n") ;
p := popPretty (p)
ELSIF isStatementSequence (s) AND isSingleStatement (s) AND (NOT forceCompoundStatement)
THEN
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
doStatementSequenceC (p, s) ;
p := popPretty (p)
ELSE
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
outText (p, "{\n") ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
doStatementSequenceC (p, s) ;
p := popPretty (p) ;
outText (p, "}\n") ;
p := popPretty (p)
END
END doCompoundStmt ;
(*
doElsifC -
*)
PROCEDURE doElsifC (p: pretty; s: node) ;
BEGIN
assert (isElsif (s)) ;
outText (p, "else if") ;
setNeedSpace (p) ;
outText (p, "(") ;
doExprC (p, s^.elsifF.expr) ;
outText (p, ")\n") ;
assert ((s^.elsifF.else = NIL) OR (s^.elsifF.elsif = NIL)) ;
IF forceCompoundStatement OR
(hasIfAndNoElse (s^.elsifF.then) AND
((s^.elsifF.else # NIL) OR (s^.elsifF.elsif # NIL)))
THEN
(* avoid dangling else. *)
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
outText (p, "{\n") ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
outText (p, "/* avoid dangling else. */\n") ;
doStatementSequenceC (p, s^.elsifF.then) ;
p := popPretty (p) ;
outText (p, "}\n") ;
p := popPretty (p)
ELSE
doCompoundStmt (p, s^.elsifF.then)
END ;
IF containsStatement (s^.elsifF.else)
THEN
outText (p, "else\n") ;
IF forceCompoundStatement
THEN
(* avoid dangling else. *)
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
outText (p, "{\n") ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
outText (p, "/* avoid dangling else. */\n") ;
doStatementSequenceC (p, s^.elsifF.else) ;
p := popPretty (p) ;
outText (p, "}\n") ;
p := popPretty (p)
ELSE
doCompoundStmt (p, s^.elsifF.else)
END
ELSIF (s^.elsifF.elsif#NIL) AND isElsif (s^.elsifF.elsif)
THEN
doElsifC (p, s^.elsifF.elsif)
END
END doElsifC ;
(*
noIfElse -
*)
PROCEDURE noIfElse (n: node) : BOOLEAN ;
BEGIN
RETURN (n # NIL) AND isIf (n) AND (n^.ifF.else = NIL) AND (n^.ifF.elsif = NIL)
END noIfElse ;
(*
noIfElseChained - returns TRUE if, n, is an IF statement which
has no associated ELSE statement. An IF with an
ELSIF is also checked for no ELSE and will result
in a return value of TRUE.
*)
PROCEDURE noIfElseChained (n: node) : BOOLEAN ;
VAR
e: node ;
BEGIN
IF n # NIL
THEN
IF isIf (n)
THEN
IF n^.ifF.else # NIL
THEN
(* we do have an else, continue to check this statement. *)
RETURN hasIfAndNoElse (n^.ifF.else)
ELSIF n^.ifF.elsif = NIL
THEN
(* neither else or elsif. *)
RETURN TRUE
ELSE
(* test elsif for lack of else. *)
e := n^.ifF.elsif ;
assert (isElsif (e)) ;
RETURN noIfElseChained (e)
END
ELSIF isElsif (n)
THEN
IF n^.elsifF.else # NIL
THEN
(* we do have an else, continue to check this statement. *)
RETURN hasIfAndNoElse (n^.elsifF.else)
ELSIF n^.elsifF.elsif = NIL
THEN
(* neither else or elsif. *)
RETURN TRUE
ELSE
(* test elsif for lack of else. *)
e := n^.elsifF.elsif ;
assert (isElsif (e)) ;
RETURN noIfElseChained (e)
END
END
END ;
RETURN FALSE
END noIfElseChained ;
(*
hasIfElse -
*)
PROCEDURE hasIfElse (n: node) : BOOLEAN ;
BEGIN
IF n # NIL
THEN
IF isStatementSequence (n)
THEN
IF isStatementSequenceEmpty (n)
THEN
RETURN FALSE
ELSIF isSingleStatement (n)
THEN
n := GetIndice (n^.stmtF.statements, 1) ;
RETURN isIfElse (n)
END
END
END ;
RETURN FALSE
END hasIfElse ;
(*
isIfElse -
*)
PROCEDURE isIfElse (n: node) : BOOLEAN ;
BEGIN
RETURN (n # NIL) AND isIf (n) AND ((n^.ifF.else # NIL) OR (n^.ifF.elsif # NIL))
END isIfElse ;
(*
hasIfAndNoElse - returns TRUE if statement, n, is a single statement
which is an IF and it has no else statement.
*)
PROCEDURE hasIfAndNoElse (n: node) : BOOLEAN ;
BEGIN
IF n # NIL
THEN
IF isStatementSequence (n)
THEN
IF isStatementSequenceEmpty (n)
THEN
RETURN FALSE
ELSIF isSingleStatement (n)
THEN
n := GetIndice (n^.stmtF.statements, 1) ;
RETURN hasIfAndNoElse (n)
ELSE
n := GetIndice (n^.stmtF.statements, HighIndice (n^.stmtF.statements)) ;
RETURN hasIfAndNoElse (n)
END
ELSIF isElsif (n) OR isIf (n)
THEN
RETURN noIfElseChained (n)
END
END ;
RETURN FALSE
END hasIfAndNoElse ;
(*
doIfC - issue an if statement and also place in an after comment if one exists.
The if statement might contain an else or elsif which are also handled.
*)
PROCEDURE doIfC (p: pretty; s: node) ;
BEGIN
assert (isIf (s)) ;
doCommentC (p, s^.ifF.ifComment.body) ;
outText (p, "if") ;
setNeedSpace (p) ;
outText (p, "(") ;
doExprC (p, s^.ifF.expr) ;
outText (p, ")") ;
doAfterCommentC (p, s^.ifF.ifComment.after) ;
IF hasIfAndNoElse (s^.ifF.then) AND
((s^.ifF.else # NIL) OR (s^.ifF.elsif # NIL))
THEN
(* avoid dangling else. *)
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
outText (p, "{\n") ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
outText (p, "/* avoid dangling else. */\n") ;
doStatementSequenceC (p, s^.ifF.then) ;
p := popPretty (p) ;
outText (p, "}\n") ;
p := popPretty (p)
ELSIF noIfElse (s) AND hasIfElse (s^.ifF.then)
THEN
(* gcc does not like legal non dangling else, as it is poor style.
So we will avoid getting a warning. *)
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
outText (p, "{\n") ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
outText (p, "/* avoid gcc warning by using compound statement even if not strictly necessary. */\n") ;
doStatementSequenceC (p, s^.ifF.then) ;
p := popPretty (p) ;
outText (p, "}\n") ;
p := popPretty (p)
ELSE
doCompoundStmt (p, s^.ifF.then)
END ;
assert ((s^.ifF.else = NIL) OR (s^.ifF.elsif = NIL)) ;
IF containsStatement (s^.ifF.else)
THEN
doCommentC (p, s^.ifF.elseComment.body) ;
outText (p, "else") ;
doAfterCommentC (p, s^.ifF.elseComment.after) ;
doCompoundStmt (p, s^.ifF.else)
ELSIF (s^.ifF.elsif#NIL) AND isElsif (s^.ifF.elsif)
THEN
doCommentC (p, s^.ifF.elseComment.body) ;
doCommentC (p, s^.ifF.elseComment.after) ;
doElsifC (p, s^.ifF.elsif)
END ;
doCommentC (p, s^.ifF.endComment.after) ;
doCommentC (p, s^.ifF.endComment.body)
END doIfC ;
(*
doForIncCP -
*)
PROCEDURE doForIncCP (p: pretty; s: node) ;
VAR
t: node ;
BEGIN
assert (isFor (s)) ;
t := skipType (getType (s^.forF.des)) ;
IF isEnumeration (t)
THEN
IF s^.forF.increment = NIL
THEN
doExprC (p, s^.forF.des) ;
outText (p, "= static_cast<") ;
doTypeNameC (p, getType (s^.forF.des)) ;
noSpace (p) ;
outText (p, ">(static_cast<int>(") ;
doExprC (p, s^.forF.des) ;
outText (p, "+1))")
ELSE
doExprC (p, s^.forF.des) ;
outText (p, "= static_cast<") ;
doTypeNameC (p, getType (s^.forF.des)) ;
noSpace (p) ;
outText (p, ">(static_cast<int>(") ;
doExprC (p, s^.forF.des) ;
outText (p, "+") ;
doExprC (p, s^.forF.increment) ;
outText (p, "))")
END
ELSE
doForIncC (p, s)
END
END doForIncCP ;
(*
doForIncC -
*)
PROCEDURE doForIncC (p: pretty; s: node) ;
BEGIN
IF s^.forF.increment = NIL
THEN
doExprC (p, s^.forF.des) ;
outText (p, "++")
ELSE
doExprC (p, s^.forF.des) ;
outText (p, "=") ;
doExprC (p, s^.forF.des) ;
outText (p, "+") ;
doExprC (p, s^.forF.increment)
END
END doForIncC ;
(*
doForInc -
*)
PROCEDURE doForInc (p: pretty; s: node) ;
BEGIN
IF lang = ansiCP
THEN
doForIncCP (p, s)
ELSE
doForIncC (p, s)
END
END doForInc ;
(*
doForC -
*)
PROCEDURE doForC (p: pretty; s: node) ;
BEGIN
assert (isFor (s)) ;
outText (p, "for (") ;
doExprC (p, s^.forF.des) ;
outText (p, "=") ;
doExprC (p, s^.forF.start) ;
outText (p, ";") ;
setNeedSpace (p) ;
doExprC (p, s^.forF.des) ;
outText (p, "<=") ;
doExprC (p, s^.forF.end) ;
outText (p, ";") ;
setNeedSpace (p) ;
doForInc (p, s) ;
outText (p, ")\n") ;
doCompoundStmt (p, s^.forF.statements)
END doForC ;
(*
doRepeatC -
*)
PROCEDURE doRepeatC (p: pretty; s: node) ;
BEGIN
assert (isRepeat (s)) ;
doCommentC (p, s^.repeatF.repeatComment.body) ;
outText (p, "do {") ;
doAfterCommentC (p, s^.repeatF.repeatComment.after) ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
doStatementSequenceC (p, s^.repeatF.statements) ;
doCommentC (p, s^.repeatF.untilComment.body) ;
p := popPretty (p) ;
outText (p, "} while (! (") ;
doExprC (p, s^.repeatF.expr) ;
outText (p, "));") ;
doAfterCommentC (p, s^.repeatF.untilComment.after)
END doRepeatC ;
(*
doWhileC -
*)
PROCEDURE doWhileC (p: pretty; s: node) ;
BEGIN
assert (isWhile (s)) ;
doCommentC (p, s^.whileF.doComment.body) ;
outText (p, "while (") ;
doExprC (p, s^.whileF.expr) ;
outText (p, ")") ;
doAfterCommentC (p, s^.whileF.doComment.after) ;
doCompoundStmt (p, s^.whileF.statements) ;
doCommentC (p, s^.whileF.endComment.body) ;
doCommentC (p, s^.whileF.endComment.after)
END doWhileC ;
(*
doFuncHighC -
*)
PROCEDURE doFuncHighC (p: pretty; a: node) ;
VAR
s, n: node ;
BEGIN
IF isLiteral (a) AND (getType (a) = charN)
THEN
outCard (p, 0)
ELSIF isString (a)
THEN
outCard (p, a^.stringF.length-2)
ELSIF isConst (a) AND isString (a^.constF.value)
THEN
doFuncHighC (p, a^.constF.value)
ELSIF isUnbounded (getType (a))
THEN
outText (p, '_') ;
outTextN (p, getSymName (a)) ;
outText (p, '_high')
ELSIF isArray (skipType (getType (a)))
THEN
n := skipType (getType (a)) ;
s := n^.arrayF.subr ;
IF isZero (getMin (s))
THEN
doExprC (p, getMax (s))
ELSE
outText (p, '(') ;
doExprC (p, getMax (s)) ;
doSubtractC (p, getMin (s)) ;
outText (p, ')')
END
ELSE
(* output sizeof (a) in bytes for the high. *)
outText (p, '(sizeof') ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, a) ;
outText (p, ')-1)')
END
END doFuncHighC ;
(*
doMultiplyBySize -
*)
PROCEDURE doMultiplyBySize (p: pretty; a: node) ;
BEGIN
IF (a # charN) AND (a # byteN) AND (a # locN)
THEN
setNeedSpace (p) ;
outText (p, '* sizeof (') ;
doTypeNameC (p, a) ;
noSpace (p) ;
outText (p, ')')
END
END doMultiplyBySize ;
(*
doTotype -
*)
PROCEDURE doTotype (p: pretty; a, t: node) ;
BEGIN
IF (NOT isString (a)) AND (NOT isLiteral (a))
THEN
IF isVar (a)
THEN
IF (a^.varF.isParameter OR a^.varF.isVarParameter) AND
isUnbounded (getType (a)) AND (skipType (getType (getType (a))) = skipType (getType (t)))
THEN
(* do not multiply by size as the existing high value is correct. *)
RETURN
END ;
a := getType (a) ;
IF isArray (a)
THEN
doMultiplyBySize (p, skipType (getType (a)))
END
END
END ;
IF t = wordN
THEN
setNeedSpace (p) ;
outText (p, '/ sizeof (') ;
doTypeNameC (p, wordN) ;
noSpace (p) ;
outText (p, ')')
END
END doTotype ;
(*
doFuncUnbounded -
*)
PROCEDURE doFuncUnbounded (p: pretty; actual, formalParam, formal, func: node) ;
VAR
h: node ;
s: String ;
BEGIN
assert (isUnbounded (formal)) ;
outText (p, '(') ;
IF (lang = ansiCP) AND isParam (formalParam)
THEN
outText (p, "const") ;
setNeedSpace (p)
END ;
doTypeC (p, getType (formal), formal) ;
setNeedSpace (p) ;
outText (p, '*)') ;
setNeedSpace (p) ;
IF isLiteral (actual) AND (getType (actual) = charN)
THEN
outText (p, '"\0') ;
s := InitStringCharStar (keyToCharStar (actual^.literalF.name)) ;
s := DynamicStrings.Slice (DynamicStrings.Mark (s), 0, -1) ;
outTextS (p, s) ;
outText (p, '"') ;
s := KillString (s)
ELSIF isString (actual)
THEN
outCstring (p, actual, TRUE)
ELSIF isConst (actual)
THEN
actual := resolveString (actual) ;
assert (isString (actual)) ;
outCstring (p, actual, TRUE)
ELSIF isFuncCall (actual)
THEN
IF getExprType (actual) = NIL
THEN
metaError3 ('there is no return type to the procedure function {%3ad} which is being passed as the parameter {%1ad} to {%2ad}', formal, func, actual)
ELSE
outText (p, '&') ;
doExprC (p, actual)
END
ELSIF isUnbounded (getType (actual))
THEN
doFQNameC (p, actual)
(* doExprC (p, actual). *)
ELSE
outText (p, '&') ;
doExprC (p, actual) ;
IF isArray (skipType (getType (actual)))
THEN
outText (p, '.array[0]')
END
END ;
IF NOT (enableDefForCStrings AND isDefForC (getScope (func)))
THEN
outText (p, ',') ;
setNeedSpace (p) ;
doFuncHighC (p, actual) ;
doTotype (p, actual, formal)
END
END doFuncUnbounded ;
(*
doProcedureParamC -
*)
PROCEDURE doProcedureParamC (p: pretty; actual, formal: node) ;
BEGIN
IF isForC (formal)
THEN
outText (p, '(') ;
doFQNameC (p, getType (formal)) ;
outText (p, "_C") ;
outText (p, ')') ;
setNeedSpace (p) ;
doExprC (p, actual)
ELSE
outText (p, '(') ;
doTypeNameC (p, getType (formal)) ;
outText (p, ')') ;
setNeedSpace (p) ;
outText (p, '{') ;
outText (p, '(') ;
doFQNameC (p, getType (formal)) ;
outText (p, '_t)') ;
setNeedSpace (p) ;
doExprC (p, actual) ;
outText (p, '}')
END
END doProcedureParamC ;
(*
doAdrExprC -
*)
PROCEDURE doAdrExprC (p: pretty; n: node) ;
BEGIN
IF isDeref (n)
THEN
(* (* no point in issuing & ( * n ) *) *)
doExprC (p, n^.unaryF.arg)
ELSIF isVar (n) AND n^.varF.isVarParameter
THEN
(* (* no point in issuing & ( * n ) *) *)
doFQNameC (p, n)
ELSE
outText (p, '&') ;
doExprC (p, n)
END
END doAdrExprC ;
(*
typePair -
*)
PROCEDURE typePair (a, b, x, y: node) : BOOLEAN ;
BEGIN
RETURN ((a = x) AND (b = y)) OR ((a = y) AND (b = x))
END typePair ;
(*
needsCast - return TRUE if the actual type parameter needs to be cast to
the formal type.
*)
PROCEDURE needsCast (at, ft: node) : BOOLEAN ;
BEGIN
at := skipType (at) ;
ft := skipType (ft) ;
IF (at = nilN) OR (at^.kind = nil) OR
(at = ft) OR
typePair (at, ft, cardinalN, wordN) OR
typePair (at, ft, cardinalN, ztypeN) OR
typePair (at, ft, integerN, ztypeN) OR
typePair (at, ft, longcardN, ztypeN) OR
typePair (at, ft, shortcardN, ztypeN) OR
typePair (at, ft, longintN, ztypeN) OR
typePair (at, ft, shortintN, ztypeN) OR
typePair (at, ft, realN, rtypeN) OR
typePair (at, ft, longrealN, rtypeN) OR
typePair (at, ft, shortrealN, rtypeN)
THEN
RETURN FALSE
ELSE
RETURN TRUE
END
END needsCast ;
(*
checkSystemCast - checks to see if we are passing to/from
a system generic type (WORD, BYTE, ADDRESS)
and if so emit a cast. It returns the number of
open parenthesis.
*)
PROCEDURE checkSystemCast (p: pretty; actual, formal: node) : CARDINAL ;
VAR
at, ft: node ;
BEGIN
at := getExprType (actual) ;
ft := getType (formal) ;
IF needsCast (at, ft)
THEN
IF lang = ansiCP
THEN
IF isString (actual) AND (skipType (ft) = addressN)
THEN
outText (p, "const_cast<void*> (reinterpret_cast<const void*> (") ;
RETURN 2
ELSIF isPointer (skipType (ft)) OR (skipType (ft) = addressN)
THEN
IF actual = nilN
THEN
IF isVarParam (formal)
THEN
metaError1 ('NIL is being passed to a VAR parameter {%1DMad}', formal)
END ;
(* NULL is compatible with pointers/address. *)
RETURN 0
ELSE
outText (p, 'reinterpret_cast<') ;
doTypeNameC (p, ft) ;
IF isVarParam (formal)
THEN
outText (p, '*')
END ;
noSpace (p) ;
outText (p, '> (')
END
ELSE
outText (p, 'static_cast<') ;
doTypeNameC (p, ft) ;
IF isVarParam (formal)
THEN
outText (p, '*')
END ;
noSpace (p) ;
outText (p, '> (')
END ;
RETURN 1
ELSE
outText (p, '(') ;
doTypeNameC (p, ft) ;
IF isVarParam (formal)
THEN
outText (p, '*')
END ;
noSpace (p) ;
outText (p, ')') ;
setNeedSpace (p)
END
END ;
RETURN 0
END checkSystemCast ;
(*
emitN -
*)
PROCEDURE emitN (p: pretty; a: ARRAY OF CHAR; n: CARDINAL) ;
BEGIN
WHILE n>0 DO
outText (p, a) ;
DEC (n)
END
END emitN ;
(*
isForC - return true if node n is a varparam, param or procedure
which was declared inside a definition module for "C".
*)
PROCEDURE isForC (n: node) : BOOLEAN ;
BEGIN
IF isVarParam (n)
THEN
RETURN n^.varparamF.isForC
ELSIF isParam (n)
THEN
RETURN n^.paramF.isForC
ELSIF isProcedure (n)
THEN
RETURN n^.procedureF.isForC
END ;
RETURN FALSE
END isForC ;
(*
isDefForCNode - return TRUE if node n was declared inside a definition module for "C".
*)
PROCEDURE isDefForCNode (n: node) : BOOLEAN ;
VAR
name: Name ;
BEGIN
WHILE (n # NIL) AND (NOT (isImp (n) OR isDef (n) OR isModule (n))) DO
n := getScope (n)
END ;
IF (n # NIL) AND isImp (n)
THEN
name := getSymName (n) ;
n := lookupDef (name) ;
END ;
RETURN (n # NIL) AND isDef (n) AND isDefForC (n)
END isDefForCNode ;
(*
doFuncParamC -
*)
PROCEDURE doFuncParamC (p: pretty; actual, formal, func: node) ;
VAR
ft, at: node ;
lbr : CARDINAL ;
BEGIN
IF formal = NIL
THEN
doExprC (p, actual)
ELSE
ft := skipType (getType (formal)) ;
IF isUnbounded (ft)
THEN
doFuncUnbounded (p, actual, formal, ft, func)
ELSE
IF isAProcType (ft) AND isProcedure (actual)
THEN
IF isVarParam (formal)
THEN
metaError1 ('{%1MDad} cannot be passed as a VAR parameter', actual)
ELSE
doProcedureParamC (p, actual, formal)
END
ELSIF (getType (actual) # NIL) AND isProcType (skipType (getType (actual))) AND isAProcType (ft) AND isForC (formal)
THEN
IF isVarParam (formal)
THEN
metaError2 ('{%1MDad} cannot be passed as a VAR parameter to the definition for C module as the parameter requires a cast to the formal type {%2MDtad}',
actual, formal)
ELSE
outText (p, '(') ;
doFQNameC (p, getType (formal)) ;
outText (p, "_C") ;
outText (p, ')') ;
setNeedSpace (p) ;
doExprC (p, actual) ;
outText (p, ".proc")
END
ELSIF (getType (actual) # NIL) AND isProcType (skipType (getType (actual))) AND (getType (actual) # getType (formal))
THEN
IF isVarParam (formal)
THEN
metaError2 ('{%1MDad} cannot be passed as a VAR parameter as the parameter requires a cast to the formal type {%2MDtad}',
actual, formal)
ELSE
doCastC (p, getType (formal), actual)
END
ELSE
lbr := checkSystemCast (p, actual, formal) ;
IF isVarParam (formal)
THEN
doAdrExprC (p, actual)
ELSE
doExprC (p, actual)
END ;
emitN (p, ")", lbr)
END
END
END
END doFuncParamC ;
(*
getNthParamType - return the type of parameter, i, in list, l.
If the parameter is a vararg NIL is returned.
*)
PROCEDURE getNthParamType (l: Index; i: CARDINAL) : node ;
VAR
p: node ;
BEGIN
p := getNthParam (l, i) ;
IF p # NIL
THEN
RETURN getType (p)
END ;
RETURN NIL
END getNthParamType ;
(*
getNthParam - return the parameter, i, in list, l.
If the parameter is a vararg NIL is returned.
*)
PROCEDURE getNthParam (l: Index; i: CARDINAL) : node ;
VAR
p : node ;
j, k, h: CARDINAL ;
BEGIN
IF l # NIL
THEN
j := LowIndice (l) ;
h := HighIndice (l) ;
WHILE j <= h DO
p := GetIndice (l, j) ;
IF isParam (p)
THEN
k := identListLen (p^.paramF.namelist)
ELSIF isVarParam (p)
THEN
k := identListLen (p^.varparamF.namelist)
ELSE
assert (isVarargs (p)) ;
RETURN NIL
END ;
IF i <= k
THEN
RETURN p
ELSE
DEC (i, k) ;
INC (j)
END
END
END ;
RETURN NIL
END getNthParam ;
(*
doFuncArgsC -
*)
PROCEDURE doFuncArgsC (p: pretty; s: node; l: Index; needParen: BOOLEAN) ;
VAR
actual, formal: node ;
i, n : CARDINAL ;
BEGIN
IF needParen
THEN
outText (p, "(")
END ;
IF s^.funccallF.args # NIL
THEN
i := 1 ;
n := expListLen (s^.funccallF.args) ;
WHILE i<=n DO
actual := getExpList (s^.funccallF.args, i) ;
formal := getNthParam (l, i) ;
doFuncParamC (p, actual, formal, s^.funccallF.function) ;
IF i<n
THEN
outText (p, ",") ;
setNeedSpace (p)
END ;
INC (i)
END
END ;
IF needParen
THEN
noSpace (p) ;
outText (p, ")")
END
END doFuncArgsC ;
(*
doProcTypeArgsC -
*)
PROCEDURE doProcTypeArgsC (p: pretty; s: node; args: Index; needParen: BOOLEAN) ;
VAR
a, b: node ;
i, n: CARDINAL ;
BEGIN
IF needParen
THEN
outText (p, "(")
END ;
IF s^.funccallF.args # NIL
THEN
i := 1 ;
n := expListLen (s^.funccallF.args) ;
WHILE i<=n DO
a := getExpList (s^.funccallF.args, i) ;
b := GetIndice (args, i) ;
doFuncParamC (p, a, b, s^.funccallF.function) ;
IF i<n
THEN
outText (p, ",") ;
setNeedSpace (p)
END ;
INC (i)
END
END ;
IF needParen
THEN
noSpace (p) ;
outText (p, ")")
END
END doProcTypeArgsC ;
(*
doAdrArgC -
*)
PROCEDURE doAdrArgC (p: pretty; n: node) ;
BEGIN
IF isDeref (n)
THEN
(* & and * cancel each other out. *)
doExprC (p, n^.unaryF.arg)
ELSIF isVar (n) AND (n^.varF.isVarParameter)
THEN
(* & and * cancel each other out. *)
outTextN (p, getSymName (n)) (* --fixme-- does the caller need to cast it? *)
ELSE
IF isString (n)
THEN
IF lang = ansiCP
THEN
outText (p, "const_cast<void*> (reinterpret_cast<const void*>") ;
outText (p, "(") ;
doExprC (p, n) ;
outText (p, "))")
ELSE
doExprC (p, n)
END
ELSE
outText (p, "&") ;
doExprC (p, n)
END
END
END doAdrArgC ;
(*
doAdrC -
*)
PROCEDURE doAdrC (p: pretty; n: node) ;
BEGIN
assert (isUnary (n)) ;
doAdrArgC (p, n^.unaryF.arg)
END doAdrC ;
(*
doInc -
*)
PROCEDURE doInc (p: pretty; n: node) ;
BEGIN
assert (isIntrinsic (n)) ;
IF lang = ansiCP
THEN
doIncDecCP (p, n, "+")
ELSE
doIncDecC (p, n, "+=")
END
END doInc ;
(*
doDec -
*)
PROCEDURE doDec (p: pretty; n: node) ;
BEGIN
assert (isIntrinsic (n)) ;
IF lang = ansiCP
THEN
doIncDecCP (p, n, "-")
ELSE
doIncDecC (p, n, "-=")
END
END doDec ;
(*
doIncDecC -
*)
PROCEDURE doIncDecC (p: pretty; n: node; op: ARRAY OF CHAR) ;
BEGIN
assert (isIntrinsic (n)) ;
IF n^.intrinsicF.args # NIL
THEN
doExprC (p, getExpList (n^.intrinsicF.args, 1)) ;
setNeedSpace (p) ;
outText (p, op) ;
setNeedSpace (p) ;
IF expListLen (n^.intrinsicF.args) = 1
THEN
outText (p, '1')
ELSE
doExprC (p, getExpList (n^.intrinsicF.args, 2))
END
END
END doIncDecC ;
(*
doIncDecCP -
*)
PROCEDURE doIncDecCP (p: pretty; n: node; op: ARRAY OF CHAR) ;
VAR
lhs,
type: node ;
BEGIN
assert (isIntrinsic (n)) ;
IF n^.intrinsicF.args # NIL
THEN
lhs := getExpList (n^.intrinsicF.args, 1) ;
doExprC (p, lhs) ;
setNeedSpace (p) ;
type := getType (lhs) ;
IF isPointer (type) OR (type = addressN)
THEN
(* cast to (char * ) and then back again after the arithmetic is complete. *)
outText (p, "=") ;
setNeedSpace (p) ;
outText (p, 'reinterpret_cast<') ;
doTypeNameC (p, type) ;
noSpace (p) ;
outText (p, '> (reinterpret_cast<char *> (') ;
doExprC (p, lhs) ;
noSpace (p) ;
outText (p, ')') ;
outText (p, op) ;
IF expListLen (n^.intrinsicF.args) = 1
THEN
outText (p, '1')
ELSE
doExprC (p, getExpList (n^.intrinsicF.args, 2))
END ;
outText (p, ')')
ELSIF isEnumeration (skipType (type))
THEN
outText (p, "= static_cast<") ;
doTypeNameC (p, type) ;
noSpace (p) ;
outText (p, ">(static_cast<int>(") ;
doExprC (p, lhs) ;
outText (p, ")") ;
outText (p, op) ;
IF expListLen (n^.intrinsicF.args) = 1
THEN
outText (p, '1')
ELSE
doExprC (p, getExpList (n^.intrinsicF.args, 2))
END ;
outText (p, ")")
ELSE
outText (p, op) ;
outText (p, "=") ;
setNeedSpace (p) ;
IF expListLen (n^.intrinsicF.args) = 1
THEN
outText (p, '1')
ELSE
doExprC (p, getExpList (n^.intrinsicF.args, 2))
END
END
END
END doIncDecCP ;
(*
doInclC -
*)
PROCEDURE doInclC (p: pretty; n: node) ;
VAR
lo: node ;
BEGIN
assert (isIntrinsic (n)) ;
IF n^.intrinsicF.args # NIL
THEN
IF expListLen (n^.intrinsicF.args) = 2
THEN
doExprC (p, getExpList (n^.intrinsicF.args, 1)) ;
lo := getSetLow (getExpList (n^.intrinsicF.args, 1)) ;
setNeedSpace (p) ;
outText (p, '|=') ;
setNeedSpace (p) ;
outText (p, '(1') ;
setNeedSpace (p) ;
outText (p, '<<') ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, getExpList (n^.intrinsicF.args, 2)) ;
doSubtractC (p, lo) ;
setNeedSpace (p) ;
outText (p, '))')
ELSE
HALT (* metaError0 ('expecting two parameters to INCL') *)
END
END
END doInclC ;
(*
doExclC -
*)
PROCEDURE doExclC (p: pretty; n: node) ;
VAR
lo: node ;
BEGIN
assert (isIntrinsic (n)) ;
IF n^.intrinsicF.args # NIL
THEN
IF expListLen (n^.intrinsicF.args) = 2
THEN
doExprC (p, getExpList (n^.intrinsicF.args, 1)) ;
lo := getSetLow (getExpList (n^.intrinsicF.args, 1)) ;
setNeedSpace (p) ;
outText (p, '&=') ;
setNeedSpace (p) ;
outText (p, '(~(1') ;
setNeedSpace (p) ;
outText (p, '<<') ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, getExpList (n^.intrinsicF.args, 2)) ;
doSubtractC (p, lo) ;
setNeedSpace (p) ;
outText (p, ')))')
ELSE
HALT (* metaError0 ('expecting two parameters to EXCL') *)
END
END
END doExclC ;
(*
doNewC -
*)
PROCEDURE doNewC (p: pretty; n: node) ;
VAR
t: node ;
BEGIN
assert (isIntrinsic (n)) ;
IF n^.intrinsicF.args = NIL
THEN
HALT
ELSE
IF expListLen (n^.intrinsicF.args) = 1
THEN
keyc.useStorage ;
outText (p, 'Storage_ALLOCATE') ;
setNeedSpace (p) ;
outText (p, '((void **)') ;
setNeedSpace (p) ;
outText (p, '&') ;
doExprC (p, getExpList (n^.intrinsicF.args, 1)) ;
outText (p, ',') ;
setNeedSpace (p) ;
t := skipType (getType (getExpList (n^.intrinsicF.args, 1))) ;
IF isPointer (t)
THEN
t := getType (t) ;
outText (p, 'sizeof') ;
setNeedSpace (p) ;
outText (p, '(') ;
doTypeNameC (p, t) ;
noSpace (p) ;
outText (p, '))')
ELSE
metaError1 ('expecting a pointer type variable as the argument to NEW, rather than {%1ad}', t)
END
END
END
END doNewC ;
(*
doDisposeC -
*)
PROCEDURE doDisposeC (p: pretty; n: node) ;
VAR
t: node ;
BEGIN
assert (isIntrinsic (n)) ;
IF n^.intrinsicF.args = NIL
THEN
HALT
ELSE
IF expListLen (n^.intrinsicF.args) = 1
THEN
keyc.useStorage ;
outText (p, 'Storage_DEALLOCATE') ;
setNeedSpace (p) ;
outText (p, '((void **)') ;
setNeedSpace (p) ;
outText (p, '&') ;
doExprC (p, getExpList (n^.intrinsicF.args, 1)) ;
outText (p, ',') ;
setNeedSpace (p) ;
t := skipType (getType (getExpList (n^.intrinsicF.args, 1))) ;
IF isPointer (t)
THEN
t := getType (t) ;
outText (p, 'sizeof') ;
setNeedSpace (p) ;
outText (p, '(') ;
doTypeNameC (p, t) ;
noSpace (p) ;
outText (p, '))')
ELSE
metaError1 ('expecting a pointer type variable as the argument to DISPOSE, rather than {%1ad}', t)
END
ELSE
HALT (* metaError0 ('expecting a single parameter to DISPOSE') *)
END
END
END doDisposeC ;
(*
doCapC -
*)
PROCEDURE doCapC (p: pretty; n: node) ;
BEGIN
assert (isUnary (n)) ;
IF n^.unaryF.arg = NIL
THEN
HALT (* metaError0 ('expecting a single parameter to CAP') *)
ELSE
keyc.useCtype ;
IF getGccConfigSystem ()
THEN
outText (p, 'TOUPPER')
ELSE
outText (p, 'toupper')
END ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, n^.unaryF.arg) ;
outText (p, ')')
END
END doCapC ;
(*
doLengthC -
*)
PROCEDURE doLengthC (p: pretty; n: node) ;
BEGIN
assert (isUnary (n)) ;
IF n^.unaryF.arg = NIL
THEN
HALT (* metaError0 ('expecting a single parameter to LENGTH') *)
ELSE
keyc.useM2RTS ;
outText (p, 'M2RTS_Length') ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, n^.unaryF.arg) ;
outText (p, ',') ;
setNeedSpace (p) ;
doFuncHighC (p, n^.unaryF.arg) ;
outText (p, ')')
END
END doLengthC ;
(*
doAbsC -
*)
PROCEDURE doAbsC (p: pretty; n: node) ;
VAR
t: node ;
BEGIN
assert (isUnary (n)) ;
IF n^.unaryF.arg = NIL
THEN
HALT
ELSE
t := getExprType (n)
END ;
IF t = longintN
THEN
keyc.useLabs ;
outText (p, "labs")
ELSIF t = integerN
THEN
keyc.useAbs ;
outText (p, "abs")
ELSIF t = realN
THEN
keyc.useFabs ;
outText (p, "fabs")
ELSIF t = longrealN
THEN
keyc.useFabsl ;
outText (p, "fabsl")
ELSIF t = cardinalN
THEN
(* do nothing. *)
ELSE
HALT
END ;
setNeedSpace (p) ;
outText (p, "(") ;
doExprC (p, n^.unaryF.arg) ;
outText (p, ")")
END doAbsC ;
(*
doValC -
*)
PROCEDURE doValC (p: pretty; n: node) ;
BEGIN
assert (isBinary (n)) ;
outText (p, '(') ;
doTypeNameC (p, n^.binaryF.left) ;
outText (p, ')') ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, n^.binaryF.right) ;
outText (p, ')')
END doValC ;
(*
doMinC -
*)
PROCEDURE doMinC (p: pretty; n: node) ;
VAR
t: node ;
BEGIN
assert (isUnary (n)) ;
t := getExprType (n^.unaryF.arg) ;
doExprC (p, getMin (t)) ;
END doMinC ;
(*
doMaxC -
*)
PROCEDURE doMaxC (p: pretty; n: node) ;
VAR
t: node ;
BEGIN
assert (isUnary (n)) ;
t := getExprType (n^.unaryF.arg) ;
doExprC (p, getMax (t)) ;
END doMaxC ;
(*
isIntrinsic - returns if, n, is an intrinsic procedure.
The intrinsic functions are represented as unary and binary nodes.
*)
PROCEDURE isIntrinsic (n: node) : BOOLEAN ;
BEGIN
CASE n^.kind OF
unreachable,
throw,
inc,
dec,
incl,
excl,
new,
dispose,
halt : RETURN TRUE
ELSE
RETURN FALSE
END
END isIntrinsic ;
(*
doHalt -
*)
PROCEDURE doHalt (p: pretty; n: node) ;
BEGIN
assert (n^.kind = halt) ;
IF (n^.intrinsicF.args = NIL) OR (expListLen (n^.intrinsicF.args) = 0)
THEN
outText (p, 'M2RTS_HALT') ;
setNeedSpace (p) ;
outText (p, '(-1)')
ELSIF expListLen (n^.intrinsicF.args) = 1
THEN
outText (p, 'M2RTS_HALT') ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, getExpList (n^.intrinsicF.args, 1)) ;
outText (p, ')')
END
END doHalt ;
(*
doCreal - emit the appropriate creal function.
*)
PROCEDURE doCreal (p: pretty; t: node) ;
BEGIN
CASE t^.kind OF
complex : keyc.useComplex ;
outText (p, "creal") |
longcomplex : keyc.useComplex ;
outText (p, "creall") |
shortcomplex: keyc.useComplex ;
outText (p, "crealf")
END
END doCreal ;
(*
doCimag - emit the appropriate cimag function.
*)
PROCEDURE doCimag (p: pretty; t: node) ;
BEGIN
CASE t^.kind OF
complex : keyc.useComplex ;
outText (p, "cimag") |
longcomplex : keyc.useComplex ;
outText (p, "cimagl") |
shortcomplex: keyc.useComplex ;
outText (p, "cimagf")
END
END doCimag ;
(*
doReC -
*)
PROCEDURE doReC (p: pretty; n: node) ;
VAR
t: node ;
BEGIN
assert (n^.kind = re) ;
IF n^.unaryF.arg # NIL
THEN
t := getExprType (n^.unaryF.arg)
ELSE
HALT
END ;
doCreal (p, t) ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, n^.unaryF.arg) ;
outText (p, ')')
END doReC ;
(*
doImC -
*)
PROCEDURE doImC (p: pretty; n: node) ;
VAR
t: node ;
BEGIN
assert (n^.kind = im) ;
IF n^.unaryF.arg # NIL
THEN
t := getExprType (n^.unaryF.arg)
ELSE
HALT
END ;
doCimag (p, t) ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, n^.unaryF.arg) ;
outText (p, ')')
END doImC ;
(*
doCmplx -
*)
PROCEDURE doCmplx (p: pretty; n: node) ;
BEGIN
assert (isBinary (n)) ;
keyc.useComplex ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, n^.binaryF.left) ;
outText (p, ')') ;
setNeedSpace (p) ;
outText (p, '+') ;
setNeedSpace (p) ;
outText (p, '(') ;
doExprC (p, n^.binaryF.right) ;
setNeedSpace (p) ;
outText (p, '*') ;
setNeedSpace (p) ;
outText (p, 'I') ;
outText (p, ')')
END doCmplx ;
(*
doIntrinsicC -
*)
PROCEDURE doIntrinsicC (p: pretty; n: node) ;
BEGIN
assert (isIntrinsic (n)) ;
doCommentC (p, n^.intrinsicF.intrinsicComment.body) ;
CASE n^.kind OF
unreachable: doUnreachableC (p, n) |
throw : doThrowC (p, n) |
halt : doHalt (p, n) |
inc : doInc (p, n) |
dec : doDec (p, n) |
incl : doInclC (p, n) |
excl : doExclC (p, n) |
new : doNewC (p, n) |
dispose : doDisposeC (p, n)
END ;
outText (p, ";") ;
doAfterCommentC (p, n^.intrinsicF.intrinsicComment.after)
END doIntrinsicC ;
(*
isIntrinsicFunction - returns true if, n, is an instrinsic function.
*)
PROCEDURE isIntrinsicFunction (n: node) : BOOLEAN ;
BEGIN
CASE n^.kind OF
val,
adr,
size,
tsize,
float,
trunc,
ord,
chr,
cap,
abs,
high,
length,
min,
max,
re,
im,
cmplx: RETURN TRUE
ELSE
RETURN FALSE
END
END isIntrinsicFunction ;
(*
doSizeC -
*)
PROCEDURE doSizeC (p: pretty; n: node) ;
BEGIN
assert (isUnary (n)) ;
outText (p, "sizeof (") ;
doExprC (p, n^.unaryF.arg) ;
outText (p, ")")
END doSizeC ;
(*
doConvertC -
*)
PROCEDURE doConvertC (p: pretty; n: node; conversion: ARRAY OF CHAR) ;
BEGIN
assert (isUnary (n)) ;
setNeedSpace (p) ;
outText (p, "(") ;
outText (p, conversion) ;
setNeedSpace (p) ;
outText (p, "(") ;
doExprC (p, n^.unaryF.arg) ;
outText (p, "))")
END doConvertC ;
(* not needed?
val: doValC (p, n) |
adr: doAdrC (p, n) |
size,
tsize: doSizeC (p, n) |
float: doConvertC (p, n, "(double)") |
trunc: doConvertC (p, n, "(int)") |
ord: doConvertC (p, n, "(unsigned int)") |
chr: doConvertC (p, n, "(char)") |
cap: doCapC (p, n) |
abs: doAbsC (p, n) |
high: doFuncHighC (p, n^.unaryF.arg, 1)) |
length: doLengthC (p, n) |
min: doMinC (p, n) |
max: doMaxC (p, n) |
throw: doThrowC (p, n) |
re: doReC (p, n) |
im: doImC (p, n) |
cmplx: doCmplx (p, n)
*)
(*
getFuncFromExpr -
*)
PROCEDURE getFuncFromExpr (n: node) : node ;
BEGIN
n := skipType (getType (n)) ;
WHILE (n # procN) AND (NOT isProcType (n)) DO
n := skipType (getType (n))
END ;
RETURN n
END getFuncFromExpr ;
(*
doFuncExprC -
*)
PROCEDURE doFuncExprC (p: pretty; n: node) ;
VAR
t: node ;
BEGIN
assert (isFuncCall (n)) ;
IF isProcedure (n^.funccallF.function)
THEN
doFQDNameC (p, n^.funccallF.function, TRUE) ;
setNeedSpace (p) ;
doFuncArgsC (p, n, n^.funccallF.function^.procedureF.parameters, TRUE)
ELSE
outText (p, "(*") ;
doExprC (p, n^.funccallF.function) ;
outText (p, ".proc") ;
outText (p, ")") ;
t := getFuncFromExpr (n^.funccallF.function) ;
setNeedSpace (p) ;
IF t = procN
THEN
doProcTypeArgsC (p, n, NIL, TRUE)
ELSE
assert (isProcType (t)) ;
doProcTypeArgsC (p, n, t^.proctypeF.parameters, TRUE)
END
END
END doFuncExprC ;
(*
doFuncCallC -
*)
PROCEDURE doFuncCallC (p: pretty; n: node) ;
BEGIN
doCommentC (p, n^.funccallF.funccallComment.body) ;
doFuncExprC (p, n) ;
outText (p, ";") ;
doAfterCommentC (p, n^.funccallF.funccallComment.after)
END doFuncCallC ;
(*
doCaseStatementC -
*)
PROCEDURE doCaseStatementC (p: pretty; n: node; needBreak: BOOLEAN) ;
BEGIN
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
doStatementSequenceC (p, n) ;
IF needBreak
THEN
outText (p, "break;\n")
END ;
p := popPretty (p)
END doCaseStatementC ;
(*
doExceptionC -
*)
PROCEDURE doExceptionC (p: pretty; a: ARRAY OF CHAR; n: node) ;
VAR
w: CARDINAL ;
BEGIN
w := getDeclaredMod (n) ;
outText (p, a) ;
setNeedSpace (p) ;
outText (p, '("') ;
outTextS (p, findFileNameFromToken (w, 0)) ;
outText (p, '",') ;
setNeedSpace (p) ;
outCard (p, tokenToLineNo (w, 0)) ;
outText (p, ',') ;
setNeedSpace (p) ;
outCard (p, tokenToColumnNo (w, 0)) ;
outText (p, ');\n') ;
outText (p, '__builtin_unreachable ();\n')
END doExceptionC ;
(*
doExceptionCP -
*)
PROCEDURE doExceptionCP (p: pretty; a: ARRAY OF CHAR; n: node) ;
VAR
w: CARDINAL ;
BEGIN
w := getDeclaredMod (n) ;
outText (p, a) ;
setNeedSpace (p) ;
outText (p, '("') ;
outTextS (p, findFileNameFromToken (w, 0)) ;
outText (p, '",') ;
setNeedSpace (p) ;
outCard (p, tokenToLineNo (w, 0)) ;
outText (p, ',') ;
setNeedSpace (p) ;
outCard (p, tokenToColumnNo (w, 0)) ;
outText (p, ');\n') ;
outText (p, '__builtin_unreachable ();\n')
END doExceptionCP ;
(*
doException -
*)
PROCEDURE doException (p: pretty; a: ARRAY OF CHAR; n: node) ;
BEGIN
keyc.useException ;
IF lang = ansiCP
THEN
doExceptionCP (p, a, n)
ELSE
doExceptionC (p, a, n)
END
END doException ;
(*
doRangeListC -
*)
PROCEDURE doRangeListC (p: pretty; c: node) ;
VAR
r : node ;
i, h: CARDINAL ;
BEGIN
assert (isCaseList (c)) ;
i := 1 ;
h := HighIndice (c^.caselistF.rangePairs) ;
WHILE i<=h DO
r := GetIndice (c^.caselistF.rangePairs, i) ;
assert ((r^.rangeF.hi = NIL) OR (r^.rangeF.lo = r^.rangeF.hi)) ;
outText (p, "case") ;
setNeedSpace (p) ;
doExprC (p, r^.rangeF.lo) ;
outText (p, ":\n") ;
INC (i)
END
END doRangeListC ;
(*
doRangeIfListC -
*)
PROCEDURE doRangeIfListC (p: pretty; e, c: node) ;
VAR
r : node ;
i, h: CARDINAL ;
BEGIN
assert (isCaseList (c)) ;
i := 1 ;
h := HighIndice (c^.caselistF.rangePairs) ;
WHILE i<=h DO
r := GetIndice (c^.caselistF.rangePairs, i) ;
IF (r^.rangeF.lo # r^.rangeF.hi) AND (r^.rangeF.hi # NIL)
THEN
outText (p, "((") ;
doExprC (p, e) ;
outText (p, ")") ;
setNeedSpace (p) ;
outText (p, ">=") ;
setNeedSpace (p) ;
doExprC (p, r^.rangeF.lo) ;
outText (p, ")") ;
setNeedSpace (p) ;
outText (p, "&&") ;
setNeedSpace (p) ;
outText (p, "((") ;
doExprC (p, e) ;
outText (p, ")") ;
setNeedSpace (p) ;
outText (p, "<=") ;
setNeedSpace (p) ;
doExprC (p, r^.rangeF.hi) ;
outText (p, ")")
ELSE
outText (p, "((") ;
doExprC (p, e) ;
outText (p, ")") ;
setNeedSpace (p) ;
outText (p, "==") ;
setNeedSpace (p) ;
doExprC (p, r^.rangeF.lo) ;
outText (p, ")")
END ;
IF i<h
THEN
setNeedSpace (p) ;
outText (p, "||") ;
setNeedSpace (p)
END ;
INC (i)
END
END doRangeIfListC ;
(*
doCaseLabels -
*)
PROCEDURE doCaseLabels (p: pretty; n: node; needBreak: BOOLEAN) ;
BEGIN
assert (isCaseLabelList (n)) ;
doRangeListC (p, n^.caselabellistF.caseList) ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
doStatementSequenceC (p, n^.caselabellistF.statements) ;
IF needBreak
THEN
outText (p, "break;\n\n")
END ;
p := popPretty (p)
END doCaseLabels ;
(*
doCaseLabelListC -
*)
PROCEDURE doCaseLabelListC (p: pretty; n: node; haveElse: BOOLEAN) ;
VAR
i, h: CARDINAL ;
c : node ;
BEGIN
assert (isCase (n)) ;
i := 1 ;
h := HighIndice (n^.caseF.caseLabelList) ;
WHILE i<=h DO
c := GetIndice (n^.caseF.caseLabelList, i) ;
doCaseLabels (p, c, (i<h) OR haveElse OR caseException) ;
INC (i)
END
END doCaseLabelListC ;
(*
doCaseIfLabels -
*)
PROCEDURE doCaseIfLabels (p: pretty; e, n: node;
i, h: CARDINAL) ;
BEGIN
assert (isCaseLabelList (n)) ;
IF i > 1
THEN
outText (p, "else") ;
setNeedSpace (p) ;
END ;
outText (p, "if") ;
setNeedSpace (p) ;
outText (p, "(") ;
doRangeIfListC (p, e, n^.caselabellistF.caseList) ;
outText (p, ")\n") ;
IF h = 1
THEN
doCompoundStmt (p, n^.caselabellistF.statements)
ELSE
outText (p, "{\n") ;
doStatementSequenceC (p, n^.caselabellistF.statements) ;
outText (p, "}\n")
END
END doCaseIfLabels ;
(*
doCaseIfLabelListC -
*)
PROCEDURE doCaseIfLabelListC (p: pretty; n: node) ;
VAR
i, h: CARDINAL ;
c : node ;
BEGIN
assert (isCase (n)) ;
i := 1 ;
h := HighIndice (n^.caseF.caseLabelList) ;
WHILE i<=h DO
c := GetIndice (n^.caseF.caseLabelList, i) ;
doCaseIfLabels (p, n^.caseF.expression, c, i, h) ;
INC (i)
END
END doCaseIfLabelListC ;
(*
doCaseElseC -
*)
PROCEDURE doCaseElseC (p: pretty; n: node) ;
BEGIN
assert (isCase (n)) ;
IF n^.caseF.else = NIL
THEN
IF caseException
THEN
outText (p, "\ndefault:\n") ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
doException (p, 'CaseException', n) ;
p := popPretty (p)
END
ELSE
outText (p, "\ndefault:\n") ;
doCaseStatementC (p, n^.caseF.else, TRUE)
END
END doCaseElseC ;
(*
doCaseIfElseC -
*)
PROCEDURE doCaseIfElseC (p: pretty; n: node) ;
BEGIN
assert (isCase (n)) ;
IF n^.caseF.else = NIL
THEN
IF TRUE
THEN
outText (p, "\n") ;
outText (p, "else {\n") ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
doException (p, 'CaseException', n) ;
p := popPretty (p) ;
outText (p, "}\n")
END
ELSE
outText (p, "\n") ;
outText (p, "else {\n") ;
doCaseStatementC (p, n^.caseF.else, FALSE) ;
outText (p, "}\n")
END
END doCaseIfElseC ;
(*
canUseSwitchCaseLabels - returns TRUE if all the case labels are
single values and not ranges.
*)
PROCEDURE canUseSwitchCaseLabels (n: node) : BOOLEAN ;
VAR
i, h: CARDINAL ;
r, l: node ;
BEGIN
assert (isCaseLabelList (n)) ;
l := n^.caselabellistF.caseList ;
i := 1 ;
h := HighIndice (l^.caselistF.rangePairs) ;
WHILE i<=h DO
r := GetIndice (l^.caselistF.rangePairs, i) ;
IF (r^.rangeF.hi # NIL) AND (r^.rangeF.lo # r^.rangeF.hi)
THEN
RETURN FALSE
END ;
INC (i)
END ;
RETURN TRUE
END canUseSwitchCaseLabels ;
(*
canUseSwitch - returns TRUE if the case statement can be implement
by a switch statement. This will be TRUE if all case
selectors are single values rather than ranges.
*)
PROCEDURE canUseSwitch (n: node) : BOOLEAN ;
VAR
i, h: CARDINAL ;
c : node ;
BEGIN
assert (isCase (n)) ;
i := 1 ;
h := HighIndice (n^.caseF.caseLabelList) ;
WHILE i<=h DO
c := GetIndice (n^.caseF.caseLabelList, i) ;
IF NOT canUseSwitchCaseLabels (c)
THEN
RETURN FALSE
END ;
INC (i)
END ;
RETURN TRUE
END canUseSwitch ;
(*
doCaseC -
*)
PROCEDURE doCaseC (p: pretty; n: node) ;
VAR
i: CARDINAL ;
BEGIN
assert (isCase (n)) ;
IF canUseSwitch (n)
THEN
i := getindent (p) ;
outText (p, "switch") ;
setNeedSpace (p) ;
outText (p, "(") ;
doExprC (p, n^.caseF.expression) ;
p := pushPretty (p) ;
outText (p, ")") ;
setindent (p, i + indentationC) ;
outText (p, "\n{\n") ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
doCaseLabelListC (p, n, n^.caseF.else # NIL) ;
doCaseElseC (p, n) ;
p := popPretty (p) ;
outText (p, "}\n") ;
p := popPretty (p)
ELSE
doCaseIfLabelListC (p, n) ;
doCaseIfElseC (p, n)
END
END doCaseC ;
(*
doLoopC -
*)
PROCEDURE doLoopC (p: pretty; s: node) ;
BEGIN
assert (isLoop (s)) ;
outText (p, 'for (;;)\n') ;
outText (p, "{\n") ;
p := pushPretty (p) ;
setindent (p, getindent (p) + indentationC) ;
doStatementSequenceC (p, s^.loopF.statements) ;
p := popPretty (p) ;
outText (p, "}\n")
END doLoopC ;
(*
doExitC -
*)
PROCEDURE doExitC (p: pretty; s: node) ;
BEGIN
assert (isExit (s)) ;
outText (p, "/* exit. */\n")
END doExitC ;
(*
doStatementsC -
*)
PROCEDURE doStatementsC (p: pretty; s: node) ;
BEGIN
IF s = NIL
THEN
(* do nothing. *)
ELSIF isStatementSequence (s)
THEN
doStatementSequenceC (p, s)
ELSIF isComment (s)
THEN
doCommentC (p, s)
ELSIF isExit (s)
THEN
doExitC (p, s)
ELSIF isReturn (s)
THEN
doReturnC (p, s)
ELSIF isAssignment (s)
THEN
doAssignmentC (p, s)
ELSIF isIf (s)
THEN
doIfC (p, s)
ELSIF isFor (s)
THEN
doForC (p, s)
ELSIF isRepeat (s)
THEN
doRepeatC (p, s)
ELSIF isWhile (s)
THEN
doWhileC (p, s)
ELSIF isIntrinsic (s)
THEN
doIntrinsicC (p, s)
ELSIF isFuncCall (s)
THEN
doFuncCallC (p, s)
ELSIF isCase (s)
THEN
doCaseC (p, s)
ELSIF isLoop (s)
THEN
doLoopC (p, s)
ELSIF isExit (s)
THEN
doExitC (p, s)
ELSE
HALT (* need to handle another s^.kind. *)
END
END doStatementsC ;
PROCEDURE stop ; END stop ;
(*
doLocalVarC -
*)
PROCEDURE doLocalVarC (p: pretty; s: scopeT) ;
BEGIN
includeVarProcedure (s) ;
debugLists ;
topologicallyOut (doConstC, doTypesC, doVarC,
outputPartial,
doNone, doCompletePartialC, doNone)
END doLocalVarC ;
(*
doLocalConstTypesC -
*)
PROCEDURE doLocalConstTypesC (p: pretty; s: scopeT) ;
BEGIN
simplifyTypes (s) ;
includeConstType (s) ;
doP := p ;
topologicallyOut (doConstC, doTypesC, doVarC,
outputPartial,
doNone, doCompletePartialC, doNone) ;
END doLocalConstTypesC ;
(*
addParamDone -
*)
PROCEDURE addParamDone (n: node) ;
BEGIN
IF isVar (n) AND n^.varF.isParameter
THEN
addDone (n) ;
addDone (getType (n))
END
END addParamDone ;
(*
includeParameters -
*)
PROCEDURE includeParameters (n: node) ;
BEGIN
assert (isProcedure (n)) ;
ForeachIndiceInIndexDo (n^.procedureF.decls.variables, addParamDone)
END includeParameters ;
(*
isHalt -
*)
PROCEDURE isHalt (n: node) : BOOLEAN ;
BEGIN
RETURN n^.kind = halt
END isHalt ;
(*
isReturnOrHalt -
*)
PROCEDURE isReturnOrHalt (n: node) : BOOLEAN ;
BEGIN
RETURN isHalt (n) OR isReturn (n)
END isReturnOrHalt ;
(*
isLastStatementReturn -
*)
PROCEDURE isLastStatementReturn (n: node) : BOOLEAN ;
BEGIN
RETURN isLastStatement (n, isReturnOrHalt)
END isLastStatementReturn ;
(*
isLastStatementSequence -
*)
PROCEDURE isLastStatementSequence (n: node; q: isNodeF) : BOOLEAN ;
VAR
h : CARDINAL ;
BEGIN
assert (isStatementSequence (n)) ;
h := HighIndice (n^.stmtF.statements) ;
IF h > 0
THEN
RETURN isLastStatement (GetIndice (n^.stmtF.statements, h), q)
END ;
RETURN FALSE
END isLastStatementSequence ;
(*
isLastStatementIf -
*)
PROCEDURE isLastStatementIf (n: node; q: isNodeF) : BOOLEAN ;
VAR
ret: BOOLEAN ;
BEGIN
assert (isIf (n)) ;
ret := TRUE ;
IF (n^.ifF.elsif # NIL) AND ret
THEN
ret := isLastStatement (n^.ifF.elsif, q)
END ;
IF (n^.ifF.then # NIL) AND ret
THEN
ret := isLastStatement (n^.ifF.then, q)
END ;
IF (n^.ifF.else # NIL) AND ret
THEN
ret := isLastStatement (n^.ifF.else, q)
END ;
RETURN ret
END isLastStatementIf ;
(*
isLastStatementElsif -
*)
PROCEDURE isLastStatementElsif (n: node; q: isNodeF) : BOOLEAN ;
VAR
ret: BOOLEAN ;
BEGIN
assert (isElsif (n)) ;
ret := TRUE ;
IF (n^.elsifF.elsif # NIL) AND ret
THEN
ret := isLastStatement (n^.elsifF.elsif, q)
END ;
IF (n^.elsifF.then # NIL) AND ret
THEN
ret := isLastStatement (n^.elsifF.then, q)
END ;
IF (n^.elsifF.else # NIL) AND ret
THEN
ret := isLastStatement (n^.elsifF.else, q)
END ;
RETURN ret
END isLastStatementElsif ;
(*
isLastStatementCase -
*)
PROCEDURE isLastStatementCase (n: node; q: isNodeF) : BOOLEAN ;
VAR
ret : BOOLEAN ;
i, h: CARDINAL ;
c : node ;
BEGIN
ret := TRUE ;
assert (isCase (n)) ;
i := 1 ;
h := HighIndice (n^.caseF.caseLabelList) ;
WHILE i<=h DO
c := GetIndice (n^.caseF.caseLabelList, i) ;
assert (isCaseLabelList (c)) ;
ret := ret AND isLastStatement (c^.caselabellistF.statements, q) ;
INC (i)
END ;
IF n^.caseF.else # NIL
THEN
ret := ret AND isLastStatement (n^.caseF.else, q)
END ;
RETURN ret
END isLastStatementCase ;
(*
isLastStatement - returns TRUE if the last statement in, n, is, q.
*)
PROCEDURE isLastStatement (n: node; q: isNodeF) : BOOLEAN ;
VAR
ret: BOOLEAN ;
BEGIN
IF n = NIL
THEN
RETURN FALSE
ELSIF isStatementSequence (n)
THEN
RETURN isLastStatementSequence (n, q)
ELSIF isProcedure (n)
THEN
assert (isProcedure (n)) ;
RETURN isLastStatement (n^.procedureF.beginStatements, q)
ELSIF isIf (n)
THEN
RETURN isLastStatementIf (n, q)
ELSIF isElsif (n)
THEN
RETURN isLastStatementElsif (n, q)
ELSIF isCase (n)
THEN
RETURN isLastStatementCase (n, q)
ELSIF q (n)
THEN
RETURN TRUE
END ;
RETURN FALSE
END isLastStatement ;
(*
doProcedureC -
*)
PROCEDURE doProcedureC (n: node) ;
VAR
s: CARDINAL ;
BEGIN
outText (doP, "\n") ;
includeParameters (n) ;
keyc.enterScope (n) ;
doProcedureHeadingC (n, FALSE) ;
outText (doP, "\n") ;
doP := outKc (doP, "{\n") ;
s := getcurline (doP) ;
doLocalConstTypesC (doP, n^.procedureF.decls) ;
doLocalVarC (doP, n^.procedureF.decls) ;
doUnboundedParamCopyC (doP, n) ;
IF s # getcurline (doP)
THEN
outText (doP, "\n")
END ;
doStatementsC (doP, n^.procedureF.beginStatements) ;
IF n^.procedureF.returnType # NIL
THEN
IF returnException
THEN
IF isLastStatementReturn (n)
THEN
outText (doP, "/* static analysis guarentees a RETURN statement will be used before here. */\n") ;
outText (doP, "__builtin_unreachable ();\n") ;
ELSE
doException (doP, 'ReturnException', n)
END
END
END ;
doP := outKc (doP, "}\n") ;
keyc.leaveScope (n)
END doProcedureC ;
(*
outProceduresC -
*)
PROCEDURE outProceduresC (p: pretty; s: scopeT) ;
BEGIN
doP := p ;
IF debugDecl
THEN
printf ("seen %d procedures\n", HighIndice (s.procedures))
END ;
ForeachIndiceInIndexDo (s.procedures, doProcedureC)
END outProceduresC ;
(*
output -
*)
PROCEDURE output (n: node; c, t, v: nodeProcedure) ;
BEGIN
IF isConst (n)
THEN
c (n)
ELSIF isVar (n)
THEN
v (n)
ELSE
t (n)
END
END output ;
(*
allDependants -
*)
PROCEDURE allDependants (n: node) : dependentState ;
VAR
l: alist ;
s: dependentState ;
BEGIN
l := alists.initList () ;
s := walkDependants (l, n) ;
alists.killList (l) ;
RETURN s
END allDependants ;
(*
walkDependants -
*)
PROCEDURE walkDependants (l: alist; n: node) : dependentState ;
BEGIN
IF (n=NIL) OR alists.isItemInList (doneQ, n)
THEN
RETURN completed
ELSIF alists.isItemInList (l, n)
THEN
RETURN recursive
ELSE
alists.includeItemIntoList (l, n) ;
RETURN doDependants (l, n)
END
END walkDependants ;
(*
walkType -
*)
PROCEDURE walkType (l: alist; n: node) : dependentState ;
VAR
t: node ;
BEGIN
t := getType (n) ;
IF alists.isItemInList (doneQ, t)
THEN
RETURN completed
ELSIF alists.isItemInList (partialQ, t)
THEN
RETURN blocked
ELSE
queueBlocked (t) ;
RETURN blocked
END
END walkType ;
(*
db -
*)
PROCEDURE db (a: ARRAY OF CHAR; n: node) ;
BEGIN
IF getDebugTopological ()
THEN
outText (doP, a) ;
IF n#NIL
THEN
outTextS (doP, gen (n))
END
END
END db ;
(*
dbt -
*)
PROCEDURE dbt (a: ARRAY OF CHAR) ;
BEGIN
IF getDebugTopological ()
THEN
outText (doP, a)
END
END dbt ;
(*
dbs -
*)
PROCEDURE dbs (s: dependentState; n: node) ;
BEGIN
IF getDebugTopological ()
THEN
CASE s OF
completed: outText (doP, '{completed ') |
blocked : outText (doP, '{blocked ') |
partial : outText (doP, '{partial ') |
recursive: outText (doP, '{recursive ')
END ;
IF n#NIL
THEN
outTextS (doP, gen (n))
END ;
outText (doP, '}\n')
END
END dbs ;
(*
dbq -
*)
PROCEDURE dbq (n: node) ;
BEGIN
IF getDebugTopological ()
THEN
IF alists.isItemInList (todoQ, n)
THEN
db ('{T', n) ; outText (doP, '}')
ELSIF alists.isItemInList (partialQ, n)
THEN
db ('{P', n) ; outText (doP, '}')
ELSIF alists.isItemInList (doneQ, n)
THEN
db ('{D', n) ; outText (doP, '}')
END
END
END dbq ;
(*
walkRecord -
*)
PROCEDURE walkRecord (l: alist; n: node) : dependentState ;
VAR
s : dependentState ;
o,
i, t: CARDINAL ;
q : node ;
BEGIN
i := LowIndice (n^.recordF.listOfSons) ;
t := HighIndice (n^.recordF.listOfSons) ;
db ('\nwalking ', n) ; o := getindent (doP) ; setindent (doP, getcurpos (doP)+3) ;
dbq (n) ;
WHILE i<=t DO
q := GetIndice (n^.recordF.listOfSons, i) ;
db ('', q) ;
IF isRecordField (q) AND q^.recordfieldF.tag
THEN
(* do nothing as it is a tag selector processed in the varient. *)
ELSE
s := walkDependants (l, q) ;
IF s#completed
THEN
dbs (s, q) ;
addTodo (n) ;
dbq (n) ;
db ('\n', NIL) ;
setindent (doP, o) ;
RETURN s
END
END ;
INC (i)
END ;
db ('{completed', n) ; dbt ('}\n') ;
setindent (doP, o) ;
RETURN completed
END walkRecord ;
(*
walkVarient -
*)
PROCEDURE walkVarient (l: alist; n: node) : dependentState ;
VAR
s : dependentState ;
i, t: CARDINAL ;
q : node ;
BEGIN
db ('\nwalking', n) ;
s := walkDependants (l, n^.varientF.tag) ;
IF s#completed
THEN
dbs (s, n^.varientF.tag) ;
dbq (n^.varientF.tag) ;
db ('\n', NIL) ;
RETURN s
END ;
i := LowIndice (n^.varientF.listOfSons) ;
t := HighIndice (n^.varientF.listOfSons) ;
WHILE i<=t DO
q := GetIndice (n^.varientF.listOfSons, i) ;
db ('', q) ;
s := walkDependants (l, q) ;
IF s#completed
THEN
dbs (s, q) ;
db ('\n', NIL) ;
RETURN s
END ;
INC (i)
END ;
db ('{completed', n) ; dbt ('}\n') ;
RETURN completed
END walkVarient ;
(*
queueBlocked -
*)
PROCEDURE queueBlocked (n: node) ;
BEGIN
IF NOT (alists.isItemInList (doneQ, n) OR alists.isItemInList (partialQ, n))
THEN
addTodo (n)
END
END queueBlocked ;
(*
walkVar -
*)
PROCEDURE walkVar (l: alist; n: node) : dependentState ;
VAR
t: node ;
BEGIN
t := getType (n) ;
IF alists.isItemInList (doneQ, t)
THEN
RETURN completed
ELSE
queueBlocked (t) ;
RETURN blocked
END
END walkVar ;
(*
walkEnumeration -
*)
PROCEDURE walkEnumeration (l: alist; n: node) : dependentState ;
VAR
s : dependentState ;
i, t: CARDINAL ;
q : node ;
BEGIN
i := LowIndice (n^.enumerationF.listOfSons) ;
t := HighIndice (n^.enumerationF.listOfSons) ;
s := completed ;
WHILE i<=t DO
q := GetIndice (n^.enumerationF.listOfSons, i) ;
s := walkDependants (l, q) ;
IF s#completed
THEN
RETURN s
END ;
INC (i)
END ;
RETURN s
END walkEnumeration ;
(*
walkSubrange -
*)
PROCEDURE walkSubrange (l: alist; n: node) : dependentState ;
VAR
s: dependentState ;
BEGIN
WITH n^.subrangeF DO
s := walkDependants (l, low) ;
IF s#completed
THEN
RETURN s
END ;
s := walkDependants (l, high) ;
IF s#completed
THEN
RETURN s
END ;
s := walkDependants (l, type) ;
IF s#completed
THEN
RETURN s
END
END ;
RETURN completed
END walkSubrange ;
(*
walkSubscript -
*)
PROCEDURE walkSubscript (l: alist; n: node) : dependentState ;
VAR
s: dependentState ;
BEGIN
WITH n^.subscriptF DO
s := walkDependants (l, expr) ;
IF s#completed
THEN
RETURN s
END ;
s := walkDependants (l, type) ;
IF s#completed
THEN
RETURN s
END
END ;
RETURN completed
END walkSubscript ;
(*
walkPointer -
*)
PROCEDURE walkPointer (l: alist; n: node) : dependentState ;
VAR
t: node ;
BEGIN
(* if the type of, n, is done or partial then we can output pointer. *)
t := getType (n) ;
IF alists.isItemInList (partialQ, t) OR alists.isItemInList (doneQ, t)
THEN
(* pointer to partial can always generate a complete type. *)
RETURN completed
END ;
RETURN walkType (l, n)
END walkPointer ;
(*
walkArray -
*)
PROCEDURE walkArray (l: alist; n: node) : dependentState ;
VAR
s: dependentState ;
BEGIN
WITH n^.arrayF DO
(*
s := walkDependants (l, type) ;
IF s#completed
THEN
RETURN s
END ;
*)
(* an array can only be declared if its data type has already been emitted. *)
IF NOT alists.isItemInList (doneQ, type)
THEN
s := walkDependants (l, type) ;
queueBlocked (type) ;
IF s=completed
THEN
(* downgrade the completed to partial as it has not yet been written. *)
RETURN partial
ELSE
RETURN s
END
END ;
RETURN walkDependants (l, subr)
END
END walkArray ;
(*
walkConst -
*)
PROCEDURE walkConst (l: alist; n: node) : dependentState ;
VAR
s: dependentState ;
BEGIN
WITH n^.constF DO
s := walkDependants (l, type) ;
IF s#completed
THEN
RETURN s
END ;
s := walkDependants (l, value) ;
IF s#completed
THEN
RETURN s
END
END ;
RETURN completed
END walkConst ;
(*
walkVarParam -
*)
PROCEDURE walkVarParam (l: alist; n: node) : dependentState ;
VAR
t: node ;
BEGIN
t := getType (n) ;
IF alists.isItemInList (partialQ, t)
THEN
(* parameter can be issued from a partial. *)
RETURN completed
END ;
RETURN walkDependants (l, t)
END walkVarParam ;
(*
walkParam -
*)
PROCEDURE walkParam (l: alist; n: node) : dependentState ;
VAR
t: node ;
BEGIN
t := getType (n) ;
IF alists.isItemInList (partialQ, t)
THEN
(* parameter can be issued from a partial. *)
RETURN completed
END ;
RETURN walkDependants (l, t)
END walkParam ;
(*
walkOptarg -
*)
PROCEDURE walkOptarg (l: alist; n: node) : dependentState ;
VAR
t: node ;
BEGIN
t := getType (n) ;
IF alists.isItemInList (partialQ, t)
THEN
(* parameter can be issued from a partial. *)
RETURN completed
END ;
RETURN walkDependants (l, t)
END walkOptarg ;
(*
walkRecordField -
*)
PROCEDURE walkRecordField (l: alist; n: node) : dependentState ;
VAR
t: node ;
s: dependentState ;
BEGIN
assert (isRecordField (n)) ;
t := getType (n) ;
IF alists.isItemInList (partialQ, t)
THEN
dbs (partial, n) ;
RETURN partial
ELSIF alists.isItemInList (doneQ, t)
THEN
dbs (completed, n) ;
RETURN completed
ELSE
addTodo (t) ;
dbs (blocked, n) ;
dbq (n) ;
dbq (t) ;
(* s := walkDependants (l, t) *)
RETURN blocked
END
END walkRecordField ;
(*
walkVarientField -
*)
PROCEDURE walkVarientField (l: alist; n: node) : dependentState ;
VAR
s : dependentState ;
i, t: CARDINAL ;
q : node ;
BEGIN
i := LowIndice (n^.varientfieldF.listOfSons) ;
t := HighIndice (n^.varientfieldF.listOfSons) ;
s := completed ;
WHILE i<=t DO
q := GetIndice (n^.varientfieldF.listOfSons, i) ;
s := walkDependants (l, q) ;
IF s#completed
THEN
dbs (s, n) ;
RETURN s
END ;
INC (i)
END ;
n^.varientfieldF.simple := (t <= 1) ;
dbs (s, n) ;
RETURN s
END walkVarientField ;
(*
walkEnumerationField -
*)
PROCEDURE walkEnumerationField (l: alist; n: node) : dependentState ;
BEGIN
RETURN completed
END walkEnumerationField ;
(*
walkSet -
*)
PROCEDURE walkSet (l: alist; n: node) : dependentState ;
BEGIN
RETURN walkDependants (l, getType (n))
END walkSet ;
(*
walkProcType -
*)
PROCEDURE walkProcType (l: alist; n: node) : dependentState ;
VAR
s: dependentState ;
t: node ;
BEGIN
t := getType (n) ;
IF alists.isItemInList (partialQ, t)
THEN
(* proctype can be generated from partial types. *)
ELSE
s := walkDependants (l, t) ;
IF s#completed
THEN
RETURN s
END
END ;
RETURN walkParameters (l, n^.proctypeF.parameters)
END walkProcType ;
(*
walkProcedure -
*)
PROCEDURE walkProcedure (l: alist; n: node) : dependentState ;
VAR
s: dependentState ;
BEGIN
s := walkDependants (l, getType (n)) ;
IF s#completed
THEN
RETURN s
END ;
RETURN walkParameters (l, n^.procedureF.parameters)
END walkProcedure ;
(*
walkParameters -
*)
PROCEDURE walkParameters (l: alist; p: Index) : dependentState ;
VAR
s : dependentState ;
i, h: CARDINAL ;
q : node ;
BEGIN
i := LowIndice (p) ;
h := HighIndice (p) ;
WHILE i<=h DO
q := GetIndice (p, i) ;
s := walkDependants (l, q) ;
IF s#completed
THEN
RETURN s
END ;
INC (i)
END ;
RETURN completed
END walkParameters ;
(*
walkFuncCall -
*)
PROCEDURE walkFuncCall (l: alist; n: node) : dependentState ;
BEGIN
RETURN completed
END walkFuncCall ;
(*
walkUnary -
*)
PROCEDURE walkUnary (l: alist; n: node) : dependentState ;
VAR
s: dependentState ;
BEGIN
WITH n^.unaryF DO
s := walkDependants (l, arg) ;
IF s#completed
THEN
RETURN s
END ;
RETURN walkDependants (l, resultType)
END
END walkUnary ;
(*
walkBinary -
*)
PROCEDURE walkBinary (l: alist; n: node) : dependentState ;
VAR
s: dependentState ;
BEGIN
WITH n^.binaryF DO
s := walkDependants (l, left) ;
IF s#completed
THEN
RETURN s
END ;
s := walkDependants (l, right) ;
IF s#completed
THEN
RETURN s
END ;
RETURN walkDependants (l, resultType)
END
END walkBinary ;
(*
walkComponentRef -
*)
PROCEDURE walkComponentRef (l: alist; n: node) : dependentState ;
VAR
s: dependentState ;
BEGIN
WITH n^.componentrefF DO
s := walkDependants (l, rec) ;
IF s#completed
THEN
RETURN s
END ;
s := walkDependants (l, field) ;
IF s#completed
THEN
RETURN s
END ;
RETURN walkDependants (l, resultType)
END
END walkComponentRef ;
(*
walkPointerRef -
*)
PROCEDURE walkPointerRef (l: alist; n: node) : dependentState ;
VAR
s: dependentState ;
BEGIN
WITH n^.pointerrefF DO
s := walkDependants (l, ptr) ;
IF s#completed
THEN
RETURN s
END ;
s := walkDependants (l, field) ;
IF s#completed
THEN
RETURN s
END ;
RETURN walkDependants (l, resultType)
END
END walkPointerRef ;
(*
walkSetValue -
*)
PROCEDURE walkSetValue (l: alist; n: node) : dependentState ;
VAR
s : dependentState ;
i, j: CARDINAL ;
BEGIN
assert (isSetValue (n)) ;
WITH n^.setvalueF DO
s := walkDependants (l, type) ;
IF s#completed
THEN
RETURN s
END ;
i := LowIndice (values) ;
j := HighIndice (values) ;
WHILE i <= j DO
s := walkDependants (l, GetIndice (values, i)) ;
IF s#completed
THEN
RETURN s
END ;
INC (i)
END
END ;
RETURN completed
END walkSetValue ;
(*
doDependants - return the dependentState depending upon whether
all dependants have been declared.
*)
PROCEDURE doDependants (l: alist; n: node) : dependentState ;
BEGIN
WITH n^ DO
CASE kind OF
throw, (* --fixme-- *)
varargs,
address,
loc,
byte,
word,
csizet,
cssizet,
(* base types. *)
boolean,
char,
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
real,
longreal,
shortreal,
bitset,
ztype,
rtype,
complex,
longcomplex,
shortcomplex,
proc : RETURN completed |
(* language features and compound type attributes. *)
type : RETURN walkType (l, n) |
record : RETURN walkRecord (l, n) |
varient : RETURN walkVarient (l, n) |
var : RETURN walkVar (l, n) |
enumeration : RETURN walkEnumeration (l, n) |
subrange : RETURN walkSubrange (l, n) |
pointer : RETURN walkPointer (l, n) |
array : RETURN walkArray (l, n) |
string : RETURN completed |
const : RETURN walkConst (l, n) |
literal : RETURN completed |
varparam : RETURN walkVarParam (l, n) |
param : RETURN walkParam (l, n) |
optarg : RETURN walkOptarg (l, n) |
recordfield : RETURN walkRecordField (l, n) |
varientfield : RETURN walkVarientField (l, n) |
enumerationfield: RETURN walkEnumerationField (l, n) |
set : RETURN walkSet (l, n) |
proctype : RETURN walkProcType (l, n) |
subscript : RETURN walkSubscript (l, n) |
(* blocks. *)
procedure : RETURN walkProcedure (l, n) |
def,
imp,
module,
(* statements. *)
loop,
while,
for,
repeat,
if,
elsif,
assignment : HALT |
(* expressions. *)
componentref : RETURN walkComponentRef (l, n) |
pointerref : RETURN walkPointerRef (l, n) |
not,
abs,
min,
max,
chr,
cap,
ord,
float,
trunc,
high : RETURN walkUnary (l, n) |
cast,
val,
plus,
sub,
div,
mod,
mult,
divide : RETURN walkBinary (l, n) |
constexp,
neg,
adr,
size,
tsize,
deref : RETURN walkUnary (l, n) |
equal,
notequal,
less,
greater,
greequal,
lessequal : RETURN walkBinary (l, n) |
funccall : RETURN walkFuncCall (l, n) |
setvalue : RETURN walkSetValue (l, n)
END
END
END doDependants ;
(*
tryComplete - returns TRUE if node, n, can be and was completed.
*)
PROCEDURE tryComplete (n: node; c, t, v: nodeProcedure) : BOOLEAN ;
BEGIN
IF isEnumeration (n)
THEN
(* can always emit enumerated types. *)
output (n, c, t, v) ;
RETURN TRUE
ELSIF isType (n) AND isTypeHidden (n) AND (getType (n)=NIL)
THEN
(* can always emit hidden types. *)
outputHidden (n) ;
RETURN TRUE
ELSIF allDependants (n) = completed
THEN
output (n, c, t, v) ;
RETURN TRUE
END ;
RETURN FALSE
END tryComplete ;
(*
tryCompleteFromPartial -
*)
PROCEDURE tryCompleteFromPartial (n: node; t: nodeProcedure) : BOOLEAN ;
BEGIN
IF isType (n) AND (getType (n)#NIL) AND isPointer (getType (n)) AND (allDependants (getType (n)) = completed)
THEN
(* alists.includeItemIntoList (partialQ, getType (n)) ; *)
outputHiddenComplete (n) ;
RETURN TRUE
ELSIF allDependants (n) = completed
THEN
t (n) ;
RETURN TRUE
END ;
RETURN FALSE
END tryCompleteFromPartial ;
(*
visitIntrinsicFunction -
*)
PROCEDURE visitIntrinsicFunction (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isIntrinsicFunction (n)) ;
CASE n^.kind OF
val,
cmplx: WITH n^.binaryF DO
visitNode (v, left, p) ;
visitNode (v, right, p) ;
visitNode (v, resultType, p)
END |
length,
adr,
size,
tsize,
float,
trunc,
ord,
chr,
cap,
abs,
high,
min,
max,
re,
im : WITH n^.unaryF DO
visitNode (v, arg, p) ;
visitNode (v, resultType, p)
END
END
END visitIntrinsicFunction ;
(*
visitUnary -
*)
PROCEDURE visitUnary (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isUnary (n)) ;
WITH n^.unaryF DO
visitNode (v, arg, p) ;
visitNode (v, resultType, p)
END
END visitUnary ;
(*
visitBinary -
*)
PROCEDURE visitBinary (v: alist; n: node; p: nodeProcedure) ;
BEGIN
WITH n^.binaryF DO
visitNode (v, left, p) ;
visitNode (v, right, p) ;
visitNode (v, resultType, p)
END
END visitBinary ;
(*
visitBoolean -
*)
PROCEDURE visitBoolean (v: alist; n: node; p: nodeProcedure) ;
BEGIN
visitNode (v, falseN, p) ;
visitNode (v, trueN, p)
END visitBoolean ;
(*
visitScope -
*)
PROCEDURE visitScope (v: alist; n: node; p: nodeProcedure) ;
BEGIN
IF mustVisitScope
THEN
visitNode (v, n, p)
END
END visitScope ;
(*
visitType -
*)
PROCEDURE visitType (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isType (n)) ;
visitNode (v, n^.typeF.type, p) ;
visitScope (v, n^.typeF.scope, p)
END visitType ;
(*
visitIndex -
*)
PROCEDURE visitIndex (v: alist; i: Index; p: nodeProcedure) ;
VAR
j, h: CARDINAL ;
BEGIN
j := 1 ;
h := HighIndice (i) ;
WHILE j <= h DO
visitNode (v, GetIndice (i, j), p) ;
INC (j)
END
END visitIndex ;
(*
visitRecord -
*)
PROCEDURE visitRecord (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isRecord (n)) ;
visitScope (v, n^.recordF.scope, p) ;
visitIndex (v, n^.recordF.listOfSons, p)
END visitRecord ;
(*
visitVarient -
*)
PROCEDURE visitVarient (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isVarient (n)) ;
visitIndex (v, n^.varientF.listOfSons, p) ;
visitNode (v, n^.varientF.varient, p) ;
visitNode (v, n^.varientF.tag, p) ;
visitScope (v, n^.varientF.scope, p)
END visitVarient ;
(*
visitVar -
*)
PROCEDURE visitVar (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isVar (n)) ;
visitNode (v, n^.varF.type, p) ;
visitNode (v, n^.varF.decl, p) ;
visitScope (v, n^.varF.scope, p)
END visitVar ;
(*
visitEnumeration -
*)
PROCEDURE visitEnumeration (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isEnumeration (n)) ;
visitIndex (v, n^.enumerationF.listOfSons, p) ;
visitScope (v, n^.enumerationF.scope, p)
END visitEnumeration ;
(*
visitSubrange -
*)
PROCEDURE visitSubrange (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isSubrange (n)) ;
visitNode (v, n^.subrangeF.low, p) ;
visitNode (v, n^.subrangeF.high, p) ;
visitNode (v, n^.subrangeF.type, p) ;
visitScope (v, n^.subrangeF.scope, p)
END visitSubrange ;
(*
visitPointer -
*)
PROCEDURE visitPointer (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isPointer (n)) ;
visitNode (v, n^.pointerF.type, p) ;
visitScope (v, n^.pointerF.scope, p)
END visitPointer ;
(*
visitArray -
*)
PROCEDURE visitArray (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isArray (n)) ;
visitNode (v, n^.arrayF.subr, p) ;
visitNode (v, n^.arrayF.type, p) ;
visitScope (v, n^.arrayF.scope, p)
END visitArray ;
(*
visitConst -
*)
PROCEDURE visitConst (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isConst (n)) ;
visitNode (v, n^.constF.type, p) ;
visitNode (v, n^.constF.value, p) ;
visitScope (v, n^.constF.scope, p)
END visitConst ;
(*
visitVarParam -
*)
PROCEDURE visitVarParam (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isVarParam (n)) ;
visitNode (v, n^.varparamF.namelist, p) ;
visitNode (v, n^.varparamF.type, p) ;
visitScope (v, n^.varparamF.scope, p)
END visitVarParam ;
(*
visitParam -
*)
PROCEDURE visitParam (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isParam (n)) ;
visitNode (v, n^.paramF.namelist, p) ;
visitNode (v, n^.paramF.type, p) ;
visitScope (v, n^.paramF.scope, p)
END visitParam ;
(*
visitOptarg -
*)
PROCEDURE visitOptarg (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isOptarg (n)) ;
visitNode (v, n^.optargF.namelist, p) ;
visitNode (v, n^.optargF.type, p) ;
visitNode (v, n^.optargF.init, p) ;
visitScope (v, n^.optargF.scope, p)
END visitOptarg ;
(*
visitRecordField -
*)
PROCEDURE visitRecordField (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isRecordField (n)) ;
visitNode (v, n^.recordfieldF.type, p) ;
visitNode (v, n^.recordfieldF.parent, p) ;
visitNode (v, n^.recordfieldF.varient, p) ;
visitScope (v, n^.recordfieldF.scope, p)
END visitRecordField ;
(*
visitVarientField -
*)
PROCEDURE visitVarientField (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isVarientField (n)) ;
visitNode (v, n^.varientfieldF.parent, p) ;
visitNode (v, n^.varientfieldF.varient, p) ;
visitIndex (v, n^.varientfieldF.listOfSons, p) ;
visitScope (v, n^.varientfieldF.scope, p)
END visitVarientField ;
(*
visitEnumerationField -
*)
PROCEDURE visitEnumerationField (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isEnumerationField (n)) ;
visitNode (v, n^.enumerationfieldF.type, p) ;
visitScope (v, n^.enumerationfieldF.scope, p)
END visitEnumerationField ;
(*
visitSet -
*)
PROCEDURE visitSet (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isSet (n)) ;
visitNode (v, n^.setF.type, p) ;
visitScope (v, n^.setF.scope, p)
END visitSet ;
(*
visitProcType -
*)
PROCEDURE visitProcType (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isProcType (n)) ;
visitIndex (v, n^.proctypeF.parameters, p) ;
visitNode (v, n^.proctypeF.optarg, p) ;
visitNode (v, n^.proctypeF.returnType, p) ;
visitScope (v, n^.proctypeF.scope, p)
END visitProcType ;
(*
visitSubscript -
*)
PROCEDURE visitSubscript (v: alist; n: node; p: nodeProcedure) ;
BEGIN
(*
assert (isSubscript (n)) ;
visitNode (v, n^.subscriptF.type, p) ;
visitNode (v, n^.subscriptF.expr, p)
*)
END visitSubscript ;
(*
visitDecls -
*)
PROCEDURE visitDecls (v: alist; s: scopeT; p: nodeProcedure) ;
BEGIN
visitIndex (v, s.constants, p) ;
visitIndex (v, s.types, p) ;
visitIndex (v, s.procedures, p) ;
visitIndex (v, s.variables, p)
END visitDecls ;
(*
visitProcedure -
*)
PROCEDURE visitProcedure (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isProcedure (n)) ;
visitDecls (v, n^.procedureF.decls, p) ;
visitScope (v, n^.procedureF.scope, p) ;
visitIndex (v, n^.procedureF.parameters, p) ;
visitNode (v, n^.procedureF.optarg, p) ;
visitNode (v, n^.procedureF.returnType, p) ;
visitNode (v, n^.procedureF.beginStatements, p)
END visitProcedure ;
(*
visitDef -
*)
PROCEDURE visitDef (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isDef (n)) ;
visitDecls (v, n^.defF.decls, p)
END visitDef ;
(*
visitImp -
*)
PROCEDURE visitImp (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isImp (n)) ;
visitDecls (v, n^.impF.decls, p) ;
visitNode (v, n^.impF.beginStatements, p) ;
visitNode (v, n^.impF.finallyStatements, p)
(* --fixme-- do we need to visit definitionModule? *)
END visitImp ;
(*
visitModule -
*)
PROCEDURE visitModule (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isModule (n)) ;
visitDecls (v, n^.moduleF.decls, p) ;
visitNode (v, n^.moduleF.beginStatements, p) ;
visitNode (v, n^.moduleF.finallyStatements, p)
END visitModule ;
(*
visitLoop -
*)
PROCEDURE visitLoop (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isLoop (n)) ;
visitNode (v, n^.loopF.statements, p)
END visitLoop ;
(*
visitWhile -
*)
PROCEDURE visitWhile (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isWhile (n)) ;
visitNode (v, n^.whileF.expr, p) ;
visitNode (v, n^.whileF.statements, p)
END visitWhile ;
(*
visitRepeat -
*)
PROCEDURE visitRepeat (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isRepeat (n)) ;
visitNode (v, n^.repeatF.expr, p) ;
visitNode (v, n^.repeatF.statements, p)
END visitRepeat ;
(*
visitCase -
*)
PROCEDURE visitCase (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isCase (n)) ;
visitNode (v, n^.caseF.expression, p) ;
visitIndex (v, n^.caseF.caseLabelList, p) ;
visitNode (v, n^.caseF.else, p)
END visitCase ;
(*
visitCaseLabelList -
*)
PROCEDURE visitCaseLabelList (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isCaseLabelList (n)) ;
visitNode (v, n^.caselabellistF.caseList, p) ;
visitNode (v, n^.caselabellistF.statements, p)
END visitCaseLabelList ;
(*
visitCaseList -
*)
PROCEDURE visitCaseList (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isCaseList (n)) ;
visitIndex (v, n^.caselistF.rangePairs, p)
END visitCaseList ;
(*
visitRange -
*)
PROCEDURE visitRange (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isRange (n)) ;
visitNode (v, n^.rangeF.lo, p) ;
visitNode (v, n^.rangeF.hi, p)
END visitRange ;
(*
visitIf -
*)
PROCEDURE visitIf (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isIf (n)) ;
visitNode (v, n^.ifF.expr, p) ;
visitNode (v, n^.ifF.elsif, p) ;
visitNode (v, n^.ifF.then, p) ;
visitNode (v, n^.ifF.else, p)
END visitIf ;
(*
visitElsif -
*)
PROCEDURE visitElsif (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isElsif (n)) ;
visitNode (v, n^.elsifF.expr, p) ;
visitNode (v, n^.elsifF.elsif, p) ;
visitNode (v, n^.elsifF.then, p) ;
visitNode (v, n^.elsifF.else, p)
END visitElsif ;
(*
visitFor -
*)
PROCEDURE visitFor (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isFor (n)) ;
visitNode (v, n^.forF.des, p) ;
visitNode (v, n^.forF.start, p) ;
visitNode (v, n^.forF.end, p) ;
visitNode (v, n^.forF.increment, p) ;
visitNode (v, n^.forF.statements, p)
END visitFor ;
(*
visitAssignment -
*)
PROCEDURE visitAssignment (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isAssignment (n)) ;
visitNode (v, n^.assignmentF.des, p) ;
visitNode (v, n^.assignmentF.expr, p)
END visitAssignment ;
(*
visitComponentRef -
*)
PROCEDURE visitComponentRef (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isComponentRef (n)) ;
visitNode (v, n^.componentrefF.rec, p) ;
visitNode (v, n^.componentrefF.field, p) ;
visitNode (v, n^.componentrefF.resultType, p)
END visitComponentRef ;
(*
visitPointerRef -
*)
PROCEDURE visitPointerRef (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isPointerRef (n)) ;
visitNode (v, n^.pointerrefF.ptr, p) ;
visitNode (v, n^.pointerrefF.field, p) ;
visitNode (v, n^.pointerrefF.resultType, p)
END visitPointerRef ;
(*
visitArrayRef -
*)
PROCEDURE visitArrayRef (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isArrayRef (n)) ;
visitNode (v, n^.arrayrefF.array, p) ;
visitNode (v, n^.arrayrefF.index, p) ;
visitNode (v, n^.arrayrefF.resultType, p)
END visitArrayRef ;
(*
visitFunccall -
*)
PROCEDURE visitFunccall (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isFuncCall (n)) ;
visitNode (v, n^.funccallF.function, p) ;
visitNode (v, n^.funccallF.args, p) ;
visitNode (v, n^.funccallF.type, p)
END visitFunccall ;
(*
visitVarDecl -
*)
PROCEDURE visitVarDecl (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isVarDecl (n)) ;
visitNode (v, n^.vardeclF.type, p) ;
visitScope (v, n^.vardeclF.scope, p)
END visitVarDecl ;
(*
visitExplist -
*)
PROCEDURE visitExplist (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isExpList (n)) ;
visitIndex (v, n^.explistF.exp, p)
END visitExplist ;
(*
visitExit -
*)
PROCEDURE visitExit (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isExit (n)) ;
visitNode (v, n^.exitF.loop, p)
END visitExit ;
(*
visitReturn -
*)
PROCEDURE visitReturn (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isReturn (n)) ;
visitNode (v, n^.returnF.exp, p)
END visitReturn ;
(*
visitStmtSeq -
*)
PROCEDURE visitStmtSeq (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isStatementSequence (n)) ;
visitIndex (v, n^.stmtF.statements, p)
END visitStmtSeq ;
(*
visitVarargs -
*)
PROCEDURE visitVarargs (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isVarargs (n)) ;
visitScope (v, n^.varargsF.scope, p)
END visitVarargs ;
(*
visitSetValue -
*)
PROCEDURE visitSetValue (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isSetValue (n)) ;
visitNode (v, n^.setvalueF.type, p) ;
visitIndex (v, n^.setvalueF.values, p)
END visitSetValue ;
(*
visitIntrinsic -
*)
PROCEDURE visitIntrinsic (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (isIntrinsic (n)) ;
visitNode (v, n^.intrinsicF.args, p)
END visitIntrinsic ;
(*
visitDependants - helper procedure function called from visitNode.
node n has just been visited, this procedure will
visit node, n, dependants.
*)
PROCEDURE visitDependants (v: alist; n: node; p: nodeProcedure) ;
BEGIN
assert (n # NIL) ;
assert (alists.isItemInList (v, n)) ;
CASE n^.kind OF
explist : visitExplist (v, n, p) |
funccall : visitFunccall (v, n, p) |
exit : visitExit (v, n, p) |
return : visitReturn (v, n, p) |
stmtseq : visitStmtSeq (v, n, p) |
comment : |
length : visitIntrinsicFunction (v, n, p) |
unreachable,
throw,
halt,
new,
dispose,
inc,
dec,
incl,
excl : visitIntrinsic (v, n, p) |
boolean : visitBoolean (v, n, p) |
nil,
false,
true : |
varargs : visitVarargs (v, n, p) |
address,
loc,
byte,
word,
csizet,
cssizet,
(* base types. *)
char,
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
real,
longreal,
shortreal,
bitset,
ztype,
rtype,
complex,
longcomplex,
shortcomplex,
proc : |
(* language features and compound type attributes. *)
type : visitType (v, n, p) |
record : visitRecord (v, n, p) |
varient : visitVarient (v, n, p) |
var : visitVar (v, n, p) |
enumeration : visitEnumeration (v, n, p) |
subrange : visitSubrange (v, n, p) |
pointer : visitPointer (v, n, p) |
array : visitArray (v, n, p) |
string : |
const : visitConst (v, n, p) |
literal : |
varparam : visitVarParam (v, n, p) |
param : visitParam (v, n, p) |
optarg : visitOptarg (v, n, p) |
recordfield : visitRecordField (v, n, p) |
varientfield : visitVarientField (v, n, p) |
enumerationfield: visitEnumerationField (v, n, p) |
set : visitSet (v, n, p) |
proctype : visitProcType (v, n, p) |
subscript : visitSubscript (v, n, p) |
(* blocks. *)
procedure : visitProcedure (v, n, p) |
def : visitDef (v, n, p) |
imp : visitImp (v, n, p) |
module : visitModule (v, n, p) |
(* statements. *)
loop : visitLoop (v, n, p) |
while : visitWhile (v, n, p) |
for : visitFor (v, n, p) |
repeat : visitRepeat (v, n, p) |
case : visitCase (v, n, p) |
caselabellist : visitCaseLabelList (v, n, p) |
caselist : visitCaseList (v, n, p) |
range : visitRange (v, n, p) |
if : visitIf (v, n, p) |
elsif : visitElsif (v, n, p) |
assignment : visitAssignment (v, n, p) |
(* expressions. *)
componentref : visitComponentRef (v, n, p) |
pointerref : visitPointerRef (v, n, p) |
arrayref : visitArrayRef (v, n, p) |
cmplx,
equal,
notequal,
less,
greater,
greequal,
lessequal,
and,
or,
in,
cast,
val,
plus,
sub,
div,
mod,
mult,
divide : visitBinary (v, n, p) |
re : visitUnary (v, n, p) |
im : visitUnary (v, n, p) |
abs : visitUnary (v, n, p) |
chr : visitUnary (v, n, p) |
cap : visitUnary (v, n, p) |
high : visitUnary (v, n, p) |
ord : visitUnary (v, n, p) |
float : visitUnary (v, n, p) |
trunc : visitUnary (v, n, p) |
not : visitUnary (v, n, p) |
neg : visitUnary (v, n, p) |
adr : visitUnary (v, n, p) |
size : visitUnary (v, n, p) |
tsize : visitUnary (v, n, p) |
min : visitUnary (v, n, p) |
max : visitUnary (v, n, p) |
constexp : visitUnary (v, n, p) |
deref : visitUnary (v, n, p) |
identlist : |
vardecl : visitVarDecl (v, n, p) |
setvalue : visitSetValue (v, n, p)
END
END visitDependants ;
(*
visitNode - visits node, n, if it is not already in the alist, v.
It calls p(n) if the node is unvisited.
*)
PROCEDURE visitNode (v: alist; n: node; p: nodeProcedure) ;
BEGIN
IF (n#NIL) AND (NOT alists.isItemInList (v, n))
THEN
alists.includeItemIntoList (v, n) ;
p (n) ;
visitDependants (v, n, p)
END
END visitNode ;
(*
genKind - returns a string depending upon the kind of node, n.
*)
PROCEDURE genKind (n: node) : String ;
BEGIN
CASE n^.kind OF
(* types, no need to generate a kind string as it it contained in the name. *)
nil,
true,
false,
address,
loc,
byte,
word,
csizet,
cssizet,
char,
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
real,
longreal,
shortreal,
bitset,
boolean,
proc,
ztype,
rtype,
complex,
longcomplex,
shortcomplex : RETURN NIL |
(* language features and compound type attributes. *)
type : RETURN InitString ('type') |
record : RETURN InitString ('record') |
varient : RETURN InitString ('varient') |
var : RETURN InitString ('var') |
enumeration : RETURN InitString ('enumeration') |
subrange : RETURN InitString ('subrange') |
array : RETURN InitString ('array') |
subscript : RETURN InitString ('subscript') |
string : RETURN InitString ('string') |
const : RETURN InitString ('const') |
literal : RETURN InitString ('literal') |
varparam : RETURN InitString ('varparam') |
param : RETURN InitString ('param') |
varargs : RETURN InitString ('varargs') |
pointer : RETURN InitString ('pointer') |
recordfield : RETURN InitString ('recordfield') |
varientfield : RETURN InitString ('varientfield') |
enumerationfield: RETURN InitString ('enumerationfield') |
set : RETURN InitString ('set') |
proctype : RETURN InitString ('proctype') |
(* blocks. *)
procedure : RETURN InitString ('procedure') |
def : RETURN InitString ('def') |
imp : RETURN InitString ('imp') |
module : RETURN InitString ('module') |
(* statements. *)
loop : RETURN InitString ('loop') |
while : RETURN InitString ('while') |
for : RETURN InitString ('for') |
repeat : RETURN InitString ('repeat') |
assignment : RETURN InitString ('assignment') |
if : RETURN InitString ('if') |
elsif : RETURN InitString ('elsif') |
(* expressions. *)
constexp : RETURN InitString ('constexp') |
neg : RETURN InitString ('neg') |
cast : RETURN InitString ('cast') |
val : RETURN InitString ('val') |
plus : RETURN InitString ('plus') |
sub : RETURN InitString ('sub') |
div : RETURN InitString ('div') |
mod : RETURN InitString ('mod') |
mult : RETURN InitString ('mult') |
divide : RETURN InitString ('divide') |
adr : RETURN InitString ('adr') |
size : RETURN InitString ('size') |
tsize : RETURN InitString ('tsize') |
chr : RETURN InitString ('chr') |
ord : RETURN InitString ('ord') |
float : RETURN InitString ('float') |
trunc : RETURN InitString ('trunc') |
high : RETURN InitString ('high') |
componentref : RETURN InitString ('componentref') |
pointerref : RETURN InitString ('pointerref') |
arrayref : RETURN InitString ('arrayref') |
deref : RETURN InitString ('deref') |
equal : RETURN InitString ('equal') |
notequal : RETURN InitString ('notequal') |
less : RETURN InitString ('less') |
greater : RETURN InitString ('greater') |
greequal : RETURN InitString ('greequal') |
lessequal : RETURN InitString ('lessequal') |
lsl : RETURN InitString ('lsl') |
lsr : RETURN InitString ('lsr') |
lor : RETURN InitString ('lor') |
land : RETURN InitString ('land') |
lnot : RETURN InitString ('lnot') |
lxor : RETURN InitString ('lxor') |
and : RETURN InitString ('and') |
or : RETURN InitString ('or') |
not : RETURN InitString ('not') |
identlist : RETURN InitString ('identlist') |
vardecl : RETURN InitString ('vardecl')
END ;
HALT
END genKind ;
(*
gen - generate a small string describing node, n.
*)
PROCEDURE gen (n: node) : String ;
VAR
s: String ;
d: CARDINAL ;
BEGIN
d := VAL (CARDINAL, VAL (LONGCARD, n)) ;
s := Sprintf1 (InitString ('< %d '), d) ; (* use 0x%x once FormatStrings has been released. *)
s := ConCat (s, genKind (n)) ;
s := ConCat (s, InitString (' ')) ;
s := ConCat (s, getFQstring (n)) ;
s := ConCat (s, InitString (' >')) ;
RETURN s
END gen ;
(*
dumpQ -
*)
PROCEDURE dumpQ (q: ARRAY OF CHAR; l: alist) ;
VAR
m : String ;
n : node ;
d,
h, i: CARDINAL ;
BEGIN
m := Sprintf0 (InitString ('Queue ')) ;
m := KillString (WriteS (StdOut, m)) ;
m := Sprintf0 (InitString (q)) ;
m := KillString (WriteS (StdOut, m)) ;
m := Sprintf0 (InitString ('\n')) ;
m := KillString (WriteS (StdOut, m)) ;
i := 1 ;
h := alists.noOfItemsInList (l) ;
WHILE i<=h DO
n := alists.getItemFromList (l, i) ;
m := KillString (WriteS (StdOut, gen (n))) ;
INC (i)
END ;
m := Sprintf0 (InitString ('\n')) ;
m := KillString (WriteS (StdOut, m))
END dumpQ ;
(*
dumpLists -
*)
PROCEDURE dumpLists ;
VAR
m: String ;
BEGIN
IF getDebugTopological ()
THEN
m := Sprintf0 (InitString ('\n')) ;
m := KillString (WriteS (StdOut, m)) ;
dumpQ ('todo', todoQ) ;
dumpQ ('partial', partialQ) ;
dumpQ ('done', doneQ)
END
END dumpLists ;
(*
outputHidden -
*)
PROCEDURE outputHidden (n: node) ;
BEGIN
outText (doP, "#if !defined (") ; doFQNameC (doP, n) ; outText (doP, "_D)\n") ;
outText (doP, "# define ") ; doFQNameC (doP, n) ; outText (doP, "_D\n") ;
outText (doP, " typedef void *") ; doFQNameC (doP, n) ; outText (doP, ";\n") ;
outText (doP, "#endif\n\n")
END outputHidden ;
(*
outputHiddenComplete -
*)
PROCEDURE outputHiddenComplete (n: node) ;
VAR
t: node ;
BEGIN
assert (isType (n)) ;
t := getType (n) ;
assert (isPointer (t)) ;
outText (doP, "#define ") ; doFQNameC (doP, n) ; outText (doP, "_D\n") ;
outText (doP, "typedef ") ; doTypeNameC (doP, getType (t)) ;
setNeedSpace (doP) ; outText (doP, "*") ; doFQNameC (doP, n) ; outText (doP, ";\n")
END outputHiddenComplete ;
(*
tryPartial -
*)
(*
PROCEDURE tryPartial (n: node; pt: nodeProcedure) : BOOLEAN ;
VAR
q : node ;
seenPointer: BOOLEAN ;
BEGIN
IF (n#NIL) AND isType (n)
THEN
seenPointer := FALSE ;
q := getType (n) ;
WHILE isPointer (q) DO
seenPointer := TRUE ;
q := getType (q)
END ;
IF q # NIL
THEN
IF isRecord (q) OR isProcType (q)
THEN
pt (n) ;
addTodo (q) ;
RETURN TRUE
ELSIF isArray (q) AND (seenPointer OR alists.isItemInList (doneQ, getType (q)))
THEN
pt (n) ;
addTodo (q) ;
RETURN TRUE
ELSIF isType (q) AND seenPointer
THEN
pt (n) ;
addTodo (q) ;
RETURN TRUE
END
END
END ;
RETURN FALSE
END tryPartial ;
*)
(*
tryPartial -
*)
PROCEDURE tryPartial (n: node; pt: nodeProcedure) : BOOLEAN ;
VAR
q: node ;
BEGIN
IF (n#NIL) AND isType (n)
THEN
q := getType (n) ;
WHILE isPointer (q) DO
q := getType (q)
END ;
IF q # NIL
THEN
IF isRecord (q) OR isProcType (q)
THEN
pt (n) ;
addTodo (q) ;
RETURN TRUE
ELSIF isArray (q)
THEN
pt (n) ;
addTodo (q) ;
RETURN TRUE
END
END
END ;
RETURN FALSE
END tryPartial ;
(*
outputPartialRecordArrayProcType -
*)
PROCEDURE outputPartialRecordArrayProcType (n, q: node; indirection: CARDINAL) ;
VAR
s: String ;
BEGIN
outText (doP, "typedef struct") ; setNeedSpace (doP) ;
s := getFQstring (n) ;
IF isRecord (q)
THEN
s := ConCat (s, Mark (InitString ("_r")))
ELSIF isArray (q)
THEN
s := ConCat (s, Mark (InitString ("_a")))
ELSIF isProcType (q)
THEN
s := ConCat (s, Mark (InitString ("_p")))
END ;
outTextS (doP, s) ;
setNeedSpace (doP) ;
s := KillString (s) ;
WHILE indirection>0 DO
outText (doP, "*") ;
DEC (indirection)
END ;
doFQNameC (doP, n) ;
outText (doP, ";\n\n")
END outputPartialRecordArrayProcType ;
(*
outputPartial -
*)
PROCEDURE outputPartial (n: node) ;
VAR
q : node ;
indirection: CARDINAL ;
BEGIN
q := getType (n) ;
indirection := 0 ;
WHILE isPointer (q) DO
q := getType (q) ;
INC (indirection)
END ;
outputPartialRecordArrayProcType (n, q, indirection)
END outputPartial ;
(*
tryOutputTodo -
*)
PROCEDURE tryOutputTodo (c, t, v, pt: nodeProcedure) ;
VAR
i, n: CARDINAL ;
d : node ;
BEGIN
i := 1 ;
n := alists.noOfItemsInList (todoQ) ;
WHILE i<=n DO
d := alists.getItemFromList (todoQ, i) ;
IF tryComplete (d, c, t, v)
THEN
alists.removeItemFromList (todoQ, d) ;
alists.includeItemIntoList (doneQ, d) ;
i := 1
ELSIF tryPartial (d, pt)
THEN
alists.removeItemFromList (todoQ, d) ;
alists.includeItemIntoList (partialQ, d) ;
i := 1
ELSE
INC (i)
END ;
n := alists.noOfItemsInList (todoQ)
END
END tryOutputTodo ;
(*
tryOutputPartial -
*)
PROCEDURE tryOutputPartial (t: nodeProcedure) ;
VAR
i, n: CARDINAL ;
d : node ;
BEGIN
i := 1 ;
n := alists.noOfItemsInList (partialQ) ;
WHILE i<=n DO
d := alists.getItemFromList (partialQ, i) ;
IF tryCompleteFromPartial (d, t)
THEN
alists.removeItemFromList (partialQ, d) ;
alists.includeItemIntoList (doneQ, d) ;
i := 1 ;
DEC (n)
ELSE
INC (i)
END
END
END tryOutputPartial ;
(*
debugList -
*)
PROCEDURE debugList (a: ARRAY OF CHAR; l: alist) ;
VAR
i, h: CARDINAL ;
n : node ;
BEGIN
h := alists.noOfItemsInList (l) ;
IF h>0
THEN
outText (doP, a) ;
outText (doP, ' still contains node(s)\n') ;
i := 1 ;
REPEAT
n := alists.getItemFromList (l, i) ;
dbg (n) ;
INC (i)
UNTIL i > h
END
END debugList ;
(*
debugLists -
*)
PROCEDURE debugLists ;
BEGIN
IF getDebugTopological ()
THEN
debugList ('todo', todoQ) ;
debugList ('partial', partialQ)
END
END debugLists ;
(*
addEnumConst -
*)
PROCEDURE addEnumConst (n: node) ;
VAR
s: String ;
BEGIN
IF isConst (n) OR isEnumeration (n)
THEN
addTodo (n)
END
END addEnumConst ;
(*
populateTodo -
*)
PROCEDURE populateTodo (p: nodeProcedure) ;
VAR
n : node ;
i, h: CARDINAL ;
l : alist ;
BEGIN
h := alists.noOfItemsInList (todoQ) ;
i := 1 ;
WHILE i <= h DO
n := alists.getItemFromList (todoQ, i) ;
l := alists.initList () ;
visitNode (l, n, p) ;
alists.killList (l) ;
h := alists.noOfItemsInList (todoQ) ;
INC (i)
END
END populateTodo ;
(*
topologicallyOut -
*)
PROCEDURE topologicallyOut (c, t, v, tp,
pc, pt, pv: nodeProcedure) ;
VAR
tol, pal,
to, pa : CARDINAL ;
BEGIN
populateTodo (addEnumConst) ;
tol := 0 ;
pal := 0 ;
to := alists.noOfItemsInList (todoQ) ;
pa := alists.noOfItemsInList (partialQ) ;
WHILE (tol#to) OR (pal#pa) DO
dumpLists ;
tryOutputTodo (c, t, v, tp) ;
dumpLists ;
tryOutputPartial (pt) ;
tol := to ;
pal := pa ;
to := alists.noOfItemsInList (todoQ) ;
pa := alists.noOfItemsInList (partialQ)
END ;
dumpLists ;
debugLists
END topologicallyOut ;
(*
scaffoldStatic -
*)
PROCEDURE scaffoldStatic (p: pretty; n: node) ;
BEGIN
outText (p, "\n") ;
doExternCP (p) ;
outText (p, "void") ;
setNeedSpace (p) ;
outText (p, "_M2_") ;
doFQNameC (p, n) ;
outText (p, "_init") ;
setNeedSpace (p) ;
outText (p, "(__attribute__((unused)) int argc") ;
outText (p, ",__attribute__((unused)) char *argv[]") ;
outText (p, ",__attribute__((unused)) char *envp[])\n");
p := outKc (p, "{\n") ;
doStatementsC (p, n^.impF.beginStatements) ;
p := outKc (p, "}\n") ;
outText (p, "\n") ;
doExternCP (p) ;
outText (p, "void") ;
setNeedSpace (p) ;
outText (p, "_M2_") ;
doFQNameC (p, n) ;
outText (p, "_fini") ;
setNeedSpace (p) ;
outText (p, "(__attribute__((unused)) int argc") ;
outText (p, ",__attribute__((unused)) char *argv[]") ;
outText (p, ",__attribute__((unused)) char *envp[])\n");
p := outKc (p, "{\n") ;
doStatementsC (p, n^.impF.finallyStatements) ;
p := outKc (p, "}\n")
END scaffoldStatic ;
(*
emitCtor -
*)
PROCEDURE emitCtor (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
outText (p, "\n") ;
outText (p, "static void") ;
setNeedSpace (p) ;
outText (p, "ctorFunction ()\n") ;
doFQNameC (p, n) ;
p := outKc (p, "{\n") ;
outText (p, 'M2RTS_RegisterModule ("') ;
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
prints (p, s) ;
outText (p, '",\n') ;
outText (p, 'init, fini, dependencies);\n') ;
p := outKc (p, "}\n\n") ;
p := outKc (p, "struct ") ;
prints (p, s) ;
p := outKc (p, "_module_m2 { ") ;
prints (p, s) ;
p := outKc (p, "_module_m2 (); ~") ;
prints (p, s) ;
p := outKc (p, "_module_m2 (); } global_module_") ;
prints (p, s) ;
outText (p, ';\n\n') ;
prints (p, s) ;
p := outKc (p, "_module_m2::") ;
prints (p, s) ;
p := outKc (p, "_module_m2 ()\n") ;
p := outKc (p, "{\n") ;
outText (p, 'M2RTS_RegisterModule ("') ;
prints (p, s) ;
outText (p, '", init, fini, dependencies);') ;
p := outKc (p, "}\n") ;
prints (p, s) ;
p := outKc (p, "_module_m2::~") ;
prints (p, s) ;
p := outKc (p, "_module_m2 ()\n") ;
p := outKc (p, "{\n") ;
p := outKc (p, "}\n") ;
s := KillString (s)
END emitCtor ;
(*
scaffoldDynamic -
*)
PROCEDURE scaffoldDynamic (p: pretty; n: node) ;
BEGIN
outText (p, "\n") ;
doExternCP (p) ;
outText (p, "void") ;
setNeedSpace (p) ;
outText (p, "_M2_") ;
doFQNameC (p, n) ;
outText (p, "_init") ;
setNeedSpace (p) ;
outText (p, "(__attribute__((unused)) int argc,") ;
outText (p, " __attribute__((unused)) char *argv[]") ;
outText (p, " __attribute__((unused)) char *envp[])\n") ;
p := outKc (p, "{\n") ;
doStatementsC (p, n^.impF.beginStatements) ;
p := outKc (p, "}\n") ;
outText (p, "\n") ;
doExternCP (p) ;
outText (p, "void") ;
setNeedSpace (p) ;
outText (p, "_M2_") ;
doFQNameC (p, n) ;
outText (p, "_fini") ;
setNeedSpace (p) ;
outText (p, "(__attribute__((unused)) int argc,") ;
outText (p, " __attribute__((unused)) char *argv[]") ;
outText (p, " __attribute__((unused)) char *envp[])\n") ;
p := outKc (p, "{\n") ;
doStatementsC (p, n^.impF.finallyStatements) ;
p := outKc (p, "}\n") ;
emitCtor (p, n)
END scaffoldDynamic ;
(*
scaffoldMain -
*)
PROCEDURE scaffoldMain (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
outText (p, "int\n") ;
outText (p, "main") ;
setNeedSpace (p) ;
outText (p, "(int argc, char *argv[], char *envp[])\n") ;
p := outKc (p, "{\n") ;
outText (p, "M2RTS_ConstructModules (") ;
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
prints (p, s) ;
outText (p, ", argc, argv, envp);\n");
outText (p, "M2RTS_DeconstructModules (") ;
prints (p, s) ;
outText (p, ", argc, argv, envp);\n");
outText (p, "return 0;") ;
p := outKc (p, "}\n") ;
s := KillString (s)
END scaffoldMain ;
(*
outImpInitC - emit the init/fini functions and main function if required.
*)
PROCEDURE outImpInitC (p: pretty; n: node) ;
BEGIN
IF getScaffoldDynamic ()
THEN
scaffoldDynamic (p, n)
ELSE
scaffoldStatic (p, n)
END ;
IF getScaffoldMain ()
THEN
scaffoldMain (p, n)
END
END outImpInitC ;
(*
runSimplifyTypes -
*)
PROCEDURE runSimplifyTypes (n: node) ;
BEGIN
IF isImp (n)
THEN
simplifyTypes (n^.impF.decls)
ELSIF isModule (n)
THEN
simplifyTypes (n^.moduleF.decls)
ELSIF isDef (n)
THEN
simplifyTypes (n^.defF.decls)
END
END runSimplifyTypes ;
(*
outDefC -
*)
PROCEDURE outDefC (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
assert (isDef (n)) ;
outputFile := mcStream.openFrag (1) ; (* first fragment. *)
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
print (p, "/* do not edit automatically generated by mc from ") ;
prints (p, s) ; print (p, ". */\n") ;
writeGPLheader (outputFile) ;
doCommentC (p, n^.defF.com.body) ;
print (p, "\n\n#if !defined (_") ; prints (p, s) ; print (p, "_H)\n") ;
print (p, "# define _") ; prints (p, s) ; print (p, "_H\n\n") ;
keyc.genConfigSystem (p) ;
print (p, "# ifdef __cplusplus\n") ;
print (p, 'extern "C" {\n') ;
print (p, "# endif\n") ;
outputFile := mcStream.openFrag (3) ; (* third fragment. *)
doP := p ;
ForeachIndiceInIndexDo (n^.defF.importedModules, doIncludeC) ;
print (p, "\n") ;
print (p, "# if defined (_") ; prints (p, s) ; print (p, "_C)\n") ;
print (p, "# define EXTERN\n") ;
print (p, "# else\n") ;
print (p, '# define EXTERN extern\n') ;
print (p, "# endif\n\n") ;
outDeclsDefC (p, n) ;
runPrototypeDefC (n) ;
print (p, "# ifdef __cplusplus\n") ;
print (p, "}\n") ;
print (p, "# endif\n") ;
print (p, "\n") ;
print (p, "# undef EXTERN\n") ;
print (p, "#endif\n") ;
outputFile := mcStream.openFrag (2) ; (* second fragment. *)
keyc.genDefs (p) ;
s := KillString (s)
END outDefC ;
(*
runPrototypeExported -
*)
PROCEDURE runPrototypeExported (n: node) ;
BEGIN
IF isExported (n)
THEN
keyc.enterScope (n) ;
doProcedureHeadingC (n, TRUE) ;
print (doP, ";\n") ;
keyc.leaveScope (n)
END
END runPrototypeExported ;
(*
runPrototypeDefC -
*)
PROCEDURE runPrototypeDefC (n: node) ;
BEGIN
IF isDef (n)
THEN
ForeachIndiceInIndexDo (n^.defF.decls.procedures, runPrototypeExported)
END
END runPrototypeDefC ;
(*
outImpC -
*)
PROCEDURE outImpC (p: pretty; n: node) ;
VAR
s : String ;
defModule: node ;
BEGIN
assert (isImp (n)) ;
outputFile := mcStream.openFrag (1) ; (* first fragment. *)
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
print (p, "/* do not edit automatically generated by mc from ") ;
prints (p, s) ; print (p, ". */\n") ;
writeGPLheader (outputFile) ;
doCommentC (p, n^.impF.com.body) ;
outText (p, "\n") ;
outputFile := mcStream.openFrag (3) ; (* third fragment. *)
IF getExtendedOpaque ()
THEN
doP := p ;
(* ForeachIndiceInIndexDo (n^.impF.importedModules, doIncludeC) ; *)
includeExternals (n) ;
foreachModuleDo (n, runSimplifyTypes) ;
printf ("/* --extended-opaque seen therefore no #include will be used and everything will be declared in full. */\n") ;
foreachDefModuleDo (runIncludeDefConstType) ;
includeDefVarProcedure (n) ;
outDeclsImpC (p, n^.impF.decls) ;
foreachDefModuleDo (runPrototypeDefC)
ELSE
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
(* we don't want to include the .h file for this implementation module. *)
print (p, "#define _") ; prints (p, s) ; print (p, "_H\n") ;
print (p, "#define _") ; prints (p, s) ; print (p, "_C\n\n") ;
s := KillString (s) ;
doP := p ;
ForeachIndiceInIndexDo (n^.impF.importedModules, doIncludeC) ;
print (p, "\n") ;
includeDefConstType (n) ;
includeDefVarProcedure (n) ;
outDeclsImpC (p, n^.impF.decls) ;
defModule := lookupDef (getSymName (n)) ;
IF defModule # NIL
THEN
runPrototypeDefC (defModule)
END
END ;
ForeachIndiceInIndexDo (n^.impF.decls.procedures, doPrototypeC) ;
outProceduresC (p, n^.impF.decls) ;
outImpInitC (p, n) ;
outputFile := mcStream.openFrag (2) ; (* second fragment. *)
keyc.genConfigSystem (p) ;
keyc.genDefs (p)
END outImpC ;
(*
outDeclsModuleC -
*)
PROCEDURE outDeclsModuleC (p: pretty; s: scopeT) ;
BEGIN
simplifyTypes (s) ;
includeConstType (s) ;
doP := p ;
topologicallyOut (doConstC, doTypesC, doVarC,
outputPartial,
doNone, doCompletePartialC, doNone) ;
(* try and output types, constants before variables and procedures. *)
includeVarProcedure (s) ;
topologicallyOut (doConstC, doTypesC, doVarC,
outputPartial,
doNone, doCompletePartialC, doNone) ;
ForeachIndiceInIndexDo (s.procedures, doPrototypeC)
END outDeclsModuleC ;
(*
outModuleInitC -
*)
PROCEDURE outModuleInitC (p: pretty; n: node) ;
BEGIN
outText (p, "\n") ;
doExternCP (p) ;
outText (p, "void") ;
setNeedSpace (p) ;
outText (p, "_M2_") ;
doFQNameC (p, n) ;
outText (p, "_init") ;
setNeedSpace (p) ;
outText (p, "(__attribute__((unused)) int argc") ;
outText (p, ",__attribute__((unused)) char *argv[]") ;
outText (p, ",__attribute__((unused)) char *envp[])\n");
p := outKc (p, "{\n") ;
doStatementsC (p, n^.moduleF.beginStatements) ;
p := outKc (p, "}\n") ;
outText (p, "\n") ;
doExternCP (p) ;
outText (p, "void") ;
setNeedSpace (p) ;
outText (p, "_M2_") ;
doFQNameC (p, n) ;
outText (p, "_fini") ;
setNeedSpace (p) ;
outText (p, "(__attribute__((unused)) int argc") ;
outText (p, ",__attribute__((unused)) char *argv[]") ;
outText (p, ",__attribute__((unused)) char *envp[])\n");
p := outKc (p, "{\n") ;
doStatementsC (p, n^.moduleF.finallyStatements) ;
p := outKc (p, "}\n")
END outModuleInitC ;
(*
outModuleC -
*)
PROCEDURE outModuleC (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
assert (isModule (n)) ;
outputFile := mcStream.openFrag (1) ; (* first fragment. *)
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
print (p, "/* do not edit automatically generated by mc from ") ;
prints (p, s) ; print (p, ". */\n") ;
writeGPLheader (outputFile) ;
doCommentC (p, n^.moduleF.com.body) ;
outText (p, "\n") ;
outputFile := mcStream.openFrag (3) ; (* third fragment. *)
IF getExtendedOpaque ()
THEN
doP := p ;
includeExternals (n) ;
foreachModuleDo (n, runSimplifyTypes) ;
printf ("/* --extended-opaque seen therefore no #include will be used and everything will be declared in full. */\n") ;
foreachDefModuleDo (runIncludeDefConstType) ;
outDeclsModuleC (p, n^.moduleF.decls) ;
foreachDefModuleDo (runPrototypeDefC)
ELSE
doP := p ;
ForeachIndiceInIndexDo (n^.moduleF.importedModules, doIncludeC) ;
print (p, "\n") ;
outDeclsModuleC (p, n^.moduleF.decls)
END ;
ForeachIndiceInIndexDo (n^.moduleF.decls.procedures, doPrototypeC) ;
outProceduresC (p, n^.moduleF.decls) ;
outModuleInitC (p, n) ;
outputFile := mcStream.openFrag (2) ; (* second fragment. *)
keyc.genConfigSystem (p) ;
keyc.genDefs (p)
END outModuleC ;
(*
outC -
*)
PROCEDURE outC (p: pretty; n: node) ;
BEGIN
keyc.enterScope (n) ;
IF isDef (n)
THEN
outDefC (p, n)
ELSIF isImp (n)
THEN
outImpC (p, n)
ELSIF isModule (n)
THEN
outModuleC (p, n)
ELSE
HALT
END ;
keyc.leaveScope (n)
END outC ;
(*
doIncludeM2 - include modules in module, n.
*)
PROCEDURE doIncludeM2 (n: node) ;
VAR
s: String ;
BEGIN
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
print (doP, 'IMPORT ') ;
prints (doP, s) ;
print (doP, ' ;\n') ;
s := KillString (s) ;
IF isDef (n)
THEN
foreachNodeDo (n^.defF.decls.symbols, addDone)
ELSIF isImp (n)
THEN
foreachNodeDo (n^.impF.decls.symbols, addDone)
ELSIF isModule (n)
THEN
foreachNodeDo (n^.moduleF.decls.symbols, addDone)
END
END doIncludeM2 ;
(*
doConstM2 -
*)
PROCEDURE doConstM2 (n: node) ;
BEGIN
print (doP, "CONST\n") ;
doFQNameC (doP, n) ;
setNeedSpace (doP) ;
doExprC (doP, n^.constF.value) ;
print (doP, '\n')
END doConstM2 ;
(*
doProcTypeM2 -
*)
PROCEDURE doProcTypeM2 (p: pretty; n: node) ;
BEGIN
outText (p, "proc type to do..")
END doProcTypeM2 ;
(*
doRecordFieldM2 -
*)
PROCEDURE doRecordFieldM2 (p: pretty; f: node) ;
BEGIN
doNameM2 (p, f) ;
outText (p, ":") ;
setNeedSpace (p) ;
doTypeM2 (p, getType (f)) ;
setNeedSpace (p)
END doRecordFieldM2 ;
(*
doVarientFieldM2 -
*)
PROCEDURE doVarientFieldM2 (p: pretty; n: node) ;
VAR
i, t: CARDINAL ;
q : node ;
BEGIN
assert (isVarientField (n)) ;
doNameM2 (p, n) ;
outText (p, ":") ;
setNeedSpace (p) ;
i := LowIndice (n^.varientfieldF.listOfSons) ;
t := HighIndice (n^.varientfieldF.listOfSons) ;
WHILE i<=t DO
q := GetIndice (n^.varientfieldF.listOfSons, i) ;
IF isRecordField (q)
THEN
doRecordFieldM2 (p, q) ;
outText (p, ";\n")
ELSIF isVarient (q)
THEN
doVarientM2 (p, q) ;
outText (p, ";\n")
ELSE
HALT
END ;
INC (i)
END
END doVarientFieldM2 ;
(*
doVarientM2 -
*)
PROCEDURE doVarientM2 (p: pretty; n: node) ;
VAR
i, t: CARDINAL ;
q : node ;
BEGIN
assert (isVarient (n)) ;
outText (p, "CASE") ; setNeedSpace (p) ;
IF n^.varientF.tag # NIL
THEN
IF isRecordField (n^.varientF.tag)
THEN
doRecordFieldM2 (p, n^.varientF.tag)
ELSIF isVarientField (n^.varientF.tag)
THEN
doVarientFieldM2 (p, n^.varientF.tag)
ELSE
HALT
END
END ;
setNeedSpace (p) ;
outText (p, "OF\n") ;
i := LowIndice (n^.varientF.listOfSons) ;
t := HighIndice (n^.varientF.listOfSons) ;
WHILE i<=t DO
q := GetIndice (n^.varientF.listOfSons, i) ;
IF isRecordField (q)
THEN
IF NOT q^.recordfieldF.tag
THEN
doRecordFieldM2 (p, q) ;
outText (p, ";\n")
END
ELSIF isVarientField (q)
THEN
doVarientFieldM2 (p, q)
ELSE
HALT
END ;
INC (i)
END ;
outText (p, "END") ; setNeedSpace (p)
END doVarientM2 ;
(*
doRecordM2 -
*)
PROCEDURE doRecordM2 (p: pretty; n: node) ;
VAR
i, h: CARDINAL ;
f : node ;
BEGIN
assert (isRecord (n)) ;
p := outKm2 (p, "RECORD") ;
i := LowIndice (n^.recordF.listOfSons) ;
h := HighIndice (n^.recordF.listOfSons) ;
outText (p, "\n") ;
WHILE i<=h DO
f := GetIndice (n^.recordF.listOfSons, i) ;
IF isRecordField (f)
THEN
IF NOT f^.recordfieldF.tag
THEN
doRecordFieldM2 (p, f) ;
outText (p, ";\n")
END
ELSIF isVarient (f)
THEN
doVarientM2 (p, f) ;
outText (p, ";\n")
ELSIF isVarientField (f)
THEN
doVarientFieldM2 (p, f)
END ;
INC (i)
END ;
p := outKm2 (p, "END") ; setNeedSpace (p)
END doRecordM2 ;
(*
doPointerM2 -
*)
PROCEDURE doPointerM2 (p: pretty; n: node) ;
BEGIN
outText (p, "POINTER TO") ;
setNeedSpace (doP) ;
doTypeM2 (p, getType (n)) ;
setNeedSpace (p) ;
outText (p, ";\n")
END doPointerM2 ;
(*
doTypeAliasM2 -
*)
PROCEDURE doTypeAliasM2 (p: pretty; n: node) ;
BEGIN
doTypeNameC (p, n) ;
setNeedSpace (p) ;
outText (doP, "=") ;
setNeedSpace (p) ;
doTypeM2 (p, getType (n)) ;
setNeedSpace (p) ;
outText (p, "\n")
END doTypeAliasM2 ;
(*
doEnumerationM2 -
*)
PROCEDURE doEnumerationM2 (p: pretty; n: node) ;
VAR
i, h: CARDINAL ;
s : node ;
t : String ;
BEGIN
outText (p, "(") ;
i := LowIndice (n^.enumerationF.listOfSons) ;
h := HighIndice (n^.enumerationF.listOfSons) ;
WHILE i <= h DO
s := GetIndice (n^.enumerationF.listOfSons, i) ;
doFQNameC (p, s) ;
IF i < h
THEN
outText (p, ",") ; setNeedSpace (p)
END ;
INC (i)
END ;
outText (p, ")")
END doEnumerationM2 ;
(*
doBaseM2 -
*)
PROCEDURE doBaseM2 (p: pretty; n: node) ;
BEGIN
CASE n^.kind OF
char,
cardinal,
longcard,
shortcard,
integer,
longint,
shortint,
complex,
longcomplex,
shortcomplex,
real,
longreal,
shortreal,
bitset,
boolean,
proc : doNameM2 (p, n)
END ;
setNeedSpace (p)
END doBaseM2 ;
(*
doSystemM2 -
*)
PROCEDURE doSystemM2 (p: pretty; n: node) ;
BEGIN
CASE n^.kind OF
address,
loc,
byte ,
word ,
csizet ,
cssizet: doNameM2 (p, n)
END
END doSystemM2 ;
(*
doTypeM2 -
*)
PROCEDURE doTypeM2 (p: pretty; n: node) ;
BEGIN
IF isBase (n)
THEN
doBaseM2 (p, n)
ELSIF isSystem (n)
THEN
doSystemM2 (p, n)
ELSIF isType (n)
THEN
doTypeAliasM2 (p, n)
ELSIF isProcType (n)
THEN
doProcTypeM2 (p, n)
ELSIF isPointer (n)
THEN
doPointerM2 (p, n)
ELSIF isEnumeration (n)
THEN
doEnumerationM2 (p, n)
ELSIF isRecord (n)
THEN
doRecordM2 (p, n)
END
END doTypeM2 ;
(*
doTypesM2 -
*)
PROCEDURE doTypesM2 (n: node) ;
VAR
m: node ;
BEGIN
outText (doP, "TYPE\n") ;
doTypeM2 (doP, n)
END doTypesM2 ;
(*
doVarM2 -
*)
PROCEDURE doVarM2 (n: node) ;
BEGIN
assert (isVar (n)) ;
doNameC (doP, n) ;
outText (doP, ":") ;
setNeedSpace (doP) ;
doTypeM2 (doP, getType (n)) ;
setNeedSpace (doP) ;
outText (doP, ";\n")
END doVarM2 ;
(*
doVarsM2 -
*)
PROCEDURE doVarsM2 (n: node) ;
VAR
m: node ;
BEGIN
outText (doP, "VAR\n") ;
doVarM2 (n)
END doVarsM2 ;
(*
doTypeNameM2 -
*)
PROCEDURE doTypeNameM2 (p: pretty; n: node) ;
BEGIN
doNameM2 (p, n)
END doTypeNameM2 ;
(*
doParamM2 -
*)
PROCEDURE doParamM2 (p: pretty; n: node) ;
VAR
ptype: node ;
i : Name ;
c, t : CARDINAL ;
l : wlist ;
BEGIN
assert (isParam (n)) ;
ptype := getType (n) ;
IF n^.paramF.namelist = NIL
THEN
doTypeNameM2 (p, ptype)
ELSE
assert (isIdentList (n^.paramF.namelist)) ;
l := n^.paramF.namelist^.identlistF.names ;
IF l=NIL
THEN
doTypeNameM2 (p, ptype)
ELSE
t := wlists.noOfItemsInList (l) ;
c := 1 ;
WHILE c <= t DO
i := wlists.getItemFromList (l, c) ;
setNeedSpace (p) ;
doNamesC (p, i) ;
IF c<t
THEN
outText (p, ',') ; setNeedSpace (p)
END ;
INC (c)
END ;
outText (p, ':') ; setNeedSpace (p) ;
doTypeNameM2 (p, ptype)
END
END
END doParamM2 ;
(*
doVarParamM2 -
*)
PROCEDURE doVarParamM2 (p: pretty; n: node) ;
VAR
ptype: node ;
i : Name ;
c, t : CARDINAL ;
l : wlist ;
BEGIN
assert (isVarParam (n)) ;
outText (p, 'VAR') ; setNeedSpace (p) ;
ptype := getType (n) ;
IF n^.varparamF.namelist = NIL
THEN
doTypeNameM2 (p, ptype)
ELSE
assert (isIdentList (n^.varparamF.namelist)) ;
l := n^.varparamF.namelist^.identlistF.names ;
IF l=NIL
THEN
doTypeNameM2 (p, ptype)
ELSE
t := wlists.noOfItemsInList (l) ;
c := 1 ;
WHILE c <= t DO
i := wlists.getItemFromList (l, c) ;
setNeedSpace (p) ;
doNamesC (p, i) ;
IF c<t
THEN
outText (p, ',') ; setNeedSpace (p)
END ;
INC (c)
END ;
outText (p, ':') ; setNeedSpace (p) ;
doTypeNameM2 (p, ptype)
END
END
END doVarParamM2 ;
(*
doParameterM2 -
*)
PROCEDURE doParameterM2 (p: pretty; n: node) ;
BEGIN
IF isParam (n)
THEN
doParamM2 (p, n)
ELSIF isVarParam (n)
THEN
doVarParamM2 (p, n)
ELSIF isVarargs (n)
THEN
print (p, "...")
END
END doParameterM2 ;
(*
doPrototypeM2 -
*)
PROCEDURE doPrototypeM2 (n: node) ;
VAR
i, h: CARDINAL ;
p : node ;
BEGIN
assert (isProcedure (n)) ;
noSpace (doP) ;
doNameM2 (doP, n) ;
setNeedSpace (doP) ;
outText (doP, "(") ;
i := LowIndice (n^.procedureF.parameters) ;
h := HighIndice (n^.procedureF.parameters) ;
WHILE i <= h DO
p := GetIndice (n^.procedureF.parameters, i) ;
doParameterM2 (doP, p) ;
noSpace (doP) ;
IF i < h
THEN
print (doP, ";") ; setNeedSpace (doP)
END ;
INC (i)
END ;
outText (doP, ")") ;
IF n^.procedureF.returnType#NIL
THEN
setNeedSpace (doP) ;
outText (doP, ":") ;
doTypeM2 (doP, n^.procedureF.returnType) ; setNeedSpace (doP)
END ;
outText (doP, ";\n")
END doPrototypeM2 ;
(*
outputPartialM2 - just writes out record, array, and proctypes.
No need for forward declarations in Modula-2
but we need to keep topological sort happy.
So when asked to output partial we emit the
full type for these types and then do nothing
when trying to complete partial to full.
*)
PROCEDURE outputPartialM2 (n: node) ;
VAR
q: node ;
BEGIN
q := getType (n) ;
IF isRecord (q)
THEN
doTypeM2 (doP, n)
ELSIF isArray (q)
THEN
doTypeM2 (doP, n)
ELSIF isProcType (q)
THEN
doTypeM2 (doP, n)
END
END outputPartialM2 ;
(*
outDeclsDefM2 -
*)
PROCEDURE outDeclsDefM2 (p: pretty; s: scopeT) ;
BEGIN
simplifyTypes (s) ;
includeConstType (s) ;
doP := p ;
topologicallyOut (doConstM2, doTypesM2, doVarsM2,
outputPartialM2,
doNothing, doNothing, doNothing) ;
includeVarProcedure (s) ;
topologicallyOut (doConstM2, doTypesM2, doVarsM2,
outputPartialM2,
doNothing, doNothing, doNothing) ;
ForeachIndiceInIndexDo (s.procedures, doPrototypeM2)
END outDeclsDefM2 ;
(*
outDefM2 -
*)
PROCEDURE outDefM2 (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
s := InitStringCharStar (keyToCharStar (getSource (n))) ;
print (p, "(* automatically created by mc from ") ; prints (p, s) ; print (p, ". *)\n\n") ;
s := KillString (s) ;
s := InitStringCharStar (keyToCharStar (getSymName (n))) ;
print (p, "DEFINITION MODULE ") ; prints (p, s) ; print (p, " ;\n\n") ;
doP := p ;
ForeachIndiceInIndexDo (n^.defF.importedModules, doIncludeM2) ;
print (p, "\n") ;
outDeclsDefM2 (p, n^.defF.decls) ;
print (p, "\n") ;
print (p, "END ") ;
prints (p, s) ;
print (p, ".\n") ;
s := KillString (s)
END outDefM2 ;
(*
outDeclsImpM2 -
*)
PROCEDURE outDeclsImpM2 (p: pretty; s: scopeT) ;
BEGIN
simplifyTypes (s) ;
includeConstType (s) ;
doP := p ;
topologicallyOut (doConstM2, doTypesM2, doVarM2,
outputPartialM2,
doNothing, doNothing, doNothing) ;
includeVarProcedure (s) ;
topologicallyOut (doConstM2, doTypesM2, doVarsM2,
outputPartialM2,
doNothing, doNothing, doNothing) ;
outText (p, "\n") ;
ForeachIndiceInIndexDo (s.procedures, doPrototypeC)
END outDeclsImpM2 ;
(*
outImpM2 -
*)
PROCEDURE outImpM2 (p: pretty; n: node) ;
VAR
s: String ;
BEGIN
s := InitStringCharStar (keyToCharStar (getSource (n))) ;
print (p, "(* automatically created by mc from ") ; prints (p, s) ; print (p, ". *)\n\n") ;
print (p, "IMPLEMENTATION MODULE ") ; prints (p, s) ; print (p, " ;\n\n") ;
doP := p ;
ForeachIndiceInIndexDo (n^.impF.importedModules, doIncludeM2) ;
print (p, "\n") ;
includeDefConstType (n) ;
outDeclsImpM2 (p, n^.impF.decls) ;
print (p, "\n") ;
print (p, "END ") ;
prints (p, s) ;
print (p, ".\n") ;
s := KillString (s)
END outImpM2 ;
(*
outModuleM2 -
*)
PROCEDURE outModuleM2 (p: pretty; n: node) ;
BEGIN
END outModuleM2 ;
(*
outM2 -
*)
PROCEDURE outM2 (p: pretty; n: node) ;
BEGIN
IF isDef (n)
THEN
outDefM2 (p, n)
ELSIF isImp (n)
THEN
outImpM2 (p, n)
ELSIF isModule (n)
THEN
outModuleM2 (p, n)
ELSE
HALT
END
END outM2 ;
(*
out - walks the tree of node declarations for the main module
and writes the output to the outputFile specified in
mcOptions. It outputs the declarations in the language
specified above.
*)
PROCEDURE out ;
VAR
p: pretty ;
BEGIN
openOutput ;
p := initPretty (write, writeln) ;
CASE lang OF
ansiC : outC (p, getMainModule ()) |
ansiCP: outC (p, getMainModule ()) |
pim4 : outM2 (p, getMainModule ())
END ;
closeOutput
END out ;
(*
setLangC -
*)
PROCEDURE setLangC ;
BEGIN
lang := ansiC
END setLangC ;
(*
setLangCP -
*)
PROCEDURE setLangCP ;
BEGIN
lang := ansiCP ;
keyc.cp
END setLangCP ;
(*
setLangM2 -
*)
PROCEDURE setLangM2 ;
BEGIN
lang := pim4
END setLangM2 ;
(*
addDone - adds node, n, to the doneQ.
*)
PROCEDURE addDone (n: node) ;
BEGIN
alists.includeItemIntoList (doneQ, n)
END addDone ;
(*
addDoneDef - adds node, n, to the doneQ providing
it is not an opaque of the main module we are compiling.
*)
PROCEDURE addDoneDef (n: node) ;
BEGIN
IF isDef (n)
THEN
addDone (n) ;
RETURN
END ;
IF (NOT isDef (n)) AND (lookupImp (getSymName (getScope (n))) = getMainModule ())
THEN
metaError1 ('cyclic dependancy found between another module using {%1ad} from the definition module of the implementation main being compiled, use the --extended-opaque option to compile', n) ;
flushErrors ;
errorAbort0 ('terminating compilation')
ELSE
addDone (n)
END
END addDoneDef ;
(*
dbgAdd -
*)
PROCEDURE dbgAdd (l: alist; n: node) : node ;
BEGIN
IF n#NIL
THEN
alists.includeItemIntoList (l, n)
END ;
RETURN n
END dbgAdd ;
(*
dbgType -
*)
PROCEDURE dbgType (l: alist; n: node) ;
VAR
t: node ;
BEGIN
t := dbgAdd (l, getType (n)) ;
out1 ("<%s type", n) ;
IF t = NIL
THEN
out0 (", type = NIL\n")
ELSE
out1 (", type = %s>\n", t)
END
END dbgType ;
(*
dbgPointer -
*)
PROCEDURE dbgPointer (l: alist; n: node) ;
VAR
t: node ;
BEGIN
t := dbgAdd (l, getType (n)) ;
out1 ("<%s pointer", n) ;
out1 (" to %s>\n", t)
END dbgPointer ;
(*
dbgRecord -
*)
PROCEDURE dbgRecord (l: alist; n: node) ;
VAR
i, t: CARDINAL ;
q : node ;
BEGIN
out1 ("<%s record:\n", n) ;
i := LowIndice (n^.recordF.listOfSons) ;
t := HighIndice (n^.recordF.listOfSons) ;
WHILE i<=t DO
q := GetIndice (n^.recordF.listOfSons, i) ;
IF isRecordField (q)
THEN
out1 (" <recordfield %s", q)
ELSIF isVarientField (q)
THEN
out1 (" <varientfield %s", q)
ELSIF isVarient (q)
THEN
out1 (" <varient %s", q)
ELSE
HALT
END ;
q := dbgAdd (l, getType (q)) ;
out1 (": %s>\n", q) ;
INC (i)
END ;
outText (doP, ">\n")
END dbgRecord ;
(*
dbgVarient -
*)
PROCEDURE dbgVarient (l: alist; n: node) ;
VAR
i, t: CARDINAL ;
q : node ;
BEGIN
out1 ("<%s varient: ", n) ;
out1 ("tag %s", n^.varientF.tag) ;
q := getType (n^.varientF.tag) ;
IF q=NIL
THEN
outText (doP, "\n")
ELSE
out1 (": %s\n", q) ;
q := dbgAdd (l, q)
END ;
i := LowIndice (n^.varientF.listOfSons) ;
t := HighIndice (n^.varientF.listOfSons) ;
WHILE i<=t DO
q := GetIndice (n^.varientF.listOfSons, i) ;
IF isRecordField (q)
THEN
out1 (" <recordfield %s", q)
ELSIF isVarientField (q)
THEN
out1 (" <varientfield %s", q)
ELSIF isVarient (q)
THEN
out1 (" <varient %s", q)
ELSE
HALT
END ;
q := dbgAdd (l, getType (q)) ;
out1 (": %s>\n", q) ;
INC (i)
END ;
outText (doP, ">\n")
END dbgVarient ;
(*
dbgEnumeration -
*)
PROCEDURE dbgEnumeration (l: alist; n: node) ;
VAR
e : node ;
i, h: CARDINAL ;
BEGIN
outText (doP, "< enumeration ") ;
i := LowIndice (n^.enumerationF.listOfSons) ;
h := HighIndice (n^.enumerationF.listOfSons) ;
WHILE i<=h DO
e := GetIndice (n^.enumerationF.listOfSons, i) ;
out1 ("%s, ", e) ;
INC (i)
END ;
outText (doP, ">\n")
END dbgEnumeration ;
(*
dbgVar -
*)
PROCEDURE dbgVar (l: alist; n: node) ;
VAR
t: node ;
BEGIN
t := dbgAdd (l, getType (n)) ;
out1 ("<%s var", n) ;
out1 (", type = %s>\n", t)
END dbgVar ;
(*
dbgSubrange -
*)
PROCEDURE dbgSubrange (l: alist; n: node) ;
BEGIN
IF n^.subrangeF.low = NIL
THEN
out1 ('%s', n^.subrangeF.type)
ELSE
out1 ('[%s', n^.subrangeF.low) ;
out1 ('..%s]', n^.subrangeF.high)
END
END dbgSubrange ;
(*
dbgArray -
*)
PROCEDURE dbgArray (l: alist; n: node) ;
VAR
t: node ;
BEGIN
t := dbgAdd (l, getType (n)) ;
out1 ("<%s array ", n) ;
IF n^.arrayF.subr # NIL
THEN
dbgSubrange (l, n^.arrayF.subr)
END ;
out1 (" of %s>\n", t)
END dbgArray ;
(*
doDbg -
*)
PROCEDURE doDbg (l: alist; n: node) ;
BEGIN
IF n=NIL
THEN
(* do nothing. *)
ELSIF isSubrange (n)
THEN
dbgSubrange (l, n)
ELSIF isType (n)
THEN
dbgType (l, n)
ELSIF isRecord (n)
THEN
dbgRecord (l, n)
ELSIF isVarient (n)
THEN
dbgVarient (l, n)
ELSIF isEnumeration (n)
THEN
dbgEnumeration (l, n)
ELSIF isPointer (n)
THEN
dbgPointer (l, n)
ELSIF isArray (n)
THEN
dbgArray (l, n)
ELSIF isVar (n)
THEN
dbgVar (l, n)
END
END doDbg ;
(*
dbg -
*)
PROCEDURE dbg (n: node) ;
VAR
l: alist ;
o: pretty ;
f: File ;
s: String ;
i: CARDINAL ;
BEGIN
o := doP ;
f := outputFile ;
outputFile := StdOut ;
doP := initPretty (write, writeln) ;
l := alists.initList () ;
alists.includeItemIntoList (l, n) ;
i := 1 ;
out1 ("dbg (%s)\n", n) ;
REPEAT
n := alists.getItemFromList (l, i) ;
doDbg (l, n) ;
INC (i)
UNTIL i>alists.noOfItemsInList (l) ;
doP := o ;
outputFile := f
END dbg ;
(*
makeStatementSequence - create and return a statement sequence node.
*)
PROCEDURE makeStatementSequence () : node ;
VAR
n: node ;
BEGIN
n := newNode (stmtseq) ;
n^.stmtF.statements := InitIndex (1) ;
RETURN n
END makeStatementSequence ;
(*
addStatement - adds node, n, as a statement to statememt sequence, s.
*)
PROCEDURE addStatement (s: node; n: node) ;
BEGIN
IF n#NIL
THEN
assert (isStatementSequence (s)) ;
PutIndice (s^.stmtF.statements, HighIndice (s^.stmtF.statements) + 1, n) ;
IF isIntrinsic (n) AND (n^.intrinsicF.postUnreachable)
THEN
n^.intrinsicF.postUnreachable := FALSE ;
addStatement (s, makeIntrinsicProc (unreachable, 0, NIL))
END
END
END addStatement ;
(*
isStatementSequence - returns TRUE if node, n, is a statement sequence.
*)
PROCEDURE isStatementSequence (n: node) : BOOLEAN ;
BEGIN
RETURN n^.kind = stmtseq
END isStatementSequence ;
(*
addGenericBody - adds comment node to funccall, return, assignment
nodes.
*)
PROCEDURE addGenericBody (n, c: node);
BEGIN
CASE n^.kind OF
unreachable,
throw,
halt,
new,
dispose,
inc,
dec,
incl,
excl : n^.intrinsicF.intrinsicComment.body := c |
funccall : n^.funccallF.funccallComment.body := c |
return : n^.returnF.returnComment.body := c |
assignment: n^.assignmentF.assignComment.body := c |
module : n^.moduleF.com.body := c |
def : n^.defF.com.body := c |
imp : n^.impF.com.body := c
ELSE
END
END addGenericBody;
(*
addGenericAfter - adds comment node to funccall, return, assignment
nodes.
*)
PROCEDURE addGenericAfter (n, c: node);
BEGIN
CASE n^.kind OF
unreachable,
throw,
halt,
new,
dispose,
inc,
dec,
incl,
excl : n^.intrinsicF.intrinsicComment.after := c |
funccall : n^.funccallF.funccallComment.after := c |
return : n^.returnF.returnComment.after := c |
assignment: n^.assignmentF.assignComment.after := c |
module : n^.moduleF.com.after := c |
def : n^.defF.com.after := c |
imp : n^.impF.com.after := c
ELSE
END
END addGenericAfter ;
(*
addCommentBody - adds a body comment to a statement sequence node.
*)
PROCEDURE addCommentBody (n: node) ;
VAR
b: commentDesc ;
BEGIN
IF n # NIL
THEN
b := getBodyComment () ;
IF b # NIL
THEN
addGenericBody (n, makeCommentS (b))
END
END
END addCommentBody ;
(*
addCommentAfter - adds an after comment to a statement sequence node.
*)
PROCEDURE addCommentAfter (n: node) ;
VAR
a: commentDesc ;
BEGIN
IF n # NIL
THEN
a := getAfterComment () ;
IF a # NIL
THEN
addGenericAfter (n, makeCommentS (a))
END
END
END addCommentAfter ;
(*
addIfComments - adds the, body, and, after, comments to if node, n.
*)
PROCEDURE addIfComments (n: node; body, after: node) ;
BEGIN
assert (isIf (n)) ;
n^.ifF.ifComment.after := after ;
n^.ifF.ifComment.body := body
END addIfComments ;
(*
addElseComments - adds the, body, and, after, comments to an, if, or an elsif, node, n.
*)
PROCEDURE addElseComments (n: node; body, after: node) ;
BEGIN
assert (isIf (n) OR isElsif (n)) ;
IF isIf (n)
THEN
n^.ifF.elseComment.after := after ;
n^.ifF.elseComment.body := body
ELSE
n^.elsifF.elseComment.after := after ;
n^.elsifF.elseComment.body := body
END
END addElseComments ;
(*
addIfEndComments - adds the, body, and, after, comments to an, if, node, n.
*)
PROCEDURE addIfEndComments (n: node; body, after: node) ;
BEGIN
assert (isIf (n)) ;
n^.ifF.endComment.after := after ;
n^.ifF.endComment.body := body
END addIfEndComments ;
(*
makeReturn - creates and returns a return node.
*)
PROCEDURE makeReturn () : node ;
VAR
type,
n : node ;
BEGIN
n := newNode (return) ;
n^.returnF.exp := NIL ;
IF isProcedure (getDeclScope ())
THEN
n^.returnF.scope := getDeclScope ()
ELSE
n^.returnF.scope := NIL
END ;
initPair (n^.returnF.returnComment) ;
RETURN n
END makeReturn ;
(*
isReturn - returns TRUE if node, n, is a return.
*)
PROCEDURE isReturn (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = return
END isReturn ;
(*
putReturn - assigns node, e, as the expression on the return node.
*)
PROCEDURE putReturn (n: node; e: node) ;
BEGIN
assert (isReturn (n)) ;
n^.returnF.exp := e
END putReturn ;
(*
makeWhile - creates and returns a while node.
*)
PROCEDURE makeWhile () : node ;
VAR
n: node ;
BEGIN
n := newNode (while) ;
n^.whileF.expr := NIL ;
n^.whileF.statements := NIL ;
initPair (n^.whileF.doComment) ;
initPair (n^.whileF.endComment) ;
RETURN n
END makeWhile ;
(*
putWhile - places an expression, e, and statement sequence, s, into the while
node, n.
*)
PROCEDURE putWhile (n: node; e, s: node) ;
BEGIN
assert (isWhile (n)) ;
n^.whileF.expr := e ;
n^.whileF.statements := s
END putWhile ;
(*
isWhile - returns TRUE if node, n, is a while.
*)
PROCEDURE isWhile (n: node) : BOOLEAN ;
BEGIN
RETURN n^.kind = while
END isWhile ;
(*
addWhileDoComment - adds body and after comments to while node, w.
*)
PROCEDURE addWhileDoComment (w: node; body, after: node) ;
BEGIN
assert (isWhile (w)) ;
w^.whileF.doComment.after := after ;
w^.whileF.doComment.body := body
END addWhileDoComment ;
(*
addWhileEndComment - adds body and after comments to the end of a while node, w.
*)
PROCEDURE addWhileEndComment (w: node; body, after: node) ;
BEGIN
assert (isWhile (w)) ;
w^.whileF.endComment.after := after ;
w^.whileF.endComment.body := body
END addWhileEndComment ;
(*
makeAssignment - creates and returns an assignment node.
The designator is, d, and expression, e.
*)
PROCEDURE makeAssignment (d, e: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (assignment) ;
n^.assignmentF.des := d ;
n^.assignmentF.expr := e ;
initPair (n^.assignmentF.assignComment) ;
RETURN n
END makeAssignment ;
(*
isAssignment -
*)
PROCEDURE isAssignment (n: node) : BOOLEAN ;
BEGIN
RETURN n^.kind = assignment
END isAssignment ;
(*
putBegin - assigns statements, s, to be the normal part in
block, b. The block may be a procedure or module,
or implementation node.
*)
PROCEDURE putBegin (b: node; s: node) ;
BEGIN
assert (isImp (b) OR isProcedure (b) OR isModule (b)) ;
CASE b^.kind OF
imp : b^.impF.beginStatements := s |
module : b^.moduleF.beginStatements := s |
procedure: b^.procedureF.beginStatements := s
END
END putBegin ;
(*
putFinally - assigns statements, s, to be the final part in
block, b. The block may be a module
or implementation node.
*)
PROCEDURE putFinally (b: node; s: node) ;
BEGIN
assert (isImp (b) OR isProcedure (b) OR isModule (b)) ;
CASE b^.kind OF
imp : b^.impF.finallyStatements := s |
module : b^.moduleF.finallyStatements := s
END
END putFinally ;
(*
makeExit - creates and returns an exit node.
*)
PROCEDURE makeExit (l: node; n: CARDINAL) : node ;
VAR
e: node ;
BEGIN
assert (isLoop (l)) ;
e := newNode (exit) ;
e^.exitF.loop := l ;
l^.loopF.labelno := n ;
RETURN e
END makeExit ;
(*
isExit - returns TRUE if node, n, is an exit.
*)
PROCEDURE isExit (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = exit
END isExit ;
(*
makeLoop - creates and returns a loop node.
*)
PROCEDURE makeLoop () : node ;
VAR
l: node ;
BEGIN
l := newNode (loop) ;
l^.loopF.statements := NIL ;
l^.loopF.labelno := 0 ;
RETURN l
END makeLoop ;
(*
putLoop - places statement sequence, s, into loop, l.
*)
PROCEDURE putLoop (l, s: node) ;
BEGIN
assert (isLoop (l)) ;
l^.loopF.statements := s
END putLoop ;
(*
isLoop - returns TRUE if, n, is a loop node.
*)
PROCEDURE isLoop (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = loop
END isLoop ;
(*
makeComment - creates and returns a comment node.
*)
PROCEDURE makeComment (a: ARRAY OF CHAR) : node ;
VAR
c: commentDesc ;
s: String ;
BEGIN
c := initComment (TRUE) ;
s := InitString (a) ;
addText (c, DynamicStrings.string (s)) ;
s := KillString (s) ;
RETURN makeCommentS (c)
END makeComment ;
(*
makeCommentS - creates and returns a comment node.
*)
PROCEDURE makeCommentS (c: commentDesc) : node ;
VAR
n: node ;
BEGIN
IF c = NIL
THEN
RETURN NIL
ELSE
n := newNode (comment) ;
n^.commentF.content := c ;
RETURN n
END
END makeCommentS ;
(*
isComment - returns TRUE if node, n, is a comment.
*)
PROCEDURE isComment (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = comment
END isComment ;
(*
initPair - initialise the commentPair, c.
*)
PROCEDURE initPair (VAR c: commentPair) ;
BEGIN
c.after := NIL ;
c.body := NIL
END initPair ;
(*
makeIf - creates and returns an if node. The if node
will have expression, e, and statement sequence, s,
as the then component.
*)
PROCEDURE makeIf (e, s: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (if) ;
n^.ifF.expr := e ;
n^.ifF.then := s ;
n^.ifF.else := NIL ;
n^.ifF.elsif := NIL ;
initPair (n^.ifF.ifComment) ;
initPair (n^.ifF.elseComment) ;
initPair (n^.ifF.endComment) ;
RETURN n
END makeIf ;
(*
isIf - returns TRUE if, n, is an if node.
*)
PROCEDURE isIf (n: node) : BOOLEAN ;
BEGIN
RETURN n^.kind = if
END isIf ;
(*
makeElsif - creates and returns an elsif node.
This node has an expression, e, and statement
sequence, s.
*)
PROCEDURE makeElsif (i, e, s: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (elsif) ;
n^.elsifF.expr := e ;
n^.elsifF.then := s ;
n^.elsifF.elsif := NIL ;
n^.elsifF.else := NIL ;
initPair (n^.elsifF.elseComment) ;
assert (isIf (i) OR isElsif (i)) ;
IF isIf (i)
THEN
i^.ifF.elsif := n ;
assert (i^.ifF.else = NIL)
ELSE
i^.elsifF.elsif := n ;
assert (i^.elsifF.else = NIL)
END ;
RETURN n
END makeElsif ;
(*
isElsif - returns TRUE if node, n, is an elsif node.
*)
PROCEDURE isElsif (n: node) : BOOLEAN ;
BEGIN
RETURN n^.kind = elsif
END isElsif ;
(*
putElse - the else is grafted onto the if/elsif node, i,
and the statement sequence will be, s.
*)
PROCEDURE putElse (i, s: node) ;
BEGIN
assert (isIf (i) OR isElsif (i)) ;
IF isIf (i)
THEN
assert (i^.ifF.elsif = NIL) ;
assert (i^.ifF.else = NIL) ;
i^.ifF.else := s
ELSE
assert (i^.elsifF.elsif = NIL) ;
assert (i^.elsifF.else = NIL) ;
i^.elsifF.else := s
END
END putElse ;
(*
makeFor - creates and returns a for node.
*)
PROCEDURE makeFor () : node ;
VAR
n: node ;
BEGIN
n := newNode (for) ;
n^.forF.des := NIL ;
n^.forF.start := NIL ;
n^.forF.end := NIL ;
n^.forF.increment := NIL ;
n^.forF.statements := NIL ;
RETURN n
END makeFor ;
(*
isFor - returns TRUE if node, n, is a for node.
*)
PROCEDURE isFor (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = for
END isFor ;
(*
putFor - assigns the fields of the for node with
ident, i,
start, s,
end, e,
increment, i,
statements, sq.
*)
PROCEDURE putFor (f, i, s, e, b, sq: node) ;
BEGIN
assert (isFor (f)) ;
f^.forF.des := i ;
f^.forF.start := s ;
f^.forF.end := e ;
f^.forF.increment := b ;
f^.forF.statements := sq
END putFor ;
(*
makeRepeat - creates and returns a repeat node.
*)
PROCEDURE makeRepeat () : node ;
VAR
n: node ;
BEGIN
n := newNode (repeat) ;
n^.repeatF.expr := NIL ;
n^.repeatF.statements := NIL ;
initPair (n^.repeatF.repeatComment) ;
initPair (n^.repeatF.untilComment) ;
RETURN n
END makeRepeat ;
(*
isRepeat - returns TRUE if node, n, is a repeat node.
*)
PROCEDURE isRepeat (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = repeat
END isRepeat ;
(*
putRepeat - places statements, s, and expression, e, into
repeat statement, n.
*)
PROCEDURE putRepeat (n, s, e: node) ;
BEGIN
n^.repeatF.expr := e ;
n^.repeatF.statements := s
END putRepeat ;
(*
addRepeatComment - adds body and after comments to repeat node, r.
*)
PROCEDURE addRepeatComment (r: node; body, after: node) ;
BEGIN
assert (isRepeat (r)) ;
r^.repeatF.repeatComment.after := after ;
r^.repeatF.repeatComment.body := body
END addRepeatComment ;
(*
addUntilComment - adds body and after comments to the until section of a repeat node, r.
*)
PROCEDURE addUntilComment (r: node; body, after: node) ;
BEGIN
assert (isRepeat (r)) ;
r^.repeatF.untilComment.after := after ;
r^.repeatF.untilComment.body := body
END addUntilComment ;
(*
makeCase - builds and returns a case statement node.
*)
PROCEDURE makeCase () : node ;
VAR
n: node ;
BEGIN
n := newNode (case) ;
n^.caseF.expression := NIL ;
n^.caseF.caseLabelList := InitIndex (1) ;
n^.caseF.else := NIL ;
RETURN n
END makeCase ;
(*
isCase - returns TRUE if node, n, is a case statement.
*)
PROCEDURE isCase (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = case
END isCase ;
(*
putCaseExpression - places expression, e, into case statement, n.
n is returned.
*)
PROCEDURE putCaseExpression (n: node; e: node) : node ;
BEGIN
assert (isCase (n)) ;
n^.caseF.expression := e ;
RETURN n
END putCaseExpression ;
(*
putCaseElse - places else statement, e, into case statement, n.
n is returned.
*)
PROCEDURE putCaseElse (n: node; e: node) : node ;
BEGIN
assert (isCase (n)) ;
n^.caseF.else := e ;
RETURN n
END putCaseElse ;
(*
putCaseStatement - places a caselist, l, and associated
statement sequence, s, into case statement, n.
n is returned.
*)
PROCEDURE putCaseStatement (n: node; l: node; s: node) : node ;
BEGIN
assert (isCase (n)) ;
assert (isCaseList (l)) ;
IncludeIndiceIntoIndex (n^.caseF.caseLabelList, makeCaseLabelList (l, s)) ;
RETURN n
END putCaseStatement ;
(*
makeCaseLabelList - creates and returns a caselabellist node.
*)
PROCEDURE makeCaseLabelList (l, s: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (caselabellist) ;
n^.caselabellistF.caseList := l ;
n^.caselabellistF.statements := s ;
RETURN n
END makeCaseLabelList ;
(*
isCaseLabelList - returns TRUE if, n, is a caselabellist.
*)
PROCEDURE isCaseLabelList (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = caselabellist
END isCaseLabelList ;
(*
makeCaseList - creates and returns a case statement node.
*)
PROCEDURE makeCaseList () : node ;
VAR
n: node ;
BEGIN
n := newNode (caselist) ;
n^.caselistF.rangePairs := InitIndex (1) ;
RETURN n
END makeCaseList ;
(*
isCaseList - returns TRUE if, n, is a case list.
*)
PROCEDURE isCaseList (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = caselist
END isCaseList ;
(*
putCaseRange - places the case range lo..hi into caselist, n.
*)
PROCEDURE putCaseRange (n: node; lo, hi: node) : node ;
BEGIN
assert (isCaseList (n)) ;
IncludeIndiceIntoIndex (n^.caselistF.rangePairs, makeRange (lo, hi)) ;
RETURN n
END putCaseRange ;
(*
makeRange - creates and returns a case range.
*)
PROCEDURE makeRange (lo, hi: node) : node ;
VAR
n: node ;
BEGIN
n := newNode (range) ;
n^.rangeF.lo := lo ;
n^.rangeF.hi := hi ;
RETURN n
END makeRange ;
(*
isRange - returns TRUE if node, n, is a range.
*)
PROCEDURE isRange (n: node) : BOOLEAN ;
BEGIN
assert (n # NIL) ;
RETURN n^.kind = range
END isRange ;
(*
dupExplist -
*)
PROCEDURE dupExplist (n: node) : node ;
VAR
m: node ;
i: CARDINAL ;
BEGIN
assert (isExpList (n)) ;
m := makeExpList () ;
i := LowIndice (n^.explistF.exp) ;
WHILE i <= HighIndice (n^.explistF.exp) DO
putExpList (m, dupExpr (GetIndice (n^.explistF.exp, i))) ;
INC (i)
END ;
RETURN m
END dupExplist ;
(*
dupArrayref -
*)
PROCEDURE dupArrayref (n: node) : node ;
BEGIN
assert (isArrayRef (n)) ;
RETURN makeArrayRef (dupExpr (n^.arrayrefF.array), dupExpr (n^.arrayrefF.index))
END dupArrayref ;
(*
dupPointerref -
*)
PROCEDURE dupPointerref (n: node) : node ;
BEGIN
assert (isPointerRef (n)) ;
RETURN makePointerRef (dupExpr (n^.pointerrefF.ptr), dupExpr (n^.pointerrefF.field))
END dupPointerref ;
(*
dupComponentref -
*)
PROCEDURE dupComponentref (n: node) : node ;
BEGIN
assert (isComponentRef (n)) ;
RETURN doMakeComponentRef (dupExpr (n^.componentrefF.rec), dupExpr (n^.componentrefF.field))
END dupComponentref ;
(*
dupBinary -
*)
PROCEDURE dupBinary (n: node) : node ;
BEGIN
(* assert (isBinary (n)) ; *)
RETURN makeBinary (n^.kind,
dupExpr (n^.binaryF.left), dupExpr (n^.binaryF.right),
n^.binaryF.resultType)
END dupBinary ;
(*
dupUnary -
*)
PROCEDURE dupUnary (n: node) : node ;
BEGIN
(* assert (isUnary (n)) ; *)
RETURN makeUnary (n^.kind, dupExpr (n^.unaryF.arg), n^.unaryF.resultType)
END dupUnary ;
(*
dupFunccall -
*)
PROCEDURE dupFunccall (n: node) : node ;
VAR
m: node ;
BEGIN
assert (isFuncCall (n)) ;
m := makeFuncCall (dupExpr (n^.funccallF.function), dupExpr (n^.funccallF.args)) ;
m^.funccallF.type := n^.funccallF.type ;
RETURN m
END dupFunccall ;
(*
dupSetValue -
*)
PROCEDURE dupSetValue (n: node) : node ;
VAR
m: node ;
i: CARDINAL ;
BEGIN
m := newNode (setvalue) ;
m^.setvalueF.type := n^.setvalueF.type ;
i := LowIndice (n^.setvalueF.values) ;
WHILE i <= HighIndice (n^.setvalueF.values) DO
m := putSetValue (m, dupExpr (GetIndice (n^.setvalueF.values, i))) ;
INC (i)
END ;
RETURN m
END dupSetValue ;
(*
dupExpr - duplicate the expression nodes, it does not duplicate
variables, literals, constants but only the expression
operators (including function calls and parameter lists).
*)
PROCEDURE dupExpr (n: node) : node ;
BEGIN
IF n = NIL
THEN
RETURN NIL
ELSE
RETURN doDupExpr (n)
END
END dupExpr ;
(*
doDupExpr -
*)
PROCEDURE doDupExpr (n: node) : node ;
BEGIN
assert (n # NIL) ;
CASE n^.kind OF
explist : RETURN dupExplist (n) |
exit,
return,
stmtseq,
comment : HALT | (* should not be duplicating code. *)
length : HALT | (* length should have been converted into unary. *)
(* base constants. *)
nil,
true,
false,
(* system types. *)
address,
loc,
byte,
word,
csizet,
cssizet,
(* base types. *)
boolean,
proc,
char,
integer,
cardinal,
longcard,
shortcard,
longint,
shortint,
real,
longreal,
shortreal,
bitset,
ztype,
rtype,
complex,
longcomplex,
shortcomplex : RETURN n |
(* language features and compound type attributes. *)
type,
record,
varient,
var,
enumeration,
subrange,
subscript,
array,
string,
const,
literal,
varparam,
param,
varargs,
optarg,
pointer,
recordfield,
varientfield,
enumerationfield,
set,
proctype : RETURN n |
(* blocks. *)
procedure,
def,
imp,
module : RETURN n |
(* statements. *)
loop,
while,
for,
repeat,
case,
caselabellist,
caselist,
range,
if,
elsif,
assignment : RETURN n |
(* expressions. *)
arrayref : RETURN dupArrayref (n) |
pointerref : RETURN dupPointerref (n) |
componentref : RETURN dupComponentref (n) |
cmplx,
and,
or,
equal,
notequal,
less,
greater,
greequal,
lessequal,
cast,
val,
plus,
sub,
div,
mod,
mult,
divide,
in : RETURN dupBinary (n) |
re,
im,
constexp,
deref,
abs,
chr,
cap,
high,
float,
trunc,
ord,
not,
neg,
adr,
size,
tsize,
min,
max : RETURN dupUnary (n) |
identlist : RETURN n |
vardecl : RETURN n |
funccall : RETURN dupFunccall (n) |
setvalue : RETURN dupSetValue (n)
END
END doDupExpr ;
(*
setNoReturn - sets noreturn field inside procedure.
*)
PROCEDURE setNoReturn (n: node; value: BOOLEAN) ;
BEGIN
assert (n#NIL) ;
assert (isProcedure (n)) ;
IF n^.procedureF.noreturnused AND (n^.procedureF.noreturn # value)
THEN
metaError1 ('{%1DMad} definition module and implementation module have different <* noreturn *> attributes', n) ;
END ;
n^.procedureF.noreturn := value ;
n^.procedureF.noreturnused := TRUE
END setNoReturn ;
(*
makeSystem -
*)
PROCEDURE makeSystem ;
BEGIN
systemN := lookupDef (makeKey ('SYSTEM')) ;
addressN := makeBase (address) ;
locN := makeBase (loc) ;
byteN := makeBase (byte) ;
wordN := makeBase (word) ;
csizetN := makeBase (csizet) ;
cssizetN := makeBase (cssizet) ;
adrN := makeBase (adr) ;
tsizeN := makeBase (tsize) ;
throwN := makeBase (throw) ;
enterScope (systemN) ;
addressN := addToScope (addressN) ;
locN := addToScope (locN) ;
byteN := addToScope (byteN) ;
wordN := addToScope (wordN) ;
csizetN := addToScope (csizetN) ;
cssizetN := addToScope (cssizetN) ;
adrN := addToScope (adrN) ;
tsizeN := addToScope (tsizeN) ;
throwN := addToScope (throwN) ;
assert (sizeN#NIL) ; (* assumed to be built already. *)
sizeN := addToScope (sizeN) ; (* also export size from system. *)
leaveScope ;
addDone (addressN) ;
addDone (locN) ;
addDone (byteN) ;
addDone (wordN) ;
addDone (csizetN) ;
addDone (cssizetN)
END makeSystem ;
(*
makeM2rts -
*)
PROCEDURE makeM2rts ;
BEGIN
m2rtsN := lookupDef (makeKey ('M2RTS'))
END makeM2rts ;
(*
makeBitnum -
*)
PROCEDURE makeBitnum () : node ;
VAR
b: node ;
BEGIN
b := newNode (subrange) ;
b^.subrangeF.type := NIL ;
b^.subrangeF.scope := NIL ;
b^.subrangeF.low := lookupConst (b, makeKey ('0')) ;
b^.subrangeF.high := lookupConst (b, makeKey ('31')) ;
RETURN b
END makeBitnum ;
(*
makeBaseSymbols -
*)
PROCEDURE makeBaseSymbols ;
BEGIN
baseSymbols := initTree () ;
booleanN := makeBase (boolean) ;
charN := makeBase (char) ;
procN := makeBase (proc) ;
cardinalN := makeBase (cardinal) ;
longcardN := makeBase (longcard) ;
shortcardN := makeBase (shortcard) ;
integerN := makeBase (integer) ;
longintN := makeBase (longint) ;
shortintN := makeBase (shortint) ;
bitsetN := makeBase (bitset) ;
bitnumN := makeBitnum () ;
ztypeN := makeBase (ztype) ;
rtypeN := makeBase (rtype) ;
complexN := makeBase (complex) ;
longcomplexN := makeBase (longcomplex) ;
shortcomplexN := makeBase (shortcomplex) ;
realN := makeBase (real) ;
longrealN := makeBase (longreal) ;
shortrealN := makeBase (shortreal) ;
nilN := makeBase (nil) ;
trueN := makeBase (true) ;
falseN := makeBase (false) ;
sizeN := makeBase (size) ;
minN := makeBase (min) ;
maxN := makeBase (max) ;
floatN := makeBase (float) ;
truncN := makeBase (trunc) ;
ordN := makeBase (ord) ;
valN := makeBase (val) ;
chrN := makeBase (chr) ;
capN := makeBase (cap) ;
absN := makeBase (abs) ;
newN := makeBase (new) ;
disposeN := makeBase (dispose) ;
lengthN := makeBase (length) ;
incN := makeBase (inc) ;
decN := makeBase (dec) ;
inclN := makeBase (incl) ;
exclN := makeBase (excl) ;
highN := makeBase (high) ;
imN := makeBase (im) ;
reN := makeBase (re) ;
cmplxN := makeBase (cmplx) ;
putSymKey (baseSymbols, makeKey ('BOOLEAN'), booleanN) ;
putSymKey (baseSymbols, makeKey ('PROC'), procN) ;
putSymKey (baseSymbols, makeKey ('CHAR'), charN) ;
putSymKey (baseSymbols, makeKey ('CARDINAL'), cardinalN) ;
putSymKey (baseSymbols, makeKey ('SHORTCARD'), shortcardN) ;
putSymKey (baseSymbols, makeKey ('LONGCARD'), longcardN) ;
putSymKey (baseSymbols, makeKey ('INTEGER'), integerN) ;
putSymKey (baseSymbols, makeKey ('LONGINT'), longintN) ;
putSymKey (baseSymbols, makeKey ('SHORTINT'), shortintN) ;
putSymKey (baseSymbols, makeKey ('BITSET'), bitsetN) ;
putSymKey (baseSymbols, makeKey ('REAL'), realN) ;
putSymKey (baseSymbols, makeKey ('SHORTREAL'), shortrealN) ;
putSymKey (baseSymbols, makeKey ('LONGREAL'), longrealN) ;
putSymKey (baseSymbols, makeKey ('COMPLEX'), complexN) ;
putSymKey (baseSymbols, makeKey ('LONGCOMPLEX'), longcomplexN) ;
putSymKey (baseSymbols, makeKey ('SHORTCOMPLEX'), shortcomplexN) ;
putSymKey (baseSymbols, makeKey ('NIL'), nilN) ;
putSymKey (baseSymbols, makeKey ('TRUE'), trueN) ;
putSymKey (baseSymbols, makeKey ('FALSE'), falseN) ;
putSymKey (baseSymbols, makeKey ('SIZE'), sizeN) ;
putSymKey (baseSymbols, makeKey ('MIN'), minN) ;
putSymKey (baseSymbols, makeKey ('MAX'), maxN) ;
putSymKey (baseSymbols, makeKey ('FLOAT'), floatN) ;
putSymKey (baseSymbols, makeKey ('TRUNC'), truncN) ;
putSymKey (baseSymbols, makeKey ('ORD'), ordN) ;
putSymKey (baseSymbols, makeKey ('VAL'), valN) ;
putSymKey (baseSymbols, makeKey ('CHR'), chrN) ;
putSymKey (baseSymbols, makeKey ('CAP'), capN) ;
putSymKey (baseSymbols, makeKey ('ABS'), absN) ;
putSymKey (baseSymbols, makeKey ('NEW'), newN) ;
putSymKey (baseSymbols, makeKey ('DISPOSE'), disposeN) ;
putSymKey (baseSymbols, makeKey ('LENGTH'), lengthN) ;
putSymKey (baseSymbols, makeKey ('INC'), incN) ;
putSymKey (baseSymbols, makeKey ('DEC'), decN) ;
putSymKey (baseSymbols, makeKey ('INCL'), inclN) ;
putSymKey (baseSymbols, makeKey ('EXCL'), exclN) ;
putSymKey (baseSymbols, makeKey ('HIGH'), highN) ;
putSymKey (baseSymbols, makeKey ('CMPLX'), cmplxN) ;
putSymKey (baseSymbols, makeKey ('RE'), reN) ;
putSymKey (baseSymbols, makeKey ('IM'), imN) ;
addDone (booleanN) ;
addDone (charN) ;
addDone (cardinalN) ;
addDone (longcardN) ;
addDone (shortcardN) ;
addDone (integerN) ;
addDone (longintN) ;
addDone (shortintN) ;
addDone (bitsetN) ;
addDone (bitnumN) ;
addDone (ztypeN) ;
addDone (rtypeN) ;
addDone (realN) ;
addDone (longrealN) ;
addDone (shortrealN) ;
addDone (complexN) ;
addDone (longcomplexN) ;
addDone (shortcomplexN) ;
addDone (procN) ;
addDone (nilN) ;
addDone (trueN) ;
addDone (falseN)
END makeBaseSymbols ;
(*
makeBuiltins -
*)
PROCEDURE makeBuiltins ;
BEGIN
bitsperunitN := makeLiteralInt (makeKey ('8')) ;
bitsperwordN := makeLiteralInt (makeKey ('32')) ;
bitspercharN := makeLiteralInt (makeKey ('8')) ;
unitsperwordN := makeLiteralInt (makeKey ('4')) ;
addDone (bitsperunitN) ;
addDone (bitsperwordN) ;
addDone (bitspercharN) ;
addDone (unitsperwordN)
END makeBuiltins ;
(*
init -
*)
PROCEDURE init ;
BEGIN
lang := ansiC ;
outputFile := StdOut ;
doP := initPretty (write, writeln) ;
todoQ := alists.initList () ;
partialQ := alists.initList () ;
doneQ := alists.initList () ;
modUniverse := initTree () ;
defUniverse := initTree () ;
modUniverseI := InitIndex (1) ;
defUniverseI := InitIndex (1) ;
scopeStack := InitIndex (1) ;
makeBaseSymbols ;
makeSystem ;
makeBuiltins ;
makeM2rts ;
outputState := punct ;
tempCount := 0 ;
mustVisitScope := FALSE
END init ;
BEGIN
init
END decl.