/* Generated By:JavaCC: Do not edit this line. ExpressionParser.java */
package prefuse.data.expression.parser;

import java.io.StringReader;
import java.util.logging.Logger;

import prefuse.data.expression.AndPredicate;
import prefuse.data.expression.ArithmeticExpression;
import prefuse.data.expression.BooleanLiteral;
import prefuse.data.expression.ColumnExpression;
import prefuse.data.expression.ComparisonPredicate;
import prefuse.data.expression.Expression;
import prefuse.data.expression.Function;
import prefuse.data.expression.FunctionTable;
import prefuse.data.expression.IfExpression;
import prefuse.data.expression.NotPredicate;
import prefuse.data.expression.NumericLiteral;
import prefuse.data.expression.ObjectLiteral;
import prefuse.data.expression.OrPredicate;
import prefuse.data.expression.Predicate;
import prefuse.data.expression.XorPredicate;
import prefuse.util.StringLib;

/**
 * Parser for statements written in the prefuse expression language. Text
 * expression are parsed into {@link prefuse.data.expression.Expression}
 * instances, and can be used as predicates or to create derived
 * table columns. This parser is implemented using the 
 * <a href="https://javacc.dev.java.net/">JavaCC package</a>. To parse
 * a text String to an {@link prefuse.data.expression.Expression}, use
 * the {@link #parse(String)} method. If a parse error occurs, the method
 * will fail silently and return null. Any generated exception can be
 * later retrieved using the {@link #getError()} method. One can also
 * use the {@link #parse(String, boolean)} with a <code>true</code>
 * boolean argument to request that Exceptions be thrown when
 * errors occur.
 * 
 * <h1>Prefuse Expression Language Reference</h1>
 * <p>
 * The prefuse expression language provides a convenient way of creating manipulable statements
 * over data in a prefuse data structure. For example, the expression language can be used to
 * write {@link prefuse.data.expression.Predicate} instances for querying and filtering a table
 * or graph, or to create arbitrary expressions over a data set to generate new, derived data
 * fields that can in turn be subject to additional processing or visualization. For example,
 * the {@link prefuse.data.tuple.TupleSet#tuples(prefuse.data.expression.Predicate)} method
 * uses a Predicate to filter the requested set of tuples, and the
 * {@link prefuse.data.Table#addColumn(java.lang.String,prefuse.data.expression.Expression)}
 * method creates a new table column whose values are generated by the provided Expression. 
 * The expression machinery is used
 * throughout the toolkit -- it underlies the filtering and query optimization features,
 * is a key component of {@link prefuse.data.query dynamic query bindings}, and is used to
 * create the rule chains evaluated by the
 * {@link prefuse.render.DefaultRendererFactory},
 * {@link prefuse.action.assignment.ColorAction},
 * {@link prefuse.action.assignment.ShapeAction},
 * {@link prefuse.action.assignment.FontAction}, and
 * {@link prefuse.action.assignment.SizeAction} classes.
 * </p>
 * <p>
 * The {@link prefuse.data.expression.Expression} interface is quite simple: given a single
 * Tuple, compute and return a value. The returned value could be an Object, a boolean, an int,
 * or other primitive type. Individual methods for each type are available, and which ones are
 * legal to call for any given Expression depends on the type of Expression.
 * </p>
 * <p>
 * Expressions can be created directly in Java, by instantiating and chaining together the
 * desired Expression instances. This process, however, can be somewhat tedious, so prefuse
 * also provides a built-in parser/compiler for generating these chains of Expression
 * instances from a textual language. The language is based on a subset of SQL, the
 * standard language for database queries. If you have ever written a "WHERE" clause in
 * a SQL "SELECT" query, you probably know most of the language already. To parse an
 * expression, simply pass a text string containing an expression statement to the
 * {@link prefuse.data.expression.parser.ExpressionParser#parse(java.lang.String)}
 * method. If the string parses successfully, the parsed Expression instance will be
 * returned.
 * </p>
 * <p>
 * Below is the reference for the language, including literal types, data field references,
 * basic operators, and included functions. If need be, you can also introduce a new
 * function by creating a new instance of the {@link prefuse.data.expression.Function} interface
 * and registering it with the {@link prefuse.data.expression.FunctionTable} class.
 * </p>
 * <p>
 * All keywords and functions in the prefuse expression language can be written in
 * either uppercase or lowercase. Writing in mixed-case, however, will likely result in parse
 * errors.
 * </p>
 * 
 * <h2>Literal Values and Data Field References</h2>
 * <p>The fundamental building blocks of the expression language, representing data values
 *  or referencing the contents of a Tuple data field.</p>
 * <ul>
 * <li><strong>Boolean literals  (<code>TRUE, FALSE</code>)</strong><br/>
 *   The boolean literals representing true and false conditions, parsed to type <code>boolean</code>
 * </li>
 * <li><strong>Integer literals (<code>1, -5, 12340</code>)</strong><br/>
 *   Undecorated, non-decimal numbers are parsed as numbers of type <code>int</code>
 * </li>
 * <li><strong>Long literals (<code>1L, -5L, 12340L</code>)</strong><br/>
 *   Integer values decorated with the suffix "L" are parsed as numbers of type <code>long</code>
 * </li>
 * <li><strong>Double literals (<code>1.0, 3.1415, 1e-35, 2.3e6</code>)</strong><br/>
 *   Numbers with decimals or exponents in scientific notation are parsed as numbers of type <code>double</code>
 * </li>
 * <li><strong>Float literals (<code>1.0f, 3.1415f, 1e-35f, 2.3e6f</code>)</strong><br/>
 *   Floating-point values decorated with the suffix "f" are parsed as numbers of type <code>float</code>
 * </li>
 * <li><strong>String literals (<code>"some text", 'a label'</code>)</strong><br/>
 *   Text strings placed in double (") or single (') quotations are parsed as <code>String</code> literals
 * </li>
 * <li><strong>Null literal  (<code>null</code>)</strong><br/>
 *   The string <code>null</code> is parsed as an ObjectLiteral of type null.
 * </li>
 * <li><strong>Data field references (<code>_strokeColor, [a data field]</code>)</strong><br/>
 *   Free-standing strings or those placed within brackets are parsed as a reference to the
 *   data field of that name. Brackets are required for any fields that include spaces or other
 *   unusual characters in their name (e.g., characters like +, -, *, etc), or conflict with
 *   an existing keyword For example, <code>true</code> parses to a boolean literal while
 *   <code>[true]</code> parses to a reference to a data field named 'true'.
 * </li>
 * </ul>
 *
 * <h2>Operators and Control Flow</h2>
 * <p>Basic operators and control flow structures for the expression language.</p>
 * <ul>
 * <li><strong><code>x + y</code> (addition)</strong><br/>
 *     Add <code>x</code> and <code>y</code>
 * </li>
 * <li><strong><code>x - y</code> (subtraction)</strong><br/>
 *     Subtract <code>y</code> from <code>x</code>
 * </li>
 * <li><strong><code>x * y</code> (multiplication)</strong><br/>
 *     Multiply <code>x</code> and <code>y</code>
 * </li>
 * <li><strong><code>x / y</code> (division)</strong><br/>
 *     Divide <code>x</code> by <code>y</code>
 * </li>
 * <li><strong><code>x ^ y</code> (exponentiation, pow)</strong><br/>
 *     Raise <code>x</code> to the exponent <code>y</code>
 * </li>
 * <li><strong><code>x % y</code> (modulo)</strong><br/>
 *     Return the remainder of <code>x</code> divded by <code>y</code>
 * </li>
 * <li><strong><code>x = y, x == y</code> (equality)</strong><br/>
 *     Indicates if <code>x</code> and <code>y</code> are equal
 * </li>
 * <li><strong><code>x != y, x <> y</code> (inequality)</strong><br/>
 *     Indicates if <code>x</code> and <code>y</code> are not equal
 * </li>
 * <li><strong><code>x > y</code> (greater than)</strong><br/>
 *     Indicates if <code>x</code> is greater than <code>y</code>
 * </li>
 * <li><strong><code>x >= y</code> (greater than or equal to)</strong><br/>
 *     Indicates if <code>x</code> is greater than or equal to <code>y</code>
 * </li>
 * <li><strong><code>x < y</code> (less than)</strong><br/>
 *     Indicates if <code>x</code> is less than <code>y</code>
 * </li>
 * <li><strong><code>x <= y</code> (less than or equal to)</strong><br/>
 *     Indicates if <code>x</code> is less than or equal to <code>y</code>
 * </li>
 * <li><strong><code>x AND y, x && y</code> (and)</strong><br/>
 *     Indicates if both <code>x</code> and <code>y</code> are true
 * </li>
 * <li><strong><code>x OR y, x || y</code> (or)</strong><br/>
 *     Indicates if either <code>x</code> or <code>y</code> is true
 * </li>
 * <li><strong><code>NOT x, !x</code> (not)</strong><br/>
 *     Indicates if the negation of <code>x</code> is true
 * </li>
 * <li><strong><code>x XOR y</code> (exclusive or)</strong><br/>
 *     Indicates if one, but not both, of <code>x</code> or <code>y</code> is true
 * </li>
 * <li><strong><code>IF test THEN x ELSE y</code> (if-then-else)</strong><br/>
 *     Evaluates the predicate <code>test</code>, and if true evaluates and returns the
 *     expression <code>x</code>, and if false evaluates and returns the expression
 *     <code>y</code>
 * </li>
 * <li><strong><code>()</code> (parentheses)</strong><br/>
 *     Groups expressions together to enfore a particular order of evaluation. For example,
 *     <code>1+2*3</code> evaluates to <code>7</code>, while <code>(1+2)*3</code> evaluates
 *     to <code>9</code>.
 * </li>
 * </ul>
 *
 * <h2>General Functions</h2> 
 * <p>General purpose functions.</p>
 * <ul>
 *   <li><strong><code>ROW()</code></strong><br/>
 *     Returns the table row number (or -1 if none) of the current Tuple.
 *   </li>
 *   <li><strong><code>ISNODE()</code></strong><br/>
 *     Returns true if the current Tuple is a graph Node.
 *   </li>
 *   <li><strong><code>ISEDGE()</code></strong><br/>
 *     Returns true if the current Tuple is a graph Edge.
 *   </li>
 *   <li><strong><code>DEGREE()</code></strong><br/>
 *     If the current Tuple is graph Node, returns the Node degree
 *     (the total number of incident edges). Otherwise returns 0.
 *   </li>
 *   <li><strong><code>INDEGREE()</code></strong><br/>
 *     If the current Tuple is graph Node, returns the Node indegree
 *     (the number of incident edges pointing towards this node).
 *     Otherwise returns 0.
 *   </li>
 *   <li><strong><code>OUTDEGREE()</code></strong><br/>
 *     If the current Tuple is graph Node, returns the Node outdegree
 *     (the number of incident edges pointing away from the node).
 *     Otherwise returns 0.
 *   </li>
 *   <li><strong><code>CHILDCOUNT()</code></strong><br/>
 *     If the current Tuple is graph Node, returns the number of tree
 *     children nodes. If the Tuple is not a Node, this method returns 0.
 *     If the Node is part of a Graph (not a Tree), the number of children
 *     nodes in the current spanning tree is returned. If no spanning tree has
 *     been computed, a new spanning tree will be computed using the default
 *     method. See {@link prefuse.data.Graph#getSpanningTree()} for more.
 *   </li>
 *   <li><strong><code>TREEDEPTH()</code></strong><br/>
 *     If the current Tuple is graph Node, returns the depth of this Node
 *     in its Tree or SpanningTree. If the Tuple is not a Node, this method
 *     returns 0. If the Node is part of a Graph (not a Tree), the tree depth
 *     of the node in the current spanning tree is returned. If no spanning
 *     tree has been computed, a new spanning tree will be computed using the
 *     default method. See {@link prefuse.data.Graph#getSpanningTree()} for
 *     more.
 *   </li>
 * </ul>
 *
 * <h2>Mathematical Functions</h2>
 * <p>Functions for performing mathematical calculations.</p>
 * <ul>
 *   <li><strong><code>ABS(x)</code></strong><br/>
 *     Returns the absolute value of <code>x</code>
 *   </li>
 *   <li><strong><code>ACOS(x)</code></strong><br/>
 *     Returns the inverse cosine (arc cosine) of a <code>x</code>
 *   </li>
 *   <li><strong><code>ASIN(x)</code></strong><br/>
 *     Returns the inverse sine (arc sine) of a <code>x</code>
 *   </li>
 *   <li><strong><code>ATAN(x)</code></strong><br/>
 *     Returns the inverse tangent (arc tangent) of a <code>x</code>
 *   </li>
 *   <li><strong><code>ATAN2(y, x)</code></strong><br/>
 *     For the Cartesian coordinates <code>x</code>, <code>y</code> return the polar coordinate angle theta
 *   </li>
 *   <li><strong><code>CEIL(x), CEILING(x)</code></strong><br/>
 *     Returns the nearest integer value greater than or equal to <code>x</code>.
 *   </li>
 *   <li><strong><code>COS(x)</code></strong><br/>
 *     Returns the cosine of <code>x</code>
 *   </li>
 *   <li><strong><code>COT(x)</code></strong><br/>
 *     Returns the cotangent of <code>x</code>
 *   </li>
 *   <li><strong><code>DEGREES(x)</code></strong><br/>
 *     Converts <code>x</code> from radians to degrees
 *   </li>
 *   <li><strong><code>EXP(x)</code></strong><br/>
 *     Returns the value of <em>e</em> (the base of natural logarithms) raised to the <code>x</code> power
 *   </li>
 *   <li><strong><code>FLOOR(x)</code></strong><br/>
 *     Returns the nearest integer value less than or equal to <code>x</code>.
 *   </li>
 *   <li><strong><code>LOG(x), LOG(b, x)</code></strong><br/>
 *     With one argument, returns the natural logarithm (logarithm base <em>e</em>) of <code>x</code><br/>
 *     With two arguments, returns the logarithm of <code>x</code> for the provided base <code>b</code>
 *   </li>
 *   <li><strong><code>LOG2(x)</code></strong><br/>
 *     Returns the logarithm base 2 of <code>x</code>
 *   </li>
 *   <li><strong><code>LOG10(x)</code></strong><br/>
 *     Returns the logarithm base 10 of <code>x</code>
 *   </li>
 *   <li><strong><code>MAX(a, b, c, ...)</code></strong><br/>
 *     Returns the maximum value among the provided arguments
 *   </li>
 *   <li><strong><code>MIN(a, b, c, ...)</code></strong><br/>
 *     Returns the minimum value among the provided arguments
 *   </li>
 *   <li><strong><code>MOD(x, y)</code></strong><br/>
 *     Returns <code>x</code> modulo <code>y</code> (the remainder of <code>x</code> divided by <code>y</code>)
 *   </li>
 *   <li><strong><code>PI()</code></strong><br/>
 *     Returns the constant &pi; (= 3.1415926535...), the ratio between the circumference and diameter of a circle
 *   </li>
 *   <li><strong><code>POW(x, y), POWER(x, y)</code></strong><br/>
 *     Return the value of <code>x</code> raised to the exponent <code>y</code>
 *   </li>
 *   <li><strong><code>RADIANS(x)</code></strong><br/>
 *     Converts <code>x</code> from degrees to radians
 *   </li>
 *   <li><strong><code>RAND()</code></strong><br/>
 *     Returns a random floating-point value between 0 and 1
 *   </li>
 *   <li><strong><code>ROUND(x)</code></strong><br/>
 *     Returns the value of <code>x</code> rounded to the nearest integer
 *   </li>
 *   <li><strong><code>SIGN(x)</code></strong><br/>
 *     Returns the sign of <code>x</code>: 1 for positive, -1 for negative
 *   </li>
 *   <li><strong><code>SIN(x)</code></strong><br/>
 *     Returns the sine of <code>x</code>
 *   </li>
 *   <li><strong><code>SQRT(x)</code></strong><br/>
 *     Returns the square root of <code>x</code>
 *   </li>
 *   <li><strong><code>SUM(a, b, c, ...)</code></strong><br/>
 *     Returns the sum of the provided input value
 *   </li>
 *   <li><strong><code>TAN(x)</code></strong><br/>
 *     Returns the tangent of <code>x</code>
 *   </li>
 *   <li><strong><code>SAFELOG10(x)</code></strong><br/>
 *     Returns a "negative safe" logarithm base 10 of <code>x</code>, equivalent to
 *     <code>SIGN(x) * LOG10(ABS(x))</code>
 *   </li>
 *   <li><strong><code>POW(x)</code></strong><br/>
 *     Returns a "negative safe" square root of <code>x</code>, equivalent to
 *     <code>SIGN(x) * SQRT(ABS(x))</code>
 *   </li>
 *   </ul>
 *   
 *   <h2>String Functions</h2>
 *   <p>Functions for processing text strings.</p>
 *   <ul>
 *   <li><strong><code>CAP(str)</code></strong><br/>
 *     Capitalize words in the string <code>str</code>. Individual words/names will be given
 *     uppercase first letters, with all other letters in lowercase.
 *   </li>
 *   <li><strong><code>CONCAT(a, b, c, ...)</code></strong><br/>
 *     Concatenate the input strings into one resulting string.
 *   </li>
 *   <li><strong><code>CONCAT_WS(sep, a, b, c, ...)</code></strong><br/>
 *     Concatenate with separator. Concatenates the input strings into one resulting
 *     string, placing the string <code>sep</code> between each of the other arguments
 *   </li>
 *   <li><strong><code>FORMAT(x, d)</code></strong><br/>
 *     Format the number <code>x</code> as a string of the type "#,###.##", showing <code>d</code> decimal places
 *   </li>
 *   <li><strong><code>INSERT(str, pos, len, newstr)</code></strong><br/>
 *     Replaces the substring of length <code>len</code> starting at position <code>pos</code> in input
 *     string <code>str</code> with the string <code>newstr</code>
 *   </li>
 *   <li><strong><code>LEFT(str, len)</code></strong><br/>
 *     Returns the leftmost <code>len</code> characters of string <code>str</code>
 *   </li>
 *   <li><strong><code>LENGTH(str)</code></strong><br/>
 *     Returns the length, in characters, of the input string <code>str</code>
 *   </li>
 *   <li><strong><code>LOWER(str), LCASE(str)</code></strong><br/>
 *     Returns the string <code>str</code> mapped to lowercase letters
 *   </li>
 *   <li><strong><code>LPAD(str, len, pad)</code></strong><br/>
 *     Pad the left side of string <code>str</code> with copies of string <code>pad</code>,
 *     up to a total padding of <code>len</code> characters
 *   </li>
 *   <li><strong><code>MID(str, pos, len)</code></strong><br/>
 *     Return a substring of <code>str</code> of length <code>len</code>, starting at
 *     position <code>pos</code>
 *   </li>
 *   <li><strong><code>POSITION(substr, str)</code></strong><br/>
 *     Returns the starting position of the first occurrence of substring <code>substr</code>
 *     in the string <code>str</code>. Returns -1 if the substring is not found.
 *   </li>
 *   <li><strong><code>REVERSE(str)</code></strong><br/>
 *     Returns a reversed copy of the input string <code>str</code>
 *   </li>
 *   <li><strong><code>REPEAT(str, count)</code></strong><br/>
 *     Returns a string consisting of <code>str</code> repeated <code>count</code> times
 *   </li>
 *   <li><strong><code>REPLACE(str, orig, replace)</code></strong><br/>
 *     Returns a copy of <code>str</code> in which all occurrences of <code>orig</code> have been
 *     replaced by <code>replace</code>
 *   </li>
 *   <li><strong><code>RIGHT(str, len)</code></strong><br/>
 *     Returns the <code>len</code> rightmost characters of string<code>str</code>
 *   </li>
 *   <li><strong><code>RPAD(x)</code></strong><br/>
 *     Pad the right side of string <code>str</code> with copies of string <code>pad</code>,
 *     up to a total padding of <code>len</code> characters
 *   </li>
 *   <li><strong><code>SPACE(n)</code></strong><br/>
 *     Returns a string consisting of <code>n</code> whitespace characters
 *   </li>
 *   <li><strong><code>SUBSTRING(str,pos), SUBSTRING(str,pos,len)</code></strong><br/>
 *     For two arguments, returns the substring of <code>str</code> starting at position
 *     <code>pos</code> and continuing to the end of the string.<br/>
 *     For three arguments, returns the substring of <code>str</code> of length <code>len</code>,
 *     beginning at position <code>pos</code>
 *   </li>
 *   <li><strong><code>UPPER(str), UCASE(str</code></strong><br/>
 *     Returns the string <code>str</code> mapped to uppercase letters
 *   </li>
 *   </ul>
 *
 *    <h2>Color Functions</h2>
 *    <p>Functions for generating, translating, and interpolating color values.</p>
 *   <ul>
 *   <li><strong><code>RGB(r, g, b)</code></strong><br/>
 *     Returns an integer representing a fully opaque RGB (red, green, blue) color value
 *   </li>
 *   <li><strong><code>RGBA(r, g, b, a)</code></strong><br/>
 *     Returns an integer representing an RGBA (red, green, blue, alpha/transparency) color value
 *   </li>
 *   <li><strong><code>GRAY(v)</code></strong><br/>
 *     Returns an integer representing a grayscale color value of intensity <code>v</code>
 *   </li>
 *   <li><strong><code>HEX(hex)</code></strong><br/>
 *     Returns an integer representing the RGB color value encoded by the hexadecimal number
 *     <code>hex</code>
 *   </li>
 *   <li><strong><code>HSB(h, s, b)</code></strong><br/>
 *     Maps the given hue (<code>hue</code>), saturation (<code>s</code>), and brightness
 *     (<code>b</code>) color space values (as floating point numbers between 0 and 1) to
 *     an integer representing an RGB color value
 *   </li>
 *   <li><strong><code>HSBA(h, s, b, a)</code></strong><br/>
 *     Maps the given hue (<code>hue</code>), saturation (<code>s</code>), brightness
 *     (<code>b</code>), and alpha (<code>a</code>) color space values (as floating point
 *     numbers between 0 and 1) to an integer representing an RGBA color value
 *   </li>
 *   <li><strong><code>COLORINTERP(c1, c2, f)</code></strong><br/>
 *     Returns an interpolated color value between the input colors <code>c1</code> and
 *     <code>c2</code> determined by the mixing proportion <code>f</code>, a value
 *     between 0 and 1
 *   </li>
 *   </ul>
 *   
 *   <h2>Visualization Functions</h2>
 *   <p>These functions can only be used when the Tuple being evaluated is
 *    a VisualItem, and provide access to data group information of the VisualItem's
 *    Visualization. Individual visual data fields can be accessed directly using
 *    a data field reference. For example, <code>_x</code>, <code>_y</code>,
 *    <code>_hover</code>, <code>_highlight</code>, <code>_fillColor</code> would
 *    evaluate to references for the x-coordinate, y-coordinate, mouse hover status,
 *    highlight status, and fill color, respectively.</p>
 *   <ul>
 *   <li><strong><code>GROUPSIZE(group)</code></strong><br/>
 *     Returns the number of members in the data group <code>group</code>
 *   </li>
 *   <li><strong><code>INGROUP(group)</code></strong><br/>
 *     Returns true if the current VisualItem is a member of data group <code>group</code>
 *   </li>
 *   <li><strong><code>MATCH(group, includeAll)</code></strong><br/>
 *     Returns true if the current VisualItem is currently a search match. This is similar
 *     to <code>INGROUP(group)</code>, but also includes a possible special case when no
 *     query has been issued and all items should be counted as "matches" (indicated
 *     by <code>includeAll</code> being true).
 *   </li>
 *   <li><strong><code>QUERY(group)</code></strong><br/>
 *     Returns the current search query string in a search group of name <code>group</code>
 *   </li>
 *   <li><strong><code>VISIBLE()</code></strong><br/>
 *     Returns true if the current VisualItem is visible, equivalent to <code>_visible</code>
 *   </li>
 *   <li><strong><code>VALIDATED()</code></strong><br/>
 *     Returns true if the current VisualItem's bounds have been validated,
 *     equivalent to <code>_validated</code>
 *   </li>
 *   </ul>
 * 
 * @author <a href="http://jheer.org">jeffrey heer</a>
 */
