/*
 * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON.
 * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/
 * Version 1.7.2
 * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
 * please contact Symisc Systems via:
 *       legal@symisc.net
 *       licensing@symisc.net
 *       contact@symisc.net
 * or visit:
 *      http://jx9.symisc.net/
 */
 /* $SymiscID: parse.c v1.2 FreeBSD 2012-12-11 00:46 stable <chm@symisc.net> $ */
#ifndef JX9_AMALGAMATION
#include "jx9Int.h"
#endif
/* Expression parser for the Jx9 programming language */
/* Operators associativity */
#define EXPR_OP_ASSOC_LEFT   0x01 /* Left associative operator */
#define EXPR_OP_ASSOC_RIGHT  0x02 /* Right associative operator */
#define EXPR_OP_NON_ASSOC    0x04 /* Non-associative operator */
/* 
 * Operators table
 * This table is sorted by operators priority (highest to lowest) according
 * the JX9 language reference manual.
 * JX9 implements all the 60 JX9 operators and have introduced the eq and ne operators.
 * The operators precedence table have been improved dramatically so that you can do same
 * amazing things now such as array dereferencing, on the fly function call, anonymous function
 * as array values, object member access on instantiation and so on.
 * Refer to the following page for a full discussion on these improvements:
 * http://jx9.symisc.net/features.html
 */
