/*
 * @(#)JPTParser.java    2.6.0   17 August 2007
 *
 * Copyright 2007
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.parser;

import edu.neu.ccs.*;
import edu.neu.ccs.util.*;

import java.text.*;
import java.util.*;
import java.math.*;

// debug
// import edu.neu.ccs.console.*;

/**
 * <p>Parses and evaulates data <code>String</code>s 
 * using simple expression evaluation.<p>
 *
 * <p>The grammar used in this parsing is similar to
 * that defined within the Java Language Specification
 * by James Gosling, Bill Joy, and Guy Steele but as
 * of 2.5.0 we have made significant additions to aid
 * the user of these facilities in interactive mode.</p>
 *
 * <p>As of 2.5.0, the parser algorithms have all been
 * refactored down to the new base class called
 * <code>BaseParser</code>.  The purpose of this class
 * is therefore to define and install constants,
 * operations, and functions.  Each such entity is now
 * public static final so they may be utilized by some
 * other class that extends <code>BaseParser</code> if
 * so desired.</p>
 * 
 * <p>The constants, functions, and operations are all
 * commented individually.  Summary tables of the
 * constants, functions, and operations are provided
 * immediately below and repeated in the comments for
 * the methods
 * <code>addConstants()</code>,
 * <code>addFunctions()</code>, and
 * <code>addOperations()</code>.
 * The summary tables for operations show precedence.</p>
 * 
 * <p>This class now provides an <i>exponentiation operator</i>
 * denoted <code>^</code> that attempts exponentiation
 * as an integral computation if possible.  This is in
 * contrast to the <code>power</code> function that
 * always uses <code>Math.pow</code> in its
 * implementation.  By choosing <code>^</code> or
 * <code>power</code>, the user may select implementation.</p>
 * 
 * <p>The function definitions continue to throw exceptions
 * if given incorrect arguments but will no longer throw
 * exceptions if mathematical errors occur.  Rather the
 * computation proceeds as in Java itself to produce either
 * an infinity or NaN.</p>
 * 
 * <p>In 2.6.0, added <i>hyperbolic</i> functions.</p>
 * 
 * <p>Constant definitions:</p>
 * 
 * <table border="1" cellpadding="5">
 *   <tr>
 *     <td style="text-align:center"><b>Identifier</b></td>
 *     <td style="text-align:center"><b>Type</b></td>
 *     <td style="text-align:center"><b>Definition</b></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>true</code></td>
 *     <td style="text-align:center"><code>XBoolean</code></td>
 *     <td style="text-align:center"><code>true</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>false</code></td>
 *     <td style="text-align:center"><code>XBoolean</code></td>
 *     <td style="text-align:center"><code>false</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>pi</code></td>
 *     <td style="text-align:center"><code>XDouble</code></td>
 *     <td style="text-align:center"><code>Math.PI</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>e</code></td>
 *     <td style="text-align:center"><code>XDouble</code></td>
 *     <td style="text-align:center"><code>Math.E</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>MaxInt</code></td>
 *     <td style="text-align:center"><code>XInt</code></td>
 *     <td style="text-align:center"><code>Integer.MAX_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>maxint</code></td>
 *     <td style="text-align:center"><code>XInt</code></td>
 *     <td style="text-align:center"><code>Integer.MAX_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>MinInt</code></td>
 *     <td style="text-align:center"><code>XInt</code></td>
 *     <td style="text-align:center"><code>Integer.MIN_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>minint</code></td>
 *     <td style="text-align:center"><code>XInt</code></td>
 *     <td style="text-align:center"><code>Integer.MIN_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>MaxLong</code></td>
 *     <td style="text-align:center"><code>XLong</code></td>
 *     <td style="text-align:center"><code>Long.MAX_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>maxlong</code></td>
 *     <td style="text-align:center"><code>XLong</code></td>
 *     <td style="text-align:center"><code>Long.MAX_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>MinLong</code></td>
 *     <td style="text-align:center"><code>XLong</code></td>
 *     <td style="text-align:center"><code>Long.MIN_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>minlong</code></td>
 *     <td style="text-align:center"><code>XLong</code></td>
 *     <td style="text-align:center"><code>Long.MIN_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>MaxDouble</code></td>
 *     <td style="text-align:center"><code>XDouble</code></td>
 *     <td style="text-align:center"><code>Double.MAX_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>maxdouble</code></td>
 *     <td style="text-align:center"><code>XDouble</code></td>
 *     <td style="text-align:center"><code>Double.MAX_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>MinDouble</code></td>
 *     <td style="text-align:center"><code>XDouble</code></td>
 *     <td style="text-align:center"><code>Double.MIN_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>mindouble</code></td>
 *     <td style="text-align:center"><code>XDouble</code></td>
 *     <td style="text-align:center"><code>Double.MIN_VALUE</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>Infinity</code></td>
 *   <td style="text-align:center"><code>XDouble</code></td>
 *     <td style="text-align:center"><code>Double.POSITIVE_INFINITY</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>infinity</code></td>
 *     <td style="text-align:center"><code>XDouble</code></td>
 *     <td style="text-align:center"><code>Double.POSITIVE_INFINITY</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>NaN</code></td>
 *     <td style="text-align:center"><code>XDouble</code></td>
 *     <td style="text-align:center"><code>Double.NaN</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>nan</code></td>
 *     <td style="text-align:center"><code>XDouble</code></td>
 *     <td style="text-align:center"><code>Double.NaN</code></td>
 *   </tr>
 * </table>
 * 
 * <p>Function definitions:</p>
 * 
 * <table border="1" cellpadding="5">
 *   <tr>
 *     <td style="text-align:center"><b>Function Name</b></td>
 *     <td style="text-align:center"><b>Typical Usage</b></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>abs</code></td>
 *     <td style="text-align:center"><code>abs(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>ceiling</code></td>
 *     <td style="text-align:center"><code>ceiling(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>floor</code></td>
 *     <td style="text-align:center"><code>floor(x)</code></td>
 *   <tr>
 *     <td style="text-align:center"><code>round</code></td>
 *     <td style="text-align:center"><code>round(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>max</code></td>
 *     <td style="text-align:center"><code>max(x,y)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>min</code></td>
 *     <td style="text-align:center"><code>min(x,y)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>sqrt</code></td>
 *     <td style="text-align:center"><code>sqrt(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>power</code></td>
 *     <td style="text-align:center"><code>power(x,y)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>root</code></td>
 *     <td style="text-align:center"><code>root(x,y)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>todegrees</code></td>
 *     <td style="text-align:center"><code>todegrees(theta)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>toradians</code></td>
 *     <td style="text-align:center"><code>toradians(angle)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>sin</code></td>
 *     <td style="text-align:center"><code>sin(theta)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>sindeg</code></td>
 *     <td style="text-align:center"><code>sindeg(angle)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>cos</code></td>
 *     <td style="text-align:center"><code>cos(theta)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>cosdeg</code></td>
 *     <td style="text-align:center"><code>cosdeg(angle)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>tan</code></td>
 *     <td style="text-align:center"><code>tan(theta)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>tandeg</code></td>
 *     <td style="text-align:center"><code>tandeg(angle)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>asin</code></td>
 *     <td style="text-align:center"><code>asin(s)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>asindeg</code></td>
 *     <td style="text-align:center"><code>asindeg(s)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>acos</code></td>
 *     <td style="text-align:center"><code>acos(c)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>acosdeg</code></td>
 *     <td style="text-align:center"><code>acosdeg(c)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>atan</code></td>
 *     <td style="text-align:center"><code>atan(t)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>atandeg(t)</code></td>
 *     <td style="text-align:center"><code>atandeg(t)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>atan2</code></td>
 *     <td style="text-align:center"><code>atan2(y,x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>atan2deg</code></td>
 *     <td style="text-align:center"><code>atan2deg(y,x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>exp</code></td>
 *     <td style="text-align:center"><code>exp(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>log</code></td>
 *     <td style="text-align:center"><code>log(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>ln</code></td>
 *     <td style="text-align:center"><code>ln(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>log2</code></td>
 *     <td style="text-align:center"><code>log2(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>log10</code></td>
 *     <td style="text-align:center"><code>log10(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>logtobase</code></td>
 *     <td style="text-align:center"><code>logtobase(x,b)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>sinh</code></td>
 *     <td style="text-align:center"><code>sinh(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>cosh</code></td>
 *     <td style="text-align:center"><code>cosh(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>tanh</code></td>
 *     <td style="text-align:center"><code>tanh(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>asinh</code></td>
 *     <td style="text-align:center"><code>asinh(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>acosh</code></td>
 *     <td style="text-align:center"><code>acosh(x)</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>atanh</code></td>
 *     <td style="text-align:center"><code>atanh(x)</code></td>
 *   </tr>
 * </table>
 * 
 * <p>In the above table:<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;<code>x</code> and <code>y</code>
 *   stand for generic variables;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;<code>theta</code>
 *   is an angle in radians;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;<code>angle</code>
 *   is an angle in degrees;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;
 *   <code>s</code>, <code>c</code>, <code>t</code>
 *   stand for possible values of
 *   <code>sin</code>, <code>cos</code>, <code>tan</code>;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;and <code>b</code>
 *   is the base for a logarithm.</p>
 * 
 * <p>In 2.5.0, <code>random</code> was removed from the
 * list of functions because as implemented in the class
 * <code>AbstractFunction</code> a function has a fixed
 * number of arguments.  Instead, <code>random</code> is
 * now implemented directly in <code>BaseParser</code>
 * to take one of three forms with the following
 * interpretations.</p>
 * 
 * <table border="1" cellpadding="5">
 *   <tr>
 *     <td style="text-align:center"><b>Function Name</b></td>
 *     <td style="text-align:center"><b>Typical Usage</b></td>
 *     <td style="text-align:center"><b>Interpretation</b></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>random</code></td>
 *     <td style="text-align:center"><code>random()</code></td>
 *     <td>Random number between 0 and 1</td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>random</code></td>
 *     <td style="text-align:center"><code>random(x)</code></td>
 *     <td>Random number between 0 and x</td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center"><code>random</code></td>
 *     <td style="text-align:center"><code>random(x,y)</code></td>
 *     <td>Random number between x and y</td>
 *   </tr>
 * </table>
 * 
 * <p>Operation definitions:</p>
 * 
 * <table border="1" cellpadding="5">
 *   <tr>
 *     <td style="text-align:center"><b>Precedence</b></td>
 *     <td style="text-align:center"><b>Operations</b></td>
 *     <td style="text-align:center"><b>Symbols</b></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center">0</td>
 *     <td style="text-align:center"><code>IDENTITY</code></td>
 *     <td style="text-align:center"><code>None</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center">1</td>
 *     <td style="text-align:center"><code>operationOR</code></td>
 *     <td style="text-align:center"><code>||</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center">2</td>
 *     <td style="text-align:center"><code>operationAND</code></td>
 *     <td style="text-align:center"><code>&amp;&amp;</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center">3</td>
 *     <td style="text-align:center"><code>operationEQ<br />operationNE</code></td>
 *     <td style="text-align:center"><code>==<br />!=</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center">4</td>
 *     <td style="text-align:center"><code>operationLT<br />operationGT<br />operationLE<br />operationGE</code></td>
 *     <td style="text-align:center"><code>&lt;<br />&gt;<br />&lt;=<br />&gt;=</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center">5</td>
 *     <td style="text-align:center"><code>operationPlus<br />operationMinus</code></td>
 *     <td style="text-align:center"><code>+<br />-</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center">6</td>
 *     <td style="text-align:center"><code>operationTimes<br />operationSlash<br />operationPercent</code></td>
 *     <td style="text-align:center"><code>*<br />/<br />%</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center">7</td>
 *     <td style="text-align:center"><code>operationCaret</code></td>
 *     <td style="text-align:center"><code>^</code></td>
 *   </tr>
 *   <tr>
 *     <td style="text-align:center">8</td>
 *     <td style="text-align:center"><code>operationNOT</code></td>
 *     <td style="text-align:center"><code>!</code></td>
 *   </tr>
 * </table>
 * 
 * @author  Richard Rasala
 * @author  Jeff Raab
 * @version 2.6.0
 * @since   1.0
 * @see <A HREF="http://java.sun.com/docs/books/jls/html/index.html">
 *      Java Language Specification</A> 
 */
