ConfigAndMesaDeps.Mesa
Last Edited by: Spreitzer, May 9, 1986 9:52:47 pm PDT
Mike Spreitzer July 31, 1986 1:01:55 pm PDT
Carl Hauser, April 11, 1985 3:52:50 pm PST
DIRECTORY Basics, BasicTime, BcdDefs, BCDery, FS, IO, IOClasses, List, ListerUtils, MakeDo, RedBlackTree, Rope, TimeStamp;
ConfigAndMesaDeps:
CEDAR
MONITOR
IMPORTS BasicTime, BCDery, FS, IO, IOClasses, ListerUtils, MakeDo, RedBlackTree, Rope =
INVARIANT
StampRef in node props
BEGIN OPEN MakeDo;
GotoSyntaxError: ERROR = CODE;
ROPE: TYPE = Rope.ROPE;
StampRef:
TYPE =
REF StampRep; StampRep:
TYPE =
RECORD [
created: BasicTime.GMT,
stamp: TimeStamp.Stamp];
SourceData:
TYPE =
REF SourceDataRep; SourceDataRep:
TYPE =
RECORD [
bcdName, shortName: ROPE,
sourceType: SourceType,
supports: RedBlackTree.Table,
sourceNode, switchesNode, bcdNode: Node,
sourceStamp: Stamp ← TimeStamp.Null,
bcdCreateTime: BasicTime.GMT,
bcdReadable, supportsInvalid: BOOL ← FALSE,
cmd: ROPE ← NIL
];
SourceType: TYPE = {Mesa, Config};
Support:
TYPE =
REF SupportRep; SupportRep:
TYPE =
RECORD [
node: Node,
version: Stamp];
ParseData:
TYPE =
REF ParseDataRep; ParseDataRep:
TYPE =
RECORD [
source: ROPE,
sourceType: SourceType,
stamp: Time ← notExistTime,
refdModules: RopeList ← NIL];
parses: RedBlackTree.Table ← RedBlackTree.Create[GetParseKey, CompareParses];
configAndMesaClass: ActionClass ←
NEW [ActionClassRep ← [
CheckConsistency: CheckConsistency,
Rederive: RederiveSource
]];
GetParseKey:
PROC [data:
REF
ANY]
RETURNS [
ROPE]
--RedBlackTree.GetKey-- = {
pd: ParseData = NARROW[data];
RETURN[pd.source]};
CompareParses:
PROC [k, data:
REF
ANY]
RETURNS [Basics.Comparison]
--RedBlackTree.Compare-- = {
k1: ROPE = NARROW[k];
k2: ROPE = GetParseKey[data];
RETURN [k1.Compare[s2: k2, case: FALSE]]};
GetSupportKey:
PROC [data:
REF
ANY]
RETURNS [Node]
--RedBlackTree.GetKey-- = {
s: Support = NARROW[data];
RETURN[s.node]};
CompareSupport:
PROC [k, data:
REF
ANY]
RETURNS [Basics.Comparison]
--RedBlackTree.Compare-- = {
k1: INT = LOOPHOLE[k];
k2: INT = LOOPHOLE[GetSupportKey[data]];
RETURN [
SELECT k1
FROM
<k2 => less,
=k2 => equal,
>k2 => greater,
ENDCASE => ERROR];
};
SourceFind:
PROC [resultName:
ROPE, finderData:
REF
ANY]
RETURNS [found:
BOOLEAN, sought: Node, makes, cmdFrom: NodeList, from: From, cmd:
ROPE, class: ActionClass, foundData:
REF
ANY]
-- FinderProc -- =
BEGIN
bcdExpanded, shortName, baseName, sourceName, bcdName, configName, switches: ROPE;
bcdCP: FS.ComponentPositions;
sourceNode, bcdNode, configNode, switchesNode: Node;
bcdCreateTime: BasicTime.GMT;
supports: RedBlackTree.Table;
md: SourceData;
sourceType: SourceType;
NoteDep:
PROC [fileName:
ROPE] = {
n: Node = GetNode[fileName.Cat[".BCD"], fileClass];
s: Support ← NARROW[supports.Lookup[n]];
IF s =
NIL
THEN {
s ← NEW [SupportRep ← [n, TimeStamp.Null]];
supports.Insert[s, n];
};
from.mustHave ← CONS[n, from.mustHave];
};
found ← TRUE;
[bcdExpanded, bcdCP, ] ← FS.ExpandName[resultName !FS.Error => {found ← FALSE; CONTINUE}];
IF NOT found THEN RETURN;
IF
NOT (found ←
bcdExpanded.Substr[start: bcdCP.ext.start, len: bcdCP.ext.length].
Equal[s2: "BCD", case: FALSE]
OR (bcdCP.ext.length = 0))
THEN RETURN;
baseName ← bcdExpanded.Substr[start: 0, len: bcdCP.base.start + bcdCP.base.length];
shortName ← bcdExpanded.Substr[start: bcdCP.base.start, len: bcdCP.base.length];
bcdName ← baseName.Cat[".BCD"];
switchesNode ← GetNode[bcdName.Concat[".Switches"], fileClass];
switches ← GetSwitches[bcdName];
makes ← LIST[sought ← bcdNode ← GetNode[bcdName, fileClass]];
bcdCreateTime ← InnerGetCreated[bcdNode];
from ← [mustHave: NIL, optional: LIST[switchesNode]];
supports ← RedBlackTree.Create[GetSupportKey, CompareSupport];
sourceType ← Mesa;
sourceName ← baseName.Concat[".Mesa"];
cmd ← Rope.Cat["RCompile ", switches, " ", shortName];
IF
(
NOT EnumerateDependancies[
(sourceNode ← GetNode[sourceName, fileClass]),
sourceType,
NoteDep])
AND EnumerateDependancies[
(configNode ← GetNode[configName ← baseName.Concat[".Config"], fileClass]),
Config,
NoteDep]
THEN {
sourceName ← configName;
sourceNode ← configNode;
sourceType ← Config;
cmd ← Rope.Cat["Bind ", switches, " ", shortName]};
cmdFrom ← LIST[sourceNode, switchesNode];
foundData ← md ← NEW [SourceDataRep ← [bcdName: bcdName, shortName: shortName, sourceType: sourceType, supports: supports, sourceNode: sourceNode, switchesNode: switchesNode, bcdNode: bcdNode, bcdCreateTime: bcdCreateTime, cmd: cmd]];
IF bcdCreateTime # MakeDo.notExistTime THEN MakeSupports[md];
from.mustHave ← CONS[sourceNode, from.mustHave];
class ← configAndMesaClass;
END;
GetSwitches:
PROC [bcdName:
ROPE]
RETURNS [switches:
ROPE] =
BEGIN
ss: IO.STREAM ← NIL;
ss ← FS.StreamOpen[bcdName.Cat[".Switches"] !FS.Error => CONTINUE];
IF ss = NIL THEN RETURN [NIL];
[] ← ss.SkipWhitespace[];
IF ss.EndOf[] THEN RETURN [NIL];
switches ← ss.GetTokenRope[IO.IDProc].token;
ss.Close[];
END;
CheckConsistency:
PROC [a: Action, result: Node]
RETURNS [consistent:
BOOL, reason:
ROPE]
--ConsistencyChecker-- =
BEGIN
md: SourceData = NARROW[a.PublicPartsOfAction[].foundData];
switchesCreate: BasicTime.GMT = InnerGetCreated[md.switchesNode];
curSourceStamp: Stamp;
CheckSupport:
PROC [data:
REF
ANY]
RETURNS [stop:
BOOL ←
FALSE]
--RedBlackTree.EachNode-- = {
s: Support = NARROW[data];
curBCDStamp: Stamp = CurBCDStamp[s.node];
IF curBCDStamp = TimeStamp.Null
THEN {
consistent ← TRUE;
reason ← IO.PutFR["input %g doesn't exist", [rope[s.node.PublicPartsOfNode[].name]] ];
RETURN [TRUE];
};
IF curBCDStamp # s.version
THEN {
out: IO.STREAM ← IO.ROS[];
out.PutRope["last used version "];
TRUSTED {ListerUtils.PrintVersion[s.version, out, FALSE]};
out.PutF[
" of %g, but current version is ",
[rope[s.node.PublicPartsOfNode[].name]]
];
TRUSTED {ListerUtils.PrintVersion[curBCDStamp, out, FALSE]};
consistent ← FALSE;
reason ← out.RopeFromROS[];
RETURN [TRUE];
};
};
UpdateSupport[md];
IF md.bcdCreateTime = MakeDo.notExistTime THEN RETURN [FALSE, "BCD doesn't exist"];
IF NOT md.bcdReadable THEN RETURN [FALSE, "BCD not readable"];
curSourceStamp ← CurSourceStamp[md.sourceNode];
IF curSourceStamp = TimeStamp.Null THEN RETURN [TRUE, "source doesn't exist"];
IF curSourceStamp # md.sourceStamp
THEN {
out: IO.STREAM ← IO.ROS[];
out.PutRope["last used source "];
TRUSTED {ListerUtils.PrintVersion[md.sourceStamp, out, TRUE]};
out.PutRope[", but current source is "];
TRUSTED {ListerUtils.PrintVersion[curSourceStamp, out, TRUE]};
RETURN [FALSE, out.RopeFromROS[]];
};
IF switchesCreate # MakeDo.notExistTime AND BasicTime.Period[md.bcdCreateTime, switchesCreate] > 0 THEN RETURN [FALSE, "switches file created later than result"];
consistent ← TRUE;
reason ← "all version stamps match";
md.supports.EnumerateIncreasing[CheckSupport];
END;
UpdateSupport:
PROC [md: SourceData] = {
oldBcd: Time = md.bcdCreateTime;
md.bcdCreateTime ← InnerGetCreated[md.bcdNode];
IF md.bcdCreateTime = MakeDo.notExistTime THEN RETURN;
IF md.bcdCreateTime = oldBcd AND NOT md.supportsInvalid THEN RETURN;
MakeSupports[md];
};
CurSourceStamp:
PROC [node: Node]
RETURNS [stamp: Stamp] =
BEGIN
time: Time ← InnerGetCreated[node];
IF time = MakeDo.notExistTime THEN RETURN [TimeStamp.Null];
stamp ← [net: 0, host: 0, time: BasicTime.ToPupTime[time]];
END;
CurBCDStamp:
ENTRY
PROC [node: Node]
RETURNS [stamp: Stamp] =
BEGIN
ENABLE UNWIND => {};
sr: StampRef ← NARROW[node.GetProp[$Stamp]];
created: BasicTime.GMT ← InnerGetCreated[node];
bcd: ListerUtils.RefBCD;
IF sr =
NIL
THEN node.SetProp[
prop: $Stamp,
val: sr ←
NEW [StampRep ← [
created: notExistTime,
stamp: TimeStamp.Null]]
];
IF created = sr.created THEN RETURN [sr.stamp];
sr.created ← created;
IF created = MakeDo.notExistTime
THEN sr.stamp ← TimeStamp.Null
ELSE {
TRUSTED {bcd ← ListerUtils.ReadBcd[node.PublicPartsOfNode[].name !FS.Error => {bcd ← NIL; CONTINUE}]};
sr.stamp ←
IF bcd =
NIL
OR bcd.versionIdent # BcdDefs.VersionID
THEN TimeStamp.Null
ELSE bcd.version;
};
stamp ← sr.stamp;
END;
MakeSupports:
PROC [md: SourceData] =
BEGIN
NoteSupport:
PROC [name:
ROPE, version: Stamp] =
BEGIN
extName: ROPE = FS.ExpandName[name.Cat[".BCD"]].fullFName;
node: Node = GetNode[extName, fileClass];
s: Support = NARROW[md.supports.Lookup[node]];
IF s # NIL THEN s.version ← version;
END;
bcd: ListerUtils.RefBCD;
md.sourceStamp ← TimeStamp.Null;
md.bcdReadable ← FALSE;
TRUSTED {bcd ← ListerUtils.ReadBcd[md.bcdName !FS.Error => {bcd ← NIL; CONTINUE}]};
IF bcd = NIL THEN RETURN;
IF bcd.versionIdent # BcdDefs.VersionID THEN RETURN;
md.sourceStamp ← bcd.sourceVersion;
[] ← BCDery.EnumerateFiles[bcd: bcd, bcdFileName: md.bcdName, to: NoteSupport];
md.bcdReadable ← TRUE;
md.supportsInvalid ← FALSE;
END;
RederiveSource:
PROC [a: Action]
RETURNS [from: From, cmd:
ROPE]
--RederiveProc-- =
BEGIN
md: SourceData ← NARROW[a.PublicPartsOfAction[].foundData];
NoteDep:
PROC [fileName:
ROPE] = {
n: Node = GetNode[fileName.Cat[".BCD"], fileClass];
s: Support ← NARROW[md.supports.Lookup[n]];
IF s =
NIL
THEN {
s ← NEW [SupportRep ← [n, TimeStamp.Null]];
md.supports.Insert[s, n];
};
from.mustHave ← CONS[n, from.mustHave];
};
from ← [NIL, NIL];
md.supports.DestroyTable[];
[] ← EnumerateDependancies[md.sourceNode, md.sourceType, NoteDep];
md.supportsInvalid ← TRUE;
UpdateSupport[md];
from.mustHave ← CONS[md.sourceNode, from.mustHave];
md.cmd ← cmd ← Rope.Cat[
SELECT md.sourceType FROM Mesa => "RCompile ", Config => "Bind ", ENDCASE => ERROR,
GetSwitches[md.bcdName],
" ",
md.shortName];
END;
Break:
IO.BreakProc = {
RETURN [
SELECT char
FROM
IN ['a .. 'z], IN ['A .. 'Z], IN ['0 .. '9] => other,
IO.SP, IO.CR, IO.TAB, IO.LF, IO.FF => sepr,
ENDCASE => break]};
Letter:
PROC [c:
CHAR]
RETURNS [letter:
BOOLEAN] =
INLINE
{letter ← (c IN ['a .. 'z]) OR (c IN ['A .. 'Z])};
EnumerateDependancies:
PROC [sourceNode: Node, sourceType: SourceType, consume:
PROC [fileName:
ROPE]]
RETURNS [exists:
BOOLEAN] =
BEGIN
sourceName: ROPE = sourceNode.PublicPartsOfNode[].name;
pd: ParseData ← NARROW[parses.Lookup[sourceName]];
cur: BasicTime.GMT;
IF pd =
NIL
THEN {
pd ← NEW [ParseDataRep ← [source: sourceName, sourceType: sourceType]];
parses.Insert[pd, sourceName];
};
cur ← InnerGetCreated[sourceNode];
IF NOT (exists ← cur # notExistTime) THEN RETURN;
IF cur # pd.stamp
THEN {
NoteDep:
PROC [fileName:
ROPE] = {
pd.refdModules ← CONS[fileName, pd.refdModules];
consume[fileName]};
pd.stamp ← cur; pd.refdModules ← NIL;
SELECT pd.sourceType
FROM
Mesa => [] ← EnumerateMesaDependancies[sourceName, NoteDep];
Config => [] ← EnumerateConfigDependancies[sourceName, NoteDep];
ENDCASE => ERROR;
}
ELSE {
FOR rml: RopeList ← pd.refdModules, rml.rest
WHILE rml #
NIL
DO
consume[rml.first] ENDLOOP};
END;
EnumerateMesaDependancies:
PROC [sourceName:
ROPE, consume:
PROC [fileName:
ROPE]]
RETURNS [exists:
BOOLEAN] =
BEGIN
NextToken:
PROC
RETURNS [
ROPE] =
{RETURN [source.GetTokenRope[Break].token]};
ParseDirectory:
PROC
RETURNS [next:
ROPE] =
BEGIN
firstClause: BOOL ← TRUE;
ParseClause:
PROC
RETURNS [next:
ROPE] =
BEGIN
fileName: ROPE ← "?";
next ← NextToken[];
IF firstClause
THEN
{firstClause ← FALSE; IF next.Equal[";"] THEN RETURN};
IF NOT Letter[next.Fetch[0]] THEN ERROR GotoSyntaxError;
fileName ← next;
next ← NextToken[];
IF next.Equal[":"]
THEN
BEGIN
next ← NextToken[];
IF next.Equal["TYPE"]
THEN {
next ← NextToken[];
IF Letter[next.Fetch[0]] AND NOT next.Equal["USING"] THEN next ← NextToken[];
}
ELSE
IF next.Equal["FROM"]
THEN {
fileName ← source.GetRopeLiteral[];
next ← NextToken[];
}
ELSE ERROR GotoSyntaxError;
END;
IF next.Equal["USING"]
THEN
BEGIN
IF NOT (next ← NextToken[]).Equal["["] THEN ERROR GotoSyntaxError;
WHILE NOT (next ← NextToken[]).Equal["]"] DO NULL ENDLOOP;
next ← NextToken[];
END;
consume[fileName];
END;
IF (next ← NextToken[]).Equal["DIRECTORY"]
THEN
BEGIN
DO
IF (next ← ParseClause[]).Equal[";"] THEN EXIT;
IF NOT next.Equal[","] THEN ERROR GotoSyntaxError;
ENDLOOP;
next ← NextToken[];
END;
IF NOT Letter[next.Fetch[0]] THEN ERROR GotoSyntaxError;
END;
source: IO.STREAM ← NIL;
source ← FS.StreamOpen[fileName: sourceName, accessOptions: $read !FS.Error => {source ← NIL; CONTINUE}];
exists ← source # NIL;
IF NOT exists THEN RETURN;
source ← IOClasses.CreateCommentFilterStream[source];
[] ← source.GetIndex[];
[] ← ParseDirectory[!GotoSyntaxError =>
BEGIN
SIGNAL Warning[IO.PutFR["Syntax error in %g; parse aborted at %g", IO.rope[sourceName], IO.int[source.GetIndex[]]]];
CONTINUE
END];
source.Close[];
END;
IsConfig:
PROC [word:
ROPE]
RETURNS [is:
BOOLEAN] =
{is ← word.Equal["CONFIGURATION"] OR word.Equal["CONFIG"]};
EnumerateConfigDependancies:
PROC [sourceName:
ROPE,
Consume:
PROC [fileName:
ROPE]]
RETURNS [exists:
BOOLEAN] = {
locals: LIST OF LIST OF ROPE ← NIL;
AddDef: PROC [name: ROPE] = {locals.first ← CONS[name, locals.first]};
MaybeConsume:
PROC [moduleName:
ROPE] = {
FOR l:
LIST
OF
LIST
OF
ROPE ← locals, l.rest
WHILE l #
NIL
DO
FOR m:
LIST
OF
ROPE ← l.first, m.rest
WHILE m #
NIL
DO
IF m.first.Equal[moduleName] THEN RETURN;
ENDLOOP;
ENDLOOP;
Consume[moduleName]};
NextToken: PROC RETURNS [ROPE] = {RETURN [source.GetTokenRope[Break].token]};
ParseConfigDescription:
PROC = {
next: ROPE ← ParseCDirectory[];
next ← ParseCPacking[next];
next ← ParseConfiguration[next];
IF NOT next.Equal["."] THEN ERROR GotoSyntaxError;
};
ParseConfiguration:
PROC [first:
ROPE]
RETURNS [next:
ROPE] = {
IF NOT Letter[first.Fetch[0]] THEN ERROR GotoSyntaxError;
IF NOT (next ← NextToken[]).Equal[":"] THEN ERROR GotoSyntaxError;
IF NOT IsConfig[next ← NextToken[]] THEN ERROR GotoSyntaxError;
next ← ParseConfigurationRemains[];
};
ParseConfigurationRemains:
PROC
RETURNS [next:
ROPE] = {
next ← ParseCHeadRemains[];
IF NOT (next.Equal["="] OR next.Equal["~"]) THEN ERROR GotoSyntaxError;
ParseCBody[];
next ← NextToken[];
};
ParseCBody:
PROC = {
next: ROPE ← NextToken[];
curly: BOOLEAN;
IF next.Equal["BEGIN"] THEN curly ← FALSE
ELSE IF next.Equal["{"] THEN curly ← TRUE
ELSE ERROR GotoSyntaxError;
locals ← CONS[NIL, locals];
next ← NextToken[];
DO
semiSeen: BOOL ← FALSE;
next ← ParseCStatement[next];
WHILE next.Equal[";"]
DO
next ← NextToken[];
semiSeen ← TRUE;
ENDLOOP;
IF next.Equal[IF curly THEN "}" ELSE "END"] THEN EXIT;
IF NOT semiSeen THEN ERROR GotoSyntaxError;
ENDLOOP;
locals ← locals.rest;
};
ParseCStatement:
PROC [first:
ROPE]
RETURNS [next:
ROPE] = {
next ← first;
IF next.Equal["["]
THEN
BEGIN
next ← ParseItemList[FALSE];
IF NOT next.Equal["]"] THEN ERROR GotoSyntaxError;
next ← NextToken[];
IF NOT next.Equal["←"] THEN ERROR GotoSyntaxError;
next ← ParseCExpression[];
END
ELSE
BEGIN
lhs, rhs: ROPE;
named: BOOL ← FALSE;
lhs ← rhs ← next;
IF named ← (next ← NextToken[]).Equal[":"]
THEN
BEGIN
IF IsConfig[rhs ← NextToken[]]
THEN {
AddDef[lhs];
next ← ParseConfigurationRemains[];
RETURN};
next ← NextToken[];
END;
IF next.Equal["←"]
THEN
BEGIN
AddDef[lhs];
next ← ParseCExpression[];
END
ELSE
BEGIN
IF named THEN AddDef[lhs];
MaybeConsume[rhs];
IF next.Equal["["]
THEN
BEGIN
IF NOT (next ← NextToken[]).Equal["]"] THEN next ← EatIDList[next, FALSE];
IF NOT next.Equal["]"] THEN ERROR GotoSyntaxError;
next ← ParseCLinks[];
END
ELSE
IF next.Equal["LINKS"]
THEN {
SIGNAL Warning[IO.PutFR["[] missing before %g in %g", IO.int[source.GetIndex[]], IO.rope[sourceName]]];
next ← ParseCLinks[next];
};
END;
END;
};
ParseCExpression:
PROC
RETURNS [next:
ROPE] = {
next ← ParseCRightSide[];
WHILE next.Equal["PLUS"]
DO
next ← ParseCRightSide[];
ENDLOOP;
WHILE next.Equal["THEN"]
DO
next ← ParseCRightSide[];
ENDLOOP;
};
ParseCRightSide:
PROC
RETURNS [next:
ROPE] = {
next ← ParseItem[NIL, TRUE];
IF next.Equal["["]
THEN
BEGIN
IF NOT (next ← NextToken[]).Equal["]"] THEN next ← EatIDList[next, FALSE];
IF NOT next.Equal["]"] THEN ERROR GotoSyntaxError;
next ← ParseCLinks[];
END;
};
ParseCHeadRemains:
PROC
RETURNS [next:
ROPE] = {
next ← ParseCLinks[];
next ← ParseImports[next];
next ← ParseCExports[next];
next ← ParseControlClause[next];
};
ParseCLinks:
PROC [first:
ROPE ←
NIL]
RETURNS [next:
ROPE] = {
next ← IF first # NIL THEN first ELSE NextToken[];
IF NOT next.Equal["LINKS"] THEN RETURN;
IF NOT (next ← NextToken[]).Equal[":"] THEN ERROR GotoSyntaxError;
next ← NextToken[];
IF NOT (next.Equal["CODE"] OR next.Equal["FRAME"]) THEN ERROR GotoSyntaxError;
next ← NextToken[];
};
ParseImports:
PROC [first:
ROPE]
RETURNS [next:
ROPE] = {
IF NOT first.Equal["IMPORTS"] THEN RETURN [first];
next ← ParseItemList[FALSE];
};
ParseCExports:
PROC [first:
ROPE]
RETURNS [next:
ROPE] = {
IF NOT first.Equal["EXPORTS"] THEN RETURN [first];
next ← ParseItemList[FALSE];
};
ParseControlClause:
PROC [first:
ROPE]
RETURNS [next:
ROPE] = {
IF NOT first.Equal["CONTROL"] THEN RETURN [first];
next ← EatIDList[NIL, FALSE];
};
ParseItemList:
PROC [notice:
BOOLEAN]
RETURNS [next:
ROPE] = {
DO
next ← ParseItem[NIL, notice];
IF NOT next.Equal[","] THEN EXIT;
ENDLOOP;
};
ParseItem:
PROC [first:
ROPE, notice:
BOOLEAN]
RETURNS [next:
ROPE] = {
lhs, rhs: ROPE;
named: BOOL ← FALSE;
lhs ← rhs ← IF first = NIL THEN NextToken[] ELSE first;
IF named ← (next ← NextToken[]).Equal[":"]
THEN
BEGIN
rhs ← NextToken[];
next ← NextToken[];
END;
IF notice
THEN {
IF named THEN AddDef[lhs];
MaybeConsume[rhs]};
};
ParseCDirectory:
PROC
RETURNS [next:
ROPE] = {
firstClause: BOOL ← TRUE;
ParseClause:
PROC
RETURNS [next:
ROPE] = {
moduleName: ROPE ← "?";
fileName: ROPE ← "?";
next ← NextToken[];
IF firstClause
THEN
{firstClause ← FALSE; IF next.Equal[";"] THEN RETURN};
IF NOT Letter[next.Fetch[0]] THEN ERROR GotoSyntaxError;
moduleName ← fileName ← next;
next ← NextToken[];
IF next.Equal[":"]
THEN
BEGIN
next ← NextToken[];
IF next.Equal["TYPE"]
THEN {
next ← NextToken[];
IF Letter[next.Fetch[0]] THEN next ← NextToken[];
}
ELSE
IF next.Equal["FROM"]
THEN {
fileName ← source.GetRopeLiteral[];
next ← NextToken[];
}
ELSE ERROR GotoSyntaxError;
END;
Consume[fileName];
AddDef[moduleName];
};
locals ← CONS[NIL, locals];
IF NOT (next ← NextToken[]).Equal["DIRECTORY"] THEN RETURN;
DO
IF (next ← ParseClause[]).Equal[";"] THEN EXIT;
IF NOT next.Equal[","] THEN ERROR GotoSyntaxError;
ENDLOOP;
next ← NextToken[];
};
ParseCPacking:
PROC [first:
ROPE]
RETURNS [next:
ROPE] = {
next ← first;
WHILE next.Equal["PACK"]
DO
next ← EatIDList[NIL, FALSE];
IF NOT next.Equal[";"] THEN ERROR GotoSyntaxError;
next ← NextToken[];
ENDLOOP;
};
EatIDList:
PROC [first:
ROPE, notice:
BOOLEAN]
RETURNS [next:
ROPE] = {
next ← IF first = NIL THEN NextToken[] ELSE first;
DO
IF NOT Letter[next.Fetch[0]] THEN ERROR GotoSyntaxError;
IF notice THEN Consume[next];
next ← NextToken[];
IF NOT next.Equal[","] THEN EXIT;
next ← NextToken[];
ENDLOOP;
};
source: IO.STREAM ← NIL;
source ← FS.StreamOpen[fileName: sourceName, accessOptions: $read !FS.Error => {source ← NIL; CONTINUE}];
exists ← source # NIL;
IF NOT exists THEN RETURN;
source ← IOClasses.CreateCommentFilterStream[source];
[] ← source.GetIndex[];
ParseConfigDescription[!GotoSyntaxError =>
BEGIN
SIGNAL Warning[IO.PutFR["Syntax error in %g; parse aborted at %g", IO.rope[sourceName], IO.int[source.GetIndex[]]]];
CONTINUE
END];
source.Close[];
};
AddFinder[["Compiler and Binder", SourceFind], front];
END.