pull apart treeviewer; rename ANTLRParserListener

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9148]
This commit is contained in:
parrt 2011-10-20 19:12:32 -08:00
parent 0dbebf879a
commit 6c104b7724
11 changed files with 361 additions and 319 deletions

View File

@ -32,7 +32,7 @@ package org.antlr.v4.runtime;
import com.sun.istack.internal.Nullable; import com.sun.istack.internal.Nullable;
/** How to emit recognition errors */ /** How to emit recognition errors */
public interface ANTLRParserListener { public interface ANTLRErrorListener {
/** Upon syntax error, notify any interested parties. This is not how to /** Upon syntax error, notify any interested parties. This is not how to
* recover from errors or compute error messages. The parser * recover from errors or compute error messages. The parser
* ANTLRErrorStrategy specifies how to recover from syntax errors * ANTLRErrorStrategy specifies how to recover from syntax errors

View File

@ -29,14 +29,10 @@
package org.antlr.v4.runtime; package org.antlr.v4.runtime;
import com.sun.istack.internal.Nullable; import com.sun.istack.internal.Nullable;
import org.antlr.v4.runtime.atn.ATNConfig; import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.atn.ParserATNSimulator; import org.antlr.v4.runtime.misc.*;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.runtime.misc.OrderedHashSet;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Set;
/** A generic recognizer that can handle recognizers generated from /** A generic recognizer that can handle recognizers generated from
* parser and tree grammars. This is all the parsing * parser and tree grammars. This is all the parsing
@ -163,17 +159,22 @@ public abstract class BaseRecognizer extends Recognizer<ParserATNSimulator> {
int line = offendingToken.getLine(); int line = offendingToken.getLine();
int charPositionInLine = offendingToken.getCharPositionInLine(); int charPositionInLine = offendingToken.getCharPositionInLine();
if ( _listeners==null || _listeners.size()==0 ) { if ( _listeners==null || _listeners.size()==0 ) {
emitErrorMessage("line "+line+":"+charPositionInLine+" "+msg); System.err.println("line "+line+":"+charPositionInLine+" "+msg);
return; return;
} }
for (ANTLRParserListener pl : _listeners) { for (ANTLRErrorListener pl : _listeners) {
pl.error(this, offendingToken, line, charPositionInLine, msg, e); pl.error(this, offendingToken, line, charPositionInLine, msg, e);
} }
} }
public void enterOuterAlt(ParserRuleContext localctx, int altNum) { public void enterOuterAlt(ParserRuleContext localctx, int altNum) {
// if we have new localctx, make sure we add to parse tree // if we have new localctx, make sure we replace existing ctx
if ( buildParseTrees && _ctx != localctx ) addContextToParseTree(); // that is previous child of parse tree
if ( buildParseTrees && _ctx != localctx ) {
RuleContext parent = _ctx.parent;
parent.removeLastChild();
if ( parent!=null ) parent.addChild(localctx);
}
_ctx = localctx; _ctx = localctx;
_ctx.altNum = altNum; _ctx.altNum = altNum;
} }
@ -195,7 +196,7 @@ public abstract class BaseRecognizer extends Recognizer<ParserATNSimulator> {
if ( buildParseTrees ) { if ( buildParseTrees ) {
// TODO: tree parsers? // TODO: tree parsers?
if ( _errHandler.inErrorRecoveryMode(this) ) { if ( _errHandler.inErrorRecoveryMode(this) ) {
System.out.println("consume in error recovery mode for "+o); // System.out.println("consume in error recovery mode for "+o);
_ctx.addErrorNode((Token) o); _ctx.addErrorNode((Token) o);
} }
else _ctx.addChild((Token)o); else _ctx.addChild((Token)o);

View File

@ -1,8 +1,6 @@
package org.antlr.v4.runtime; package org.antlr.v4.runtime;
import org.antlr.v4.runtime.atn.ATN; import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.atn.RuleTransition;
import org.antlr.v4.runtime.misc.IntervalSet; import org.antlr.v4.runtime.misc.IntervalSet;
/** This is the default error handling mechanism for ANTLR parsers /** This is the default error handling mechanism for ANTLR parsers
@ -50,8 +48,8 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
// if we've already reported an error and have not matched a token // if we've already reported an error and have not matched a token
// yet successfully, don't report any errors. // yet successfully, don't report any errors.
if (errorRecoveryMode) { if (errorRecoveryMode) {
System.err.print("[SPURIOUS] "); // System.err.print("[SPURIOUS] ");
//return; // don't count spurious errors return; // don't count spurious errors
} }
recognizer.syntaxErrors++; recognizer.syntaxErrors++;
beginErrorCondition(recognizer); beginErrorCondition(recognizer);
@ -90,6 +88,7 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
// at least to prevent an infinite loop; this is a failsafe. // at least to prevent an infinite loop; this is a failsafe.
// System.err.println("seen error condition before index="+ // System.err.println("seen error condition before index="+
// lastErrorIndex+", states="+lastErrorStates); // lastErrorIndex+", states="+lastErrorStates);
// System.err.println("FAILSAFE consumes "+recognizer.getTokenNames()[recognizer.getInputStream().LA(1)]);
recognizer.consume(); recognizer.consume();
} }
lastErrorIndex = recognizer.getInputStream().index(); lastErrorIndex = recognizer.getInputStream().index();
@ -426,7 +425,7 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
/** Consume tokens until one matches the given token set */ /** Consume tokens until one matches the given token set */
public void consumeUntil(BaseRecognizer recognizer, IntervalSet set) { public void consumeUntil(BaseRecognizer recognizer, IntervalSet set) {
System.out.println("consumeUntil("+set.toString(recognizer.getTokenNames())+")"); // System.out.println("consumeUntil("+set.toString(recognizer.getTokenNames())+")");
int ttype = recognizer.getInputStream().LA(1); int ttype = recognizer.getInputStream().LA(1);
while (ttype != Token.EOF && !set.contains(ttype) ) { while (ttype != Token.EOF && !set.contains(ttype) ) {
//System.out.println("consume during recover LA(1)="+getTokenNames()[input.LA(1)]); //System.out.println("consume during recover LA(1)="+getTokenNames()[input.LA(1)]);

View File

@ -37,7 +37,7 @@ public class Recognizer<ATNInterpreter> {
public static final int EOF=-1; public static final int EOF=-1;
protected ANTLRErrorStrategy _errHandler = new DefaultANTLRErrorStrategy(); protected ANTLRErrorStrategy _errHandler = new DefaultANTLRErrorStrategy();
protected List<ANTLRParserListener> _listeners; protected List<ANTLRErrorListener> _listeners;
protected ATNInterpreter _interp; protected ATNInterpreter _interp;
@ -194,24 +194,19 @@ public class Recognizer<ATNInterpreter> {
return "'"+s+"'"; return "'"+s+"'";
} }
/** Override this method to change where error messages go */ public void addListener(ANTLRErrorListener pl) {
public void emitErrorMessage(String msg) {
System.err.println(msg);
}
public void addListener(ANTLRParserListener pl) {
if ( _listeners ==null ) { if ( _listeners ==null ) {
_listeners = _listeners =
Collections.synchronizedList(new ArrayList<ANTLRParserListener>(2)); Collections.synchronizedList(new ArrayList<ANTLRErrorListener>(2));
} }
if ( pl!=null ) _listeners.add(pl); if ( pl!=null ) _listeners.add(pl);
} }
public void removeListener(ANTLRParserListener pl) { _listeners.remove(pl); } public void removeListener(ANTLRErrorListener pl) { _listeners.remove(pl); }
public void removeListeners() { _listeners.clear(); } public void removeListeners() { _listeners.clear(); }
public List<ANTLRParserListener> getListeners() { return _listeners; } public List<ANTLRErrorListener> getListeners() { return _listeners; }
public ANTLRErrorStrategy getErrHandler() { return _errHandler; } public ANTLRErrorStrategy getErrHandler() { return _errHandler; }

View File

@ -28,15 +28,11 @@
*/ */
package org.antlr.v4.runtime; package org.antlr.v4.runtime;
import org.antlr.v4.runtime.atn.ATN; import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.misc.Interval; import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.Trees;
import java.util.ArrayList; import java.util.*;
import java.util.List;
/** Rules can return start/stop info as well as possible trees and templates. /** Rules can return start/stop info as well as possible trees and templates.
* Each context knows about invoking context and pointer into ATN so we * Each context knows about invoking context and pointer into ATN so we
@ -166,6 +162,16 @@ public class RuleContext implements ParseTree.RuleNode {
children.add(ruleInvocation); children.add(ruleInvocation);
} }
/** Used by enterOuterAlt to toss out a RuleContext previously added as
* we entered a rule. If we have # label, we will need to remove
* generic ruleContext object.
*/
public void removeLastChild() {
if ( children!=null ) {
children.remove(children.size()-1);
}
}
public void trace(int s) { public void trace(int s) {
if ( states==null ) states = new ArrayList<Integer>(); if ( states==null ) states = new ArrayList<Integer>();
states.add(s); states.add(s);

View File

@ -123,7 +123,12 @@ public class ATNState {
transitions.set(i, e); transitions.set(i, e);
} }
public boolean onlyHasEpsilonTransitions() { protected int epsilonOnlyTransitions = -1;
//lexer atn sim: getEpTar: 13.2%
// ruleCtx.equals 10%
public boolean onlyHasEpsilonTransitions() { // 22% time
if ( epsilonOnlyTransitions>=0 ) return epsilonOnlyTransitions==1;
if ( transitions.size()==0 ) return false; if ( transitions.size()==0 ) return false;
for (Transition t : transitions) { for (Transition t : transitions) {
if ( !t.isEpsilon() ) return false; if ( !t.isEpsilon() ) return false;

View File

@ -29,17 +29,13 @@
package org.antlr.v4.runtime.tree; package org.antlr.v4.runtime.tree;
import org.antlr.v4.runtime.BaseRecognizer; import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.Token;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/** A set of utility routines useful for all kinds of ANTLR trees */ /** A set of utility routines useful for all kinds of ANTLR trees */
public class Trees { public class Trees {
/** Print out a whole tree in LISP form. toString is used on the /** Print out a whole tree in LISP form. getNodeText is used on the
* node payloads to get the text for the nodes. Detect * node payloads to get the text for the nodes. Detect
* parse trees and extract data appropriately. * parse trees and extract data appropriately.
*/ */

View File

@ -0,0 +1,164 @@
/*
[The "BSD license"]
Copyright (c) 2011 Terence Parr
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.antlr.v4.runtime.tree.gui;
import org.abego.treelayout.TreeForTreeLayout;
import org.abego.treelayout.util.*;
import org.antlr.v4.runtime.tree.Tree;
import java.util.*;
public class AntlrTreeLayouter {
// TODO: provide public interface to the configuration/nodeExtent
private double gapBetweenLevels = 50;
private double gapBetweenNodes = 10;
private double nodeWidth = 60;
private double nodeHeight = 20;
public TreeViewer.AntlrTreeLayout layout(Tree tree) {
return new TreeViewer.AntlrTreeLayout(new AntlrTreeForTreeLayout(tree),
new FixedNodeExtentProvider<Tree>(nodeWidth, nodeHeight),
// new TreeViewer.VariableExtentProvide<Tree>(),
new DefaultConfiguration<Tree>(gapBetweenLevels,
gapBetweenNodes));
}
private static class AntlrTreeForTreeLayout implements TreeForTreeLayout<Tree> {
private static class AntlrTreeChildrenIterable implements Iterable<Tree> {
private final Tree tree;
public AntlrTreeChildrenIterable(Tree tree) {
this.tree = tree;
}
@Override
public Iterator<Tree> iterator() {
return new Iterator<Tree>() {
private int i = 0;
@Override
public boolean hasNext() {
return tree.getChildCount() > i;
}
@Override
public Tree next() {
if (!hasNext())
throw new NoSuchElementException();
return tree.getChild(i++);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
private static class AntlrTreeChildrenReverseIterable implements
Iterable<Tree>
{
private final Tree tree;
public AntlrTreeChildrenReverseIterable(Tree tree) {
this.tree = tree;
}
@Override
public Iterator<Tree> iterator() {
return new Iterator<Tree>() {
private int i = tree.getChildCount();
@Override
public boolean hasNext() {
return i > 0;
}
@Override
public Tree next() {
if (!hasNext())
throw new NoSuchElementException();
return tree.getChild(--i);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
private Tree root;
public AntlrTreeForTreeLayout(Tree root) {
this.root = root;
}
@Override
public boolean isLeaf(Tree node) {
return node.getChildCount() == 0;
}
@Override
public boolean isChildOfParent(Tree node, Tree parentNode) {
return node.getParent() == parentNode;
}
@Override
public Tree getRoot() {
return root;
}
@Override
public Tree getLastChild(Tree parentNode) {
return (Tree) parentNode
.getChild(parentNode.getChildCount() - 1);
}
@Override
public Tree getFirstChild(Tree parentNode) {
return (Tree) parentNode.getChild(0);
}
@Override
public Iterable<Tree> getChildrenReverse(Tree node) {
return new AntlrTreeChildrenReverseIterable(node);
}
@Override
public Iterable<Tree> getChildren(Tree node) {
return new AntlrTreeChildrenIterable(node);
}
}
}

View File

@ -1,257 +1,14 @@
package org.antlr.v4.runtime.tree.gui; package org.antlr.v4.runtime.tree.gui;
import java.awt.Color; import org.abego.treelayout.*;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import java.util.NoSuchElementException;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JDialog;
import org.abego.treelayout.Configuration;
import org.abego.treelayout.NodeExtentProvider;
import org.abego.treelayout.TreeForTreeLayout;
import org.abego.treelayout.TreeLayout;
import org.abego.treelayout.util.DefaultConfiguration;
import org.abego.treelayout.util.FixedNodeExtentProvider;
import org.antlr.v4.runtime.tree.Tree; import org.antlr.v4.runtime.tree.Tree;
public class TreeViewer { import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
// ---------------------------------------------------------------------- public class TreeViewer extends JComponent {
private Font font = new Font(Font.MONOSPACED, Font.PLAIN, 12);
private static class AntlrTreeLayout extends TreeLayout<Tree> {
public AntlrTreeLayout(TreeForTreeLayout<Tree> tree,
NodeExtentProvider<Tree> nodeExtentProvider,
Configuration<Tree> configuration) {
super(tree, nodeExtentProvider, configuration);
}
}
// ----------------------------------------------------------------------
private static class AntlrTreeLayouter {
// TODO: provide public interface to the configuration/nodeExtent
private double gapBetweenLevels = 50;
private double gapBetweenNodes = 10;
private double nodeWidth = 60;
private double nodeHeight = 20;
public AntlrTreeLayout layout(Tree tree) {
return new AntlrTreeLayout(new AntlrTreeForTreeLayout(tree),
new FixedNodeExtentProvider<Tree>(nodeWidth, nodeHeight),
new DefaultConfiguration<Tree>(gapBetweenLevels,
gapBetweenNodes));
}
private static class AntlrTreeForTreeLayout implements
TreeForTreeLayout<Tree> {
private static class AntlrTreeChildrenIterable implements
Iterable<Tree> {
private final Tree tree;
public AntlrTreeChildrenIterable(Tree tree) {
this.tree = tree;
}
@Override
public Iterator<Tree> iterator() {
return new Iterator<Tree>() {
private int i = 0;
@Override
public boolean hasNext() {
return tree.getChildCount() > i;
}
@Override
public Tree next() {
if (!hasNext())
throw new NoSuchElementException();
return tree.getChild(i++);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
private static class AntlrTreeChildrenReverseIterable implements
Iterable<Tree> {
private final Tree tree;
public AntlrTreeChildrenReverseIterable(Tree tree) {
this.tree = tree;
}
@Override
public Iterator<Tree> iterator() {
return new Iterator<Tree>() {
private int i = tree.getChildCount();
@Override
public boolean hasNext() {
return i > 0;
}
@Override
public Tree next() {
if (!hasNext())
throw new NoSuchElementException();
return tree.getChild(--i);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
private Tree root;
public AntlrTreeForTreeLayout(Tree root) {
this.root = root;
}
@Override
public boolean isLeaf(Tree node) {
return node.getChildCount() == 0;
}
@Override
public boolean isChildOfParent(Tree node, Tree parentNode) {
return node.getParent() == parentNode;
}
@Override
public Tree getRoot() {
return root;
}
@Override
public Tree getLastChild(Tree parentNode) {
return (Tree) parentNode
.getChild(parentNode.getChildCount() - 1);
}
@Override
public Tree getFirstChild(Tree parentNode) {
return (Tree) parentNode.getChild(0);
}
@Override
public Iterable<Tree> getChildrenReverse(Tree node) {
return new AntlrTreeChildrenReverseIterable(node);
}
@Override
public Iterable<Tree> getChildren(Tree node) {
return new AntlrTreeChildrenIterable(node);
}
}
}
// ----------------------------------------------------------------------
private class AntlrTreePane extends JComponent {
private final AntlrTreeLayout treeLayout;
private TreeForTreeLayout<Tree> getTree() {
return treeLayout.getTree();
}
private Iterable<Tree> getChildren(Tree parent) {
return getTree().getChildren(parent);
}
private Rectangle2D.Double getBoundsOfNode(Tree node) {
return treeLayout.getNodeBounds().get(node);
}
private String getText(Tree tree) {
return treeTextProvider.getText(tree);
}
/**
* Specifies the tree to be displayed by passing in a {@link TreeLayout}
* for that tree.
*
* @param treeLayout
*/
public AntlrTreePane(AntlrTreeLayout treeLayout) {
this.treeLayout = treeLayout;
Dimension size = treeLayout.getBounds().getBounds().getSize();
setPreferredSize(size);
}
// -------------------------------------------------------------------
// painting
private void paintEdges(Graphics g, Tree parent) {
if (!getTree().isLeaf(parent)) {
Rectangle2D.Double b1 = getBoundsOfNode(parent);
double x1 = b1.getCenterX();
double y1 = b1.getCenterY();
for (Tree child : getChildren(parent)) {
Rectangle2D.Double b2 = getBoundsOfNode(child);
g.drawLine((int) x1, (int) y1, (int) b2.getCenterX(),
(int) b2.getCenterY());
paintEdges(g, child);
}
}
}
private void paintBox(Graphics g, Tree tree) {
// draw the box in the background
g.setColor(boxColor);
Rectangle2D.Double box = getBoundsOfNode(tree);
g.fillRoundRect((int) box.x, (int) box.y, (int) box.width - 1,
(int) box.height - 1, arcSize, arcSize);
g.setColor(borderColor);
g.drawRoundRect((int) box.x, (int) box.y, (int) box.width - 1,
(int) box.height - 1, arcSize, arcSize);
// draw the text on top of the box (possibly multiple lines)
g.setColor(textColor);
String s = getText(tree);
String[] lines = s.split("\n");
FontMetrics m = getFontMetrics(getFont());
int x = (int) box.x + arcSize / 2;
int y = (int) box.y + m.getAscent() + m.getLeading() + 1;
for (int i = 0; i < lines.length; i++) {
g.drawString(lines[i], x, y);
y += m.getHeight();
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
paintEdges(g, getTree().getRoot());
// paint the boxes
for (Tree Tree : treeLayout.getNodeBounds().keySet()) {
paintBox(g, Tree);
}
}
}
// ----------------------------------------------------------------------
private int arcSize = 10; private int arcSize = 10;
@ -299,6 +56,112 @@ public class TreeViewer {
this.textColor = textColor; this.textColor = textColor;
} }
private TreeViewer.AntlrTreeLayout treeLayout;
private TreeForTreeLayout<Tree> getTree() {
return treeLayout.getTree();
}
private Iterable<Tree> getChildren(Tree parent) {
return getTree().getChildren(parent);
}
private Rectangle2D.Double getBoundsOfNode(Tree node) {
return treeLayout.getNodeBounds().get(node);
}
private String getText(Tree tree) {
return treeTextProvider.getText(tree);
}
public TreeViewer(Tree tree) {
this.treeLayout = layouter.layout(tree);
Dimension size = treeLayout.getBounds().getBounds().getSize();
setPreferredSize(size);
setFont(font);
}
// -------------------------------------------------------------------
// painting
private void paintEdges(Graphics g, Tree parent) {
if (!getTree().isLeaf(parent)) {
Rectangle2D.Double b1 = getBoundsOfNode(parent);
double x1 = b1.getCenterX();
double y1 = b1.getCenterY();
for (Tree child : getChildren(parent)) {
Rectangle2D.Double b2 = getBoundsOfNode(child);
g.drawLine((int) x1, (int) y1, (int) b2.getCenterX(),
(int) b2.getCenterY());
paintEdges(g, child);
}
}
}
private void paintBox(Graphics g, Tree tree) {
// draw the box in the background
g.setColor(boxColor);
Rectangle2D.Double box = getBoundsOfNode(tree);
g.fillRoundRect((int) box.x, (int) box.y, (int) box.width - 1,
(int) box.height - 1, arcSize, arcSize);
g.setColor(borderColor);
g.drawRoundRect((int) box.x, (int) box.y, (int) box.width - 1,
(int) box.height - 1, arcSize, arcSize);
// draw the text on top of the box (possibly multiple lines)
g.setColor(textColor);
String s = getText(tree);
String[] lines = s.split("\n");
FontMetrics m = getFontMetrics(font);
int x = (int) box.x + arcSize / 2;
int y = (int) box.y + m.getAscent() + m.getLeading() + 1;
for (int i = 0; i < lines.length; i++) {
g.drawString(lines[i], x, y);
y += m.getHeight();
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
paintEdges(g, getTree().getRoot());
// paint the boxes
for (Tree Tree : treeLayout.getNodeBounds().keySet()) {
paintBox(g, Tree);
}
}
// ----------------------------------------------------------------------
public static class VariableExtentProvide<Tree> implements NodeExtentProvider<Tree> {
@Override
public double getHeight(Tree tree) {
// FontMetrics m = getFontMetrics(font);
// String text = treeTextProvider.getText(tree);
// int x = (int) box.x + arcSize / 2;
// int y = (int) box.y + m.getAscent() + m.getLeading() + 1;
// int hgt = metrics.getHeight();
// // get the advance of my text in this font and render context
// int adv = metrics.stringWidth(text);
return 0;
}
@Override
public double getWidth(Tree tree) {
return 0;
}
}
public static class AntlrTreeLayout extends TreeLayout<Tree> {
public AntlrTreeLayout(TreeForTreeLayout<Tree> tree,
NodeExtentProvider<Tree> nodeExtentProvider,
Configuration<Tree> configuration) {
super(tree, nodeExtentProvider, configuration);
}
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
private TreeTextProvider treeTextProvider = new DefaultTreeTextProvider(); private TreeTextProvider treeTextProvider = new DefaultTreeTextProvider();
@ -328,10 +191,8 @@ public class TreeViewer {
dialog.setVisible(true); dialog.setVisible(true);
} }
public void open(Tree tree) { public void open() {
AntlrTreeLayout layout = layouter.layout(tree); showInDialog(this);
AntlrTreePane panel = new AntlrTreePane(layout);
showInDialog(panel);
} }
} }

View File

@ -1,13 +1,9 @@
grammar T; grammar T;
s : i=ifstat {System.out.println(_input.toString(0,_input.index()-1));} ; s : i=ifstat {System.out.println(_input.toString(0,_input.index()-1));} ;
ifstat : 'if' {$s::start = null;} '(' INT ')' ID '=' ID ';' # DoIf; ifstat : 'if' '(' expr ')' assign ;
assign : ID '=' expr ';' ;
r[int x] returns [int y] expr : INT | ID ;
locals [int z]
: name=ID # foo
| ID (ID|';'{;}) # bar
;
EQ : '=' ; EQ : '=' ;
INT : '0'..'9'+ ; INT : '0'..'9'+ ;

View File

@ -1,9 +1,23 @@
import org.antlr.v4.runtime.ANTLRFileStream; import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.gui.*;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import java.awt.*;
public class TestT { public class TestT {
public static class MyTreeTextProvider implements TreeTextProvider {
BaseRecognizer parser;
public MyTreeTextProvider(BaseRecognizer parser) {
this.parser = parser;
}
@Override
public String getText(Tree node) {
return String.valueOf(Trees.getNodeText(node, parser));
}
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
TLexer t = new TLexer(new ANTLRFileStream(args[0])); TLexer t = new TLexer(new ANTLRFileStream(args[0]));
CommonTokenStream tokens = new CommonTokenStream(t); CommonTokenStream tokens = new CommonTokenStream(t);
@ -16,16 +30,21 @@ public class TestT {
TParser.sContext tree = p.s(); TParser.sContext tree = p.s();
System.out.println(tree.toStringTree(p)); System.out.println(tree.toStringTree(p));
TreeViewer tv = new TreeViewer(tree);
ParseTreeWalker walker = new ParseTreeWalker(); tv.setTreeTextProvider(new MyTreeTextProvider(p));
TListener listener = new BlankTListener() { tv.setBoxColor(Color.lightGray);
public void enterEveryRule(ParserRuleContext ctx) { tv.setBorderColor(Color.darkGray);
System.out.println("enter rule "+TParser.ruleNames[ctx.ruleIndex]); tv.open();
} //
public void exitRule(TParser.DoIfContext ctx) { // specific to rule ifstat // ParseTreeWalker walker = new ParseTreeWalker();
System.out.println("exit rule ifstat"); // TListener listener = new BlankTListener() {
} // public void enterEveryRule(ParserRuleContext ctx) {
}; // System.out.println("enter rule "+TParser.ruleNames[ctx.ruleIndex]);
walker.walk(listener, tree); // }
// public void exitRule(TParser.DoIfContext ctx) { // specific to rule ifstat
// System.out.println("exit rule ifstat");
// }
// };
// walker.walk(listener, tree);
} }
} }