public class ExpressionParser implements ExpressionParserConstants {

        private static final Logger s_logger
            = Logger.getLogger(ExpressionParser.class.getName());

    private static boolean s_init = false;
    private static Throwable s_error;

    /**
     * Parse an expression.
     * @param expr the expression text to parse
     * @param throwsException true if this method should throw an
     * exception if an error occurs or should fail quietly
     * @return the parsed Expression, or null if the parse failed
     * and throwsException is false
     */
    public synchronized static Expression parse(String expr,
                                                boolean throwsException)
    {
        // initialize the parser
        if ( !s_init ) {
            new ExpressionParser(new StringReader(expr));
            s_init = true;
        } else {
            ExpressionParser.ReInit(new StringReader(expr));
        }
        // attempt to parse the expression
        try {
            Expression e = Parse();
            s_error = null;
            s_logger.info("Parsed Expression: "+e);
            return e;
        } catch ( ParseException t ) {
            s_error = t;
            if ( throwsException ) {
                throw t;
            } else {
                s_logger.warning("Expression Parse Error: " + t.getMessage()
                        + "\n" + StringLib.getStackTrace(t));
                return null;
            }
        }
    }

    /**
     * Parse an expression. This method does not throw an exception if
     * a parse error occurs. Use {@link #getError()} to access any
     * generated exceptions.
     * @param expr the expression text to parse
     * @return the parsed Expression, or null if the parse failed
     */
    public synchronized static Expression parse(String expr) {
        return parse(expr, false);
    }
    
