Skip to content

Commit

Permalink
Merge pull request #1231 from twz123/iterative-tree-walker
Browse files Browse the repository at this point in the history
Add an iterative version of the ParseTreeWalker
  • Loading branch information
parrt authored Nov 25, 2016
2 parents 14bc6c4 + d1bc0f5 commit ee614db
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 1 deletion.
1 change: 1 addition & 0 deletions contributors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ YYYY/MM/DD, github id, Full name, email
2016/03/27, beardlybread, Bradley Steinbacher, bradley.j.steinbacher@gmail.com
2016/03/29, msteiger, Martin Steiger, antlr@martin-steiger.de
2016/03/28, gagern, Martin von Gagern, gagern@ma.tum.de
2016/07/10, twz123, Tom Wieczorek, tom.wieczorek@zalando.de
2016/07/20, chrisheller, Chris Heller, chris.heller.greyheller@gmail.com
2016/07/20, nburles, Nathan Burles, nburles@gmail.com
2016/07/20, kosl90, Li Liqiang, kos1990l@gmail.com
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* [The "BSD license"]
* Copyright (c) 2012 Terence Parr
* Copyright (c) 2012 Sam Harwell
* 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;

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
* doesn't use the thread stack but heap-based stacks. Makes it possible to
* process deeply nested parse trees.
*/
public class IterativeParseTreeWalker extends ParseTreeWalker {

@Override
public void walk(ParseTreeListener listener, ParseTree t) {

final Deque<ParseTree> nodeStack = new ArrayDeque<ParseTree>();
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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import org.antlr.v4.runtime.RuleContext;

public class ParseTreeWalker {
public static final ParseTreeWalker DEFAULT = new ParseTreeWalker();
public static final ParseTreeWalker DEFAULT = new IterativeParseTreeWalker();

public void walk(ParseTreeListener listener, ParseTree t) {
if ( t instanceof ErrorNode) {
Expand Down

0 comments on commit ee614db

Please sign in to comment.