/* $ANTLR 2.7.2: "XPathSelection.g" -> "XPathSelectionTreeParser.cpp"$ */
#include "XPathSelectionTreeParser.hpp"
#include <antlr/Token.hpp>
#include <antlr/AST.hpp>
#include <antlr/NoViableAltException.hpp>
#include <antlr/MismatchedTokenException.hpp>
#include <antlr/SemanticException.hpp>
#include <antlr/BitSet.hpp>
#line 42 "XPathSelection.g"


	// Utility function to count the number of children of an AST node.
	//
	int ASTNumChildren(AST *ast)
	{
		int n= 0;
		RefAST rast= ast->getFirstChild();
		while(rast)
		{
			++n;
			rast= rast->getNextSibling();
		}
		return n;
	}

#line 27 "XPathSelectionTreeParser.cpp"
XPathSelectionTreeParser::XPathSelectionTreeParser()
	: ANTLR_USE_NAMESPACE(antlr)TreeParser() {
}

QueryPlan::SharedPtr  XPathSelectionTreeParser::xpath(ANTLR_USE_NAMESPACE(antlr)RefAST _t,
	XmlQueryContext &context
) {
#line 68 "XPathSelection.g"
	QueryPlan::SharedPtr r;
#line 37 "XPathSelectionTreeParser.cpp"
	ANTLR_USE_NAMESPACE(antlr)RefAST xpath_AST_in = _t;
	
	ANTLR_USE_NAMESPACE(antlr)RefAST __t2 = _t;
	ANTLR_USE_NAMESPACE(antlr)RefAST tmp1_AST_in = _t;
	match(_t,XPATH);
	_t = _t->getFirstChild();
	r=expr(_t,context);
	_t = _retTree;
	_t = __t2;
	_t = _t->getNextSibling();
	_retTree = _t;
	return r;
}