    /**
     * Parse an expression as a predicate. This method does not throw an
     * exception if a parse error occurs. Use {@link #getError()} to access
     * any generated exceptions.
     * @param expr the expression text to parse
     * @return the parsed Expression, or null if the parse failed
     */
    public synchronized static Predicate predicate(String expr) {
        Expression ex = parse(expr, false);
        if ( ex == null ) {
            return null;
        } else if ( ex instanceof Predicate ) {
            return (Predicate) ex;
        } else {
            s_error = new ClassCastException("Expression is not a predicate");
            return null;
        }
    }

    /**
     * Get the last error, if any, generated by a parse operation.
     * @return the last error generated during parsing
     */
    public synchronized static Throwable getError() {
        return s_error;
    }

    /**
     * Replace escape sequences with represented characters. This
     * includes newlines, tabs, and quotes.
     * @param s the input String, possibly with escape sequences
     * @return a String with recognized escape sequences properly replaced
     */
    private static String unescape(String s) {
        int len = s.length(), base = 0, idx;
        String escapes = "tnrbf\\\"'";
        String chars = "\t\n\r\b\f\\\"'";

        StringBuffer sbuf = null;

        while ( (idx=s.indexOf('\\',base)) != -1) {
            if ( sbuf != null )
                sbuf.append(s.substring(base, idx));

            if (idx+1 == len) break;

            // find escape character
            char c = s.charAt(idx+1);

            // find the index of the escape character
            int cidx = escapes.indexOf(c);
            if (cidx == -1) {
                // no match, so continue
                sbuf.append('\\');
                sbuf.append(c);
            } else {
                // replace escape sequence with true char
                if ( sbuf == null )
                    sbuf = new StringBuffer(s.substring(base, idx));
                sbuf.append(chars.charAt(cidx));
            }

            // skip over escape sequence
            base = idx + 2;
        }
        if ( sbuf != null && base < len )
            sbuf.append(s.substring(base));

        return ( sbuf == null ? s : sbuf.toString() );
    }