static const jx9_expr_op aOpTable[] = {
	                              /* Postfix operators */
	/* Precedence 2(Highest), left-associative */
	{ {".", sizeof(char)}, EXPR_OP_DOT,     2, EXPR_OP_ASSOC_LEFT ,   JX9_OP_MEMBER },
	{ {"[", sizeof(char)}, EXPR_OP_SUBSCRIPT, 2, EXPR_OP_ASSOC_LEFT , JX9_OP_LOAD_IDX}, 
	/* Precedence 3, non-associative  */
	{ {"++", sizeof(char)*2}, EXPR_OP_INCR, 3, EXPR_OP_NON_ASSOC , JX9_OP_INCR}, 
	{ {"--", sizeof(char)*2}, EXPR_OP_DECR, 3, EXPR_OP_NON_ASSOC , JX9_OP_DECR}, 
	                              /* Unary operators */
	/* Precedence 4, right-associative  */
	{ {"-", sizeof(char)},                 EXPR_OP_UMINUS,    4, EXPR_OP_ASSOC_RIGHT, JX9_OP_UMINUS }, 
	{ {"+", sizeof(char)},                 EXPR_OP_UPLUS,     4, EXPR_OP_ASSOC_RIGHT, JX9_OP_UPLUS }, 
	{ {"~", sizeof(char)},                 EXPR_OP_BITNOT,    4, EXPR_OP_ASSOC_RIGHT, JX9_OP_BITNOT }, 
	{ {"!", sizeof(char)},                 EXPR_OP_LOGNOT,    4, EXPR_OP_ASSOC_RIGHT, JX9_OP_LNOT }, 
	                             /* Cast operators */
	{ {"(int)",    sizeof("(int)")-1   }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_INT  }, 
	{ {"(bool)",   sizeof("(bool)")-1  }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_BOOL }, 
	{ {"(string)", sizeof("(string)")-1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_STR  }, 
	{ {"(float)",  sizeof("(float)")-1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_REAL },
	{ {"(array)",  sizeof("(array)")-1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_ARRAY },   /* Not used, but reserved for future use */
	{ {"(object)",  sizeof("(object)")-1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_ARRAY }, /* Not used, but reserved for future use */
	                           /* Binary operators */
	/* Precedence 7, left-associative */ 
	{ {"*", sizeof(char)}, EXPR_OP_MUL, 7, EXPR_OP_ASSOC_LEFT , JX9_OP_MUL}, 
	{ {"/", sizeof(char)}, EXPR_OP_DIV, 7, EXPR_OP_ASSOC_LEFT , JX9_OP_DIV}, 
	{ {"%", sizeof(char)}, EXPR_OP_MOD, 7, EXPR_OP_ASSOC_LEFT , JX9_OP_MOD}, 
	/* Precedence 8, left-associative */
	{ {"+", sizeof(char)}, EXPR_OP_ADD, 8,  EXPR_OP_ASSOC_LEFT, JX9_OP_ADD}, 
	{ {"-", sizeof(char)}, EXPR_OP_SUB, 8,  EXPR_OP_ASSOC_LEFT, JX9_OP_SUB}, 
	{ {"..", sizeof(char)*2},EXPR_OP_DDOT, 8,  EXPR_OP_ASSOC_LEFT, JX9_OP_CAT}, 
	/* Precedence 9, left-associative */
	{ {"<<", sizeof(char)*2}, EXPR_OP_SHL, 9, EXPR_OP_ASSOC_LEFT, JX9_OP_SHL}, 
	{ {">>", sizeof(char)*2}, EXPR_OP_SHR, 9, EXPR_OP_ASSOC_LEFT, JX9_OP_SHR}, 
	/* Precedence 10, non-associative */
	{ {"<", sizeof(char)},    EXPR_OP_LT,  10, EXPR_OP_NON_ASSOC, JX9_OP_LT}, 
	{ {">", sizeof(char)},    EXPR_OP_GT,  10, EXPR_OP_NON_ASSOC, JX9_OP_GT}, 
	{ {"<=", sizeof(char)*2}, EXPR_OP_LE,  10, EXPR_OP_NON_ASSOC, JX9_OP_LE}, 
	{ {">=", sizeof(char)*2}, EXPR_OP_GE,  10, EXPR_OP_NON_ASSOC, JX9_OP_GE}, 
	{ {"<>", sizeof(char)*2}, EXPR_OP_NE,  10, EXPR_OP_NON_ASSOC, JX9_OP_NEQ}, 
	/* Precedence 11, non-associative */
	{ {"==", sizeof(char)*2},  EXPR_OP_EQ,  11, EXPR_OP_NON_ASSOC, JX9_OP_EQ}, 
	{ {"!=", sizeof(char)*2},  EXPR_OP_NE,  11, EXPR_OP_NON_ASSOC, JX9_OP_NEQ}, 
	{ {"===", sizeof(char)*3}, EXPR_OP_TEQ, 11, EXPR_OP_NON_ASSOC, JX9_OP_TEQ}, 
	{ {"!==", sizeof(char)*3}, EXPR_OP_TNE, 11, EXPR_OP_NON_ASSOC, JX9_OP_TNE}, 
		/* Precedence 12, left-associative */
	{ {"&", sizeof(char)}, EXPR_OP_BAND, 12, EXPR_OP_ASSOC_LEFT,   JX9_OP_BAND}, 
	                         /* Binary operators */
	/* Precedence 13, left-associative */
	{ {"^", sizeof(char)}, EXPR_OP_XOR, 13, EXPR_OP_ASSOC_LEFT, JX9_OP_BXOR}, 
	/* Precedence 14, left-associative */
	{ {"|", sizeof(char)}, EXPR_OP_BOR, 14, EXPR_OP_ASSOC_LEFT, JX9_OP_BOR}, 
	/* Precedence 15, left-associative */
	{ {"&&", sizeof(char)*2}, EXPR_OP_LAND, 15, EXPR_OP_ASSOC_LEFT, JX9_OP_LAND}, 
	/* Precedence 16, left-associative */
	{ {"||", sizeof(char)*2}, EXPR_OP_LOR, 16, EXPR_OP_ASSOC_LEFT, JX9_OP_LOR}, 
	                      /* Ternary operator */
	/* Precedence 17, left-associative */
    { {"?", sizeof(char)}, EXPR_OP_QUESTY, 17, EXPR_OP_ASSOC_LEFT, 0}, 
	                     /* Combined binary operators */
	/* Precedence 18, right-associative */
	{ {"=", sizeof(char)},     EXPR_OP_ASSIGN,     18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_STORE}, 
	{ {"+=", sizeof(char)*2},  EXPR_OP_ADD_ASSIGN, 18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_ADD_STORE }, 
	{ {"-=", sizeof(char)*2},  EXPR_OP_SUB_ASSIGN, 18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_SUB_STORE }, 
	{ {".=", sizeof(char)*2},  EXPR_OP_DOT_ASSIGN, 18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_CAT_STORE }, 
	{ {"*=", sizeof(char)*2},  EXPR_OP_MUL_ASSIGN, 18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_MUL_STORE }, 
	{ {"/=", sizeof(char)*2},  EXPR_OP_DIV_ASSIGN, 18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_DIV_STORE }, 
	{ {"%=", sizeof(char)*2},  EXPR_OP_MOD_ASSIGN, 18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_MOD_STORE }, 
	{ {"&=", sizeof(char)*2},  EXPR_OP_AND_ASSIGN, 18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_BAND_STORE }, 
	{ {"|=", sizeof(char)*2},  EXPR_OP_OR_ASSIGN,  18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_BOR_STORE  }, 
	{ {"^=", sizeof(char)*2},  EXPR_OP_XOR_ASSIGN, 18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_BXOR_STORE }, 
	{ {"<<=", sizeof(char)*3}, EXPR_OP_SHL_ASSIGN, 18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_SHL_STORE }, 
	{ {">>=", sizeof(char)*3}, EXPR_OP_SHR_ASSIGN, 18,  EXPR_OP_ASSOC_RIGHT, JX9_OP_SHR_STORE },
		/* Precedence 22, left-associative [Lowest operator] */
	{ {",", sizeof(char)},  EXPR_OP_COMMA, 22, EXPR_OP_ASSOC_LEFT, 0}, /* IMP-0139-COMMA: Symisc eXtension */
};
/* Function call operator need special handling */
static const jx9_expr_op sFCallOp = {{"(", sizeof(char)}, EXPR_OP_FUNC_CALL, 2, EXPR_OP_ASSOC_LEFT , JX9_OP_CALL};
/*
 * Check if the given token is a potential operator or not.
 * This function is called by the lexer each time it extract a token that may 
 * look like an operator.
 * Return a structure [i.e: jx9_expr_op instnace ] that describe the operator on success.
 * Otherwise NULL.
 * Note that the function take care of handling ambiguity [i.e: whether we are dealing with
 * a binary minus or unary minus.]
 */
JX9_PRIVATE const jx9_expr_op *  jx9ExprExtractOperator(SyString *pStr, SyToken *pLast)
{
	sxu32 n = 0;
	sxi32 rc;
	/* Do a linear lookup on the operators table */
	for(;;){
		if( n >= SX_ARRAYSIZE(aOpTable) ){
			break;
		}
		rc = SyStringCmp(pStr, &aOpTable[n].sOp, SyMemcmp);		
		if( rc == 0 ){
			if( aOpTable[n].sOp.nByte != sizeof(char) || (aOpTable[n].iOp != EXPR_OP_UMINUS && aOpTable[n].iOp != EXPR_OP_UPLUS) || pLast == 0 ){
				if( aOpTable[n].iOp == EXPR_OP_SUBSCRIPT && (pLast == 0 || (pLast->nType & (JX9_TK_ID|JX9_TK_CSB/*]*/|JX9_TK_RPAREN/*)*/)) == 0) ){
					/* JSON Array not subscripting, return NULL  */
					return 0;
				}
				/* There is no ambiguity here, simply return the first operator seen */
				return &aOpTable[n];
			}
			/* Handle ambiguity */
			if( pLast->nType & (JX9_TK_LPAREN/*'('*/|JX9_TK_OCB/*'{'*/|JX9_TK_OSB/*'['*/|JX9_TK_COLON/*:*/|JX9_TK_COMMA/*, '*/) ){
				/* Unary opertors have prcedence here over binary operators */
				return &aOpTable[n];
			}
			if( pLast->nType & JX9_TK_OP ){
				const jx9_expr_op *pOp = (const jx9_expr_op *)pLast->pUserData;
				/* Ticket 1433-31: Handle the '++', '--' operators case */
				if( pOp->iOp != EXPR_OP_INCR && pOp->iOp != EXPR_OP_DECR ){
					/* Unary opertors have prcedence here over binary operators */
					return &aOpTable[n];
				}
			
			}
		}
		++n; /* Next operator in the table */
	}
	/* No such operator */
	return 0;
}
/*
 * Delimit a set of token stream.
 * This function take care of handling the nesting level and stops when it hit
 * the end of the input or the ending token is found and the nesting level is zero.
 */
JX9_PRIVATE void jx9DelimitNestedTokens(SyToken *pIn,SyToken *pEnd,sxu32 nTokStart,sxu32 nTokEnd,SyToken **ppEnd)
{
	SyToken *pCur = pIn;
	sxi32 iNest = 1;
	for(;;){
		if( pCur >= pEnd ){
			break;
		}
		if( pCur->nType & nTokStart ){
			/* Increment nesting level */
			iNest++;
		}else if( pCur->nType & nTokEnd ){
			/* Decrement nesting level */
			iNest--;
			if( iNest <= 0 ){
				break;
			}
		}
		/* Advance cursor */
		pCur++;
	}
	/* Point to the end of the chunk */
	*ppEnd = pCur;
}
/*
 * Retrun TRUE if the given ID represent a language construct [i.e: print, print..]. FALSE otherwise.
 * Note on reserved keywords.
 *  According to the JX9 language reference manual:
 *   These words have special meaning in JX9. Some of them represent things which look like 
 *   functions, some look like constants, and so on--but they're not, really: they are language
 *   constructs. You cannot use any of the following words as constants, object names, function
 *   or method names. Using them as variable names is generally OK, but could lead to confusion.
 */
JX9_PRIVATE int jx9IsLangConstruct(sxu32 nKeyID)
{
	if( nKeyID == JX9_TKWRD_PRINT || nKeyID == JX9_TKWRD_EXIT || nKeyID == JX9_TKWRD_DIE
		|| nKeyID == JX9_TKWRD_INCLUDE|| nKeyID == JX9_TKWRD_IMPORT ){
			return TRUE;
	}
	/* Not a language construct */
	return FALSE; 
}
/*
 * Point to the next expression that should be evaluated shortly.
 * The cursor stops when it hit a comma ', ' or a semi-colon and the nesting
 * level is zero.
 */
JX9_PRIVATE sxi32 jx9GetNextExpr(SyToken *pStart,SyToken *pEnd,SyToken **ppNext)
{
	SyToken *pCur = pStart;
	sxi32 iNest = 0;
	if( pCur >= pEnd || (pCur->nType & JX9_TK_SEMI/*';'*/) ){
		/* Last expression */
		return SXERR_EOF;
	}
	while( pCur < pEnd ){
		if( (pCur->nType & (JX9_TK_COMMA/*','*/|JX9_TK_SEMI/*';'*/)) && iNest <= 0){
			break;
		}
		if( pCur->nType & (JX9_TK_LPAREN/*'('*/|JX9_TK_OSB/*'['*/|JX9_TK_OCB/*'{'*/) ){
			iNest++;
		}else if( pCur->nType & (JX9_TK_RPAREN/*')'*/|JX9_TK_CSB/*']'*/|JX9_TK_CCB/*'}*/) ){
			iNest--;
		}
		pCur++;
	}
	*ppNext = pCur;
	return SXRET_OK;
}
/*
 * Collect and assemble tokens holding annonymous functions/closure body.
 * When errors, JX9 take care of generating the appropriate error message.
 * Note on annonymous functions.
 *  According to the JX9 language reference manual:
 *  Anonymous functions, also known as closures, allow the creation of functions
 *  which have no specified name. They are most useful as the value of callback
 *  parameters, but they have many other uses. 
 *  Closures may also inherit variables from the parent scope. Any such variables
 *  must be declared in the function header. Inheriting variables from the parent
 *  scope is not the same as using global variables. Global variables exist in the global scope
 *  which is the same no matter what function is executing. The parent scope of a closure is the 
 *  function in which the closure was declared (not necessarily the function it was called from).
 *
 * Some example:
 *  $greet = function($name)
 * {
 *   printf("Hello %s\r\n", $name);
 * };
 *  $greet('World');
 *  $greet('JX9');
 *
 * $double = function($a) {
 *   return $a * 2;
 * };
 * // This is our range of numbers
 * $numbers = range(1, 5);
 * // Use the Annonymous function as a callback here to 
 * // double the size of each element in our 
 * // range
 * $new_numbers = array_map($double, $numbers);
 * print implode(' ', $new_numbers);
 */
static sxi32 ExprAssembleAnnon(jx9_gen_state *pGen,SyToken **ppCur, SyToken *pEnd)
{
	SyToken *pIn = *ppCur;
	sxu32 nLine;
	sxi32 rc;
	/* Jump the 'function' keyword */
	nLine = pIn->nLine;
	pIn++;
	if( pIn < pEnd && (pIn->nType & (JX9_TK_ID|JX9_TK_KEYWORD)) ){
		pIn++;
	}
	if( pIn >= pEnd || (pIn->nType & JX9_TK_LPAREN) == 0 ){
		/* Syntax error */
		rc = jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Missing opening parenthesis '(' while declaring annonymous function");
		if( rc != SXERR_ABORT ){
			rc = SXERR_SYNTAX;
		}
		goto Synchronize;
	}
	pIn++; /* Jump the leading parenthesis '(' */
	jx9DelimitNestedTokens(pIn, pEnd, JX9_TK_LPAREN/*'('*/, JX9_TK_RPAREN/*')'*/, &pIn);
	if( pIn >= pEnd || &pIn[1] >= pEnd ){
		/* Syntax error */
		rc = jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Syntax error while declaring annonymous function");
		if( rc != SXERR_ABORT ){
			rc = SXERR_SYNTAX;
		}
		goto Synchronize;
	}
	pIn++; /* Jump the trailing parenthesis */
	if( pIn->nType & JX9_TK_OCB /*'{'*/ ){
		pIn++; /* Jump the leading curly '{' */
		jx9DelimitNestedTokens(pIn, pEnd, JX9_TK_OCB/*'{'*/, JX9_TK_CCB/*'}'*/, &pIn);
		if( pIn < pEnd ){
			pIn++;
		}
	}else{
		/* Syntax error */
		rc = jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Syntax error while declaring annonymous function, missing '{'");
		if( rc == SXERR_ABORT ){
			return SXERR_ABORT;
		}			
	}
	rc = SXRET_OK;
Synchronize:
	/* Synchronize pointers */
	*ppCur = pIn;
	return rc;
}
/*
 * Make sure we are dealing with a valid expression tree.
 * This function check for balanced parenthesis, braces, brackets and so on.
 * When errors, JX9 take care of generating the appropriate error message.
 * Return SXRET_OK on success. Any other return value indicates syntax error.
 */
static sxi32 ExprVerifyNodes(jx9_gen_state *pGen, jx9_expr_node **apNode, sxi32 nNode)
{
	sxi32 iParen, iSquare, iBraces;
	sxi32 i, rc;

	if( nNode > 0 && apNode[0]->pOp && (apNode[0]->pOp->iOp == EXPR_OP_ADD || apNode[0]->pOp->iOp == EXPR_OP_SUB) ){
		/* Fix and mark as an unary not binary plus/minus operator */
		apNode[0]->pOp = jx9ExprExtractOperator(&apNode[0]->pStart->sData, 0);
		apNode[0]->pStart->pUserData = (void *)apNode[0]->pOp;
	}
	iParen = iSquare = iBraces = 0;
	for( i = 0 ; i < nNode ; ++i ){
		if( apNode[i]->pStart->nType & JX9_TK_LPAREN /*'('*/){
			if( i > 0 && ( apNode[i-1]->xCode == jx9CompileVariable || apNode[i-1]->xCode == jx9CompileLiteral ||
				(apNode[i - 1]->pStart->nType & (JX9_TK_ID|JX9_TK_KEYWORD|JX9_TK_SSTR|JX9_TK_DSTR|JX9_TK_RPAREN/*')'*/|JX9_TK_CSB/*]*/))) ){
					/* Ticket 1433-033: Take care to ignore alpha-stream [i.e: or, xor] operators followed by an opening parenthesis */
					if( (apNode[i - 1]->pStart->nType & JX9_TK_OP) == 0 ){
						/* We are dealing with a postfix [i.e: function call]  operator
						 * not a simple left parenthesis. Mark the node.
						 */
						apNode[i]->pStart->nType |= JX9_TK_OP;
						apNode[i]->pStart->pUserData = (void *)&sFCallOp; /* Function call operator */
						apNode[i]->pOp = &sFCallOp;
					}
			}
			iParen++;
		}else if( apNode[i]->pStart->nType & JX9_TK_RPAREN/*')*/){
			if( iParen <= 0 ){
				rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[i]->pStart->nLine, "Syntax error: Unexpected token ')'");
				if( rc != SXERR_ABORT ){
					rc = SXERR_SYNTAX;
				}
				return rc;
			}
			iParen--;
		}else if( apNode[i]->pStart->nType & JX9_TK_OSB /*'['*/ && apNode[i]->xCode == 0 ){
			iSquare++;
		}else if (apNode[i]->pStart->nType & JX9_TK_CSB /*']'*/){
			if( iSquare <= 0 ){
				rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[i]->pStart->nLine, "Syntax error: Unexpected token ']'");
				if( rc != SXERR_ABORT ){
					rc = SXERR_SYNTAX;
				}
				return rc;
			}
			iSquare--;
		}else if( apNode[i]->pStart->nType & JX9_TK_OCB /*'{'*/ && apNode[i]->xCode == 0 ){
			iBraces++;
		}else if (apNode[i]->pStart->nType & JX9_TK_CCB /*'}'*/){
			if( iBraces <= 0 ){
				rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[i]->pStart->nLine, "Syntax error: Unexpected token '}'");
				if( rc != SXERR_ABORT ){
					rc = SXERR_SYNTAX;
				}
				return rc;
			}
			iBraces--;
		}else if( apNode[i]->pStart->nType & JX9_TK_OP ){
			const jx9_expr_op *pOp = (const jx9_expr_op *)apNode[i]->pOp;
			if( i > 0 && (pOp->iOp == EXPR_OP_UMINUS || pOp->iOp == EXPR_OP_UPLUS)){
				if( apNode[i-1]->xCode == jx9CompileVariable || apNode[i-1]->xCode == jx9CompileLiteral ){
					sxi32 iExprOp = EXPR_OP_SUB; /* Binary minus */
					sxu32 n = 0;
					if( pOp->iOp == EXPR_OP_UPLUS ){
						iExprOp = EXPR_OP_ADD; /* Binary plus */
					}
					/*
					 * TICKET 1433-013: This is a fix around an obscure bug when the user uses
					 * a variable name which is an alpha-stream operator [i.e: $and, $xor, $eq..].
					 */
					while( n < SX_ARRAYSIZE(aOpTable) && aOpTable[n].iOp != iExprOp ){
						++n;
					}
					pOp = &aOpTable[n];
					/* Mark as binary '+' or '-', not an unary */
					apNode[i]->pOp = pOp;
					apNode[i]->pStart->pUserData = (void *)pOp;
				}
			}
		}
	}
	if( iParen != 0 || iSquare != 0 || iBraces != 0){
		rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[0]->pStart->nLine, "Syntax error, mismatched '(', '[' or '{'");
		if( rc != SXERR_ABORT ){
			rc = SXERR_SYNTAX;
		}
		return rc;
	}
	return SXRET_OK;
}
/*
 * Extract a single expression node from the input.
 * On success store the freshly extractd node in ppNode.
 * When errors, JX9 take care of generating the appropriate error message.
 * An expression node can be a variable [i.e: $var], an operator [i.e: ++] 
 * an annonymous function [i.e: function(){ return "Hello"; }, a double/single
 * quoted string, a heredoc/nowdoc, a literal [i.e: JX9_EOL], a namespace path
 * [i.e: namespaces\path\to..], a array/list [i.e: array(4, 5, 6)] and so on.
 */