public class JPTParser 
    extends BaseParser
// debug
//    implements ConsoleAware
{
    //////////////////////////////////
    // AbstractFunction Definitions //
    //////////////////////////////////
    
    /** AbstractFunction to implement <code>abs</code>. */
    public static final AbstractFunction functionAbs =
        new AbstractFunction("abs", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            if (ParserUtilities.isXIntegral(values[0])) {
                XBigInteger a =
                    ParserUtilities.toXBigInteger((XNumber) values[0]);
                
                BigInteger va = a.getValue();
                
                int test = va.compareTo(BigInteger.ZERO);
                
                if (test >= 0)
                    return a;
                
                va = va.negate();
                
                return new XBigInteger(va);
            }
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            if (vx >= 0)
                return x;
            
            return new XDouble(-vx);
        }
    };

    
    /** AbstractFunction to implement <code>ceiling</code>. */
    public static final AbstractFunction functionCeiling =
        new AbstractFunction("ceiling", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            if (ParserUtilities.isXIntegral(values[0])) {
                XBigInteger a =
                    ParserUtilities.toXBigInteger((XNumber) values[0]);
                
                return a;
            }
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            vx = Math.ceil(vx);
            return new XDouble(vx);
        }
    };

    
    /** AbstractFunction to implement <code>floor</code>. */
    public static final AbstractFunction functionFloor =
        new AbstractFunction("floor", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            if (ParserUtilities.isXIntegral(values[0])) {
                XBigInteger a =
                    ParserUtilities.toXBigInteger((XNumber) values[0]);
                
                return a;
            }
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            vx = Math.floor(vx);
            return new XDouble(vx);
        }
    };

    
    /** AbstractFunction to implement <code>round</code>. */
    public static final AbstractFunction functionRound =
        new AbstractFunction("round", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            if (ParserUtilities.isXIntegral(values[0])) {
                XBigInteger a =
                    ParserUtilities.toXBigInteger((XNumber) values[0]);
                
                return a;
            }
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            vx = Math.rint(vx);
            return new XDouble(vx);
        }
    };

    
    /** AbstractFunction to implement <code>max</code>. */
    public static final AbstractFunction functionMax =
        new AbstractFunction("max", 2)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            if (ParserUtilities.isXIntegral(values[0]) &&
                ParserUtilities.isXIntegral(values[1]))
            {
                XBigInteger a =
                    ParserUtilities.toXBigInteger((XNumber) values[0]);
                
                XBigInteger b =
                    ParserUtilities.toXBigInteger((XNumber) values[1]);
                
                BigInteger va = a.getValue();
                BigInteger vb = b.getValue();
                
                int test = va.compareTo(vb);
                
                if (test >= 0)
                    return a;
                
                return b;
            }
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            XDouble y = ParserUtilities.toXDouble((XNumber) values[1]);
            double vx = x.getValue();
            double vy = y.getValue();
            
            if (vx >= vy)
                return x;
            
            return y;
        }
    };

    
    /** AbstractFunction to implement <code>min</code>. */
    public static final AbstractFunction functionMin =
        new AbstractFunction("min", 2)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            if (ParserUtilities.isXIntegral(values[0]) &&
                ParserUtilities.isXIntegral(values[1]))
            {
                XBigInteger a =
                    ParserUtilities.toXBigInteger((XNumber) values[0]);
                
                XBigInteger b =
                    ParserUtilities.toXBigInteger((XNumber) values[1]);
                
                BigInteger va = a.getValue();
                BigInteger vb = b.getValue();
                
                int test = va.compareTo(vb);
                
                if (test >= 0)
                    return b;
                
                return a;
            }
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            XDouble y = ParserUtilities.toXDouble((XNumber) values[1]);
            double vx = x.getValue();
            double vy = y.getValue();
            
            if (vx >= vy)
                return y;
            
            return x;
        }
    };

    
    /**
     * AbstractFunction to implement <code>sqrt</code>
     * based on <code>Math.sqrt</code>.
     */
    public static final AbstractFunction functionSqrt =
        new AbstractFunction("sqrt", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.sqrt(vx));
        }
    };

    
    /**
     * AbstractFunction to implement <code>power</code>
     * based on <code>Math.pow</code>.
     * 
     * @see #operationCaret
     */
    public static final AbstractFunction functionPower =
        new AbstractFunction("power", 2)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            XDouble y = ParserUtilities.toXDouble((XNumber) values[1]);
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XDouble(Math.pow(vx, vy));
        }
    };

    
    /**
     * AbstractFunction to implement <code>root</code>
     * based on <code>MathUtilities.root</code>.
     */
    public static final AbstractFunction functionRoot =
        new AbstractFunction("root", 2)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            XDouble y = ParserUtilities.toXDouble((XNumber) values[1]);
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XDouble(MathUtilities.root(vx, vy));
        }
    };

    
    /**
     * AbstractFunction to implement <code>todegrees</code>
     * based on <code>Math.toDegrees</code>.
     */
    public static final AbstractFunction functionToDegrees =
        new AbstractFunction("todegrees", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.toDegrees(vx));
        }
    };

    
    /**
     * AbstractFunction to implement <code>toradians</code>
     * based on <code>Math.toRadians</code>.
     */
    public static final AbstractFunction functionToRadians =
        new AbstractFunction("toradians", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.toRadians(vx));
        }
    };

    
    /**
     * AbstractFunction to implement <code>sin</code>
     * based on <code>Math.sin</code>.
     */
    public static final AbstractFunction functionSin =
        new AbstractFunction("sin", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.sin(vx));
        }
    };

    
    /**
     * AbstractFunction to implement <code>sindeg</code>
     * based on <code>Math.sin</code>
     * and appropriate degrees to radians conversion.
     */
    public static final AbstractFunction functionSinDeg =
        new AbstractFunction("sindeg", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.sin(Math.toRadians(vx)));
        }
    };

    
    /**
     * AbstractFunction to implement <code>cos</code>
     * based on <code>Math.cos</code>.
     */
    public static final AbstractFunction functionCos =
        new AbstractFunction("cos", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.cos(vx));
        }
    };

    
    /**
     * AbstractFunction to implement <code>cosdeg</code>
     * based on <code>Math.cos</code>
     * and appropriate degrees to radians conversion.
     */
    public static final AbstractFunction functionCosDeg =
        new AbstractFunction("cosdeg", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.cos(Math.toRadians(vx)));
        }
    };

    
    /**
     * AbstractFunction to implement <code>tan</code>
     * based on <code>Math.tan</code>.
     */
    public static final AbstractFunction functionTan =
        new AbstractFunction("tan", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.tan(vx));
        }
    };

    
    /**
     * AbstractFunction to implement <code>tandeg</code>
     * based on <code>Math.tan</code>
     * and appropriate degrees to radians conversion.
     */
    public static final AbstractFunction functionTanDeg =
        new AbstractFunction("tandeg", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.tan(Math.toRadians(vx)));
        }
    };

    
    /**
     * AbstractFunction to implement <code>asin</code>
     * based on <code>Math.asin</code>.
     */
    public static final AbstractFunction functionASin =
        new AbstractFunction("asin", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.asin(vx));
        }
    };

    
    /**
     * AbstractFunction to implement <code>asindeg</code>
     * based on <code>Math.asin</code>
     * and appropriate radians to degrees conversion.
     */
    public static final AbstractFunction functionASinDeg =
        new AbstractFunction("asindeg", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.toDegrees(Math.asin(vx)));
        }
    };

    
    /**
     * AbstractFunction to implement <code>acos</code>
     * based on <code>Math.acos</code>.
     */
    public static final AbstractFunction functionACos =
        new AbstractFunction("acos", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.acos(vx));
        }
    };

    
    /**
     * AbstractFunction to implement <code>acosdeg</code>
     * based on <code>Math.acos</code>
     * and appropriate radians to degrees conversion.
     */
    public static final AbstractFunction functionACosDeg =
        new AbstractFunction("acosdeg", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.toDegrees(Math.acos(vx)));
        }
    };

    
    /**
     * AbstractFunction to implement <code>atan</code>
     * based on <code>Math.atan</code>.
     */
    public static final AbstractFunction functionATan =
        new AbstractFunction("atan", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.atan(vx));
        }
    };

    
    /**
     * AbstractFunction to implement <code>atandeg</code>
     * based on <code>Math.atan</code>
     * and appropriate radians to degrees conversion.
     */
    public static final AbstractFunction functionATanDeg =
        new AbstractFunction("atandeg", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.toDegrees(Math.atan(vx)));
        }
    };

    
    /**
     * AbstractFunction to implement <code>atan2</code>
     * based on <code>Math.atan2</code>.
     */
    public static final AbstractFunction functionATan2 =
        new AbstractFunction("atan2", 2)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            // note that for atan2, y precedes x
            XDouble y = ParserUtilities.toXDouble((XNumber) values[0]);
            XDouble x = ParserUtilities.toXDouble((XNumber) values[1]);
            double vy = y.getValue();
            double vx = x.getValue();
            
            return new XDouble(Math.atan2(vy, vx));
        }
    };

    
    /**
     * AbstractFunction to implement <code>atan2deg</code>
     * based on <code>Math.atan2</code>
     * and appropriate radians to degrees conversion.
     */
    public static final AbstractFunction functionATan2Deg =
        new AbstractFunction("atan2deg", 2)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            // note that for atan2deg, y precedes x
            XDouble y = ParserUtilities.toXDouble((XNumber) values[0]);
            XDouble x = ParserUtilities.toXDouble((XNumber) values[1]);
            double vy = y.getValue();
            double vx = x.getValue();
            
            return new XDouble(Math.toDegrees(Math.atan2(vy, vx)));
        }
    };

    
    /**
     * AbstractFunction to implement <code>exp</code>
     * based on <code>Math.exp</code>.
     */
    public static final AbstractFunction functionExp =
        new AbstractFunction("exp", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.exp(vx));
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>log</code>
     * based on <code>Math.log</code>.</p>
     * 
     * <p>This is identical to <code>ln</code>.</p>
     */
    public static final AbstractFunction functionLog =
        new AbstractFunction("log", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.log(vx));
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>ln</code>
     * based on <code>Math.log</code>.</p>
     * 
     * <p>This is identical to <code>log</code>.</p>
     */
    public static final AbstractFunction functionLn =
        new AbstractFunction("ln", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.log(vx));
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>log2</code>.<p>
     * 
     * <p><code>log2(x)</code> is computed as:</p>
     * 
     * <p><code>Math.log(x) / Math.log(2)</code></p>
     */
    public static final AbstractFunction functionLog2 =
        new AbstractFunction("log2", 1)
    {
        private final double log2 = Math.log(2);
        
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.log(vx) / log2);
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>log10</code>.<p>
     * 
     * <p><code>log10(x)</code> is computed as:</p>
     * 
     * <p><code>Math.log(x) / Math.log(10)</code></p>
     */
    public static final AbstractFunction functionLog10 =
        new AbstractFunction("log10", 1)
    {
        private final double log10 = Math.log(10);
        
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(Math.log(vx) / log10);
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>logtobase</code>.<p>
     * 
     * <p><code>logtobase(x,b)</code> is computed as:</p>
     * 
     * <p><code>Math.log(x) / Math.log(b)</code></p>
     */
    public static final AbstractFunction functionLogToBase =
        new AbstractFunction("logtobase", 2)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            XDouble b = ParserUtilities.toXDouble((XNumber) values[1]);
            double vx = x.getValue();
            double vb = b.getValue();
            
            return new XDouble(Math.log(vx) / Math.log(vb));
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>sinh</code>.<p>
     * 
     * <p><code>sinh(x)</code> is computed as:</p>
     * 
     * <p><code>MathUtilities.sinh(x)</code></p>
     */
    public static final AbstractFunction functionSinh =
        new AbstractFunction("sinh", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(MathUtilities.sinh(vx));
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>cosh</code>.<p>
     * 
     * <p><code>cosh(x)</code> is computed as:</p>
     * 
     * <p><code>MathUtilities.cosh(x)</code></p>
     */
    public static final AbstractFunction functionCosh =
        new AbstractFunction("cosh", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(MathUtilities.cosh(vx));
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>tanh</code>.<p>
     * 
     * <p><code>tanh(x)</code> is computed as:</p>
     * 
     * <p><code>MathUtilities.tanh(x)</code></p>
     */
    public static final AbstractFunction functionTanh =
        new AbstractFunction("tanh", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(MathUtilities.tanh(vx));
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>asinh</code>.<p>
     * 
     * <p><code>asinh(x)</code> is computed as:</p>
     * 
     * <p><code>MathUtilities.asinh(x)</code></p>
     */
    public static final AbstractFunction functionASinh =
        new AbstractFunction("asinh", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(MathUtilities.asinh(vx));
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>acosh</code>.<p>
     * 
     * <p><code>acosh(x)</code> is computed as:</p>
     * 
     * <p><code>MathUtilities.acosh(x)</code></p>
     */
    public static final AbstractFunction functionACosh =
        new AbstractFunction("acosh", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(MathUtilities.acosh(vx));
        }
    };

    
    /**
     * <p>AbstractFunction to implement <code>atanh</code>.<p>
     * 
     * <p><code>atanh(x)</code> is computed as:</p>
     * 
     * <p><code>MathUtilities.atanh(x)</code></p>
     */
    public static final AbstractFunction functionATanh =
        new AbstractFunction("atanh", 1)
    {
        public Object functionCall(Object[] values)
            throws ParseException
        {
            checkValuesAsNumeric(values);
            
            XDouble x = ParserUtilities.toXDouble((XNumber) values[0]);
            double vx = x.getValue();
            
            return new XDouble(MathUtilities.atanh(vx));
        }
    };

    
    ///////////////////////////
    // Operation Definitions //
    ///////////////////////////
    
    /**
     * <p>NumericOperation to implement plus.</p>
     * 
     * <p>Symbol: "+".</p>
     * 
     * <p>Unary and binary.</p>
     */
    public static final NumericOperation operationPlus =
        new NumericOperation("+", true, true)
    {
        public Object unaryForXIntegral(XBigInteger a) {
            return a;
        }
        
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            return new XBigInteger(va.add(vb));
        }
        
        public Object unaryForXFloating(XDouble x) {
            return x;
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XDouble(vx + vy);
        }
    };
    
    
    /**
     * <p>NumericOperation to implement minus.</p>
     * 
     * <p>Symbol: "-".</p>
     * 
     * <p>Unary and binary.</p>
     */
    public static final NumericOperation operationMinus =
        new NumericOperation("-", true, true)
    {
        public Object unaryForXIntegral(XBigInteger a) {
            BigInteger va = a.getValue();
            
            return new XBigInteger(va.negate());
        }
        
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            return new XBigInteger(va.subtract(vb));
        }
        
        public Object unaryForXFloating(XDouble x) {
            double vx = x.getValue();
            
            return new XDouble(-vx);
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XDouble(vx - vy);
        }
    };
    
    
    /**
     * <p>NumericOperation to implement times.</p>
     * 
     * <p>Symbol: "*".</p>
     * 
     * <p>Binary.</p>
     */
    public static final NumericOperation operationTimes =
        new NumericOperation("*", false, true)
    {
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            return new XBigInteger(va.multiply(vb));
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XDouble(vx * vy);
        }
    };

    
    /**
     * <p>NumericOperation to implement division.</p>
     * 
     * <p>Symbol: "/".</p>
     * 
     * <p>Binary.</p>
     */
    public static final NumericOperation operationSlash =
        new NumericOperation("/", false, true)
    {
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            if (vb.equals(BigInteger.ZERO)) {
                int test = va.compareTo(BigInteger.ZERO);
                
                if (test > 0)
                    return new XDouble(Double.POSITIVE_INFINITY);
                
                if (test < 0)
                    return new XDouble(Double.NEGATIVE_INFINITY);
                
                return new XDouble(Double.NaN);
            }
            
            return new XBigInteger(va.divide(vb));
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XDouble(vx / vy);
        }
    };

    
    /**
     * <p>NumericOperation to implement remainder.</p>
     * 
     * <p>Symbol: "%".</p>
     * 
     * <p>Binary.</p>
     */
    public static final NumericOperation operationPercent =
        new NumericOperation("%", false, true)
    {
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            if (vb.equals(BigInteger.ZERO))
                return new XDouble(Double.NaN);
            
            return new XBigInteger(va.remainder(vb));
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XDouble(vx % vy);
        }
    };

    
    /**
     * <p>NumericOperation to implement exponentiation.</p>
     * 
     * <p>Symbol: "^".</p>
     * 
     * <p>Binary.</p>
     * 
     * <p>If the arguments are integral, that is, of type
     * <code>XBigInteger</code>, then an effort will be
     * made to carry out the exponentiation in integral
     * arithmetic.</p>
     * 
     * <p>If the arguments are not integral or if it is
     * impossible to do an integral computation, then
     * this method reverts to using <code>Math.pow</code>.</p>
     * 
     * <p>This operation is more subtle than the function
     * <code>functionPower</code> introduced in this class.
     * The power function always uses <code>Math.pow</code>
     * and makes no attempt to handle integral arguments in
     * a special way.</p>
     * 
     * <p>It is intentional that this operation and the power
     * function operate differently.  In some cases, the user
     * may want an integral computation but in other cases if
     * the internal BigInteger would be extremely large may
     * actually perfer to do the computation using double
     * precision floating point.</p>
     * 
     * @see #functionPower
     */
    public static final NumericOperation operationCaret =
        new NumericOperation("^", false, true)
    {
        private final BigInteger ZERO     = BigInteger.ZERO;
        private final BigInteger ONE      = BigInteger.ONE;
        private final BigInteger MINUSONE = ONE.negate();
        
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            // special cases
            
            if (vb.equals(ZERO))
                return new XBigInteger(ONE);
            
            int test = vb.compareTo(ZERO);
            
            if (va.equals(ZERO)) {
                if (test > 0)
                    return new XBigInteger(ZERO);
                else
                    return new XDouble(Double.NaN);
            }
            
            if (va.equals(ONE))
                return new XBigInteger(ONE);
            
            if (va.equals(MINUSONE)) {
                int lowbit = vb.getLowestSetBit();
                
                if (lowbit == 0)
                    return new XBigInteger(MINUSONE);
                else
                    return new XBigInteger(ONE);
            }
            
            // if vb is equivalent to a positive int exponent
            // then use the BigInteger pow function
            
            if (test > 0) {
                // get the associated exponent as an int
                int exponent = vb.intValue();
                
                // prepare to test if vb equals exponent
                String bits = Integer.toBinaryString(exponent);
                BigInteger vc = new BigInteger(bits, 2);
                
                // if vb equals exponent use BigInteger pow
                if (vb.equals(vc)) {
                    return new XBigInteger(va.pow(exponent));
                }
            }
            
            // otherwise compute in double precision
            
            double vx = va.doubleValue();
            double vy = vb.doubleValue();
            
            return new XDouble(Math.pow(vx, vy));
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XDouble(Math.pow(vx, vy));
        }
    };
    
    
    /**
     * <p>BooleanOperation to implement equals.</p>
     * 
     * <p>Symbol: "==".</p>
     * 
     * <p>Binary.  All types.</p>
     */
    public static final BooleanOperation operationEQ =
        new BooleanOperation("==", false, true, true)
    {
        public Object binaryForXBoolean(XBoolean p, XBoolean q) {
            boolean vp = p.getValue();
            boolean vq = q.getValue();
            
            return new XBoolean(vp == vq);
        }
    
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            int test = va.compareTo(vb);
                
            return new XBoolean(test == 0);
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XBoolean(vx == vy);
        }
    };

    
    /**
     * <p>BooleanOperation to implement not equals.</p>
     * 
     * <p>Symbol: "!=".</p>
     * 
     * <p>Binary.  All types.</p>
     */
    public static final BooleanOperation operationNE =
        new BooleanOperation("!=", false, true, true)
    {
        public Object binaryForXBoolean(XBoolean p, XBoolean q) {
            boolean vp = p.getValue();
            boolean vq = q.getValue();
            
            return new XBoolean(vp != vq);
        }
    
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            int test = va.compareTo(vb);
                
            return new XBoolean(test != 0);
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XBoolean(vx != vy);
        }
    };

    
    /**
     * <p>BooleanOperation to implement less than.</p>
     * 
     * <p>Symbol: "<".</p>
     * 
     * <p>Binary.  All types.</p>
     */
    public static final BooleanOperation operationLT =
        new BooleanOperation("<", false, true, true)
    {
        public Object binaryForXBoolean(XBoolean p, XBoolean q) {
            boolean vp = p.getValue();
            boolean vq = q.getValue();
            
            return new XBoolean(!vp && vq);
        }
    
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            int test = va.compareTo(vb);
                
            return new XBoolean(test < 0);
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XBoolean(vx < vy);
        }
    };

    
    /**
     * <p>BooleanOperation to implement greater than.</p>
     * 
     * <p>Symbol: ">".</p>
     * 
     * <p>Binary.  All types.</p>
     */
    public static final BooleanOperation operationGT =
        new BooleanOperation(">", false, true, true)
    {
        public Object binaryForXBoolean(XBoolean p, XBoolean q) {
            boolean vp = p.getValue();
            boolean vq = q.getValue();
            
            return new XBoolean(vp && !vq);
        }
    
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            int test = va.compareTo(vb);
                
            return new XBoolean(test > 0);
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XBoolean(vx > vy);
        }
    };

    
    /**
     * <p>BooleanOperation to implement less than or equals.</p>
     * 
     * <p>Symbol: "<=".</p>
     * 
     * <p>Binary.  All types.</p>
     */
    public static final BooleanOperation operationLE =
        new BooleanOperation("<=", false, true, true)
    {
        public Object binaryForXBoolean(XBoolean p, XBoolean q) {
            boolean vp = p.getValue();
            boolean vq = q.getValue();
            
            return new XBoolean(!vp || vq);
        }
    
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            int test = va.compareTo(vb);
                
            return new XBoolean(test <= 0);
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XBoolean(vx <= vy);
        }
    };

    
    /**
     * <p>BooleanOperation to implement greater than or equals.</p>
     * 
     * <p>Symbol: ">=".</p>
     * 
     * <p>Binary.  All types.</p>
     */
    public static final BooleanOperation operationGE =
        new BooleanOperation(">=", false, true, true)
    {
        public Object binaryForXBoolean(XBoolean p, XBoolean q) {
            boolean vp = p.getValue();
            boolean vq = q.getValue();
            
            return new XBoolean(vp || !vq);
        }
    
        public Object binaryForXIntegral(XBigInteger a, XBigInteger b) {
            BigInteger va = a.getValue();
            BigInteger vb = b.getValue();
            
            int test = va.compareTo(vb);
                
            return new XBoolean(test >= 0);
        }
        
        public Object binaryForXFloating(XDouble x, XDouble y) {
            double vx = x.getValue();
            double vy = y.getValue();
            
            return new XBoolean(vx >= vy);
        }
    };

    
    /**
     * <p>BooleanOperation to implement "and".</p>
     * 
     * <p>Symbol: "&amp;&amp;".</p>
     * 
     * <p>Binary.  Boolean only.</p>
     */
    public static final BooleanOperation operationAND =
        new BooleanOperation("&&", false, true, false)
    {
        public Object binaryForXBoolean(XBoolean p, XBoolean q) {
            boolean vp = p.getValue();
            boolean vq = q.getValue();
            
            return new XBoolean(vp && vq);
        }
    };

    
    /**
     * <p>BooleanOperation to implement "or".</p>
     * 
     * <p>Symbol: "||".</p>
     * 
     * <p>Binary.  Boolean only.</p>
     */
    public static final BooleanOperation operationOR =
        new BooleanOperation("||", false, true, false)
    {
        public Object binaryForXBoolean(XBoolean p, XBoolean q) {
            boolean vp = p.getValue();
            boolean vq = q.getValue();
            
            return new XBoolean(vp || vq);
        }
    };

    
    /**
     * <p>BooleanOperation to implement "not".</p>
     * 
     * <p>Symbol: "!".</p>
     * 
     * <p>Binary.  Boolean only.</p>
     */
    public static final BooleanOperation operationNOT =
        new BooleanOperation("!", true, false, false)
    {
        public Object unaryForXBoolean(XBoolean p) {
            boolean vp = p.getValue();
            
            return new XBoolean(! vp);
        }
    };

    
    /////////////
    // Methods //
    /////////////
    
    /**
     * <p>Adds the standard constants for this parser
     * to the environment.</p>
     * 
     * <table border="1" cellpadding="5">
     *   <tr>
     *     <td style="text-align:center"><b>Identifier</b></td>
     *     <td style="text-align:center"><b>Type</b></td>
     *     <td style="text-align:center"><b>Definition</b></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>true</code></td>
     *     <td style="text-align:center"><code>XBoolean</code></td>
     *     <td style="text-align:center"><code>true</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>false</code></td>
     *     <td style="text-align:center"><code>XBoolean</code></td>
     *     <td style="text-align:center"><code>false</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>pi</code></td>
     *     <td style="text-align:center"><code>XDouble</code></td>
     *     <td style="text-align:center"><code>Math.PI</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>e</code></td>
     *     <td style="text-align:center"><code>XDouble</code></td>
     *     <td style="text-align:center"><code>Math.E</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>MaxInt</code></td>
     *     <td style="text-align:center"><code>XInt</code></td>
     *     <td style="text-align:center"><code>Integer.MAX_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>maxint</code></td>
     *     <td style="text-align:center"><code>XInt</code></td>
     *     <td style="text-align:center"><code>Integer.MAX_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>MinInt</code></td>
     *     <td style="text-align:center"><code>XInt</code></td>
     *     <td style="text-align:center"><code>Integer.MIN_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>minint</code></td>
     *     <td style="text-align:center"><code>XInt</code></td>
     *     <td style="text-align:center"><code>Integer.MIN_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>MaxLong</code></td>
     *     <td style="text-align:center"><code>XLong</code></td>
     *     <td style="text-align:center"><code>Long.MAX_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>maxlong</code></td>
     *     <td style="text-align:center"><code>XLong</code></td>
     *     <td style="text-align:center"><code>Long.MAX_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>MinLong</code></td>
     *     <td style="text-align:center"><code>XLong</code></td>
     *     <td style="text-align:center"><code>Long.MIN_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>minlong</code></td>
     *     <td style="text-align:center"><code>XLong</code></td>
     *     <td style="text-align:center"><code>Long.MIN_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>MaxDouble</code></td>
     *     <td style="text-align:center"><code>XDouble</code></td>
     *     <td style="text-align:center"><code>Double.MAX_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>maxdouble</code></td>
     *     <td style="text-align:center"><code>XDouble</code></td>
     *     <td style="text-align:center"><code>Double.MAX_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>MinDouble</code></td>
     *     <td style="text-align:center"><code>XDouble</code></td>
     *     <td style="text-align:center"><code>Double.MIN_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>mindouble</code></td>
     *     <td style="text-align:center"><code>XDouble</code></td>
     *     <td style="text-align:center"><code>Double.MIN_VALUE</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>Infinity</code></td>
     *     <td style="text-align:center"><code>XDouble</code></td>
     *     <td style="text-align:center"><code>Double.POSITIVE_INFINITY</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>infinity</code></td>
     *     <td style="text-align:center"><code>XDouble</code></td>
     *     <td style="text-align:center"><code>Double.POSITIVE_INFINITY</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>NaN</code></td>
     *     <td style="text-align:center"><code>XDouble</code></td>
     *     <td style="text-align:center"><code>Double.NaN</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>nan</code></td>
     *     <td style="text-align:center"><code>XDouble</code></td>
     *     <td style="text-align:center"><code>Double.NaN</code></td>
     *   </tr>
     * </table>
     */
    protected void addConstants() {
        addConstant("true",      new XBoolean(true));
        addConstant("false",     new XBoolean(false));
        addConstant("pi",        new XDouble(Math.PI));
        addConstant("e",         new XDouble(Math.E));
        addConstant("MaxInt",    new XInt(Integer.MAX_VALUE));
        addConstant("maxint",    new XInt(Integer.MAX_VALUE));
        addConstant("MinInt",    new XInt(Integer.MIN_VALUE));
        addConstant("minint",    new XInt(Integer.MIN_VALUE));
        addConstant("MaxLong",   new XLong(Long.MAX_VALUE));
        addConstant("maxlong",   new XLong(Long.MAX_VALUE));
        addConstant("MinLong",   new XLong(Long.MIN_VALUE));
        addConstant("minlong",   new XLong(Long.MIN_VALUE));
        addConstant("MaxDouble", new XDouble(Double.MAX_VALUE));
        addConstant("maxdouble", new XDouble(Double.MAX_VALUE));
        addConstant("MinDouble", new XDouble(Double.MIN_VALUE));
        addConstant("mindouble", new XDouble(Double.MIN_VALUE));
        addConstant("Infinity",  new XDouble(Double.POSITIVE_INFINITY));
        addConstant("infinity",  new XDouble(Double.POSITIVE_INFINITY));
        addConstant("NaN",       new XDouble(Double.NaN));
        addConstant("nan",       new XDouble(Double.NaN));
    }
    
    
    /**
     * <p>Adds the standard functions for this parser
     * to the function table.</p>
     * 
     * <table border="1" cellpadding="5">
     *   <tr>
     *     <td style="text-align:center"><b>Function Name</b></td>
     *     <td style="text-align:center"><b>Typical Usage</b></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>abs</code></td>
     *     <td style="text-align:center"><code>abs(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>ceiling</code></td>
     *     <td style="text-align:center"><code>ceiling(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>floor</code></td>
     *     <td style="text-align:center"><code>floor(x)</code></td>
     *   <tr>
     *     <td style="text-align:center"><code>round</code></td>
     *     <td style="text-align:center"><code>round(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>max</code></td>
     *     <td style="text-align:center"><code>max(x,y)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>min</code></td>
     *     <td style="text-align:center"><code>min(x,y)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>sqrt</code></td>
     *     <td style="text-align:center"><code>sqrt(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>power</code></td>
     *     <td style="text-align:center"><code>power(x,y)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>root</code></td>
     *     <td style="text-align:center"><code>root(x,y)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>todegrees</code></td>
     *     <td style="text-align:center"><code>todegrees(theta)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>toradians</code></td>
     *     <td style="text-align:center"><code>toradians(angle)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>sin</code></td>
     *     <td style="text-align:center"><code>sin(theta)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>sindeg</code></td>
     *     <td style="text-align:center"><code>sindeg(angle)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>cos</code></td>
     *     <td style="text-align:center"><code>cos(theta)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>cosdeg</code></td>
     *     <td style="text-align:center"><code>cosdeg(angle)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>tan</code></td>
     *     <td style="text-align:center"><code>tan(theta)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>tandeg</code></td>
     *     <td style="text-align:center"><code>tandeg(angle)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>asin</code></td>
     *     <td style="text-align:center"><code>asin(s)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>asindeg</code></td>
     *     <td style="text-align:center"><code>asindeg(s)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>acos</code></td>
     *     <td style="text-align:center"><code>acos(c)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>acosdeg</code></td>
     *     <td style="text-align:center"><code>acosdeg(c)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>atan</code></td>
     *     <td style="text-align:center"><code>atan(t)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>atandeg(t)</code></td>
     *     <td style="text-align:center"><code>atandeg(t)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>atan2</code></td>
     *     <td style="text-align:center"><code>atan2(y,x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>atan2deg</code></td>
     *     <td style="text-align:center"><code>atan2deg(y,x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>exp</code></td>
     *     <td style="text-align:center"><code>exp(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>log</code></td>
     *     <td style="text-align:center"><code>log(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>ln</code></td>
     *     <td style="text-align:center"><code>ln(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>log2</code></td>
     *     <td style="text-align:center"><code>log2(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>log10</code></td>
     *     <td style="text-align:center"><code>log10(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>logtobase</code></td>
     *     <td style="text-align:center"><code>logtobase(x,b)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>sinh</code></td>
     *     <td style="text-align:center"><code>sinh(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>cosh</code></td>
     *     <td style="text-align:center"><code>cosh(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>tanh</code></td>
     *     <td style="text-align:center"><code>tanh(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>asinh</code></td>
     *     <td style="text-align:center"><code>asinh(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>acosh</code></td>
     *     <td style="text-align:center"><code>acosh(x)</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>atanh</code></td>
     *     <td style="text-align:center"><code>atanh(x)</code></td>
     *   </tr>
     * </table>
     * 
     * <p>In the above table:<br />
     * &nbsp;&nbsp;&nbsp;&nbsp;<code>x</code> and <code>y</code>
     *   stand for generic variables;<br />
     * &nbsp;&nbsp;&nbsp;&nbsp;<code>theta</code>
     *   is an angle in radians;<br />
     * &nbsp;&nbsp;&nbsp;&nbsp;<code>angle</code>
     *   is an angle in degrees;<br />
     * &nbsp;&nbsp;&nbsp;&nbsp;
     *   <code>s</code>, <code>c</code>, <code>t</code>
     *   stand for possible values of
     *   <code>sin</code>, <code>cos</code>, <code>tan</code>;<br />
     * &nbsp;&nbsp;&nbsp;&nbsp;and <code>b</code>
     *   is the base for a logarithm.</p>
     * 
     * <p>In 2.5.0, <code>random</code> was removed from the
     * list of functions because as implemented in the class
     * <code>AbstractFunction</code> a function has a fixed
     * number of arguments.  Instead, <code>random</code> is
     * now implemented directly in <code>BaseParser</code>
     * to take one of three forms with the following
     * interpretations.</p>
     * 
     * <table border="1" cellpadding="5">
     *   <tr>
     *     <td style="text-align:center"><b>Function Name</b></td>
     *     <td style="text-align:center"><b>Typical Usage</b></td>
     *     <td style="text-align:center"><b>Interpretation</b></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>random</code></td>
     *     <td style="text-align:center"><code>random()</code></td>
     *     <td>Random number between 0 and 1</td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>random</code></td>
     *     <td style="text-align:center"><code>random(x)</code></td>
     *     <td>Random number between 0 and x</td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center"><code>random</code></td>
     *     <td style="text-align:center"><code>random(x,y)</code></td>
     *     <td>Random number between x and y</td>
     *   </tr>
     * </table>
     */
    protected void addFunctions() {
        addFunction(functionAbs);
        addFunction(functionCeiling);
        addFunction(functionFloor);
        addFunction(functionRound);
        addFunction(functionMax);
        addFunction(functionMin);
    
        addFunction(functionSqrt);
        addFunction(functionPower);
        addFunction(functionRoot);
    
        addFunction(functionToDegrees);
        addFunction(functionToRadians);
    
        addFunction(functionSin);
        addFunction(functionSinDeg);
        addFunction(functionCos);
        addFunction(functionCosDeg);
        addFunction(functionTan);
        addFunction(functionTanDeg);
    
        addFunction(functionASin);
        addFunction(functionASinDeg);
        addFunction(functionACos);
        addFunction(functionACosDeg);
        addFunction(functionATan);
        addFunction(functionATanDeg);
        addFunction(functionATan2);
        addFunction(functionATan2Deg);
    
        addFunction(functionExp);
        addFunction(functionLog);
        addFunction(functionLn);
        addFunction(functionLog2);
        addFunction(functionLog10);
        addFunction(functionLogToBase);
        
        addFunction(functionSinh);
        addFunction(functionCosh);
        addFunction(functionTanh);
        addFunction(functionASinh);
        addFunction(functionACosh);
        addFunction(functionATanh);
    }
    
    
    /**
     * <p>Adds the standard operations for this parser 
     * to the operation table.</p>
     *
     * <p>Except for the introduction of the <code>^</code>
     * operation, follows Arnold, Gosling, Holmes:</p>
     * 
     * <p><i>The Java Programming Language</i>, Third Edition, 6.10</p>
     * 
     * <table border="1" cellpadding="5">
     *   <tr>
     *     <td style="text-align:center"><b>Precedence</b></td>
     *     <td style="text-align:center"><b>Operations</b></td>
     *     <td style="text-align:center"><b>Symbols</b></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center">0</td>
     *     <td style="text-align:center"><code>IDENTITY</code></td>
     *     <td style="text-align:center"><code>None</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center">1</td>
     *     <td style="text-align:center"><code>operationOR</code></td>
     *     <td style="text-align:center"><code>||</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center">2</td>
     *     <td style="text-align:center"><code>operationAND</code></td>
     *     <td style="text-align:center"><code>&amp;&amp;</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center">3</td>
     *     <td style="text-align:center"><code>operationEQ<br />operationNE</code></td>
     *     <td style="text-align:center"><code>==<br />!=</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center">4</td>
     *     <td style="text-align:center"><code>operationLT<br />operationGT<br />operationLE<br />operationGE</code></td>
     *     <td style="text-align:center"><code>&lt;<br />&gt;<br />&lt;=<br />&gt;=</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center">5</td>
     *     <td style="text-align:center"><code>operationPlus<br />operationMinus</code></td>
     *     <td style="text-align:center"><code>+<br />-</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center">6</td>
     *     <td style="text-align:center"><code>operationTimes<br />operationSlash<br />operationPercent</code></td>
     *     <td style="text-align:center"><code>*<br />/<br />%</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center">7</td>
     *     <td style="text-align:center"><code>operationCaret</code></td>
     *     <td style="text-align:center"><code>^</code></td>
     *   </tr>
     *   <tr>
     *     <td style="text-align:center">8</td>
     *     <td style="text-align:center"><code>operationNOT</code></td>
     *     <td style="text-align:center"><code>!</code></td>
     *   </tr>
     * </table>
     * 
     * @see #operationCaret
     */
    protected void addOperations() {
        addOperationAfterPrecedenceOf(IDENTITY       , operationOR      );
        
        addOperationAfterPrecedenceOf(operationOR    , operationAND     );
        
        addOperationAfterPrecedenceOf(operationAND   , operationEQ      );
        addOperationAtPrecedenceOf   (operationEQ    , operationNE      );
        
        addOperationAfterPrecedenceOf(operationEQ    , operationLT      );
        addOperationAtPrecedenceOf   (operationLT    , operationGT      );
        addOperationAtPrecedenceOf   (operationLT    , operationLE      );
        addOperationAtPrecedenceOf   (operationLT    , operationGE      );
        
        addOperationAfterPrecedenceOf(operationLT    , operationPlus    );
        addOperationAtPrecedenceOf   (operationPlus  , operationMinus   );
        
        addOperationAfterPrecedenceOf(operationPlus  , operationTimes   );
        addOperationAtPrecedenceOf   (operationTimes , operationSlash   );
        addOperationAtPrecedenceOf   (operationTimes , operationPercent );
        
        addOperationAfterPrecedenceOf(operationTimes , operationCaret   );
        
        addOperationAfterPrecedenceOf(operationCaret , operationNOT     );
    }
    
}