  // ----------------------------------------------------------------------------
  // Grammar definitions
  static final public String Name() throws ParseException {
  Token t;
    t = jj_consume_token(IDENTIFIER);
                   {if (true) return t.image;}
    throw new Error("Missing return statement in function");
  }

  static final public String Quoted() throws ParseException {
  Token t;
    t = jj_consume_token(QUOTED);
               {if (true) return t.image.substring(1,t.image.length()-1);}
    throw new Error("Missing return statement in function");
  }

  static final public Expression Parse() throws ParseException {
  Expression e;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case TRUE:
    case FALSE:
    case NULL:
    case IF:
    case NOT:
    case INT:
    case LONG:
    case DOUBLE:
    case FLOAT:
    case STRING:
    case QUOTED:
    case IDENTIFIER:
    case LPAREN:
    case ADD:
    case SUB:
      e = Expression();
      jj_consume_token(0);
                         {if (true) return e;}
      break;
    case 0:
      jj_consume_token(0);
          {if (true) throw new ParseException("No expression provided");}
      break;
    default:
      jj_la1[0] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  static final public Expression Expression() throws ParseException {
  Expression e;
    e = OrExpression();
                     {if (true) return e;}
    throw new Error("Missing return statement in function");
  }

  static final public Expression OrExpression() throws ParseException {
  Expression l, r;
    l = XorExpression();
    label_1:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case OR:
        ;
        break;
      default:
        jj_la1[1] = jj_gen;
        break label_1;
      }
      jj_consume_token(OR);
      r = XorExpression();
      if ( l instanceof OrPredicate ) {
          ((OrPredicate)l).add((Predicate)r);
      } else {
          l = new OrPredicate((Predicate)l,(Predicate)r);
      }
    }
       {if (true) return l;}
    throw new Error("Missing return statement in function");
  }

  static final public Expression XorExpression() throws ParseException {
  Expression l, r;
    l = AndExpression();
    label_2:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case XOR:
        ;
        break;
      default:
        jj_la1[2] = jj_gen;
        break label_2;
      }
      jj_consume_token(XOR);
      r = AndExpression();
      if ( l instanceof XorPredicate ) {
          ((XorPredicate)l).add((Predicate)r);
      } else {
          l = new XorPredicate((Predicate)l,(Predicate)r);
      }
    }
       {if (true) return l;}
    throw new Error("Missing return statement in function");
  }

  static final public Expression AndExpression() throws ParseException {
  Expression l, r;
    l = EqualityExpression();
    label_3:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case AND:
        ;
        break;
      default:
        jj_la1[3] = jj_gen;
        break label_3;
      }
      jj_consume_token(AND);
      r = EqualityExpression();
      if ( l instanceof AndPredicate ) {
          ((AndPredicate)l).add((Predicate)r);
      } else {
          l = new AndPredicate((Predicate)l,(Predicate)r);
      }
    }
       {if (true) return l;}
    throw new Error("Missing return statement in function");
  }

  static final public Expression EqualityExpression() throws ParseException {
  Expression l, r; Token t; int op;
    l = RelationalExpression();
    label_4:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case EQ:
      case NE:
        ;
        break;
      default:
        jj_la1[4] = jj_gen;
        break label_4;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case EQ:
        t = jj_consume_token(EQ);
        break;
      case NE:
        t = jj_consume_token(NE);
        break;
      default:
        jj_la1[5] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      r = RelationalExpression();
      op = (t.kind==EQ ? ComparisonPredicate.EQ : ComparisonPredicate.NEQ);
      l = new ComparisonPredicate(op, l, r);
    }
           {if (true) return l;}
    throw new Error("Missing return statement in function");
  }

  static final public Expression RelationalExpression() throws ParseException {
  Expression l, r; Token t; int op=-1;
    l = AdditiveExpression();
    label_5:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case GT:
      case LT:
      case LE:
      case GE:
        ;
        break;
      default:
        jj_la1[6] = jj_gen;
        break label_5;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case LT:
        t = jj_consume_token(LT);
        break;
      case GT:
        t = jj_consume_token(GT);
        break;
      case LE:
        t = jj_consume_token(LE);
        break;
      case GE:
        t = jj_consume_token(GE);
        break;
      default:
        jj_la1[7] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      r = AdditiveExpression();
      switch ( t.kind ) {
      case LT:
          op = ComparisonPredicate.LT;
          break;
      case GT:
          op = ComparisonPredicate.GT;
          break;
      case LE:
          op = ComparisonPredicate.LTEQ;
          break;
      case GE:
          op = ComparisonPredicate.GTEQ;
          break;
      }
      l = new ComparisonPredicate(op, l, r);
    }
           {if (true) return l;}
    throw new Error("Missing return statement in function");
  }

  static final public Expression AdditiveExpression() throws ParseException {
  Expression l, r; Token t; int op=-1;
    l = MultiplicativeExpression();
    label_6:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ADD:
      case SUB:
      case MOD:
        ;
        break;
      default:
        jj_la1[8] = jj_gen;
        break label_6;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ADD:
        t = jj_consume_token(ADD);
        break;
      case SUB:
        t = jj_consume_token(SUB);
        break;
      case MOD:
        t = jj_consume_token(MOD);
        break;
      default:
        jj_la1[9] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      r = MultiplicativeExpression();
      switch ( t.kind ) {
      case ADD:
        op = ArithmeticExpression.ADD;
        break;
      case SUB:
        op = ArithmeticExpression.SUB;
        break;
      case MOD:
        op = ArithmeticExpression.MOD;
        break;
      }
      l = new ArithmeticExpression(op, l, r);
    }
           {if (true) return l;}
    throw new Error("Missing return statement in function");
  }

  static final public Expression MultiplicativeExpression() throws ParseException {
  Expression l, r; Token t; int op=-1;
    l = UnaryExpression();
    label_7:
    while (true) {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case MUL:
      case DIV:
      case POW:
        ;
        break;
      default:
        jj_la1[10] = jj_gen;
        break label_7;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case MUL:
        t = jj_consume_token(MUL);
        break;
      case DIV:
        t = jj_consume_token(DIV);
        break;
      case POW:
        t = jj_consume_token(POW);
        break;
      default:
        jj_la1[11] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      r = UnaryExpression();
      switch ( t.kind ) {
      case MUL:
        op = ArithmeticExpression.MUL;
        break;
      case DIV:
        op = ArithmeticExpression.DIV;
        break;
      case POW:
        op = ArithmeticExpression.POW;
        break;
      }
      l = new ArithmeticExpression(op, l, r);
    }
           {if (true) return l;}
    throw new Error("Missing return statement in function");
  }

  static final public Expression UnaryExpression() throws ParseException {
  Expression e; Token t;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case ADD:
    case SUB:
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case ADD:
        t = jj_consume_token(ADD);
        break;
      case SUB:
        t = jj_consume_token(SUB);
        break;
      default:
        jj_la1[12] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      e = UnaryExpression();
        if ( t.kind == SUB  && e instanceof NumericLiteral ) {
          Number n = (Number)e.get(null);
          if ( n instanceof Integer ) {
              {if (true) return new NumericLiteral(-1*n.intValue());}
          } if ( n instanceof Double ) {
              {if (true) return new NumericLiteral(-1*n.doubleValue());}
          } if ( n instanceof Long ) {
              {if (true) return new NumericLiteral(-1*n.longValue());}
          } if ( n instanceof Float ) {
              {if (true) return new NumericLiteral(-1*n.floatValue());}
          } else {
              {if (true) return new ArithmeticExpression(ArithmeticExpression.MUL,
                                              new NumericLiteral(-1), e);}
          }
        } else if ( t.kind == SUB ) {
          {if (true) return new ArithmeticExpression(ArithmeticExpression.MUL,
                                          new NumericLiteral(-1), e);}
        } else {
          {if (true) return e;}
        }
      break;
    case NOT:
      e = UnaryExpressionNotPlusMinus();
                                      {if (true) return e;}
      break;
    case TRUE:
    case FALSE:
    case NULL:
    case IF:
    case INT:
    case LONG:
    case DOUBLE:
    case FLOAT:
    case STRING:
    case QUOTED:
    case IDENTIFIER:
    case LPAREN:
      e = PrimaryExpression();
                            {if (true) return e;}
      break;
    default:
      jj_la1[13] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  static final public Expression UnaryExpressionNotPlusMinus() throws ParseException {
  Expression e;
    jj_consume_token(NOT);
    e = UnaryExpression();
        if ( e instanceof NotPredicate ) {
            {if (true) return ((NotPredicate)e).getPredicate();}
        } else {
            if ( !(e instanceof Predicate) ) {
                {if (true) throw new ParseException("Can't negate a non-predicate");}
            } else {
                {if (true) return new NotPredicate((Predicate)e);}
            }
        }
    throw new Error("Missing return statement in function");
  }

  static final public Expression PrimaryExpression() throws ParseException {
  Expression e;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case TRUE:
    case FALSE:
    case NULL:
    case INT:
    case LONG:
    case DOUBLE:
    case FLOAT:
    case STRING:
      e = Literal();
                  {if (true) return e;}
      break;
    case IF:
      e = IfStatement();
                      {if (true) return e;}
      break;
    case QUOTED:
    case IDENTIFIER:
      e = Identifier();
                     {if (true) return e;}
      break;
    case LPAREN:
      jj_consume_token(LPAREN);
      e = Expression();
      jj_consume_token(RPAREN);
                                       {if (true) return e;}
      break;
    default:
      jj_la1[14] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  static final public Expression Literal() throws ParseException {
  Token t;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case INT:
      t = jj_consume_token(INT);
              {if (true) return new NumericLiteral(Integer.parseInt(t.image));}
      break;
    case LONG:
      t = jj_consume_token(LONG);
               {if (true) return new NumericLiteral(Long.parseLong(t.image));}
      break;
    case FLOAT:
      t = jj_consume_token(FLOAT);
                {if (true) return new NumericLiteral(Float.parseFloat(t.image));}
      break;
    case DOUBLE:
      t = jj_consume_token(DOUBLE);
                 {if (true) return new NumericLiteral(Double.parseDouble(t.image));}
      break;
    case STRING:
      t = jj_consume_token(STRING);
                String s = unescape(t.image.substring(1, t.image.length()-1));
                {if (true) return new ObjectLiteral(s);}
      break;
    case TRUE:
      jj_consume_token(TRUE);
             {if (true) return new BooleanLiteral(true);}
      break;
    case FALSE:
      jj_consume_token(FALSE);
              {if (true) return new BooleanLiteral(false);}
      break;
    case NULL:
      jj_consume_token(NULL);
             {if (true) return new ObjectLiteral(null);}
      break;
    default:
      jj_la1[15] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  static final public Expression Identifier() throws ParseException {
  String s; Function f=null; Expression e;
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case QUOTED:
      s = Quoted();
                 {if (true) return new ColumnExpression(s);}
      break;
    case IDENTIFIER:
      s = Name();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case LPAREN:
        jj_consume_token(LPAREN);
                 f = FunctionTable.createFunction(s);
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case TRUE:
        case FALSE:
        case NULL:
        case IF:
        case NOT:
        case INT:
        case LONG:
        case DOUBLE:
        case FLOAT:
        case STRING:
        case QUOTED:
        case IDENTIFIER:
        case LPAREN:
        case ADD:
        case SUB:
          e = Expression();
                         f.addParameter(e);
          label_8:
          while (true) {
            switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
            case 43:
              ;
              break;
            default:
              jj_la1[16] = jj_gen;
              break label_8;
            }
            jj_consume_token(43);
            e = Expression();
                              f.addParameter(e);
          }
          break;
        default:
          jj_la1[17] = jj_gen;
          ;
        }
        jj_consume_token(RPAREN);
        break;
      default:
        jj_la1[18] = jj_gen;
        ;
      }
      {if (true) return f==null ? new ColumnExpression(s) : (Expression)f;}
      break;
    default:
      jj_la1[19] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
    throw new Error("Missing return statement in function");
  }

  static final public Expression IfStatement() throws ParseException {
  Expression p, t, e;
    jj_consume_token(IF);
    p = Expression();
    jj_consume_token(THEN);
    t = Expression();
    jj_consume_token(ELSE);
    e = Expression();
      if ( !(p instanceof Predicate) )
          {if (true) throw new ParseException("IF-statement test must be a predicate");}
      {if (true) return new IfExpression((Predicate)p, t, e);}
    throw new Error("Missing return statement in function");
  }

  static private boolean jj_initialized_once = false;
  static public ExpressionParserTokenManager token_source;
  static JavaCharStream jj_input_stream;
  static public Token token, jj_nt;
  static private int jj_ntk;
  static private int jj_gen;
  static final private int[] jj_la1 = new int[20];
  static private int[] jj_la1_0;
  static private int[] jj_la1_1;
  static {
      jj_la1_0();
      jj_la1_1();
   }
   private static void jj_la1_0() {
      jj_la1_0 = new int[] {0x277143c1,0x2000,0x8000,0x1000,0x80000000,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x277143c0,0x277103c0,0x17101c0,0x0,0x277143c0,0x20000000,0x6000000,};
   }
   private static void jj_la1_1() {
      jj_la1_1 = new int[] {0x60,0x0,0x0,0x0,0x10,0x10,0xf,0xf,0x460,0x460,0x380,0x380,0x60,0x60,0x0,0x0,0x800,0x60,0x0,0x0,};
   }

  public ExpressionParser(java.io.InputStream stream) {
    if (jj_initialized_once) {
      System.out.println("ERROR: Second call to constructor of static parser.  You must");
      System.out.println("       either use ReInit() or set the JavaCC option STATIC to false");
      System.out.println("       during parser generation.");
      throw new Error();
    }
    jj_initialized_once = true;
    jj_input_stream = new JavaCharStream(stream, 1, 1);
    token_source = new ExpressionParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 20; i++) jj_la1[i] = -1;
  }

  static public void ReInit(java.io.InputStream stream) {
    jj_input_stream.ReInit(stream, 1, 1);
    ExpressionParserTokenManager.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 20; i++) jj_la1[i] = -1;
  }

  public ExpressionParser(java.io.Reader stream) {
    if (jj_initialized_once) {
      System.out.println("ERROR: Second call to constructor of static parser.  You must");
      System.out.println("       either use ReInit() or set the JavaCC option STATIC to false");
      System.out.println("       during parser generation.");
      throw new Error();
    }
    jj_initialized_once = true;
    jj_input_stream = new JavaCharStream(stream, 1, 1);
    token_source = new ExpressionParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 20; i++) jj_la1[i] = -1;
  }

  static public void ReInit(java.io.Reader stream) {
    jj_input_stream.ReInit(stream, 1, 1);
    ExpressionParserTokenManager.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 20; i++) jj_la1[i] = -1;
  }

  public ExpressionParser(ExpressionParserTokenManager tm) {
    if (jj_initialized_once) {
      System.out.println("ERROR: Second call to constructor of static parser.  You must");
      System.out.println("       either use ReInit() or set the JavaCC option STATIC to false");
      System.out.println("       during parser generation.");
      throw new Error();
    }
    jj_initialized_once = true;
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 20; i++) jj_la1[i] = -1;
  }

  public void ReInit(ExpressionParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 20; i++) jj_la1[i] = -1;
  }

  static final private Token jj_consume_token(int kind) throws ParseException {
    Token oldToken;
    if ((oldToken = token).next != null) token = token.next;
    else token = token.next = ExpressionParserTokenManager.getNextToken();
    jj_ntk = -1;
    if (token.kind == kind) {
      jj_gen++;
      return token;
    }
    token = oldToken;
    jj_kind = kind;
    throw generateParseException();
  }

  static final public Token getNextToken() {
    if (token.next != null) token = token.next;
    else token = token.next = ExpressionParserTokenManager.getNextToken();
    jj_ntk = -1;
    jj_gen++;
    return token;
  }

  static final public Token getToken(int index) {
    Token t = token;
    for (int i = 0; i < index; i++) {
      if (t.next != null) t = t.next;
      else t = t.next = ExpressionParserTokenManager.getNextToken();
    }
    return t;
  }

  static final private int jj_ntk() {
    if ((jj_nt=token.next) == null)
      return (jj_ntk = (token.next=ExpressionParserTokenManager.getNextToken()).kind);
    else
      return (jj_ntk = jj_nt.kind);
  }

  static private java.util.Vector jj_expentries = new java.util.Vector();
  static private int[] jj_expentry;
  static private int jj_kind = -1;

  static public ParseException generateParseException() {
    jj_expentries.removeAllElements();
    boolean[] la1tokens = new boolean[44];
    for (int i = 0; i < 44; i++) {
      la1tokens[i] = false;
    }
    if (jj_kind >= 0) {
      la1tokens[jj_kind] = true;
      jj_kind = -1;
    }
    for (int i = 0; i < 20; i++) {
      if (jj_la1[i] == jj_gen) {
        for (int j = 0; j < 32; j++) {
          if ((jj_la1_0[i] & (1<<j)) != 0) {
            la1tokens[j] = true;
          }
          if ((jj_la1_1[i] & (1<<j)) != 0) {
            la1tokens[32+j] = true;
          }
        }
      }
    }
    for (int i = 0; i < 44; i++) {
      if (la1tokens[i]) {
        jj_expentry = new int[1];
        jj_expentry[0] = i;
        jj_expentries.addElement(jj_expentry);
      }
    }
    int[][] exptokseq = new int[jj_expentries.size()][];
    for (int i = 0; i < jj_expentries.size(); i++) {
      exptokseq[i] = (int[])jj_expentries.elementAt(i);
    }
    return new ParseException(token, exptokseq, tokenImage);
  }

  static final public void enable_tracing() {
  }

  static final public void disable_tracing() {
  }

}
