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; 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]]; }; 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]; 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]; 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[]; }; 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 ~ { 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]; }; 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 ~ { 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]; }; cParser: Parser ~ NEW [ParserRep ¬ [ parserClass: $C, parserName: "C Parser", parserProc: CParseProc, parserData: NIL ]]; CParseProc: MakeDoParsing.ParserProc ~ { ParseCFile: PROC = { 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; includesFileList ¬ CONS[string, includesFileList]; }; WHILE NOT IO.EndOf[source] DO 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]; }; Init: PROC ~ { MakeDoParsing.AddParser[mesaParser, front]; MakeDoParsing.AddParser[configParser, front]; MakeDoParsing.AddParser[cParser, front]; }; Init[]; END. „MakeDoParsingImpl.mesa Copyright Σ 1989, 1991 by Xerox Corporation. All rights reserved. Eduardo Pelegri-Llopart, August 20, 1989 9:26:14 pm PDT Auxiliary Procs Public Procs pe _ NARROW[parseCache.Lookup[key]]; should it be an error? Mesa/Cedar parser PROC [stream: STREAM, parserData: REF] RETURNS [parseData: ParseData] Config parser PROC [stream: STREAM, parserData: REF] RETURNS [parseData: ParseData] C parser (sort-of) 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 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 IF string.SkipTo[0, "/"] # string.Length[] THEN RETURN; We exit the loop by finding the end of the source stream Initialization Κπ–(cedarcode) style•NewlineDelimiter ˜code™Kšœ Οeœ7™BK™7—K˜šΟk ˜ Kšœ žœžœ˜Kšžœ˜Kšžœ˜K˜Kšœ˜Kšœ˜K˜Kšœ˜Kšœ˜Kšœ ˜ K˜—KšΠlnœžœž˜ KšžœžœžœM˜[Kšžœ˜šœž˜K˜Itypešžœžœžœ˜Lšžœžœžœžœ˜L˜K˜LKšœ žœžœ˜K˜šœžœžœžœ˜HK˜—Kšœ žœ˜,Kšœ žœžœžœ˜XKšœžœ˜K˜Kšœ žœ˜.Kšœ žœ˜*Kšœžœ˜ K˜KšΟnœžœžœžœ˜%Kš   œžœžœ žœžœ˜0K˜KšΠbnœžœžœ˜K˜head™Kš   œžœžœžœžœžœ˜,K˜š  œžœžœžœžœ˜1Kš œžœžœžœžœ˜8K˜šžœžœžœž˜!Kšœžœ˜#Kšžœ˜—K˜K˜—š   œžœžœžœžœ˜6Kšœžœ˜Kšœžœ˜Kš žœžœžœžœžœžœ ˜2Kšžœžœ%˜MK˜—K˜š   œžœžœžœžœ˜1Kšœžœ˜Kšœžœ ˜,Kšœžœ˜%Kšžœ žœ ˜ K˜——™ š  œžœžœ"žœ˜`Kšœžœ ˜9Kšœ žœ!˜/Kšžœ"žœžœžœ˜6˜K˜"KšœžœDžœ˜_Kšœ žœžœ˜K˜Kšžœ žœžœžœ˜+Kšœžœ˜'Kšœžœ™$KšžœžœžœžœV˜oKšžœžœžœ˜*KšœCžœžœžœ˜kš žœ žœžœžœžœ˜$K™—Kšœ˜šœ>˜>Kšžœžœžœ˜"Kš œžœžœžœžœžœ˜zK˜—K˜Kšžœžœžœ ˜0Kšžœ˜Kšœ˜—K˜—K˜š  œžœžœžœ˜;Kšžœžœ˜šžœž˜Kšœžœ˜)šœ ˜ Kšœžœžœž˜Kš žœ žœžœ žœ žœ˜7Kš žœžœ žœžœžœžœ˜DKšœ žœ ˜—Kšžœžœ˜—K˜K˜—š   œžœžœžœžœ˜NKšžœžœ˜š žœžœžœžœžœž˜AKšžœ žœžœ˜;Kšžœ˜—Kšžœ˜K˜K™—š œžœžœžœžœžœžœžœ˜`Kšžœžœ˜š žœžœžœžœžœž˜AKšžœžœžœ˜Kšžœ˜—Kšž˜Kšœ˜—K˜š  œžœžœžœ˜!Kšžœžœ˜K˜K˜—K˜—™šœžœ˜'K˜K˜ Kšœ˜Kšœ ž˜K˜K˜—š   œžœžœžœž˜3Kšžœ žœ žœ˜5Kšžœžœžœžœžœžœžœžœžœžœ ˜+Kšžœ ˜K˜—š   œžœžœžœ žœž˜=Kšœ žœ žœžœ˜2K˜—K˜š  œ˜+Kš žœ žœžœžœΟs™Fš œžœ žœ˜"Kšœžœ˜6Kšžœ˜K˜—š  œžœžœžœ˜ Kšœžœ  œ ˜0—š œžœžœžœ˜+Kšž˜Kšœ žœžœ˜š  œžœžœžœ˜(Kšž˜Kšœ žœ˜K˜šžœ ž˜Kš œžœžœžœžœ˜6—Kšžœžœžœžœ˜Kš œžœ žœžœžœ ˜2Kšžœžœžœžœ˜'Kšžœžœ!žœžœ˜BK˜Kš žœžœžœžœžœ˜NK˜Kšœ˜—š   œžœ žœžœžœ˜9Kšžœžœžœžœ ˜2Kšœžœ˜Kšœ˜—š   œžœ žœžœžœ˜:Kšžœžœžœžœ ˜2Kšœžœ˜Kšœ˜—š   œžœ žœžœžœ˜9Kšžœžœžœžœ ˜1Kšžœžœ(žœžœ˜IKšœžœ˜Kšœ˜—š   œžœ žœžœžœ˜:Kšžœžœžœžœ ˜2Kšžœžœ(žœžœ˜IKšœžœ˜Kšœ˜—š  œžœ žœžœžœ˜?Kšžœžœžœžœ ˜2Kšœžœžœ˜Kšœ˜—š   œžœ žœžœžœ˜>šž˜Kšœžœ ˜Kšžœžœžœžœ˜!Kšžœ˜—Kšœ˜—š   œžœ žœ žœžœžœ˜GKšœ žœ˜Kšœžœžœ˜Kš œ žœ žœžœ žœ˜7šžœ)ž˜/Kšž˜Kšœ˜K˜Kšžœ˜—šžœžœ˜Kšžœžœ ˜Kšœ˜—Kšœ˜—š  œžœ žœžœžœ˜@šž˜Kšœ˜Kšžœžœžœžœ˜!Kšžœ˜—Kšœ˜—š   œžœ žœžœžœ˜