MODULEDefault methods returning NIL; IMPORT Text, SynWr, SynLocation, Fmt, SynScan, TextRefTbl; REVEAL T = TPublic BRANDED "SynParse.T" OBJECT sc: SynScan.T; env: GrammarEnv; failedName: TEXT; OVERRIDES Grammar:=GetGrammarEnv; Scanner:=GetScanner; ReadNonTerminal:=ReadNonTerminal; Read:=Read; Lookup:=Lookup; Add:=Add; Extend:=Extend; ExtendIter:=ExtendIter; END; Grammar = Tree BRANDED "Grammar" OBJECT END ; GrammarEnvRoot = BRANDED "GrammarEnvRoot" OBJECT table: TextRefTbl.T; END; TYPE ParGram = BRANDED OBJECT grammar : Grammar; args: Args ; END; PROCEDURE SynParse Setup () = BEGIN noArgs := NEW(REF ARRAY OF INTEGER,0); END Setup; VAR setupDone := FALSE; PROCEDUREPackageSetup () = BEGIN IF NOT setupDone THEN setupDone := TRUE; SynLocation.PackageSetup(); SynScan.Setup(); Setup(); END; END PackageSetup; PROCEDURENew (swr: SynWr.T; env: GrammarEnv; stackSize: CARDINAL := 10240): T = BEGIN RETURN NEW(T, stack := NEW(REF ARRAY OF Tree, stackSize), sc := SynScan.New(swr), env:=env, failedName := ""); END New; PROCEDUREMsg (p: T; msg: TEXT) = VAR swr: SynWr.T; BEGIN swr := SynScan.GetWriter(p.sc); IF NOT Text.Empty(msg) THEN SynWr.Text(swr, msg); SynWr.Char(swr, '\n'); SynWr.Flush(swr); END; END Msg; PROCEDUREFault (p: T; msg: TEXT) RAISES {Fail} = BEGIN Msg(p, msg); RAISE Fail; END Fault;
PROCEDUREBuildNoAction (<*UNUSED*>self: Action; <*UNUSED*>g: T; <*UNUSED*>base: INTEGER; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoAction; PROCEDUREBuildNoGivenKeyword (<*UNUSED*>self: GivenKeyword; <*UNUSED*>g: T; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoGivenKeyword; PROCEDUREBuildNoGivenIdentifier (<*UNUSED*>self: GivenIdentifier; <*UNUSED*>g: T; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoGivenIdentifier; PROCEDUREBuildNoGivenName (<*UNUSED*>self: GivenName; <*UNUSED*>g: T; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoGivenName; PROCEDUREBuildNoGivenDelimiter (<*UNUSED*>self: GivenDelimiter; <*UNUSED*>g: T; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoGivenDelimiter; PROCEDUREBuildNoIdentifier (<*UNUSED*>self: Identifier; <*UNUSED*>g: T; <*UNUSED*>name: TEXT; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoIdentifier; PROCEDUREBuildNoName (<*UNUSED*>self: Name; <*UNUSED*>g: T; <*UNUSED*>name: TEXT; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoName; PROCEDUREBuildNoQuotedChar (<*UNUSED*>self: QuotedChar; <*UNUSED*>g: T; <*UNUSED*>char: CHAR; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoQuotedChar; PROCEDUREBuildNoInteger (<*UNUSED*>self: Integer; <*UNUSED*>g: T; <*UNUSED*>int: INTEGER; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoInteger; PROCEDUREBuildNoReal (<*UNUSED*>self: Real; <*UNUSED*>g: T; <*UNUSED*>real: LONGREAL; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoReal; PROCEDUREBuildNoQuotedString (<*UNUSED*>self: QuotedString; <*UNUSED*>g: T; <*UNUSED*>string: TEXT; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoQuotedString; PROCEDUREBuildNoEof (<*UNUSED*>self: Eof; <*UNUSED*>g: T; <*UNUSED*>READONLY info: SynLocation.Info): Tree = BEGIN RETURN NIL END BuildNoEof; PROCEDUREGetScanner (g: T): SynScan.T = BEGIN RETURN g.sc END GetScanner; PROCEDUREGetGrammarEnv (g: T): GrammarEnv = BEGIN RETURN g.env END GetGrammarEnv; PROCEDUREReadNonTerminal (g: T; named: TEXT) : Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR args: Args; BEGIN RETURN g.Read(g.Lookup(named, (*out*) args)); (* -- should have zero arguments. *) END ReadNonTerminal; PROCEDURERead (g: T; gram: Grammar; base: INTEGER:=0) : Tree RAISES {Fail, SynScan.NoReader} = VAR max: INTEGER; tree: Tree; failed: Grammar; BEGIN max:=0; tree:=Read1(g, gram, base, (*in-out*)max, (*out*)failed); IF failed#NIL THEN Reset(g, base+max); Error(g, failed); SynScan.SyntaxMsg(g.sc); RAISE Fail; END; RETURN tree; END Read; (* To be called when Read fails to reset the parse state without giving an error message. Set stackLevel=base+max, for the base given to, and the max returned by, Read. *) PROCEDUREReset (g: T; stackLevel: INTEGER) = BEGIN FOR i:=0 TO stackLevel DO g.stack[i]:=NIL END; END Reset; (* To be called when Read fails, to give an error message. Should be followed by SynScan.SyntaxMsg(); RAISE Fail. *) PROCEDUREError (g: T; failed: Grammar) = VAR info: SynLocation.Info; swr: SynWr.T; BEGIN swr := SynScan.GetWriter(g.sc); SynScan.CurrentLocationInfo(g.sc, (*out*)info); SynWr.Text(swr, "Parsing " & g.failedName & " ", loud:=TRUE); SynLocation.PrintLocation(swr, failed.location); SynWr.Char(swr, '\n', loud:=TRUE); SynWr.Flush(swr, loud:=TRUE); END Error; PROCEDURENewEnv (): GrammarEnv = BEGIN RETURN NEW(GrammarEnv, table:=NEW(TextRefTbl.Default).init(100)); END NewEnv; PROCEDUREList (item1,item2,item3,item4,item5,item6,item7,item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18, item19, item20: Grammar:=NIL; rest: GrammarList:=NIL): GrammarList = VAR list: GrammarList; BEGIN list:=rest; IF item20#NIL THEN list:=NEW(GrammarList, first:=item20, rest:=list) END; IF item19#NIL THEN list:=NEW(GrammarList, first:=item19, rest:=list) END; IF item18#NIL THEN list:=NEW(GrammarList, first:=item18, rest:=list) END; IF item17#NIL THEN list:=NEW(GrammarList, first:=item17, rest:=list) END; IF item16#NIL THEN list:=NEW(GrammarList, first:=item16, rest:=list) END; IF item15#NIL THEN list:=NEW(GrammarList, first:=item15, rest:=list) END; IF item14#NIL THEN list:=NEW(GrammarList, first:=item14, rest:=list) END; IF item13#NIL THEN list:=NEW(GrammarList, first:=item13, rest:=list) END; IF item12#NIL THEN list:=NEW(GrammarList, first:=item12, rest:=list) END; IF item11#NIL THEN list:=NEW(GrammarList, first:=item11, rest:=list) END; IF item10#NIL THEN list:=NEW(GrammarList, first:=item10, rest:=list) END; IF item9#NIL THEN list:=NEW(GrammarList, first:=item9, rest:=list) END; IF item8#NIL THEN list:=NEW(GrammarList, first:=item8, rest:=list) END; IF item7#NIL THEN list:=NEW(GrammarList, first:=item7, rest:=list) END; IF item6#NIL THEN list:=NEW(GrammarList, first:=item6, rest:=list) END; IF item5#NIL THEN list:=NEW(GrammarList, first:=item5, rest:=list) END; IF item4#NIL THEN list:=NEW(GrammarList, first:=item4, rest:=list) END; IF item3#NIL THEN list:=NEW(GrammarList, first:=item3, rest:=list) END; IF item2#NIL THEN list:=NEW(GrammarList, first:=item2, rest:=list) END; IF item1#NIL THEN list:=NEW(GrammarList, first:=item1, rest:=list) END; RETURN list; END List; PROCEDUREStore (position: INTEGER; grammar: Grammar): Grammar = BEGIN RETURN NEW(Storage, item:=grammar, position:=position); END Store; PROCEDUREVerifyArgs (g: T; args1,args2: Args; name: TEXT) RAISES {Fail}= BEGIN IF NUMBER(args1^) # NUMBER(args2^) THEN SynScan.SyntaxMsg(g.sc, "Bad number of arguments: "&name); RAISE Fail; END; FOR i:= 0 TO NUMBER(args1^)-1 DO IF args1^[i] # args2^[i] THEN SynScan.SyntaxMsg(g.sc, "Arguments number "&Fmt.Int(i)&" differ: "&name); RAISE Fail; END; END; END VerifyArgs; PROCEDURELookup (g: T; name: TEXT; VAR (*out*) args: Args): Grammar RAISES {Fail}= VAR value : REFANY; BEGIN IF NOT g.env.table.get(name, (*out*) value) THEN SynScan.SyntaxMsg(g.sc, "Unbound non-terminal: "&name); RAISE Fail; END; TYPECASE value OF | NULL => SynScan.SyntaxMsg(g.sc, "Non-Terminal bound to Nil object: "&name); RAISE Fail; | ParGram(node) => args := node.args; RETURN node.grammar ; ELSE SynScan.SyntaxMsg(g.sc, "Non-Terminal not bound to ParGram object: "&name); RAISE Fail; END; END Lookup; PROCEDUREAdd (g: T; name: TEXT; grammar: Grammar; args: Args := NIL) RAISES {Fail} = VAR value: REFANY; newParGram: ParGram; BEGIN IF args = NIL THEN args := noArgs END; IF g.env.table.get(name, (*VAR OUT*) value) THEN SynScan.SyntaxMsg(g.sc, "Duplicated non-terminal: "&name); RAISE Fail; END; newParGram := NEW(ParGram, grammar := grammar, args := args); EVAL g.env.table.put(name, newParGram); END Add; PROCEDUREExtend (g: T; name: TEXT; grammar: Grammar; args: Args := NIL) RAISES {Fail} = VAR args2: Args; grammar2: Grammar; BEGIN IF args = NIL THEN args := noArgs END; grammar2 := g.Lookup(name,args2); VerifyArgs(g, args ,args2, name); TYPECASE grammar2 OF | Choice(node) => IF node.choice=NIL THEN RETURN END ELSE END; EVAL g.env.table.put( name, NEW(ParGram, args := args2 , grammar := NEW(Choice, choice:= NEW(GrammarList, first:=grammar2, rest:= NEW(GrammarList, first:=grammar, rest:= NIL))))); END Extend; PROCEDUREExtendIter (g: T; name: TEXT; iterPosPresent: BOOLEAN; iterPos: INTEGER; grammar: Grammar; args: Args := NIL) RAISES {Fail} = VAR args2: Args; BEGIN IF args = NIL THEN args := noArgs END; TYPECASE g.Lookup(name,args2) OF | Iter(node) => VerifyArgs(g, args, args2, name); IF iterPosPresent AND (iterPos#node.accumPosition) THEN SynScan.SyntaxMsg(g.sc, "Does not mach iteration position: _" & Fmt.Int(iterPos)); RAISE Fail; END; node.iter := NEW(Choice, choice:= NEW(GrammarList, first:=node.iter, rest:= NEW(GrammarList, first:=grammar, rest:= NIL))); ELSE SynScan.SyntaxMsg(g.sc, "Not a grammar iteration: "&name); RAISE Fail; END; END ExtendIter; (* Parse according to the given gram/env. The base should be the current stack level (usually 0); max should be 0. If parsing fails it returns failed#NIL; then Reset should be called, followed by either "SynScan.Reset()" or "Error(failed); SynScan.SyntaxMsg(); RAISE Fail" *) PROCEDURERead1 (g: T; gram: Grammar; base: INTEGER; VAR (*in-out*) max: INTEGER; VAR (*out*) failed: Grammar; name: TEXT:=NIL): Tree RAISES {Fail, SynScan.NoReader} = VAR tree: Tree; BEGIN IF name = NIL THEN TYPECASE( gram ) OF | NonTerminal(node) => name := node.name ; ELSE name := "toplevel"; END; END; TRY (* base is in-out so the stack can be cleaned up properly even on Fail exceptions occurring during parsing. *) tree:=Read0(g, gram, (*in-out*)base, 0, (*in-out*)max, (*out*)failed, name); EXCEPT SynScan.Fail, Fail => Reset(g, base+max); RAISE Fail; END; RETURN tree; END Read1; PROCEDURERead0 (g: T; gram: Grammar; VAR (*in-out*) base: INTEGER; (* Base of the current stack frame *) minWrite: INTEGER; (* Min writable index in the stack frame, for Choose and Iter *) VAR (*in-out*) max: INTEGER; (* Max index used so far in the stack frame *) VAR (*out*) failed: Grammar; name: TEXT:=NIL): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = (* A NIL result means that a client Build did not care about generating a parse grammar. *) BEGIN TYPECASE gram OF | NonTerminal(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR grammar: Grammar; args: Args; tree: Tree; saveBase, saveMax: INTEGER; BEGIN saveBase := base; saveMax := max; INC(base,max); max := 0; (* look up subgrammar *) grammar := g.Lookup(node.name,args); (* check bounds *) IF NUMBER(args^) # NUMBER(node.args^) THEN Fault(g, "Bad argument count calling "&node.name); END; (* copy the arguments *) FOR i:= 0 TO NUMBER(node.args^)-1 DO g.stack[base+args^[i]] := g.stack[saveBase+node.args^[i]]; IF args^[i] > max THEN max := args^[i]+1; END; END; tree := Read0(g, grammar, (*in-out*)base, 0, (*in-out*) max, (*out*) failed, node.name); FOR i:=0 TO max-1 DO g.stack[base+i]:=NIL END; base := saveBase; max := saveMax; IF failed#NIL THEN RETURN NIL; END; RETURN tree; END F; BEGIN RETURN F(); END; | Storage(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR tree: Tree; BEGIN tree := Read0(g, node.item, (*in-out*)base, 0, (*in-out*)max, (*out*)failed, name); IF failed#NIL THEN RETURN NIL END; IF node.position<0 THEN Fault(g, "Invalid index: _" & Fmt.Int(node.position)); END; IF node.position<minWrite THEN Fault(g, "Invalid index: _" & Fmt.Int(node.position) & " is too small to be storeable within this" & " choice or iteration branch"); END; IF g.stack[base+node.position] # NIL THEN Fault(g, "Redefinition of: _" & Fmt.Int(node.position)); END; g.stack[base+node.position] := tree; max := MAX(max, node.position+1); RETURN NIL; END F; BEGIN RETURN F(); END; | Action(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); EVAL Read0(g, node.grammar, (*in-out*)base, 0, (*in-out*)max, (*out*)failed, name); IF failed#NIL THEN RETURN NIL END; RETURN node.Build(node, g, base, (*in*)locInfo); END F; BEGIN RETURN F(); END; | GivenKeyword(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.HaveTokenKey(g.sc, node.key) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, (*in*)locInfo); END F; BEGIN RETURN F(); END; | GivenIdentifier(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.HaveTokenIde(g.sc, node.ide) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, (*in*)locInfo); END F; BEGIN RETURN F(); END; | GivenName(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.HaveTokenName(g.sc, node.text) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, (*in*)locInfo); END F; BEGIN RETURN F(); END; | GivenDelimiter(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.HaveTokenDelim(g.sc, node.delim) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, (*in*)locInfo); END F; BEGIN RETURN F(); END; | Identifier(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR ide: TEXT; locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.GetTokenIde(g.sc, (*out*)ide) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, ide, (*in*)locInfo); END F; BEGIN RETURN F(); END; | Name(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR text: TEXT; locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.GetTokenName(g.sc, (*out*)text) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, text, (*in*)locInfo); END F; BEGIN RETURN F(); END; | Eof(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.GetTokenEof(g.sc) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, (*in*) locInfo); END F; BEGIN RETURN F(); END; | QuotedChar(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR char: CHAR; locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.GetTokenChar(g.sc, (*out*)char) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, char, (*in*)locInfo); END F; BEGIN RETURN F(); END; | Integer(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR int: INTEGER; locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.GetTokenInt(g.sc, (*out*)int) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, int, (*in*)locInfo); END F; BEGIN RETURN F(); END; | Real(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR real: LONGREAL; locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.GetTokenReal(g.sc, (*out*)real) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, real, (*in*)locInfo); END F; BEGIN RETURN F(); END; | QuotedString(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR string: TEXT; locInfo: SynLocation.Info; BEGIN SynScan.CurrentLocationInfo(g.sc, (*out*)locInfo); IF SynScan.GetTokenString(g.sc, (*out*)string) THEN failed:=NIL ELSE failed:=gram; g.failedName:=name; RETURN NIL; END; RETURN node.Build(node, g, string, (*in*)locInfo); END F; BEGIN RETURN F(); END; | Sequence(node) => PROCEDURE F() RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR gramList: GrammarList; BEGIN gramList := node.items; failed := NIL; LOOP IF gramList=NIL THEN EXIT END; EVAL Read0(g, gramList.first, (*in-out*)base, 0, (*in-out*)max, (*out*)failed, name); IF failed#NIL THEN EXIT END; gramList := gramList.rest; END; END F; BEGIN F(); RETURN NIL; END; | Choice(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR tree: Tree; list: GrammarList; scanPoint: INTEGER; saveMax: INTEGER; BEGIN list := node.choice; saveMax := max; LOOP IF list=NIL THEN failed := gram; g.failedName:=name; RETURN NIL; END; scanPoint := SynScan.ScanPoint(g.sc); tree := Read0(g, list.first, (*in-out*) base, saveMax, (*in-out*) max, (*out*) failed, name); FOR i:=saveMax TO max-1 DO g.stack[base+i]:=NIL END; max := saveMax; IF failed=NIL THEN RETURN tree END; IF failed#NIL AND scanPoint#SynScan.ScanPoint(g.sc) THEN RETURN NIL END; list := list.rest; END; END F; BEGIN RETURN F(); END; | Iter(node) => PROCEDURE F(): Tree RAISES {Fail, SynScan.Fail, SynScan.NoReader} = VAR tree: Tree; scanPoint: INTEGER; saveMax: INTEGER; BEGIN tree := Read0(g, node.base, (*in-out*)base, 0, (*in-out*)max, (*out*) failed, name); IF failed#NIL THEN RETURN NIL END; IF node.accum THEN IF node.accumPosition<0 THEN Fault(g, "Invalid index: _" & Fmt.Int(node.accumPosition)); END; IF node.accumPosition<minWrite THEN Fault(g, "Invalid index: _" & Fmt.Int(node.accumPosition) & " is too small to be storeable within this" & " choice or iteration branch"); END; g.stack[base+node.accumPosition] := tree; max := MAX(max, node.accumPosition+1); END; saveMax := max; LOOP scanPoint := SynScan.ScanPoint(g.sc); tree := Read0(g, node.iter, (*in-out*)base, saveMax, (*in-out*)max, (*out*)failed, name); FOR i:=saveMax TO max-1 DO g.stack[base+i]:=NIL END; max := saveMax; IF failed#NIL AND scanPoint#SynScan.ScanPoint(g.sc) THEN RETURN NIL END; IF failed#NIL THEN failed:=NIL; IF node.accum THEN RETURN g.stack[base+node.accumPosition]; ELSE RETURN NIL; END; END; IF node.accum THEN g.stack[base+node.accumPosition] := tree; END; END; END F; BEGIN RETURN F(); END; ELSE Fault(g, "SynParse.Read0"); <*ASSERT FALSE*> END; END Read0; BEGIN END SynParse.
UndoAdd(name: TEXT) RAISES {Fail}; (* Remove a definition, and give an error if not found.
PROCEDURE UndoAdd(g: T; name: TEXT) RAISES {Fail} = VAR value: REFANY; BEGIN IF NOT g.env.table.delete(name, (*VAR OUT*) value) THEN SynScan.ErrorMsg(g.sc, "GrammarEnv.UndoAdd: could not find: "&name); RAISE Fail; END; END UndoAdd; UndoExtend(name: TEXT; grammar: Grammar) RAISES {Fail}; (* Undo an extension, or give an error if not possible. *) PROCEDURE UndoExtend(g: T; name: TEXT; grammar: Grammar) RAISES {Fail} = VAR args: Args; BEGIN TYPECASE grammar OF | Choice(node) => IF node.choice=NIL THEN RETURN END ELSE END; TYPECASE g.Lookup(name,args) OF | Choice(node) => IF grammar # node.choice.rest.first THEN SynScan.ErrorMsg(g.sc, "GrammarEnv.UndoExtend: bad undo: "&name); RAISE Fail; END; EVAL g.env.table.put(name, NEW(ParGram, args := args, grammar := node.choice.first)); ELSE SynScan.ErrorMsg(g.sc, "GrammarEnv.UndoExtend failed: "&name); RAISE Fail; END; END UndoExtend; UndoExtendIter(name: TEXT; grammar: Grammar) RAISES {Fail}; (* Undo an Iter extension, or give anerror if not possible. *) PROCEDURE UndoExtendIter(g: T; name: TEXT; grammar: Grammar) RAISES {Fail} = VAR args: Args; BEGIN TYPECASE g.Lookup(name,args) OF | Iter(iterNode) => TYPECASE iterNode.iter OF | Choice(choiceNode) => IF grammar # choiceNode.choice.rest.first THEN SynScan.ErrorMsg(g.sc, "GrammarEnv.UndoExtendIter: bad undo: "&name); RAISE Fail; END; iterNode.iter:=choiceNode.choice.first; ELSE SynScan.ErrorMsg(g.sc, "GrammarEnv.UndoExtendIter failed: "&name); RAISE Fail; END; ELSE SynScan.ErrorMsg(g.sc, "GrammarEnv.UndoExtendIter failed: "&name); RAISE Fail; END; END UndoExtendIter; *)