org.antlr.v4.runtime.tree.ParseTreeWalker Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2012 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD-3-Clause license that
* can be found in the LICENSE.txt file in the project root.
*/
package org.antlr.v4.runtime.tree;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.misc.IntegerStack;
import java.util.ArrayDeque;
import java.util.Deque;
public class ParseTreeWalker {
public static final ParseTreeWalker DEFAULT = new ParseTreeWalker();
/**
* Performs a walk on the given parse tree starting at the root and going down recursively
* with depth-first search. On each node, {@link ParseTreeWalker#enterRule} is called before
* recursively walking down into child nodes, then
* {@link ParseTreeWalker#exitRule} is called after the recursive call to wind up.
* @param listener The listener used by the walker to process grammar rules
* @param t The parse tree to be walked on
*/
public void walk(ParseTreeListener listener, ParseTree t) {
final Deque nodeStack = new ArrayDeque();
final IntegerStack indexStack = new IntegerStack();
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;
}
// No child nodes, so walk tree
do {
// post-order visit
if (currentNode instanceof RuleNode) {
exitRule(listener, (RuleNode)currentNode);
}
// No parent, so no siblings
if (nodeStack.isEmpty()) {
currentNode = null;
currentIndex = 0;
break;
}
// Move to next sibling if possible
currentNode = nodeStack.peek().getChild(++currentIndex);
if (currentNode != null) {
break;
}
// No next sibling, so move up
currentNode = nodeStack.pop();
currentIndex = indexStack.pop();
} while (currentNode != null);
}
}
/**
* Enters a grammar rule by first triggering the generic event {@link ParseTreeListener#enterEveryRule}
* then by triggering the event specific to the given parse tree node
* @param listener The listener responding to the trigger events
* @param r The grammar rule containing the rule context
*/
protected void enterRule(ParseTreeListener listener, RuleNode r) {
ParserRuleContext ctx = (ParserRuleContext)r.getRuleContext();
listener.enterEveryRule(ctx);
ctx.enterRule(listener);
}
/**
* Exits a grammar rule by first triggering the event specific to the given parse tree node
* then by triggering the generic event {@link ParseTreeListener#exitEveryRule}
* @param listener The listener responding to the trigger events
* @param r The grammar rule containing the rule context
*/
protected void exitRule(ParseTreeListener listener, RuleNode r) {
ParserRuleContext ctx = (ParserRuleContext)r.getRuleContext();
ctx.exitRule(listener);
listener.exitEveryRule(ctx);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy