forked from jasder/antlr
pull apart treeviewer; rename ANTLRParserListener
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9148]
This commit is contained in:
parent
0dbebf879a
commit
6c104b7724
|
@ -32,7 +32,7 @@ package org.antlr.v4.runtime;
|
|||
import com.sun.istack.internal.Nullable;
|
||||
|
||||
/** How to emit recognition errors */
|
||||
public interface ANTLRParserListener {
|
||||
public interface ANTLRErrorListener {
|
||||
/** Upon syntax error, notify any interested parties. This is not how to
|
||||
* recover from errors or compute error messages. The parser
|
||||
* ANTLRErrorStrategy specifies how to recover from syntax errors
|
|
@ -29,14 +29,10 @@
|
|||
package org.antlr.v4.runtime;
|
||||
|
||||
import com.sun.istack.internal.Nullable;
|
||||
import org.antlr.v4.runtime.atn.ATNConfig;
|
||||
import org.antlr.v4.runtime.atn.ParserATNSimulator;
|
||||
import org.antlr.v4.runtime.misc.IntervalSet;
|
||||
import org.antlr.v4.runtime.misc.OrderedHashSet;
|
||||
import org.antlr.v4.runtime.atn.*;
|
||||
import org.antlr.v4.runtime.misc.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/** A generic recognizer that can handle recognizers generated from
|
||||
* 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 charPositionInLine = offendingToken.getCharPositionInLine();
|
||||
if ( _listeners==null || _listeners.size()==0 ) {
|
||||
emitErrorMessage("line "+line+":"+charPositionInLine+" "+msg);
|
||||
System.err.println("line "+line+":"+charPositionInLine+" "+msg);
|
||||
return;
|
||||
}
|
||||
for (ANTLRParserListener pl : _listeners) {
|
||||
for (ANTLRErrorListener pl : _listeners) {
|
||||
pl.error(this, offendingToken, line, charPositionInLine, msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void enterOuterAlt(ParserRuleContext localctx, int altNum) {
|
||||
// if we have new localctx, make sure we add to parse tree
|
||||
if ( buildParseTrees && _ctx != localctx ) addContextToParseTree();
|
||||
// if we have new localctx, make sure we replace existing ctx
|
||||
// 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.altNum = altNum;
|
||||
}
|
||||
|
@ -195,7 +196,7 @@ public abstract class BaseRecognizer extends Recognizer<ParserATNSimulator> {
|
|||
if ( buildParseTrees ) {
|
||||
// TODO: tree parsers?
|
||||
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);
|
||||
}
|
||||
else _ctx.addChild((Token)o);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package org.antlr.v4.runtime;
|
||||
|
||||
import org.antlr.v4.runtime.atn.ATN;
|
||||
import org.antlr.v4.runtime.atn.ATNState;
|
||||
import org.antlr.v4.runtime.atn.RuleTransition;
|
||||
import org.antlr.v4.runtime.atn.*;
|
||||
import org.antlr.v4.runtime.misc.IntervalSet;
|
||||
|
||||
/** 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
|
||||
// yet successfully, don't report any errors.
|
||||
if (errorRecoveryMode) {
|
||||
System.err.print("[SPURIOUS] ");
|
||||
//return; // don't count spurious errors
|
||||
// System.err.print("[SPURIOUS] ");
|
||||
return; // don't count spurious errors
|
||||
}
|
||||
recognizer.syntaxErrors++;
|
||||
beginErrorCondition(recognizer);
|
||||
|
@ -90,6 +88,7 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
|||
// at least to prevent an infinite loop; this is a failsafe.
|
||||
// System.err.println("seen error condition before index="+
|
||||
// lastErrorIndex+", states="+lastErrorStates);
|
||||
// System.err.println("FAILSAFE consumes "+recognizer.getTokenNames()[recognizer.getInputStream().LA(1)]);
|
||||
recognizer.consume();
|
||||
}
|
||||
lastErrorIndex = recognizer.getInputStream().index();
|
||||
|
@ -426,7 +425,7 @@ public class DefaultANTLRErrorStrategy implements ANTLRErrorStrategy {
|
|||
|
||||
/** Consume tokens until one matches the given token 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);
|
||||
while (ttype != Token.EOF && !set.contains(ttype) ) {
|
||||
//System.out.println("consume during recover LA(1)="+getTokenNames()[input.LA(1)]);
|
||||
|
|
|
@ -37,7 +37,7 @@ public class Recognizer<ATNInterpreter> {
|
|||
public static final int EOF=-1;
|
||||
|
||||
protected ANTLRErrorStrategy _errHandler = new DefaultANTLRErrorStrategy();
|
||||
protected List<ANTLRParserListener> _listeners;
|
||||
protected List<ANTLRErrorListener> _listeners;
|
||||
|
||||
protected ATNInterpreter _interp;
|
||||
|
||||
|
@ -194,24 +194,19 @@ public class Recognizer<ATNInterpreter> {
|
|||
return "'"+s+"'";
|
||||
}
|
||||
|
||||
/** Override this method to change where error messages go */
|
||||
public void emitErrorMessage(String msg) {
|
||||
System.err.println(msg);
|
||||
}
|
||||
|
||||
public void addListener(ANTLRParserListener pl) {
|
||||
public void addListener(ANTLRErrorListener pl) {
|
||||
if ( _listeners ==null ) {
|
||||
_listeners =
|
||||
Collections.synchronizedList(new ArrayList<ANTLRParserListener>(2));
|
||||
Collections.synchronizedList(new ArrayList<ANTLRErrorListener>(2));
|
||||
}
|
||||
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 List<ANTLRParserListener> getListeners() { return _listeners; }
|
||||
public List<ANTLRErrorListener> getListeners() { return _listeners; }
|
||||
|
||||
public ANTLRErrorStrategy getErrHandler() { return _errHandler; }
|
||||
|
||||
|
|
|
@ -28,15 +28,11 @@
|
|||
*/
|
||||
package org.antlr.v4.runtime;
|
||||
|
||||
import org.antlr.v4.runtime.atn.ATN;
|
||||
import org.antlr.v4.runtime.atn.ATNState;
|
||||
import org.antlr.v4.runtime.atn.*;
|
||||
import org.antlr.v4.runtime.misc.Interval;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeListener;
|
||||
import org.antlr.v4.runtime.tree.Trees;
|
||||
import org.antlr.v4.runtime.tree.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/** 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
|
||||
|
@ -166,6 +162,16 @@ public class RuleContext implements ParseTree.RuleNode {
|
|||
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) {
|
||||
if ( states==null ) states = new ArrayList<Integer>();
|
||||
states.add(s);
|
||||
|
|
|
@ -123,7 +123,12 @@ public class ATNState {
|
|||
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;
|
||||
for (Transition t : transitions) {
|
||||
if ( !t.isEpsilon() ) return false;
|
||||
|
|
|
@ -29,17 +29,13 @@
|
|||
|
||||
package org.antlr.v4.runtime.tree;
|
||||
|
||||
import org.antlr.v4.runtime.BaseRecognizer;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.*;
|
||||
|
||||
/** A set of utility routines useful for all kinds of ANTLR 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
|
||||
* parse trees and extract data appropriately.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,257 +1,14 @@
|
|||
package org.antlr.v4.runtime.tree.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
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.abego.treelayout.*;
|
||||
import org.antlr.v4.runtime.tree.Tree;
|
||||
|
||||
public class TreeViewer {
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
public class TreeViewer extends JComponent {
|
||||
private Font font = new Font(Font.MONOSPACED, Font.PLAIN, 12);
|
||||
|
||||
private int arcSize = 10;
|
||||
|
||||
|
@ -299,6 +56,112 @@ public class TreeViewer {
|
|||
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();
|
||||
|
@ -328,10 +191,8 @@ public class TreeViewer {
|
|||
dialog.setVisible(true);
|
||||
}
|
||||
|
||||
public void open(Tree tree) {
|
||||
AntlrTreeLayout layout = layouter.layout(tree);
|
||||
AntlrTreePane panel = new AntlrTreePane(layout);
|
||||
showInDialog(panel);
|
||||
public void open() {
|
||||
showInDialog(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
grammar T;
|
||||
s : i=ifstat {System.out.println(_input.toString(0,_input.index()-1));} ;
|
||||
|
||||
ifstat : 'if' {$s::start = null;} '(' INT ')' ID '=' ID ';' # DoIf;
|
||||
|
||||
r[int x] returns [int y]
|
||||
locals [int z]
|
||||
: name=ID # foo
|
||||
| ID (ID|';'{;}) # bar
|
||||
;
|
||||
ifstat : 'if' '(' expr ')' assign ;
|
||||
assign : ID '=' expr ';' ;
|
||||
expr : INT | ID ;
|
||||
|
||||
EQ : '=' ;
|
||||
INT : '0'..'9'+ ;
|
||||
|
|
|
@ -1,9 +1,23 @@
|
|||
import org.antlr.v4.runtime.ANTLRFileStream;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.tree.*;
|
||||
import org.antlr.v4.runtime.tree.gui.*;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
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 {
|
||||
TLexer t = new TLexer(new ANTLRFileStream(args[0]));
|
||||
CommonTokenStream tokens = new CommonTokenStream(t);
|
||||
|
@ -16,16 +30,21 @@ public class TestT {
|
|||
TParser.sContext tree = p.s();
|
||||
|
||||
System.out.println(tree.toStringTree(p));
|
||||
|
||||
ParseTreeWalker walker = new ParseTreeWalker();
|
||||
TListener listener = new BlankTListener() {
|
||||
public void enterEveryRule(ParserRuleContext ctx) {
|
||||
System.out.println("enter rule "+TParser.ruleNames[ctx.ruleIndex]);
|
||||
}
|
||||
public void exitRule(TParser.DoIfContext ctx) { // specific to rule ifstat
|
||||
System.out.println("exit rule ifstat");
|
||||
}
|
||||
};
|
||||
walker.walk(listener, tree);
|
||||
TreeViewer tv = new TreeViewer(tree);
|
||||
tv.setTreeTextProvider(new MyTreeTextProvider(p));
|
||||
tv.setBoxColor(Color.lightGray);
|
||||
tv.setBorderColor(Color.darkGray);
|
||||
tv.open();
|
||||
//
|
||||
// ParseTreeWalker walker = new ParseTreeWalker();
|
||||
// TListener listener = new BlankTListener() {
|
||||
// public void enterEveryRule(ParserRuleContext ctx) {
|
||||
// System.out.println("enter rule "+TParser.ruleNames[ctx.ruleIndex]);
|
||||
// }
|
||||
// public void exitRule(TParser.DoIfContext ctx) { // specific to rule ifstat
|
||||
// System.out.println("exit rule ifstat");
|
||||
// }
|
||||
// };
|
||||
// walker.walk(listener, tree);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue