001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2006.
003: *
004: * Licensed under the Aduna BSD-style license.
005: */
006: package org.openrdf.query.parser.serql.ast;
007:
008: class JJTSyntaxTreeBuilderState {
009: private java.util.Stack<Node> nodes;
010: private java.util.Stack<Integer> marks;
011:
012: private int sp; // number of nodes on stack
013: private int mk; // current mark
014: private boolean node_created;
015:
016: JJTSyntaxTreeBuilderState() {
017: nodes = new java.util.Stack<Node>();
018: marks = new java.util.Stack<Integer>();
019: sp = 0;
020: mk = 0;
021: }
022:
023: /* Determines whether the current node was actually closed and
024: pushed. This should only be called in the final user action of a
025: node scope. */
026: boolean nodeCreated() {
027: return node_created;
028: }
029:
030: /* Call this to reinitialize the node stack. It is called
031: automatically by the parser's ReInit() method. */
032: void reset() {
033: nodes.removeAllElements();
034: marks.removeAllElements();
035: sp = 0;
036: mk = 0;
037: }
038:
039: /* Returns the root node of the AST. It only makes sense to call
040: this after a successful parse. */
041: Node rootNode() {
042: return (Node) nodes.elementAt(0);
043: }
044:
045: /* Pushes a node on to the stack. */
046: void pushNode(Node n) {
047: nodes.push(n);
048: ++sp;
049: }
050:
051: /* Returns the node on the top of the stack, and remove it from the
052: stack. */
053: Node popNode() {
054: if (--sp < mk) {
055: mk = ((Integer) marks.pop()).intValue();
056: }
057: return (Node) nodes.pop();
058: }
059:
060: /* Returns the node currently on the top of the stack. */
061: Node peekNode() {
062: return (Node) nodes.peek();
063: }
064:
065: /* Returns the number of children on the stack in the current node
066: scope. */
067: int nodeArity() {
068: return sp - mk;
069: }
070:
071: void clearNodeScope(Node n) {
072: while (sp > mk) {
073: popNode();
074: }
075: mk = ((Integer) marks.pop()).intValue();
076: }
077:
078: void openNodeScope(Node n) {
079: marks.push(new Integer(mk));
080: mk = sp;
081: n.jjtOpen();
082: }
083:
084: /* A definite node is constructed from a specified number of
085: children. That number of nodes are popped from the stack and
086: made the children of the definite node. Then the definite node
087: is pushed on to the stack. */
088: void closeNodeScope(Node n, int num) {
089: mk = ((Integer) marks.pop()).intValue();
090: while (num-- > 0) {
091: Node c = popNode();
092: c.jjtSetParent(n);
093: n.jjtAddChild(c, num);
094: }
095: n.jjtClose();
096: pushNode(n);
097: node_created = true;
098: }
099:
100: /* A conditional node is constructed if its condition is true. All
101: the nodes that have been pushed since the node was opened are
102: made children of the the conditional node, which is then pushed
103: on to the stack. If the condition is false the node is not
104: constructed and they are left on the stack. */
105: void closeNodeScope(Node n, boolean condition) {
106: if (condition) {
107: int a = nodeArity();
108: mk = ((Integer) marks.pop()).intValue();
109: while (a-- > 0) {
110: Node c = popNode();
111: c.jjtSetParent(n);
112: n.jjtAddChild(c, a);
113: }
114: n.jjtClose();
115: pushNode(n);
116: node_created = true;
117: } else {
118: mk = ((Integer) marks.pop()).intValue();
119: node_created = false;
120: }
121: }
122: }
|