static sxi32 ExprExtractNode(jx9_gen_state *pGen, jx9_expr_node **ppNode)
{
	jx9_expr_node *pNode;
	SyToken *pCur;
	sxi32 rc;
	/* Allocate a new node */
	pNode = (jx9_expr_node *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(jx9_expr_node));
	if( pNode == 0 ){
		/* If the supplied memory subsystem is so sick that we are unable to allocate
		 * a tiny chunk of memory, there is no much we can do here.
		 */
		return SXERR_MEM;
	}
	/* Zero the structure */
	SyZero(pNode, sizeof(jx9_expr_node));
	SySetInit(&pNode->aNodeArgs, &pGen->pVm->sAllocator, sizeof(jx9_expr_node **));
	/* Point to the head of the token stream */
	pCur = pNode->pStart = pGen->pIn;
	/* Start collecting tokens */
	if( pCur->nType & JX9_TK_OP ){
		/* Point to the instance that describe this operator */
		pNode->pOp = (const jx9_expr_op *)pCur->pUserData;
		/* Advance the stream cursor */
		pCur++;
	}else if( pCur->nType & JX9_TK_DOLLAR ){
		/* Isolate variable */
		pCur++; /* Jump the dollar sign */
		if( pCur >= pGen->pEnd ){
			/* Syntax error */
			rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,"Invalid variable name");
			if( rc != SXERR_ABORT ){
				rc = SXERR_SYNTAX;
			}
			SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
			return rc;
		}
		pCur++; /* Jump the variable name */
		pNode->xCode = jx9CompileVariable;
	}else if( pCur->nType & JX9_TK_OCB /* '{' */ ){
		/* JSON Object, assemble tokens */
		pCur++;
		jx9DelimitNestedTokens(pCur, pGen->pEnd, JX9_TK_OCB /* '[' */, JX9_TK_CCB /* ']' */, &pCur);
		if( pCur < pGen->pEnd ){
			pCur++;
		}else{
			/* Syntax error */
			rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,"JSON Object: Missing closing braces '}'");
			if( rc != SXERR_ABORT ){
				rc = SXERR_SYNTAX;
			}
			SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
			return rc;
		}
		pNode->xCode = jx9CompileJsonObject;
	}else if( pCur->nType & JX9_TK_OSB /* '[' */ && !(pCur->nType & JX9_TK_OP) ){
		/* JSON Array, assemble tokens */
		pCur++;
		jx9DelimitNestedTokens(pCur, pGen->pEnd, JX9_TK_OSB /* '[' */, JX9_TK_CSB /* ']' */, &pCur);
		if( pCur < pGen->pEnd ){
			pCur++;
		}else{
			/* Syntax error */
			rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,"JSON Array: Missing closing square bracket ']'");
			if( rc != SXERR_ABORT ){
				rc = SXERR_SYNTAX;
			}
			SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
			return rc;
		}
		pNode->xCode = jx9CompileJsonArray;
	}else if( pCur->nType & JX9_TK_KEYWORD ){
		 int nKeyword = SX_PTR_TO_INT(pCur->pUserData);
		 if( nKeyword == JX9_TKWRD_FUNCTION ){
			 /* Annonymous function */
			  if( &pCur[1] >= pGen->pEnd ){
				 /* Assume a literal */
				pCur++;
				pNode->xCode = jx9CompileLiteral;
			 }else{
				 /* Assemble annonymous functions body */
				 rc = ExprAssembleAnnon(&(*pGen), &pCur, pGen->pEnd);
				 if( rc != SXRET_OK ){
					 SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
					 return rc; 
				 }
				 pNode->xCode = jx9CompileAnnonFunc;
			  }
		 }else if( jx9IsLangConstruct(nKeyword) && &pCur[1] < pGen->pEnd ){
			 /* Language constructs [i.e: print,die...] require special handling */
			 jx9DelimitNestedTokens(pCur, pGen->pEnd, JX9_TK_LPAREN|JX9_TK_OCB|JX9_TK_OSB, JX9_TK_RPAREN|JX9_TK_CCB|JX9_TK_CSB, &pCur);
			 pNode->xCode = jx9CompileLangConstruct;
		 }else{
			 /* Assume a literal */
			 pCur++;
			 pNode->xCode = jx9CompileLiteral;
		 }
	 }else if( pCur->nType & (JX9_TK_ID) ){
		 /* Constants, function name, namespace path, object name... */
		 pCur++;
		 pNode->xCode = jx9CompileLiteral;
	 }else{
		 if( (pCur->nType & (JX9_TK_LPAREN|JX9_TK_RPAREN|JX9_TK_COMMA|JX9_TK_CSB|JX9_TK_OCB|JX9_TK_CCB|JX9_TK_COLON)) == 0 ){
			 /* Point to the code generator routine */
			 pNode->xCode = jx9GetNodeHandler(pCur->nType);
			 if( pNode->xCode == 0 ){
				 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "Syntax error: Unexpected token '%z'", &pNode->pStart->sData);
				 if( rc != SXERR_ABORT ){
					 rc = SXERR_SYNTAX;
				 }
				 SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
				 return rc;
			 }
		 }
		/* Advance the stream cursor */
		pCur++;
	 }
	/* Point to the end of the token stream */
	pNode->pEnd = pCur;
	/* Save the node for later processing */
	*ppNode = pNode;
	/* Synchronize cursors */
	pGen->pIn = pCur;
	return SXRET_OK;
}
/*
 * Free an expression tree.
 */
