/* ADQLParser.java */
/* Generated By:JavaCC: Do not edit this line. ADQLParser.java */
package adql.parser;

import java.util.Stack;
import java.util.Vector;
import java.util.ArrayList;
import java.util.Collection;

import java.io.FileReader;
import java.io.IOException;

import adql.db.exception.UnresolvedIdentifiersException;

import adql.parser.IdentifierItems.IdentifierItem;

import adql.parser.ADQLQueryFactory.JoinType;

import adql.query.*;
import adql.query.from.*;
import adql.query.constraint.*;

import adql.query.operand.*;

import adql.query.operand.function.*;

import adql.query.operand.function.geometry.*;
import adql.query.operand.function.geometry.GeometryFunction.GeometryValue;

import adql.translator.PostgreSQLTranslator;
import adql.translator.TranslationException;

/**
* Parses an ADQL query thanks to the {@link ADQLParser#Query()} function.
* 
* <p>
*   This parser is able, thanks to a {@link QueryChecker} object, to check each
*   {@link ADQLQuery} just after its generation. It could be used to check the
*   consistency between the ADQL query to parse and the "database" on which the
*   query must be executed. By default, there is no {@link QueryChecker}. Thus
*   you must extend {@link QueryChecker} to check semantically all generated
*   ADQLQuery objects.
* </p>
* 
* <p>
*   To create an object representation of the given ADQL query, this parser uses
*   a {@link ADQLQueryFactory} object. So if you want customize some object
*   (ie. CONTAINS) of this representation you just have to extend the
*   corresponding default object (ie. ContainsFunction) and to extend the
*   corresponding function of {@link ADQLQueryFactory}
*   (ie. createContains(...)).
* </p>
*
* <p>Here are the key functions to use:</p>
* <ul>
* 	<li>{@link #parseQuery(java.lang.String)} (or any of its alternatives)
* 		to parse an input ADQL query String and get its corresponding ADQL tree
*   </li>
*   <li>{@link #tryQuickFix(java.lang.String)} to try fixing the most common
* 		issues with ADQL queries (e.g. Unicode confusable characters,
* 		unescaped ADQL identifiers, SQL reserved keywords, ...)</li>
* </ul>
* 
* <p><b><u>WARNING:</u>
*   To modify this class it's strongly encouraged to modify the .jj file in the
*   section between <i>PARSER_BEGIN</i> and <i>PARSER_END</i> and to re-compile
*   it with JavaCC.
* </b></p>
*
* @see QueryChecker
* @see ADQLQueryFactory
*
* @author Gr&eacute;gory Mantelet (CDS;ARI)
* @version 1.5-2 (10/2020)
*/
public class ADQLParser implements ADQLParserConstants {

        /** Tools to build the object representation of the ADQL query. */
        private ADQLQueryFactory queryFactory = new ADQLQueryFactory();

        /** The stack of queries (because there may be some sub-queries). */
        private Stack<ADQLQuery> stackQuery = new Stack<ADQLQuery>();

        /** The object representation of the ADQL query to parse.
	 * (ONLY USED DURING THE PARSING, else it is always <i>null</i>). */
        private ADQLQuery query = null;

        /** Checks each {@link ADQLQuery} (sub-query or not) just after their
	 * generation. */
        private QueryChecker queryChecker = null;

        /** The first token of a table/column name. This token is extracted by
	 * {@link #Identifier()}. */
        private Token currentIdentifierToken = null;

        /**
	* Builds an ADQL parser without a query to parse.
	*/
        public ADQLParser(){
                this(new java.io.ByteArrayInputStream("".getBytes()));
                setDebug(false);
        }

        /**
	* Builds an ADQL parser without a query to parse but with a
	* {@link QueryChecker} and a {@link ADQLQueryFactory}.
	*
	* @param checker	The object to use to check each {@link ADQLQuery}.
	* @param factory	The object to use to build an object representation of
	*               	the given ADQL query.
	*/
        public ADQLParser(QueryChecker checker, ADQLQueryFactory factory) {
                this();

                queryChecker = checker;

                if (factory != null)
                        queryFactory = factory;
        }

        /**
	* Builds an ADQL parser without a query to parse but with a
	* {@link QueryChecker}.
	*
	* @param checker	The object to use to check each {@link ADQLQuery}.
	*/
        public ADQLParser(QueryChecker checker) {
                this(checker, null);
        }

        /**
	* Builds an ADQL parser without a query to parse but with a
	* {@link ADQLQueryFactory}.
	*
	* @param factory	The object to use to build an object representation of
	*               	the given ADQL query.
	*/
        public ADQLParser(ADQLQueryFactory factory) {
                this((QueryChecker)null, factory);
        }

        /**
	* Builds a parser with a stream containing the query to parse.
	*
	* @param stream		The stream in which the ADQL query to parse is given.
	* @param checker	The object to use to check each {@link ADQLQuery}.
	* @param factory	The object to use to build an object representation of
	*               	the given ADQL query.
	*/
        public ADQLParser(java.io.InputStream stream, QueryChecker checker, ADQLQueryFactory factory) {
                this(stream);
                setDebug(false);

                setDebug(false);

                queryChecker = checker;

                if (factory != null)
                        queryFactory = factory;
        }

        /**
	* Builds a parser with a stream containing the query to parse.
	*
	* @param stream		The stream in which the ADQL query to parse is given.
	* @param checker	The object to use to check each {@link ADQLQuery}.
	*/
        public ADQLParser(java.io.InputStream stream, QueryChecker checker) {
                this(stream, checker, null);
        }

        /**
	* Builds a parser with a stream containing the query to parse.
	*
	* @param stream		The stream in which the ADQL query to parse is given.
	* @param factory	The object to use to build an object representation of
	*               	the given ADQL query.
	*/
        public ADQLParser(java.io.InputStream stream, ADQLQueryFactory factory) {
                this(stream, (QueryChecker)null, factory);
        }

        /**
	* Builds a parser with a stream containing the query to parse.
	*
	* @param stream		The stream in which the ADQL query to parse is given.
	* @param encoding	The supplied encoding.
	* @param checker	The object to use to check each {@link ADQLQuery}.
	* @param factory	The object to use to build an object representation
	*               	of the given ADQL query.
	*/
        public ADQLParser(java.io.InputStream stream, String encoding, QueryChecker checker, ADQLQueryFactory factory) {
                this(stream, encoding);
                setDebug(false);

                queryChecker = checker;

                if (factory != null)
                        queryFactory = factory;
        }

        /**
	* Builds a parser with a stream containing the query to parse.
	*
	* @param stream		The stream in which the ADQL query to parse is given.
	* @param encoding	The supplied encoding.
	* @param checker	The object to use to check each {@link ADQLQuery}.
	*/
        public ADQLParser(java.io.InputStream stream, String encoding, QueryChecker checker) {
                this(stream, encoding, checker, null);
        }

        /**
	* Builds a parser with a stream containing the query to parse.
	*
	* @param stream		The stream in which the ADQL query to parse is given.
	* @param encoding	The supplied encoding.
	* @param factory	The object to use to build an object representation
	*               	of the given ADQL query.
	*/
        public ADQLParser(java.io.InputStream stream, String encoding, ADQLQueryFactory factory) {
                this(stream, encoding, null, factory);
        }

        /**
	* Builds a parser with a reader containing the query to parse.
	*
	* @param reader		The reader in which the ADQL query to parse is given.
	* @param checker	The object to use to check each {@link ADQLQuery}.
	* @param factory	The object to use to build an object representation
	*               	of the given ADQL query.
	*/
        public ADQLParser(java.io.Reader reader, QueryChecker checker, ADQLQueryFactory factory) {
                this(reader);
                setDebug(false);

                setDebug(false);

                queryChecker = checker;

                if (factory != null)
                        queryFactory = factory;
        }

        /**
	* Builds a parser with a reader containing the query to parse.
	*
	* @param reader		The reader in which the ADQL query to parse is given.
	* @param checker	The object to use to check each {@link ADQLQuery}.
	*/
        public ADQLParser(java.io.Reader reader, QueryChecker checker) {
                this(reader, checker, null);
        }

        /**
	* Builds a parser with a reader containing the query to parse.
	*
	* @param reader		The reader in which the ADQL query to parse is given.
	* @param factory	The object to use to build an object representation
	*               	of the given ADQL query.
	*/
        public ADQLParser(java.io.Reader reader, ADQLQueryFactory factory) {
                this(reader, null, factory);
        }

        /**
	* Builds a parser with another token manager.
	*
	* @param tm			The manager which associates a token to a numeric code.
	* @param checker	The object to use to check each {@link ADQLQuery }.
	* @param factory	The object to use to build an object representation
	*               	of the given ADQL query.
	*/
        public ADQLParser(ADQLParserTokenManager tm, QueryChecker checker, ADQLQueryFactory factory) {
                this(tm);
                setDebug(false);

                setDebug(false);

                queryChecker = checker;

                if (factory != null)
                        queryFactory = factory;
        }

        /**
	* Builds a parser with another token manager.
	*
	* @param tm			The manager which associates a token to a numeric code.
	* @param checker	The object to use to check each {@link ADQLQuery}.
	*/
        public ADQLParser(ADQLParserTokenManager tm, QueryChecker checker) {
                this(tm, checker, null);
        }

        /**
	* Builds a parser with another token manager.
	*
	* @param tm			The manager which associates a token to a numeric code.
	* @param factory	The object to use to build an object representation of
	*               	the given ADQL query.
	*/
        public ADQLParser(ADQLParserTokenManager tm, ADQLQueryFactory factory) {
                this(tm, null, factory);
        }

        /* ADDITIONAL GETTERS & SETTERS */

        public final void setDebug(boolean debug){
                if (debug) enable_tracing();
                else       disable_tracing();
        }

        public final QueryChecker getQueryChecker(){
                return queryChecker;
        }

        public final void setQueryChecker(QueryChecker checker){
                queryChecker = checker;
        }

        public final ADQLQueryFactory getQueryFactory(){
                return queryFactory;
        }

        public final void setQueryFactory(ADQLQueryFactory factory){
                queryFactory = (factory!=null)?factory:(new ADQLQueryFactory());
        }

        /* EXCEPTION HELPER FUNCTION */

        private final ParseException generateParseException(Exception ex){
                if (!(ex instanceof ParseException)){
                        ParseException pex = new ParseException("["+ex.getClass().getName()+"] "+ex.getMessage());
                        pex.setStackTrace(ex.getStackTrace());
                        return pex;
                }else
                        return (ParseException)ex;
        }

        /* QUERY PARSING FUNCTIONS */

        /**
	 * Tell whether the given string is a valid ADQL regular identifier.
	 *
	 * <p>
	 * 	According to the ADQL-2.0's BNF, a regular identifier (i.e. not delimited
	 * 	; not between double quotes) must be a letter followed by a letter, digit
	 * 	or underscore. So, the following regular expression:
	 * </p>
	 * <pre>[a-zA-Z]+[a-zA-Z0-9_]*</pre>
	 *
	 * <p>This is what this function tests on the given string.</p>
	 *
	 * @param idCandidate	The string to test.
	 *
	 * @return	<code>true</code> if the given string is a valid regular
	 *        	identifier,
	 *        	<code>false</code> otherwise.
	 *
	 * @see #testRegularIdentifier(adql.parser.Token)
	 *
	 * @since 1.5
	 */
        public final boolean isRegularIdentifier(final String idCandidate) {
                return idCandidate.matches("[a-zA-Z]+[a-zA-Z0-9_]*");
        }

        /**
	 * Test the given token as an ADQL's regular identifier.
	 *
	 * <p>
	 * 	This function uses {@link #isRegularIdentifier(java.lang.String)} to
	 * 	test the given token's image. If the test fails, a
	 * 	{@link adql.parser.ParseException} is thrown.
	 * </p>
	 *
	 * @param token	The token to test.
	 *
	 * @throws ParseException	If the given token is not a valid ADQL regular
	 *                       	identifier.
	 *
	 * @see #isRegularIdentifier(java.lang.String)
	 *
	 * @since 1.5
	 */
        public final void testRegularIdentifier(final Token token) throws ParseException {
                if (!isRegularIdentifier(token.image))
                        throw new ParseException("Invalid ADQL regular identifier: \u005c""+token.image+"\u005c"! If it aims to be a column/table name/alias, you should write it between double quotes.", new TextPosition(token));
        }

        /**
	* Parses the query given at the creation of this parser or in the
	* <i>ReInit</i> functions.
	*
	* @return 	The object representation of the given ADQL query.
	* 
	* @throws ParseException	If there is at least one syntactic error.
	*
	* @see ADQLParser#Query()
	*/
        public final ADQLQuery parseQuery() throws ParseException {
                stackQuery.clear();
                query = null;
                try {
                        return Query();
                }catch(TokenMgrError tme) {
                        throw new ParseException(tme);
                }
        }

        /**
	* Parses the query given in parameter.
	*
	* @param q	The ADQL query to parse.
	* 
	* @return	The object representation of the given ADQL query.
	* 
	* @throws ParseException	If there is at least one syntactic error.
	*
	* @see ADQLParser#ReInit(java.io.InputStream)
	* @see ADQLParser#setDebug(boolean)
	* @see ADQLParser#Query()
	*/
        public final ADQLQuery parseQuery(String q) throws ParseException {
                stackQuery.clear();
                query = null;
                ReInit(new java.io.ByteArrayInputStream(q.getBytes()));
                try {
                        return Query();
                }catch(TokenMgrError tme) {
                        throw new ParseException(tme);
                }
        }

        /**
	* Parses the query contained in the stream given in parameter.
	*
	* @param stream		The stream which contains the ADQL query to parse.
	* 
	* @return	The object representation of the given ADQL query.
	* 
	* @throws ParseException	If there is at least one syntactic error.
	*
	* @see ADQLParser#ReInit(java.io.InputStream)
	* @see ADQLParser#setDebug(boolean)
	* @see ADQLParser#Query()
	*/
        public final ADQLQuery parseQuery(java.io.InputStream stream) throws ParseException {
                stackQuery.clear();
                query = null;
                ReInit(stream);
                try {
                        return Query();
                }catch(TokenMgrError tme) {
                        throw new ParseException(tme);
                }
        }

        /* CORRECTION SUGGESTION */

        /**
	 * Try fixing tokens/terms of the input ADQL query.
	 *
	 * <p>
	 * 	<b>This function does not try to fix syntactical or semantical errors.</b>
	 *  It just try to fix the most common issues in ADQL queries, such as:
	 * </p>
	 * <ul>
	 * 	<li>some Unicode characters confusable with ASCII characters (like a
	 * 		space, a dash, ...) ; this function replace them by their ASCII
	 * 		alternative,</li>
	 * 	<li>any of the following are double quoted:
	 * 		<ul>
	 * 			<li>non regular ADQL identifiers
	 * 				(e.g. <code>_RAJ2000</code>),</li>
	 * 			<li>ADQL function names used as identifiers
	 * 				(e.g. <code>distance</code>)</li>
	 * 			<li>and SQL reserved keywords
	 * 				(e.g. <code>public</code>).</li>
	 * 		</ul>
	 * 	</li>
	 * </ul>
	 *
	 * <p><i><b>Note 1:</b>
	 * 	The given stream is NOT closed by this function even if the EOF is
	 * 	reached. It is the responsibility of the caller to close it.
	 * </i></p>
	 *
	 * <p><i><b>Note 2:</b>
	 * 	This function does not use any instance variable of this parser
	 * 	(especially the InputStream or Reader provided at initialisation or
	 * 	ReInit).
	 * </i></p>
	 *
	 * @param input	Stream containing the input ADQL query to fix.
	 *
	 * @return	The suggested correction of the input ADQL query.
	 *
	 * @throws java.io.IOException	If there is any error while reading from the
	 *                            	given input stream.
	 * @throws ParseException	If any unrecognised character is encountered,
	 *                       	or if anything else prevented the tokenization
	 *                       	   of some characters/words/terms.
	 *
	 * @see #tryQuickFix(java.lang.String)
	 *
	 * @since 1.5
	 */
        public final String tryQuickFix(final java.io.InputStream input) throws java.io.IOException, ParseException {
                // Fetch everything into a single string:
                StringBuffer buf = new StringBuffer();
                byte[] cBuf = new byte[1024];
                int nbChar;
                while((nbChar = input.read(cBuf)) > -1){
                        buf.append(new String(cBuf, 0, nbChar));
                }

                // Convert the buffer into a String and now try to fix it:
                return tryQuickFix(buf.toString());
        }

