Use two queues instead of a custom linked memory structure

This commit is contained in:
Tom Wieczorek 2016-07-20 09:17:50 +02:00
parent 53f2a67b9d
commit 7ca7acd084
No known key found for this signature in database
GPG Key ID: 97132D3CD100563E
1 changed files with 54 additions and 102 deletions

View File

@ -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);
} }
} }
} }