static void ExprFreeTree(jx9_gen_state *pGen, jx9_expr_node *pNode)
{
	if( pNode->pLeft ){
		/* Release the left tree */
		ExprFreeTree(&(*pGen), pNode->pLeft);
	}
	if( pNode->pRight ){
		/* Release the right tree */
		ExprFreeTree(&(*pGen), pNode->pRight);
	}
	if( pNode->pCond ){
		/* Release the conditional tree used by the ternary operator */
		ExprFreeTree(&(*pGen), pNode->pCond);
	}
	if( SySetUsed(&pNode->aNodeArgs) > 0 ){
		jx9_expr_node **apArg;
		sxu32 n;
		/* Release node arguments */
		apArg = (jx9_expr_node **)SySetBasePtr(&pNode->aNodeArgs);
		for( n = 0 ; n < SySetUsed(&pNode->aNodeArgs) ; ++n ){
			ExprFreeTree(&(*pGen), apArg[n]);
		}
		SySetRelease(&pNode->aNodeArgs);
	}
	/* Finally, release this node */
	SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
}
/*
 * Free an expression tree.
 * This function is a wrapper around ExprFreeTree() defined above.
 */
JX9_PRIVATE sxi32 jx9ExprFreeTree(jx9_gen_state *pGen, SySet *pNodeSet)
{
	jx9_expr_node **apNode;
	sxu32 n;
	apNode = (jx9_expr_node **)SySetBasePtr(pNodeSet);
	for( n = 0  ; n < SySetUsed(pNodeSet) ; ++n ){
		if( apNode[n] ){
			ExprFreeTree(&(*pGen), apNode[n]);
		}
	}
	return SXRET_OK;
}
/*
 * Check if the given node is a modifialbe l/r-value.
 * Return TRUE if modifiable.FALSE otherwise.
 */
static int ExprIsModifiableValue(jx9_expr_node *pNode)
{
	sxi32 iExprOp;
	if( pNode->pOp == 0 ){
		return pNode->xCode == jx9CompileVariable ? TRUE : FALSE;
	}
	iExprOp = pNode->pOp->iOp;
	if( iExprOp == EXPR_OP_DOT /*'.' */  ){
			return TRUE;
	}
	if( iExprOp == EXPR_OP_SUBSCRIPT/*'[]'*/ ){
		if( pNode->pLeft->pOp ) {
			if( pNode->pLeft->pOp->iOp != EXPR_OP_SUBSCRIPT /*'['*/ && pNode->pLeft->pOp->iOp != EXPR_OP_DOT /*'.'*/){
				return FALSE;
			}
		}else if( pNode->pLeft->xCode != jx9CompileVariable ){
			return FALSE;
		}
		return TRUE;
	}
	/* Not a modifiable l or r-value */
	return FALSE;
}
/* Forward declaration */
static sxi32 ExprMakeTree(jx9_gen_state *pGen, jx9_expr_node **apNode, sxi32 nToken);
/* Macro to check if the given node is a terminal */
#define NODE_ISTERM(NODE) (apNode[NODE] && (!apNode[NODE]->pOp || apNode[NODE]->pLeft ))
/*
 * Buid an expression tree for each given function argument.
 * When errors, JX9 take care of generating the appropriate error message.
 */
static sxi32 ExprProcessFuncArguments(jx9_gen_state *pGen, jx9_expr_node *pOp, jx9_expr_node **apNode, sxi32 nToken)
{
	sxi32 iNest, iCur, iNode;
	sxi32 rc;
	/* Process function arguments from left to right */
	iCur = 0;
	for(;;){
		if( iCur >= nToken ){
			/* No more arguments to process */
			break;
		}
		iNode = iCur;
		iNest = 0;
		while( iCur < nToken ){
			if( apNode[iCur] ){
				if( (apNode[iCur]->pStart->nType & JX9_TK_COMMA) && apNode[iCur]->pLeft == 0 && iNest <= 0 ){
					break;
				}else if( apNode[iCur]->pStart->nType & (JX9_TK_LPAREN|JX9_TK_OSB|JX9_TK_OCB) ){
					iNest++;
				}else if( apNode[iCur]->pStart->nType & (JX9_TK_RPAREN|JX9_TK_CCB|JX9_TK_CSB) ){
					iNest--;
				}
			}
			iCur++;
		}
		if( iCur > iNode ){
			ExprMakeTree(&(*pGen), &apNode[iNode], iCur-iNode);
			if( apNode[iNode] ){
				/* Put a pointer to the root of the tree in the arguments set */
				SySetPut(&pOp->aNodeArgs, (const void *)&apNode[iNode]);
			}else{
				/* Empty function argument */
				rc = jx9GenCompileError(&(*pGen), E_ERROR, pOp->pStart->nLine, "Empty function argument");
				if( rc != SXERR_ABORT ){
					rc = SXERR_SYNTAX;
				}
				return rc;
			}
		}else{
			rc = jx9GenCompileError(&(*pGen), E_ERROR, pOp->pStart->nLine, "Missing function argument");
			if( rc != SXERR_ABORT ){
				rc = SXERR_SYNTAX;
			}
			return rc;
		}
		/* Jump trailing comma */
		if( iCur < nToken && apNode[iCur] && (apNode[iCur]->pStart->nType & JX9_TK_COMMA) ){
			iCur++;
			if( iCur >= nToken ){
				/* missing function argument */
				rc = jx9GenCompileError(&(*pGen), E_ERROR, pOp->pStart->nLine, "Missing function argument");
				if( rc != SXERR_ABORT ){
					rc = SXERR_SYNTAX;
				}
				return rc;
			}
		}
	}
	return SXRET_OK;
}
/*
  * Create an expression tree from an array of tokens.
  * If successful, the root of the tree is stored in apNode[0].
  * When errors, JX9 take care of generating the appropriate error message.
  */
 static sxi32 ExprMakeTree(jx9_gen_state *pGen, jx9_expr_node **apNode, sxi32 nToken)
 {
	 sxi32 i, iLeft, iRight;
	 jx9_expr_node *pNode;
	 sxi32 iCur;
	 sxi32 rc;
	 if( nToken <= 0 || (nToken == 1 && apNode[0]->xCode) ){
		 /* TICKET 1433-17: self evaluating node */
		 return SXRET_OK;
	 }
	 /* Process expressions enclosed in parenthesis first */
	 for( iCur =  0 ; iCur < nToken ; ++iCur ){
		 sxi32 iNest;
		 /* Note that, we use strict comparison here '!=' instead of the bitwise and '&' operator
		  * since the LPAREN token can also be an operator [i.e: Function call].
		  */
		 if( apNode[iCur] == 0 || apNode[iCur]->pStart->nType != JX9_TK_LPAREN ){
			 continue;
		 }
		 iNest = 1;
		 iLeft = iCur;
		 /* Find the closing parenthesis */
		 iCur++;
		 while( iCur < nToken ){
			 if( apNode[iCur] ){
				 if( apNode[iCur]->pStart->nType & JX9_TK_RPAREN /* ')' */){
					 /* Decrement nesting level */
					 iNest--;
					 if( iNest <= 0 ){
						 break;
					 }
				 }else if( apNode[iCur]->pStart->nType & JX9_TK_LPAREN /* '(' */ ){
					 /* Increment nesting level */
					 iNest++;
				 }
			 }
			 iCur++;
		 }
		 if( iCur - iLeft > 1 ){
			 /* Recurse and process this expression */
			 rc = ExprMakeTree(&(*pGen), &apNode[iLeft + 1], iCur - iLeft - 1);
			 if( rc != SXRET_OK ){
				 return rc;
			 }
		 }
		 /* Free the left and right nodes */
		 ExprFreeTree(&(*pGen), apNode[iLeft]);
		 ExprFreeTree(&(*pGen), apNode[iCur]);
		 apNode[iLeft] = 0;
		 apNode[iCur] = 0;
	 }
	 /* Handle postfix [i.e: function call, member access] operators with precedence 2 */
	 iLeft = -1;
	 for( iCur = 0 ; iCur < nToken ; ++iCur ){
		 if( apNode[iCur] == 0 ){
			 continue;
		 }
		 pNode = apNode[iCur];
		 if( pNode->pOp && pNode->pOp->iPrec == 2 && pNode->pLeft == 0  ){
			 if( pNode->pOp->iOp == EXPR_OP_FUNC_CALL ){
				 /* Collect function arguments */
				 sxi32 iPtr = 0;
				 sxi32 nFuncTok = 0;
				 while( nFuncTok + iCur < nToken ){
					 if( apNode[nFuncTok+iCur] ){
						 if( apNode[nFuncTok+iCur]->pStart->nType & JX9_TK_LPAREN /*'('*/ ){
							 iPtr++;
						 }else if ( apNode[nFuncTok+iCur]->pStart->nType & JX9_TK_RPAREN /*')'*/){
							 iPtr--;
							 if( iPtr <= 0 ){
								 break;
							 }
						 }
					 }
					 nFuncTok++;
				 }
				 if( nFuncTok + iCur >= nToken ){
					 /* Syntax error */
					 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "Missing right parenthesis ')'");
					 if( rc != SXERR_ABORT ){
						 rc = SXERR_SYNTAX;
					 }
					 return rc; 
				 }
				 if(  iLeft < 0 || !NODE_ISTERM(iLeft) /*|| ( apNode[iLeft]->pOp && apNode[iLeft]->pOp->iPrec != 2)*/ ){
					 /* Syntax error */
					 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "Invalid function name");
					 if( rc != SXERR_ABORT ){
						 rc = SXERR_SYNTAX;
					 }
					 return rc;
				 }
				 if( nFuncTok > 1 ){
					 /* Process function arguments */
					 rc = ExprProcessFuncArguments(&(*pGen), pNode, &apNode[iCur+1], nFuncTok-1);
					 if( rc != SXRET_OK ){
						 return rc;
					 }
				 }
				 /* Link the node to the tree */
				 pNode->pLeft = apNode[iLeft];
				 apNode[iLeft] = 0;
				 for( iPtr = 1; iPtr <= nFuncTok ; iPtr++ ){
					 apNode[iCur+iPtr] = 0;
				 }
			 }else if (pNode->pOp->iOp == EXPR_OP_SUBSCRIPT ){
				 /* Subscripting */
				 sxi32 iArrTok = iCur + 1;
				 sxi32 iNest = 1;
				 if(  iLeft >= 0 && (apNode[iLeft]->xCode == jx9CompileVariable || (apNode[iLeft]->pOp && apNode[iLeft]->pOp->iPrec == 2 /* postfix */) ) ){
					 /* Collect index tokens */
				    while( iArrTok < nToken ){
					 if( apNode[iArrTok] ){
						 if( apNode[iArrTok]->pStart->nType & JX9_TK_OSB /*'['*/){
							 /* Increment nesting level */
							 iNest++;
						 }else if( apNode[iArrTok]->pStart->nType & JX9_TK_CSB /*']'*/){
							 /* Decrement nesting level */
							 iNest--;
							 if( iNest <= 0 ){
								 break;
							 }
						 }
					 }
					 ++iArrTok;
				   }
				   if( iArrTok > iCur + 1 ){
					 /* Recurse and process this expression */
					 rc = ExprMakeTree(&(*pGen), &apNode[iCur+1], iArrTok - iCur - 1);
					 if( rc != SXRET_OK ){
						 return rc;
					 }
					 /* Link the node to it's index */
					 SySetPut(&pNode->aNodeArgs, (const void *)&apNode[iCur+1]);
				   }
				   /* Link the node to the tree */
				   pNode->pLeft = apNode[iLeft];
				   pNode->pRight = 0;
				   apNode[iLeft] = 0;
				   for( iNest = iCur + 1 ; iNest <= iArrTok ; ++iNest ){
					 apNode[iNest] = 0;
				  }
				 }
			 }else{
				 /* Member access operators [i.e: '.' ] */
				 iRight = iCur + 1;
				 while( iRight < nToken && apNode[iRight] == 0 ){
					 iRight++;
				 }
				 if( iRight >= nToken || iLeft < 0 || !NODE_ISTERM(iRight) || !NODE_ISTERM(iLeft) ){
					 /* Syntax error */
					 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing/Invalid member name", &pNode->pOp->sOp);
					 if( rc != SXERR_ABORT ){
						 rc = SXERR_SYNTAX;
					 }
					 return rc;
				 }
				 /* Link the node to the tree */
				 pNode->pLeft = apNode[iLeft];
				 if( pNode->pLeft->pOp == 0 && pNode->pLeft->xCode != jx9CompileVariable ){
					 /* Syntax error */
					 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, 
						 "'%z': Expecting a variable as left operand", &pNode->pOp->sOp);
					 if( rc != SXERR_ABORT ){
						 rc = SXERR_SYNTAX;
					 }
					 return rc;
				 }
				 pNode->pRight = apNode[iRight];
				 apNode[iLeft] = apNode[iRight] = 0;
			 }
		 }
		 iLeft = iCur;
	 }
	  /* Handle post/pre icrement/decrement [i.e: ++/--] operators with precedence 3 */
	 iLeft = -1;
	 for( iCur = 0 ; iCur < nToken ; ++iCur ){
		 if( apNode[iCur] == 0 ){
			 continue;
		 }
		 pNode = apNode[iCur];
		 if( pNode->pOp && pNode->pOp->iPrec == 3 && pNode->pLeft == 0){
			 if( iLeft >= 0 && ((apNode[iLeft]->pOp && apNode[iLeft]->pOp->iPrec == 2 /* Postfix */)
				 || apNode[iLeft]->xCode == jx9CompileVariable) ){
					 /* Link the node to the tree */
					 pNode->pLeft = apNode[iLeft];
					 apNode[iLeft] = 0; 
			 }
		  }
		 iLeft = iCur;
	  }
	 iLeft = -1;
	 for( iCur = nToken -  1 ; iCur >= 0 ; iCur-- ){
		 if( apNode[iCur] == 0 ){
			 continue;
		 }
		 pNode = apNode[iCur];
		 if( pNode->pOp && pNode->pOp->iPrec == 3 && pNode->pLeft == 0){
			 if( iLeft < 0 || (apNode[iLeft]->pOp == 0 && apNode[iLeft]->xCode != jx9CompileVariable)
				 || ( apNode[iLeft]->pOp && apNode[iLeft]->pOp->iPrec != 2 /* Postfix */) ){
					 /* Syntax error */
					 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z' operator needs l-value", &pNode->pOp->sOp);
					 if( rc != SXERR_ABORT ){
						 rc = SXERR_SYNTAX;
					 }
					 return rc;
			 }
			 /* Link the node to the tree */
			 pNode->pLeft = apNode[iLeft];
			 apNode[iLeft] = 0;
			 /* Mark as pre-increment/decrement node */
			 pNode->iFlags |= EXPR_NODE_PRE_INCR;
		  }
		 iLeft = iCur;
	 }
	 /* Handle right associative unary and cast operators [i.e: !, (string), ~...]  with precedence 4 */
	  iLeft = 0;
	  for( iCur = nToken -  1 ; iCur >= 0 ; iCur-- ){
		  if( apNode[iCur] ){
			  pNode = apNode[iCur];
			  if( pNode->pOp && pNode->pOp->iPrec == 4 && pNode->pLeft == 0){
				  if( iLeft > 0 ){
					  /* Link the node to the tree */
					  pNode->pLeft = apNode[iLeft];
					  apNode[iLeft] = 0;
					  if( pNode->pLeft && pNode->pLeft->pOp && pNode->pLeft->pOp->iPrec > 4 ){
						  if( pNode->pLeft->pLeft == 0 || pNode->pLeft->pRight == 0 ){
							   /* Syntax error */
							  rc = jx9GenCompileError(pGen, E_ERROR, pNode->pLeft->pStart->nLine, "'%z': Missing operand", &pNode->pLeft->pOp->sOp);
							  if( rc != SXERR_ABORT ){
								  rc = SXERR_SYNTAX;
							  }
							  return rc;
						  }
					  }
				  }else{
					  /* Syntax error */
					  rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing operand", &pNode->pOp->sOp);
					  if( rc != SXERR_ABORT ){
						  rc = SXERR_SYNTAX;
					  }
					  return rc;
				  }
			  }
			  /* Save terminal position */
			  iLeft = iCur;
		  }
	  }	 
	 /* Process left and non-associative binary operators [i.e: *, /, &&, ||...]*/
	 for( i = 7 ; i < 17 ; i++ ){
		 iLeft = -1;
		 for( iCur = 0 ; iCur < nToken ; ++iCur ){
			 if( apNode[iCur] == 0 ){
				 continue;
			 }
			 pNode = apNode[iCur];
			 if( pNode->pOp && pNode->pOp->iPrec == i && pNode->pLeft == 0 ){
				 /* Get the right node */
				 iRight = iCur + 1;
				 while( iRight < nToken && apNode[iRight] == 0 ){
					 iRight++;
				 }
				 if( iRight >= nToken || iLeft < 0 || !NODE_ISTERM(iRight) || !NODE_ISTERM(iLeft) ){
					 /* Syntax error */
					 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing/Invalid operand", &pNode->pOp->sOp);
					 if( rc != SXERR_ABORT ){
						 rc = SXERR_SYNTAX;
					 }
					 return rc; 
				 }
				 /* Link the node to the tree */
				 pNode->pLeft = apNode[iLeft];
				 pNode->pRight = apNode[iRight];
				 apNode[iLeft] = apNode[iRight] = 0;
			 }
			 iLeft = iCur;
		 }
	 }
	 /* Handle the ternary operator. (expr1) ? (expr2) : (expr3) 
	  * Note that we do not need a precedence loop here since
	  * we are dealing with a single operator.
	  */
	  iLeft = -1;
	  for( iCur = 0 ; iCur < nToken ; ++iCur ){
		  if( apNode[iCur] == 0 ){
			  continue;
		  }
		  pNode = apNode[iCur];
		  if( pNode->pOp && pNode->pOp->iOp == EXPR_OP_QUESTY && pNode->pLeft == 0 ){
			  sxi32 iNest = 1;
			  if( iLeft < 0 || !NODE_ISTERM(iLeft) ){
				  /* Missing condition */
				  rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Syntax error", &pNode->pOp->sOp);
				  if( rc != SXERR_ABORT ){
					  rc = SXERR_SYNTAX;
				  }
				  return rc;
			  }
			  /* Get the right node */
			  iRight = iCur + 1;
			  while( iRight < nToken  ){
				  if( apNode[iRight] ){
					  if( apNode[iRight]->pOp && apNode[iRight]->pOp->iOp == EXPR_OP_QUESTY && apNode[iRight]->pCond == 0){
						  /* Increment nesting level */
						  ++iNest;
					  }else if( apNode[iRight]->pStart->nType & JX9_TK_COLON /*:*/ ){
						  /* Decrement nesting level */
						  --iNest;
						  if( iNest <= 0 ){
							  break;
						  }
					  }
				  }
				  iRight++;
			  }
			  if( iRight > iCur + 1 ){
				  /* Recurse and process the then expression */
				  rc = ExprMakeTree(&(*pGen), &apNode[iCur + 1], iRight - iCur - 1);
				  if( rc != SXRET_OK ){
					  return rc;
				  }
				  /* Link the node to the tree */
				  pNode->pLeft = apNode[iCur + 1];
			  }else{
				  rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing 'then' expression", &pNode->pOp->sOp);
				  if( rc != SXERR_ABORT ){
					 rc = SXERR_SYNTAX;
				 }
				 return rc;
			  }
			  apNode[iCur + 1] = 0;
			  if( iRight + 1 < nToken ){
				  /* Recurse and process the else expression */
				  rc = ExprMakeTree(&(*pGen), &apNode[iRight + 1], nToken - iRight - 1);
				  if( rc != SXRET_OK ){
					  return rc;
				  }
				  /* Link the node to the tree */
				  pNode->pRight = apNode[iRight + 1];
				  apNode[iRight + 1] =  apNode[iRight] = 0;
			  }else{
				  rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing 'else' expression", &pNode->pOp->sOp);
				  if( rc != SXERR_ABORT ){
					 rc = SXERR_SYNTAX;
				 }
				 return rc;
			  }
			  /* Point to the condition */
			  pNode->pCond  = apNode[iLeft];
			  apNode[iLeft] = 0;
			  break;
		  }
		  iLeft = iCur;
	  }
	 /* Process right associative binary operators [i.e: '=', '+=', '/='] 
	  * Note: All right associative binary operators have precedence 18
	  * so there is no need for a precedence loop here.
	  */
	 iRight = -1;
	 for( iCur = nToken -  1 ; iCur >= 0 ; iCur--){
		 if( apNode[iCur] == 0 ){
			 continue;
		 }
		 pNode = apNode[iCur];
		 if( pNode->pOp && pNode->pOp->iPrec == 18 && pNode->pLeft == 0 ){
			 /* Get the left node */
			 iLeft = iCur - 1;
			 while( iLeft >= 0 && apNode[iLeft] == 0 ){
				 iLeft--;
			 }
			 if( iLeft < 0 || iRight < 0 || !NODE_ISTERM(iRight) || !NODE_ISTERM(iLeft) ){
				 /* Syntax error */
				 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing/Invalid operand", &pNode->pOp->sOp);
				 if( rc != SXERR_ABORT ){
					 rc = SXERR_SYNTAX;
				 }
				 return rc;
			 }
			 if( ExprIsModifiableValue(apNode[iLeft]) == FALSE ){
				 if( pNode->pOp->iVmOp != JX9_OP_STORE  ){
					 /* Left operand must be a modifiable l-value */
					 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, 
						 "'%z': Left operand must be a modifiable l-value", &pNode->pOp->sOp);
					 if( rc != SXERR_ABORT ){
						 rc = SXERR_SYNTAX;
					 }
					 return rc; 
				 }
			 }
			 /* Link the node to the tree (Reverse) */
			 pNode->pLeft = apNode[iRight];
			 pNode->pRight = apNode[iLeft];
			 apNode[iLeft] = apNode[iRight] = 0;
		 }
		 iRight = iCur;
	 }
	 /* Process the lowest precedence operator (22, comma) */
	 iLeft = -1;
	 for( iCur = 0 ; iCur < nToken ; ++iCur ){
		 if( apNode[iCur] == 0 ){
			 continue;
		 }
		 pNode = apNode[iCur];
		 if( pNode->pOp && pNode->pOp->iPrec == 22 /* ',' */ && pNode->pLeft == 0 ){
			 /* Get the right node */
			 iRight = iCur + 1;
			 while( iRight < nToken && apNode[iRight] == 0 ){
				 iRight++;
			 }
			 if( iRight >= nToken || iLeft < 0 || !NODE_ISTERM(iRight) || !NODE_ISTERM(iLeft) ){
				 /* Syntax error */
				 rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing/Invalid operand", &pNode->pOp->sOp);
				 if( rc != SXERR_ABORT ){
					 rc = SXERR_SYNTAX;
				 }
				 return rc;
			 }
			 /* Link the node to the tree */
			 pNode->pLeft = apNode[iLeft];
			 pNode->pRight = apNode[iRight];
			 apNode[iLeft] = apNode[iRight] = 0;
		 }
		 iLeft = iCur;
	 }
	 /* Point to the root of the expression tree */
	 for( iCur = 1 ; iCur < nToken ; ++iCur ){
		 if( apNode[iCur] ){
			 if( (apNode[iCur]->pOp || apNode[iCur]->xCode ) && apNode[0] != 0){
				 rc = jx9GenCompileError(pGen, E_ERROR, apNode[iCur]->pStart->nLine, "Unexpected token '%z'", &apNode[iCur]->pStart->sData);
				  if( rc != SXERR_ABORT ){
					  rc = SXERR_SYNTAX;
				  }
				  return rc;  
			 }
			 apNode[0] = apNode[iCur];
			 apNode[iCur] = 0;
		 }
	 }
	 return SXRET_OK;
 }
 /*
  * Build an expression tree from the freshly extracted raw tokens.
  * If successful, the root of the tree is stored in ppRoot.
  * When errors, JX9 take care of generating the appropriate error message.
  * This is the public interface used by the most code generator routines.
  */
JX9_PRIVATE sxi32 jx9ExprMakeTree(jx9_gen_state *pGen, SySet *pExprNode, jx9_expr_node **ppRoot)
{
	jx9_expr_node **apNode;
	jx9_expr_node *pNode;
	sxi32 rc;
	/* Reset node container */
	SySetReset(pExprNode);
	pNode = 0; /* Prevent compiler warning */
	/* Extract nodes one after one until we hit the end of the input */
	while( pGen->pIn < pGen->pEnd ){
		rc = ExprExtractNode(&(*pGen), &pNode);
		if( rc != SXRET_OK ){
			return rc;
		}
		/* Save the extracted node */
		SySetPut(pExprNode, (const void *)&pNode);
	}
	if( SySetUsed(pExprNode) < 1 ){
		/* Empty expression [i.e: A semi-colon;] */
		*ppRoot = 0;
		return SXRET_OK;
	}
	apNode = (jx9_expr_node **)SySetBasePtr(pExprNode);
	/* Make sure we are dealing with valid nodes */
	rc = ExprVerifyNodes(&(*pGen), apNode, (sxi32)SySetUsed(pExprNode));
	if( rc != SXRET_OK ){
		/* Don't worry about freeing memory, upper layer will
		 * cleanup the mess left behind.
		 */
		*ppRoot = 0;
		return rc;
	}
	/* Build the tree */
	rc = ExprMakeTree(&(*pGen), apNode, (sxi32)SySetUsed(pExprNode));
	if( rc != SXRET_OK ){
		/* Something goes wrong [i.e: Syntax error] */
		*ppRoot = 0;
		return rc;
	}
	/* Point to the root of the tree */
	*ppRoot = apNode[0];
	return SXRET_OK;
}
