MakeDoParsingImpl.mesa
Copyright Ó 1989, 1991 by Xerox Corporation. All rights reserved.
Eduardo Pelegri-Llopart, August 20, 1989 9:26:14 pm PDT
DIRECTORY
BasicTime USING [GMT],
FS,
IO,
IOTrueCommentFilter,
MakeDo,
MakeDoParsing,
PBasics,
RefTab,
Rope,
RopeHash;
MakeDoParsingImpl: CEDAR MONITOR
IMPORTS FS, IO, IOTrueCommentFilter, MakeDo, MakeDoParsing, PBasics, RefTab, Rope, RopeHash
EXPORTS MakeDoParsing
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
STREAM: TYPE ~ IO.STREAM;
parseCache: RefTab.Ref ~ RefTab.Create[equal: EqualParses, hash: HashParse];
parsers: LIST OF Parser;
Parser: TYPE ~ REF ParserRep; ParserRep: TYPE ~ MakeDoParsing.ParserRep;
ParserProc: TYPE ~ MakeDoParsing.ParserProc;
ParseEntry: TYPE ~ REF ParseEntryRep; ParseEntryRep: TYPE ~ MakeDoParsing.ParseEntryRep;
End: TYPE ~ MakeDo.End;
ParserClass: TYPE ~ MakeDoParsing.ParserClass;
ParseData: TYPE ~ MakeDoParsing.ParseData;
Node: TYPE ~ MakeDoParsing.Node;
ParserClassFail: PUBLIC ERROR ~ CODE;
SyntaxError: PUBLIC SIGNAL[synMsg: ROPE] = CODE;
GotoSyntaxError: ERROR = CODE;
Auxiliary Procs
CardsPerRef: INT ~ SIZE[REF]/SIZE[CARDINAL];
Munch: PROC [in: REF] RETURNS [out: CARDINAL] ~ {
temp: ARRAY [0..CardsPerRef) OF CARDINAL ~ LOOPHOLE[in];
out ¬ temp[0];
FOR i: INT IN (0..CardsPerRef) DO
out ¬ PBasics.BITXOR[out, temp[i]];
ENDLOOP;
};
EqualParses: PROC [key1, key2: REF] RETURNS [BOOL] ~ {
pe1: ParseEntry ~ NARROW[key1];
pe2: ParseEntry ~ NARROW[key2];
IF pe1 = NIL OR pe2 = NIL THEN RETURN [pe1 = pe2];
RETURN [pe1.source.Equal[pe2.source] AND pe1.parserClass = pe2.parserClass];
};
HashParse: PROC [key: REF] RETURNS [CARDINAL] ~ {
pe: ParseEntry ~ NARROW[key];
w1: CARDINAL ~ RopeHash.FromRope[pe.source];
w2: CARDINAL ~ Munch[pe.parserClass];
RETURN [PBasics.BITXOR[w1, w2]];
};
Public Procs
GetParseEntry: PUBLIC PROC [node: Node, class: ParserClass] RETURNS [parseEntry: ParseEntry] ~ {
createTime: BasicTime.GMT ~ MakeDo.InnerGetCreated[node];
nodeName: ROPE ~ node.PublicPartsOfNode[].name;
IF createTime = MakeDo.notExistTime THEN RETURN [NIL];
{
parser: Parser ~ GetParser[class];
key: ParseEntry ~ NEW [ParseEntryRep ¬ [source: nodeName, parserClass: class, parseData: NIL]];
inStream: STREAM ¬ NIL;
pe: ParseEntry;
IF parser = NIL THEN ERROR ParserClassFail;
pe ¬ NARROW[parseCache.Fetch[key].val];
pe ← NARROW[parseCache.Lookup[key]];
IF pe = NIL THEN pe ¬ NEW [ParseEntryRep ¬ [source: nodeName, parserClass: class, parseData: RefTab.Create[]]];
IF pe.stamp = createTime THEN RETURN [pe];
inStream ¬ FS.StreamOpen[fileName: nodeName, accessOptions: $read !FS.Error => {inStream ¬ NIL; CONTINUE}];
IF inStream = NIL THEN RETURN [NIL];
should it be an error?
pe.stamp ¬ createTime;
pe.parseData ¬ parser.parserProc[inStream, parser.parserData !
FS.Error => { pe ¬ NIL; CONTINUE};
MakeDoParsing.SyntaxError => { SIGNAL MakeDo.Warning[IO.PutFR["In %g: %g", IO.rope[nodeName], IO.rope[synMsg]]]; RESUME };
];
inStream.Close[];
IF pe # NIL THEN [] ¬ parseCache.Insert[pe, pe];
RETURN [parseEntry: pe];
};
};
AddParser: PUBLIC ENTRY PROC [parser: Parser, end: End] ~ {
ENABLE UNWIND => {};
SELECT end FROM
front => parsers ¬ CONS[parser, parsers];
back => {
list : LIST OF Parser;
IF parsers = NIL THEN {parsers ¬ LIST[parser]; RETURN};
FOR list ¬ parsers, list.rest WHILE list.rest # NIL DO NULL ENDLOOP;
list.rest ¬ LIST[parser]};
ENDCASE => ERROR;
};
GetParser: PUBLIC ENTRY PROC [class: ParserClass] RETURNS [parser: Parser] ~ {
ENABLE UNWIND => {};
FOR list: LIST OF Parser ¬ parsers, list.rest WHILE list # NIL DO
IF class = list.first.parserClass THEN RETURN [list.first];
ENDLOOP;
RETURN;
};
EnumerateParsers: PUBLIC ENTRY PROC [to: PROC [parser: Parser] RETURNS [stop: BOOL ¬ FALSE]] ~ {
ENABLE UNWIND => {};
FOR list: LIST OF Parser ¬ parsers, list.rest WHILE list # NIL DO
IF to[list.first] THEN EXIT;
ENDLOOP;
RETURN
};
ClearCache: PUBLIC ENTRY PROC ~ {
ENABLE UNWIND => {};
parseCache.Erase[];
};
Mesa/Cedar parser
mesaParser: Parser ~ NEW [ParserRep ¬ [
parserClass: $Mesa,
parserName: "Cedar/Mesa Parser",
parserProc: MesaParseProc,
parserData: NIL
]];
MesaBreak: 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]};
MesaLetter: PROC [c: CHAR] RETURNS [letter: BOOLEAN] = INLINE
{letter ¬ (c IN ['a .. 'z]) OR (c IN ['A .. 'Z])};
MesaParseProc: MakeDoParsing.ParserProc ~ {
PROC [stream: STREAM, parserData: REF] RETURNS [parseData: ParseData]
Consume: PROC [fileName: ROPE] ~ {
directoryFileList ¬ CONS[fileName, directoryFileList];
RETURN;
};
NextToken: PROC RETURNS [ROPE] =
{RETURN [source.GetTokenRope[MesaBreak].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 MesaLetter[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 MesaLetter[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 MesaLetter[next.Fetch[0]] THEN ERROR GotoSyntaxError;
END;
ParseMesaHead: PROC RETURNS [next: ROPE] ~ {
type: ATOM ¬ $Unknown;
next ¬ NextToken[];
WHILE next.Equal[","] DO
next ¬ NextToken[];
next ¬ NextToken[]
ENDLOOP;
IF NOT next.Equal[":"] THEN ERROR GotoSyntaxError;
next ¬ NextToken[];
IF next.Equal["CEDAR"] THEN next ¬ NextToken[];
SELECT TRUE FROM
next.Equal["DEFINITIONS"] => sourceType ¬ $CedarDefs;
next.Equal["PROGRAM"] => sourceType ¬ $CedarProg;
next.Equal["MONITOR"] => sourceType ¬ $CedarMonitor;
ENDCASE => ERROR GotoSyntaxError;
};
DoIt: PROC ~ {
[] ¬ ParseDirectory[!
GotoSyntaxError => {
SIGNAL MakeDoParsing.SyntaxError[IO.PutFR["Syntax error; parse aborted at %g", [integer[source.GetIndex[]]]]];
GOTO Done
};
IO.EndOfStream => {
SIGNAL MakeDoParsing.SyntaxError[IO.PutFR["Premature end-of-file; parse aborted at %g", [integer[source.GetIndex[]]]]];
GOTO Done
};
];
[] ¬ ParseMesaHead[!
GotoSyntaxError => {
SIGNAL MakeDoParsing.SyntaxError[IO.PutFR["Syntax error; parse aborted at %g", [integer[source.GetIndex[]]]]];
GOTO Done
};
IO.EndOfStream => {
SIGNAL MakeDoParsing.SyntaxError[IO.PutFR["Premature end-of-file; parse aborted at %g", [integer[source.GetIndex[]]]]];
GOTO Done
};
];
EXITS
Done => NULL;
};
source: STREAM ~ IOTrueCommentFilter.CreateCommentFilterStream[stream];
sourceType: ATOM ¬ $Unknown;
directoryFileList: LIST OF ROPE ¬ NIL;
[] ¬ source.GetIndex[];
DoIt[];
parseData ¬ RefTab.Create[];
[] ¬ parseData.Insert[$SourceType, sourceType];
[] ¬ parseData.Insert[$Directory, directoryFileList];
RETURN [parseData];
};
Config parser
configParser: Parser ~ NEW [ParserRep ¬ [
parserClass: $Config,
parserName: "Config Parser",
parserProc: ConfigParseProc,
parserData: NIL
]];
ListOfListsToList: PROC [listOfLists: LIST OF LIST OF ROPE] RETURNS [list: LIST OF ROPE ¬ NIL] ~ {
FOR l: LIST OF LIST OF ROPE ¬ listOfLists, l.rest WHILE l # NIL DO
FOR m: LIST OF ROPE ¬ l.first, m.rest WHILE m # NIL DO
list ¬ CONS[m.first, list];
ENDLOOP;
ENDLOOP;
};
ConfigParseProc: MakeDoParsing.ParserProc ~ {
PROC [stream: STREAM, parserData: REF] RETURNS [parseData: ParseData]
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;
requestsFileList ¬ CONS[moduleName, requestsFileList];
};
Consume: PROC [fileName: ROPE] ~ {
requestsFileList ¬ CONS[fileName, requestsFileList];
};
ConsumeSimple: PROC [fileName: ROPE] ~ {
staticRequestsFileList ¬ CONS[fileName, staticRequestsFileList];
};
NextToken: PROC RETURNS [ROPE] = {RETURN [source.GetTokenRope[MesaBreak].token]};
IsConfig: PROC [word: ROPE] RETURNS [is: BOOLEAN] = {
is ¬ word.Equal["CONFIGURATION"] OR word.Equal["CONFIG"];
sourceType ¬ $Config
};
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 MesaLetter[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 MakeDoParsing.SyntaxError[IO.PutFR["[] missing before %g", IO.int[source.GetIndex[]]]];
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 ¬ ParseStatics[next];
next ¬ ParseDynamics[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];
};
ParseStatics: PROC [first: ROPE] RETURNS [next: ROPE] = {
IF NOT first.Equal["STATIC"] THEN RETURN [first];
IF NOT (next ¬ NextToken[]).Equal["REQUESTS"] THEN ERROR GotoSyntaxError;
next ¬ ParseStringList[TRUE];
};
ParseDynamics: PROC [first: ROPE] RETURNS [next: ROPE] = {
IF NOT first.Equal["DYNAMIC"] THEN RETURN [first];
IF NOT (next ¬ NextToken[]).Equal["REQUESTS"] THEN ERROR GotoSyntaxError;
next ¬ ParseStringList[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]};
};
ParseStringList: PROC [notice: BOOLEAN] RETURNS [next: ROPE] = {
DO
next ¬ ParseString[notice];
IF NOT next.Equal[","] THEN EXIT;
ENDLOOP;
};
ParseString: PROC [notice: BOOLEAN] RETURNS [next: ROPE] = {
string: ROPE;
string ¬ source.GetRopeLiteral[ !IO.Error => ERROR GotoSyntaxError];
next ¬ NextToken[];
IF notice THEN {
ConsumeSimple[string]};
};
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 MesaLetter[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 MesaLetter[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 MesaLetter[next.Fetch[0]] THEN ERROR GotoSyntaxError;
IF notice THEN Consume[next];
next ¬ NextToken[];
IF NOT next.Equal[","] THEN EXIT;
next ¬ NextToken[];
ENDLOOP;
};
DoIt: PROC ~ {
ParseConfigDescription[!
GotoSyntaxError => {
SIGNAL MakeDoParsing.SyntaxError[IO.PutFR["Syntax error in; parse aborted at %g", [integer[source.GetIndex[]]]]];
GOTO Done
};
IO.EndOfStream => {
SIGNAL MakeDoParsing.SyntaxError[IO.PutFR["Premature end-of-file; parse aborted at %g", [integer[source.GetIndex[]]]]];
GOTO Done
};
];
EXITS
Done => NULL;
};
source: IO.STREAM ~ IOTrueCommentFilter.CreateCommentFilterStream[stream];
sourceType: ATOM ¬ $Unknown;
locals: LIST OF LIST OF ROPE ¬ NIL;
requestsFileList: LIST OF ROPE ¬ NIL;
staticRequestsFileList: LIST OF ROPE ¬ NIL;
[] ¬ source.GetIndex[];
DoIt[];
parseData ¬ RefTab.Create[];
[] ¬ parseData.Insert[$SourceType, sourceType];
[] ¬ parseData.Insert[$Requests, requestsFileList];
[] ¬ parseData.Insert[$StaticRequests, staticRequestsFileList];
[] ¬ parseData.Insert[$Locals, ListOfListsToList[locals]];
RETURN [parseData];
};
C parser (sort-of)
cParser: Parser ~ NEW [ParserRep ¬ [
parserClass: $C,
parserName: "C Parser",
parserProc: CParseProc,
parserData: NIL
]];
CParseProc: MakeDoParsing.ParserProc ~ {
PROC [stream: STREAM, parserData: REF] RETURNS [parseData: ParseData]
This procedure does NOT take into account all the /lib/cpp tricks that can actually be done.
Actually, the correct way to do this is to use /lib/cpp, which, strictly speaking,
would not work because files may not exist yet and /lib/cpp will complain.
Which takes us to comparing the real differences between the binding models of C and Mesa, but this is not the moment to discuss them
ParseCFile: PROC = {
currentLine ← source.GetLineRope;
IF currentLine.... THEN currentLine ← currentLine.Cat[source.GetLineRope ! IO.EndOfStream => ERROR GotoSyntaxError];
--- repeat
if currentLine.Fetch[0] = SharpSign then
SkipOverBlanks
SkipToBlank
if inbetween is "include"
SkipOverBlanks  - if not found here is SyntaxError --
GetSeparatorCharacter  - too
SkipToSeparatorCharater  - too
CONSUME;
REPEAT ALL
IncludeSep: ROPE ~ """<";
WhiteSpace: ROPE ~ "  "; -- that is a tab and a blank --
WhiteSpaceOrSep: ROPE ~ "\t ""<";
SharpSign: CHAR ~ '#;
IncludeString: ROPE ~ "include";
Consume: PROC [string: ROPE, sepChar: CHAR] ~ {
IF sepChar # '" THEN RETURN;
IF string.Fetch[0] = '/ THEN RETURN;
IF string.SkipTo[0, "/"] # string.Length[] THEN RETURN;
includesFileList ¬ CONS[string, includesFileList];
};
WHILE NOT IO.EndOf[source] DO
We exit the loop by finding the end of the source stream
currentLine: ROPE;
lineLength: INT;
currentLine ¬ IO.GetLineRope[source];
IF currentLine = NIL THEN LOOP;
lineLength ¬ currentLine.Length[];
WHILE currentLine.Fetch[lineLength-1] = '\\ DO
currentLine ¬ currentLine.Cat[IO.GetLineRope[source ! IO.EndOfStream => ERROR GotoSyntaxError]];
lineLength ¬ currentLine.Length[];
ENDLOOP;
IF currentLine.Fetch[0] = SharpSign THEN {
tokStart, tokEnd: INT;
tokStart ¬ currentLine.SkipOver[1, WhiteSpace];
IF tokStart = lineLength THEN LOOP;
tokEnd ¬ currentLine.SkipTo[tokStart+1, WhiteSpaceOrSep];
IF NOT Rope.Equal[currentLine.Substr[tokStart, tokEnd-tokStart], IncludeString] THEN LOOP;
BEGIN
ENABLE {IO.EndOfStream => ERROR GotoSyntaxError};
matchSep: ROPE;
sepChar: CHAR;
tokStart ¬ currentLine.SkipTo[tokEnd, IncludeSep];
sepChar ¬ currentLine.Fetch[tokStart];
matchSep ¬ IF sepChar = '" THEN """" ELSE ">";
tokEnd ¬ currentLine.SkipTo[tokStart+1, matchSep];
Consume[currentLine.Substr[tokStart+1, tokEnd-(1+tokStart)], sepChar];
END;
};
ENDLOOP;
};
DoIt: PROC ~ {
ParseCFile[!
GotoSyntaxError => {
SIGNAL MakeDoParsing.SyntaxError[IO.PutFR["Syntax error at %g", [integer[source.GetIndex[]]]]];
GOTO Done
};
IO.EndOfStream => {
SIGNAL MakeDoParsing.SyntaxError[IO.PutFR["Premature end-of-file; parse aborted at %g", [integer[source.GetIndex[]]]]];
GOTO Done
};
];
EXITS
Done => NULL;
};
source: IO.STREAM ~ IOTrueCommentFilter.CreateCommentFilterStream[stream];
sourceType: ATOM ¬ $C;
includesFileList: LIST OF ROPE ¬ NIL;
[] ¬ source.GetIndex[];
DoIt[];
parseData ¬ RefTab.Create[];
[] ¬ parseData.Insert[$SourceType, sourceType];
[] ¬ parseData.Insert[$Includes, includesFileList];
RETURN [parseData];
};
Initialization
Init: PROC ~ {
MakeDoParsing.AddParser[mesaParser, front];
MakeDoParsing.AddParser[configParser, front];
MakeDoParsing.AddParser[cParser, front];
};
Init[];
END.