QueryPlan::SharedPtr  XPathSelectionTreeParser::expr(ANTLR_USE_NAMESPACE(antlr)RefAST _t,
	XmlQueryContext &context
) {
#line 72 "XPathSelection.g"
	QueryPlan::SharedPtr r;
#line 57 "XPathSelectionTreeParser.cpp"
	ANTLR_USE_NAMESPACE(antlr)RefAST expr_AST_in = _t;
	ANTLR_USE_NAMESPACE(antlr)RefAST a3 = ANTLR_USE_NAMESPACE(antlr)nullAST;
	ANTLR_USE_NAMESPACE(antlr)RefAST b3 = ANTLR_USE_NAMESPACE(antlr)nullAST;
	ANTLR_USE_NAMESPACE(antlr)RefAST a19 = ANTLR_USE_NAMESPACE(antlr)nullAST;
	ANTLR_USE_NAMESPACE(antlr)RefAST a20 = ANTLR_USE_NAMESPACE(antlr)nullAST;
	ANTLR_USE_NAMESPACE(antlr)RefAST a21 = ANTLR_USE_NAMESPACE(antlr)nullAST;
	ANTLR_USE_NAMESPACE(antlr)RefAST a22 = ANTLR_USE_NAMESPACE(antlr)nullAST;
#line 72 "XPathSelection.g"
	
		QueryPlan::SharedPtr a;
		QueryPlan::SharedPtr b;
		QueryPlan::SharedPtr c;
	
#line 71 "XPathSelectionTreeParser.cpp"
	
	if (_t == ANTLR_USE_NAMESPACE(antlr)nullAST )
		_t = ASTNULL;
	switch ( _t->getType()) {
	case CHAIN:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t4 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp2_AST_in = _t;
		match(_t,CHAIN);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t4;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 80 "XPathSelection.g"
			
				// Optimize away constants.
				// JCM - What if both are constants?
				if(!a || QueryPlan::is(a,QueryPlan::CONSTANT))
				{
					r=b;
				}
				else if(!b || QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					r=a;
				}
				else
				{
					r.reset(new PlaceHolderQP(QueryPlan::GLUE,"@",a,b));
				}
			
#line 106 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case PREDICATE:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t5 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp3_AST_in = _t;
		match(_t,PREDICATE);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		_t = __t5;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 98 "XPathSelection.g"
			
				r= a;
			
#line 125 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case ROOT:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp4_AST_in = _t;
		match(_t,ROOT);
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 103 "XPathSelection.g"
			
				r.reset(new SequentialScanQP);
				r->setReturnType(QueryPlan::RETURNTYPE_RESULTSET);
			
#line 140 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case DISCOVER:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t6 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp5_AST_in = _t;
		match(_t,DISCOVER);
		_t = _t->getFirstChild();
		a3 = _t;
		match(_t,AXIS);
		_t = _t->getNextSibling();
		b3 = (_t == ASTNULL) ? ANTLR_USE_NAMESPACE(antlr)nullAST : _t;
		nodeTest(_t);
		_t = _retTree;
		_t = __t6;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 109 "XPathSelection.g"
			
				if(b3!=0)
				{
					// The parser adds a '.any/' prefix to the name when it appears after a '//'.
					//
					// *                     => name='/*'
					// /*                    => name='/*'
					// //*                   => name='.any/*'
					// //foo[bar]            => name='.any/foo',name='bar'
					// //foo[text()='bar']   => name='.any/foo',name='*foo'
					// //*[text()='bar']     => name='.any/*',text (*1)
					//
					// *1 - would need an index that does not have the node type and name
					//      before the value in the key.
					//
					// jcm - /foo/bar/foo/parent::bar/parent::foo
					//
					std::string n(b3->getText());
					std::string n1;
					std::string n2;
					bool anywhere= false;
					std::string::size_type p1 = n.find("\\");
					if(p1!=std::string::npos) {
						std::string::size_type p2 = n.find("\\", p1+1);
						if(p2!=std::string::npos) {
							anywhere= strncmp(n.c_str(),".any",4)==0;
							n1= n.substr(p1+1, p2-p1-1);
							n2= n.substr(p2+1);
						} else {
							n1= n.substr(0, p1);
							n2= n.substr(p1+1);
							anywhere= n1.compare(".any")==0;
						}
						if(!n1.empty() && (n1[0]=='.' || n1[0]=='*')) n1= "";
					}
					if(n2.empty() || n2.compare("*")==0)
					{
						r.reset(new SequentialScanQP());
						r->setReturnType(QueryPlan::RETURNTYPE_RESULTSET);
					}
					else
					{
						switch(b3->getType())
						{
						case NAME:
							r.reset(new StepQP(a3->getText(), n1, n2));
							((StepQP*)r.get())->setContextNode(true);
							break;
						case NODE:
							//
							r.reset(new StepQP(a3->getText(), n1, n2));
							((StepQP*)r.get())->setContextNode(true);
							break;
						case TEXT:
							//
							// If the query doesn't explicitly state which node we want the text value
							// of then we get no help from the indexes.
							//
							// Explicit    : //foo[text()='bar']
							// Not Explicit: //*[text()='bar']
							//
							r.reset(new StepQP(a3->getText(), n1, n2));
							((StepQP*)r.get())->setContextNode(true);
							break;
						case COMMENT:
						case PROCESSING_INSTRUCTION:
							//
							// Comment nodes are not indexed
							// Processing Instruction nodes are not indexed
							//
							r.reset(new SequentialScanQP());
							break;
						}
						if(anywhere)
						{
							r->setReturnType(QueryPlan::RETURNTYPE_RESULTSET);
							((StepQP*)r.get())->setAnywhere(anywhere);
						}
					}
				}
			
#line 241 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case UNION:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t7 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp6_AST_in = _t;
		match(_t,UNION);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t7;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 192 "XPathSelection.g"
			
				// Optimize away constants.
				// JCM - What if both are constants?
				if(!a || QueryPlan::is(a,QueryPlan::CONSTANT))
				{
					r= b;
				}
				else if(!b || QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					r= a;
				}
				else
				{
					r.reset(new SetOperationUnionQP(a,b));
				}
			
#line 275 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case OR:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t8 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp7_AST_in = _t;
		match(_t,OR);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t8;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 210 "XPathSelection.g"
			
				bool isbool_a= false;
				bool isbool_b= false;
				bool b_a= false;
				bool b_b= false;
				ConstantQP *cqp_a= (ConstantQP*)a.get();
				if(QueryPlan::is(a,QueryPlan::CONSTANT))
				{
					isbool_a= true;
					b_a= cqp_a->getValue().asBoolean(&context);
				}
				if(QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					isbool_b= true;
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					b_b= cqp_b->getValue().asBoolean(&context);
				}
				if(isbool_a && isbool_b)
				{
					cqp_a->setBoolean(b_a||b_b);
					r= a;
				}
				else if(isbool_a)
				{
					r= (b_a?a:b);
				}
				else if(isbool_b)
				{
					r= (b_b?b:a);
				}
				else
				{
					r.reset(new PlaceHolderQP(QueryPlan::OR,"|",a,b));
				}
			
#line 328 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case AND:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t9 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp8_AST_in = _t;
		match(_t,AND);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t9;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 247 "XPathSelection.g"
			
				bool isbool_a= false;
				bool isbool_b= false;
				bool b_a= false;
				bool b_b= false;
				ConstantQP *cqp_a= (ConstantQP*)a.get();
				if(QueryPlan::is(a,QueryPlan::CONSTANT))
				{
					isbool_a= true;
					b_a= cqp_a->getValue().asBoolean(&context);
				}
				if(QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					isbool_b= true;
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					b_b= cqp_b->getValue().asBoolean(&context);
				}
				if(isbool_a && isbool_b)
				{
					cqp_a->setBoolean(b_a&&b_b);
					r= a;
				}
				else if(isbool_a)
				{
					r= (!b_a?a:b);
				}
				else if(isbool_b)
				{
					r= (!b_b?b:a);
				}
				else
				{
					r.reset(new PlaceHolderQP(QueryPlan::AND,"&",a,b));
				}
			
#line 381 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case EQUAL:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t10 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp9_AST_in = _t;
		match(_t,EQUAL);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t10;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 284 "XPathSelection.g"
			
				if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
				   QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					ConstantQP *cqp_a= (ConstantQP*)a.get();
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					cqp_a->setBoolean(cqp_a->getValue().equals(cqp_b->getValue(),&context));
					r= a;
				}
				else
				{
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						QueryPlan::SharedPtr t=a; a=b; b=t; // swap(a,b)
					}
					QueryPlan &qp_a= a->rightmost();
					if(qp_a.getType()==QueryPlan::STEP &&
						QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						StepQP *sqp_a= (StepQP*)&qp_a;
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						sqp_a->setOperation(Database::EQUALITY);
						sqp_a->setValue(cqp_b->getValue());
						r= a;
					}
					else
					{
						r.reset(new SequentialScanQP());
					}
				}
			
#line 430 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case NOTEQUAL:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t11 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp10_AST_in = _t;
		match(_t,NOTEQUAL);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t11;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 317 "XPathSelection.g"
			
				if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
				   QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					ConstantQP *cqp_a= (ConstantQP*)a.get();
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					cqp_a->setBoolean(!cqp_a->getValue().equals(cqp_b->getValue(),&context));
					r= a;
				}
				else
				{
					// There's no index support for inequality.
					r.reset(new SequentialScanQP());
				}
			
#line 463 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case LTX:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t12 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp11_AST_in = _t;
		match(_t,LTX);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t12;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 334 "XPathSelection.g"
			
				// Only supported for Numbers.
				r.reset(0);
				if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
				   QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					ConstantQP *cqp_a= (ConstantQP*)a.get();
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					XmlValue v_a(cqp_a->getValue());
					XmlValue v_b(cqp_b->getValue());
					if(v_a.isNumber(&context) && v_b.isNumber(&context))
					{
						cqp_a->setBoolean(v_a.asNumber(&context) < v_b.asNumber(&context));
						r= a;
					}
				}
				else
				{
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						QueryPlan::SharedPtr t=a; a=b; b=t; // swap(a,b)
					}
					QueryPlan &qp_a= a->rightmost();
					if(qp_a.getType()==QueryPlan::STEP &&
						QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						StepQP *sqp_a= (StepQP*)&qp_a;
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						XmlValue v_b(cqp_b->getValue());
						if(v_b.isNumber(&context)) // JCM - Should be asNumber
						{
							sqp_a->setOperation(Database::LTX);
							sqp_a->setValue(v_b);
							r= a;
						}
						else
						{
							throw XmlException(XmlException::XPATH_PARSER_ERROR,"Inequality searches (<) are only supported for numbers.");
						}
					}
					else
					{
						r.reset(new SequentialScanQP());
					}
				}
			
#line 527 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case GTX:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t13 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp12_AST_in = _t;
		match(_t,GTX);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t13;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 382 "XPathSelection.g"
			
				// Only supported for Numbers.
				r.reset(0);
				if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
				   QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					ConstantQP *cqp_a= (ConstantQP*)a.get();
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					XmlValue v_a(cqp_a->getValue());
					XmlValue v_b(cqp_b->getValue());
					if(v_a.isNumber(&context) && v_b.isNumber(&context))
					{
						cqp_a->setBoolean(v_a.asNumber(&context) > v_b.asNumber(&context));
						r= a;
					}
				}
				else
				{
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						QueryPlan::SharedPtr t=a; a=b; b=t; // swap(a,b)
					}
					QueryPlan &qp_a= a->rightmost();
					if(qp_a.getType()==QueryPlan::STEP &&
						QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						StepQP *sqp_a= (StepQP*)&qp_a;
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						XmlValue v_b(cqp_b->getValue());
						if(v_b.isNumber(&context)) // JCM - Should be asNumber
						{
							sqp_a->setOperation(Database::GTX);
							sqp_a->setValue(v_b);
							r= a;
						}
						else
						{
							throw XmlException(XmlException::XPATH_PARSER_ERROR,"Inequality searches (>) are only supported for numbers.");
						}
					}
					else
					{
						r.reset(new SequentialScanQP());
					}
				}
			
#line 591 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case LTE:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t14 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp13_AST_in = _t;
		match(_t,LTE);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t14;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 430 "XPathSelection.g"
			
				// Only supported for Numbers.
				r.reset(0);
				if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
				   QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					ConstantQP *cqp_a= (ConstantQP*)a.get();
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					XmlValue v_a(cqp_a->getValue());
					XmlValue v_b(cqp_b->getValue());
					if(v_a.isNumber(&context) && v_b.isNumber(&context))
					{
						cqp_a->setBoolean(v_a.asNumber(&context) <= v_b.asNumber(&context));
						r= a;
					}
				}
				else
				{
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						QueryPlan::SharedPtr t=a; a=b; b=t; // swap(a,b)
					}
					QueryPlan &qp_a= a->rightmost();
					if(qp_a.getType()==QueryPlan::STEP &&
						QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						StepQP *sqp_a= (StepQP*)&qp_a;
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						XmlValue v_b(cqp_b->getValue());
						if(v_b.isNumber(&context)) // JCM - Should be asNumber
						{
							sqp_a->setOperation(Database::LTE);
							sqp_a->setValue(v_b);
							r= a;
						}
						else
						{
							throw XmlException(XmlException::XPATH_PARSER_ERROR,"Inequality searches (<=) are only supported for numbers.");
						}
					}
					else
					{
						r.reset(new SequentialScanQP());
					}
				}
			
#line 655 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case GTE:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t15 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp14_AST_in = _t;
		match(_t,GTE);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t15;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 478 "XPathSelection.g"
			
				// Only supported for Numbers.
				r.reset(0);
				if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
				   QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					ConstantQP *cqp_a= (ConstantQP*)a.get();
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					XmlValue v_a(cqp_a->getValue());
					XmlValue v_b(cqp_b->getValue());
					if(v_a.isNumber(&context) && v_b.isNumber(&context))
					{
						cqp_a->setBoolean(v_a.asNumber(&context) >= v_b.asNumber(&context));
						r= a;
					}
				}
				else
				{
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						QueryPlan::SharedPtr t=a; a=b; b=t; // swap(a,b)
					}
					QueryPlan &qp_a= a->rightmost();
					if(qp_a.getType()==QueryPlan::STEP &&
						QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						StepQP *sqp_a= (StepQP*)&qp_a;
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						XmlValue v_b(cqp_b->getValue());
						if(v_b.isNumber(&context)) // JCM - Should be asNumber
						{
							sqp_a->setOperation(Database::GTE);
							sqp_a->setValue(v_b);
							r= a;
						}
						else
						{
							throw XmlException(XmlException::XPATH_PARSER_ERROR,"Inequality searches (>=) are only supported for numbers.");
						}
					}
					else
					{
						r.reset(new SequentialScanQP());
					}
				}
			
#line 719 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case PLUS:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t16 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp15_AST_in = _t;
		match(_t,PLUS);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t16;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 526 "XPathSelection.g"
			
				r.reset(0);
				if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
				   QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					ConstantQP *cqp_a= (ConstantQP*)a.get();
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					XmlValue v_a(cqp_a->getValue());
					XmlValue v_b(cqp_b->getValue());
					if(v_a.isNumber(&context) && v_b.isNumber(&context))
					{
						cqp_a->setNumber(v_a.asNumber(&context) + v_b.asNumber(&context));
						r= a;
					}
				}
				else
				{
					r.reset(new SequentialScanQP());
				}
			
#line 757 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case STAR:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t22 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp16_AST_in = _t;
		match(_t,STAR);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t22;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 593 "XPathSelection.g"
			
				r.reset(0);
				if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
				   QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					ConstantQP *cqp_a= (ConstantQP*)a.get();
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					XmlValue v_a(cqp_a->getValue());
					XmlValue v_b(cqp_b->getValue());
					if(v_a.isNumber(&context) && v_b.isNumber(&context))
					{
						cqp_a->setNumber(v_a.asNumber(&context) * v_b.asNumber(&context));
						r= a;
					}
				}
				else
				{
					r.reset(new SequentialScanQP());
				}
			
#line 795 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case DIV:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t23 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp17_AST_in = _t;
		match(_t,DIV);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t23;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 615 "XPathSelection.g"
			
				r.reset(0);
				if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
				   QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					ConstantQP *cqp_a= (ConstantQP*)a.get();
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					XmlValue v_a(cqp_a->getValue());
					XmlValue v_b(cqp_b->getValue());
					if(v_a.isNumber(&context) && v_b.isNumber(&context))
					{
						cqp_a->setNumber(v_a.asNumber(&context) / v_b.asNumber(&context));
						r= a;
					}
				}
				else
				{
					r.reset(new SequentialScanQP());
				}
			
#line 833 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case MOD:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST __t24 = _t;
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp18_AST_in = _t;
		match(_t,MOD);
		_t = _t->getFirstChild();
		a=expr(_t,context);
		_t = _retTree;
		b=expr(_t,context);
		_t = _retTree;
		_t = __t24;
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 637 "XPathSelection.g"
			
				r.reset(0);
				if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
				   QueryPlan::is(b,QueryPlan::CONSTANT))
				{
					ConstantQP *cqp_a= (ConstantQP*)a.get();
					ConstantQP *cqp_b= (ConstantQP*)b.get();
					XmlValue v_a(cqp_a->getValue());
					XmlValue v_b(cqp_b->getValue());
					if(v_a.isNumber(&context) && v_b.isNumber(&context))
					{
						cqp_a->setNumber(fmod(v_a.asNumber(&context),v_b.asNumber(&context)));
						r= a;
					}
				}
				else
				{
					r.reset(new SequentialScanQP());
				}
			
#line 871 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case VARIABLE:
	{
		a19 = _t;
		match(_t,VARIABLE);
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 659 "XPathSelection.g"
			
				XmlValue v(XmlValue::VARIABLE,a19->getText());
			r.reset(new ConstantQP(v));
			
#line 886 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case LITERAL:
	{
		a20 = _t;
		match(_t,LITERAL);
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 665 "XPathSelection.g"
			
			std::string s(a20->getText());
				s= s.substr(1,s.length()-2); // Strip off quotes.
				XmlValue v(s);
			r.reset(new ConstantQP(v));
			
#line 903 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case NUMBER:
	{
		a21 = _t;
		match(_t,NUMBER);
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 673 "XPathSelection.g"
			
				XmlValue v(atof(a21->getText().c_str()));
				r.reset(new ConstantQP(v));
			
#line 918 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	case FUNCTION:
	{
		a22 = _t;
		match(_t,FUNCTION);
		_t = _t->getNextSibling();
		if ( inputState->guessing==0 ) {
#line 679 "XPathSelection.g"
			
				r.reset(0);
				std::string fn= a22->getText();
				int na= ASTNumChildren(a22);
				// last
				// position
				// count
				if(fn.compare("id")==0 && na==1)
				{
					RefAST arg1= a22->getFirstChild();
					a= expr(arg1,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						std::string s(cqp_a->getValue().asString(&context));
						tokenizer tok(s);
						for(string val; tok.next(val) == 0; )
						{
							QueryPlan::SharedPtr sqp(new StepQP("attribute","id",""));
							((StepQP *)sqp.get())->setValue(val);
							((StepQP *)sqp.get())->setOperation(Database::EQUALITY);
							sqp->setReturnType(QueryPlan::RETURNTYPE_RESULTSET);
							if(!r)
							{
								r= sqp;
							}
							else
							{
								r.reset(new PlaceHolderQP(QueryPlan::OR,"|",sqp,r));
							}
						}
					}
				}
				// local-name
				// namespace-uri
				else if(fn.compare("name")==0 && na==0)
				{
					// JCM - Implement support for '[name()='foo']'
					//
					// A step must come before the predicate, and the axis will tell
					// us what kind of node we're dealing with... 
					//
					// '/*[name()='x']' is the same as '/x'
					// '/*[name()=$x]' is interesting
				}
				else if(fn.compare("starts-with")==0 && na==2)
				{
					RefAST arg1= a22->getFirstChild();
					RefAST arg2= arg1->getNextSibling();
					a= expr(arg1,context);
					b= expr(arg2,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
					   QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						cqp_a->setValue(XmlValue::startsWith(&context,cqp_a->getValue(),cqp_b->getValue()));
						r= a;
					}
					else
					{
						QueryPlan &qp_a= a->rightmost();
						if(qp_a.getType()==QueryPlan::STEP &&
						   QueryPlan::is(b,QueryPlan::CONSTANT))
						{
							StepQP *sqp_a= (StepQP*)&qp_a;
							ConstantQP *cqp_b= (ConstantQP*)b.get();
							sqp_a->setOperation(Database::PREFIX);
							sqp_a->setValue(cqp_b->getValue());
							r= a;
						}
					}
				}
				else if(fn.compare("contains")==0 && na==2)
				{
					RefAST arg1= a22->getFirstChild();
					RefAST arg2= arg1->getNextSibling();
					a= expr(arg1,context);
					b= expr(arg2,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
					   QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						cqp_a->setValue(XmlValue::contains(&context,cqp_a->getValue(),cqp_b->getValue()));
						r= a;
					}
					else
					{
						QueryPlan &qp_a= a->rightmost();
						if(qp_a.getType()==QueryPlan::STEP &&
						   QueryPlan::is(b,QueryPlan::CONSTANT))
						{
							StepQP *sqp_a= (StepQP*)&qp_a;
							ConstantQP *cqp_b= (ConstantQP*)b.get();
							sqp_a->setOperation(Database::SUBSTRING);
							sqp_a->setValue(cqp_b->getValue());
							r= a;
						}
					}
				}
				else if(fn.compare("string")==0 && na==1)
				{
					RefAST arg1= a22->getFirstChild();
					a= expr(arg1,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						cqp_a->setValue(XmlValue::string(&context,cqp_a->getValue()));
						r= a;
					}
				}
				else if(fn.compare("concat")==0 && na>=2)
				{
					string s;
					bool failed= false;
					RefAST rast= a22->getFirstChild();
					while(rast && !failed)
					{
						a= expr(rast,context);
						if(QueryPlan::is(a,QueryPlan::CONSTANT))
						{
							ConstantQP *cqp_a= (ConstantQP*)a.get();
							s+= cqp_a->getValue().asString(&context);
							if(!r)
							{
								r= a;
							}
						}
						else
						{
							failed= true;
						}
						rast= rast->getNextSibling();
					}
					if(!failed)
					{
						((ConstantQP*)r.get())->setString(s);
					}
				}
				else if(fn.compare("substring-before")==0 && na==2)
				{
					RefAST arg1= a22->getFirstChild();
					RefAST arg2= arg1->getNextSibling();
					a= expr(arg1,context);
					b= expr(arg2,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
					   QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						cqp_a->setValue(XmlValue::substringBefore(&context,cqp_a->getValue(),cqp_b->getValue()));
						r= a;
					}
					else
					{
						QueryPlan &qp_a= a->rightmost();
						if(qp_a.getType()==QueryPlan::STEP &&
						   QueryPlan::is(b,QueryPlan::CONSTANT))
						{
							StepQP *sqp_a= (StepQP*)&qp_a;
							ConstantQP *cqp_b= (ConstantQP*)b.get();
							sqp_a->setOperation(Database::SUBSTRING);
							sqp_a->setValue(cqp_b->getValue());
							r= a;
						}
					}
				}
				else if(fn.compare("substring-after")==0 && na==2)
				{
					RefAST arg1= a22->getFirstChild();
					RefAST arg2= arg1->getNextSibling();
					a= expr(arg1,context);
					b= expr(arg2,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
					   QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						cqp_a->setValue(XmlValue::substringAfter(&context,cqp_a->getValue(),cqp_b->getValue()));
						r= a;
					}
					else
					{
						QueryPlan &qp_a= a->rightmost();
						if(qp_a.getType()==QueryPlan::STEP &&
						   QueryPlan::is(b,QueryPlan::CONSTANT))
						{
							StepQP *sqp_a= (StepQP*)&qp_a;
							ConstantQP *cqp_b= (ConstantQP*)b.get();
							sqp_a->setOperation(Database::SUBSTRING);
							sqp_a->setValue(cqp_b->getValue());
							r= a;
						}
					}
				}
				else if(fn.compare("substring")==0 && (na==2 || na==3))
				{
					RefAST arg1= a22->getFirstChild();
					RefAST arg2= arg1->getNextSibling();
					a= expr(arg1,context);
					b= expr(arg2,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
					   QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						if(na==2)
						{
							cqp_a->setValue(XmlValue::substring(&context,cqp_a->getValue(),cqp_b->getValue()));
							r= a;
						}
						else
						{
							RefAST arg3= arg2->getNextSibling();
							c= expr(arg3,context);
							if(QueryPlan::is(c,QueryPlan::CONSTANT))
							{
								ConstantQP *cqp_c= (ConstantQP*)c.get();
								cqp_a->setValue(XmlValue::substring(&context,cqp_a->getValue(),cqp_b->getValue(),cqp_c->getValue()));
								r= a;
							}
						}
					}
				}
				else if(fn.compare("string-length")==0 && na==1)
				{
					RefAST arg1= a22->getFirstChild();
					a= expr(arg1,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						cqp_a->setValue(XmlValue::stringLength(&context,cqp_a->getValue()));
						r= a;
					}
				}
				else if(fn.compare("normalize-space")==0 && na==1)
				{
					RefAST arg1= a22->getFirstChild();
					a= expr(arg1,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						cqp_a->setValue(XmlValue::normalizeSpace(&context,cqp_a->getValue()));
						r= a;
					}
				}
				else if(fn.compare("translate")==0 && na==3)
				{
					RefAST arg1= a22->getFirstChild();
					RefAST arg2= arg1->getNextSibling();
					RefAST arg3= arg2->getNextSibling();
					a= expr(arg1,context);
					b= expr(arg2,context);
					c= expr(arg3,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
					   QueryPlan::is(b,QueryPlan::CONSTANT) &&
					   QueryPlan::is(c,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						ConstantQP *cqp_c= (ConstantQP*)c.get();
						cqp_a->setValue(XmlValue::translate(&context,cqp_a->getValue(),cqp_b->getValue(),cqp_c->getValue()));
						r= a;
					}
				}
				else if(fn.compare("boolean")==0 && na==1)
				{
					RefAST arg1= a22->getFirstChild();
					a= expr(arg1,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						cqp_a->setValue(XmlValue::boolean(&context,cqp_a->getValue()));
						r= a;
					}
				}
				else if(fn.compare("not")==0 && na==1)
				{
					RefAST arg1= a22->getFirstChild();
					a= expr(arg1,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						cqp_a->setValue(XmlValue::booleanNot(&context,cqp_a->getValue()));
						r= a;
					}
					else
					{
						// The query plan for the contained expression is discarded.
						// This is OK, as predicates like [not(x='y')] will map onto
						// a SequentialScan, which is OK. Double negative expressions
						// like [not(x!='y')] will not be mapped onto anything clever
						// though... perhaps an exercise for you dear reader.
					}
				}
				else if(fn.compare("true")==0 && na==0)
				{
					XmlValue v(XmlValue::booleanTrue(&context));
					r.reset(new ConstantQP(v));
				}
				else if(fn.compare("false")==0 && na==0)
				{
					XmlValue v(XmlValue::booleanFalse(&context));
					r.reset(new ConstantQP(v));
				}
				else if(fn.compare("number")==0 && na==1)
				{
					RefAST arg1= a22->getFirstChild();
					a= expr(arg1,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						cqp_a->setValue(XmlValue::number(&context,cqp_a->getValue()));
						r= a;
					}
				}
				else if(fn.compare("floor")==0 && na==1)
				{
					RefAST arg1= a22->getFirstChild();
					a= expr(arg1,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						XmlValue v_a(cqp_a->getValue());
						if(v_a.isNumber(&context))
						{
							cqp_a->setValue(XmlValue::floor(&context,v_a));
							r= a;
						}
					}
				}
				else if(fn.compare("ceiling")==0 && na==1)
				{
					RefAST arg1= a22->getFirstChild();
					a= expr(arg1,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						XmlValue v_a(cqp_a->getValue());
						if(v_a.isNumber(&context))
						{
							cqp_a->setValue(XmlValue::ceiling(&context,v_a));
							r= a;
						}
					}
				}
				else if(fn.compare("round")==0 && na==1)
				{
					RefAST arg1= a22->getFirstChild();
					a= expr(arg1,context);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						XmlValue v_a(cqp_a->getValue());
						cqp_a->setValue(XmlValue::round(&context,v_a));
						r= a;
					}
				}
				else
				{
					// Indexes don't support this function...
				}
				if(!r)
				{
					r.reset(new SequentialScanQP());
				}
			
#line 1297 "XPathSelectionTreeParser.cpp"
		}
		break;
	}
	default:
		bool synPredMatched19 = false;
		if (((_t->getType() == MINUS))) {
			ANTLR_USE_NAMESPACE(antlr)RefAST __t19 = _t;
			synPredMatched19 = true;
			inputState->guessing++;
			try {
				{
				ANTLR_USE_NAMESPACE(antlr)RefAST __t18 = _t;
				ANTLR_USE_NAMESPACE(antlr)RefAST tmp19_AST_in = _t;
				match(_t,MINUS);
				_t = _t->getFirstChild();
				expr(_t,context);
				_t = _retTree;
				expr(_t,context);
				_t = _retTree;
				_t = __t18;
				_t = _t->getNextSibling();
				}
			}
			catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException& pe) {
				synPredMatched19 = false;
			}
			_t = __t19;
			inputState->guessing--;
		}
		if ( synPredMatched19 ) {
			ANTLR_USE_NAMESPACE(antlr)RefAST __t20 = _t;
			ANTLR_USE_NAMESPACE(antlr)RefAST tmp20_AST_in = _t;
			match(_t,MINUS);
			_t = _t->getFirstChild();
			a=expr(_t,context);
			_t = _retTree;
			b=expr(_t,context);
			_t = _retTree;
			_t = __t20;
			_t = _t->getNextSibling();
			if ( inputState->guessing==0 ) {
#line 548 "XPathSelection.g"
				
					r.reset(0);
					if(QueryPlan::is(a,QueryPlan::CONSTANT) &&
					   QueryPlan::is(b,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						ConstantQP *cqp_b= (ConstantQP*)b.get();
						XmlValue v_a(cqp_a->getValue());
						XmlValue v_b(cqp_b->getValue());
						if(v_a.isNumber(&context) && v_b.isNumber(&context))
						{
							cqp_a->setNumber(v_a.asNumber(&context) - v_b.asNumber(&context));
							r= a;
						}
					}
					else
					{
						r.reset(new SequentialScanQP());
					}
				
#line 1360 "XPathSelectionTreeParser.cpp"
			}
		}
		else if ((_t->getType() == MINUS)) {
			ANTLR_USE_NAMESPACE(antlr)RefAST __t21 = _t;
			ANTLR_USE_NAMESPACE(antlr)RefAST tmp21_AST_in = _t;
			match(_t,MINUS);
			_t = _t->getFirstChild();
			a=expr(_t,context);
			_t = _retTree;
			_t = __t21;
			_t = _t->getNextSibling();
			if ( inputState->guessing==0 ) {
#line 570 "XPathSelection.g"
				
					r.reset(0);
					if(QueryPlan::is(a,QueryPlan::CONSTANT))
					{
						ConstantQP *cqp_a= (ConstantQP*)a.get();
						XmlValue v_a(cqp_a->getValue());
						if(v_a.isNumber(&context))
						{
							cqp_a->setNumber(-v_a.asNumber(&context));
							r= a;
						}
						else
						{
						 	throw XmlException(XmlException::XPATH_PARSER_ERROR,"Minus Literal (eg. -123) is only supported for numbers.");
						}
					}
					else
					{
						r.reset(new SequentialScanQP());
					}
				
#line 1395 "XPathSelectionTreeParser.cpp"
			}
		}
	else {
		throw ANTLR_USE_NAMESPACE(antlr)NoViableAltException(_t);
	}
	}
	_retTree = _t;
	return r;
}

void XPathSelectionTreeParser::nodeTest(ANTLR_USE_NAMESPACE(antlr)RefAST _t) {
	ANTLR_USE_NAMESPACE(antlr)RefAST nodeTest_AST_in = _t;
	
	if (_t == ANTLR_USE_NAMESPACE(antlr)nullAST )
		_t = ASTNULL;
	switch ( _t->getType()) {
	case NAME:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp22_AST_in = _t;
		match(_t,NAME);
		_t = _t->getNextSibling();
		break;
	}
	case COMMENT:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp23_AST_in = _t;
		match(_t,COMMENT);
		_t = _t->getNextSibling();
		break;
	}
	case TEXT:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp24_AST_in = _t;
		match(_t,TEXT);
		_t = _t->getNextSibling();
		break;
	}
	case NODE:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp25_AST_in = _t;
		match(_t,NODE);
		_t = _t->getNextSibling();
		break;
	}
	case PROCESSING_INSTRUCTION:
	{
		ANTLR_USE_NAMESPACE(antlr)RefAST tmp26_AST_in = _t;
		match(_t,PROCESSING_INSTRUCTION);
		_t = _t->getNextSibling();
		break;
	}
	default:
	{
		throw ANTLR_USE_NAMESPACE(antlr)NoViableAltException(_t);
	}
	}
	_retTree = _t;
}

void XPathSelectionTreeParser::initializeASTFactory( ANTLR_USE_NAMESPACE(antlr)ASTFactory& factory )
{
}
const char* XPathSelectionTreeParser::tokenNames[] = {
	"<0>",
	"EOF",
	"<2>",
	"NULL_TREE_LOOKAHEAD",
	"\"and\"",
	"\"or\"",
	"\"div\"",
	"\"mod\"",
	"\"ancestor\"",
	"\"ancestor-or-self\"",
	"\"attribute\"",
	"\"child\"",
	"\"descendant\"",
	"\"descendant-or-self\"",
	"\"following\"",
	"\"following-sibling\"",
	"\"namespace\"",
	"\"parent\"",
	"\"preceding\"",
	"\"preceding-sibling\"",
	"\"self\"",
	"whitespace",
	"a comment",
	"an identifier",
	"NCNAMECHAR",
	"a string literal",
	"LETTER",
	"a numeric literal",
	"a number",
	"STAR",
	"SLASH",
	"SLASHSLASH",
	"COLON",
	"COLONCOLON",
	"a left bracket '('",
	"a right bracket ')'",
	"a left square bracket '['",
	"a right square bracket ']'",
	"AT",
	"SEMICOLON",
	"a current node selector '.'",
	"a parent node selector '..'",
	"an equals operator '='",
	"a not equals operator '!='",
	"a subtraction or unary minus operator '-'",
	"an addition operator '+'",
	"a greater than operator '>'",
	"a greater than or equals operator '>='",
	"a less than operator '<'",
	"a less than or equals operator '<='",
	"an argument separator ','",
	"a union operator '|'",
	"a variable dereference operator '$'",
	"XPATH",
	"DISCOVER",
	"CHAIN",
	"ROOT",
	"AXIS",
	"OPERATION",
	"NAME",
	"FUNCTION",
	"VARIABLE",
	"TEXT",
	"NODE",
	"COMMENT",
	"PROCESSING_INSTRUCTION",
	"PREDICATE",
	0
};