        /**
	 * Try fixing tokens/terms of the given ADQL query.
	 *
	 * <p>
	 * 	<b>This function does not try to fix syntactical or semantical errors.</b>
	 *  It just try to fix the most common issues in ADQL queries, such as:
	 * </p>
	 * <ul>
	 * 	<li>some Unicode characters confusable with ASCII characters (like a
	 * 		space, a dash, ...) ; this function replace them by their ASCII
	 * 		alternative,</li>
	 * 	<li>any of the following are double quoted:
	 * 		<ul>
	 * 			<li>non regular ADQL identifiers
	 * 				(e.g. <code>_RAJ2000</code>),</li>
	 * 			<li>ADQL function names used as identifiers
	 * 				(e.g. <code>distance</code>)</li>
	 * 			<li>and SQL reserved keywords
	 * 				(e.g. <code>public</code>).</li>
	 * 		</ul>
	 * 	</li>
	 * </ul>
	 *
	 * <p><i><b>Note:</b>
	 * 	This function does not use any instance variable of this parser
	 * 	(especially the InputStream or Reader provided at initialisation or
	 * 	ReInit).
	 * </i></p>
	 *
	 * @param adqlQuery	The input ADQL query to fix.
	 *
	 * @return	The suggested correction of the given ADQL query.
	 *
	 * @throws ParseException	If any unrecognised character is encountered,
	 *                       	or if anything else prevented the tokenization
	 *                       	   of some characters/words/terms.
	 *
	 * @since 1.5
	 */
        public String tryQuickFix(String adqlQuery) throws ParseException {
                StringBuffer suggestedQuery = new StringBuffer();

                // 1. Replace all Unicode confusable characters:
                adqlQuery = replaceUnicodeConfusables(adqlQuery);

                /* 1.bis. Normalise new lines and tabulations
		 *        (to simplify the column counting): */
                adqlQuery = adqlQuery.replaceAll("(\u005cr\u005cn|\u005cr|\u005cn)", System.getProperty("line.separator")).replaceAll("\u005ct", "    ");

                // 2. Analyse the query token by token:
                ADQLParserTokenManager parser = new ADQLParserTokenManager(new SimpleCharStream(new java.io.ByteArrayInputStream(adqlQuery.getBytes())));

                final String[] lines = adqlQuery.split(System.getProperty("line.separator"));

                try{
                        String suggestedToken;
                        int lastLine = 1, lastCol = 1;

                        Token token = null, nextToken = parser.getNextToken();
                        // for all tokens until the EOF or EOQ:
                        do{
                                // get the next token:
                                token = nextToken;
                                nextToken = (isEnd(token) ? null : parser.getNextToken());

                                // 3. Double quote any suspect token:
                                if (mustEscape(token, nextToken)){
                                        suggestedToken = "\u005c"" + token.image + "\u005c"";
                                }else
                                        suggestedToken = token.image;

                                /* 4. Append all space characters (and comments) before the
				 *    token: */
                                /* same line, just get the space characters between the last
				 * token and the one to append: */
                                if (lastLine == token.beginLine){
                                        if (token.kind == ADQLParserConstants.EOF)
                                                suggestedQuery.append(lines[lastLine - 1].substring(lastCol - 1));
                                        else
                                                suggestedQuery.append(lines[lastLine - 1].substring(lastCol - 1, token.beginColumn - (isEnd(token) ? 0 : 1)));
                                        lastCol = token.endColumn + 1;
                                }
                                // not the same line...
                                else{
                                    /* append all remaining space characters until the position
				     * of the token to append: */
                                        do{
                                                suggestedQuery.append(lines[lastLine - 1].substring(lastCol - 1)).append('\u005cn');
                                                lastLine++;
                                                lastCol = 1;
                                        }while(lastLine < token.beginLine);
                                        /* if there are still space characters before the token,
					 * append them as well: */
                                        if (lastCol < token.beginColumn)
                                                suggestedQuery.append(lines[lastLine - 1].substring(lastCol - 1, token.beginColumn - 1));
                                        // finally, set the correct column position:
                                        lastCol = token.endColumn + 1;
                                }

                                // 5. Append the suggested token:
                                suggestedQuery.append(suggestedToken);

                        }while(!isEnd(token));

                }catch(TokenMgrError err){
                    // wrap such errors and propagate them:
                        throw new ParseException(err);
                }

                return suggestedQuery.toString();
        }

        /**
	 * All of the most common Unicode confusable characters and their
	 * ASCII/UTF-8 alternative.
	 *
	 * <p>
	 * 	Keys of this map represent the ASCII character while the values are the
	 * 	regular expression for all possible Unicode alternatives.
	 * </p>
	 *
	 * <p><i><b>Note:</b>
	 * 	All of them have been listed using
	 * 	<a href="https://unicode.org/cldr/utility/confusables.jsp">Unicode Utilities: Confusables</a>.
	 * </i></p>
	 *
	 * @since 1.5
	 */
        protected final static java.util.Map<String, String> REGEX_UNICODE_CONFUSABLES = new java.util.HashMap<String, String>(10);
        /** Regular expression matching all Unicode alternatives for <code>-</code>.
	 * @since 1.5 */
        protected final static String REGEX_DASH         = "[-\u02d7\u06d4\u2010\u2011\u2012\u2013\u2043\u2212\u2796\u2cba\ufe58\u2014\u2015\u207b\u208b\u0096\u058a\ufe63\uff0d]";
        /** Regular expression matching all Unicode alternatives for <code>_</code>.
	 * @since 1.5 */
        protected final static String REGEX_UNDERSCORE   = "[_\u07fa\ufe4d\ufe4e\ufe4f]";
        /** Regular expression matching all Unicode alternatives for <code>'</code>.
	 * @since 1.5 */
        protected final static String REGEX_QUOTE        = "['`\u00b4\u02b9\u02bb\u02bc\u02bd\u02be\u02c8\u02ca\u02cb\u02f4\u0374\u0384\u055a\u055d\u05d9\u05f3\u07f4\u07f5\u144a\u16cc\u1fbd\u1fbf\u1fef\u1ffd\u1ffe\u2018\u2019\u201b\u2032\u2035\ua78c\uff07\uff40]";
        /** Regular expression matching all Unicode alternatives for <code>"</code>.
	 * @since 1.5 */
        protected final static String REGEX_DOUBLE_QUOTE = "[\u02ba\u02dd\u02ee\u02f6\u05f2\u05f4\u1cd3\u201c\u201d\u201f\u2033\u2036\u3003\uff02]";
        /** Regular expression matching all Unicode alternatives for <code>.</code>.
	 * @since 1.5 */
        protected final static String REGEX_STOP         = "[.\u0660\u06f0\u0701\u0702\u2024\ua4f8\ua60e]";
        /** Regular expression matching all Unicode alternatives for <code>+</code>.
	 * @since 1.5 */
        protected final static String REGEX_PLUS         = "[+\u16ed\u2795]";
        /** Regular expression matching all Unicode alternatives for <code> </code>.
	 * @since 1.5 */
        protected final static String REGEX_SPACE        = "[ \u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f]";
        /** Regular expression matching all Unicode alternatives for <code>&lt;</code>.
	 * @since 1.5 */
        protected final static String REGEX_LESS_THAN    = "[<\u02c2\u1438\u16b2\u2039\u276e]";
        /** Regular expression matching all Unicode alternatives for <code>&gt;</code>.
	 * @since 1.5 */
        protected final static String REGEX_GREATER_THAN = "[>\u02c3\u1433\u203a\u276f]";
        /** Regular expression matching all Unicode alternatives for <code>=</code>.
	 * @since 1.5 */
        protected final static String REGEX_EQUAL        = "[=\u1400\u2e40\u30a0\ua4ff]";
        static {
                REGEX_UNICODE_CONFUSABLES.put("-", REGEX_DASH);
                REGEX_UNICODE_CONFUSABLES.put("_", REGEX_UNDERSCORE);
                REGEX_UNICODE_CONFUSABLES.put("'", REGEX_QUOTE);
                REGEX_UNICODE_CONFUSABLES.put("\u005c"", REGEX_DOUBLE_QUOTE);
                REGEX_UNICODE_CONFUSABLES.put(".", REGEX_STOP);
                REGEX_UNICODE_CONFUSABLES.put("+", REGEX_PLUS);
                REGEX_UNICODE_CONFUSABLES.put(" ", REGEX_SPACE);
                REGEX_UNICODE_CONFUSABLES.put("<", REGEX_LESS_THAN);
                REGEX_UNICODE_CONFUSABLES.put(">", REGEX_GREATER_THAN);
                REGEX_UNICODE_CONFUSABLES.put("=", REGEX_EQUAL);
        }

        /**
	 * Replace all Unicode characters that can be confused with other ASCI/UTF-8
	 * characters (e.g. different spaces, dashes, ...) in their ASCII version.
	 *
	 * @param adqlQuery	The ADQL query string in which Unicode confusable
	 *                 	characters must be replaced.
	 *
	 * @return	The same query without the most common Unicode confusable
	 *        	characters.
	 *
	 * @since 1.5
	 */
        protected String replaceUnicodeConfusables(final String adqlQuery){
                String newAdqlQuery = adqlQuery;
                for(java.util.Map.Entry<String, String> confusable : REGEX_UNICODE_CONFUSABLES.entrySet())
                        newAdqlQuery = newAdqlQuery.replaceAll(confusable.getValue(), confusable.getKey());
                return newAdqlQuery;
        }

        /**
	 * Tell whether the given token represents the end of an ADQL query.
	 *
	 * @param token	Token to analyze.
	 *
	 * @return	<code>true</code> if the given token represents a query end,
	 *        	<code>false</code> otherwise.
	 *
	 * @since 1.5
	 */
        protected boolean isEnd(final Token token){
                return token.kind == ADQLParserConstants.EOF || token.kind == ADQLParserConstants.EOQ;
        }

        /**
	 * Tell whether the given token must be double quoted.
	 *
	 * <p>
	 * 	This function considers all the following as terms to double quote:
	 * </p>
	 * <ul>
	 * 	<li>SQL reserved keywords</li>,
	 * 	<li>unrecognised regular identifiers (e.g. neither a delimited nor a
	 * 		valid ADQL regular identifier)</li>
	 * 	<li>and ADQL function name without a parameters list.</li>
	 * </ul>
	 *
	 * @param token		The token to analyze.
	 * @param nextToken	The following token. (useful to detect the start of a
	 *                 	function's parameters list)
	 *
	 * @return	<code>true</code> if the given token must be double quoted,
	 *        	<code>false</code> to keep it as provided.
	 *
	 * @since 1.5
	 */
        protected boolean mustEscape(final Token token, final Token nextToken){
                switch(token.kind){
                        case ADQLParserConstants.SQL_RESERVED_WORD:
                                return true;
                        case ADQLParserConstants.REGULAR_IDENTIFIER_CANDIDATE:
                                return !isRegularIdentifier(token.image);
                        default:
                                return isFunctionName(token) && (nextToken == null || nextToken.kind != ADQLParserConstants.LEFT_PAR);
                }
        }

        /**
	 * Tell whether the given token matches to an ADQL function name.
	 *
	 * @param token	The token to analyze.
	 *
	 * @return	<code>true</code> if the given token is an ADQL function name,
	 *        	<code>false</code> otherwise.
	 *
	 * @since 1.5
	 */
        protected boolean isFunctionName(final Token token){
                switch(token.kind){
                        case ADQLParserConstants.COUNT:
                        case ADQLParserConstants.EXISTS:
                        case ADQLParserConstants.AVG:
                        case ADQLParserConstants.MAX:
                        case ADQLParserConstants.MIN:
                        case ADQLParserConstants.SUM:
                        case ADQLParserConstants.BOX:
                        case ADQLParserConstants.CENTROID:
                        case ADQLParserConstants.CIRCLE:
                        case ADQLParserConstants.POINT:
                        case ADQLParserConstants.POLYGON:
                        case ADQLParserConstants.REGION:
                        case ADQLParserConstants.CONTAINS:
                        case ADQLParserConstants.INTERSECTS:
                        case ADQLParserConstants.AREA:
                        case ADQLParserConstants.COORD1:
                        case ADQLParserConstants.COORD2:
                        case ADQLParserConstants.COORDSYS:
                        case ADQLParserConstants.DISTANCE:
                        case ADQLParserConstants.ABS:
                        case ADQLParserConstants.CEILING:
                        case ADQLParserConstants.DEGREES:
                        case ADQLParserConstants.EXP:
                        case ADQLParserConstants.FLOOR:
                        case ADQLParserConstants.LOG:
                        case ADQLParserConstants.LOG10:
                        case ADQLParserConstants.MOD:
                        case ADQLParserConstants.PI:
                        case ADQLParserConstants.POWER:
                        case ADQLParserConstants.RADIANS:
                        case ADQLParserConstants.RAND:
                        case ADQLParserConstants.ROUND:
                        case ADQLParserConstants.SQRT:
                        case ADQLParserConstants.TRUNCATE:
                        case ADQLParserConstants.ACOS:
                        case ADQLParserConstants.ASIN:
                        case ADQLParserConstants.ATAN:
                        case ADQLParserConstants.ATAN2:
                        case ADQLParserConstants.COS:
                        case ADQLParserConstants.COT:
                        case ADQLParserConstants.SIN:
                        case ADQLParserConstants.TAN:
                        case ADQLParserConstants.USING:
                                return true;
                        default:
                                return false;
                }
        }

        /* MAIN PROGRAM */

        /**
	* Gets the specified ADQL query and parses the given ADQL query. The SQL
	* translation is then printed if the syntax is correct.
	* 
	* <p>
	*     <b>ONLY the syntax is checked: the query is NOT EXECUTED !</b>
	* </p>
	*
	* @param args
	
	* @throws Exception
	*/
        public static final void main(String[] args) throws Exception {
                final String USAGE = "Usage:\u005cn    adqlParser.jar [-d] [-v] [-e] [-a|-s] [-f] [<FILE>|<URL>]\u005cn\u005cnNOTE: If no file or URL is given, the ADQL query is expected in the standard\u005cn      input. This query must end with a ';' or <Ctrl+D>!\u005cn\u005cnParameters:\u005cn    -v or --verbose : Print the main steps of the parsing\u005cn    -d or --debug   : Print stack traces when a grave error occurs\u005cn    -e or --explain : Explain the ADQL parsing (or Expand the parsing tree)\u005cn    -a or --adql    : Display the understood ADQL query\u005cn    -s or --sql     : Ask the SQL translation of the given ADQL query\u005cn                      (SQL compatible with PostgreSQL)\u005cn    -f or --try-fix : Try fixing the most common ADQL query issues before\u005cn                      attempting to parse the query.\u005cn\u005cnReturn:\u005cn    By default: nothing if the query is correct. Otherwise a message explaining\u005cn                why the query is not correct is displayed.\u005cn    With the -s option, the SQL translation of the given ADQL query will be\u005cn    returned.\u005cn    With the -a option, the ADQL query is returned as it has been understood.\u005cn\u005cnExit status:\u005cn    0  OK !\u005cn    1  Parameter error (missing or incorrect parameter)\u005cn    2  File error (incorrect file/url, reading error, ...)\u005cn    3  Parsing error (syntactic or semantic error)\u005cn    4  Translation error (a problem has occurred during the translation of the\u005cn       given ADQL query in SQL).";

                ADQLParser parser;

                final String urlRegex = "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";

                String file = null, metaFile = null;
                short mode = -1;
                boolean verbose=false, debug=false, explain=false, tryFix=false;

                // Parameters reading:
                for(int i=0; i<args.length; i++){
                        if (args[i].equalsIgnoreCase("-d") || args[i].equalsIgnoreCase("--debug"))
                                debug = true;
                        else if (args[i].equalsIgnoreCase("-v") || args[i].equalsIgnoreCase("--verbose"))
                                verbose = true;
                        else if (args[i].equalsIgnoreCase("-e") || args[i].equalsIgnoreCase("--explain"))
                                explain = true;
                        else if (args[i].equalsIgnoreCase("-a") || args[i].equalsIgnoreCase("--adql")){
                                if (mode != -1){
                                        System.err.println("((!)) Too much parameter: you must choose between -s, -c, -a or nothing ((!))\u005cn"+USAGE);
                                        System.exit(1);
                                }else
                                        mode = 1;
                        }else if (args[i].equalsIgnoreCase("-s") || args[i].equalsIgnoreCase("--sql")){
                                if (mode != -1){
                                        System.err.println("((!)) Too much parameter: you must choose between -s, -c, -a or nothing ((!))\u005cn"+USAGE);
                                        System.exit(1);
                                }else
                                        mode = 2;
                        }else if (args[i].equalsIgnoreCase("-f") || args[i].equalsIgnoreCase("--try-fix"))
                                tryFix = true;
                        else if (args[i].equalsIgnoreCase("-h") || args[i].equalsIgnoreCase("--help")){
                                System.out.println(USAGE);
                                System.exit(0);
                        }else if (args[i].startsWith("-")){
                                System.err.println("((!)) Unknown parameter: \u005c""+args[i]+"\u005c" ((!))\u005cn"+USAGE);
                                System.exit(1);
                        }else
                                file = args[i].trim();
                }

                try{

                        // Try fixing the query, if asked:
                        if (tryFix) {
                                if (verbose)
                                        System.out.println("((i)) Trying to automatically fix the query...");

                                String query;
                                java.io.InputStream in = null;
                                try {
                                        // get the input stream...
                                        if (file == null || file.length() == 0)
                                                in = System.in;
                                        else if (file.matches(urlRegex))
                                                in = (new java.net.URL(file)).openStream();
                                        else
                                                in = new java.io.FileInputStream(file);

                                        // ...and try fixing the query:
                                        query = (new ADQLParser()).tryQuickFix(in);
                                } finally {
                                        // close the stream (if opened):
                                        if (in != null)
                                                in.close();
                                        in = null;
                                }

                                if (verbose)
                                        System.out.println("((i)) SUGGESTED QUERY:\u005cn" + query);

                                // Initialise the parser with this fixed query:
                                parser = new ADQLParser(new java.io.ByteArrayInputStream(query.getBytes()));
                        }
                        // Otherwise, take the query as provided:
                        else {
                                // Initialise the parser with the specified input:
                                if (file == null || file.length() == 0)
                                        parser = new ADQLParser(System.in);
                                else if (file.matches(urlRegex))
                                        parser = new ADQLParser((new java.net.URL(file)).openStream());
                                else
                                        parser = new ADQLParser(new java.io.FileInputStream(file));
                        }

                        // Enable/Disable the debugging in function of the parameters:
                        parser.setDebug(explain);

                        // Query parsing:
                        try{
                                if (verbose)    System.out.print("((i)) Parsing ADQL query...");
                                ADQLQuery q = parser.parseQuery();
                                if (verbose)    System.out.println("((i)) CORRECT ADQL QUERY ((i))");
                                if (mode==2){
                                        PostgreSQLTranslator translator = new PostgreSQLTranslator();
                                        if (verbose)    System.out.print("((i)) Translating in SQL...");
                                        String sql = translator.translate(q);
                                        if (verbose)    System.out.println("ok");
                                        System.out.println(sql);
                                }else if (mode==1){
                                        System.out.println(q.toADQL());
                                }
                        }catch(UnresolvedIdentifiersException uie){
                                System.err.println("((X)) "+uie.getNbErrors()+" unresolved identifiers:");
                                for(ParseException pe : uie)
                                        System.err.println("\u005ct - at "+pe.getPosition()+": "+uie.getMessage());
                                if (debug)              uie.printStackTrace(System.err);
                                System.exit(3);
                        }catch(ParseException pe){
                                System.err.println("((X)) Syntax error: "+pe.getMessage()+" ((X))");
                                if (debug)              pe.printStackTrace(System.err);
                                System.exit(3);
                        }catch(TranslationException te){
                                if (verbose)    System.out.println("error");
                                System.err.println("((X)) Translation error: "+te.getMessage()+" ((X))");
                                if (debug)              te.printStackTrace(System.err);
                                System.exit(4);
                        }

                }catch(IOException ioe){
                        System.err.println("\u005cn((X)) Error while reading the file \u005c""+file+"\u005c": "+ioe.getMessage()+" ((X))");
                        if (debug)              ioe.printStackTrace(System.err);
                        System.exit(2);
                }

    }

/* ########## */
                                                        /* # SYNTAX # */
                                                        /* ########## */

/* ******************* */
/* GENERAL ADQL SYNTAX */
/* ******************* */
/**
* Parses the ADQL query given at the parser creation or in the {@link ADQLParser#ReInit(java.io.InputStream)}
* or in the <i>parseQuery</i> functions.
*
* @return					The object representation of the query.
* @throws ParseException	If the query syntax is incorrect.
*/
  final public ADQLQuery Query() throws ParseException {
    trace_call("Query");
    try {ADQLQuery q = null;
      q = QueryExpression();
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case 0:{
        jj_consume_token(0);
        break;
        }
      case EOQ:{
        jj_consume_token(EOQ);
        break;
        }
      default:
        jj_la1[0] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
// check the query:
                if (queryChecker != null)
                        queryChecker.check(q);

                {if ("" != null) return q;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("Query");
    }
  }

  final public ADQLQuery QueryExpression() throws ParseException {
    trace_call("QueryExpression");
    try {TextPosition endPos = null;
try{
                        // create the query:
                        query = queryFactory.createQuery();
                        stackQuery.push(query);
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
      Select();
      From();
endPos = query.getFrom().getPosition();
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case WHERE:{
        Where();
endPos = query.getWhere().getPosition();
        break;
        }
      default:
        jj_la1[1] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case GROUP:{
        GroupBy();
endPos = query.getGroupBy().getPosition();
        break;
        }
      default:
        jj_la1[2] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case HAVING:{
        Having();
endPos = query.getHaving().getPosition();
        break;
        }
      default:
        jj_la1[3] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case ORDER:{
        OrderBy();
endPos = query.getOrderBy().getPosition();
        break;
        }
      default:
        jj_la1[4] = jj_gen;
        ;
      }
// set the position of the query:
                query.setPosition(new TextPosition(query.getSelect().getPosition(), endPos));

                // get the previous query (!= null if the current query is a sub-query):
                ADQLQuery previousQuery = stackQuery.pop();
                if (stackQuery.isEmpty())
                        query = null;
                else
                        query = stackQuery.peek();

                {if ("" != null) return previousQuery;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("QueryExpression");
    }
  }

  final public ADQLQuery SubQueryExpression() throws ParseException {
    trace_call("SubQueryExpression");
    try {ADQLQuery q = null; Token start, end;
      start = jj_consume_token(LEFT_PAR);
      q = QueryExpression();
      end = jj_consume_token(RIGHT_PAR);
q.setPosition(new TextPosition(start, end));
                {if ("" != null) return q;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("SubQueryExpression");
    }
  }

  final public void Select() throws ParseException {
    trace_call("Select");
    try {ClauseSelect select = query.getSelect(); SelectItem item=null; Token start,t = null;
      start = jj_consume_token(SELECT);
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case QUANTIFIER:{
        t = jj_consume_token(QUANTIFIER);
select.setDistinctColumns(t.image.equalsIgnoreCase("DISTINCT"));
        break;
        }
      default:
        jj_la1[5] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case TOP:{
        jj_consume_token(TOP);
        t = jj_consume_token(UNSIGNED_INTEGER);
try{
                select.setLimit(Integer.parseInt(t.image));
          }catch(NumberFormatException nfe){
                {if (true) throw new ParseException("[l."+t.beginLine+";c."+t.beginColumn+"] The TOP limit (\u005c""+t.image+"\u005c") isn't a regular unsigned integer !");}
          }
        break;
        }
      default:
        jj_la1[6] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case OFFSET:{
        jj_consume_token(OFFSET);
        t = jj_consume_token(UNSIGNED_INTEGER);
try{
                select.setOffset(Integer.parseInt(t.image));
          }catch(NumberFormatException nfe){
                {if (true) throw new ParseException("[l."+t.beginLine+";c."+t.beginColumn+"] The OFFSET limit (\u005c""+t.image+"\u005c") isn't a regular unsigned integer !");}
          }
        break;
        }
      default:
        jj_la1[7] = jj_gen;
        ;
      }
      item = SelectItem();
select.add(item);
      label_1:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case COMMA:{
          ;
          break;
          }
        default:
          jj_la1[8] = jj_gen;
          break label_1;
        }
        jj_consume_token(COMMA);
        item = SelectItem();
select.add(item);
      }
TextPosition lastItemPos = query.getSelect().get(query.getSelect().size()-1).getPosition();
                select.setPosition(new TextPosition(start.beginLine, start.beginColumn, lastItemPos.endLine, lastItemPos.endColumn));
    } finally {
      trace_return("Select");
    }
  }

  final public SelectItem SelectItem() throws ParseException {
    trace_call("SelectItem");
    try {IdentifierItems identifiers = new IdentifierItems(true); IdentifierItem id = null, label = null; ADQLOperand op = null; SelectItem item; Token starToken;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case ASTERISK:{
        starToken = jj_consume_token(ASTERISK);
item = new SelectAllColumns(query);
                    item.setPosition(new TextPosition(starToken));
                    {if ("" != null) return item;}
        break;
        }
      default:
        jj_la1[13] = jj_gen;
        if (jj_2_1(7)) {
          id = Identifier();
          jj_consume_token(DOT);
identifiers.append(id);
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            id = Identifier();
            jj_consume_token(DOT);
identifiers.append(id);
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case DELIMITED_IDENTIFIER:
            case REGULAR_IDENTIFIER_CANDIDATE:{
              id = Identifier();
              jj_consume_token(DOT);
identifiers.append(id);
              break;
              }
            default:
              jj_la1[9] = jj_gen;
              ;
            }
            break;
            }
          default:
            jj_la1[10] = jj_gen;
            ;
          }
          starToken = jj_consume_token(ASTERISK);
try{
                                        item = new SelectAllColumns( queryFactory.createTable(identifiers, null) );
                                        TextPosition firstPos = identifiers.get(0).position;
                                        item.setPosition(new TextPosition(firstPos.beginLine, firstPos.beginColumn, starToken.endLine, (starToken.endColumn < 0) ? -1 : (starToken.endColumn + 1)));
                                        {if ("" != null) return item;}
                                }catch(Exception ex) {
                                        {if (true) throw generateParseException(ex);}
                                }
        } else {
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case LEFT_PAR:
          case PLUS:
          case MINUS:
          case AVG:
          case MAX:
          case MIN:
          case SUM:
          case COUNT:
          case BOX:
          case CENTROID:
          case CIRCLE:
          case POINT:
          case POLYGON:
          case REGION:
          case CONTAINS:
          case INTERSECTS:
          case AREA:
          case COORD1:
          case COORD2:
          case COORDSYS:
          case DISTANCE:
          case ABS:
          case CEILING:
          case DEGREES:
          case EXP:
          case FLOOR:
          case LOG:
          case LOG10:
          case MOD:
          case PI:
          case POWER:
          case RADIANS:
          case RAND:
          case ROUND:
          case SQRT:
          case TRUNCATE:
          case ACOS:
          case ASIN:
          case ATAN:
          case ATAN2:
          case COS:
          case COT:
          case SIN:
          case TAN:
          case STRING_LITERAL:
          case SCIENTIFIC_NUMBER:
          case UNSIGNED_FLOAT:
          case UNSIGNED_INTEGER:
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            op = ValueExpression();
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case AS:
            case DELIMITED_IDENTIFIER:
            case REGULAR_IDENTIFIER_CANDIDATE:{
              switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
              case AS:{
                jj_consume_token(AS);
                break;
                }
              default:
                jj_la1[11] = jj_gen;
                ;
              }
              label = Identifier();
              break;
              }
            default:
              jj_la1[12] = jj_gen;
              ;
            }
            break;
            }
          default:
            jj_la1[14] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
        }
      }
try{
                        item = queryFactory.createSelectItem(op, (label==null)?null:label.identifier);
                        if (label != null){
                                item.setCaseSensitive(label.caseSensitivity);
                                item.setPosition(new TextPosition(op.getPosition(), label.position));
                        }else
                                item.setPosition(new TextPosition(op.getPosition()));
                        {if ("" != null) return item;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("SelectItem");
    }
  }

  final public void From() throws ParseException {
    trace_call("From");
    try {FromContent content = null, content2 = null;
      try {
        jj_consume_token(FROM);
        content = TableRef();
        label_2:
        while (true) {
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case COMMA:{
            ;
            break;
            }
          default:
            jj_la1[15] = jj_gen;
            break label_2;
          }
          jj_consume_token(COMMA);
          content2 = TableRef();
TextPosition startPos = content.getPosition(), endPos = content2.getPosition();
                   content = queryFactory.createJoin(JoinType.CROSS, content, content2);
                   content.setPosition(new TextPosition(startPos, endPos));
        }
query.setFrom(content);
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
    } finally {
      trace_return("From");
    }
  }

  final public void Where() throws ParseException {
    trace_call("Where");
    try {ClauseConstraints where = query.getWhere(); ADQLConstraint condition; Token start;
      start = jj_consume_token(WHERE);
      ConditionsList(where);
TextPosition endPosition = where.getPosition();
          where.setPosition(new TextPosition(start.beginLine, start.beginColumn, endPosition.endLine, endPosition.endColumn));
    } finally {
      trace_return("Where");
    }
  }

  final public void GroupBy() throws ParseException {
    trace_call("GroupBy");
    try {ClauseADQL<ADQLColumn> groupBy = query.getGroupBy(); ADQLColumn colRef = null; Token start;
      start = jj_consume_token(GROUP);
      jj_consume_token(BY);
      colRef = Column();
groupBy.add(colRef);
      label_3:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case COMMA:{
          ;
          break;
          }
        default:
          jj_la1[16] = jj_gen;
          break label_3;
        }
        jj_consume_token(COMMA);
        colRef = Column();
groupBy.add(colRef);
      }
groupBy.setPosition(new TextPosition(start.beginLine, start.beginColumn, colRef.getPosition().endLine, colRef.getPosition().endColumn));
    } finally {
      trace_return("GroupBy");
    }
  }

  final public void Having() throws ParseException {
    trace_call("Having");
    try {ClauseConstraints having = query.getHaving(); Token start;
      start = jj_consume_token(HAVING);
      ConditionsList(having);
TextPosition endPosition = having.getPosition();
          having.setPosition(new TextPosition(start.beginLine, start.beginColumn, endPosition.endLine, endPosition.endColumn));
    } finally {
      trace_return("Having");
    }
  }

  final public void OrderBy() throws ParseException {
    trace_call("OrderBy");
    try {ClauseADQL<ADQLOrder> orderBy = query.getOrderBy(); ADQLOrder order = null; Token start;
      start = jj_consume_token(ORDER);
      jj_consume_token(BY);
      order = OrderItem();
orderBy.add(order);
      label_4:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case COMMA:{
          ;
          break;
          }
        default:
          jj_la1[17] = jj_gen;
          break label_4;
        }
        jj_consume_token(COMMA);
        order = OrderItem();
orderBy.add(order);
      }
orderBy.setPosition(new TextPosition(start, token));
    } finally {
      trace_return("OrderBy");
    }
  }

/* *************************** */
/* COLUMN AND TABLE REFERENCES */
/* *************************** */
  final public IdentifierItem Identifier() throws ParseException {
    trace_call("Identifier");
    try {Token t;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case REGULAR_IDENTIFIER_CANDIDATE:{
        t = jj_consume_token(REGULAR_IDENTIFIER_CANDIDATE);
testRegularIdentifier(t);
                        {if ("" != null) return new IdentifierItem(t, false);}
        break;
        }
      case DELIMITED_IDENTIFIER:{
        t = jj_consume_token(DELIMITED_IDENTIFIER);
{if ("" != null) return new IdentifierItem(t, true);}
        break;
        }
      default:
        jj_la1[18] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("Identifier");
    }
  }

/**
 * Extracts the name of a table with its possible catalog and schema prefixes.
 * 
 * @return A {@link IdentifierItems} which contains at most three items: catalogName, schemaName and tableName.
 */
  final public IdentifierItems TableName() throws ParseException {
    trace_call("TableName");
    try {IdentifierItems identifiers=new IdentifierItems(true); IdentifierItem id=null;
      id = Identifier();
identifiers.append(id);
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case DOT:{
        jj_consume_token(DOT);
        id = Identifier();
identifiers.append(id);
        break;
        }
      default:
        jj_la1[19] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case DOT:{
        jj_consume_token(DOT);
        id = Identifier();
identifiers.append(id);
        break;
        }
      default:
        jj_la1[20] = jj_gen;
        ;
      }
{if ("" != null) return identifiers;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("TableName");
    }
  }

/**
 * Extracts the name of a column with its possible catalog, schema and table prefixes.
 * 
 * @return A {@link IdentifierItems} which contains at most four items: catalogName, schemaName, tableName and columnName.
 */
  final public IdentifierItems ColumnName() throws ParseException {
    trace_call("ColumnName");
    try {IdentifierItem id; IdentifierItems table=null, identifiers=new IdentifierItems(false);
      id = Identifier();
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case DOT:{
        jj_consume_token(DOT);
        table = TableName();
        break;
        }
      default:
        jj_la1[21] = jj_gen;
        ;
      }
identifiers.append(id);
                if (table != null){
                        for(int i=0; i<table.size(); i++)
                                identifiers.append(table.get(i));
                }
                {if ("" != null) return identifiers;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("ColumnName");
    }
  }

  final public ADQLColumn Column() throws ParseException {
    trace_call("Column");
    try {IdentifierItems identifiers;
      identifiers = ColumnName();
try{
                        {if ("" != null) return queryFactory.createColumn(identifiers);}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("Column");
    }
  }

  final public ADQLOrder OrderItem() throws ParseException {
    trace_call("OrderItem");
    try {IdentifierItem identifier = null; Token ind = null, desc = null;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case DELIMITED_IDENTIFIER:
      case REGULAR_IDENTIFIER_CANDIDATE:{
        identifier = Identifier();
        break;
        }
      case UNSIGNED_INTEGER:{
        ind = jj_consume_token(UNSIGNED_INTEGER);
        break;
        }
      default:
        jj_la1[22] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case ASC:
      case DESC:{
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case ASC:{
          jj_consume_token(ASC);
          break;
          }
        case DESC:{
          desc = jj_consume_token(DESC);
          break;
          }
        default:
          jj_la1[23] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
        break;
        }
      default:
        jj_la1[24] = jj_gen;
        ;
      }
try{
                        ADQLOrder order = null;
                        if (identifier != null){
                                order = queryFactory.createOrder(identifier, desc!=null);
                                order.setPosition(identifier.position);
                        }else{
                                order = queryFactory.createOrder(Integer.parseInt(ind.image), desc!=null);
                                order.setPosition(new TextPosition(ind));
                        }
                        {if ("" != null) return order;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("OrderItem");
    }
  }

  final public FromContent SimpleTableRef() throws ParseException {
    trace_call("SimpleTableRef");
    try {IdentifierItem alias = null; IdentifierItems identifiers = null; ADQLQuery subQuery = null; FromContent content = null; Token start,end;
      try {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case DELIMITED_IDENTIFIER:
        case REGULAR_IDENTIFIER_CANDIDATE:{
          identifiers = TableName();
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case AS:
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case AS:{
              jj_consume_token(AS);
              break;
              }
            default:
              jj_la1[25] = jj_gen;
              ;
            }
            alias = Identifier();
            break;
            }
          default:
            jj_la1[26] = jj_gen;
            ;
          }
content = queryFactory.createTable(identifiers, alias);
                          if (alias == null)
                                content.setPosition(new TextPosition(identifiers.get(0).position, identifiers.get(identifiers.size()-1).position));
                          else
                                content.setPosition(new TextPosition(identifiers.get(0).position, alias.position));
                          {if ("" != null) return content;}
          break;
          }
        default:
          jj_la1[28] = jj_gen;
          if (jj_2_2(2)) {
            subQuery = SubQueryExpression();
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case AS:{
              jj_consume_token(AS);
              break;
              }
            default:
              jj_la1[27] = jj_gen;
              ;
            }
            alias = Identifier();
content = queryFactory.createTable(subQuery, alias);
                          if (alias == null)
                                content.setPosition(new TextPosition(subQuery.getPosition()));
                          else
                                content.setPosition(new TextPosition(subQuery.getPosition(), alias.position));
                          {if ("" != null) return content;}
          } else {
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case LEFT_PAR:{
              start = jj_consume_token(LEFT_PAR);
              content = JoinedTable();
              end = jj_consume_token(RIGHT_PAR);
content.setPosition(new TextPosition(start, end));
                          {if ("" != null) return content;}
              break;
              }
            default:
              jj_la1[29] = jj_gen;
              jj_consume_token(-1);
              throw new ParseException();
            }
          }
        }
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("SimpleTableRef");
    }
  }

  final public FromContent TableRef() throws ParseException {
    trace_call("TableRef");
    try {FromContent content;
      content = SimpleTableRef();
      label_5:
      while (true) {
        if (jj_2_3(2)) {
          ;
        } else {
          break label_5;
        }
        content = JoinSpecification(content);
      }
{if ("" != null) return content;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("TableRef");
    }
  }

  final public FromContent JoinedTable() throws ParseException {
    trace_call("JoinedTable");
    try {FromContent content;
      content = SimpleTableRef();
      label_6:
      while (true) {
        content = JoinSpecification(content);
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case NATURAL:
        case INNER:
        case RIGHT:
        case LEFT:
        case FULL:
        case JOIN:{
          ;
          break;
          }
        default:
          jj_la1[30] = jj_gen;
          break label_6;
        }
      }
{if ("" != null) return content;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("JoinedTable");
    }
  }

  final public ADQLJoin JoinSpecification(FromContent leftTable) throws ParseException {
    trace_call("JoinSpecification");
    try {boolean natural = false; JoinType type = JoinType.INNER;  ClauseConstraints condition = new ClauseConstraints("ON"); ArrayList<ADQLColumn> lstColumns=new ArrayList<ADQLColumn>(); IdentifierItem id; FromContent rightTable; ADQLJoin join; Token lastPar;
      try {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case NATURAL:{
          jj_consume_token(NATURAL);
natural=true;
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case INNER:
          case RIGHT:
          case LEFT:
          case FULL:{
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case INNER:{
              jj_consume_token(INNER);
              break;
              }
            case RIGHT:
            case LEFT:
            case FULL:{
              switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
              case LEFT:{
                jj_consume_token(LEFT);
type = JoinType.OUTER_LEFT;
                break;
                }
              case RIGHT:{
                jj_consume_token(RIGHT);
type = JoinType.OUTER_RIGHT;
                break;
                }
              case FULL:{
                jj_consume_token(FULL);
type = JoinType.OUTER_FULL;
                break;
                }
              default:
                jj_la1[31] = jj_gen;
                jj_consume_token(-1);
                throw new ParseException();
              }
              switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
              case OUTER:{
                jj_consume_token(OUTER);
                break;
                }
              default:
                jj_la1[32] = jj_gen;
                ;
              }
              break;
              }
            default:
              jj_la1[33] = jj_gen;
              jj_consume_token(-1);
              throw new ParseException();
            }
            break;
            }
          default:
            jj_la1[34] = jj_gen;
            ;
          }
          jj_consume_token(JOIN);
          rightTable = SimpleTableRef();
join = queryFactory.createJoin(type, leftTable, rightTable);
                          join.setPosition(new TextPosition(leftTable.getPosition(), rightTable.getPosition()));
                          {if ("" != null) return join;}
          break;
          }
        case INNER:
        case RIGHT:
        case LEFT:
        case FULL:
        case JOIN:{
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case INNER:
          case RIGHT:
          case LEFT:
          case FULL:{
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case INNER:{
              jj_consume_token(INNER);
              break;
              }
            case RIGHT:
            case LEFT:
            case FULL:{
              switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
              case LEFT:{
                jj_consume_token(LEFT);
type = JoinType.OUTER_LEFT;
                break;
                }
              case RIGHT:{
                jj_consume_token(RIGHT);
type = JoinType.OUTER_RIGHT;
                break;
                }
              case FULL:{
                jj_consume_token(FULL);
type = JoinType.OUTER_FULL;
                break;
                }
              default:
                jj_la1[35] = jj_gen;
                jj_consume_token(-1);
                throw new ParseException();
              }
              switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
              case OUTER:{
                jj_consume_token(OUTER);
                break;
                }
              default:
                jj_la1[36] = jj_gen;
                ;
              }
              break;
              }
            default:
              jj_la1[37] = jj_gen;
              jj_consume_token(-1);
              throw new ParseException();
            }
            break;
            }
          default:
            jj_la1[38] = jj_gen;
            ;
          }
          jj_consume_token(JOIN);
          rightTable = SimpleTableRef();
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case ON:{
            jj_consume_token(ON);
            ConditionsList(condition);
join = queryFactory.createJoin(type, leftTable, rightTable, condition);
                                  join.setPosition(new TextPosition(leftTable.getPosition(), condition.getPosition()));
                                  {if ("" != null) return join;}
            break;
            }
          case USING:{
            jj_consume_token(USING);
            jj_consume_token(LEFT_PAR);
            id = Identifier();
lstColumns.add( queryFactory.createColumn(id) );
            label_7:
            while (true) {
              switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
              case COMMA:{
                ;
                break;
                }
              default:
                jj_la1[39] = jj_gen;
                break label_7;
              }
              jj_consume_token(COMMA);
              id = Identifier();
lstColumns.add( queryFactory.createColumn(id) );
            }
            lastPar = jj_consume_token(RIGHT_PAR);
join = queryFactory.createJoin(type, leftTable, rightTable, lstColumns);
                                  join.setPosition(new TextPosition(leftTable.getPosition().beginLine, leftTable.getPosition().beginColumn, lastPar.endLine, (lastPar.endColumn < 0) ? -1 : (lastPar.endColumn + 1)));
                                  {if ("" != null) return join;}
            break;
            }
          default:
            jj_la1[40] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
          break;
          }
        default:
          jj_la1[41] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("JoinSpecification");
    }
  }

