diff options
Diffstat (limited to 'antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as')
-rw-r--r-- | antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as b/antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as new file mode 100644 index 0000000..a6fd778 --- /dev/null +++ b/antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as @@ -0,0 +1,438 @@ +/* +[The "BSD licence"] +Copyright (c) 2005-2006 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.runtime.tree { + + import org.antlr.runtime.TokenConstants; + import org.antlr.runtime.TokenStream; + + + /** A buffered stream of tree nodes. Nodes can be from a tree of ANY kind. + * + * This node stream sucks all nodes out of the tree specified in + * the constructor during construction and makes pointers into + * the tree using an array of Object pointers. The stream necessarily + * includes pointers to DOWN and UP and EOF nodes. + * + * This stream knows how to mark/release for backtracking. + * + * This stream is most suitable for tree interpreters that need to + * jump around a lot or for tree parsers requiring speed (at cost of memory). + * There is some duplicated functionality here with UnBufferedTreeNodeStream + * but just in bookkeeping, not tree walking etc... + * + * @see UnBufferedTreeNodeStream + */ + public class CommonTreeNodeStream implements TreeNodeStream { + public static const DEFAULT_INITIAL_BUFFER_SIZE:int = 100; + public static const INITIAL_CALL_STACK_SIZE:int = 10; + + // all these navigation nodes are shared and hence they + // cannot contain any line/column info + + protected var down:Object; + protected var up:Object; + protected var eof:Object; + + /** The complete mapping from stream index to tree node. + * This buffer includes pointers to DOWN, UP, and EOF nodes. + * It is built upon ctor invocation. The elements are type + * Object as we don't what the trees look like. + * + * Load upon first need of the buffer so we can set token types + * of interest for reverseIndexing. Slows us down a wee bit to + * do all of the if p==-1 testing everywhere though. + */ + protected var nodes:Array; + + /** Pull nodes from which tree? */ + protected var root:Object; + + /** IF this tree (root) was created from a token stream, track it. */ + protected var tokens:TokenStream; + + /** What tree adaptor was used to build these trees */ + internal var adaptor:TreeAdaptor; + + /** Reuse same DOWN, UP navigation nodes unless this is true */ + protected var uniqueNavigationNodes:Boolean = false; + + /** The index into the nodes list of the current node (next node + * to consume). If -1, nodes array not filled yet. + */ + protected var p:int = -1; + + /** Track the last mark() call result value for use in rewind(). */ + protected var lastMarker:int; + + /** Stack of indexes used for push/pop calls */ + protected var calls:Array; + + public function CommonTreeNodeStream(tree:Object, adaptor:TreeAdaptor = null, initialBufferSize:int = DEFAULT_INITIAL_BUFFER_SIZE) { + if (tree == null) { + // return uninitalized for static resuse function + return; + } + this.root = tree; + this.adaptor = adaptor == null ? new CommonTreeAdaptor() : adaptor; + + nodes = new Array(); + down = this.adaptor.createFromType(TokenConstants.DOWN, "DOWN"); + up = this.adaptor.createFromType(TokenConstants.UP, "UP"); + eof = this.adaptor.createFromType(TokenConstants.EOF, "EOF"); + } + + /** Reuse an existing node stream's buffer of nodes. Do not point at a + * node stream that can change. Must have static node list. start/stop + * are indexes into the parent.nodes stream. We avoid making a new + * list of nodes like this. + */ + public static function reuse(parent:CommonTreeNodeStream, start:int, stop:int):CommonTreeNodeStream { + var stream:CommonTreeNodeStream = new CommonTreeNodeStream(null); + stream.root = parent.root; + stream.adaptor = parent.adaptor; + stream.nodes = parent.nodes.slice(start, stop); + stream.down = parent.down; + stream.up = parent.up; + stream.eof = parent.eof; + return stream; + } + + /** Walk tree with depth-first-search and fill nodes buffer. + * Don't do DOWN, UP nodes if its a list (t is isNil). + */ + protected function fillBuffer():void { + fillBufferTo(root); + //System.out.println("revIndex="+tokenTypeToStreamIndexesMap); + p = 0; // buffer of nodes intialized now + } + + public function fillBufferTo(t:Object):void { + var nil:Boolean = adaptor.isNil(t); + if ( !nil ) { + nodes.push(t); // add this node + } + // add DOWN node if t has children + var n:int = adaptor.getChildCount(t); + if ( !nil && n>0 ) { + addNavigationNode(TokenConstants.DOWN); + } + // and now add all its children + for (var c:int=0; c<n; c++) { + var child:Object = adaptor.getChild(t,c); + fillBufferTo(child); + } + // add UP node if t has children + if ( !nil && n>0 ) { + addNavigationNode(TokenConstants.UP); + } + } + + /** What is the stream index for node? 0..n-1 + * Return -1 if node not found. + */ + protected function getNodeIndex(node:Object):int { + if ( p==-1 ) { + fillBuffer(); + } + for (var i:int = 0; i < nodes.length; i++) { + var t:Object = nodes[i]; + if ( t===node ) { + return i; + } + } + return -1; + } + + /** As we flatten the tree, we use UP, DOWN nodes to represent + * the tree structure. When debugging we need unique nodes + * so instantiate new ones when uniqueNavigationNodes is true. + */ + protected function addNavigationNode(ttype:int):void { + var navNode:Object = null; + if ( ttype==TokenConstants.DOWN ) { + if ( hasUniqueNavigationNodes) { + navNode = adaptor.createFromType(TokenConstants.DOWN, "DOWN"); + } + else { + navNode = down; + } + } + else { + if ( hasUniqueNavigationNodes ) { + navNode = adaptor.createFromType(TokenConstants.UP, "UP"); + } + else { + navNode = up; + } + } + nodes.push(navNode); + } + + public function getNode(i:int):Object { + if ( p==-1 ) { + fillBuffer(); + } + return nodes[i]; + } + + public function LT(k:int):Object { + if ( p==-1 ) { + fillBuffer(); + } + if ( k==0 ) { + return null; + } + if ( k<0 ) { + return LB(-k); + } + //System.out.print("LT(p="+p+","+k+")="); + if ( (p+k-1) >= nodes.length ) { + return eof; + } + return nodes[p+k-1]; + } + + public function get currentSymbol():Object { return LT(1); } + + /** Look backwards k nodes */ + protected function LB(k:int):Object { + if ( k==0 ) { + return null; + } + if ( (p-k)<0 ) { + return null; + } + return nodes[p-k]; + } + + public function get treeSource():Object { + return root; + } + + public function get sourceName():String { + return tokenStream.sourceName; + } + + public function get tokenStream():TokenStream { + return tokens; + } + + public function set tokenStream(tokens:TokenStream):void { + this.tokens = tokens; + } + + public function get treeAdaptor():TreeAdaptor { + return adaptor; + } + + public function set treeAdaptor(adaptor:TreeAdaptor):void { + this.adaptor = adaptor; + } + + public function get hasUniqueNavigationNodes():Boolean { + return uniqueNavigationNodes; + } + + public function set hasUniqueNavigationNodes(uniqueNavigationNodes:Boolean):void { + this.uniqueNavigationNodes = uniqueNavigationNodes; + } + + public function consume():void { + if ( p==-1 ) { + fillBuffer(); + } + p++; + } + + public function LA(i:int):int { + return adaptor.getType(LT(i)); + } + + public function mark():int { + if ( p==-1 ) { + fillBuffer(); + } + lastMarker = index; + return lastMarker; + } + + public function release(marker:int):void { + // no resources to release + } + + public function get index():int { + return p; + } + + public function rewindTo(marker:int):void { + seek(marker); + } + + public function rewind():void { + seek(lastMarker); + } + + public function seek(index:int):void { + if ( p==-1 ) { + fillBuffer(); + } + p = index; + } + + /** Make stream jump to a new location, saving old location. + * Switch back with pop(). + */ + public function push(index:int):void { + if ( calls==null ) { + calls = new Array(); + } + calls.push(p); // save current index + seek(index); + } + + /** Seek back to previous index saved during last push() call. + * Return top of stack (return index). + */ + public function pop():int { + var ret:int = calls.pop(); + seek(ret); + return ret; + } + + public function reset():void { + p = 0; + lastMarker = 0; + if (calls != null) { + calls = new Array(); + } + } + + public function get size():int { + if ( p==-1 ) { + fillBuffer(); + } + return nodes.length; + } + + // TREE REWRITE INTERFACE + public function replaceChildren(parent:Object, startChildIndex:int, stopChildIndex:int, t:Object):void { + if ( parent!=null ) { + adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t); + } + } + + /** Used for testing, just return the token type stream */ + public function toString():String { + if ( p==-1 ) { + fillBuffer(); + } + var buf:String = ""; + for (var i:int = 0; i < nodes.length; i++) { + var t:Object = nodes[i]; + buf += " "; + buf += (adaptor.getType(t)); + } + return buf.toString(); + } + + /** Debugging */ + public function toTokenString(start:int, stop:int):String { + if ( p==-1 ) { + fillBuffer(); + } + var buf:String = ""; + for (var i:int = start; i < nodes.length && i <= stop; i++) { + var t:Object = nodes[i]; + buf += " "; + buf += adaptor.getToken(t); + } + return buf; + } + + public function toStringWithRange(start:Object, stop:Object):String { + if ( start==null || stop==null ) { + return null; + } + if ( p==-1 ) { + fillBuffer(); + } + trace("stop: "+stop); + if ( start is CommonTree ) + trace("toString: "+CommonTree(start).token+", "); + else + trace(start); + if ( stop is CommonTree ) + trace(CommonTree(stop).token); + else + trace(stop); + // if we have the token stream, use that to dump text in order + if ( tokens!=null ) { + var beginTokenIndex:int = adaptor.getTokenStartIndex(start); + var endTokenIndex:int = adaptor.getTokenStopIndex(stop); + // if it's a tree, use start/stop index from start node + // else use token range from start/stop nodes + if ( adaptor.getType(stop)==TokenConstants.UP ) { + endTokenIndex = adaptor.getTokenStopIndex(start); + } + else if ( adaptor.getType(stop)==TokenConstants.EOF ) { + endTokenIndex = size-2; // don't use EOF + } + return tokens.toStringWithRange(beginTokenIndex, endTokenIndex); + } + // walk nodes looking for start + var t:Object = null; + var i:int = 0; + for (; i < nodes.length; i++) { + t = nodes[i]; + if ( t==start ) { + break; + } + } + // now walk until we see stop, filling string buffer with text + var buf:String = ""; + t = nodes[i]; + while ( t!=stop ) { + var text:String = adaptor.getText(t); + if ( text==null ) { + text = " "+ adaptor.getType(t); + } + buf += text; + i++; + t = nodes[i]; + } + // include stop node too + text = adaptor.getText(stop); + if ( text==null ) { + text = " " + adaptor.getType(stop); + } + buf += text; + return buf.toString(); + } + } + +}
\ No newline at end of file |