| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050 | /*------------------------------------------------------------------------------ * NAME    : Evaluator.js * PURPOSE : Expression Evaluator * AUTHOR  : Prasad P. Khandekar * CREATED : August 21, 2005 Unary Minus = 0xAD *------------------------------------------------------------------------------ * Copyright (c) 2005. Khan Information Systems. All Rights Reserved * The contents of this file are subject to the KIS Public License 1.0 * (the "License"); you may not use this file except in compliance with the  * License. You should have received a copy of the KIS Public License along with  * this library; if not, please ask your software vendor to provide one. *  * YOU AGREE THAT THE PROGRAM IS PROVIDED AS-IS, WITHOUT WARRANTY OF ANY KIND * (EITHER EXPRESS OR IMPLIED) INCLUDING, WITHOUT LIMITATION, ANY IMPLIED  * WARRANTY OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND ANY  * WARRANTY OF NON INFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE  * PROGRAM, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * See the License for the specific language governing rights and limitations  * under the License. *-----------------------------------------------------------------------------*/var UNARY_NEG    = "";var ARG_TERMINAL = "Ø";var LESS_THAN    = "«";var GREATER_THAN = "»";var NOT_EQUAL    = "×";var DEBUG_ON     = false;var NUMARIC_OP   = "*,/,%,^";function Expression(pstrExp){	var strInFix = null;	var arrVars = null;    var arrTokens = null;    var arrPostFix = null;    var dtFormat = "dd/MM/yyyy";	this.DateFormat = SetDateFormat;	this.Expression = SetExpression;    this.Parse = ParseExpression;    this.Evaluate = EvaluateExpression;    this.AddVariable = AddNewVariable;    this.Reset = ClearAll;	function SetDateFormat(pstrFmt)	{	    dtFormat = pstrFmt;	}	function SetExpression(pstrExp)	{		strInFix = pstrExp;	}	function AddNewVariable(varName, varValue)	{	    if (arrVars == null || arrVars == undefined)	        arrVars = new Array();		arrVars[varName] = varValue;	}	function ClearAll()	{		arrVars = null;		strInFix = null;		arrTokens = null;		arrPostFix = null;	}	function ParseExpression()	{    	arrTokens = Tokanize(strInFix);    	if (arrTokens == null || arrTokens == undefined)    	    throw "Unable to tokanize the expression!";    	if (arrTokens.length <= 0)    	    throw "Unable to tokanize the expression!";    	arrPostFix = InFixToPostFix(arrTokens);    	if (arrPostFix == null || arrPostFix == undefined)    	    throw "Unable to convert the expression to postfix form!";    	if (arrPostFix.length <= 0)    	    throw "Unable to convert the expression to postfix form!";    	return arrPostFix.toString();	}	function getVariable(strVarName)	{	    var retVal;		debugAssert(strVarName);	    if (arrVars == null || arrVars == undefined)	        throw "Variable values are not supplied!";		retVal = arrVars[strVarName];        if (retVal == undefined || retVal == null)            throw "Variable [" + strVarName + "] not defined";        debugAssert(strVarName + " - " + retVal);        return retVal;	}	// postfix function evaluator	function EvaluateExpression()	{	    var intIndex;	    var myStack;	    var strTok, strOp;	    var objOp1, objOp2, objTmp1, objTmp2;	    var dblNo, dblVal1, dblVal2;	    var parrExp;	    if (arrPostFix == null || arrPostFix == undefined)	        ParseExpression();	    if (arrPostFix.length == 0)	        throw "Unable to parse the expression!";	    parrExp = arrPostFix;	    if (parrExp == null || parrExp == undefined)	    {	        throw "Invalid postfix expression!";	        return;	    }	    if (parrExp.length == 0)	    {	        throw "Invalid postfix expression!";	        return;	    }	    intIndex = 0;	    myStack  =  new Stack();	    while (intIndex < parrExp.length)	    {	        strTok = parrExp[intIndex];	        switch (strTok)	        {	            case ARG_TERMINAL :	                myStack.Push(strTok);	                break;	            case UNARY_NEG :	                if (myStack.IsEmpty())	                    throw "No operand to negate!";	                objOp1 = null;	                objOp2 = null;	                objOp1 = myStack.Pop();	                if (IsVariable(objOp1))	                    objOp1 = getVariable(objOp1);	                dblNo = ToNumber(objOp1);	                if (isNaN(dblNo))	                    throw "Not a numaric value!";	                else	                {	                    dblNo = (0 - dblNo);	                    myStack.Push(dblNo);	                }	                break;	            case "!" :	                if (myStack.IsEmpty())	                    throw "No operand on stack!";	                objOp1 = null;	                objOp2 = null;	                objOp1 = myStack.Pop();	                if (IsVariable(objOp1))	                    objOp1 = getVariable(objOp1);	                objOp1 = ToBoolean(objOp1);	                if (objOp1 == null)	                    throw "Not a boolean value!";	                else	                    myStack.Push(!objOp1);	                break;	            case "*" :	            case "/" :	            case "%" :	            case "^" :	                if (myStack.IsEmpty() || myStack.Size() < 2)	                    throw "Stack is empty, can not perform [" + strTok + "]";	                objOp1 = null;	                objOp2 = null;	                objTmp = null;	                objOp2 = myStack.Pop();	                objOp1 = myStack.Pop();	                if (IsVariable(objOp1))	                    objOp1 = getVariable(objOp1);	                if (IsVariable(objOp2))	                    objOp2 = getVariable(objOp2);	                dblVal1 = ToNumber(objOp1);	                dblVal2 = ToNumber(objOp2);	                if (isNaN(dblVal1) || isNaN(dblVal2))	                    throw "Either one of the operand is not a number can not perform [" +	                            strTok + "]";	                if (strTok == "^")	                    myStack.Push(Math.pow(dblVal1, dblVal2));	                else if (strTok == "*")	                    myStack.Push((dblVal1 * dblVal2));	                else if (strTok == "/")	                    myStack.Push((dblVal1 / dblVal2));	                else	                {	                    debugAssert (dblVal1 + " - " + dblVal2);	                    myStack.Push((dblVal1 % dblVal2));	                }	                break;	            case "+" :	            case "-" :	                if (myStack.IsEmpty() || myStack.Size() < 2)	                    throw "Stack is empty, can not perform [" + strTok + "]";	                objOp1 = null;	                objOp2 = null;	                objTmp1 = null;	                objTmp2 = null;	                strOp = ((strTok == "+") ? "Addition" : "Substraction");	                objOp2 = myStack.Pop();	                objOp1 = myStack.Pop();	                if (IsVariable(objOp1))	                    objOp1 = getVariable(objOp1);	                if (IsVariable(objOp2))	                    objOp2 = getVariable(objOp2);	                if (IsBoolean(objOp1) || IsBoolean(objOp2))	                    throw "Can not perform " + strOp + " with boolean values!";	                else if (isDate(objOp1, dtFormat) && isDate(objOp1, dtFormat))	                    throw strOp + " of two dates not supported!";	                else if (typeof(objOp1) == "object" || typeof(objOp1) == "object")	                    throw strOp + " of two objects not supported!";	                else if (typeof(objOp1) == "undefined" || typeof(objOp1) == "undefined")	                    throw strOp + " of two undefined not supported!";	                else if (IsNumber(objOp1) && IsNumber(objOp2))	                {	                    // Number addition	                    dblVal1 = ToNumber(objOp1);	                    dblVal2 = ToNumber(objOp2);	                    if (strTok == "+")	                        myStack.Push((dblVal1 + dblVal2));	                    else	                        myStack.Push((dblVal1 - dblVal2));	                }	                else	                {	                    if (strTok == "+")	                        myStack.Push((objOp1 + objOp2));	                    else	                        throw strOP + " not supported for strings!"	                }	                break;	            case "=" :	            case "<" :	            case ">" :	            case "<>" :	            case "<=" :	            case ">=" :	                if (myStack.IsEmpty() || myStack.Size() < 2)	                    throw "Stack is empty, can not perform [" + strTok + "]";	                objOp1  = null;	                objOp2  = null;	                objTmp1 = null;	                objTmp2 = null;	                objOp2  = myStack.Pop();	                objOp1  = myStack.Pop();	                if (IsVariable(objOp1))	                    objOp1 = getVariable(objOp1);	                if (IsVariable(objOp2))	                    objOp2 = getVariable(objOp2);	                if (IsNumber(objOp1) && IsNumber(objOp2))	                {	                    dblVal1 = ToNumber(objOp1);	                    dblVal2 = ToNumber(objOp2);	                    if (strTok == "=")	                        myStack.Push((dblVal1 == dblVal2));	                    else if (strTok == "<>")	                        myStack.Push((dblVal1 != dblVal2));	                    else if (strTok == ">")	                        myStack.Push((dblVal1 > dblVal2));	                    else if (strTok == "<")	                        myStack.Push((dblVal1 < dblVal2));	                    else if (strTok == "<=")	                        myStack.Push((dblVal1 <= dblVal2));	                    else if (strTok == ">=")	                        myStack.Push((dblVal1 >= dblVal2));	                }	                else if (IsBoolean(objOp1) && IsBoolean(objOp2) &&	                        (strTok == "=" || strTok == "<>"))	                {	                    objTmp1 = ToBoolean(objOp1);	                    objTmp2 = ToBoolean(objOp2);	                    if (strTok == "=")	                        myStack.Push((objTmp1 == objTmp2));	                    else if (strTok == "<>")	                        myStack.Push((objTmp1 != objTmp2));	                }	                else if (isDate(objOp1, dtFormat) &&	                            isDate(objOp2, dtFormat))	                {	                    if (typeof(objOp1) == "string")	                        objTmp1 = getDateFromFormat(objOp1, dtFormat);	                    else	                        objTmp1 = objOp1;	                    if (typeof(objOp1) == "string")	                        objTmp2 = getDateFromFormat(objOp2, dtFormat);	                    else	                        objTmp2 = objOp2;	                    if (strTok == "=")	                        myStack.Push((objTmp1 == objTmp2));	                    else if (strTok == "<>")	                        myStack.Push((objTmp1 != objTmp2));	                    else if (strTok == ">")	                        myStack.Push((objTmp1 > objTmp2));	                    else if (strTok == "<")	                        myStack.Push((objTmp1 < objTmp2));	                    else if (strTok == "<=")	                        myStack.Push((objTmp1 <= objTmp2));	                    else if (strTok == ">=")	                        myStack.Push((objTmp1 >= objTmp2));	                }	                else if ((typeof(objOp1) == "string" &&	                        typeof(objOp2) == "string") &&	                        (strTok == "=" || strTok == "<>"))	                {	                    if (strTok == "=")	                        myStack.Push((objOp1 == objOp2));	                    else if (strTok == "<>")	                        myStack.Push((objOp1 != objOp2));	                }	                else	                    throw "For " + strTok +	                            " operator LHS & RHS should be of same data type!";	                break;	            case "&" :	            case "|" :	                if (myStack.IsEmpty() || myStack.Size() < 2)	                    throw "Stack is empty, can not perform [" + strTok + "]";	                objOp1  = null;	                objOp2  = null;	                objTmp1 = null;	                objTmp2 = null;	                objOp2  = myStack.Pop();	                objOp1  = myStack.Pop();	                if (IsVariable(objOp1))	                    objOp1 = getVariable(objOp1);	                if (IsVariable(objOp2))	                    objOp2 = getVariable(objOp2);	                if (IsBoolean(objOp1) && IsBoolean(objOp2))	                {	                    objTmp1 = ToBoolean(objOp1);	                    objTmp2 = ToBoolean(objOp2);	                    if (strTok == "&")	                        myStack.Push((objTmp1 && objTmp2));	                    else if (strTok == "|")	                        myStack.Push((objTmp1 || objTmp2));	                }	                else	                    throw "Logical operator requires LHS & RHS of boolean type!";	                break;	            default :	                // Handle functions and operands	                if (IsNumber(strTok) || IsBoolean(strTok) ||	                    isDate(strTok, dtFormat) || typeof(strTok) == "number"	                    || typeof(strTok) == "boolean" || typeof(strTok) == "object"	                    || IsVariable(strTok))	                {	                    myStack.Push(strTok);	                    break;	                }	                else	                    HandleFunctions(strTok, myStack, dtFormat, arrVars);	        }	        intIndex++;	    }	    if (myStack.IsEmpty() || myStack.Size() > 1)	        throw "Unable to evaluate expression!";	    else	        return myStack.Pop();	}	/*------------------------------------------------------------------------------ 	 * NAME       : InFixToPostFix	 * PURPOSE    : Convert an Infix expression into a postfix (RPN) equivalent	 * PARAMETERS : Infix expression element array	 * RETURNS    : array containing postfix expression element tokens	 *----------------------------------------------------------------------------*/	function InFixToPostFix(arrToks)	{	    var myStack;	    var intCntr, intIndex;	    var strTok, strTop, strNext, strPrev;	    var blnStart;	    blnStart = false;	    intIndex = 0;	    arrPFix  = new Array();	    myStack  = new Stack();	    // Infix to postfix converter	    for (intCntr = 0; intCntr < arrToks.length; intCntr++)	    {	        strTok = arrToks[intCntr];	        debugAssert ("Processing token [" + strTok + "]");	        switch (strTok)	        {	            case "(" :	                if (myStack.Size() > 0 && IsFunction(myStack.Get(0)))	                {	                    arrPFix[intIndex] = ARG_TERMINAL;	                    intIndex++;	                }	                myStack.Push(strTok);	                break;	            case ")" :	                blnStart = true;	                debugAssert("Stack.Pop [" + myStack.toString());	                while (!myStack.IsEmpty())	                {	                    strTok = myStack.Pop();	                    if (strTok != "(")	                    {	                        arrPFix[intIndex] = strTok;	                        intIndex++;	                    }	                    else	                    {	                        blnStart = false;	                        break;	                    }	                }	                if (myStack.IsEmpty() && blnStart)	                    throw "Unbalanced parenthesis!";	                break;	            case "," :	                if (myStack.IsEmpty()) break;	                debugAssert("Pop stack till opening bracket found!")	                while (!myStack.IsEmpty())	                {	                    strTok = myStack.Get(0);	                    if (strTok == "(") break;	                    arrPFix[intIndex] = myStack.Pop();	                    intIndex++;	                }	                break;	            case "!" :	            case "-" :	                // check for unary negative operator.	                if (strTok == "-")	                {	                    strPrev = null;	                    if (intCntr > 0)	                        strPrev = arrToks[intCntr - 1];	                    strNext = arrToks[intCntr + 1];	                    if (strPrev == null || IsOperator(strPrev) || strPrev == "(")	                    {	                        debugAssert("Unary negation!")	                        strTok = UNARY_NEG;	                    }	                }	            case "^" :	            case "*" :	            case "/" :	            case "%" :	            case "+" :	                // check for unary + addition operator, we need to ignore this.	                if (strTok == "+")	                {	                    strPrev = null;	                    if (intCntr > 0)	                        strPrev = arrToks[intCntr - 1];	                    strNext = arrToks[intCntr + 1];	                    if (strPrev == null || IsOperator(strPrev) || strPrev == "(")	                    {	                        debugAssert("Unary add, Skipping");	                        break;	                    }	                }	            case "&" :	            case "|" :	            case ">" :	            case "<" :	            case "=" :	            case ">=" :	            case "<=" :	            case "<>" :	                strTop = "";	                if (!myStack.IsEmpty()) strTop = myStack.Get(0);	                if (myStack.IsEmpty() || (!myStack.IsEmpty() && strTop == "("))	                {	                    debugAssert("Empty stack pushing operator [" + strTok + "]");	                    myStack.Push(strTok);	                }	                else if (Precedence(strTok) > Precedence(strTop))	                {	                    debugAssert("[" + strTok +	                                "] has higher precedence over [" +	                                strTop + "]");	                    myStack.Push(strTok);	                }	                else	                {	                    // Pop operators with precedence >= operator strTok	                    while (!myStack.IsEmpty())	                    {	                        strTop = myStack.Get(0);	                        if (strTop == "(" || Precedence(strTop) < Precedence(strTok))	                        {	                            debugAssert ("[" + strTop +	                                        "] has lesser precedence over [" +	                                        strTok + "]")	                            break;	                        }	                        else	                        {	                            arrPFix[intIndex] = myStack.Pop();	                            intIndex++;	                        }	                    }	                    myStack.Push(strTok);	                }	                break;	            default :	                if (!IsFunction(strTok))	                {	                    debugAssert("Token [" + strTok + "] is a variable/number!");	                    // Token is an operand	                    if (IsNumber(strTok))	                        strTok = ToNumber(strTok);	                    else if (IsBoolean(strTok))	                        strTok = ToBoolean(strTok);	                    else if (isDate(strTok, dtFormat))	                        strTok = getDateFromFormat(strTok, dtFormat);	                    arrPFix[intIndex] = strTok;	                    intIndex++;	                    break;	                }	                else	                {	                    strTop = "";	                    if (!myStack.IsEmpty()) strTop = myStack.Get(0);	                    if (myStack.IsEmpty() || (!myStack.IsEmpty() && strTop == "("))	                    {	                        debugAssert("Empty stack pushing operator [" + strTok + "]");	                        myStack.Push(strTok);	                    }	                    else if (Precedence(strTok) > Precedence(strTop))	                    {	                            debugAssert("[" + strTok +	                                        "] has higher precedence over [" +	                                        strTop + "]");	                        myStack.Push(strTok);	                    }	                    else	                    {	                        // Pop operators with precedence >= operator in strTok	                        while (!myStack.IsEmpty())	                        {	                            strTop = myStack.Get(0);	                            if (strTop == "(" || Precedence(strTop) < Precedence(strTok))	                            {	                                debugAssert ("[" + strTop +	                                            "] has lesser precedence over [" +	                                            strTok + "]")	                                break;	                            }	                            else	                            {	                                arrPFix[intIndex] = myStack.Pop();	                                intIndex++;	                            }	                        }	                        myStack.Push(strTok);	                    }	                }	                break;	        }	        debugAssert("Stack   : " + myStack.toString() + "\n" +	                    "RPN Exp : " + arrPFix.toString());	    }	    // Pop remaining operators from stack.	    while (!myStack.IsEmpty())	    {	        arrPFix[intIndex] = myStack.Pop();	        intIndex++;	    }	    return arrPFix;	}}/*------------------------------------------------------------------------------ * NAME       : HandleFunctions * PURPOSE    : Execute built-in functions * PARAMETERS : pstrTok - The current function name *              pStack - Operand stack * RETURNS    : Nothing, the result is pushed back onto the stack. *----------------------------------------------------------------------------*/function HandleFunctions(pstrTok, pStack, pdtFormat, parrVars){    var varTmp, varTerm, objTmp;    var objOp1, objOp2;    var arrArgs;    var intCntr;    if (!IsFunction(pstrTok))        throw "Unsupported function token [" + pstrTok + "]";    varTmp = pstrTok.toUpperCase();    arrArgs = new Array();    while (!pStack.IsEmpty())    {        varTerm = ARG_TERMINAL;        varTerm = pStack.Pop();        if (varTerm != ARG_TERMINAL)            arrArgs[arrArgs.length] = varTerm;        else            break;    }    switch (varTmp)    {        case "DATE" :            varTerm = new Date();            pStack.Push(formatDate(varTerm, pdtFormat));            break;        case "ACOS" :        case "ASIN" :        case "ATAN" :            throw "Function [" + varTmp + "] is not implemented!";            break;        case "ABS" :        case "CHR" :        case "COS" :        case "FIX" :        case "HEX" :        case "LOG" :        case "ROUND" :        case "SIN" :        case "SQRT" :        case "TAN" :            if (arrArgs.length < 1)                throw varTmp + " requires atleast one argument!";            else if (arrArgs.length > 1)                throw varTmp + " requires only one argument!";            varTerm = arrArgs[0];            if (IsVariable(varTerm))            {                objTmp = parrVars[varTerm];                if (objTmp == undefined || objTmp == null)                    throw "Variable [" + varTerm + "] not defined";                else                    varTerm = objTmp;            }            if (!IsNumber(varTerm))                throw varTmp + " operates on numeric operands only!";            else            {                objTmp = ToNumber(varTerm);                if (varTmp == "ABS")                    pStack.Push(Math.abs(objTmp));                else if (varTmp == "CHR")                    pStack.Push(String.fromCharCode(objTmp));                else if (varTmp == "COS")                    pStack.Push(Math.cos(objTmp));                else if (varTmp == "FIX")                    pStack.Push(Math.floor(objTmp));                else if (varTmp == "HEX")                    pStack.Push(objTmp.toString(16));                else if (varTmp == "LOG")                    pStack.Push(Math.log(objTmp));                else if (varTmp == "ROUND")                    pStack.Push(Math.round(objTmp));                else if (varTmp == "SIN")                    pStack.Push(Math.sin(objTmp));                else if (varTmp == "SQRT")                    pStack.Push(Math.sqrt(objTmp));                else if (varTmp == "TAN")                    pStack.Push(Math.tan(objTmp));            }            break;        case "ASC" :            if (arrArgs.length > 1)                throw varTmp + " requires only one argument!";            else if (arrArgs.length < 1)                throw varTmp + " requires atleast one argument!";            varTerm = arrArgs[0];            if (IsVariable(varTerm))            {                objTmp = parrVars[varTerm];                if (objTmp == undefined || objTmp == null)                    throw "Variable [" + varTerm + "] not defined";                else                    varTerm = objTmp;            }            if (IsNumber(varTerm) || IsBoolean(varTerm) ||                 isDate(varTerm, pdtFormat) || typeof(varTerm) != "string")                throw varTmp + " requires a string type operand!";            else                pStack.Push(varTerm.charCodeAt(0));            break;        case "LCASE" :        case "UCASE" :        case "CDATE" :            if (arrArgs.length < 1)                throw varTmp + " requires atleast one argument!";            else if (arrArgs.length > 1)                throw varTmp + " requires only one argument!";            varTerm = arrArgs[0];            if (IsVariable(varTerm))            {                objTmp = parrVars[varTerm];                if (objTmp == undefined || objTmp == null)                    throw "Variable [" + varTerm + "] not defined";                else                    varTerm = objTmp;            }            if (varTmp == "CDATE" && !isDate(varTerm, pdtFormat))                throw "CDate can not convert [" + varTerm + "] to a valid date!";            else if (typeof(varTerm) == "number" || typeof(varTerm) != "string")                throw varTmp + " requires a string type operand!";            else            {                if (varTmp == "LCASE")                    pStack.Push(varTerm.toLowerCase());                else if (varTmp == "UCASE")                    pStack.Push(varTerm.toUpperCase());                else if (varTmp == "CDATE")                {                    objTmp = getDateFromFormat(varTerm, pdtFormat);                    pStack.Push(new Date(objTmp));                }            }            break;        case "LEFT" :        case "RIGHT" :            if (arrArgs.length < 2)                throw varTmp + " requires atleast two arguments!";            else if (arrArgs.length > 2)                throw varTmp + " requires only two arguments!";            for (intCntr = 0; intCntr < arrArgs.length; intCntr++)            {                varTerm = arrArgs[intCntr];                if (IsVariable(varTerm))                {                    objTmp = parrVars[varTerm];                    if (objTmp == undefined || objTmp == null)                        throw "Variable [" + varTerm + "] not defined";                    else                        varTerm = objTmp;                }                if (intCntr == 0 && !IsNumber(varTerm))                    throw varTmp + " oprator requires numaric length!";                arrArgs[intCntr] = varTerm;            }            varTerm = new String(arrArgs[1]);            objTmp = ToNumber(arrArgs[0]);            if (varTmp == "LEFT")                pStack.Push(varTmp.substring(0, objTmp));            else                pStack.Push(varTmp.substr((varTerm.length - objTmp), objTmp));            break;        case "MID" :        case "IIF" :            if (arrArgs.length < 3)                throw varTmp + " requires atleast three arguments!";            else if (arrArgs.length > 3)                throw varTmp + " requires only three arguments!";            for (intCntr = 0; intCntr < arrArgs.length; intCntr++)            {                varTerm = arrArgs[intCntr];                if (IsVariable(varTerm))                {                    objTmp = parrVars[varTerm];                    if (objTmp == undefined || objTmp == null)                        throw "Variable [" + varTerm + "] not defined";                    else                        varTerm = objTmp;                }                if (varTerm == "MID" && intCntr <= 1 && !IsNumber(varTerm))                    throw varTmp + " oprator requires numaric lengths!";                else if (varTerm == "IIF" && intCntr == 2 && !IsBoolean(varTerm))                    throw varTmp + " oprator requires boolean condition!";                arrArgs[intCntr] = varTerm;            }            if (varTmp == "MID")            {                varTerm = new String(arrArgs[2]);                objOp1 = ToNumber(arrArgs[1]);                objOp2 = ToNumber(arrArgs[0]);                pStack.Push(varTerm.substring(objOp1, objOp2));            }            else            {                varTerm = ToBoolean(arrArgs[2]);                objOp1 = arrArgs[1];                objOp2 = arrArgs[0];                if (varTerm)                    pStack.Push(objOp1);                else                    pStack.Push(objOp2);            }            break;        case "AVG" :        case "MAX" :        case "MIN" :            if (arrArgs.length < 2)                throw varTmp + " requires atleast two operands!";            objTmp = 0;            for (intCntr = 0; intCntr < arrArgs.length; intCntr++)            {                varTerm = arrArgs[intCntr];                if (IsVariable(varTerm))                {                    objTmp = parrVars[varTerm];                    if (objTmp == undefined || objTmp == null)                        throw "Variable [" + varTerm + "] not defined";                    else                        varTerm = objTmp;                }                if (!IsNumber(varTerm))                    throw varTmp + " requires numaric operands only!";                varTerm = ToNumber(varTerm);                if (varTmp == "AVG")                    objTmp +=  varTerm;                else if (varTmp == "MAX" && objTmp < varTerm)                    objTmp = varTerm;                else if (varTmp == "MIN")                {                    if (intCntr == 1)                         objTmp = varTerm;                    else if (objTmp > varTerm)                        objTmp = varTerm;                }            }            if (varTmp == "AVG")                pStack.Push(objTmp/arrArgs.length);            else                pStack.Push(objTmp);            break;    }}/*------------------------------------------------------------------------------ * NAME       : IsNumber * PURPOSE    : Checks whether the specified parameter is a number. * RETURNS    : True - If supplied parameter can be succesfully converted to a number *              False - Otherwise *----------------------------------------------------------------------------*/function IsNumber(pstrVal){    var dblNo = Number.NaN;    dblNo = new Number(pstrVal);    if (isNaN(dblNo))        return false;    return true;}/*------------------------------------------------------------------------------ * NAME       : IsBoolean * PURPOSE    : Checks whether the specified parameter is a boolean value. * PARAMETERS : pstrVal - The string to be checked. * RETURNS    : True - If supplied parameter is a boolean constant *              False - Otherwise *----------------------------------------------------------------------------*/function IsBoolean(pstrVal){    var varType = typeof(pstrVal);    var strTmp  = null;    if (varType == "boolean") return true;    if (varType == "number" || varType == "function" || varType == undefined)        return false;    if (IsNumber(pstrVal)) return false;    if (varType == "object")    {        strTmp = pstrVal.toString();        if (strTmp.toUpperCase() == "TRUE" || strTmp.toUpperCase() == "FALSE")            return true;    }    if (pstrVal.toUpperCase() == "TRUE" || pstrVal.toUpperCase() == "FALSE")        return true;    return false;}/*------------------------------------------------------------------------------ * NAME       : IsVariable * PURPOSE    : Checks whether the specified parameter is a user defined variable. * RETURNS    : True - If supplied parameter identifies a user defined variable *              False - Otherwise  *----------------------------------------------------------------------------*/function IsVariable(pstrVal){     if (lstArithOps.indexOf(pstrVal) >= 0 || lstLogicOps.indexOf(pstrVal) >=0 ||        lstCompaOps.indexOf(pstrVal) >= 0 ||         (typeof(pstrVal) == "string" && (pstrVal.toUpperCase() == "TRUE" ||         pstrVal.toUpperCase() == "FALSE" || parseDate(pstrVal) != null)) ||         typeof(pstrVal) == "number" || typeof(pstrVal) == "boolean" ||         typeof(pstrVal) == "object" || IsNumber(pstrVal) || IsFunction(pstrVal))        return false;    return true;}/*------------------------------------------------------------------------------ * NAME       : ToNumber * PURPOSE    : Converts the supplied parameter to numaric type. * PARAMETERS : pobjVal - The string to be converted to equvalent number. * RETURNS    : numaric value if string represents a number * THROWS     : Exception if string can not be converted  *----------------------------------------------------------------------------*/function ToNumber(pobjVal){    var dblRet = Number.NaN;    if (typeof(pobjVal) == "number")        return pobjVal;    else    {        dblRet = new Number(pobjVal);        return dblRet.valueOf();    }}/*------------------------------------------------------------------------------ * NAME       : ToBoolean * PURPOSE    : Converts the supplied parameter to boolean value * PARAMETERS : pobjVal - The parameter to be converted. * RETURNS    : Boolean value *----------------------------------------------------------------------------*/function ToBoolean(pobjVal){    var dblNo = Number.NaN;    var strTmp = null;    if (pobjVal == null || pobjVal == undefined)        throw "Boolean value is not defined!";    else if (typeof(pobjVal) == "boolean")        return pobjVal;    else if (typeof(pobjVal) == "number")        return (pobjval > 0);    else if (IsNumber(pobjVal))    {        dblNo = ToNumber(pobjVal);        if (isNaN(dblNo))             return null;        else            return (dblNo > 0);    }    else if (typeof(pobjVal) == "object")    {        strTmp = pobjVal.toString();        if (strTmp.toUpperCase() == "TRUE")            return true;        else if (strTmp.toUpperCase() == "FALSE")            return false;        else            return null;    }    else if (typeof(pobjVal) == "string")    {        if (pobjVal.toUpperCase() == "TRUE")            return true;        else if (pobjVal.toUpperCase() == "FALSE")            return false;        else            return null;    }    else        return null;}/*------------------------------------------------------------------------------ * NAME       : Precedence * PURPOSE    : Returns the precedence of a given operator * PARAMETERS : pstrTok - The operator token whose precedence is to be returned. * RETURNS    : Integer *----------------------------------------------------------------------------*/function Precedence(pstrTok){    var intRet = 0;    switch (pstrTok)    {        case "+" :        case "-" :            intRet = 5;            break;        case "*" :        case "/" :        case "%" :            intRet = 6;            break;        case "^" :            intRet = 7;            break;        case UNARY_NEG :        case "!" :            intRet = 10;            break;        case "(" :            intRet = 99;            break;        case "&" :        case "|" :            intRet = 3;            break;        case ">" :        case ">=" :        case "<" :        case "<=" :        case "=" :        case "<>" :            intRet = 4;            break;        default :            if (IsFunction(pstrTok))                intRet = 9;            else                intRet = 0;            break;    }    debugAssert ("Precedence of " + pstrTok + " is " + intRet);    return intRet;}/*------------------------------------------------------------------------------ * NAME       : debugAssert * PURPOSE    : Shows a messagebox displaying supplied message * PARAMETERS : pObject - The object whose string representation is to be displayed. * RETURNS    : Nothing *----------------------------------------------------------------------------*/function debugAssert(pObject){    if (DEBUG_ON)        alert (pObject.toString())}
 |