/* ****** */
/* STRING */
/* ****** */
  final public StringConstant String() throws ParseException {
    trace_call("String");
    try {Token t, start=null; String str=""; StringConstant cst;
      label_8:
      while (true) {
        t = jj_consume_token(STRING_LITERAL);
str += t.image.substring(1, t.image.length()-1).replaceAll("''", "'");
                if (start == null)
                        start = t;
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case STRING_LITERAL:{
          ;
          break;
          }
        default:
          jj_la1[42] = jj_gen;
          break label_8;
        }
      }
try{
                  cst = queryFactory.createStringConstant(str);
                  cst.setPosition(new TextPosition(start, t));
                  {if ("" != null) return cst;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("String");
    }
  }

/* ************* */
/* NUMERIC TYPES */
/* ************* */
  final public NumericConstant UnsignedNumeric() throws ParseException {
    trace_call("UnsignedNumeric");
    try {Token t; NumericConstant cst;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case SCIENTIFIC_NUMBER:{
        t = jj_consume_token(SCIENTIFIC_NUMBER);
        break;
        }
      case UNSIGNED_FLOAT:{
        t = jj_consume_token(UNSIGNED_FLOAT);
        break;
        }
      case UNSIGNED_INTEGER:{
        t = jj_consume_token(UNSIGNED_INTEGER);
        break;
        }
      default:
        jj_la1[43] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
try{
                  cst = queryFactory.createNumericConstant(t.image);
                  cst.setPosition(new TextPosition(t));
                  {if ("" != null) return cst;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("UnsignedNumeric");
    }
  }

  final public NumericConstant UnsignedFloat() throws ParseException {
    trace_call("UnsignedFloat");
    try {Token t; NumericConstant cst;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case UNSIGNED_INTEGER:{
        t = jj_consume_token(UNSIGNED_INTEGER);
        break;
        }
      case UNSIGNED_FLOAT:{
        t = jj_consume_token(UNSIGNED_FLOAT);
        break;
        }
      default:
        jj_la1[44] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
try{
                        cst = queryFactory.createNumericConstant(t.image);
                        cst.setPosition(new TextPosition(t));
                        {if ("" != null) return cst;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("UnsignedFloat");
    }
  }

  final public NumericConstant SignedInteger() throws ParseException {
    trace_call("SignedInteger");
    try {Token sign=null, number; NumericConstant cst;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case PLUS:
      case MINUS:{
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case PLUS:{
          sign = jj_consume_token(PLUS);
          break;
          }
        case MINUS:{
          sign = jj_consume_token(MINUS);
          break;
          }
        default:
          jj_la1[45] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
        break;
        }
      default:
        jj_la1[46] = jj_gen;
        ;
      }
      number = jj_consume_token(UNSIGNED_INTEGER);
try{
                        if (sign == null){                              cst = queryFactory.createNumericConstant(number.image);
                                cst.setPosition(new TextPosition(number));
                        }else{                          cst = queryFactory.createNumericConstant(sign.image+number.image);
                                cst.setPosition(new TextPosition(sign, number));
                        }
                        {if ("" != null) return cst;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("SignedInteger");
    }
  }

/* *********** */
/* EXPRESSIONS */
/* *********** */
  final public ADQLOperand NumericValueExpressionPrimary() throws ParseException {
    trace_call("NumericValueExpressionPrimary");
    try {ADQLColumn column; ADQLOperand op; Token left, right;
      try {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case SCIENTIFIC_NUMBER:
        case UNSIGNED_FLOAT:
        case UNSIGNED_INTEGER:{
          // unsigned_value_specification
                            op = UnsignedNumeric();
{if ("" != null) return op;}
          break;
          }
        case DELIMITED_IDENTIFIER:
        case REGULAR_IDENTIFIER_CANDIDATE:{
          column = Column();
column.setExpectedType('N'); {if ("" != null) return column;}
          break;
          }
        case AVG:
        case MAX:
        case MIN:
        case SUM:
        case COUNT:{
          op = SqlFunction();
{if ("" != null) return op;}
          break;
          }
        case LEFT_PAR:{
          left = jj_consume_token(LEFT_PAR);
          op = NumericExpression();
          right = jj_consume_token(RIGHT_PAR);
WrappedOperand wop = queryFactory.createWrappedOperand(op); wop.setPosition(new TextPosition(left, right)); {if ("" != null) return wop;}
          break;
          }
        default:
          jj_la1[47] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("NumericValueExpressionPrimary");
    }
  }

  final public ADQLOperand StringValueExpressionPrimary() throws ParseException {
    trace_call("StringValueExpressionPrimary");
    try {StringConstant expr; ADQLColumn column; ADQLOperand op; Token left, right;
      try {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case STRING_LITERAL:{
          // string
                            expr = String();
{if ("" != null) return expr;}
          break;
          }
        case SCIENTIFIC_NUMBER:
        case UNSIGNED_FLOAT:
        case UNSIGNED_INTEGER:{
          op = UnsignedNumeric();
{if ("" != null) return op;}
          break;
          }
        case AVG:
        case MAX:
        case MIN:
        case SUM:
        case COUNT:{
          op = SqlFunction();
{if ("" != null) return op;}
          break;
          }
        case DELIMITED_IDENTIFIER:
        case REGULAR_IDENTIFIER_CANDIDATE:{
          column = Column();
column.setExpectedType('*'); {if ("" != null) return column;}
          break;
          }
        case LEFT_PAR:{
          left = jj_consume_token(LEFT_PAR);
          op = ValueExpression();
          right = jj_consume_token(RIGHT_PAR);
WrappedOperand wop = queryFactory.createWrappedOperand(op); wop.setPosition(new TextPosition(left, right)); {if ("" != null) return wop;}
          break;
          }
        default:
          jj_la1[48] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("StringValueExpressionPrimary");
    }
  }

  final public ADQLOperand ValueExpression() throws ParseException {
    trace_call("ValueExpression");
    try {ADQLOperand valueExpr = null; Token left, right;
      try {
        if (jj_2_4(2147483647)) {
          valueExpr = NumericExpression();
        } else if (jj_2_5(2147483647)) {
          valueExpr = StringExpression();
        } else if (jj_2_6(2147483647)) {
          left = jj_consume_token(LEFT_PAR);
          valueExpr = ValueExpression();
          right = jj_consume_token(RIGHT_PAR);
valueExpr = queryFactory.createWrappedOperand(valueExpr); ((WrappedOperand)valueExpr).setPosition(new TextPosition(left, right));
        } else if (jj_2_7(2147483647)) {
          valueExpr = UserDefinedFunction();
        } else if (jj_2_8(2)) {
          valueExpr = GeometryValueFunction();
        } else if (jj_2_9(2147483647)) {
          valueExpr = Column();
        } else if (jj_2_10(2147483647)) {
          valueExpr = StringFactor();
        } else if (jj_2_11(3)) {
          valueExpr = Factor();
        } else {
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            valueExpr = Column();
            break;
            }
          default:
            jj_la1[49] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
        }
{if ("" != null) return valueExpr;}
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("ValueExpression");
    }
  }

  final public ADQLOperand NumericExpression() throws ParseException {
    trace_call("NumericExpression");
    try {Token sign=null; ADQLOperand leftOp, rightOp=null;
      leftOp = NumericTerm();
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case PLUS:
      case MINUS:{
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case PLUS:{
          sign = jj_consume_token(PLUS);
          break;
          }
        case MINUS:{
          sign = jj_consume_token(MINUS);
          break;
          }
        default:
          jj_la1[50] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
        rightOp = NumericExpression();
        break;
        }
      default:
        jj_la1[51] = jj_gen;
        ;
      }
if (sign == null)
                {if ("" != null) return leftOp;}
        else{
                try{
                        Operation operation = queryFactory.createOperation(leftOp, OperationType.getOperator(sign.image), rightOp);
                        operation.setPosition(new TextPosition(leftOp.getPosition(), rightOp.getPosition()));
                        {if ("" != null) return operation;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
        }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("NumericExpression");
    }
  }

  final public ADQLOperand NumericTerm() throws ParseException {
    trace_call("NumericTerm");
    try {Token sign=null; ADQLOperand leftOp, rightOp=null;
      leftOp = Factor();
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case ASTERISK:
      case DIVIDE:{
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case ASTERISK:{
          sign = jj_consume_token(ASTERISK);
          break;
          }
        case DIVIDE:{
          sign = jj_consume_token(DIVIDE);
          break;
          }
        default:
          jj_la1[52] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
        rightOp = NumericTerm();
        break;
        }
      default:
        jj_la1[53] = jj_gen;
        ;
      }
if (sign == null)
                {if ("" != null) return leftOp;}
        else{
                try{
                        Operation operation = queryFactory.createOperation(leftOp, OperationType.getOperator(sign.image), rightOp);
                        operation.setPosition(new TextPosition(leftOp.getPosition(), rightOp.getPosition()));
                        {if ("" != null) return operation;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
        }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("NumericTerm");
    }
  }

  final public ADQLOperand Factor() throws ParseException {
    trace_call("Factor");
    try {boolean negative = false; Token minusSign = null; ADQLOperand op;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case PLUS:
      case MINUS:{
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case PLUS:{
          jj_consume_token(PLUS);
          break;
          }
        case MINUS:{
          minusSign = jj_consume_token(MINUS);
negative = true;
          break;
          }
        default:
          jj_la1[54] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
        break;
        }
      default:
        jj_la1[55] = jj_gen;
        ;
      }
      if (jj_2_12(2)) {
        op = NumericFunction();
      } else {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case LEFT_PAR:
        case AVG:
        case MAX:
        case MIN:
        case SUM:
        case COUNT:
        case SCIENTIFIC_NUMBER:
        case UNSIGNED_FLOAT:
        case UNSIGNED_INTEGER:
        case DELIMITED_IDENTIFIER:
        case REGULAR_IDENTIFIER_CANDIDATE:{
          op = NumericValueExpressionPrimary();
          break;
          }
        default:
          jj_la1[56] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      }
if (negative){
                        try{
                                TextPosition position = op.getPosition();
                                op = queryFactory.createNegativeOperand(op);
                                NegativeOperand negativeOp = (NegativeOperand)op;
                                if (minusSign != null)
                                        negativeOp.setPosition(new TextPosition(minusSign.beginLine, minusSign.beginColumn, position.endLine, position.endColumn));
                                else
                                        negativeOp.setPosition(position);
                        }catch(Exception ex){
                                {if (true) throw generateParseException(ex);}
                        }
                }

                {if ("" != null) return op;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("Factor");
    }
  }

  final public ADQLOperand StringExpression() throws ParseException {
    trace_call("StringExpression");
    try {ADQLOperand leftOp; ADQLOperand rightOp = null;
      leftOp = StringFactor();
      label_9:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case CONCAT:{
          ;
          break;
          }
        default:
          jj_la1[57] = jj_gen;
          break label_9;
        }
        jj_consume_token(CONCAT);
        rightOp = StringFactor();
if (!(leftOp instanceof Concatenation)){
                                try{
                                        ADQLOperand temp = leftOp;
                                        leftOp = queryFactory.createConcatenation();
                                        ((Concatenation)leftOp).add(temp);
                                }catch(Exception ex){
                                        {if (true) throw generateParseException(ex);}
                                }
                        }
                        ((Concatenation)leftOp).add(rightOp);
      }
if (leftOp instanceof Concatenation){
                        Concatenation concat = (Concatenation)leftOp;
                        concat.setPosition(new TextPosition(concat.get(0).getPosition(), concat.get(concat.size()-1).getPosition()));
                }
          {if ("" != null) return leftOp;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("StringExpression");
    }
  }

  final public ADQLOperand StringFactor() throws ParseException {
    trace_call("StringFactor");
    try {ADQLOperand op;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case COORDSYS:{
        op = ExtractCoordSys();
        break;
        }
      default:
        jj_la1[58] = jj_gen;
        if (jj_2_13(2)) {
          op = UserDefinedFunction();
((UserDefinedFunction)op).setExpectedType('S');
        } else {
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case LEFT_PAR:
          case AVG:
          case MAX:
          case MIN:
          case SUM:
          case COUNT:
          case STRING_LITERAL:
          case SCIENTIFIC_NUMBER:
          case UNSIGNED_FLOAT:
          case UNSIGNED_INTEGER:
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            op = StringValueExpressionPrimary();
            break;
            }
          default:
            jj_la1[59] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
        }
      }
{if ("" != null) return op;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("StringFactor");
    }
  }

  final public GeometryValue<GeometryFunction> GeometryExpression() throws ParseException {
    trace_call("GeometryExpression");
    try {ADQLColumn col = null; GeometryFunction gf = null;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case DELIMITED_IDENTIFIER:
      case REGULAR_IDENTIFIER_CANDIDATE:{
        col = Column();
        break;
        }
      case BOX:
      case CENTROID:
      case CIRCLE:
      case POINT:
      case POLYGON:
      case REGION:{
        gf = GeometryValueFunction();
        break;
        }
      default:
        jj_la1[60] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
if (col != null){
                        col.setExpectedType('G');
                        {if ("" != null) return new GeometryValue<GeometryFunction>(col);}
                }else
                        {if ("" != null) return new GeometryValue<GeometryFunction>(gf);}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("GeometryExpression");
    }
  }

/* ********************************** */
/* BOOLEAN EXPRESSIONS (WHERE clause) */
/* ********************************** */
  final public ClauseConstraints ConditionsList(ClauseConstraints clause) throws ParseException {
    trace_call("ConditionsList");
    try {ADQLConstraint constraint = null; Token op = null; boolean notOp = false;
      try {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case NOT:{
          op = jj_consume_token(NOT);
notOp = true;
          break;
          }
        default:
          jj_la1[61] = jj_gen;
          ;
        }
        constraint = Constraint();
if (notOp){
                                TextPosition oldPos = constraint.getPosition();
                                constraint = queryFactory.createNot(constraint);
                                ((NotConstraint)constraint).setPosition(new TextPosition(op.beginLine, op.beginColumn, oldPos.endLine, oldPos.endColumn));
                        }
                        notOp = false;

                        if (clause instanceof ADQLConstraint)
                                clause.add(constraint);
                        else
                                clause.add(constraint);
        label_10:
        while (true) {
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case AND:
          case OR:{
            ;
            break;
            }
          default:
            jj_la1[62] = jj_gen;
            break label_10;
          }
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case AND:{
            op = jj_consume_token(AND);
            break;
            }
          case OR:{
            op = jj_consume_token(OR);
            break;
            }
          default:
            jj_la1[63] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case NOT:{
            jj_consume_token(NOT);
notOp = true;
            break;
            }
          default:
            jj_la1[64] = jj_gen;
            ;
          }
          constraint = Constraint();
if (notOp){
                                        TextPosition oldPos = constraint.getPosition();
                                        constraint = queryFactory.createNot(constraint);
                                        ((NotConstraint)constraint).setPosition(new TextPosition(op.beginLine, op.beginColumn, oldPos.endLine, oldPos.endColumn));
                                }
                                notOp = false;

                                if (clause instanceof ADQLConstraint)
                                        clause.add(op.image, constraint);
                                else
                                        clause.add(op.image, constraint);
        }
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
if (!clause.isEmpty()){
                        TextPosition start = clause.get(0).getPosition();
                        TextPosition end = clause.get(clause.size()-1).getPosition();
                        clause.setPosition(new TextPosition(start, end));
                }
                {if ("" != null) return clause;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("ConditionsList");
    }
  }

  final public ADQLConstraint Constraint() throws ParseException {
    trace_call("Constraint");
    try {ADQLConstraint constraint =  null; Token start, end;
      if (jj_2_14(2147483647)) {
        constraint = Predicate();
      } else {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case LEFT_PAR:{
          start = jj_consume_token(LEFT_PAR);
try{
                                constraint = queryFactory.createGroupOfConstraints();
                        }catch(Exception ex){
                                {if (true) throw generateParseException(ex);}
                        }
          ConditionsList((ConstraintsGroup)constraint);
          end = jj_consume_token(RIGHT_PAR);
((ConstraintsGroup)constraint).setPosition(new TextPosition(start, end));
          break;
          }
        default:
          jj_la1[65] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      }
{if ("" != null) return constraint;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("Constraint");
    }
  }

  final public ADQLConstraint Predicate() throws ParseException {
    trace_call("Predicate");
    try {ADQLQuery q=null; ADQLColumn column=null; ADQLOperand strExpr1=null, strExpr2=null; ADQLOperand op; Token start, notToken = null, end; ADQLConstraint constraint = null;
      try {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case EXISTS:{
          start = jj_consume_token(EXISTS);
          q = SubQueryExpression();
Exists e = queryFactory.createExists(q);
                          e.setPosition(new TextPosition(start.beginLine, start.beginColumn, q.getPosition().endLine, q.getPosition().endColumn));
                          {if ("" != null) return e;}
          break;
          }
        default:
          jj_la1[70] = jj_gen;
          if (jj_2_16(2147483647)) {
            column = Column();
            jj_consume_token(IS);
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case NOT:{
              notToken = jj_consume_token(NOT);
              break;
              }
            default:
              jj_la1[66] = jj_gen;
              ;
            }
            end = jj_consume_token(NULL);
IsNull in = queryFactory.createIsNull((notToken!=null), column);
                      in.setPosition(new TextPosition(column.getPosition().beginLine, column.getPosition().beginColumn, end.endLine, (end.endColumn < 0) ? -1 : (end.endColumn + 1)));
                      {if ("" != null) return in;}
          } else if (jj_2_17(2147483647)) {
            strExpr1 = StringExpression();
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case NOT:{
              notToken = jj_consume_token(NOT);
              break;
              }
            default:
              jj_la1[67] = jj_gen;
              ;
            }
            jj_consume_token(LIKE);
            strExpr2 = StringExpression();
Comparison comp = queryFactory.createComparison(strExpr1, (notToken==null)?ComparisonOperator.LIKE:ComparisonOperator.NOTLIKE, strExpr2);
                      comp.setPosition(new TextPosition(strExpr1.getPosition(), strExpr2.getPosition()));
                      {if ("" != null) return comp;}
          } else {
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case LEFT_PAR:
            case PLUS:
            case MINUS:
            case AVG:
            case MAX:
            case MIN:
            case SUM:
            case COUNT:
            case BOX:
            case CENTROID:
            case CIRCLE:
            case POINT:
            case POLYGON:
            case REGION:
            case CONTAINS:
            case INTERSECTS:
            case AREA:
            case COORD1:
            case COORD2:
            case COORDSYS:
            case DISTANCE:
            case ABS:
            case CEILING:
            case DEGREES:
            case EXP:
            case FLOOR:
            case LOG:
            case LOG10:
            case MOD:
            case PI:
            case POWER:
            case RADIANS:
            case RAND:
            case ROUND:
            case SQRT:
            case TRUNCATE:
            case ACOS:
            case ASIN:
            case ATAN:
            case ATAN2:
            case COS:
            case COT:
            case SIN:
            case TAN:
            case STRING_LITERAL:
            case SCIENTIFIC_NUMBER:
            case UNSIGNED_FLOAT:
            case UNSIGNED_INTEGER:
            case DELIMITED_IDENTIFIER:
            case REGULAR_IDENTIFIER_CANDIDATE:{
              op = ValueExpression();
              switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
              case EQUAL:
              case NOT_EQUAL:
              case LESS_THAN:
              case LESS_EQUAL_THAN:
              case GREATER_THAN:
              case GREATER_EQUAL_THAN:{
                constraint = ComparisonEnd(op);
                break;
                }
              default:
                jj_la1[68] = jj_gen;
                if (jj_2_15(2)) {
                  constraint = BetweenEnd(op);
                } else {
                  switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
                  case NOT:
                  case IN:{
                    constraint = InEnd(op);
                    break;
                    }
                  default:
                    jj_la1[69] = jj_gen;
                    jj_consume_token(-1);
                    throw new ParseException();
                  }
                }
              }
              break;
              }
            default:
              jj_la1[71] = jj_gen;
              jj_consume_token(-1);
              throw new ParseException();
            }
          }
        }
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
{if ("" != null) return constraint;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("Predicate");
    }
  }

  final public Comparison ComparisonEnd(ADQLOperand leftOp) throws ParseException {
    trace_call("ComparisonEnd");
    try {Token comp; ADQLOperand rightOp;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case EQUAL:{
        comp = jj_consume_token(EQUAL);
        break;
        }
      case NOT_EQUAL:{
        comp = jj_consume_token(NOT_EQUAL);
        break;
        }
      case LESS_THAN:{
        comp = jj_consume_token(LESS_THAN);
        break;
        }
      case LESS_EQUAL_THAN:{
        comp = jj_consume_token(LESS_EQUAL_THAN);
        break;
        }
      case GREATER_THAN:{
        comp = jj_consume_token(GREATER_THAN);
        break;
        }
      case GREATER_EQUAL_THAN:{
        comp = jj_consume_token(GREATER_EQUAL_THAN);
        break;
        }
      default:
        jj_la1[72] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      rightOp = ValueExpression();
try{
                        Comparison comparison = queryFactory.createComparison(leftOp, ComparisonOperator.getOperator(comp.image), rightOp);
                        comparison.setPosition(new TextPosition(leftOp.getPosition(), rightOp.getPosition()));
                        {if ("" != null) return comparison;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("ComparisonEnd");
    }
  }

  final public Between BetweenEnd(ADQLOperand leftOp) throws ParseException {
    trace_call("BetweenEnd");
    try {Token start,notToken=null; ADQLOperand min, max;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case NOT:{
        notToken = jj_consume_token(NOT);
        break;
        }
      default:
        jj_la1[73] = jj_gen;
        ;
      }
      start = jj_consume_token(BETWEEN);
      min = ValueExpression();
      jj_consume_token(AND);
      max = ValueExpression();
try{
                        Between bet = queryFactory.createBetween((notToken!=null), leftOp, min, max);
                        if (notToken != null) start = notToken;
                        bet.setPosition(new TextPosition(start.beginLine, start.beginColumn, max.getPosition().endLine, max.getPosition().endColumn));
                        {if ("" != null) return bet;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("BetweenEnd");
    }
  }

  final public In InEnd(ADQLOperand leftOp) throws ParseException {
    trace_call("InEnd");
    try {Token not=null, start; ADQLQuery q = null; ADQLOperand item; Vector<ADQLOperand> items = new Vector<ADQLOperand>();
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case NOT:{
        not = jj_consume_token(NOT);
        break;
        }
      default:
        jj_la1[74] = jj_gen;
        ;
      }
      start = jj_consume_token(IN);
      if (jj_2_18(2)) {
        q = SubQueryExpression();
      } else {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case LEFT_PAR:{
          jj_consume_token(LEFT_PAR);
          item = ValueExpression();
items.add(item);
          label_11:
          while (true) {
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case COMMA:{
              ;
              break;
              }
            default:
              jj_la1[75] = jj_gen;
              break label_11;
            }
            jj_consume_token(COMMA);
            item = ValueExpression();
items.add(item);
          }
          jj_consume_token(RIGHT_PAR);
          break;
          }
        default:
          jj_la1[76] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      }
try{
                        In in;
                        start = (not!=null) ? not : start;
                        if (q != null){
                                in = queryFactory.createIn(leftOp, q, not!=null);
                                in.setPosition(new TextPosition(start.beginLine, start.beginColumn, q.getPosition().endLine, q.getPosition().endColumn));
                        }else{
                                ADQLOperand[] list = new ADQLOperand[items.size()];
                                int i=0;
                                for(ADQLOperand op : items)
                                        list[i++] = op;
                                in = queryFactory.createIn(leftOp, list, not!=null);
                                in.setPosition(new TextPosition(start.beginLine, start.beginColumn, list[list.length-1].getPosition().endLine, list[list.length-1].getPosition().endColumn));
                        }
                        {if ("" != null) return in;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("InEnd");
    }
  }

/* ************* */
/* SQL FUNCTIONS */
/* ************* */
  final public SQLFunction SqlFunction() throws ParseException {
    trace_call("SqlFunction");
    try {Token fct, all=null, distinct=null, end; ADQLOperand op=null; SQLFunction funct = null;
      try {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case COUNT:{
          fct = jj_consume_token(COUNT);
          jj_consume_token(LEFT_PAR);
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case QUANTIFIER:{
            distinct = jj_consume_token(QUANTIFIER);
            break;
            }
          default:
            jj_la1[77] = jj_gen;
            ;
          }
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case ASTERISK:{
            all = jj_consume_token(ASTERISK);
            break;
            }
          case LEFT_PAR:
          case PLUS:
          case MINUS:
          case AVG:
          case MAX:
          case MIN:
          case SUM:
          case COUNT:
          case BOX:
          case CENTROID:
          case CIRCLE:
          case POINT:
          case POLYGON:
          case REGION:
          case CONTAINS:
          case INTERSECTS:
          case AREA:
          case COORD1:
          case COORD2:
          case COORDSYS:
          case DISTANCE:
          case ABS:
          case CEILING:
          case DEGREES:
          case EXP:
          case FLOOR:
          case LOG:
          case LOG10:
          case MOD:
          case PI:
          case POWER:
          case RADIANS:
          case RAND:
          case ROUND:
          case SQRT:
          case TRUNCATE:
          case ACOS:
          case ASIN:
          case ATAN:
          case ATAN2:
          case COS:
          case COT:
          case SIN:
          case TAN:
          case STRING_LITERAL:
          case SCIENTIFIC_NUMBER:
          case UNSIGNED_FLOAT:
          case UNSIGNED_INTEGER:
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            op = ValueExpression();
            break;
            }
          default:
            jj_la1[78] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
          end = jj_consume_token(RIGHT_PAR);
funct = queryFactory.createSQLFunction((all!=null)?SQLFunctionType.COUNT_ALL:SQLFunctionType.COUNT, op, distinct != null && distinct.image.equalsIgnoreCase("distinct"));
                          funct.setPosition(new TextPosition(fct, end));
          break;
          }
        case AVG:
        case MAX:
        case MIN:
        case SUM:{
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case AVG:{
            fct = jj_consume_token(AVG);
            break;
            }
          case MAX:{
            fct = jj_consume_token(MAX);
            break;
            }
          case MIN:{
            fct = jj_consume_token(MIN);
            break;
            }
          case SUM:{
            fct = jj_consume_token(SUM);
            break;
            }
          default:
            jj_la1[79] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
          jj_consume_token(LEFT_PAR);
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case QUANTIFIER:{
            distinct = jj_consume_token(QUANTIFIER);
            break;
            }
          default:
            jj_la1[80] = jj_gen;
            ;
          }
          op = ValueExpression();
          end = jj_consume_token(RIGHT_PAR);
funct = queryFactory.createSQLFunction(SQLFunctionType.valueOf(fct.image.toUpperCase()), op, distinct != null && distinct.image.equalsIgnoreCase("distinct"));
                          funct.setPosition(new TextPosition(fct, end));
          break;
          }
        default:
          jj_la1[81] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
{if ("" != null) return funct;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("SqlFunction");
    }
  }

/* ************** */
/* ADQL FUNCTIONS */
/* ************** */
  final public ADQLOperand[] Coordinates() throws ParseException {
    trace_call("Coordinates");
    try {ADQLOperand[] ops = new ADQLOperand[2];
      ops[0] = NumericExpression();
      jj_consume_token(COMMA);
      ops[1] = NumericExpression();
{if ("" != null) return ops;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("Coordinates");
    }
  }

  final public GeometryFunction GeometryFunction() throws ParseException {
    trace_call("GeometryFunction");
    try {Token fct=null, end; GeometryValue<GeometryFunction> gvf1, gvf2; GeometryValue<PointFunction> gvp1, gvp2; GeometryFunction gf = null; PointFunction p1=null, p2=null; ADQLColumn col1 = null, col2 = null;
      try {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case CONTAINS:
        case INTERSECTS:{
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case CONTAINS:{
            fct = jj_consume_token(CONTAINS);
            break;
            }
          case INTERSECTS:{
            fct = jj_consume_token(INTERSECTS);
            break;
            }
          default:
            jj_la1[82] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
          jj_consume_token(LEFT_PAR);
          gvf1 = GeometryExpression();
          jj_consume_token(COMMA);
          gvf2 = GeometryExpression();
          end = jj_consume_token(RIGHT_PAR);
if (fct.image.equalsIgnoreCase("contains"))
                                        gf = queryFactory.createContains(gvf1, gvf2);
                                else
                                        gf = queryFactory.createIntersects(gvf1, gvf2);
          break;
          }
        case AREA:{
          fct = jj_consume_token(AREA);
          jj_consume_token(LEFT_PAR);
          gvf1 = GeometryExpression();
          end = jj_consume_token(RIGHT_PAR);
gf = queryFactory.createArea(gvf1);
          break;
          }
        case COORD1:{
          fct = jj_consume_token(COORD1);
          jj_consume_token(LEFT_PAR);
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case POINT:{
            p1 = Point();
gf = queryFactory.createCoord1(p1);
            break;
            }
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            col1 = Column();
col1.setExpectedType('G'); gf = queryFactory.createCoord1(col1);
            break;
            }
          default:
            jj_la1[83] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case COORD2:{
          fct = jj_consume_token(COORD2);
          jj_consume_token(LEFT_PAR);
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case POINT:{
            p1 = Point();
gf = queryFactory.createCoord2(p1);
            break;
            }
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            col1 = Column();
col1.setExpectedType('G'); gf = queryFactory.createCoord2(col1);
            break;
            }
          default:
            jj_la1[84] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case DISTANCE:{
          fct = jj_consume_token(DISTANCE);
          jj_consume_token(LEFT_PAR);
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case POINT:{
            p1 = Point();
            break;
            }
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            col1 = Column();
            break;
            }
          default:
            jj_la1[85] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
if (p1 != null)
                                                gvp1 = new GeometryValue<PointFunction>(p1);
                                        else{
                                                col1.setExpectedType('G');
                                                gvp1 = new GeometryValue<PointFunction>(col1);
                                        }
          jj_consume_token(COMMA);
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case POINT:{
            p2 = Point();
            break;
            }
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            col2 = Column();
            break;
            }
          default:
            jj_la1[86] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
if (p2 != null)
                                                gvp2 = new GeometryValue<PointFunction>(p2);
                                        else{
                                                col2.setExpectedType('G');
                                                gvp2 = new GeometryValue<PointFunction>(col2);
                                        }
          end = jj_consume_token(RIGHT_PAR);
gf = queryFactory.createDistance(gvp1, gvp2);
          break;
          }
        default:
          jj_la1[87] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
gf.setPosition(new TextPosition(fct, end));
          {if ("" != null) return gf;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("GeometryFunction");
    }
  }

  final public ADQLOperand CoordinateSystem() throws ParseException {
    trace_call("CoordinateSystem");
    try {ADQLOperand coordSys=null;
      coordSys = StringExpression();
{if ("" != null) return coordSys;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("CoordinateSystem");
    }
  }

  final public GeometryFunction GeometryValueFunction() throws ParseException {
    trace_call("GeometryValueFunction");
    try {Token fct=null, end=null; ADQLOperand coordSys; ADQLOperand width, height; ADQLOperand[] coords, tmp; Vector<ADQLOperand> vCoords; ADQLOperand op=null; GeometryValue<GeometryFunction> gvf = null; GeometryFunction gf = null;
      try {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case BOX:{
          fct = jj_consume_token(BOX);
          jj_consume_token(LEFT_PAR);
          coordSys = CoordinateSystem();
          jj_consume_token(COMMA);
          coords = Coordinates();
          jj_consume_token(COMMA);
          width = NumericExpression();
          jj_consume_token(COMMA);
          height = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
gf = queryFactory.createBox(coordSys, coords[0], coords[1], width, height);
          break;
          }
        case CENTROID:{
          fct = jj_consume_token(CENTROID);
          jj_consume_token(LEFT_PAR);
          gvf = GeometryExpression();
          end = jj_consume_token(RIGHT_PAR);
gf = queryFactory.createCentroid(gvf);
          break;
          }
        case CIRCLE:{
          fct = jj_consume_token(CIRCLE);
          jj_consume_token(LEFT_PAR);
          coordSys = CoordinateSystem();
          jj_consume_token(COMMA);
          coords = Coordinates();
          jj_consume_token(COMMA);
          width = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
gf = queryFactory.createCircle(coordSys, coords[0], coords[1], width);
          break;
          }
        case POINT:{
          gf = Point();
          break;
          }
        case POLYGON:{
          fct = jj_consume_token(POLYGON);
          jj_consume_token(LEFT_PAR);
          coordSys = CoordinateSystem();
vCoords = new Vector<ADQLOperand>();
          jj_consume_token(COMMA);
          tmp = Coordinates();
vCoords.add(tmp[0]); vCoords.add(tmp[1]);
          jj_consume_token(COMMA);
          tmp = Coordinates();
vCoords.add(tmp[0]); vCoords.add(tmp[1]);
          jj_consume_token(COMMA);
          tmp = Coordinates();
vCoords.add(tmp[0]); vCoords.add(tmp[1]);
          label_12:
          while (true) {
            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
            case COMMA:{
              ;
              break;
              }
            default:
              jj_la1[88] = jj_gen;
              break label_12;
            }
            jj_consume_token(COMMA);
            tmp = Coordinates();
vCoords.add(tmp[0]); vCoords.add(tmp[1]);
          }
          end = jj_consume_token(RIGHT_PAR);
gf = queryFactory.createPolygon(coordSys, vCoords);
          break;
          }
        case REGION:{
          fct = jj_consume_token(REGION);
          jj_consume_token(LEFT_PAR);
          op = StringExpression();
          end = jj_consume_token(RIGHT_PAR);
gf = queryFactory.createRegion(op);
          break;
          }
        default:
          jj_la1[89] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
if (fct != null && end != null) // = !(gf instanceof Point)
                gf.setPosition(new TextPosition(fct, end));
          {if ("" != null) return gf;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("GeometryValueFunction");
    }
  }

  final public PointFunction Point() throws ParseException {
    trace_call("Point");
    try {Token start, end; ADQLOperand coordSys; ADQLOperand[] coords;
      start = jj_consume_token(POINT);
      jj_consume_token(LEFT_PAR);
      coordSys = CoordinateSystem();
      jj_consume_token(COMMA);
      coords = Coordinates();
      end = jj_consume_token(RIGHT_PAR);
try{
                        PointFunction pf = queryFactory.createPoint(coordSys, coords[0], coords[1]);
                        pf.setPosition(new TextPosition(start, end));
                        {if ("" != null) return pf;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("Point");
    }
  }

  final public GeometryFunction ExtractCoordSys() throws ParseException {
    trace_call("ExtractCoordSys");
    try {Token start, end; GeometryValue<GeometryFunction> gvf;
      start = jj_consume_token(COORDSYS);
      jj_consume_token(LEFT_PAR);
      gvf = GeometryExpression();
      end = jj_consume_token(RIGHT_PAR);
try{
                        GeometryFunction gf = queryFactory.createExtractCoordSys(gvf);
                        gf.setPosition(new TextPosition(start, end));
                        {if ("" != null) return gf;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("ExtractCoordSys");
    }
  }

/* ***************** */
/* NUMERIC FUNCTIONS */
/* ***************** */
  final public ADQLFunction NumericFunction() throws ParseException {
    trace_call("NumericFunction");
    try {ADQLFunction fct;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case ABS:
      case CEILING:
      case DEGREES:
      case EXP:
      case FLOOR:
      case LOG:
      case LOG10:
      case MOD:
      case PI:
      case POWER:
      case RADIANS:
      case RAND:
      case ROUND:
      case SQRT:
      case TRUNCATE:{
        fct = MathFunction();
        break;
        }
      case ACOS:
      case ASIN:
      case ATAN:
      case ATAN2:
      case COS:
      case COT:
      case SIN:
      case TAN:{
        fct = TrigFunction();
        break;
        }
      case CONTAINS:
      case INTERSECTS:
      case AREA:
      case COORD1:
      case COORD2:
      case DISTANCE:{
        fct = GeometryFunction();
        break;
        }
      case REGULAR_IDENTIFIER_CANDIDATE:{
        fct = UserDefinedFunction();
((UserDefinedFunction)fct).setExpectedType('N');
        break;
        }
      default:
        jj_la1[90] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
{if ("" != null) return fct;}
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("NumericFunction");
    }
  }

  final public MathFunction MathFunction() throws ParseException {
    trace_call("MathFunction");
    try {Token fct=null, end; ADQLOperand param1=null, param2=null; NumericConstant integerValue = null;
      try {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case ABS:{
          fct = jj_consume_token(ABS);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case CEILING:{
          fct = jj_consume_token(CEILING);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case DEGREES:{
          fct = jj_consume_token(DEGREES);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case EXP:{
          fct = jj_consume_token(EXP);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case FLOOR:{
          fct = jj_consume_token(FLOOR);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case LOG:{
          fct = jj_consume_token(LOG);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case LOG10:{
          fct = jj_consume_token(LOG10);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case MOD:{
          fct = jj_consume_token(MOD);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          jj_consume_token(COMMA);
          param2 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case PI:{
          fct = jj_consume_token(PI);
          jj_consume_token(LEFT_PAR);
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case POWER:{
          fct = jj_consume_token(POWER);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          jj_consume_token(COMMA);
          param2 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case RADIANS:{
          fct = jj_consume_token(RADIANS);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case RAND:{
          fct = jj_consume_token(RAND);
          jj_consume_token(LEFT_PAR);
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case LEFT_PAR:
          case PLUS:
          case MINUS:
          case AVG:
          case MAX:
          case MIN:
          case SUM:
          case COUNT:
          case CONTAINS:
          case INTERSECTS:
          case AREA:
          case COORD1:
          case COORD2:
          case DISTANCE:
          case ABS:
          case CEILING:
          case DEGREES:
          case EXP:
          case FLOOR:
          case LOG:
          case LOG10:
          case MOD:
          case PI:
          case POWER:
          case RADIANS:
          case RAND:
          case ROUND:
          case SQRT:
          case TRUNCATE:
          case ACOS:
          case ASIN:
          case ATAN:
          case ATAN2:
          case COS:
          case COT:
          case SIN:
          case TAN:
          case SCIENTIFIC_NUMBER:
          case UNSIGNED_FLOAT:
          case UNSIGNED_INTEGER:
          case DELIMITED_IDENTIFIER:
          case REGULAR_IDENTIFIER_CANDIDATE:{
            param1 = NumericExpression();
            break;
            }
          default:
            jj_la1[91] = jj_gen;
            ;
          }
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case ROUND:{
          fct = jj_consume_token(ROUND);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case COMMA:{
            jj_consume_token(COMMA);
            param2 = SignedInteger();
            break;
            }
          default:
            jj_la1[92] = jj_gen;
            ;
          }
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case SQRT:{
          fct = jj_consume_token(SQRT);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        case TRUNCATE:{
          fct = jj_consume_token(TRUNCATE);
          jj_consume_token(LEFT_PAR);
          param1 = NumericExpression();
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case COMMA:{
            jj_consume_token(COMMA);
            param2 = SignedInteger();
            break;
            }
          default:
            jj_la1[93] = jj_gen;
            ;
          }
          end = jj_consume_token(RIGHT_PAR);
          break;
          }
        default:
          jj_la1[94] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
MathFunction mf = queryFactory.createMathFunction(MathFunctionType.valueOf(fct.image.toUpperCase()), param1, param2);
                        mf.setPosition(new TextPosition(fct, end));
                        {if ("" != null) return mf;}
      } catch (Exception ex) {
{if (true) throw generateParseException(ex);}
      }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("MathFunction");
    }
  }

  final public MathFunction TrigFunction() throws ParseException {
    trace_call("TrigFunction");
    try {Token fct=null, end; ADQLOperand param1=null, param2=null;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case ACOS:{
        fct = jj_consume_token(ACOS);
        jj_consume_token(LEFT_PAR);
        param1 = NumericExpression();
        end = jj_consume_token(RIGHT_PAR);
        break;
        }
      case ASIN:{
        fct = jj_consume_token(ASIN);
        jj_consume_token(LEFT_PAR);
        param1 = NumericExpression();
        end = jj_consume_token(RIGHT_PAR);
        break;
        }
      case ATAN:{
        fct = jj_consume_token(ATAN);
        jj_consume_token(LEFT_PAR);
        param1 = NumericExpression();
        end = jj_consume_token(RIGHT_PAR);
        break;
        }
      case ATAN2:{
        fct = jj_consume_token(ATAN2);
        jj_consume_token(LEFT_PAR);
        param1 = NumericExpression();
        jj_consume_token(COMMA);
        param2 = NumericExpression();
        end = jj_consume_token(RIGHT_PAR);
        break;
        }
      case COS:{
        fct = jj_consume_token(COS);
        jj_consume_token(LEFT_PAR);
        param1 = NumericExpression();
        end = jj_consume_token(RIGHT_PAR);
        break;
        }
      case COT:{
        fct = jj_consume_token(COT);
        jj_consume_token(LEFT_PAR);
        param1 = NumericExpression();
        end = jj_consume_token(RIGHT_PAR);
        break;
        }
      case SIN:{
        fct = jj_consume_token(SIN);
        jj_consume_token(LEFT_PAR);
        param1 = NumericExpression();
        end = jj_consume_token(RIGHT_PAR);
        break;
        }
      case TAN:{
        fct = jj_consume_token(TAN);
        jj_consume_token(LEFT_PAR);
        param1 = NumericExpression();
        end = jj_consume_token(RIGHT_PAR);
        break;
        }
      default:
        jj_la1[95] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
try{
                        MathFunction mf = queryFactory.createMathFunction(MathFunctionType.valueOf(fct.image.toUpperCase()), param1, param2);
                        mf.setPosition(new TextPosition(fct, end));
                        {if ("" != null) return mf;}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("TrigFunction");
    }
  }

  final public UserDefinedFunction UserDefinedFunction() throws ParseException {
    trace_call("UserDefinedFunction");
    try {Token fct, end; Vector<ADQLOperand> params = new Vector<ADQLOperand>(); ADQLOperand op;
      fct = jj_consume_token(REGULAR_IDENTIFIER_CANDIDATE);
      jj_consume_token(LEFT_PAR);
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case LEFT_PAR:
      case PLUS:
      case MINUS:
      case AVG:
      case MAX:
      case MIN:
      case SUM:
      case COUNT:
      case BOX:
      case CENTROID:
      case CIRCLE:
      case POINT:
      case POLYGON:
      case REGION:
      case CONTAINS:
      case INTERSECTS:
      case AREA:
      case COORD1:
      case COORD2:
      case COORDSYS:
      case DISTANCE:
      case ABS:
      case CEILING:
      case DEGREES:
      case EXP:
      case FLOOR:
      case LOG:
      case LOG10:
      case MOD:
      case PI:
      case POWER:
      case RADIANS:
      case RAND:
      case ROUND:
      case SQRT:
      case TRUNCATE:
      case ACOS:
      case ASIN:
      case ATAN:
      case ATAN2:
      case COS:
      case COT:
      case SIN:
      case TAN:
      case STRING_LITERAL:
      case SCIENTIFIC_NUMBER:
      case UNSIGNED_FLOAT:
      case UNSIGNED_INTEGER:
      case DELIMITED_IDENTIFIER:
      case REGULAR_IDENTIFIER_CANDIDATE:{
        op = ValueExpression();
params.add(op);
        label_13:
        while (true) {
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case COMMA:{
            ;
            break;
            }
          default:
            jj_la1[96] = jj_gen;
            break label_13;
          }
          jj_consume_token(COMMA);
          op = ValueExpression();
params.add(op);
        }
        break;
        }
      default:
        jj_la1[97] = jj_gen;
        ;
      }
      end = jj_consume_token(RIGHT_PAR);
// Ensure the given function name is valid: 
                if (!isRegularIdentifier(fct.image))
                        {if (true) throw new ParseException("Invalid (User Defined) Function name: \u005c""+fct.image+"\u005c"!", new TextPosition(fct));}

                //System.out.println("INFO [ADQLParser]: \""+fct.image+"\" (from line "+fct.beginLine+" and column "+fct.beginColumn+" to line "+token.endLine+" and column "+(token.endColumn+1)+") is considered as an user defined function !");

                try{
                        //  Build the parameters list:
                        ADQLOperand[] parameters = new ADQLOperand[params.size()];
                        for(int i=0; i<params.size(); i++)
                                parameters[i] = params.get(i);

                        // Create the UDF function:
                        UserDefinedFunction udf = queryFactory.createUserDefinedFunction(fct.image, parameters);
                        udf.setPosition(new TextPosition(fct, end));
                        {if ("" != null) return udf;}

                }catch(UnsupportedOperationException uoe){
                        /* This catch clause is just for backward compatibility:
		  	 * if the createUserDefinedFunction(...) is overridden and
		  	 * the function can not be identified a such exception may be thrown). */
                        {if (true) throw new ParseException(uoe.getMessage(), new TextPosition(fct, token));}
                }catch(Exception ex){
                        {if (true) throw generateParseException(ex);}
                }
    throw new Error("Missing return statement in function");
    } finally {
      trace_return("UserDefinedFunction");
    }
  }

  private boolean jj_2_1(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_1(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(0, xla); }
  }

  private boolean jj_2_2(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_2(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(1, xla); }
  }

  private boolean jj_2_3(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_3(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(2, xla); }
  }

  private boolean jj_2_4(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_4(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(3, xla); }
  }

  private boolean jj_2_5(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_5(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(4, xla); }
  }

  private boolean jj_2_6(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_6(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(5, xla); }
  }

  private boolean jj_2_7(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_7(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(6, xla); }
  }

  private boolean jj_2_8(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_8(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(7, xla); }
  }

  private boolean jj_2_9(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_9(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(8, xla); }
  }

  private boolean jj_2_10(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_10(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(9, xla); }
  }

  private boolean jj_2_11(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_11(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(10, xla); }
  }

  private boolean jj_2_12(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_12(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(11, xla); }
  }

  private boolean jj_2_13(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_13(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(12, xla); }
  }

  private boolean jj_2_14(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_14(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(13, xla); }
  }

  private boolean jj_2_15(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_15(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(14, xla); }
  }

  private boolean jj_2_16(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_16(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(15, xla); }
  }

  private boolean jj_2_17(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_17(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(16, xla); }
  }

  private boolean jj_2_18(int xla)
 {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_18(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(17, xla); }
  }

  private boolean jj_3R_134()
 {
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_51()) return true;
    return false;
  }

  private boolean jj_3_2()
 {
    if (jj_3R_16()) return true;
    return false;
  }

  private boolean jj_3R_75()
 {
    if (jj_3R_79()) return true;
    return false;
  }

  private boolean jj_3R_27()
 {
    if (jj_3R_51()) return true;
    return false;
  }

  private boolean jj_3R_56()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_75()) {
    jj_scanpos = xsp;
    if (jj_3_2()) {
    jj_scanpos = xsp;
    if (jj_3R_76()) return true;
    }
    }
    return false;
  }

  private boolean jj_3_14()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(43)) {
    jj_scanpos = xsp;
    if (jj_3R_27()) return true;
    }
    return false;
  }

  private boolean jj_3R_120()
 {
    if (jj_3R_51()) return true;
    Token xsp;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_134()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  private boolean jj_3R_60()
 {
    if (jj_scan_token(DOT)) return true;
    if (jj_3R_79()) return true;
    return false;
  }

  private boolean jj_3R_22()
 {
    if (jj_3R_43()) return true;
    return false;
  }

  private boolean jj_3R_150()
 {
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_153()) return true;
    return false;
  }

  private boolean jj_3R_149()
 {
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_153()) return true;
    return false;
  }

  private boolean jj_3R_43()
 {
    if (jj_3R_14()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_60()) jj_scanpos = xsp;
    return false;
  }

  private boolean jj_3R_127()
 {
    if (jj_scan_token(DOT)) return true;
    if (jj_3R_14()) return true;
    return false;
  }

  private boolean jj_3R_126()
 {
    if (jj_scan_token(DOT)) return true;
    if (jj_3R_14()) return true;
    return false;
  }

  private boolean jj_3R_79()
 {
    if (jj_3R_14()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_126()) jj_scanpos = xsp;
    xsp = jj_scanpos;
    if (jj_3R_127()) jj_scanpos = xsp;
    return false;
  }

  private boolean jj_3R_31()
 {
    if (jj_scan_token(DELIMITED_IDENTIFIER)) return true;
    return false;
  }

  private boolean jj_3R_133()
 {
    if (jj_3R_21()) return true;
    return false;
  }

  private boolean jj_3R_30()
 {
    if (jj_scan_token(REGULAR_IDENTIFIER_CANDIDATE)) return true;
    return false;
  }

  private boolean jj_3R_26()
 {
    if (jj_scan_token(REGULAR_IDENTIFIER_CANDIDATE)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_120()) jj_scanpos = xsp;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_141()
 {
    if (jj_3R_112()) return true;
    return false;
  }

  private boolean jj_3R_14()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_30()) {
    jj_scanpos = xsp;
    if (jj_3R_31()) return true;
    }
    return false;
  }

  private boolean jj_3R_132()
 {
    if (jj_3R_22()) return true;
    return false;
  }

  private boolean jj_3R_119()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_132()) {
    jj_scanpos = xsp;
    if (jj_3R_133()) return true;
    }
    return false;
  }

  private boolean jj_3R_106()
 {
    if (jj_scan_token(TAN)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_105()
 {
    if (jj_scan_token(SIN)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_58()
 {
    if (jj_3R_78()) return true;
    return false;
  }

  private boolean jj_3R_104()
 {
    if (jj_scan_token(COT)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3_13()
 {
    if (jj_3R_26()) return true;
    return false;
  }

  private boolean jj_3R_103()
 {
    if (jj_scan_token(COS)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_102()
 {
    if (jj_scan_token(ATAN2)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_57()
 {
    if (jj_3R_77()) return true;
    return false;
  }

  private boolean jj_3R_101()
 {
    if (jj_scan_token(ATAN)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_36()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_57()) {
    jj_scanpos = xsp;
    if (jj_3_13()) {
    jj_scanpos = xsp;
    if (jj_3R_58()) return true;
    }
    }
    return false;
  }

  private boolean jj_3R_100()
 {
    if (jj_scan_token(ASIN)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_99()
 {
    if (jj_scan_token(ACOS)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_64()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_99()) {
    jj_scanpos = xsp;
    if (jj_3R_100()) {
    jj_scanpos = xsp;
    if (jj_3R_101()) {
    jj_scanpos = xsp;
    if (jj_3R_102()) {
    jj_scanpos = xsp;
    if (jj_3R_103()) {
    jj_scanpos = xsp;
    if (jj_3R_104()) {
    jj_scanpos = xsp;
    if (jj_3R_105()) {
    jj_scanpos = xsp;
    if (jj_3R_106()) return true;
    }
    }
    }
    }
    }
    }
    }
    return false;
  }

  private boolean jj_3R_46()
 {
    if (jj_3R_62()) return true;
    return false;
  }

  private boolean jj_3R_98()
 {
    if (jj_scan_token(TRUNCATE)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_150()) jj_scanpos = xsp;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_97()
 {
    if (jj_scan_token(SQRT)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_96()
 {
    if (jj_scan_token(ROUND)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_149()) jj_scanpos = xsp;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_95()
 {
    if (jj_scan_token(RAND)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_141()) jj_scanpos = xsp;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_94()
 {
    if (jj_scan_token(RADIANS)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_93()
 {
    if (jj_scan_token(POWER)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_92()
 {
    if (jj_scan_token(PI)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_91()
 {
    if (jj_scan_token(MOD)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_90()
 {
    if (jj_scan_token(LOG10)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_89()
 {
    if (jj_scan_token(LOG)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_88()
 {
    if (jj_scan_token(FLOOR)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_87()
 {
    if (jj_scan_token(EXP)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_52()
 {
    if (jj_scan_token(CONCAT)) return true;
    if (jj_3R_36()) return true;
    return false;
  }

  private boolean jj_3R_86()
 {
    if (jj_scan_token(DEGREES)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_85()
 {
    if (jj_scan_token(CEILING)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_84()
 {
    if (jj_scan_token(ABS)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_29()
 {
    if (jj_3R_36()) return true;
    Token xsp;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_52()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  private boolean jj_3R_63()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_84()) {
    jj_scanpos = xsp;
    if (jj_3R_85()) {
    jj_scanpos = xsp;
    if (jj_3R_86()) {
    jj_scanpos = xsp;
    if (jj_3R_87()) {
    jj_scanpos = xsp;
    if (jj_3R_88()) {
    jj_scanpos = xsp;
    if (jj_3R_89()) {
    jj_scanpos = xsp;
    if (jj_3R_90()) {
    jj_scanpos = xsp;
    if (jj_3R_91()) {
    jj_scanpos = xsp;
    if (jj_3R_92()) {
    jj_scanpos = xsp;
    if (jj_3R_93()) {
    jj_scanpos = xsp;
    if (jj_3R_94()) {
    jj_scanpos = xsp;
    if (jj_3R_95()) {
    jj_scanpos = xsp;
    if (jj_3R_96()) {
    jj_scanpos = xsp;
    if (jj_3R_97()) {
    jj_scanpos = xsp;
    if (jj_3R_98()) return true;
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    return false;
  }

  private boolean jj_3R_61()
 {
    if (jj_scan_token(MINUS)) return true;
    return false;
  }

  private boolean jj_3R_50()
 {
    if (jj_3R_26()) return true;
    return false;
  }

  private boolean jj_3R_49()
 {
    if (jj_3R_65()) return true;
    return false;
  }

  private boolean jj_3R_48()
 {
    if (jj_3R_64()) return true;
    return false;
  }

  private boolean jj_3R_47()
 {
    if (jj_3R_63()) return true;
    return false;
  }

  private boolean jj_3R_25()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_47()) {
    jj_scanpos = xsp;
    if (jj_3R_48()) {
    jj_scanpos = xsp;
    if (jj_3R_49()) {
    jj_scanpos = xsp;
    if (jj_3R_50()) return true;
    }
    }
    }
    return false;
  }

  private boolean jj_3_12()
 {
    if (jj_3R_25()) return true;
    return false;
  }

  private boolean jj_3R_45()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(9)) {
    jj_scanpos = xsp;
    if (jj_3R_61()) return true;
    }
    return false;
  }

  private boolean jj_3R_32()
 {
    if (jj_3R_14()) return true;
    if (jj_scan_token(DOT)) return true;
    return false;
  }

  private boolean jj_3R_137()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(11)) {
    jj_scanpos = xsp;
    if (jj_scan_token(12)) return true;
    }
    if (jj_3R_130()) return true;
    return false;
  }

  private boolean jj_3R_24()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_45()) jj_scanpos = xsp;
    xsp = jj_scanpos;
    if (jj_3_12()) {
    jj_scanpos = xsp;
    if (jj_3R_46()) return true;
    }
    return false;
  }

  private boolean jj_3R_15()
 {
    if (jj_3R_14()) return true;
    if (jj_scan_token(DOT)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_32()) jj_scanpos = xsp;
    return false;
  }

  private boolean jj_3R_77()
 {
    if (jj_scan_token(COORDSYS)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_119()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_145()
 {
    if (jj_3R_22()) return true;
    return false;
  }

  private boolean jj_3R_143()
 {
    if (jj_3R_22()) return true;
    return false;
  }

  private boolean jj_3R_140()
 {
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_139()) return true;
    return false;
  }

  private boolean jj_3R_131()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(9)) {
    jj_scanpos = xsp;
    if (jj_scan_token(10)) return true;
    }
    if (jj_3R_112()) return true;
    return false;
  }

  private boolean jj_3R_59()
 {
    if (jj_scan_token(POINT)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_138()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_139()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_130()
 {
    if (jj_3R_24()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_137()) jj_scanpos = xsp;
    return false;
  }

  private boolean jj_3R_42()
 {
    if (jj_scan_token(REGION)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_29()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_19()
 {
    if (jj_3R_24()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(9)) {
    jj_scanpos = xsp;
    if (jj_scan_token(10)) {
    jj_scanpos = xsp;
    if (jj_scan_token(11)) {
    jj_scanpos = xsp;
    if (jj_scan_token(12)) return true;
    }
    }
    }
    return false;
  }

  private boolean jj_3R_20()
 {
    if (jj_3R_36()) return true;
    if (jj_scan_token(CONCAT)) return true;
    return false;
  }

  private boolean jj_3_1()
 {
    if (jj_3R_14()) return true;
    if (jj_scan_token(DOT)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_15()) jj_scanpos = xsp;
    if (jj_scan_token(ASTERISK)) return true;
    return false;
  }

  private boolean jj_3R_41()
 {
    if (jj_scan_token(POLYGON)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_138()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_139()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_139()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_139()) return true;
    Token xsp;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_140()) { jj_scanpos = xsp; break; }
    }
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_72()
 {
    if (jj_3R_22()) return true;
    return false;
  }

  private boolean jj_3R_40()
 {
    if (jj_3R_59()) return true;
    return false;
  }

  private boolean jj_3_10()
 {
    if (jj_3R_23()) return true;
    return false;
  }

  private boolean jj_3R_112()
 {
    if (jj_3R_130()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_131()) jj_scanpos = xsp;
    return false;
  }

  private boolean jj_3_9()
 {
    if (jj_3R_22()) return true;
    return false;
  }

  private boolean jj_3_7()
 {
    if (jj_scan_token(REGULAR_IDENTIFIER_CANDIDATE)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    return false;
  }

  private boolean jj_3_6()
 {
    if (jj_scan_token(LEFT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_39()
 {
    if (jj_scan_token(CIRCLE)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_138()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_139()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3_5()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(66)) {
    jj_scanpos = xsp;
    if (jj_3R_20()) return true;
    }
    return false;
  }

  private boolean jj_3_4()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_18()) {
    jj_scanpos = xsp;
    if (jj_3R_19()) return true;
    }
    return false;
  }

  private boolean jj_3R_18()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(9)) {
    jj_scanpos = xsp;
    if (jj_scan_token(10)) return true;
    }
    return false;
  }

  private boolean jj_3R_38()
 {
    if (jj_scan_token(CENTROID)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_119()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3_11()
 {
    if (jj_3R_24()) return true;
    return false;
  }

  private boolean jj_3R_71()
 {
    if (jj_3R_36()) return true;
    return false;
  }

  private boolean jj_3R_70()
 {
    if (jj_3R_22()) return true;
    return false;
  }

  private boolean jj_3_8()
 {
    if (jj_3R_21()) return true;
    return false;
  }

  private boolean jj_3R_69()
 {
    if (jj_3R_26()) return true;
    return false;
  }

  private boolean jj_3R_68()
 {
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_51()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_37()
 {
    if (jj_scan_token(BOX)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_138()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_139()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_67()
 {
    if (jj_3R_29()) return true;
    return false;
  }

  private boolean jj_3R_66()
 {
    if (jj_3R_112()) return true;
    return false;
  }

  private boolean jj_3R_152()
 {
    if (jj_3R_22()) return true;
    return false;
  }

  private boolean jj_3R_125()
 {
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_51()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_144()
 {
    if (jj_3R_59()) return true;
    return false;
  }

  private boolean jj_3R_21()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_37()) {
    jj_scanpos = xsp;
    if (jj_3R_38()) {
    jj_scanpos = xsp;
    if (jj_3R_39()) {
    jj_scanpos = xsp;
    if (jj_3R_40()) {
    jj_scanpos = xsp;
    if (jj_3R_41()) {
    jj_scanpos = xsp;
    if (jj_3R_42()) return true;
    }
    }
    }
    }
    }
    return false;
  }

  private boolean jj_3R_148()
 {
    if (jj_3R_51()) return true;
    return false;
  }

  private boolean jj_3R_142()
 {
    if (jj_3R_59()) return true;
    return false;
  }

  private boolean jj_3R_124()
 {
    if (jj_3R_22()) return true;
    return false;
  }

  private boolean jj_3R_51()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_66()) {
    jj_scanpos = xsp;
    if (jj_3R_67()) {
    jj_scanpos = xsp;
    if (jj_3R_68()) {
    jj_scanpos = xsp;
    if (jj_3R_69()) {
    jj_scanpos = xsp;
    if (jj_3_8()) {
    jj_scanpos = xsp;
    if (jj_3R_70()) {
    jj_scanpos = xsp;
    if (jj_3R_71()) {
    jj_scanpos = xsp;
    if (jj_3_11()) {
    jj_scanpos = xsp;
    if (jj_3R_72()) return true;
    }
    }
    }
    }
    }
    }
    }
    }
    return false;
  }

  private boolean jj_3R_147()
 {
    if (jj_3R_22()) return true;
    return false;
  }

  private boolean jj_3R_123()
 {
    if (jj_3R_129()) return true;
    return false;
  }

  private boolean jj_3R_151()
 {
    if (jj_3R_59()) return true;
    return false;
  }

  private boolean jj_3R_138()
 {
    if (jj_3R_29()) return true;
    return false;
  }

  private boolean jj_3R_122()
 {
    if (jj_3R_128()) return true;
    return false;
  }

  private boolean jj_3R_121()
 {
    if (jj_3R_23()) return true;
    return false;
  }

  private boolean jj_3R_53()
 {
    if (jj_scan_token(SELECT)) return true;
    return false;
  }

  private boolean jj_3R_115()
 {
    if (jj_scan_token(FULL)) return true;
    return false;
  }

  private boolean jj_3R_146()
 {
    if (jj_3R_59()) return true;
    return false;
  }

  private boolean jj_3R_16()
 {
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_33()) return true;
    return false;
  }

  private boolean jj_3R_83()
 {
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_112()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_82()
 {
    if (jj_3R_129()) return true;
    return false;
  }

  private boolean jj_3R_78()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_121()) {
    jj_scanpos = xsp;
    if (jj_3R_122()) {
    jj_scanpos = xsp;
    if (jj_3R_123()) {
    jj_scanpos = xsp;
    if (jj_3R_124()) {
    jj_scanpos = xsp;
    if (jj_3R_125()) return true;
    }
    }
    }
    }
    return false;
  }

  private boolean jj_3R_81()
 {
    if (jj_3R_22()) return true;
    return false;
  }

  private boolean jj_3R_80()
 {
    if (jj_3R_128()) return true;
    return false;
  }

  private boolean jj_3R_111()
 {
    if (jj_scan_token(DISTANCE)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_146()) {
    jj_scanpos = xsp;
    if (jj_3R_147()) return true;
    }
    if (jj_scan_token(COMMA)) return true;
    xsp = jj_scanpos;
    if (jj_3R_151()) {
    jj_scanpos = xsp;
    if (jj_3R_152()) return true;
    }
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_110()
 {
    if (jj_scan_token(COORD2)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_144()) {
    jj_scanpos = xsp;
    if (jj_3R_145()) return true;
    }
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_109()
 {
    if (jj_scan_token(COORD1)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_142()) {
    jj_scanpos = xsp;
    if (jj_3R_143()) return true;
    }
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_108()
 {
    if (jj_scan_token(AREA)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_119()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_118()
 {
    if (jj_scan_token(FULL)) return true;
    return false;
  }

  private boolean jj_3R_62()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_80()) {
    jj_scanpos = xsp;
    if (jj_3R_81()) {
    jj_scanpos = xsp;
    if (jj_3R_82()) {
    jj_scanpos = xsp;
    if (jj_3R_83()) return true;
    }
    }
    }
    return false;
  }

  private boolean jj_3R_107()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(61)) {
    jj_scanpos = xsp;
    if (jj_scan_token(62)) return true;
    }
    if (jj_scan_token(LEFT_PAR)) return true;
    if (jj_3R_119()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_119()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_33()
 {
    if (jj_3R_53()) return true;
    return false;
  }

  private boolean jj_3R_114()
 {
    if (jj_scan_token(RIGHT)) return true;
    return false;
  }

  private boolean jj_3R_154()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(9)) {
    jj_scanpos = xsp;
    if (jj_scan_token(10)) return true;
    }
    return false;
  }

  private boolean jj_3R_153()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_154()) jj_scanpos = xsp;
    if (jj_scan_token(UNSIGNED_INTEGER)) return true;
    return false;
  }

  private boolean jj_3R_65()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_107()) {
    jj_scanpos = xsp;
    if (jj_3R_108()) {
    jj_scanpos = xsp;
    if (jj_3R_109()) {
    jj_scanpos = xsp;
    if (jj_3R_110()) {
    jj_scanpos = xsp;
    if (jj_3R_111()) return true;
    }
    }
    }
    }
    return false;
  }

  private boolean jj_3R_139()
 {
    if (jj_3R_112()) return true;
    if (jj_scan_token(COMMA)) return true;
    if (jj_3R_112()) return true;
    return false;
  }

  private boolean jj_3R_136()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(50)) {
    jj_scanpos = xsp;
    if (jj_scan_token(51)) {
    jj_scanpos = xsp;
    if (jj_scan_token(52)) {
    jj_scanpos = xsp;
    if (jj_scan_token(53)) return true;
    }
    }
    }
    if (jj_scan_token(LEFT_PAR)) return true;
    xsp = jj_scanpos;
    if (jj_scan_token(20)) jj_scanpos = xsp;
    if (jj_3R_51()) return true;
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_135()
 {
    if (jj_scan_token(COUNT)) return true;
    if (jj_scan_token(LEFT_PAR)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(20)) jj_scanpos = xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(11)) {
    jj_scanpos = xsp;
    if (jj_3R_148()) return true;
    }
    if (jj_scan_token(RIGHT_PAR)) return true;
    return false;
  }

  private boolean jj_3R_117()
 {
    if (jj_scan_token(RIGHT)) return true;
    return false;
  }

  private boolean jj_3R_128()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(95)) {
    jj_scanpos = xsp;
    if (jj_scan_token(96)) {
    jj_scanpos = xsp;
    if (jj_scan_token(97)) return true;
    }
    }
    return false;
  }

  private boolean jj_3R_129()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_135()) {
    jj_scanpos = xsp;
    if (jj_3R_136()) return true;
    }
    return false;
  }

  private boolean jj_3R_113()
 {
    if (jj_scan_token(LEFT)) return true;
    return false;
  }

  private boolean jj_3R_73()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_113()) {
    jj_scanpos = xsp;
    if (jj_3R_114()) {
    jj_scanpos = xsp;
    if (jj_3R_115()) return true;
    }
    }
    return false;
  }

  private boolean jj_3R_54()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(26)) {
    jj_scanpos = xsp;
    if (jj_3R_73()) return true;
    }
    return false;
  }

  private boolean jj_3R_44()
 {
    if (jj_scan_token(STRING_LITERAL)) return true;
    return false;
  }

  private boolean jj_3R_23()
 {
    Token xsp;
    if (jj_3R_44()) return true;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_44()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  private boolean jj_3R_116()
 {
    if (jj_scan_token(LEFT)) return true;
    return false;
  }

  private boolean jj_3R_74()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_116()) {
    jj_scanpos = xsp;
    if (jj_3R_117()) {
    jj_scanpos = xsp;
    if (jj_3R_118()) return true;
    }
    }
    xsp = jj_scanpos;
    if (jj_scan_token(27)) jj_scanpos = xsp;
    return false;
  }

  private boolean jj_3_18()
 {
    if (jj_3R_16()) return true;
    return false;
  }

  private boolean jj_3R_55()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(26)) {
    jj_scanpos = xsp;
    if (jj_3R_74()) return true;
    }
    return false;
  }

  private boolean jj_3R_35()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_55()) jj_scanpos = xsp;
    if (jj_scan_token(JOIN)) return true;
    if (jj_3R_56()) return true;
    return false;
  }

  private boolean jj_3R_34()
 {
    if (jj_scan_token(NATURAL)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_54()) jj_scanpos = xsp;
    if (jj_scan_token(JOIN)) return true;
    return false;
  }

  private boolean jj_3R_28()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(37)) jj_scanpos = xsp;
    if (jj_scan_token(BETWEEN)) return true;
    if (jj_3R_51()) return true;
    return false;
  }

  private boolean jj_3_15()
 {
    if (jj_3R_28()) return true;
    return false;
  }

  private boolean jj_3R_17()
 {
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_34()) {
    jj_scanpos = xsp;
    if (jj_3R_35()) return true;
    }
    return false;
  }

  private boolean jj_3_17()
 {
    if (jj_3R_29()) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_scan_token(37)) jj_scanpos = xsp;
    if (jj_scan_token(LIKE)) return true;
    return false;
  }

  private boolean jj_3R_76()
 {
    if (jj_scan_token(LEFT_PAR)) return true;
    return false;
  }

  private boolean jj_3_3()
 {
    if (jj_3R_17()) return true;
    return false;
  }

  private boolean jj_3_16()
 {
    if (jj_3R_22()) return true;
    if (jj_scan_token(IS)) return true;
    return false;
  }

  /** Generated Token Manager. */
  public ADQLParserTokenManager token_source;
  SimpleCharStream jj_input_stream;
  /** Current token. */
  public Token token;
  /** Next token. */
  public Token jj_nt;
  private int jj_ntk;
  private Token jj_scanpos, jj_lastpos;
  private int jj_la;
  private int jj_gen;
  final private int[] jj_la1 = new int[98];
  static private int[] jj_la1_0;
  static private int[] jj_la1_1;
  static private int[] jj_la1_2;
  static private int[] jj_la1_3;
  static {
      jj_la1_init_0();
      jj_la1_init_1();
      jj_la1_init_2();
      jj_la1_init_3();
   }
   private static void jj_la1_init_0() {
      jj_la1_0 = new int[] {0x81,0x0,0x0,0x0,0x0,0x100000,0x200000,0x400000,0x40,0x0,0x0,0x1000000,0x1000000,0x800,0x608,0x40,0x40,0x40,0x0,0x20,0x20,0x20,0x0,0x0,0x0,0x1000000,0x1000000,0x1000000,0x0,0x8,0xf6000000,0x70000000,0x8000000,0x74000000,0x74000000,0x70000000,0x8000000,0x74000000,0x74000000,0x40,0x0,0xf6000000,0x0,0x0,0x0,0x600,0x600,0x8,0x8,0x0,0x600,0x600,0x1800,0x1800,0x600,0x600,0x8,0x100,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x7e000,0x0,0x0,0x608,0x7e000,0x0,0x0,0x40,0x8,0x100000,0xe08,0x0,0x100000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x608,0x40,0x40,0x0,0x0,0x40,0x608,};
   }
   private static void jj_la1_init_1() {
      jj_la1_1 = new int[] {0x0,0x4,0x2000,0x4000,0x8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000,0x30000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0000,0x7c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0000,0x0,0x0,0x7c0000,0x1f800000,0x20,0x18,0x18,0x20,0x0,0x20,0x20,0x0,0x420,0x800,0xfffc0000,0x0,0x20,0x20,0x0,0x0,0x0,0xfffc0000,0x3c0000,0x0,0x7c0000,0x60000000,0x4000000,0x4000000,0x4000000,0x4000000,0xe0000000,0x0,0x1f800000,0xe0000000,0xe07c0000,0x0,0x0,0x0,0x0,0x0,0xfffc0000,};
   }
   private static void jj_la1_init_2() {
      jj_la1_2 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc7ffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000000,0x80000000,0x0,0x0,0x0,0x80000000,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,0x0,0x4,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc7ffffff,0x0,0x0,0x0,0x0,0x0,0x0,0xc7ffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xb,0x0,0x0,0x7fffffb,0x87fffffb,0x0,0x0,0x7fff0,0x7f80000,0x0,0xc7ffffff,};
   }
   private static void jj_la1_init_3() {
      jj_la1_3 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x60,0x0,0x60,0x0,0x63,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x62,0x0,0x0,0x0,0x60,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x3,0x0,0x0,0x63,0x63,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x63,0x0,0x0,0x63,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x63,0x0,0x0,0x0,0x0,0x0,0x0,0x63,0x0,0x0,0x0,0x0,0x60,0x60,0x60,0x60,0x0,0x0,0x0,0x40,0x63,0x0,0x0,0x0,0x0,0x0,0x63,};
   }
  final private JJCalls[] jj_2_rtns = new JJCalls[18];
  private boolean jj_rescan = false;
  private int jj_gc = 0;

  /** Constructor with InputStream. */
  public ADQLParser(java.io.InputStream stream) {
     this(stream, (String) null);
  }
  /** Constructor with InputStream and supplied encoding */
  public ADQLParser(java.io.InputStream stream, String encoding) {
    try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
    token_source = new ADQLParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 98; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  /** Reinitialise. */
  public void ReInit(java.io.InputStream stream) {
     ReInit(stream, null);
  }
  /** Reinitialise. */
  public void ReInit(java.io.InputStream stream, String encoding) {
    try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
    token_source.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 98; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  /** Constructor. */
  public ADQLParser(java.io.Reader stream) {
    jj_input_stream = new SimpleCharStream(stream, 1, 1);
    token_source = new ADQLParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 98; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  /** Reinitialise. */
  public void ReInit(java.io.Reader stream) {
    jj_input_stream.ReInit(stream, 1, 1);
    token_source.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 98; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  /** Constructor with generated Token Manager. */
  public ADQLParser(ADQLParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 98; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  /** Reinitialise. */
  public void ReInit(ADQLParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 98; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  private Token jj_consume_token(int kind) throws ParseException {
    Token oldToken;
    if ((oldToken = token).next != null) token = token.next;
    else token = token.next = token_source.getNextToken();
    jj_ntk = -1;
    if (token.kind == kind) {
      jj_gen++;
      if (++jj_gc > 100) {
        jj_gc = 0;
        for (int i = 0; i < jj_2_rtns.length; i++) {
          JJCalls c = jj_2_rtns[i];
          while (c != null) {
            if (c.gen < jj_gen) c.first = null;
            c = c.next;
          }
        }
      }
      trace_token(token, "");
      return token;
    }
    token = oldToken;
    jj_kind = kind;
    throw generateParseException();
  }

  @SuppressWarnings("serial")
  static private final class LookaheadSuccess extends java.lang.Error { }
  final private LookaheadSuccess jj_ls = new LookaheadSuccess();
  private boolean jj_scan_token(int kind) {
    if (jj_scanpos == jj_lastpos) {
      jj_la--;
      if (jj_scanpos.next == null) {
        jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
      } else {
        jj_lastpos = jj_scanpos = jj_scanpos.next;
      }
    } else {
      jj_scanpos = jj_scanpos.next;
    }
    if (jj_rescan) {
      int i = 0; Token tok = token;
      while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
      if (tok != null) jj_add_error_token(kind, i);
    }
    if (jj_scanpos.kind != kind) return true;
    if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls;
    return false;
  }


/** Get the next Token. */
  final public Token getNextToken() {
    if (token.next != null) token = token.next;
    else token = token.next = token_source.getNextToken();
    jj_ntk = -1;
    jj_gen++;
      trace_token(token, " (in getNextToken)");
    return token;
  }

/** Get the specific Token. */
  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 = token_source.getNextToken();
    }
    return t;
  }

  private int jj_ntk_f() {
    if ((jj_nt=token.next) == null)
      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
    else
      return (jj_ntk = jj_nt.kind);
  }

  private java.util.List<int[]> jj_expentries = new java.util.ArrayList<int[]>();
  private int[] jj_expentry;
  private int jj_kind = -1;
  private int[] jj_lasttokens = new int[100];
  private int jj_endpos;

  private void jj_add_error_token(int kind, int pos) {
    if (pos >= 100) return;
    if (pos == jj_endpos + 1) {
      jj_lasttokens[jj_endpos++] = kind;
    } else if (jj_endpos != 0) {
      jj_expentry = new int[jj_endpos];
      for (int i = 0; i < jj_endpos; i++) {
        jj_expentry[i] = jj_lasttokens[i];
      }
      jj_entries_loop: for (java.util.Iterator<?> it = jj_expentries.iterator(); it.hasNext();) {
        int[] oldentry = (int[])(it.next());
        if (oldentry.length == jj_expentry.length) {
          for (int i = 0; i < jj_expentry.length; i++) {
            if (oldentry[i] != jj_expentry[i]) {
              continue jj_entries_loop;
            }
          }
          jj_expentries.add(jj_expentry);
          break jj_entries_loop;
        }
      }
      if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
    }
  }

  /** Generate ParseException. */
  public ParseException generateParseException() {
    jj_expentries.clear();
    boolean[] la1tokens = new boolean[104];
    if (jj_kind >= 0) {
      la1tokens[jj_kind] = true;
      jj_kind = -1;
    }
    for (int i = 0; i < 98; 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;
          }
          if ((jj_la1_2[i] & (1<<j)) != 0) {
            la1tokens[64+j] = true;
          }
          if ((jj_la1_3[i] & (1<<j)) != 0) {
            la1tokens[96+j] = true;
          }
        }
      }
    }
    for (int i = 0; i < 104; i++) {
      if (la1tokens[i]) {
        jj_expentry = new int[1];
        jj_expentry[0] = i;
        jj_expentries.add(jj_expentry);
      }
    }
    jj_endpos = 0;
    jj_rescan_token();
    jj_add_error_token(0, 0);
    int[][] exptokseq = new int[jj_expentries.size()][];
    for (int i = 0; i < jj_expentries.size(); i++) {
      exptokseq[i] = jj_expentries.get(i);
    }
    return new ParseException(token, exptokseq, tokenImage);
  }

  private int trace_indent = 0;
  private boolean trace_enabled = true;

/** Enable tracing. */
  final public void enable_tracing() {
    trace_enabled = true;
  }

/** Disable tracing. */
  final public void disable_tracing() {
    trace_enabled = false;
  }

  private void trace_call(String s) {
    if (trace_enabled) {
      for (int i = 0; i < trace_indent; i++) { System.out.print(" "); }
      System.out.println("Call:   " + s);
    }
    trace_indent = trace_indent + 2;
  }

  private void trace_return(String s) {
    trace_indent = trace_indent - 2;
    if (trace_enabled) {
      for (int i = 0; i < trace_indent; i++) { System.out.print(" "); }
      System.out.println("Return: " + s);
    }
  }

  private void trace_token(Token t, String where) {
    if (trace_enabled) {
      for (int i = 0; i < trace_indent; i++) { System.out.print(" "); }
      System.out.print("Consumed token: <" + tokenImage[t.kind]);
      if (t.kind != 0 && !tokenImage[t.kind].equals("\"" + t.image + "\"")) {
        System.out.print(": \"" + t.image + "\"");
      }
      System.out.println(" at line " + t.beginLine + " column " + t.beginColumn + ">" + where);
    }
  }

  private void trace_scan(Token t1, int t2) {
    if (trace_enabled) {
      for (int i = 0; i < trace_indent; i++) { System.out.print(" "); }
      System.out.print("Visited token: <" + tokenImage[t1.kind]);
      if (t1.kind != 0 && !tokenImage[t1.kind].equals("\"" + t1.image + "\"")) {
        System.out.print(": \"" + t1.image + "\"");
      }
      System.out.println(" at line " + t1.beginLine + " column " + t1.beginColumn + ">; Expected token: <" + tokenImage[t2] + ">");
    }
  }

  private void jj_rescan_token() {
    jj_rescan = true;
    for (int i = 0; i < 18; i++) {
    try {
      JJCalls p = jj_2_rtns[i];
      do {
        if (p.gen > jj_gen) {
          jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
          switch (i) {
            case 0: jj_3_1(); break;
            case 1: jj_3_2(); break;
            case 2: jj_3_3(); break;
            case 3: jj_3_4(); break;
            case 4: jj_3_5(); break;
            case 5: jj_3_6(); break;
            case 6: jj_3_7(); break;
            case 7: jj_3_8(); break;
            case 8: jj_3_9(); break;
            case 9: jj_3_10(); break;
            case 10: jj_3_11(); break;
            case 11: jj_3_12(); break;
            case 12: jj_3_13(); break;
            case 13: jj_3_14(); break;
            case 14: jj_3_15(); break;
            case 15: jj_3_16(); break;
            case 16: jj_3_17(); break;
            case 17: jj_3_18(); break;
          }
        }
        p = p.next;
      } while (p != null);
      } catch(LookaheadSuccess ls) { }
    }
    jj_rescan = false;
  }

  private void jj_save(int index, int xla) {
    JJCalls p = jj_2_rtns[index];
    while (p.gen > jj_gen) {
      if (p.next == null) { p = p.next = new JJCalls(); break; }
      p = p.next;
    }
    p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla;
  }

  static final class JJCalls {
    int gen;
    Token first;
    int arg;
    JJCalls next;
  }

}