forked from jasder/antlr
Use two queues instead of a custom linked memory structure
This commit is contained in:
parent
53f2a67b9d
commit
7ca7acd084
|
@ -30,122 +30,74 @@
|
||||||
|
|
||||||
package org.antlr.v4.runtime.tree;
|
package org.antlr.v4.runtime.tree;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.misc.IntegerStack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An iterative (read: non-recursive) pre-order and post-order tree walker that
|
* An iterative (read: non-recursive) pre-order and post-order tree walker that
|
||||||
* doesn't use the thread stack but it's own heap-based stack using linked data
|
* doesn't use the thread stack but heap-based stacks. Makes it possible to
|
||||||
* structures. Makes it possible to process deeply nested parse trees.
|
* process deeply nested parse trees.
|
||||||
*/
|
*/
|
||||||
public class IterativeParseTreeWalker extends ParseTreeWalker {
|
public class IterativeParseTreeWalker extends ParseTreeWalker {
|
||||||
public static final ParseTreeWalker DEFAULT = new IterativeParseTreeWalker();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void walk(final ParseTreeListener listener, final ParseTree t) {
|
public void walk(ParseTreeListener listener, ParseTree t) {
|
||||||
for (WalkerNode<?> currentNode = createNode(null, t, 0); currentNode != null;) {
|
|
||||||
currentNode.enter(listener); // Pre order visit
|
|
||||||
|
|
||||||
// Move down to first child
|
final Deque<ParseTree> nodeStack = new ArrayDeque<ParseTree>();
|
||||||
WalkerNode<?> nextNode = currentNode.getFirstChild();
|
final IntegerStack indexStack = new IntegerStack();
|
||||||
if (nextNode != null) {
|
|
||||||
currentNode = nextNode;
|
ParseTree currentNode = t;
|
||||||
|
int currentIndex = 0;
|
||||||
|
|
||||||
|
while (currentNode != null) {
|
||||||
|
|
||||||
|
// pre-order visit
|
||||||
|
if (currentNode instanceof ErrorNode) {
|
||||||
|
listener.visitErrorNode((ErrorNode) currentNode);
|
||||||
|
} else if (currentNode instanceof TerminalNode) {
|
||||||
|
listener.visitTerminal((TerminalNode) currentNode);
|
||||||
|
} else {
|
||||||
|
final RuleNode r = (RuleNode) currentNode;
|
||||||
|
enterRule(listener, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move down to first child, if exists
|
||||||
|
if (currentNode.getChildCount() > 0) {
|
||||||
|
nodeStack.push(currentNode);
|
||||||
|
indexStack.push(currentIndex);
|
||||||
|
currentIndex = 0;
|
||||||
|
currentNode = currentNode.getChild(0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No child nodes, so walk tree
|
// No child nodes, so walk tree
|
||||||
while (currentNode != null) {
|
do {
|
||||||
currentNode.exit(listener); // Post order visit
|
|
||||||
|
|
||||||
// Move to sibling if possible
|
// post-order visit
|
||||||
nextNode = currentNode.getNextSibling();
|
if (currentNode instanceof RuleNode) {
|
||||||
if (nextNode != null) {
|
exitRule(listener, (RuleNode) currentNode);
|
||||||
currentNode = nextNode;
|
}
|
||||||
|
|
||||||
|
// No parent, so no siblings
|
||||||
|
if (nodeStack.isEmpty()) {
|
||||||
|
currentNode = null;
|
||||||
|
currentIndex = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move up
|
// Move to next sibling if possible
|
||||||
currentNode = currentNode.getParentNode();
|
currentNode = nodeStack.peek().getChild(++currentIndex);
|
||||||
}
|
if (currentNode != null) {
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WalkerNode<?> createNode(final WalkerNode<?> parent, final ParseTree self, final int pos) {
|
// No next, sibling, so move up
|
||||||
if (self instanceof ErrorNode) {
|
currentNode = nodeStack.pop();
|
||||||
return new ErrorWalkerNode(parent, (ErrorNode) self, pos);
|
currentIndex = indexStack.pop();
|
||||||
} else if (self instanceof TerminalNode) {
|
|
||||||
return new TerminalWalkerNode(parent, (TerminalNode) self, pos);
|
|
||||||
} else {
|
|
||||||
return new RuleWalkerNode(parent, (RuleNode) self, pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract class WalkerNode<N extends ParseTree> {
|
} while (currentNode != null);
|
||||||
private final WalkerNode<?> parent;
|
|
||||||
protected final N self;
|
|
||||||
private final int pos;
|
|
||||||
|
|
||||||
protected WalkerNode(final WalkerNode<?> parent, final N self, final int pos) {
|
|
||||||
this.parent = parent;
|
|
||||||
this.self = self;
|
|
||||||
this.pos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WalkerNode<?> getFirstChild() {
|
|
||||||
return self.getChildCount() > 0 ? createChildNode(0) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WalkerNode<?> getNextSibling() {
|
|
||||||
return parent != null && parent.self.getChildCount() > pos + 1 ? parent.createChildNode(pos + 1) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WalkerNode<?> getParentNode() {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void enter(ParseTreeListener listener);
|
|
||||||
|
|
||||||
public void exit(final ParseTreeListener listener) {
|
|
||||||
// defaults to do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
protected WalkerNode<?> createChildNode(final int pos) {
|
|
||||||
return createNode(this, self.getChild(pos), pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class RuleWalkerNode extends WalkerNode<RuleNode> {
|
|
||||||
public RuleWalkerNode(final WalkerNode<?> parent, final RuleNode self, final int pos) {
|
|
||||||
super(parent, self, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enter(final ParseTreeListener listener) {
|
|
||||||
enterRule(listener, self);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exit(final ParseTreeListener listener) {
|
|
||||||
exitRule(listener, self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class ErrorWalkerNode extends WalkerNode<ErrorNode> {
|
|
||||||
public ErrorWalkerNode(final WalkerNode<?> parent, final ErrorNode self, final int pos) {
|
|
||||||
super(parent, self, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enter(final ParseTreeListener listener) {
|
|
||||||
listener.visitErrorNode(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class TerminalWalkerNode extends WalkerNode<TerminalNode> {
|
|
||||||
public TerminalWalkerNode(final WalkerNode<?> parent, final TerminalNode self, final int pos) {
|
|
||||||
super(parent, self, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enter(final ParseTreeListener listener) {
|
|
||||||
listener.visitTerminal(self);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue