-- MDSupportImpl.mesa
-- last edit by Schmidt, 4-Mar-82 14:13:41
-- last edit by Satterthwaite, January 31, 1983 9:56 am
-- Pilot 6.0/ Mesa 7.0
-- mdsupportimpl for the system modeller
-- this module is also used in DesignModel.Config
DIRECTORY
CompilerOps: TYPE USING [LetterSwitches],
CWF: TYPE USING [SWF1, SWF2, WF0, WF1, WF2],
Dir: TYPE USING [FileInfo, FileInfoRecord],
Directory: TYPE USING [Error, Handle, ignore, Lookup],
Environment: TYPE USING [wordsPerPage],
File: TYPE USING [Capability, nullCapability],
Inline: TYPE USING [LowHalf],
LongString: TYPE USING [EqualString, EquivalentString],
MDModel: TYPE USING [APPLSymbol, CkType, LETSymbol, LISTSymbol, ListType, LocForType,
LOCSymbol, ModelSeqRecord, MODELSymbol, NarrowToLET, NarrowToLIST,
NarrowToLOC, NarrowToMODEL, NarrowToTYPE, OPENSymbol, PROCSymbol,
STRINGSymbol, SubType, Sym, Symbol, SymbolRecord, SymbolSeq, SymbolSeqRecord, TYPESymbol],
PilotLoadStateOps: TYPE USING [NullConfig],
Runtime: TYPE USING [CallDebugger],
Space: TYPE USING [Create, CreateUniformSwapUnits, Delete, GetHandle, Handle, LongPointer, Map,
nullHandle, PageFromLongPointer, virtualMemory],
String: TYPE USING [LowerCase],
Subr: TYPE USING [CopyString, debugflg, FindMappedSpace, FreeString, GetCreateDateWithSpace,
LongZone, Prefix, SubStrCopy],
TimeStamp: TYPE USING [Null, Stamp];
MDSupportImpl: PROGRAM
IMPORTS CWF, Directory, Inline, LongString, MDModel, Runtime, Space, String,
Subr
EXPORTS MDModel = {
NumberOfModels: CARDINAL = 10;
NumberOfFileInfoRecords: CARDINAL = 300;
-- declarations used throughout this module
TooManySymbols: ERROR = CODE;
FileInfoSeq: TYPE = LONG POINTER TO FileInfoSeqRecord;
FileInfoSeqRecord: TYPE = RECORD[
size: CARDINAL ← 0,
body: SEQUENCE maxsize: CARDINAL OF Dir.FileInfo
];
-- MDS Usage!!
-- these are set by StartMDSupport and freed by StopMDSupport
traversetreecalled: PUBLIC CARDINAL ← 0;
numberofbcdsmapped: PUBLIC CARDINAL ← 0;
numberofsourcesparsed: PUBLIC CARDINAL ← 0;
globalLDSpace: Space.Handle ← Space.nullHandle; -- should be monitored
fileInfoSeq: FileInfoSeq ← NIL;
-- end of MDS usage
-- for FileInfo
-- takes a LOC, returns its fi if already calculated
-- if not, will look on local disk for bcd and src files
-- does not compute bcdvers or depseq's or the moduleName, which would require it to analyze the
-- contents of the source or bcd files
GetFileInfo: PUBLIC PROC[sploc: MDModel.LOCSymbol] RETURNS[fi: Dir.FileInfo] = {
MDModel.CkType[sploc, $typeLOC];
IF sploc.fi ~= NIL THEN RETURN[sploc.fi];
{
longzone: UNCOUNTED ZONE ← Subr.LongZone[];
srcsfn: STRING ← [100];
bcdsfn: STRING ← [100];
sploc.fi ← fi ← AllocateFileInfo[];
-- look for source
IF NOT LongString.EquivalentString[sploc.sext, "bcd"L] THEN {
CWF.SWF2[srcsfn, "%s.%s"L, sploc.tail, sploc.sext];
fi.srcFileName ← Subr.CopyString[srcsfn];
fi.srcCap ← Directory.Lookup[fileName: srcsfn, permissions: Directory.ignore
! Directory.Error => CONTINUE];
IF fi.srcCap ~= File.nullCapability THEN
fi.srcPresent ← TRUE;
-- does not set bcdCreate, depseq or modulename
}
ELSE fi.isBcd ← TRUE;
CWF.SWF1[bcdsfn, "%s.Bcd"L, sploc.tail];
fi.bcdCap ← Directory.Lookup[fileName: bcdsfn, permissions: Directory.ignore
! Directory.Error => CONTINUE];
IF fi.bcdCap = File.nullCapability AND Subr.Prefix[bcdsfn, "pilot"L] THEN {
Subr.SubStrCopy[bcdsfn, bcdsfn, 5];
fi.bcdCap ← Directory.Lookup[fileName: bcdsfn, permissions: Directory.ignore
! Directory.Error => CONTINUE];
};
IF fi.bcdCap = File.nullCapability AND Subr.Prefix[bcdsfn, "long"L] THEN {
Subr.SubStrCopy[bcdsfn, bcdsfn, 4];
fi.bcdCap ← Directory.Lookup[fileName: bcdsfn, permissions: Directory.ignore
! Directory.Error => CONTINUE];
};
fi.bcdFileName ← Subr.CopyString[bcdsfn];
IF fi.bcdCap ~= File.nullCapability THEN
fi.bcdPresent ← TRUE;
}};
AllocateFileInfo: PROC RETURNS[fi: Dir.FileInfo] = {
longzone: UNCOUNTED ZONE ← Subr.LongZone[];
IF fileInfoSeq.size >= fileInfoSeq.maxsize THEN ERROR
ELSE {
fi ← fileInfoSeq[fileInfoSeq.size] ← longzone.NEW[Dir.FileInfoRecord ← []];
fileInfoSeq.size ← fileInfoSeq.size + 1;
};
};
-- frees the data structure and NIL's out LOC's fi
GetBcdCreate: PUBLIC PROC[fi: Dir.FileInfo] RETURNS[bcdCreate: LONG CARDINAL] = {
IF fi.bcdCreate ~= 0 OR NOT fi.bcdPresent THEN RETURN[fi.bcdCreate]
ELSE RETURN[fi.bcdCreate ← Subr.GetCreateDateWithSpace[fi.bcdCap, globalLDSpace]];
};
GetSrcCreate: PUBLIC PROC[fi: Dir.FileInfo] RETURNS[srcCreate: LONG CARDINAL] = {
IF fi.srcCreate ~= 0 OR NOT fi.srcPresent THEN RETURN[fi.srcCreate]
ELSE RETURN[fi.srcCreate ← Subr.GetCreateDateWithSpace[fi.srcCap, globalLDSpace]];
};
EraseCacheEntry: PUBLIC PROC[fi: Dir.FileInfo, src: BOOL] = {
IF src THEN {
fi.srcCap ← File.nullCapability;
fi.srcPresent ← FALSE;
fi.srcDepSeq ← NIL;
fi.srcCreate ← 0;
}
ELSE {
oldCap: File.Capability ← fi.bcdCap;
fi.bcdCap ← File.nullCapability;
fi.bcdPresent ← FALSE;
fi.bcdDepSeq ← NIL;
fi.bcdCreate ← 0;
fi.bcdVers ← TimeStamp.Null;
IF oldCap ~= File.nullCapability THEN ResetFileEntries[oldCap, fi];
};
};
-- will make sure that entries in the fileInfo data structure
-- that mention the same bcd file are reset to point to the version "fi" wants
-- oldCapability is the old capability for the file
ResetFileEntries: PUBLIC PROC[oldCapability: File.Capability, fi: Dir.FileInfo] = {
f: Dir.FileInfo;
IF oldCapability = File.nullCapability THEN RETURN;
FOR i: CARDINAL IN [0 .. fileInfoSeq.size) DO
f ← fileInfoSeq[i];
IF f.bcdCap = oldCapability THEN {
f.bcdPresent ← fi.bcdPresent;
f.bcdVers ← fi.bcdVers;
f.bcdCreate ← fi.bcdCreate;
f.bcdDepSeq ← fi.bcdDepSeq;
f.bcdCap ← fi.bcdCap;
};
ENDLOOP;
};
LookupFileInfo: PUBLIC PROC[bcdFileName: LONG STRING, bcdVers: TimeStamp.Stamp]
RETURNS[fi: Dir.FileInfo] = {
FOR i: CARDINAL IN [0 .. fileInfoSeq.size) DO
fi ← fileInfoSeq[i];
IF fi.bcdVers = bcdVers
AND LongString.EquivalentString[fi.bcdFileName, bcdFileName] THEN
RETURN[fi];
ENDLOOP;
RETURN[NIL];
};
LocForType: PUBLIC PROC[sptype: MDModel.TYPESymbol] RETURNS[sploc: MDModel.LOCSymbol] = {
IF sptype.typeval = NIL AND sptype.letparent = NIL THEN RETURN[NIL];
sploc ← MDModel.NarrowToLOC[IF sptype.letparent ~= NIL
THEN sptype.letparent.letval ELSE sptype.typeval];
};
LocForAppl: PUBLIC PROC[spappl: MDModel.APPLSymbol] RETURNS[sploc: MDModel.LOCSymbol] = {
IF spappl.applval = NIL AND spappl.letparent = NIL THEN RETURN[NIL];
sploc ← MDModel.NarrowToLOC[IF spappl.letparent ~= NIL
THEN spappl.letparent.letval ELSE spappl.applval];
};
-- stick in a Defs file
-- formal is X and typeName is X1 in
-- X: TYPE X1, in directory stmt of source file
-- we look for a statement X: TYPE X1 == @file already in the model
-- returns sptype = NIL if not found
LookForTypeSource: PUBLIC PROC[formal, typeName: LONG STRING, symbolseq: MDModel.SymbolSeq,
spmodel: MDModel.MODELSymbol]
RETURNS[sptype: MDModel.TYPESymbol, sptypeloc: MDModel.LOCSymbol, spproc: MDModel.PROCSymbol] = {
ProcAnalyze: PROC[sp: MDModel.Symbol, innermodel: MDModel.MODELSymbol]
RETURNS[proceed: BOOL ← TRUE] = {
fiInner: Dir.FileInfo;
IF sptype ~= NIL THEN RETURN[FALSE];
WITH sp SELECT FROM
spt: MDModel.TYPESymbol => {
sploc: MDModel.LOCSymbol = MDModel.LocForType[spt];
-- in case this symbol has not been defined
IF sploc = NIL THEN RETURN[TRUE];
fiInner ← GetFileInfo[sploc];
IF LongString.EqualString[spt.typesym, formal]
AND LongString.EqualString[spt.typeName, typeName]
THEN {
sptypeloc ← sploc;
sptype ← spt;
RETURN[FALSE];
};
};
spt: MDModel.PROCSymbol => spproc ← spt;
ENDCASE => NULL;
RETURN[TRUE];
};
spproc ← NIL;
sptypeloc ← NIL;
sptype ← NIL;
-- postorder is important here
TraverseTree[spmodel, symbolseq, ProcAnalyze, FALSE, TRUE];
};
-- stick in a Defs file
-- we look for an entry with stamp bcdVers
-- or, if a file has not been analyzed, we accept a bcdFileName match (wrong!)
-- returns NIL if not found
LookForTypeBcd: PUBLIC PROC[bcdFileName: LONG STRING, bcdVers: TimeStamp.Stamp,
symbolseq: MDModel.SymbolSeq, spmodel: MDModel.MODELSymbol]
RETURNS[sptype: MDModel.TYPESymbol, sptypeloc: MDModel.LOCSymbol, spproc: MDModel.PROCSymbol] = {
bcdfilename: STRING ← [200];
ProcAnalyze: PROC[sp: MDModel.Symbol, innermodel: MDModel.MODELSymbol]
RETURNS[proceed: BOOL ← TRUE] = {
fiInner: Dir.FileInfo;
IF sptype ~= NIL THEN RETURN[FALSE];
WITH sp SELECT FROM
spt: MDModel.TYPESymbol => {
sploc: MDModel.LOCSymbol = MDModel.LocForType[spt];
-- in case this symbol has not been defined
IF sploc = NIL THEN RETURN[TRUE];
fiInner ← GetFileInfo[sploc];
IF (fiInner.bcdVers.time = bcdVers.time
OR (fiInner.bcdVers = TimeStamp.Null
-- handles case where fInner has not been anal
AND LongString.EquivalentString[fiInner.bcdFileName, bcdFileName]))
THEN {
sptypeloc ← sploc;
sptype ← spt;
RETURN[FALSE];
};
};
spt: MDModel.PROCSymbol => spproc ← spt;
ENDCASE => NULL;
RETURN[TRUE];
};
spproc ← NIL;
sptypeloc ← NIL;
sptype ← NIL;
-- postorder is important here
TraverseTree[spmodel, symbolseq, ProcAnalyze, FALSE, TRUE];
};
-- spimpl is either APPL or LET
-- if sptype is not NIL, then use sptype as the type of the instance
-- formal and type are from IMPORTS formal: type
-- we look for formalImpl: type in the model
-- returns spappl = NIL if not found
LookForInstSource: PUBLIC PROC[formal, type: LONG STRING,
symbolseq: MDModel.SymbolSeq, spmodel: MDModel.MODELSymbol, sptype: MDModel.TYPESymbol]
RETURNS[spappl: MDModel.APPLSymbol, spnewtype: MDModel.TYPESymbol, spproc: MDModel.PROCSymbol] ={
intname: STRING ← [100];
ProcAnalyze: PROC[sp: MDModel.Symbol, innermodel: MDModel.MODELSymbol]
RETURNS[proceed: BOOL ← TRUE] = {
IF spappl ~= NIL THEN RETURN[FALSE];
WITH sp SELECT FROM
spt: MDModel.LETSymbol => {
FOR splist: MDModel.LISTSymbol ← spt.letgrp, splist.rest UNTIL splist = NIL DO
WITH splist.first SELECT FROM
spa1: MDModel.APPLSymbol => {
-- the types must agree
-- the interface record names must agree
IF spa1.appltype = sptype
AND LongString.EqualString[intname, spa1.applsym] THEN {
spappl ← spa1;
RETURN[FALSE];
};
};
ENDCASE;
ENDLOOP;
};
spt: MDModel.APPLSymbol => {
-- the types must agree
-- the interface record names must agree
IF spt.appltype = sptype
AND LongString.EqualString[intname, spt.applsym] THEN {
spappl ← spt;
RETURN[FALSE];
};
};
spt: MDModel.PROCSymbol => spproc ← spt;
ENDCASE => NULL;
RETURN[TRUE];
};
spappl ← NIL;
spproc ← NIL;
IF sptype = NIL THEN {
-- this is buggy: we should call LookForType with
-- the formal and typeNames for the corresponding Defs that is
-- mentioned in IMPORTS Y: Defs =
-- instead we pass the string "defs" as both formal and typename
[sptype] ← LookForTypeSource[type, type, symbolseq, spmodel];
IF sptype = NIL THEN RETURN[NIL, NIL, NIL]; -- can't be found
};
spnewtype ← sptype;
MDModel.CkType[sptype, $typeTYPE];
CWF.SWF1[intname, "%sImpl"L, formal];
-- postorder is important here
TraverseTree[spmodel, symbolseq, ProcAnalyze, FALSE, TRUE];
};
-- spimpl is either APPL or LET
-- if sptype is not NIL, then use sptype as the type of the instance
-- just looks for any instance with a bcdVers timestamp
-- (more precisely, any instance with type sptype)
LookForInstBcd: PUBLIC PROC[bcdFileName: LONG STRING, bcdVers: TimeStamp.Stamp,
symbolseq: MDModel.SymbolSeq, spmodel: MDModel.MODELSymbol, sptype: MDModel.TYPESymbol]
RETURNS[spappl: MDModel.APPLSymbol, spnewtype: MDModel.TYPESymbol, spproc: MDModel.PROCSymbol] ={
ProcAnalyze: PROC[sp: MDModel.Symbol, innermodel: MDModel.MODELSymbol]
RETURNS[proceed: BOOL ← TRUE] = {
IF spappl ~= NIL THEN RETURN[FALSE];
WITH sp SELECT FROM
spt: MDModel.LETSymbol => {
FOR splist: MDModel.LISTSymbol ← spt.letgrp, splist.rest UNTIL splist = NIL DO
WITH splist.first SELECT FROM
spa1: MDModel.APPLSymbol => {
-- the types must agree
-- the interface record names must agree
IF spa1.appltype = sptype THEN {
spappl ← spa1;
RETURN[FALSE];
};
};
ENDCASE;
ENDLOOP;
};
spt: MDModel.APPLSymbol => {
-- the types must agree
IF spt.appltype = sptype THEN {
spappl ← spt;
RETURN[FALSE];
};
};
spt: MDModel.PROCSymbol => spproc ← spt;
ENDCASE => NULL;
RETURN[TRUE];
};
spappl ← NIL;
spproc ← NIL;
IF sptype = NIL THEN {
[sptype] ← LookForTypeBcd[bcdFileName, bcdVers, symbolseq, spmodel];
IF sptype = NIL THEN RETURN[NIL, NIL, NIL]; -- can't be found
};
spnewtype ← sptype;
MDModel.CkType[sptype, $typeTYPE];
-- postorder is important here
TraverseTree[spmodel, symbolseq, ProcAnalyze, FALSE, TRUE];
};
ValidateModel: PUBLIC PROC[symbolseq: MDModel.SymbolSeq] = {
AnalProc: PROC[sp1: MDModel.Symbol, spmodel: MDModel.MODELSymbol]
RETURNS[proceed: BOOL ← TRUE] = {
WITH sp~~sp1 SELECT FROM
typeTYPE => {
CkS[sp.typesym];
CkS[sp.typeName];
VerifyLoc[sp.typeval];
VerifyLet[sp1, sp.letparent];
IF sp.letparent = NIL AND sp.typeval = NIL
AND sp1 ~= symbolseq.controlv THEN
CWF.WF1["%s is undefined.\n"L, sp.typesym];
};
typeLOC => {
CkT[sp.parmlist, $typeLIST];
CkT[sp.nestedmodel, $typeMODEL];
CkS[sp.tail];
CkS[sp.sext];
};
typePROC => {
CkS[sp.procsym];
CkT[sp.procparm, $typeLIST];
CkT[sp.procret, $typeLIST];
CkT[sp.procval, $typeLIST];
};
typeSTRING => {
CkS[sp.strval];
};
typeAPPL => {
CkS[sp.applsym];
CkT[sp.appltype, $typeTYPE];
VerifyLoc[sp.applval];
VerifyLet[sp1, sp.letparent];
IF sp.letparent = NIL AND sp.applval = NIL AND Subr.debugflg THEN
CWF.WF1["Check: %s is a parameter.\n"L, sp.applsym];
};
typeLET => {
splist: MDModel.LISTSymbol;
splist ← sp.letgrp;
WHILE splist ~= NIL DO
WITH spi~~splist.first SELECT FROM
typeTYPE => VerifyLet[splist.first, MDModel.NarrowToLET[sp1]];
typeAPPL => VerifyLet[splist.first, MDModel.NarrowToLET[sp1]];
ENDCASE => NULL;
splist ← splist.rest;
ENDLOOP;
VerifyLoc[sp.letval];
};
typeLIST => {
CkT[sp.rest, $typeLIST];
};
typeOPEN => NULL;
typeMODEL => {
CkS[sp.modelfilename];
CkT[sp.model, $typeLIST];
};
ENDCASE => NULL;
};
TraverseTree[symbolseq.toploc, symbolseq, AnalProc, FALSE, FALSE];
};
CkS: PROC[s: LONG STRING] = {
IF s = NIL THEN
IF Subr.debugflg THEN Runtime.CallDebugger["A String is NIL"L]
ELSE CWF.WF0["A String is NIL\n"L];
};
CkT: PROC[sp: MDModel.Symbol, st: MDModel.SubType] = {
IF sp ~= NIL AND sp.stype ~= st THEN
IF Subr.debugflg THEN Runtime.CallDebugger["Bad type"L]
ELSE CWF.WF1["Bad type %s\n"L, MDModel.Sym[sp]];
};
-- verify spelem is on splet.letgrp
VerifyLet: PROC[spelem: MDModel.Symbol, splet: MDModel.LETSymbol] = {
splist: MDModel.LISTSymbol;
IF splet = NIL THEN RETURN;
splist ← splet.letgrp;
WHILE splist ~= NIL DO
IF splist.first = spelem THEN EXIT;
splist ← splist.rest;
ENDLOOP;
IF splist = NIL THEN {
CWF.WF1["%s is not on LET list.\n"L, MDModel.Sym[spelem]];
RETURN;
};
WITH spt~~spelem SELECT FROM
typeTYPE => IF spt.letparent ~= splet THEN
-- type letparent is not filled in
IF Subr.debugflg THEN Runtime.CallDebugger["Bad letparent"L]
ELSE CWF.WF1["Bad letparent for %s\n"L, spt.typesym];
typeAPPL => IF spt.letparent ~= splet THEN
-- type letparent is not filled in
IF Subr.debugflg THEN Runtime.CallDebugger["Bad letparent"L]
ELSE CWF.WF1["Bad letparent for %s\n"L, spt.applsym];
ENDCASE => ERROR;
};
-- calls itself recursively
VerifyLoc: PROC[sp: MDModel.Symbol] = {
IF sp = NIL THEN RETURN;
WITH sp SELECT FROM
spt: MDModel.LISTSymbol => TraverseList[spt, VerifyLoc];
ENDCASE => IF sp.stype # $typeLOC AND sp.stype # $typeAPPL THEN
IF Subr.debugflg THEN Runtime.CallDebugger["Loc is neither a LOC nor an APPL\n"L]
ELSE CWF.WF0["Loc is neither a LOC nor an APPL\n"L];
};
GenerateUniqueName: PUBLIC PROC[spappl: MDModel.APPLSymbol]
RETURNS[sym: LONG STRING] = {
stemp: STRING ← [100];
u: CARDINAL;
sptype: MDModel.TYPESymbol = MDModel.NarrowToTYPE[spappl.appltype];
sptype.uniqueno ← sptype.uniqueno + 1;
u ← sptype.uniqueno;
CWF.SWF2[stemp, "%s%u"L, spappl.applsym, @u];
RETURN[Subr.CopyString[stemp]];
};
-- returns TRUE if first occurs after second in list sptoplist
After: PUBLIC PROC[first, second: MDModel.Symbol, sptoplist: MDModel.LISTSymbol]
RETURNS[BOOL] = {
splist: MDModel.LISTSymbol ← sptoplist;
IF first = NIL OR second = NIL THEN ERROR;
WHILE splist ~= NIL DO
IF first = splist.first THEN {
WHILE splist ~= NIL DO
IF second = splist.first THEN RETURN[FALSE];
splist ← splist.rest;
ENDLOOP;
RETURN[FALSE]; -- second not in list
};
IF second = splist.first THEN {
-- second is in list, if first is after then TRUE
-- if first is not on list at all, then FALSE
WHILE splist ~= NIL DO
IF first = splist.first THEN RETURN[TRUE];
splist ← splist.rest;
ENDLOOP;
RETURN[FALSE];
};
splist ← splist.rest;
ENDLOOP;
RETURN[FALSE]; -- neither is in list
};
-- return TRUE if spnode is on the list beginning at splist
IsOnList: PUBLIC PROC[spnode: MDModel.Symbol, splist: MDModel.LISTSymbol]
RETURNS[BOOL] = {
WHILE splist ~= NIL DO
IF splist.first = spnode THEN RETURN[TRUE];
splist ← splist.rest;
ENDLOOP;
RETURN[FALSE];
};
-- remove spremove from the list descending from psptoplist↑
-- returns spparent, a list node, parent of spremove and no longer on the list
-- as well as spremove; returns NIL if spremove is not on the root list
-- returns also a new list with the element removed
RemoveFromList: PUBLIC PROC[spremove: MDModel.Symbol, oldlist: MDModel.LISTSymbol]
RETURNS[spparent, newlist: MDModel.LISTSymbol] = {
splist, splast: MDModel.LISTSymbol;
splist ← newlist ← splast ← oldlist;
WHILE splist ~= NIL DO
MDModel.CkType[splist, $typeLIST];
IF splist.first = spremove THEN {
-- delete it
IF splist = oldlist THEN
newlist ← splist.rest
ELSE IF splast.stype = typeLIST THEN
splast.rest ← splist.rest
ELSE ERROR;
spparent ← splist;
RETURN[spparent, newlist];
}
ELSE splast ← splist;
splist ← splist.rest;
ENDLOOP;
RETURN[NIL, newlist];
};
SaveBitArray: TYPE = PACKED ARRAY[0..0) OF BOOL;
-- proceed here means don't anlayze any sons of this node
-- it doesn't mean abort the whole tree search
-- if followscopingrules then it will only follow LOC's for models
-- if they are preceded by an OPEN; this is a crock
TraverseTree: PUBLIC PROC[sproot: MDModel.Symbol, symbolseq: MDModel.SymbolSeq,
proc: PROC[MDModel.Symbol, MDModel.MODELSymbol] RETURNS[BOOL],
preorder, followscopingrules: BOOL] = {
oldsize: CARDINAL;
savebit: LONG POINTER TO SaveBitArray ← NIL;
longzone: UNCOUNTED ZONE;
nearopen: BOOL;
arrtype: TYPE = RECORD[
SEQUENCE maxl: CARDINAL OF CARDINAL
];
RecurTraverseTree: PROC[sp: MDModel.Symbol, spmodel: MDModel.MODELSymbol,
proc: PROC[MDModel.Symbol, MDModel.MODELSymbol] RETURNS[BOOL]] = {
proceed: BOOL;
IF sp = NIL OR sp.visited THEN RETURN;
sp.visited ← TRUE;
IF preorder THEN {
proceed ← proc[sp, spmodel];
IF NOT proceed THEN RETURN;
};
WITH spt~~sp SELECT FROM
typeTYPE => {
RecurTraverseTree[spt.typeval, spmodel, proc];
};
typePROC => {
RecurTraverseTree[spt.procparm, spmodel, proc];
RecurTraverseTree[spt.procret, spmodel, proc];
RecurTraverseTree[spt.procval, spmodel, proc];
};
typeAPPL => {
RecurTraverseTree[spt.appltype, spmodel, proc];
RecurTraverseTree[spt.applval, spmodel, proc];
};
typeLIST => {
RunThruList: PROC[spelem: MDModel.Symbol] = {
RecurTraverseTree[spelem, spmodel, proc];
};
TraverseList[MDModel.NarrowToLIST[sp], RunThruList];
};
typeLET => {
RecurTraverseTree[spt.letgrp, spmodel, proc];
RecurTraverseTree[spt.letval, spmodel, proc];
};
typeLOC => {
-- IF Subr.debugflg THEN
-- CWF.WF2["%s is in %s.\n"L, spt.tail,
-- IF spmodel = NIL THEN "-NIL-"L
-- ELSE spmodel.modelfilename];
RecurTraverseTree[spt.parmlist, spmodel, proc];
IF NOT followscopingrules OR nearopen THEN
RecurTraverseTree[spt.nestedmodel, spmodel, proc];
nearopen ← FALSE;
};
typeOPEN => {
nearopen ← TRUE;
RecurTraverseTree[spt.open, spmodel, proc];
nearopen ← FALSE;
};
typeMODEL => {
RecurTraverseTree[spt.model, MDModel.NarrowToMODEL[sp], proc];
};
typeSTRING => NULL;
ENDCASE => ERROR; -- Unknown stype
IF NOT preorder THEN {
[] ← proc[sp, spmodel];
sp.visited ← TRUE;
};
};
{
ENABLE UNWIND => IF savebit = NIL THEN symbolseq.traversalInProgress ← FALSE;
IF sproot = NIL THEN RETURN;
traversetreecalled ← traversetreecalled + 1;
-- IF Subr.debugflg THEN
-- CWF.WF0["~~~Traverse Tree Begun.\n"L];
IF symbolseq.traversalInProgress THEN {
longzone ← Subr.LongZone[];
-- this is to be able to allocate PACKED SEQUENCES
-- 16 bits ber cardinal
oldsize ← symbolseq.size;
IF NOT symbolseq.savedInUse THEN {
symbolseq.savedInUse ← TRUE;
savebit ← symbolseq.savedVisited;
}
ELSE {
nwords: CARDINAL ← (oldsize / 16) + 1;
savebit ← LOOPHOLE[longzone.NEW[arrtype[nwords]]];
};
FOR i: CARDINAL IN [0.. symbolseq.size) DO
savebit[i] ← symbolseq[i].visited;
ENDLOOP;
};
symbolseq.traversalInProgress ← TRUE;
FOR i: CARDINAL IN [0.. symbolseq.size) DO
symbolseq[i].visited ← FALSE;
ENDLOOP;
nearopen ← TRUE;
RecurTraverseTree[sproot,
IF sproot.stype = $typeMODEL THEN MDModel.NarrowToMODEL[sproot] ELSE NIL, proc];
IF savebit ~= NIL THEN {
FOR i: CARDINAL IN [0.. oldsize) DO
symbolseq[i].visited ← savebit[i];
ENDLOOP;
-- is this necessary?
FOR i: CARDINAL IN [oldsize .. symbolseq.size) DO
symbolseq[i].visited ← FALSE;
ENDLOOP;
IF savebit ~= symbolseq.savedVisited THEN
longzone.FREE[@savebit];
}
ELSE symbolseq.traversalInProgress ← FALSE;
-- IF Subr.debugflg THEN
-- CWF.WF0["~~~Traverse Tree Finished.\n"L];
}};
-- the null list is simply sp = NIL
-- the unit list is one list node with a NIL sp.rest
-- lists are always terminated by sp.rest = NIL
-- sp.rest is always of type typeLIST
TraverseList: PUBLIC PROC[sp: MDModel.LISTSymbol, proc: PROC[MDModel.Symbol]] = {
nelem: CARDINAL ← 0;
spnext: MDModel.LISTSymbol;
WHILE sp ~= NIL DO
MDModel.CkType[sp, $typeLIST];
nelem ← nelem + 1;
IF nelem > 1000 THEN ERROR; -- cycling
spnext ← sp.rest; -- in case he deletes it
proc[sp.first];
sp ← spnext;
ENDLOOP;
};
TraverseAndRemove: PUBLIC PROC[oldlist: MDModel.LISTSymbol,
proc: PROC[sp: MDModel.Symbol] RETURNS[remove: BOOL]]
RETURNS[newlist: MDModel.LISTSymbol] = {
splist, splast: MDModel.LISTSymbol;
splast ← splist ← newlist ← oldlist;
WHILE splist ~= NIL DO
MDModel.CkType[splist, $typeLIST];
IF proc[splist.first] THEN {
-- remove it from the list
IF splist = newlist THEN
newlist ← splist.rest
ELSE IF splast.stype = $typeLIST THEN
splast.rest ← splist.rest
ELSE ERROR;
}
ELSE splast ← splist;
splist ← splist.rest;
ENDLOOP;
RETURN[newlist];
};
-- add to the end of a list
-- psp is a pointer to a node that is the beginning of a list
-- if non-NIL then psp↑ must be of type typeLIST
AddToEndOfList: PUBLIC PROC[oldlist: MDModel.LISTSymbol,
spadd: MDModel.Symbol, listtype: MDModel.ListType,
symbolseq: MDModel.SymbolSeq]
RETURNS[newlist: MDModel.LISTSymbol]= {
sp, spbin: MDModel.LISTSymbol;
sp ← newlist ← oldlist;
IF spadd = NIL THEN ERROR;
spbin ← NewSymLIST[symbolseq];
spbin.first ← spadd;
spbin.rest ← NIL;
spbin.listtype ← listtype;
IF sp = NIL THEN newlist ← spbin
ELSE {
WHILE sp.rest ~= NIL DO
MDModel.CkType[sp.rest, $typeLIST];
IF sp.listtype ~= listtype THEN ERROR;
sp ← sp.rest;
ENDLOOP;
sp.rest ← spbin;
};
RETURN[newlist];
};
-- behaves unusually depending on slist's form
-- if slist = NIL then returns sadd
-- if slist is not a list, the returns a list of slist and sadd
-- if slist is a list, appends sadd to slist and returns slist
-- if sadd is a list, the list is appended,
-- if not, sadd is added to the list
MergeIntoList: PUBLIC PROC[slist, sadd: MDModel.Symbol,
symbolseq: MDModel.SymbolSeq, listtype: MDModel.ListType]
RETURNS[MDModel.Symbol] = {
CheckNotNil[sadd];
IF slist = NIL THEN RETURN[sadd];
IF slist.stype ~= $typeLIST THEN {
stop: MDModel.LISTSymbol;
stop ← AddToEndOfList[NIL, slist, listtype, symbolseq];
IF sadd.stype = $typeLIST THEN
stop.rest ← MDModel.NarrowToLIST[sadd]
ELSE
stop ← AddToEndOfList[stop, sadd, listtype, symbolseq];
RETURN[stop];
}
ELSE {
sl: MDModel.LISTSymbol ← MDModel.NarrowToLIST[slist];
IF sadd.stype = $typeLIST THEN {
sp: MDModel.LISTSymbol ← sl;
WHILE sp.rest ~= NIL DO
sp ← sp.rest;
ENDLOOP;
sp.rest ← MDModel.NarrowToLIST[sadd];
}
ELSE
sl ← AddToEndOfList[sl, sadd, listtype, symbolseq];
RETURN[sl];
};
};
-- the beginning of the list is "sptoplist"
-- spmove is a MDModel.Symbol, spstay is a typeList MDModel.Symbol
-- move "spmove" before "spstay" in symbolseq
-- spmove does not have to be in the list already
SpliceBefore: PUBLIC PROC[symbolseq: MDModel.SymbolSeq,
spmove: MDModel.Symbol, spstay: MDModel.LISTSymbol,
oldlist: MDModel.LISTSymbol]
RETURNS[newlist: MDModel.LISTSymbol] = {
spl, spparent, splast: MDModel.LISTSymbol;
[spparent, newlist] ← RemoveFromList[spmove, oldlist];
IF spparent = NIL THEN {
-- not on list already, must make a new list node first
spparent ← NewSymLIST[symbolseq];
spparent.first ← spmove;
};
splast ← spl ← newlist;
WHILE spl ~= NIL DO
IF spl = spstay THEN {
-- stick in front of spstay
spparent.rest ← spstay;
IF spl = newlist THEN
newlist ← spparent
ELSE IF splast.stype = $typeLIST THEN
splast.rest ← spparent
ELSE ERROR;
EXIT;
}
ELSE splast ← spl;
spl ← spl.rest;
ENDLOOP;
RETURN[newlist];
};
ZeroOut: PUBLIC PROC[sp: MDModel.Symbol] = {
IF sp = NIL THEN ERROR;
LongZero[sp, MDModel.SymbolRecord.SIZE];
sp.vpart ← typeBAD[];
};
LongZero: PROC[lp: LONG POINTER, size: CARDINAL] = {
IF lp = NIL THEN ERROR;
FOR i: CARDINAL IN [0..size) DO
(lp+i)↑ ← 0;
ENDLOOP;
};
CheckNotNil: PUBLIC PROC[p: LONG POINTER] = {
IF p = NIL THEN ERROR;
};
-- returns the zone used by the symbolseq
AllocateSymbolSeq: PUBLIC PROC[nsym: CARDINAL]
RETURNS[symbolseq: MDModel.SymbolSeq] = {
arrtype: TYPE = RECORD[
SEQUENCE maxl: CARDINAL OF CARDINAL
];
space: Space.Handle;
longzone: UNCOUNTED ZONE ← Subr.LongZone[];
npages: LONG CARDINAL;
npages ← (MDModel.SymbolRecord.SIZE.LONG * nsym + MDModel.SymbolSeqRecord[0].SIZE)
/Environment.wordsPerPage + 1;
space ← Space.Create[size: Inline.LowHalf[npages], parent: Space.virtualMemory];
Space.Map[space];
IF npages > 20 THEN Space.CreateUniformSwapUnits[10, space];
symbolseq ← Space.LongPointer[space];
-- assign to the MAX SIZE !!!!
(LOOPHOLE[symbolseq, LONG POINTER] + MDModel.SymbolSeqRecord[0].SIZE - 1)↑ ← nsym;
symbolseq.toploc ← NIL;
symbolseq.controlv ← NIL;
symbolseq.traversalInProgress ← FALSE;
symbolseq.modelSeq ← longzone.NEW[MDModel.ModelSeqRecord[NumberOfModels]];
symbolseq.savedInUse ← FALSE;
symbolseq.savedVisited ← longzone.NEW[arrtype[(symbolseq.maxsize / 16) + 1]];
symbolseq.size ← 0;
RETURN[symbolseq];
};
FreeSymbolSeq: PUBLIC PROC[psymbolseq: LONG POINTER TO MDModel.SymbolSeq] = {
longzone: UNCOUNTED ZONE ← Subr.LongZone[];
space: Space.Handle;
s: MDModel.Symbol;
IF psymbolseq↑ = NIL THEN RETURN;
FOR i: CARDINAL IN [0.. psymbolseq↑.size) DO
s ← @(psymbolseq↑)[i];
FreeStringsOf[s];
ENDLOOP;
longzone.FREE[@psymbolseq.savedVisited];
longzone.FREE[@psymbolseq.modelSeq];
-- this frees symbolseq
space ← Subr.FindMappedSpace[Space.GetHandle[Space.PageFromLongPointer[psymbolseq↑]]];
Space.Delete[space: space];
psymbolseq↑ ← NIL;
};
FreeStringsOf: PUBLIC PROC[sp1: MDModel.Symbol] = {
WITH sp~~sp1 SELECT FROM
typeTYPE => {
Subr.FreeString[sp.typesym];
Subr.FreeString[sp.typeName];
};
typeLOC => {
Subr.FreeString[sp.host];
Subr.FreeString[sp.path];
Subr.FreeString[sp.tail];
Subr.FreeString[sp.sext];
};
typePROC => Subr.FreeString[sp.procsym];
typeSTRING => {
Subr.FreeString[sp.strsym];
Subr.FreeString[sp.strval];
};
typeAPPL => {
Subr.FreeString[sp.applsym];
Subr.FreeString[sp.configname];
};
typeMODEL => Subr.FreeString[sp.modelfilename];
typeLET, typeLIST, typeBAD, typeOPEN => NULL;
ENDCASE => ERROR;
};
-- create new Symbol's
NewSym: PROC[symbolseq: MDModel.SymbolSeq]
RETURNS[sym: MDModel.Symbol] = {
sym ← @symbolseq[symbolseq.size];
-- fill in with defaulted values
sym↑ ← [vpart: typeBAD[]];
symbolseq.size ← symbolseq.size + 1;
IF symbolseq.size >= symbolseq.maxsize THEN TooManySymbols;
RETURN[sym];
};
NewSymTYPE: PUBLIC PROC[symbolseq: MDModel.SymbolSeq]
RETURNS[sym: MDModel.TYPESymbol] = {
sym ← LOOPHOLE[NewSym[symbolseq]];
-- fill in with defaulted values
sym↑ ← [vpart: typeTYPE[NIL, NIL, NIL, FALSE, NIL, 0]];
};
NewSymLOC: PUBLIC PROC[symbolseq: MDModel.SymbolSeq]
RETURNS[sym: MDModel.LOCSymbol] = {
sym ← LOOPHOLE[NewSym[symbolseq]];
-- fill in with defaulted values
sym↑ ← [vpart: typeLOC[NIL, NIL, NIL, NIL, 0, NIL, NIL, NIL, FALSE, 0]];
};
NewSymPROC: PUBLIC PROC[symbolseq: MDModel.SymbolSeq]
RETURNS[sym: MDModel.PROCSymbol] = {
sym ← LOOPHOLE[NewSym[symbolseq]];
-- fill in with defaulted values
sym↑ ← [vpart: typePROC[NIL, NIL, NIL, NIL]];
};
NewSymSTRING: PUBLIC PROC[symbolseq: MDModel.SymbolSeq]
RETURNS[sym: MDModel.STRINGSymbol] = {
sym ← LOOPHOLE[NewSym[symbolseq]];
-- fill in with defaulted values
sym↑ ← [vpart: typeSTRING[NIL, NIL]];
};
NewSymAPPL: PUBLIC PROC[symbolseq: MDModel.SymbolSeq]
RETURNS[sym: MDModel.APPLSymbol] = {
sym ← LOOPHOLE[NewSym[symbolseq]];
-- fill in with defaulted values
sym↑ ← [vpart: typeAPPL[NIL, NIL, NIL, NIL, NIL, NIL]];
};
NewSymLET: PUBLIC PROC[symbolseq: MDModel.SymbolSeq]
RETURNS[sym: MDModel.LETSymbol] = {
sym ← LOOPHOLE[NewSym[symbolseq]];
-- fill in with defaulted values
sym↑ ← [vpart: typeLET[NIL, NIL]];
};
NewSymLIST: PUBLIC PROC[symbolseq: MDModel.SymbolSeq]
RETURNS[sym: MDModel.LISTSymbol] = {
sym ← LOOPHOLE[NewSym[symbolseq]];
-- fill in with defaulted values
sym↑ ← [vpart: typeLIST[normal, NIL, NIL]];
};
NewSymOPEN: PUBLIC PROC[symbolseq: MDModel.SymbolSeq]
RETURNS[sym: MDModel.OPENSymbol] = {
sym ← LOOPHOLE[NewSym[symbolseq]];
-- fill in with defaulted values
sym↑ ← [vpart: typeOPEN[NIL]];
};
NewSymMODEL: PUBLIC PROC[symbolseq: MDModel.SymbolSeq]
RETURNS[sym: MDModel.MODELSymbol] = {
sym ← LOOPHOLE[NewSym[symbolseq]];
-- fill in with defaulted values
sym↑ ← [vpart: typeMODEL[NIL, FALSE, File.nullCapability, 0, NIL,
Space.nullHandle, PilotLoadStateOps.NullConfig, FALSE]];
};
-- discover which nodes are recursive
-- callable from the Debugger
ValidateList: PROC[spl: MDModel.LISTSymbol, print: BOOL ← FALSE] = {
nelem: CARDINAL ← 0;
WHILE spl ~= NIL DO
MDModel.CkType[spl, $typeLIST];
nelem ← nelem + 1;
IF nelem > 1000 THEN ERROR; -- cycling
IF print THEN {
s: LONG STRING;
spa: MDModel.Symbol ← spl.first;
s ← MDModel.Sym[spa];
CWF.WF2["Node %lb, str <%s>\n"L, @spa, s];
};
spl ← spl.rest;
ENDLOOP;
CWF.WF1["%u links.\n"L, @nelem];
};
-- parse command line compiler switches
FoldInParms: PUBLIC PROC[parms: LONG STRING]
RETURNS[switches: CompilerOps.LetterSwitches, explicitSortSwitch: BOOL] = {
i: CARDINAL ← 0;
on: BOOL;
ch: CHAR;
StandardDefaults: CompilerOps.LetterSwitches = [
TRUE , -- A Address faults for Nil checks
TRUE , -- B Bounds checking
TRUE , -- C Compile for Cedar (special FORK)
FALSE, -- D Call debugger on compiler error (FALSE => just log error)
TRUE , -- E Fixed (big eval stack)
TRUE , -- F Floating point microcode
TRUE , -- G TRUE => errlog goes to compiler.log, FALSE => use foo.errlog
FALSE, -- H Unused
FALSE, -- I Unused
FALSE, -- J cross-Jumping optimization
FALSE, -- K Unused
TRUE , -- L Fixed (handle Long pointers)
TRUE , -- M Reference counting microcode
TRUE , -- N Nil pointer checking
FALSE, -- O Unused
FALSE, -- P Pause after compilation with errors
FALSE, -- Q Unused
FALSE, -- R Unused
TRUE , -- S Sort (by static frequency) global vars & entry indexes
FALSE, -- T Unused
FALSE, -- U Uninitialized variable checking
FALSE, -- V Unused
TRUE , -- W log Warning messages
FALSE, -- X Unused
FALSE, -- Y complain about KFCB
FALSE -- Z Unused
];
-- set defaults
switches ← -- CompilerOps.DefaultSwitches[]; -- StandardDefaults;
switches['s] ← FALSE; -- the modeller defaults to /-s
explicitSortSwitch ← FALSE;
IF parms = NIL THEN RETURN;
WHILE i < parms.length DO
on ← TRUE;
IF parms[i] = '- THEN {
i ← i + 1;
on ← FALSE;
};
ch ← String.LowerCase[parms[i]];
IF ch IN ['a .. 'z] THEN {
switches[ch] ← on;
IF ch = 's THEN explicitSortSwitch ← TRUE;
};
i ← i + 1;
ENDLOOP;
};
StartMDSupport: PUBLIC PROC = {
longzone: UNCOUNTED ZONE ← Subr.LongZone[];
globalLDSpace ← Space.Create[1, Space.virtualMemory];
Space.Map[globalLDSpace];
fileInfoSeq ← longzone.NEW[FileInfoSeqRecord[NumberOfFileInfoRecords]];
};
StopMDSupport: PUBLIC PROC = {
f: Dir.FileInfo;
longzone: UNCOUNTED ZONE ← Subr.LongZone[];
IF globalLDSpace ~= Space.nullHandle THEN Space.Delete[globalLDSpace];
globalLDSpace ← Space.nullHandle;
FOR i: CARDINAL IN [0 .. fileInfoSeq.size) DO
f ← fileInfoSeq[i];
Subr.FreeString[f.bcdFileName];
Subr.FreeString[f.srcFileName];
Subr.FreeString[f.moduleName];
longzone.FREE[@f];
ENDLOOP;
longzone.FREE[@fileInfoSeq];
};
}.
-- UNUSED or OLD code
-ReplaceBy: PUBLIC PROC[spold, spnew: MDModel.Symbol,
symbolseq: MDModel.SymbolSeq] = {
IF spold = spnew THEN ERROR;
FOR i: CARDINAL IN [0.. symbolseq.size) DO
WITH sp~~(@symbolseq[i]) SELECT FROM
typeTYPE => {
IF sp.typeval = spold THEN sp.typeval ← spnew;
};
typePROC => {
IF sp.procparm = spold THEN
sp.procparm ← MDModel.NarrowToLIST[spnew];
IF sp.procret = spold THEN
sp.procret ← MDModel.NarrowToLIST[spnew];
IF sp.procval = spold THEN sp.procval ← spnew;
};
typeAPPL => {
IF sp.appltype = spold THEN sp.appltype ← spnew;
IF sp.applval = spold THEN sp.applval ← spnew;
};
typeLIST => {
IF sp.first = spold THEN sp.first ← spnew;
IF sp.rest = spold THEN
sp.rest ← MDModel.NarrowToLIST[spnew];
};
typeLET => {
IF sp.letgrp = spold THEN
sp.letgrp ← MDModel.NarrowToLIST[spnew];
IF sp.letval = spold THEN sp.letval ← spnew;
};
typeLOC => {
IF sp.parmlist = spold THEN
sp.parmlist ← MDModel.NarrowToLIST[spnew];
IF sp.nestedmodel = spold THEN
sp.nestedmodel ← MDModel.NarrowToMODEL[spnew];
};
typeOPEN => {
IF sp.open = spold THEN sp.open ← spnew;
};
typeMODEL => {
IF sp.model = spold THEN sp.model ← MDModel.NarrowToLIST[spnew];
};
typeSTRING => NULL;
typeBAD => NULL;
ENDCASE => ERROR;
ENDLOOP;
};
- uses a POSTORDER tree walk
OldReplaceBy: PROC[spold, spnew: MDModel.Symbol, symbolseq: MDModel.SymbolSeq] = {
ProcAnalyze: PROC[sp: MDModel.Symbol] RETURNS[proceed: BOOL ← TRUE] = {
SELECT sp.stype FROM
$typeTYPE => {
IF sp.subid = spold THEN sp.subid ← spnew;
IF sp.typeval = spold THEN sp.typeval ← spnew;
};
$typePROC => {
IF sp.procparm = spold THEN sp.procparm ← spnew;
IF sp.procret = spold THEN sp.procret ← spnew;
IF sp.procval = spold THEN sp.procval ← spnew;
};
$typeAPPL => {
IF sp.appltype = spold THEN sp.appltype ← spnew;
IF sp.applval = spold THEN sp.applval ← spnew;
};
$typeLIST => {
IF sp.first = spold THEN sp.first ← spnew;
IF sp.rest = spold THEN sp.rest ← spnew;
};
$typeLET => {
IF sp.letgrp = spold THEN sp.letgrp ← spnew;
IF sp.letval = spold THEN sp.letval ← spnew;
};
$typeLOC => {
IF sp.parmlist = spold THEN sp.parmlist ← spnew;
};
$typeSTRING => NULL;
ENDCASE => ERROR;
RETURN[TRUE];
};
IF spold = spnew THEN ERROR;
TraverseTree[symbolseq.toploc, symbolseq, ProcAnalyze, FALSE];
};