MODULE; IMPORT PaintOp, GraphVBT, View, ZeusPanel, Text, R2; IMPORT Parse, ParseViewClass, ParseColor, Thread; TYPE T = ParseViewClass.T OBJECT graph : GraphVBT.T; vertices : REF ARRAY OF GraphVBT.Vertex; state : Parse.State; length : INTEGER; cursor : INTEGER; font : GraphVBT.WorldFont; OVERRIDES oeSetup := Setup; oeScan := Scan; oeNoteError := NoteError END; CONST V_Pos = 0.5; PROCEDURE V_Input Setup (t: T; s: Parse.State) RAISES {Thread.Alerted} = VAR n_chars : INTEGER; v : REF ARRAY OF GraphVBT.Vertex; used : INTEGER; len : INTEGER; scale : REAL; h_pos : REAL; max_tok : INTEGER; BEGIN (* compute the total # of characters of input *) n_chars := 1; (* the terminal space *) max_tok := 1; FOR i := 0 TO s.n_tokens-1 DO (*@@ INC (n_chars, Text.Length (s.tokens[i])); @@*) max_tok := MAX (max_tok, Text.Length (s.tokens[i])); (*@@*) END; INC (max_tok); (* leave a little breathing room *) n_chars := (max_tok+1) * (s.n_tokens+1); (*@@*) (* initialize the view *) t.state := s; t.length := n_chars; t.cursor := 0; (* remove any old vertices from graph *) v := t.vertices; IF v # NIL THEN LOCK t.graph.mu DO FOR i := FIRST (v^) TO LAST (v^) DO v[ i ].remove() END END END; (* add the new vertices *) t.vertices := NEW (REF ARRAY OF GraphVBT.Vertex, s.n_tokens + 1); FOR i := 0 TO s.n_tokens - 1 DO t.vertices[i] := NewVertex (t, s.tokens[i], max_tok, ParseColor.Virgin); END; (* add an error node *) t.vertices[s.n_tokens] := NewVertex (t, " ", max_tok, ParseColor.Clear); (* display all vertices in one place *) t.graph.redisplay (); (* move vertices to correct positions via animation *) LOCK t.graph.mu DO used := 0; scale := 1.0 / FLOAT (n_chars + 1); FOR i := 0 TO s.n_tokens DO (*@@ IF (i < s.n_tokens) THEN len := Text.Length (s.tokens[i]); ELSE len := 1; END; @@*) len := max_tok + 1; h_pos := (FLOAT (used) + 0.5 * FLOAT (len) + 0.5) * scale; t.vertices[i].move (R2.T { h_pos, V_Pos }, TRUE); INC (used, len); END; END; (* and display the final result *) t.graph.animate (0.0, 1.0); END Setup; PROCEDURENewVertex (t: T; label: TEXT; len: INTEGER; c: PaintOp.T): GraphVBT.Vertex = VAR nodeSize := R2.T { FLOAT (len) / FLOAT (t.length + 2), 0.5 }; BEGIN RETURN NEW (GraphVBT.Vertex, graph := t.graph, shape := GraphVBT.VertexShape.Rectangle, pos := R2.T { 0.0, V_Pos }, size := nodeSize, color := c, label := label, font := t.font ).init() END NewVertex; PROCEDUREScan (t: T; <*UNUSED*> token: TEXT) = VAR n := t.cursor; BEGIN LOCK t.graph.mu DO IF (n > 0) THEN t.vertices[n - 1].setColor (ParseColor.Accepted) END; IF (n < t.state.n_tokens) THEN t.vertices[n].setColor (ParseColor.Current); END; END; INC (t.cursor); t.graph.redisplay (); END Scan; PROCEDURENoteError (t: T) = BEGIN LOCK t.graph.mu DO t.vertices [t.cursor].setColor (ParseColor.Error); END; t.graph.redisplay (); END NoteError; PROCEDURENewInput (): View.T = VAR g := NEW (GraphVBT.T).init (); BEGIN RETURN NEW (T, graph := g, font := g.font(size := 0.03)).init (g); END NewInput; BEGIN ZeusPanel.RegisterView (NewInput, "input stream", "Parse"); END V_Input.