MODULE; IMPORT Algorithm, Thread, ZeusPanel, ZeusCodeView, RefList; IMPORT Parse, ParseIE, ParseAlgClass, Token; TYPE T = ParseAlgClass.T BRANDED OBJECT state : Parse.State; input : REF ARRAY OF Token.T; tok : Token.T; cursor : INTEGER; next_id: INTEGER; OVERRIDES run := Run; END; EXCEPTION SyntaxError; PROCEDURE A_RecDescent Run (t: T) RAISES {Thread.Alerted} = BEGIN t.state := Parse.Init (t.data); t.input := t.state.input; t.cursor := 0; t.next_id := t.state.n_tokens + 1; ParseIE.Setup (t, t.state); PEnter (t, "Parse"); TRY At(t, 1); Scan (t); (* prime the input stream *) At(t, 2); Program (t); EXCEPT SyntaxError => ParseIE.NoteError (t); END; PExit (t); END Run; PROCEDUREProgram (t: T) RAISES {Thread.Alerted, SyntaxError} = VAR self := t.next_id; BEGIN INC (t.next_id); PEnter (t, "Program"); ParseIE.NewNode (t, self, "<program>"); ParseIE.UpdateDone (t); ParseIE.Push (t, self, "<program>"); LOOP At (t, 1); Stmt (t, self); At (t, 2); IF (t.tok # Token.T.Semi) THEN EXIT END; At (t, 3); Match (t, Token.T.Semi, self); END; At (t, 4); Match (t, Token.T.EOF, self); ParseIE.Pop (t, self); PExit (t); END Program; PROCEDUREStmt (t: T; parent: INTEGER) RAISES {Thread.Alerted, SyntaxError} = VAR self := t.next_id; BEGIN INC (t.next_id); PEnter (t, "Stmt"); ParseIE.NewNode (t, self, "<stmt>"); ParseIE.NewEdge (t, self, parent); ParseIE.UpdateDone (t); ParseIE.Push (t, self, "<stmt>"); At (t, 1); Match (t, Token.T.Id, self); At (t, 2); Match (t, Token.T.Assign, self); At (t, 3); Expr (t, self); ParseIE.Pop (t, self); PExit (t); END Stmt; PROCEDUREExpr (t: T; parent: INTEGER) RAISES {Thread.Alerted, SyntaxError} = VAR self := t.next_id; BEGIN INC (t.next_id); PEnter (t, "Expr"); ParseIE.NewNode (t, self, "<expr>"); ParseIE.NewEdge (t, self, parent); ParseIE.UpdateDone (t); ParseIE.Push (t, self, "<expr>"); At (t, 1); Term (t, self); At (t, 2); WHILE (t.tok = Token.T.Plus) DO At (t, 3); Match (t, Token.T.Plus, self); At (t, 4); Term (t, self); END; At (t, 2); ParseIE.Pop (t, self); PExit (t); END Expr; PROCEDURETerm (t: T; parent: INTEGER) RAISES {Thread.Alerted, SyntaxError} = VAR self := t.next_id; BEGIN INC (t.next_id); PEnter (t, "Term"); ParseIE.NewNode (t, self, "<term>"); ParseIE.NewEdge (t, self, parent); ParseIE.UpdateDone (t); ParseIE.Push (t, self, "<term>"); At (t, 1); Factor (t, self); At (t, 2); WHILE (t.tok = Token.T.Star) DO At (t, 3); Match (t, Token.T.Star, self); At (t, 4); Factor (t, self); END; At (t, 2); ParseIE.Pop (t, self); PExit (t); END Term; PROCEDUREFactor (t: T; parent: INTEGER) RAISES {Thread.Alerted, SyntaxError}= VAR self := t.next_id; BEGIN INC (t.next_id); PEnter (t, "Factor"); ParseIE.NewNode (t, self, "<factor>"); ParseIE.NewEdge (t, self, parent); ParseIE.UpdateDone (t); ParseIE.Push (t, self, "<factor>"); At (t, 1); IF (t.tok = Token.T.LParen) THEN At (t, 4); Match (t, Token.T.LParen, self); At (t, 5); Expr (t, self); At (t, 6); Match (t, Token.T.RParen, self); ELSE At (t, 2); Match (t, Token.T.Id, self); END; ParseIE.Pop (t, self); PExit (t); END Factor; PROCEDUREMatch (t: T; tok: Token.T; parent: INTEGER) RAISES {Thread.Alerted, SyntaxError} = BEGIN IF (t.tok # tok) THEN RAISE SyntaxError END; ParseIE.NewEdge (t, t.cursor-1, parent); ParseIE.UpdateDone (t); Scan (t); END Match; PROCEDUREScan (t: T) RAISES {Thread.Alerted} = VAR x := MIN (t.cursor, t.state.n_tokens-1); BEGIN t.tok := t.state.input [x]; ParseIE.Scan (t, t.state.tokens [x]); INC (t.cursor); END Scan; PROCEDUREAt (t: T; line: INTEGER) RAISES {Thread.Alerted} = BEGIN ZeusCodeView.At (t, line) END At; PROCEDUREPEnter (t: T; proc: TEXT) RAISES {Thread.Alerted} = BEGIN ZeusCodeView.Enter (t, procedureName := proc) END PEnter; PROCEDUREPExit (t: T) RAISES {Thread.Alerted} = BEGIN ZeusCodeView.Exit (t) END PExit; PROCEDURENew (): Algorithm.T = VAR fv := ZeusPanel.NewForm("Parse.fv"); cv := RefList.List1 (RefList.List2 ("code view", "A_RecDescent.code")); BEGIN RETURN NEW (T, data := fv, codeViews := cv).init () END New; BEGIN ZeusPanel.RegisterAlg(New, "recursive descent", "Parse"); END A_RecDescent.