/* * JBoss, Home of Professional Open Source * Copyright 2009-10 Red Hat and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * * @authors Andrew Dinn */ package org.jboss.byteman.rule.grammar; import org.jboss.byteman.rule.helper.Helper; /** * Class used by the JavaCUP parser to construct a parse tree. */ public abstract class ParseNode { /* * tags for different types of parse nodes */ public final static int ARRAY = 0; public final static int ASSIGN = 1; public final static int BIND = 2; public final static int BINOP = 3; public final static int BOOLEAN_LITERAL = 4; public final static int COMMA = 5; public final static int COLON = 6; public final static int FIELD = 7; public final static int FLOAT_LITERAL = 8; public final static int IDENTIFIER = 9; public final static int INTEGER_LITERAL = 10; public final static int METH = 11; public final static int NOTHING = 12; public final static int PATH = 13; public final static int RETURN = 14; public final static int SEMI = 15; public final static int STRING_LITERAL = 16; public final static int TERNOP = 17; public final static int THROW = 18; public final static int UNOP = 19; public final static int NEW = 20; public final static int NULL_LITERAL = 21; public final static int CLASS = 22; public final static int ARRAY_INIT = 23; /* tags for operators */ public final static int AND = 30; public final static int BAND = 31; public final static int BOR = 32; public final static int BXOR = 33; public final static int DIV = 34; public final static int DOLLAR = 35; public final static int EQ = 36; public final static int GE = 37; public final static int GT = 38; public final static int LE = 39; public final static int LT = 40; public final static int MINUS = 41; public final static int MOD = 42; public final static int MUL = 43; public final static int NE = 44; public final static int NOT = 45; public final static int OR = 46; public final static int PLUS = 47; public final static int TWIDDLE = 48; public final static int UMINUS = 49; public final static int LSH = 50; public final static int RSH = 51; public final static int URSH = 52; /** * the type tag for this node */ private int tag; /** * the script file containing the text form which this node was parsed */ private String file; /** * the line position fo rthis node */ private int line; /** * the column position for this node */ private int column; /** * generic constructor * @param tag identifies the type of this node * @param file identifies the file containing the node's text * @param line identifies the start line for this node's text * @param column identifies the start columen for this node's text */ protected ParseNode(int tag, String file, int line, int column) { this.tag = tag; this.file = file; this.line = line; this.column = column; } /** * get the tag for this node * @return the tag for this node */ public int getTag() { return tag; } /** * get the line position for this node * @return the line position for this node */ public int getLine() { return line; } /** * get the column position for this node * @return the column position for this node */ public int getColumn() { return column; } /** * get the child count for this node * @return the child count for this node */ public abstract int getChildCount(); /** * get the nth child for this node or null if the index exceeds the child count * @param idx the child index * @return the nth child for this node */ public abstract Object getChild(int idx); /** * get the display representation of this node * @return the display representation of this node */ public abstract String getText(); /** * get a string representing the position for this node * @return a string representing the position for this node */ public String getPos() { return " " + file + " line " + line; } /** * create a simple node for a builtin token * @param tag identifies the type of this node * @param file identifies the file containing the node's text * @param line identifies the start line for this node's text * @param column identifies the start columen for this node's text * @return a simple node for a builtin token */ public static ParseNode node(int tag, String file, int line, int column) { return new NullaryNode(tag, file, line, column); } /** * create a simple node for a builtin token * @param tag identifies the type of this node * @param file identifies the file containing the node's text * @param line identifies the start line for this node's text * @param column identifies the start columen for this node's text * @param child0 the first child for this node * @return a simple node for a builtin token */ public static ParseNode node(int tag, String file, int line, int column, Object child0) { return new UnaryNode(tag, file, line, column, child0); } /** * create a simple node for a builtin token * @param tag identifies the type of this node * @param file identifies the file containing the node's text * @param line identifies the start line for this node's text * @param column identifies the start columen for this node's text * @param child0 the first child for this node * @param child1 the second child for this node * @return a simple node for a builtin token */ public static ParseNode node(int tag, String file, int line, int column, Object child0, Object child1) { return new BinaryNode(tag, file, line, column, child0, child1); } /** * create a simple node for a builtin token * @param tag identifies the type of this node * @param file identifies the file containing the node's text * @param line identifies the start line for this node's text * @param column identifies the start columen for this node's text * @param child0 the first child for this node * @param child1 the second child for this node * @param child2 the third child for this node * @return a simple node for a builtin token */ public static ParseNode node(int tag, String file, int line, int column, Object child0, Object child1, Object child2) { return new TernaryNode(tag, file, line, column, child0, child1, child2); } /** * create a simple node for a builtin token * @param tag identifies the type of this node * @param file identifies the file containing the node's text * @param line identifies the start line for this node's text * @param column identifies the start columen for this node's text * @param child0 the first child for this node * @param child1 the second child for this node * @param child2 the third child for this node * @param child3 the fourth child for this node * @return a simple node for a builtin token */ public static ParseNode node(int tag, String file, int line, int column, Object child0, Object child1, Object child2, Object child3) { return new QuaternaryNode(tag, file, line, column, child0, child1, child2, child3); } /** * a parse node with no children */ private static class NullaryNode extends ParseNode { public NullaryNode(int tag, String file, int line, int column) { super(tag, file, line, column); } /** * get the child count for this node * * @return the child count for this node */ public int getChildCount() { return 0; } /** * get the nth child for this node or null if the index exceeds the child count * * @return the nth child for this node */ public Object getChild(int idx) { return null; } /** * get the display representation of this node * * @return athe display representation of this node */ public String getText() { int tag = getTag(); switch(tag) { case NOTHING: return "NOTHING"; case AND: return "&&"; case LSH: return "<<"; case RSH: return ">>"; case URSH: return ">>>"; case BAND: return "&"; case BOR: return "|"; case BXOR: return "^"; case DIV: return "/"; case DOLLAR: return "$"; case EQ: return "=="; case GE: return ">="; case GT: return ">"; case LE: return "<="; case LT: return "<"; case MINUS: return "-"; case MOD: return "%"; case MUL: return "*"; case NE: return "!="; case NOT: return "!"; case OR: return "||"; case PLUS: return "+"; case TWIDDLE: return "~"; case UMINUS: return "-"; case NULL_LITERAL: return "null"; case ARRAY_INIT: return "{}"; default: Helper.err("NullaryNode.getText() : Unexpected tag " + tag); return "???"; } } } /** * a parse node with one child */ private static class UnaryNode extends ParseNode { private Object child0; public UnaryNode(int tag, String file, int line, int column, Object child0) { super(tag, file, line, column); this.child0 = child0; } /** * get the child count for this node * * @return the child count for this node */ public int getChildCount() { return 1; } /** * get the nth child for this node or null if the index exceeds the child count * * @return the nth child for this node */ public Object getChild(int idx) { if (idx == 0) { return child0; } return null; } /** * get a string representing the display representation of this node * * @return a string representing the display representation of this node */ public String getText() { int tag = getTag(); switch(tag) { case ARRAY: { // these occur when we have a type array declaration return ((ParseNode)child0).getText() + "[]"; } case BOOLEAN_LITERAL: return child0.toString(); case FLOAT_LITERAL: return child0.toString(); case INTEGER_LITERAL: return child0.toString(); case RETURN: return "RETURN"; case STRING_LITERAL: return "\"" + ((String)child0) + "\""; case DOLLAR: return ((String)child0); case CLASS: return ((String)child0); case ARRAY_INIT: return ("{" + ((ParseNode)child0).getText() + "}"); default: Helper.err("UnaryNode.getText() : Unexpected tag " + tag); return "???"; } } } /** * a parse node with two children */ private static class BinaryNode extends ParseNode { private Object child0; private Object child1; public BinaryNode(int tag, String file, int line, int column, Object child0, Object child1) { super(tag, file, line, column); this.child0 = child0; this.child1 = child1; } /** * get the child count for this node * * @return the child count for this node */ public int getChildCount() { return 2; } /** * get the nth child for this node or null if the index exceeds the child count * * @return the nth child for this node */ public Object getChild(int idx) { switch (idx) { case 0: return child0; case 1: return child1; } return null; } /** * get the display representation of this node * * @return the display representation of this node */ public String getText() { int tag = getTag(); switch(tag) { case ARRAY: // these occur when we have an array expression return ((ParseNode)child0).getText() + "[" + ((ParseNode)child1).getText() + "]"; case ASSIGN: return "="; case BIND: return "BIND"; case COLON: return ((ParseNode)child0).getText(); case FIELD: return "." + ((ParseNode)child1).getText(); case IDENTIFIER: { String text = (String)child0; // include path prefix ParseNode next = (ParseNode)child1; while (next != null) { text = ((ParseNode)next).getText() + "." + text; next = (ParseNode)next.getChild(1); } return text; } case PATH: return (String)child0; case SEMI: { String text = ((ParseNode)child0).getText(); text += ";"; text += ((ParseNode)child1).getText(); return text; } case COMMA: { String text = ((ParseNode)child0).getText(); text += ","; text += ((ParseNode)child1).getText(); return text; } case THROW: return "THROW"; case NEW: return "NEW"; case UNOP: return ((ParseNode)child0).getText(); default: Helper.err("BinaryNode.getText() : Unexpected tag " + tag); return "???"; } } } /** * a parse node with three children */ private static class TernaryNode extends ParseNode { private Object child0; private Object child1; private Object child2; public TernaryNode(int tag, String file, int line, int column, Object child0, Object child1, Object child2) { super(tag, file, line, column); this.child0 = child0; this.child1 = child1; this.child2 = child2; } /** * get the child count for this node * * @return the child count for this node */ public int getChildCount() { return 3; } /** * get the nth child for this node or null if the index exceeds the child count * * @return the nth child for this node */ public Object getChild(int idx) { switch (idx) { case 0: return child0; case 1: return child1; case 2: return child2; } return null; } /** * get the display representation of this node * * @return the display representation of this node */ public String getText() { int tag = getTag(); switch(tag) { case BINOP: return ((ParseNode)child0).getText(); case METH: return ((ParseNode)child0).getText(); case TERNOP: return "?"; default: Helper.err("TernaryNode.getText() : Unexpected tag " + tag); return "???"; } } } /** * a parse node with four children */ private static class QuaternaryNode extends ParseNode { private Object child0; private Object child1; private Object child2; private Object child3; public QuaternaryNode(int tag, String file, int line, int column, Object child0, Object child1, Object child2, Object child3) { super(tag, file, line, column); this.child0 = child0; this.child1 = child1; this.child2 = child2; this.child3 = child3; } /** * get the child count for this node * * @return the child count for this node */ public int getChildCount() { return 2; } /** * get the nth child for this node or null if the index exceeds the child count * * @return the nth child for this node */ public Object getChild(int idx) { switch (idx) { case 0: return child0; case 1: return child1; case 2: return child2; case 3: return child3; } return null; } /** * get the display representation of this node * * @return the display representation of this node */ public String getText() { int tag = getTag(); switch(tag) { default: Helper.err("QuaternaryNode.getText() : Unexpected tag " + tag); return "???"; } } } }