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

import java.io.IOException;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Vector;

import adql.db.exception.UnresolvedIdentifiersException;
import adql.parser.ADQLQueryFactory.JoinType;
import adql.parser.IdentifierItems.IdentifierItem;
import adql.query.ADQLOrder;
import adql.query.ADQLQuery;
import adql.query.ClauseADQL;
import adql.query.ClauseConstraints;
import adql.query.ClauseSelect;
import adql.query.SelectAllColumns;
import adql.query.SelectItem;
import adql.query.TextPosition;
import adql.query.constraint.ADQLConstraint;
import adql.query.constraint.Between;
import adql.query.constraint.Comparison;
import adql.query.constraint.ComparisonOperator;
import adql.query.constraint.ConstraintsGroup;
import adql.query.constraint.Exists;
import adql.query.constraint.In;
import adql.query.constraint.IsNull;
import adql.query.constraint.NotConstraint;
import adql.query.from.ADQLJoin;
import adql.query.from.FromContent;
import adql.query.operand.ADQLColumn;
import adql.query.operand.ADQLOperand;
import adql.query.operand.Concatenation;
import adql.query.operand.NegativeOperand;
import adql.query.operand.NumericConstant;
import adql.query.operand.Operation;
import adql.query.operand.OperationType;
import adql.query.operand.StringConstant;
import adql.query.operand.WrappedOperand;
import adql.query.operand.function.ADQLFunction;
import adql.query.operand.function.MathFunction;
import adql.query.operand.function.MathFunctionType;
import adql.query.operand.function.SQLFunction;
import adql.query.operand.function.SQLFunctionType;
import adql.query.operand.function.UserDefinedFunction;
import adql.query.operand.function.geometry.GeometryFunction;
import adql.query.operand.function.geometry.GeometryFunction.GeometryValue;
import adql.query.operand.function.geometry.PointFunction;
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() : 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 (true)
					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() : jj_ntk) {
				case WHERE:
					Where();
					endPos = query.getWhere().getPosition();
					break;
				default:
					jj_la1[1] = jj_gen;
					;
			}
			switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
				case GROUP:
					GroupBy();
					endPos = query.getGroupBy().getPosition();
					break;
				default:
					jj_la1[2] = jj_gen;
					;
			}
			switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
				case HAVING:
					Having();
					endPos = query.getHaving().getPosition();
					break;
				default:
					jj_la1[3] = jj_gen;
					;
			}
			switch((jj_ntk == -1) ? jj_ntk() : 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 (true)
					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 (true)
					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() : 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() : 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;
					;
			}
			item = SelectItem();
			select.add(item);
			label_1: while(true) {
				switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
					case COMMA:
						;
						break;
					default:
						jj_la1[7] = 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() : jj_ntk) {
				case ASTERISK:
					starToken = jj_consume_token(ASTERISK);
					item = new SelectAllColumns(query);
					item.setPosition(new TextPosition(starToken)); {
					if (true)
						return item;
				}
					break;
				default:
					jj_la1[12] = jj_gen;
					if (jj_2_1(7)) {
						id = Identifier();
						jj_consume_token(DOT);
						identifiers.append(id);
						switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
							case DELIMITED_IDENTIFIER:
							case REGULAR_IDENTIFIER_CANDIDATE:
								id = Identifier();
								jj_consume_token(DOT);
								identifiers.append(id);
								switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
									case DELIMITED_IDENTIFIER:
									case REGULAR_IDENTIFIER_CANDIDATE:
										id = Identifier();
										jj_consume_token(DOT);
										identifiers.append(id);
										break;
									default:
										jj_la1[8] = jj_gen;
										;
								}
								break;
							default:
								jj_la1[9] = 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 (true)
									return item;
							}
						} catch(Exception ex) {
							{
								if (true)
									throw generateParseException(ex);
							}
						}
					} else {
						switch((jj_ntk == -1) ? jj_ntk() : 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() : jj_ntk) {
									case AS:
									case DELIMITED_IDENTIFIER:
									case REGULAR_IDENTIFIER_CANDIDATE:
										switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
											case AS:
												jj_consume_token(AS);
												break;
											default:
												jj_la1[10] = jj_gen;
												;
										}
										label = Identifier();
										break;
									default:
										jj_la1[11] = jj_gen;
										;
								}
								break;
							default:
								jj_la1[13] = 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 (true)
						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() : jj_ntk) {
						case COMMA:
							;
							break;
						default:
							jj_la1[14] = 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() : jj_ntk) {
					case COMMA:
						;
						break;
					default:
						jj_la1[15] = 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() : jj_ntk) {
					case COMMA:
						;
						break;
					default:
						jj_la1[16] = 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() : jj_ntk) {
				case REGULAR_IDENTIFIER_CANDIDATE:
					t = jj_consume_token(REGULAR_IDENTIFIER_CANDIDATE);
					testRegularIdentifier(t); {
					if (true)
						return new IdentifierItem(t, false);
				}
					break;
				case DELIMITED_IDENTIFIER:
					t = jj_consume_token(DELIMITED_IDENTIFIER); {
					if (true)
						return new IdentifierItem(t, true);
				}
					break;
				default:
					jj_la1[17] = 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() : jj_ntk) {
				case DOT:
					jj_consume_token(DOT);
					id = Identifier();
					identifiers.append(id);
					break;
				default:
					jj_la1[18] = jj_gen;
					;
			}
			switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
				case DOT:
					jj_consume_token(DOT);
					id = Identifier();
					identifiers.append(id);
					break;
				default:
					jj_la1[19] = jj_gen;
					;
			}
			{
				if (true)
					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() : jj_ntk) {
				case DOT:
					jj_consume_token(DOT);
					table = TableName();
					break;
				default:
					jj_la1[20] = jj_gen;
					;
			}
			identifiers.append(id);
			if (table != null) {
				for(int i = 0; i < table.size(); i++)
					identifiers.append(table.get(i));
			}
			{
				if (true)
					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 (true)
						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() : 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[21] = jj_gen;
					jj_consume_token(-1);
					throw new ParseException();
			}
			switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
				case ASC:
				case DESC:
					switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
						case ASC:
							jj_consume_token(ASC);
							break;
						case DESC:
							desc = jj_consume_token(DESC);
							break;
						default:
							jj_la1[22] = jj_gen;
							jj_consume_token(-1);
							throw new ParseException();
					}
					break;
				default:
					jj_la1[23] = 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 (true)
						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() : jj_ntk) {
					case DELIMITED_IDENTIFIER:
					case REGULAR_IDENTIFIER_CANDIDATE:
						identifiers = TableName();
						switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
							case AS:
							case DELIMITED_IDENTIFIER:
							case REGULAR_IDENTIFIER_CANDIDATE:
								switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
									case AS:
										jj_consume_token(AS);
										break;
									default:
										jj_la1[24] = jj_gen;
										;
								}
								alias = Identifier();
								break;
							default:
								jj_la1[25] = 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 (true)
							return content;
					}
						break;
					default:
						jj_la1[27] = jj_gen;
						if (jj_2_2(2)) {
							subQuery = SubQueryExpression();
							switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
								case AS:
									jj_consume_token(AS);
									break;
								default:
									jj_la1[26] = 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 (true)
									return content;
							}
						} else {
							switch((jj_ntk == -1) ? jj_ntk() : 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 (true)
										return content;
								}
									break;
								default:
									jj_la1[28] = 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 (true)
					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() : jj_ntk) {
					case NATURAL:
					case INNER:
					case RIGHT:
					case LEFT:
					case FULL:
					case JOIN:
						;
						break;
					default:
						jj_la1[29] = jj_gen;
						break label_6;
				}
			}
			{
				if (true)
					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() : jj_ntk) {
					case NATURAL:
						jj_consume_token(NATURAL);
						natural = true;
						switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
							case INNER:
							case RIGHT:
							case LEFT:
							case FULL:
								switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
									case INNER:
										jj_consume_token(INNER);
										break;
									case RIGHT:
									case LEFT:
									case FULL:
										switch((jj_ntk == -1) ? jj_ntk() : 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[30] = jj_gen;
												jj_consume_token(-1);
												throw new ParseException();
										}
										switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
											case OUTER:
												jj_consume_token(OUTER);
												break;
											default:
												jj_la1[31] = jj_gen;
												;
										}
										break;
									default:
										jj_la1[32] = jj_gen;
										jj_consume_token(-1);
										throw new ParseException();
								}
								break;
							default:
								jj_la1[33] = jj_gen;
								;
						}
						jj_consume_token(JOIN);
						rightTable = SimpleTableRef();
						join = queryFactory.createJoin(type, leftTable, rightTable);
						join.setPosition(new TextPosition(leftTable.getPosition(), rightTable.getPosition())); {
						if (true)
							return join;
					}
						break;
					case INNER:
					case RIGHT:
					case LEFT:
					case FULL:
					case JOIN:
						switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
							case INNER:
							case RIGHT:
							case LEFT:
							case FULL:
								switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
									case INNER:
										jj_consume_token(INNER);
										break;
									case RIGHT:
									case LEFT:
									case FULL:
										switch((jj_ntk == -1) ? jj_ntk() : 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[34] = jj_gen;
												jj_consume_token(-1);
												throw new ParseException();
										}
										switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
											case OUTER:
												jj_consume_token(OUTER);
												break;
											default:
												jj_la1[35] = jj_gen;
												;
										}
										break;
									default:
										jj_la1[36] = jj_gen;
										jj_consume_token(-1);
										throw new ParseException();
								}
								break;
							default:
								jj_la1[37] = jj_gen;
								;
						}
						jj_consume_token(JOIN);
						rightTable = SimpleTableRef();
						switch((jj_ntk == -1) ? jj_ntk() : 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 (true)
									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() : jj_ntk) {
										case COMMA:
											;
											break;
										default:
											jj_la1[38] = 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 (true)
									return join;
							}
								break;
							default:
								jj_la1[39] = jj_gen;
								jj_consume_token(-1);
								throw new ParseException();
						}
						break;
					default:
						jj_la1[40] = 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() : jj_ntk) {
					case STRING_LITERAL:
						;
						break;
					default:
						jj_la1[41] = jj_gen;
						break label_8;
				}
			}
			try {
				cst = queryFactory.createStringConstant(str);
				cst.setPosition(new TextPosition(start, t));
				{
					if (true)
						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() : 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[42] = jj_gen;
					jj_consume_token(-1);
					throw new ParseException();
			}
			try {
				cst = queryFactory.createNumericConstant(t.image);
				cst.setPosition(new TextPosition(t));
				{
					if (true)
						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() : 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[43] = jj_gen;
					jj_consume_token(-1);
					throw new ParseException();
			}
			try {
				cst = queryFactory.createNumericConstant(t.image);
				cst.setPosition(new TextPosition(t));
				{
					if (true)
						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() : jj_ntk) {
				case PLUS:
				case MINUS:
					switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
						case PLUS:
							sign = jj_consume_token(PLUS);
							break;
						case MINUS:
							sign = jj_consume_token(MINUS);
							break;
						default:
							jj_la1[44] = jj_gen;
							jj_consume_token(-1);
							throw new ParseException();
					}
					break;
				default:
					jj_la1[45] = 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 (true)
						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() : jj_ntk) {
					case SCIENTIFIC_NUMBER:
					case UNSIGNED_FLOAT:
					case UNSIGNED_INTEGER:
						// unsigned_value_specification
						op = UnsignedNumeric(); {
						if (true)
							return op;
					}
						break;
					case DELIMITED_IDENTIFIER:
					case REGULAR_IDENTIFIER_CANDIDATE:
						column = Column();
						column.setExpectedType('N'); {
						if (true)
							return column;
					}
						break;
					case AVG:
					case MAX:
					case MIN:
					case SUM:
					case COUNT:
						op = SqlFunction(); {
						if (true)
							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 (true)
							return wop;
					}
						break;
					default:
						jj_la1[46] = 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() : jj_ntk) {
					case STRING_LITERAL:
						// string
						expr = String(); {
						if (true)
							return expr;
					}
						break;
					case SCIENTIFIC_NUMBER:
					case UNSIGNED_FLOAT:
					case UNSIGNED_INTEGER:
						op = UnsignedNumeric(); {
						if (true)
							return op;
					}
						break;
					case AVG:
					case MAX:
					case MIN:
					case SUM:
					case COUNT:
						op = SqlFunction(); {
						if (true)
							return op;
					}
						break;
					case DELIMITED_IDENTIFIER:
					case REGULAR_IDENTIFIER_CANDIDATE:
						column = Column();
						column.setExpectedType('*'); {
						if (true)
							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 (true)
							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("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() : jj_ntk) {
						case DELIMITED_IDENTIFIER:
						case REGULAR_IDENTIFIER_CANDIDATE:
							valueExpr = Column();
							break;
						default:
							jj_la1[48] = jj_gen;
							jj_consume_token(-1);
							throw new ParseException();
					}
				}
				{
					if (true)
						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() : jj_ntk) {
				case PLUS:
				case MINUS:
					switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
						case PLUS:
							sign = jj_consume_token(PLUS);
							break;
						case MINUS:
							sign = jj_consume_token(MINUS);
							break;
						default:
							jj_la1[49] = jj_gen;
							jj_consume_token(-1);
							throw new ParseException();
					}
					rightOp = NumericExpression();
					break;
				default:
					jj_la1[50] = jj_gen;
					;
			}
			if (sign == null) {
				if (true)
					return leftOp;
			} else {
				try {
					Operation operation = queryFactory.createOperation(leftOp, OperationType.getOperator(sign.image), rightOp);
					operation.setPosition(new TextPosition(leftOp.getPosition(), rightOp.getPosition()));
					{
						if (true)
							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() : jj_ntk) {
				case ASTERISK:
				case DIVIDE:
					switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
						case ASTERISK:
							sign = jj_consume_token(ASTERISK);
							break;
						case DIVIDE:
							sign = jj_consume_token(DIVIDE);
							break;
						default:
							jj_la1[51] = jj_gen;
							jj_consume_token(-1);
							throw new ParseException();
					}
					rightOp = NumericTerm();
					break;
				default:
					jj_la1[52] = jj_gen;
					;
			}
			if (sign == null) {
				if (true)
					return leftOp;
			} else {
				try {
					Operation operation = queryFactory.createOperation(leftOp, OperationType.getOperator(sign.image), rightOp);
					operation.setPosition(new TextPosition(leftOp.getPosition(), rightOp.getPosition()));
					{
						if (true)
							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() : jj_ntk) {
				case PLUS:
				case MINUS:
					switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
						case PLUS:
							jj_consume_token(PLUS);
							break;
						case MINUS:
							minusSign = jj_consume_token(MINUS);
							negative = true;
							break;
						default:
							jj_la1[53] = jj_gen;
							jj_consume_token(-1);
							throw new ParseException();
					}
					break;
				default:
					jj_la1[54] = jj_gen;
					;
			}
			if (jj_2_12(2)) {
				op = NumericFunction();
			} else {
				switch((jj_ntk == -1) ? jj_ntk() : 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[55] = 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 (true)
					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() : jj_ntk) {
					case CONCAT:
						;
						break;
					default:
						jj_la1[56] = 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 (true)
					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() : jj_ntk) {
				case COORDSYS:
					op = ExtractCoordSys();
					break;
				default:
					jj_la1[57] = jj_gen;
					if (jj_2_13(2)) {
						op = UserDefinedFunction();
						((UserDefinedFunction)op).setExpectedType('S');
					} else {
						switch((jj_ntk == -1) ? jj_ntk() : 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[58] = jj_gen;
								jj_consume_token(-1);
								throw new ParseException();
						}
					}
			}
			{
				if (true)
					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() : 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[59] = jj_gen;
					jj_consume_token(-1);
					throw new ParseException();
			}
			if (col != null) {
				col.setExpectedType('G');
				{
					if (true)
						return new GeometryValue<GeometryFunction>(col);
				}
			} else {
				if (true)
					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() : jj_ntk) {
					case NOT:
						op = jj_consume_token(NOT);
						notOp = true;
						break;
					default:
						jj_la1[60] = 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() : jj_ntk) {
						case AND:
						case OR:
							;
							break;
						default:
							jj_la1[61] = jj_gen;
							break label_10;
					}
					switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
						case AND:
							op = jj_consume_token(AND);
							break;
						case OR:
							op = jj_consume_token(OR);
							break;
						default:
							jj_la1[62] = jj_gen;
							jj_consume_token(-1);
							throw new ParseException();
					}
					switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
						case NOT:
							jj_consume_token(NOT);
							notOp = true;
							break;
						default:
							jj_la1[63] = 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 (true)
					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() : 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[64] = jj_gen;
						jj_consume_token(-1);
						throw new ParseException();
				}
			}
			{
				if (true)
					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() : 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 (true)
							return e;
					}
						break;
					default:
						jj_la1[69] = jj_gen;
						if (jj_2_16(2147483647)) {
							column = Column();
							jj_consume_token(IS);
							switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
								case NOT:
									notToken = jj_consume_token(NOT);
									break;
								default:
									jj_la1[65] = 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 (true)
									return in;
							}
						} else if (jj_2_17(2147483647)) {
							strExpr1 = StringExpression();
							switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
								case NOT:
									notToken = jj_consume_token(NOT);
									break;
								default:
									jj_la1[66] = 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 (true)
									return comp;
							}
						} else {
							switch((jj_ntk == -1) ? jj_ntk() : 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() : 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[67] = jj_gen;
											if (jj_2_15(2)) {
												constraint = BetweenEnd(op);
											} else {
												switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
													case NOT:
													case IN:
														constraint = InEnd(op);
														break;
													default:
														jj_la1[68] = jj_gen;
														jj_consume_token(-1);
														throw new ParseException();
												}
											}
									}
									break;
								default:
									jj_la1[70] = jj_gen;
									jj_consume_token(-1);
									throw new ParseException();
							}
						}
				}
			} catch(Exception ex) {
				{
					if (true)
						throw generateParseException(ex);
				}
			}
			{
				if (true)
					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() : 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[71] = 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 (true)
						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() : jj_ntk) {
				case NOT:
					notToken = jj_consume_token(NOT);
					break;
				default:
					jj_la1[72] = 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 (true)
						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() : jj_ntk) {
				case NOT:
					not = jj_consume_token(NOT);
					break;
				default:
					jj_la1[73] = jj_gen;
					;
			}
			start = jj_consume_token(IN);
			if (jj_2_18(2)) {
				q = SubQueryExpression();
			} else {
				switch((jj_ntk == -1) ? jj_ntk() : 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() : jj_ntk) {
								case COMMA:
									;
									break;
								default:
									jj_la1[74] = jj_gen;
									break label_11;
							}
							jj_consume_token(COMMA);
							item = ValueExpression();
							items.add(item);
						}
						jj_consume_token(RIGHT_PAR);
						break;
					default:
						jj_la1[75] = 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 (true)
						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() : jj_ntk) {
					case COUNT:
						fct = jj_consume_token(COUNT);
						jj_consume_token(LEFT_PAR);
						switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
							case QUANTIFIER:
								distinct = jj_consume_token(QUANTIFIER);
								break;
							default:
								jj_la1[76] = jj_gen;
								;
						}
						switch((jj_ntk == -1) ? jj_ntk() : 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[77] = 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() : 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[78] = jj_gen;
								jj_consume_token(-1);
								throw new ParseException();
						}
						jj_consume_token(LEFT_PAR);
						switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
							case QUANTIFIER:
								distinct = jj_consume_token(QUANTIFIER);
								break;
							default:
								jj_la1[79] = 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[80] = jj_gen;
						jj_consume_token(-1);
						throw new ParseException();
				}
			} catch(Exception ex) {
				{
					if (true)
						throw generateParseException(ex);
				}
			}
			{
				if (true)
					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 (true)
					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() : jj_ntk) {
					case CONTAINS:
					case INTERSECTS:
						switch((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
							case CONTAINS:
								fct = jj_consume_token(CONTAINS);
								break;
							case INTERSECTS:
								fct = jj_consume_token(INTERSECTS);
								break;
							default:
								jj_la1[81] = 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() : 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[82] = 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() : 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[83] = 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() : jj_ntk) {
							case POINT:
								p1 = Point();
								break;
							case DELIMITED_IDENTIFIER:
							case REGULAR_IDENTIFIER_CANDIDATE:
								col1 = Column();
								break;
							default:
								jj_la1[84] = 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() : jj_ntk) {
							case POINT:
								p2 = Point();
								break;
							case DELIMITED_IDENTIFIER:
							case REGULAR_IDENTIFIER_CANDIDATE:
								col2 = Column();
								break;
							default:
								jj_la1[85] = 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[86] = jj_gen;
						jj_consume_token(-1);
						throw new ParseException();
				}
			} catch(Exception ex) {
				{
					if (true)
						throw generateParseException(ex);
				}
			}
			gf.setPosition(new TextPosition(fct, end));
			{
				if (true)
					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 (true)
					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() : 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() : jj_ntk) {
								case COMMA:
									;
									break;
								default:
									jj_la1[87] = 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[88] = 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 (true)
					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 (true)
						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 (true)
						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() : 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[89] = jj_gen;
					jj_consume_token(-1);
					throw new ParseException();
			}
			{
				if (true)
					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() : 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() : 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[90] = 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() : jj_ntk) {
							case COMMA:
								jj_consume_token(COMMA);
								param2 = SignedInteger();
								break;
							default:
								jj_la1[91] = 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() : jj_ntk) {
							case COMMA:
								jj_consume_token(COMMA);
								param2 = SignedInteger();
								break;
							default:
								jj_la1[92] = jj_gen;
								;
						}
						end = jj_consume_token(RIGHT_PAR);
						break;
					default:
						jj_la1[93] = 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 (true)
						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() : 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[94] = 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 (true)
						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() : 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() : jj_ntk) {
							case COMMA:
								;
								break;
							default:
								jj_la1[95] = jj_gen;
								break label_13;
						}
						jj_consume_token(COMMA);
						op = ValueExpression();
						params.add(op);
					}
					break;
				default:
					jj_la1[96] = 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 (true)
						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_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;
	}

	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(42)) {
			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(65)) {
			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_53() {
		if (jj_scan_token(SELECT))
			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_16() {
		if (jj_scan_token(LEFT_PAR))
			return true;
		if (jj_3R_33())
			return true;
		return false;
	}

	private boolean jj_3R_121() {
		if (jj_3R_23())
			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_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(60)) {
			jj_scanpos = xsp;
			if (jj_scan_token(61))
				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(49)) {
			jj_scanpos = xsp;
			if (jj_scan_token(50)) {
				jj_scanpos = xsp;
				if (jj_scan_token(51)) {
					jj_scanpos = xsp;
					if (jj_scan_token(52))
						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(94)) {
			jj_scanpos = xsp;
			if (jj_scan_token(95)) {
				jj_scanpos = xsp;
				if (jj_scan_token(96))
					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(25)) {
			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(26))
			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(25)) {
			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(36))
			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(36))
			jj_scanpos = xsp;
		if (jj_scan_token(LIKE))
			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[97];
	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, 0x40, 0x0, 0x0, 0x800000, 0x800000, 0x800, 0x608, 0x40, 0x40, 0x40, 0x0, 0x20, 0x20, 0x20, 0x0, 0x0, 0x0, 0x800000, 0x800000, 0x800000, 0x0, 0x8, 0x7b000000, 0x38000000, 0x4000000, 0x3a000000, 0x3a000000, 0x38000000, 0x4000000, 0x3a000000, 0x3a000000, 0x40, 0x80000000, 0x7b000000, 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, 0x2, 0x1000, 0x2000, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfffe0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18000, 0x18000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e0000, 0x3e0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e0000, 0x0, 0x0, 0x3e0000, 0xfc00000, 0x10, 0xc, 0xc, 0x10, 0x0, 0x10, 0x10, 0x0, 0x210, 0x400, 0xfffe0000, 0x0, 0x10, 0x10, 0x0, 0x0, 0x0, 0xfffe0000, 0x1e0000, 0x0, 0x3e0000, 0x30000000, 0x2000000, 0x2000000, 0x2000000, 0x2000000, 0xf0000000, 0x0, 0xfc00000, 0xf0000000, 0xf03e0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfffe0000, };
	}

	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, 0xe3ffffff, 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, 0x20000000, 0xc0000000, 0x80000000, 0x0, 0x0, 0xc0000000, 0xe0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0000000, 0x0, 0x2, 0xe0000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe3ffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe3ffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x3fffffd, 0xc3fffffd, 0x0, 0x0, 0x3fff8, 0x3fc0000, 0x0, 0xe3ffffff, };
	}

	private static void jj_la1_init_3() {
		jj_la1_3 = new int[]{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x30, 0x0, 0x30, 0x0, 0x31, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x30, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x31, 0x31, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x31, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x0, 0x30, 0x30, 0x30, 0x30, 0x0, 0x0, 0x0, 0x20, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, };
	}

	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 < 97; 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 < 97; 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 < 97; 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 < 97; 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 < 97; 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 < 97; 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();
	}

	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() {
		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[103];
		if (jj_kind >= 0) {
			la1tokens[jj_kind] = true;
			jj_kind = -1;
		}
		for(int i = 0; i < 97; 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 < 103; 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;
	}

}
