All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xfa.formcalc.CalcParser.jj Maven / Gradle / Ivy

The newest version!
/**
 * The class CalcParser defines the FormCalc parser.  It uses
 * JavaCC to generate
 * the necessary Java classes from this source.
 * Running JavaCC on this source will generate the sources
 * for the following Java classes:
 * 
    *
  • TokenMgrError *
  • Token *
  • ParseException *
  • JavaCharStream *
  • CalcParserTokenManager *
  • CalcParserConstants *
  • CalcParser *
* Do not edit any of these generated Java classes. *

* The C++ implementation used a LALR yacc-based parser. JavaCC * generates LL (recursive descent) parsers. This means than * left-recursive production are verboten. Thus all left-recursive * productions in the Yacc-based grammar of the form: * * A ::= B | A C * * are now specified as * * A ::= B ( C )* * * herein. *

* Lastly, it was not evident how to integrate our own * lexical analyzer, so we've use JavaCC's. */ options { JDK_VERSION = "1.5"; STATIC = false; UNICODE_INPUT = true; /* * The any of following may be enable to debug parser issues. */ DEBUG_TOKEN_MANAGER = false; DEBUG_PARSER = false; DEBUG_LOOKAHEAD = false; } PARSER_BEGIN(CalcParser) /* * Do not edit this JavaCC-generated Java class. * * Copyright 2007 Adobe Systems Incorporated All Rights Reserved. * * NOTICE: All information contained herein is, and remains the property of * Adobe Systems Incorporated and its suppliers, if any. The intellectual and * technical concepts contained herein are proprietary to Adobe Systems * Incorporated and its suppliers and may be covered by U.S. and Foreign * Patents, patents in process, and are protected by trade secret or copyright * law. Dissemination of this information or reproduction of this material * is strictly forbidden unless prior written permission is obtained from * Adobe Systems Incorporated. */ package com.adobe.xfa.formcalc; import java.lang.reflect.Method; import java.io.StringReader; import java.util.EnumSet; import com.adobe.xfa.ut.ExFull; import com.adobe.xfa.ut.FindBugsSuppress; import com.adobe.xfa.ut.LcLocale; import com.adobe.xfa.ut.MsgFormatPos; import com.adobe.xfa.ut.ResId; import com.adobe.xfa.ut.StringUtils; /** * This class defines the FormCalc scripting engine. It embodies * both the parser and interpreter for the FormCalc language. * * *

Here's a simple example demonstrating the use of this class. * The colored sequence of instructions can be repeated ad infinitum. *

 *     import com.adobe.xfa.formcalc.CalcParser;
 *     ...
 *     CalcParser oParser = new CalcParser();
 *     //
 *     // Specify a script host. This is mandatory.
 *     //
 *     oParser.setScriptHost(...);
 *     //
 *     // Specify a display host. This is optional.
 *     //
 *     oParser.setDisplayHost(...);
 *     //
 *     // Specify a calculation.
 *     //
 *     oParser.putScript(L"if (4 * atan(1) eq pi(), \"Eureka!\")");
 *     //
 *     // Parse and evaluate calculation.
 *     //
 *     oParser.evaluate(false, false);
 *     //
 *     // Retrieve and classify the result.
 *     //
 *     CalcSymbol Symbol = oParser.getCalcSymbol();
 *     String sResult;
 *     switch(Symbol.getType()) {
 *     case CalcSymbol.TypeString:
 *         sResult = Symbol.getStringValue();
 *         break;
 *     case CalcSymbol.TypeReturn:
 *         sResult = Symbol.getStringValue();
 *         break;
 *     case CalcSymbol.TypeError:
 *         sResult = Symbol.getErrorValue(null, null);
 *         break;
 *     case CalcSymbol.TypeNull:
 *         sResult = "null";
 *         break;
 *     }
 *     System.out.println(sResult);
 * 
* * @author Paul Imerson, Mike P. Tardif * * @exclude from published api. */ @FindBugsSuppress(code="Nm,Bx,UrF") @SuppressWarnings("unchecked") public class CalcParser implements Cloneable { /** * Enumerate scripting legacy versions. * * This enumeration defines a mapping between vX.Y-scripting legacy flags * to a set of internal legacy scripting behaviours. * These enumerations are defined as a set; hence the i'th enumeration * must have value 2^i - 1. * JAVA PORT: Define LegacyVersion as Java enum */ public enum LegacyVersion { /* * Use values 0, 1 and 3 just like in XFA code. Although, strictly speaking, it isn't necessary to define * it in such a manner, but this helps keep the code in both the cases as close as possible. */ CUR_SCRIPTING(0), /* no legacy scripting behaviour */ V30_SCRIPTING(1), /* v3.0 legacy scripting behaviour */ V32_SCRIPTING(2); /* v3.2 legacy scripting behaviour */ private LegacyVersion(int nValue){ value=nValue; } private final int value; final int getValue(){ return value; } } public static final int CODESIZE = 512; // must be a power of 2! public static final int DATASIZE = 509; // must be a prime! /** * Instantiates a CalcParser object. */ public CalcParser() { this(CODESIZE, DATASIZE); } /** * Instantiates a CalcParser object. * * @param nCodeSize an initial size for instruction memory. * @param nDataSize an initial size for data memory. */ CalcParser(int nCodeSize /* = CODESIZE */, int nDataSize /* = DATASIZE */) { this(System.in); create(nCodeSize, nDataSize); } /** * Clones this object. * * Clone a new CalcParser object from the properties of this object. * * @return the new CalcParser. */ public Object clone() { CalcParser oParser = null; try { oParser = (CalcParser) super.clone(); oParser.create(moCode.getCodeSize(), moData.getTableSize()); oParser.setDisplayHost(moDisplayHost); oParser.setScriptHost(moScriptHost); oParser.setProtocolHost(moProtocolHost); oParser.setDebugHost(moDebugHost); oParser.setLocale(msLocaleName); oParser.setDupsMode(mbAllowDups); oParser.setLegacyScripting(moLegacyScripting); } catch(CloneNotSupportedException e) { ; } return oParser; } /* * Create required parser and interpreter components. * * @param nCodeSize initial size of instruction memory. * @param nDataSize initial size of data memory. */ boolean create(int nCodeSize, int nDataSize) { moCode = new Instruction(); if (moCode.create(nCodeSize) == 0) return false; moData = new SymbolTable(); if (moData.create(nDataSize) == 0) return false; moScope = new ScopeTable(); if (moScope.create(ScopeTable.SIZE) == 0) return false; moFrame = new FrameTable(); if (moFrame.create(FrameTable.SIZE) == 0) return false; mStack = new Stack(); if (mStack.create(Stack.SIZE) == 0) return false; mBuiltin = new SymbolTable(); if (mBuiltin.create(97) == 0) return false; Builtins.init(mBuiltin); moDisplayHost = null; moScriptHost = null; moProtocolHost = null; moDebugHost = null; mnScriptID = -1; LcLocale oLocale = new LcLocale(LcLocale.getLocale()); if (! oLocale.isValid()) oLocale = new LcLocale(LcLocale.DEFAULT_LOCALE); msLocaleName = oLocale.getIsoName(); mbWasInSaveMode = false; mbInSaveMode = false; mbInSyntaxCheckMode = false; mbInUse = false; mbAllowDups = true; mbSyntaxErrorSeen = false; mbDebugEnabled = false; mbInterrupted = false; moLegacyScripting = EnumSet.of(LegacyVersion.CUR_SCRIPTING); mnSavedDecl = 0; moResult = null; return true; } /* * Handle a syntax error: generate error symbols and push it * on the runtime stack. * * @param nResId the resource id used to format the error message. * @param token the error message token parameter. */ void yyError(int nResId) { if (! mbSyntaxErrorSeen) yyError(nResId, token.image); } /* * Handle a syntax error: generate error symbols and push it * on the runtime stack. * * @param nResId the resource id used to format the error message. * @param token the error message token parameter. */ void yyError(int nResId, String sToken) { if (! mbSyntaxErrorSeen) { mbInThrow = true; Token t = token; if (t.next != null && t.next.image.length() > 0) t = t.next; MsgFormatPos oErr = new MsgFormatPos(nResId); oErr.format(sToken); // token String sLineNo = Integer.toString(t.beginLine); oErr.format(sLineNo); // line number String sColNo = Integer.toString(t.beginColumn); oErr.format(sColNo); // column number CalcSymbol oSym = new CalcSymbol(oErr.toString(), true, t.beginLine, nResId); mStack.push(oSym); mbSyntaxErrorSeen = true; throw new RuntimeException(); } } /* * Parse the current source and generate code. * @return boolean false when errors were detected during * compilation, and true otherwise. */ boolean yyParse() { if (mbInUse) { mbInThrow = true; MsgFormatPos sErr = new MsgFormatPos(ResId.FC_SYS_ERR_REENT); CalcSymbol oSym = new CalcSymbol(sErr.toString(), true, 0, 0); mStack.push(oSym); setCalcResult(oSym); return false; } mbInUse = true; // // Re-initialize the parser and interpreter on entry. // moCode.init(this); moData.init(this); moScope.init(this); mStack.init(); moFrame.init(); mbWasInSaveMode = mbInSaveMode; mbInDowntoLoop = false; mbInVarDeclaration = false; mbInFuncDeclaration = false; mbInFuncParameters = false; mbInLoopDeclaration = false; mbInForeachLoop = false; mbInThrow = false; mbInBreak = false; mbInContinue = false; // mbInAccessor = false; Javaport: not used. mbDeleteOk = false; mbSyntaxErrorSeen = false; // mbNoTokenssSeen = true; Javaport: not used. mbCancelStatus = false; mnLoopOffset = 0; // mnLastLineSeen = 0; Javaport: not used. // // Parse the script, and generate pseudo code. // try { FormCalculation(); } catch (RuntimeException e) { if (! mbSyntaxErrorSeen) { CalcSymbol oSym = new CalcSymbol(e.toString(), true, 0, 0); mStack.push(oSym); } } catch (ParseException e) { Token t = e.currentToken; if (t.next != null && t.next.image.length() > 0) t = t.next; MsgFormatPos oErr = new MsgFormatPos(ResId.FC_ERR_SYNTAX); oErr.format(t.image); String sLineNo = Integer.toString(t.beginLine); oErr.format(sLineNo); String sColNo = Integer.toString(t.beginColumn); oErr.format(sColNo); CalcSymbol oSym = new CalcSymbol(oErr.toString(), true, t.beginLine, 0); mStack.push(oSym); mbSyntaxErrorSeen = true; } catch (TokenMgrError e) { CalcSymbol oSym = new CalcSymbol(e.toString(), true, 0, 0); mStack.push(oSym); mbSyntaxErrorSeen = true; } // // Add an extra instruction in case of syntax errors. // generate(Instruction.gStop); // // Note: there will always be one symbol on top of the stack, // when there are syntax/semantic errors! // if (mbSyntaxErrorSeen) { setCalcResult(mStack.pop()); cleanCode(); } else { moResult = null; } mbInUse = false; return (! mbSyntaxErrorSeen); } void yyTrace(String s) { // Javaport: not needed. For tracing, set JavaCC option DEBUG_PARSER instead. } /* * Interpret the current source. yyParse() must * already have been called successfully. * */ void execute() { if (mbInUse) { mbInThrow = true; MsgFormatPos sErr = new MsgFormatPos(ResId.FC_SYS_ERR_REENT); CalcSymbol oSym = new CalcSymbol(sErr.toString(), true, 0, 0); mStack.push(oSym); setCalcResult(oSym); } // // If successfully parsed Then interpret the pseudo code, pop off // the resulting symbol and save its value. // if (mbSyntaxErrorSeen) return; mbInUse = true; moCode.execute(this, moCode.getCodeStart()); setCalcResult(mStack.pop()); cleanCode(); mbInUse = false; } /* * Release or relocate code according to the setting * of mbInSaveMode. */ void cleanCode() { // // Release all resources consumed from code generation and // interpretation. Relocate code if save mode is turned on. // mbDeleteOk = true; if (mbSyntaxErrorSeen) moCode.release(this, moCode.getProgStart()); else if (mbInSaveMode) moCode.relocate(this); else moCode.release(this, moCode.getCodeStart()); } /* * Set the intermediate code saviour mode for all subsequent compilations. * * @param bSaveMode saves the intermediate code of global variable * and function definitions when set, and discarts the intermediate code * of subsequent compilations when reset. */ void setSaveMode(boolean bSaveMode) { mbInSaveMode = bSaveMode; } /** * Set (specify) a {@link DisplayHost}. * * This method identifies a host capable of displaying message box * dialogs. Without such a host, all MessageBox calcs will fail. * *

Use of this method is optional, * but should be invoked before any FormCalc script is evaluated. * * @param oDisplayHost an interface to the display host. */ public void setDisplayHost(DisplayHost oDisplayHost) { moDisplayHost = oDisplayHost; if (moDisplayHost != null) Builtins.add(mBuiltin, "MessageBox", com.adobe.xfa.formcalc.BuiltinMisc.class); } /** * Set (specify) a {@link ScriptHost}. * * This method identifies a host capable of resolving SOM references. * *

Use of this method is mandatory * and should be invoked before any FormCalc script is evaluated. * * @param oScriptHost an interface to the script host. */ public void setScriptHost(ScriptHost oScriptHost) { moScriptHost = oScriptHost; } /** * Set (specify) a scripting legacy flag. * * This method sets the state of a scripting legacy flag. * * @param oLegacyScripting the state of the scripting legacy flag. */ public void setLegacyScripting(EnumSet oLegacyScripting) { moLegacyScripting = EnumSet.copyOf(oLegacyScripting); } /** * Set (specify) a {@link ProtocolHost}. * * This method identifies a host capable of getting/putting/posting URLs. * *

Use of this method is optional * but should be invoked before any FormCalc script is evaluated. * * @param oProtocolHost an interface to the protocol host. */ public void setProtocolHost(ProtocolHost oProtocolHost) { moProtocolHost = oProtocolHost; if (moProtocolHost != null) { Builtins.add(mBuiltin, "Get", com.adobe.xfa.formcalc.BuiltinUrl.class); Builtins.add(mBuiltin, "Put", com.adobe.xfa.formcalc.BuiltinUrl.class); Builtins.add(mBuiltin, "Post", com.adobe.xfa.formcalc.BuiltinUrl.class); } } /** * Set (specify) a {@link DebugHost}. * * This method identifies a host capable of acting as a debugger. * *

Use of this method is optional * but should be invoked before any FormCalc script is evaluated. * * @param oDebugHost an interface to the debug host. */ public void setDebugHost(DebugHost oDebugHost) { moDebugHost = oDebugHost; } /** * Provide an identifier for the script that will be compiled * or evaluated next. * * Set the script ID. Script IDs are used to identify which script * is invoking a break-point callback via {@link DebugHost}. * It's not necessarily the most * recently-invoked script, since function definitions can be cached. * @param nScriptID the script ID. */ public void setScriptID(int nScriptID) { mnScriptID = nScriptID; } /* * Enable debugging support. This will cause line numbers * to be stored internally. */ public void debugEnable(boolean bEnableDebug) { mbDebugEnabled = bEnableDebug; } /* * Get one (the first) symbol referenced by the given accessor symbol. * * @param oSymIn CalcSymbol. */ CalcSymbol getOneValue(CalcSymbol oSymIn) { CalcSymbol oSym = new CalcSymbol(oSymIn); do { switch (oSym.getType()) { case CalcSymbol.TypeAccessor: try { CalcSymbol[] oSyms = moScriptHost.getItemValue(oSym.getName(), oSym.getObjValues()); oSym = oSyms[0]; } catch (CalcException e) { oSym = e.getSymbol(); } continue; case CalcSymbol.TypeReference: case CalcSymbol.TypeDouble: case CalcSymbol.TypeString: case CalcSymbol.TypeNull: case CalcSymbol.TypeVariable: case CalcSymbol.TypeError: case CalcSymbol.TypeReturn: case CalcSymbol.TypeFunction: break; default: assert(false); break; } break; } while (true); CalcSymbol oRetSym = new CalcSymbol(oSym); return oRetSym; } /* * Get the value symbol referenced by the given reference symbol. * * @param oSymIn CalcSymbol. */ CalcSymbol getRefValue(CalcSymbol oSymIn) { CalcSymbol oSym = new CalcSymbol(oSymIn); switch (oSym.getType()) { case CalcSymbol.TypeReference: try { if (oSym.getObjValue() != null) { CalcSymbol[] oSyms = moScriptHost.getItemValue("#0", oSym.getObjValues()); oSym = oSyms[0]; } else if (oSym.getName() != null && oSym.getName().length() > 0) { mbInThrow = true; MsgFormatPos sFmt = new MsgFormatPos(ResId.FC_ERR_REF_NULL); sFmt.format(oSym.getName()); oSym = new CalcSymbol(sFmt.toString(), true, 0, 0); } else { oSym = new CalcSymbol(); } } catch (CalcException e) { oSym = e.getSymbol(); } break; default: assert(false); break; } CalcSymbol oRetSym = new CalcSymbol(oSym); return oRetSym; } /* * Get the numeric value of the given symbol. * * @param oSymIn CalcSymbol. */ double getNumeric(CalcSymbol oSymIn) { double nRetVal = Double.MAX_VALUE; // sentinel value; do { CalcSymbol oSym = null; switch (oSymIn.getType()) { case CalcSymbol.TypeAccessor: oSym = getOneValue(oSymIn); if (oSym.getType() != CalcSymbol.TypeError && oSymIn.getName().indexOf('*') >= 0) { // more orecisely, "[*]" mbInThrow = true; throw new CalcException(); } oSymIn = oSym; continue; case CalcSymbol.TypeReference: oSym = getRefValue(oSymIn); oSymIn = oSym; continue; case CalcSymbol.TypeDouble: nRetVal = oSymIn.getNumericValue(); break; case CalcSymbol.TypeString: nRetVal = FormCalcUtil.strToDbl(oSymIn.getStringValue(), false); break; case CalcSymbol.TypeVariable: String sVal = oSymIn.getStringValue(); if (sVal != null) nRetVal = FormCalcUtil.strToDbl(sVal, false); else nRetVal = 0.; break; case CalcSymbol.TypeFunction: case CalcSymbol.TypeNull: nRetVal =0.; break; case CalcSymbol.TypeError: case CalcSymbol.TypeReturn: mbInThrow = true; throw new CalcException(oSymIn); default: assert(false); break; } break; } while (true); return nRetVal; } /* * Get the actual type of the given symbol; that is, if oSymIn points to * an accessor or a reference, return the type of the ref value rather than * oSymIn.getType(). * * @param oSymIn CalcSymbol. */ CalcSymbol getActualType(CalcSymbol oSymIn) { CalcSymbol cRetVal = null; // sentinel value; do { CalcSymbol oSym = null; cRetVal = new CalcSymbol(oSymIn); switch (oSymIn.getType()) { case CalcSymbol.TypeAccessor: oSym = getOneValue(oSymIn); oSymIn = oSym; continue; case CalcSymbol.TypeReference: oSym = getRefValue(oSymIn); oSymIn = oSym; continue; case CalcSymbol.TypeVariable: String sVal = oSymIn.getStringValue(); if (null == sVal) { //Enforces TypeNull cRetVal = new CalcSymbol(); } break; default: break; } break; } while (true); return cRetVal; } /* * Get the Cancel Status for the script. * */ boolean getCancelStatus(){ return mbCancelStatus; } /* * Set the Cancel Status for the script. * * @param bStatus boolean. */ void setCancelStatus(boolean bStatus) { mbCancelStatus = bStatus; } /* * Get the string value of the given symbol. * * @param oSymIn CalcSymbol. */ String getString(CalcSymbol oSymIn) { String sRetVal = "E Pluribus Unix"; // sentinel value; do { CalcSymbol oSym = null; switch (oSymIn.getType()) { case CalcSymbol.TypeAccessor: oSym = getOneValue(oSymIn); if (oSym.getType() != CalcSymbol.TypeError && oSymIn.getName().indexOf('*') >= 0) { // more orecisely, "[*]" mbInThrow = true; throw new CalcException(); } oSymIn = oSym; continue; case CalcSymbol.TypeReference: oSym = getRefValue(oSymIn); oSymIn = oSym; continue; case CalcSymbol.TypeDouble: oSymIn.setTypeToString(); sRetVal = oSymIn.getStringValue(); break; case CalcSymbol.TypeString: sRetVal = oSymIn.getStringValue(); break; case CalcSymbol.TypeVariable: sRetVal = oSymIn.getStringValue(); if (sRetVal == null) sRetVal = ""; break; case CalcSymbol.TypeFunction: case CalcSymbol.TypeNull: sRetVal = ""; break; case CalcSymbol.TypeError: case CalcSymbol.TypeReturn: mbInThrow = true; throw new CalcException(oSymIn); default: assert(false); break; } break; } while (true); return sRetVal; } /* * Get the exception value of the given symbol. * * @param oSymIn CalcSymbol. */ void getExceptions(CalcSymbol oSymIn) { do { CalcSymbol oSym = null; switch (oSymIn.getType()) { case CalcSymbol.TypeAccessor: if (mbInBreak || mbInContinue) break; oSym = getOneValue(oSymIn); if (oSym.getType() != CalcSymbol.TypeError && oSymIn.getName().indexOf('*') >= 0) { // more precisely, "[*]" mbInThrow = true; throw new CalcException(); } oSymIn = oSym; continue; case CalcSymbol.TypeReference: case CalcSymbol.TypeDouble: case CalcSymbol.TypeString: case CalcSymbol.TypeVariable: case CalcSymbol.TypeFunction: case CalcSymbol.TypeNull: break; case CalcSymbol.TypeError: case CalcSymbol.TypeReturn: mbInThrow = true; throw new CalcException(oSymIn); default: assert(true); break; } break; } while (true); } /* * Set the (calculation) result to the given value. * * @param oSymIn CalcSymbol. */ void setCalcResult(CalcSymbol oSymIn) { try { do { CalcSymbol oSym = null; switch (oSymIn.getType()) { case CalcSymbol.TypeAccessor: oSym = getOneValue(oSymIn); oSymIn.assign(oSym); continue; case CalcSymbol.TypeReference: oSym = getRefValue(oSymIn); oSymIn.assign(oSym); break; case CalcSymbol.TypeDouble: oSymIn.setTypeToString(); break; case CalcSymbol.TypeReturn: case CalcSymbol.TypeVariable: case CalcSymbol.TypeString: case CalcSymbol.TypeNull: case CalcSymbol.TypeError: break; default: assert(false); break; } break; } while (true); moResult = new CalcSymbol(oSymIn); } catch (CalcException e) { moResult = e.getSymbol(); } if (moResult.getType() == CalcSymbol.TypeVariable) { moResult.setType(moResult.getStringValue() != null ? CalcSymbol.TypeString : CalcSymbol.TypeNull); } // // Watson bug 1357801 don't strip off the sign char. // /* if (moResult.getType() == CalcSymbol.TypeString) { String sStr = moResult.getStringValue(); if (FormCalcUtil.strIsNumeric(sStr)) { StringBuilder sBuf = new StringBuilder(sStr); FormCalcUtil.trimZeroes(sBuf); FormCalcUtil.trimRadix(sBuf); FormCalcUtil.trimSign(sSBuf); moResult.setStrValue(sBuf.toString()); } } */ } /** * Determine if the symbol given already exists at the scope given. * * @param pName the name of the symbol being checked. * @return the symbol if the given identifier is a variable * at the scope given, and NULL otherwise. */ private CalcSymbol varExists(String sName, ScopeTable oScope) { CalcSymbol oSym = moData.lookup(sName, oScope); if (oSym != null) { if (oSym.getType() == CalcSymbol.TypeVariable) return (oSym.getScope() == oScope.getScope()) ? oSym : null; else if (oSym.getType() == CalcSymbol.TypeParameter) return oSym; } return null; } private int generate(Object oInstruction) { if (mbDebugEnabled) { if (oInstruction instanceof Method) { Method oMethod = (Method) oInstruction; if (oMethod == Instruction.gEnter || oMethod == Instruction.gExit) setLine(); } throw new ExFull(ResId.UNSUPPORTED_OPERATION, "CalcParser#generate"); // return moCode.generate(oInstruction, mnScriptID, mnLastLineSeen); } else return moCode.generate(oInstruction); } private void setLine() { Token t = token; if (t.next != null) t = t.next; // mnLastLineSeen = t.beginLine; // Javaport: not used. } /** * Specify the FormCalc script that will be compiled or evaluated next. * * @param sCalc the FormCalc script. */ public void putScript(String sCalc) { ReInit(new StringReader(sCalc)); } /** * Specify the operating locale. If omitted, it will default to the * ambient locale. * * @param sLocale the (RFC-1766) locale name. */ public void setLocale(String sLocale) { if (!StringUtils.isEmpty(sLocale)) msLocaleName = sLocale; } /** * Get the strictness mode for the redefinition of global variables * and function. * * @return boolean - the strictness mode. */ public boolean getDupsMode() { return mbAllowDups; } /** * Set the strictness mode for the redefinition of global variables * and function. * * @param bAllowDups allow the redefinition of global variables * and functions when set. */ public void setDupsMode(boolean bAllowDups) { mbAllowDups = bAllowDups; } /** * Set the parser into syntax-check mode. This means that * functions are assumed to exist; unknown functions do not * cause a syntax error during parsing. * * @param bSyntaxCheckMode Specify the syntax-check mode. */ public void setSyntaxCheckMode(boolean bSyntaxCheckMode) { mbInSyntaxCheckMode = bSyntaxCheckMode; } /** * Compile (only) the FormCalc script. * *

Upon syntax errors, text describing error is available by * invoking the {@link #getCalcResult()} method. * *

When saving the resulting intermediate code (bSaveDeclarations), only * the code from function declarations and global variable declarations * is saved, unless bSaveAllCode is true. * *

This method is provided for specialized debugging environments, * as it is more efficient to simly invoke the * {@link #evaluate(boolean, boolean)} method. * * @param bSaveDeclarations save the resulting intermediate code relating * to function declarations and global variable declarations upon success * when set, and don't save it when reset. * @param bSaveAllCode save all generated code upon success when set, * and don't save it when reset. The saved code can be executed by calling * Evaluate with the bExecSavedCode arameter set. * @param bSyntaxCheckOnly if the saved code will not be executed, then * set this flag to true. This will mean that missing functions are not * considered errors (since they are assumed to exist elsewhere). * @return boolean false on syntax errors, and true otherwise. */ public boolean compile(boolean bSaveDeclarations /* = false */, boolean bSaveAllCode /* = false */, boolean bSyntaxCheckOnly /* = false */) { setSaveMode(bSaveDeclarations); setSyntaxCheckMode(bSyntaxCheckOnly); if (! yyParse()) return false; if (! bSaveAllCode) cleanCode(); return true; } /** * (Compile and) Evaluate the FormCalc script. * *

This method always yield a result, which is an object of type * {@link CalcSymbol}. That object is * is available by invoking the {@link #getCalcResult()} * method. * *

When saving the resulting intermediate code (bSaveDeclarations), * only * code from function declarations and global variable declarations * is saved. * * @param bSaveDeclarations save the resulting intermediate code relating * to function declarations and global variable declarations upon success * when set, and don't save it when reset. * @param bExecSavedCode execute saved code upon success when set, * and regenerate code (from original source) when reset. * @return boolean false on syntax errors, and true otherwise. */ public boolean evaluate(boolean bSaveDeclarations /* = false */, boolean bExecSavedCode /* = false */) { setSaveMode(bSaveDeclarations); setSyntaxCheckMode(false); if (! bExecSavedCode && ! yyParse()) return false; execute(); return true; } /** * Is this FormCalc object already in use? * *

This method determines if the FormCalc is in the middle of * evaluating a script. The FormCalc parser is YACC based, and * hence not re-entrant. Re-invoking the parser when in use, throws * an excetion. Use this method to avert such exceptions. * * @return boolean true when in use, and false otherwise. */ public boolean inUse() { return mbInUse; } /** * Retrieve the calculation (or compilation) result. * *

If the evaluated (or compiled) Formcalc script: *

*
*
contained a syntax error, *
the resulting CalcSymbol object will be of type * CalcSymbol.TypeError. * Use {@link CalcSymbol#getErrorValue(IntegerHolder, IntegerHolder)} * to access the associated error message text. *
evaluated to a runtime error, *
the resulting CalcSymbol object will again be of type * CalcSymbol.TypeError. Again use * {@link CalcSymbol#getErrorValue(IntegerHolder, IntegerHolder)} * to access the associated error message text. *
evaluated to an excetion resulting from execution * of a return() exression, *
the resulting CalcSymbol object will be of type * CalcSymbol.TypeReturn. Use * {@link CalcSymbol#getStringValue()} * to access the associated string value. *
evaluated to a null-valued result, *
the resulting CalcSymbol object will again be of type * CalcSymbol.TypeNull. *
evaluated to a string-valued or numeric-valued result, *
the resulting CalcSymbol object will again be of type * CalcSymbol.TypeString. Use * {@link CalcSymbol#getStringValue()} * to access the associated string value. *
*
* * @return the resulting object. It's the application's responsability to */ public CalcSymbol getCalcResult() { return moResult; } public Instruction moCode; // the instruction memory. public SymbolTable moData; // the data memory. public ScopeTable moScope; // the scope info. public FrameTable moFrame; // the frame table. public Stack mStack; // the runtime stack. SymbolTable mBuiltin; // the builtin table. String msLocaleName; // the operating locale name. ScriptHost moScriptHost; // the script host. DisplayHost moDisplayHost; // the display host. ProtocolHost moProtocolHost; // the protocol host. DebugHost moDebugHost; // the debug host. int mnLoopOffset; // the enclosing loop offset. int mnSavedDecl; // the saved declaration count. int mnScriptID; // an optional ID for this script (for debugging) // the parser state flags. boolean mbCancelStatus; boolean mbWasInSaveMode; boolean mbInSaveMode; boolean mbInSyntaxCheckMode; boolean mbInDowntoLoop; boolean mbInVarDeclaration; boolean mbInFuncDeclaration; boolean mbInFuncParameters; boolean mbInLoopDeclaration; boolean mbInForeachLoop; boolean mbInThrow; boolean mbInBreak; boolean mbInContinue; // boolean mbInAccessor; // Javaport: not used. boolean mbDeleteOk; boolean mbSyntaxErrorSeen; boolean mbInUse; boolean mbAllowDups; // boolean mbNoTokensSeen; // Javaport: not used. boolean mbDebugEnabled; boolean mbInterrupted; //Javaport: Implement legacy version as EnumSet. This enables efficient bit twiddling logic in Java //(albeit via Java's EnumSet pattern/paradigm), while enforcing & maintaining enum based type safety. EnumSet moLegacyScripting; private CalcSymbol moResult; // the resulting symbol. private String msFunc; // the function name. // private int mnLastLineSeen; // the last line of source encountered. Javaport: not used. } PARSER_END(CalcParser) SKIP : /* WHITESPACE and COMMENT */ { " " | "\t" | "\013" | "\f" | "\n" | "\r" | < ";" ( ~[ "\n", "\r" ] )* ( "\n" | "\r" | "\r\n" )? > | < "//" ( ~[ "\n", "\r" ] )* ( "\n" | "\r" | "\r\n" )? > } TOKEN : { /* LITERALS */ < INTEGER : > | < REAL : "." ( [ "0"-"9" ] )* ( )? | "." ( )? | ( )? > | < #INTEGER_PART : ( [ "0"-"9" ] )+ > | < #EXPONENT_PART : [ "e", "E" ] ( [ "+", "-" ] )? > | < #HEXDIGIT : [ "0"-"9", "a"-"f", "A"-"F" ] > | < STRING : "\"" ( ~[ "\\", "\"", "\n", "\r" ] | ( "\"\"" | "\\u" | "\\U" ) )* "\"" > } TOKEN [IGNORE_CASE] : { /* NULL LITERALS */ < NULL1 : "null" > | < NULL2 : "%null%" > } TOKEN [IGNORE_CASE] : { /* KEYWORDS: keep sorted in increasing string length for best performance. */ < DO : "do" > | < IF : "if" > | < IN : "in" > | < END : "end" > | < FOR : "for" > | < VAR : "var" > | < ELSE : "else" > | < EXIT : "exit" > /* reserved for future use. */ | < FUNC : "func" > | < STEP : "step" > | < THEN : "then" > | < UPTO : "upto" > | < BREAK : "break" > | < ENDIF : "endif" > | < WHILE : "while" > | < DOWNTO : "downto" > | < ELSEIF : "elseif" > | < ENDFOR : "endfor" > | < RETURN : "return" > /* reserved for future use. */ | < ENDFUNC : "endfunc" > | < FOREACH : "foreach" > | < CONTINUE : "continue" > | < ENDWHILE : "endwhile" > } TOKEN [IGNORE_CASE] : { /* OPERATORS: keep sorted in increasing string length. */ < LT1 : "<" > | < GT1 : ">" > | < OR1 : "|" > | < AND1 : "&" > | < LE1 : "<=" > | < NE1 : "<>" > | < EQ1 : "==" > | < GE1 : ">=" > | < EQ2 : "eq" > | < GE2 : "ge" > | < GT2 : "gt" > | < LE2 : "le" > | < LT2 : "lt" > | < NE2 : "ne" > | < OR2 : "or" > | < AND2 : "and" > | < NOT : "not" > } TOKEN : { /* OPERATORS: keep sorted in increasing string length. */ < PLUS : "+" > | < MINUS : "-" > | < STAR : "*" > | < DIV : "/" > | < ASGN : "=" > | < DOT : "." > : ALLOWKEYWORDS | < DOTDOT : ".." > : ALLOWKEYWORDS | < DOTHASH : ".#" > : ALLOWKEYWORDS | < DOTSTAR : ".*" > : ALLOWKEYWORDS } TOKEN : { /* PUNCTUATIONS */ < COMMA : "," > | < LPAREN : "(" > | < RPAREN : ")" > | < LBRACE : "[" > | < RBRACE : "]" > } TOKEN : { /* IDENTIFIER */ < IDENT : ( )* > } TOKEN : { /* IDENTIFIER or KEYWORD */ < KEYID : ( )* > : DEFAULT } TOKEN : { < ALPHA_PART : [ "!", "$", "A"-"Z", "_", "a"-"z", // Javaport: All chars for which Character.isUnicodeIdentifierStart(char) is true. // Sadly, C++ hasn't kept up with Unicode. Though more recent, this too isn't // up to the latest Unicode. "\u00a2"-"\u00a5", "\u00aa", "\u00b5", "\u00ba", "\u00c0"-"\u00d6", "\u00d8"-"\u00f6", "\u00f8"-"\u021f", "\u0222"-"\u0233", "\u0250"-"\u02ad", "\u02b0"-"\u02b8", "\u02bb"-"\u02c1", "\u02d0"-"\u02d1", "\u02e0"-"\u02e4", "\u02ee", "\u037a", "\u0386", "\u0388"-"\u038a", "\u038c", "\u038e"-"\u03a1", "\u03a3"-"\u03ce", "\u03d0"-"\u03d7", "\u03da"-"\u03f3", "\u0400"-"\u0481", "\u048c"-"\u04c4", "\u04c7"-"\u04c8", "\u04cb"-"\u04cc", "\u04d0"-"\u04f5", "\u04f8"-"\u04f9", "\u0531"-"\u0556", "\u0559", "\u0561"-"\u0587", "\u05d0"-"\u05ea", "\u05f0"-"\u05f2", "\u0621"-"\u063a", "\u0640"-"\u064a", "\u0671"-"\u06d3", "\u06d5", "\u06e5"-"\u06e6", "\u06fa"-"\u06fc", "\u0710", "\u0712"-"\u072c", "\u0780"-"\u07a5", "\u0905"-"\u0939", "\u093d", "\u0950", "\u0958"-"\u0961", "\u0985"-"\u098c", "\u098f"-"\u0990", "\u0993"-"\u09a8", "\u09aa"-"\u09b0", "\u09b2", "\u09b6"-"\u09b9", "\u09dc"-"\u09dd", "\u09df"-"\u09e1", "\u09f0"-"\u09f3", "\u0a05"-"\u0a0a", "\u0a0f"-"\u0a10", "\u0a13"-"\u0a28", "\u0a2a"-"\u0a30", "\u0a32"-"\u0a33", "\u0a35"-"\u0a36", "\u0a38"-"\u0a39", "\u0a59"-"\u0a5c", "\u0a5e", "\u0a72"-"\u0a74", "\u0a85"-"\u0a8b", "\u0a8d", "\u0a8f"-"\u0a91", "\u0a93"-"\u0aa8", "\u0aaa"-"\u0ab0", "\u0ab2"-"\u0ab3", "\u0ab5"-"\u0ab9", "\u0abd", "\u0ad0", "\u0ae0", "\u0b05"-"\u0b0c", "\u0b0f"-"\u0b10", "\u0b13"-"\u0b28", "\u0b2a"-"\u0b30", "\u0b32"-"\u0b33", "\u0b36"-"\u0b39", "\u0b3d", "\u0b5c"-"\u0b5d", "\u0b5f"-"\u0b61", "\u0b85"-"\u0b8a", "\u0b8e"-"\u0b90", "\u0b92"-"\u0b95", "\u0b99"-"\u0b9a", "\u0b9c", "\u0b9e"-"\u0b9f", "\u0ba3"-"\u0ba4", "\u0ba8"-"\u0baa", "\u0bae"-"\u0bb5", "\u0bb7"-"\u0bb9", "\u0c05"-"\u0c0c", "\u0c0e"-"\u0c10", "\u0c12"-"\u0c28", "\u0c2a"-"\u0c33", "\u0c35"-"\u0c39", "\u0c60"-"\u0c61", "\u0c85"-"\u0c8c", "\u0c8e"-"\u0c90", "\u0c92"-"\u0ca8", "\u0caa"-"\u0cb3", "\u0cb5"-"\u0cb9", "\u0cde", "\u0ce0"-"\u0ce1", "\u0d05"-"\u0d0c", "\u0d0e"-"\u0d10", "\u0d12"-"\u0d28", "\u0d2a"-"\u0d39", "\u0d60"-"\u0d61", "\u0d85"-"\u0d96", "\u0d9a"-"\u0db1", "\u0db3"-"\u0dbb", "\u0dbd", "\u0dc0"-"\u0dc6", "\u0e01"-"\u0e30", "\u0e32"-"\u0e33", "\u0e3f"-"\u0e46", "\u0e81"-"\u0e82", "\u0e84", "\u0e87"-"\u0e88", "\u0e8a", "\u0e8d", "\u0e94"-"\u0e97", "\u0e99"-"\u0e9f", "\u0ea1"-"\u0ea3", "\u0ea5", "\u0ea7", "\u0eaa"-"\u0eab", "\u0ead"-"\u0eb0", "\u0eb2"-"\u0eb3", "\u0ebd", "\u0ec0"-"\u0ec4", "\u0ec6", "\u0edc"-"\u0edd", "\u0f00", "\u0f40"-"\u0f47", "\u0f49"-"\u0f6a", "\u0f88"-"\u0f8b", "\u1000"-"\u1021", "\u1023"-"\u1027", "\u1029"-"\u102a", "\u1050"-"\u1055", "\u10a0"-"\u10c5", "\u10d0"-"\u10f6", "\u1100"-"\u1159", "\u115f"-"\u11a2", "\u11a8"-"\u11f9", "\u1200"-"\u1206", "\u1208"-"\u1246", "\u1248", "\u124a"-"\u124d", "\u1250"-"\u1256", "\u1258", "\u125a"-"\u125d", "\u1260"-"\u1286", "\u1288", "\u128a"-"\u128d", "\u1290"-"\u12ae", "\u12b0", "\u12b2"-"\u12b5", "\u12b8"-"\u12be", "\u12c0", "\u12c2"-"\u12c5", "\u12c8"-"\u12ce", "\u12d0"-"\u12d6", "\u12d8"-"\u12ee", "\u12f0"-"\u130e", "\u1310", "\u1312"-"\u1315", "\u1318"-"\u131e", "\u1320"-"\u1346", "\u1348"-"\u135a", "\u13a0"-"\u13f4", "\u1401"-"\u166c", "\u166f"-"\u1676", "\u1681"-"\u169a", "\u16a0"-"\u16ea", "\u1780"-"\u17b3", "\u17db", "\u1820"-"\u1877", "\u1880"-"\u18a8", "\u1e00"-"\u1e9b", "\u1ea0"-"\u1ef9", "\u1f00"-"\u1f15", "\u1f18"-"\u1f1d", "\u1f20"-"\u1f45", "\u1f48"-"\u1f4d", "\u1f50"-"\u1f57", "\u1f59", "\u1f5b", "\u1f5d", "\u1f5f"-"\u1f7d", "\u1f80"-"\u1fb4", "\u1fb6"-"\u1fbc", "\u1fbe", "\u1fc2"-"\u1fc4", "\u1fc6"-"\u1fcc", "\u1fd0"-"\u1fd3", "\u1fd6"-"\u1fdb", "\u1fe0"-"\u1fec", "\u1ff2"-"\u1ff4", "\u1ff6"-"\u1ffc", "\u203f"-"\u2040", "\u207f", "\u20a0"-"\u20af", "\u2102", "\u2107", "\u210a"-"\u2113", "\u2115", "\u2119"-"\u211d", "\u2124", "\u2126", "\u2128", "\u212a"-"\u212d", "\u212f"-"\u2131", "\u2133"-"\u2139", "\u2160"-"\u2183", "\u3005"-"\u3007", "\u3021"-"\u3029", "\u3031"-"\u3035", "\u3038"-"\u303a", "\u3041"-"\u3094", "\u309d"-"\u309e", "\u30a1"-"\u30fe", "\u3105"-"\u312c", "\u3131"-"\u318e", "\u31a0"-"\u31b7", "\u3400"-"\u4db5", "\u4e00"-"\u9fa5", "\ua000"-"\ua48c", "\uac00"-"\ud7a3", "\uf900"-"\ufa2d", "\ufb00"-"\ufb06", "\ufb13"-"\ufb17", "\ufb1d", "\ufb1f"-"\ufb28", "\ufb2a"-"\ufb36", "\ufb38"-"\ufb3c", "\ufb3e", "\ufb40"-"\ufb41", "\ufb43"-"\ufb44", "\ufb46"-"\ufbb1", "\ufbd3"-"\ufd3d", "\ufd50"-"\ufd8f", "\ufd92"-"\ufdc7", "\ufdf0"-"\ufdfb", "\ufe33"-"\ufe34", "\ufe4d"-"\ufe4f", "\ufe69", "\ufe70"-"\ufe72", "\ufe74", "\ufe76"-"\ufefc", "\uff04", "\uff21"-"\uff3a", "\uff3f", "\uff41"-"\uff5a", "\uff65"-"\uffbe", "\uffc2"-"\uffc7", "\uffca"-"\uffcf", "\uffd2"-"\uffd7", "\uffda"-"\uffdc", "\uffe0"-"\uffe1", "\uffe5"-"\uffe6" ] > } TOKEN : { < ALNUM_PART : [ "!", "$", "0"-"9", "A"-"Z", "_", "a"-"z", // Javaport: All chars for which Character.isUnicodeIdentifierPart(char) is true. // Sadly, C++ hasn't kept up with Unicode. Though more recent, this too isn't // up to the latest Unicode, which of course, is subject to change without notice. "\u007f"-"\u009f", "\u00a2"-"\u00a5", "\u00aa", "\u00b5", "\u00ba", "\u00c0"-"\u00d6", "\u00d8"-"\u00f6", "\u00f8"-"\u021f", "\u0222"-"\u0233", "\u0250"-"\u02ad", "\u02b0"-"\u02b8", "\u02bb"-"\u02c1", "\u02d0"-"\u02d1", "\u02e0"-"\u02e4", "\u02ee", "\u0300"-"\u034e", "\u0360"-"\u0362", "\u037a", "\u0386", "\u0388"-"\u038a", "\u038c", "\u038e"-"\u03a1", "\u03a3"-"\u03ce", "\u03d0"-"\u03d7", "\u03da"-"\u03f3", "\u0400"-"\u0481", "\u0483"-"\u0486", "\u048c"-"\u04c4", "\u04c7"-"\u04c8", "\u04cb"-"\u04cc", "\u04d0"-"\u04f5", "\u04f8"-"\u04f9", "\u0531"-"\u0556", "\u0559", "\u0561"-"\u0587", "\u0591"-"\u05a1", "\u05a3"-"\u05b9", "\u05bb"-"\u05bd", "\u05bf", "\u05c1"-"\u05c2", "\u05c4", "\u05d0"-"\u05ea", "\u05f0"-"\u05f2", "\u0621"-"\u063a", "\u0640"-"\u0655", "\u0660"-"\u0669", "\u0670"-"\u06d3", "\u06d5"-"\u06dc", "\u06df"-"\u06e8", "\u06ea"-"\u06ed", "\u06f0"-"\u06fc", "\u070f"-"\u072c", "\u0730"-"\u074a", "\u0780"-"\u07b0", "\u0901"-"\u0903", "\u0905"-"\u0939", "\u093c"-"\u094d", "\u0950"-"\u0954", "\u0958"-"\u0963", "\u0966"-"\u096f", "\u0981"-"\u0983", "\u0985"-"\u098c", "\u098f"-"\u0990", "\u0993"-"\u09a8", "\u09aa"-"\u09b0", "\u09b2", "\u09b6"-"\u09b9", "\u09bc", "\u09be"-"\u09c4", "\u09c7"-"\u09c8", "\u09cb"-"\u09cd", "\u09d7", "\u09dc"-"\u09dd", "\u09df"-"\u09e3", "\u09e6"-"\u09f3", "\u0a02", "\u0a05"-"\u0a0a", "\u0a0f"-"\u0a10", "\u0a13"-"\u0a28", "\u0a2a"-"\u0a30", "\u0a32"-"\u0a33", "\u0a35"-"\u0a36", "\u0a38"-"\u0a39", "\u0a3c", "\u0a3e"-"\u0a42", "\u0a47"-"\u0a48", "\u0a4b"-"\u0a4d", "\u0a59"-"\u0a5c", "\u0a5e", "\u0a66"-"\u0a74", "\u0a81"-"\u0a83", "\u0a85"-"\u0a8b", "\u0a8d", "\u0a8f"-"\u0a91", "\u0a93"-"\u0aa8", "\u0aaa"-"\u0ab0", "\u0ab2"-"\u0ab3", "\u0ab5"-"\u0ab9", "\u0abc"-"\u0ac5", "\u0ac7"-"\u0ac9", "\u0acb"-"\u0acd", "\u0ad0", "\u0ae0", "\u0ae6"-"\u0aef", "\u0b01"-"\u0b03", "\u0b05"-"\u0b0c", "\u0b0f"-"\u0b10", "\u0b13"-"\u0b28", "\u0b2a"-"\u0b30", "\u0b32"-"\u0b33", "\u0b36"-"\u0b39", "\u0b3c"-"\u0b43", "\u0b47"-"\u0b48", "\u0b4b"-"\u0b4d", "\u0b56"-"\u0b57", "\u0b5c"-"\u0b5d", "\u0b5f"-"\u0b61", "\u0b66"-"\u0b6f", "\u0b82"-"\u0b83", "\u0b85"-"\u0b8a", "\u0b8e"-"\u0b90", "\u0b92"-"\u0b95", "\u0b99"-"\u0b9a", "\u0b9c", "\u0b9e"-"\u0b9f", "\u0ba3"-"\u0ba4", "\u0ba8"-"\u0baa", "\u0bae"-"\u0bb5", "\u0bb7"-"\u0bb9", "\u0bbe"-"\u0bc2", "\u0bc6"-"\u0bc8", "\u0bca"-"\u0bcd", "\u0bd7", "\u0be7"-"\u0bef", "\u0c01"-"\u0c03", "\u0c05"-"\u0c0c", "\u0c0e"-"\u0c10", "\u0c12"-"\u0c28", "\u0c2a"-"\u0c33", "\u0c35"-"\u0c39", "\u0c3e"-"\u0c44", "\u0c46"-"\u0c48", "\u0c4a"-"\u0c4d", "\u0c55"-"\u0c56", "\u0c60"-"\u0c61", "\u0c66"-"\u0c6f", "\u0c82"-"\u0c83", "\u0c85"-"\u0c8c", "\u0c8e"-"\u0c90", "\u0c92"-"\u0ca8", "\u0caa"-"\u0cb3", "\u0cb5"-"\u0cb9", "\u0cbe"-"\u0cc4", "\u0cc6"-"\u0cc8", "\u0cca"-"\u0ccd", "\u0cd5"-"\u0cd6", "\u0cde", "\u0ce0"-"\u0ce1", "\u0ce6"-"\u0cef", "\u0d02"-"\u0d03", "\u0d05"-"\u0d0c", "\u0d0e"-"\u0d10", "\u0d12"-"\u0d28", "\u0d2a"-"\u0d39", "\u0d3e"-"\u0d43", "\u0d46"-"\u0d48", "\u0d4a"-"\u0d4d", "\u0d57", "\u0d60"-"\u0d61", "\u0d66"-"\u0d6f", "\u0d82"-"\u0d83", "\u0d85"-"\u0d96", "\u0d9a"-"\u0db1", "\u0db3"-"\u0dbb", "\u0dbd", "\u0dc0"-"\u0dc6", "\u0dca", "\u0dcf"-"\u0dd4", "\u0dd6", "\u0dd8"-"\u0ddf", "\u0df2"-"\u0df3", "\u0e01"-"\u0e3a", "\u0e3f"-"\u0e4e", "\u0e50"-"\u0e59", "\u0e81"-"\u0e82", "\u0e84", "\u0e87"-"\u0e88", "\u0e8a", "\u0e8d", "\u0e94"-"\u0e97", "\u0e99"-"\u0e9f", "\u0ea1"-"\u0ea3", "\u0ea5", "\u0ea7", "\u0eaa"-"\u0eab", "\u0ead"-"\u0eb9", "\u0ebb"-"\u0ebd", "\u0ec0"-"\u0ec4", "\u0ec6", "\u0ec8"-"\u0ecd", "\u0ed0"-"\u0ed9", "\u0edc"-"\u0edd", "\u0f00", "\u0f18"-"\u0f19", "\u0f20"-"\u0f29", "\u0f35", "\u0f37", "\u0f39", "\u0f3e"-"\u0f47", "\u0f49"-"\u0f6a", "\u0f71"-"\u0f84", "\u0f86"-"\u0f8b", "\u0f90"-"\u0f97", "\u0f99"-"\u0fbc", "\u0fc6", "\u1000"-"\u1021", "\u1023"-"\u1027", "\u1029"-"\u102a", "\u102c"-"\u1032", "\u1036"-"\u1039", "\u1040"-"\u1049", "\u1050"-"\u1059", "\u10a0"-"\u10c5", "\u10d0"-"\u10f6", "\u1100"-"\u1159", "\u115f"-"\u11a2", "\u11a8"-"\u11f9", "\u1200"-"\u1206", "\u1208"-"\u1246", "\u1248", "\u124a"-"\u124d", "\u1250"-"\u1256", "\u1258", "\u125a"-"\u125d", "\u1260"-"\u1286", "\u1288", "\u128a"-"\u128d", "\u1290"-"\u12ae", "\u12b0", "\u12b2"-"\u12b5", "\u12b8"-"\u12be", "\u12c0", "\u12c2"-"\u12c5", "\u12c8"-"\u12ce", "\u12d0"-"\u12d6", "\u12d8"-"\u12ee", "\u12f0"-"\u130e", "\u1310", "\u1312"-"\u1315", "\u1318"-"\u131e", "\u1320"-"\u1346", "\u1348"-"\u135a", "\u1369"-"\u1371", "\u13a0"-"\u13f4", "\u1401"-"\u166c", "\u166f"-"\u1676", "\u1681"-"\u169a", "\u16a0"-"\u16ea", "\u1780"-"\u17d3", "\u17db", "\u17e0"-"\u17e9", "\u180b"-"\u180e", "\u1810"-"\u1819", "\u1820"-"\u1877", "\u1880"-"\u18a9", "\u1e00"-"\u1e9b", "\u1ea0"-"\u1ef9", "\u1f00"-"\u1f15", "\u1f18"-"\u1f1d", "\u1f20"-"\u1f45", "\u1f48"-"\u1f4d", "\u1f50"-"\u1f57", "\u1f59", "\u1f5b", "\u1f5d", "\u1f5f"-"\u1f7d", "\u1f80"-"\u1fb4", "\u1fb6"-"\u1fbc", "\u1fbe", "\u1fc2"-"\u1fc4", "\u1fc6"-"\u1fcc", "\u1fd0"-"\u1fd3", "\u1fd6"-"\u1fdb", "\u1fe0"-"\u1fec", "\u1ff2"-"\u1ff4", "\u1ff6"-"\u1ffc", "\u200c"-"\u200f", "\u202a"-"\u202e", "\u203f"-"\u2040", "\u206a"-"\u206f", "\u207f", "\u20a0"-"\u20af", "\u20d0"-"\u20dc", "\u20e1", "\u2102", "\u2107", "\u210a"-"\u2113", "\u2115", "\u2119"-"\u211d", "\u2124", "\u2126", "\u2128", "\u212a"-"\u212d", "\u212f"-"\u2131", "\u2133"-"\u2139", "\u2160"-"\u2183", "\u3005"-"\u3007", "\u3021"-"\u302f", "\u3031"-"\u3035", "\u3038"-"\u303a", "\u3041"-"\u3094", "\u3099"-"\u309a", "\u309d"-"\u309e", "\u30a1"-"\u30fe", "\u3105"-"\u312c", "\u3131"-"\u318e", "\u31a0"-"\u31b7", "\u3400"-"\u4db5", "\u4e00"-"\u9fa5", "\ua000"-"\ua48c", "\uac00"-"\ud7a3", "\uf900"-"\ufa2d", "\ufb00"-"\ufb06", "\ufb13"-"\ufb17", "\ufb1d"-"\ufb28", "\ufb2a"-"\ufb36", "\ufb38"-"\ufb3c", "\ufb3e", "\ufb40"-"\ufb41", "\ufb43"-"\ufb44", "\ufb46"-"\ufbb1", "\ufbd3"-"\ufd3d", "\ufd50"-"\ufd8f", "\ufd92"-"\ufdc7", "\ufdf0"-"\ufdfb", "\ufe20"-"\ufe23", "\ufe33"-"\ufe34", "\ufe4d"-"\ufe4f", "\ufe69", "\ufe70"-"\ufe72", "\ufe74", "\ufe76"-"\ufefc", "\ufeff", "\uff04", "\uff10"-"\uff19", "\uff21"-"\uff3a", "\uff3f", "\uff41"-"\uff5a", "\uff65"-"\uffbe", "\uffc2"-"\uffc7", "\uffca"-"\uffcf", "\uffd2"-"\uffd7", "\uffda"-"\uffdc", "\uffe0"-"\uffe1", "\uffe5"-"\uffe6", "\ufff9"-"\ufffb" ] > } TOKEN : { /* NO MATCH */ < ERROR : ~[] > } void FormCalculation() : { } { { // // No expressions parsed: emit a "no expression encountered" error. // MsgFormatPos sErr = new MsgFormatPos(ResId.FC_ERR_NO_EXPR); CalcSymbol oSym = new CalcSymbol(sErr.toString(), true, 0, 0); mStack.push(oSym); } | { yyError(ResId.FC_ERR_SYNTAX); } | { // // Generate code for entry of outermost scope // provided we've not cached anything yet. // if (! mbInSaveMode || mnSavedDecl == 0) { generate(Instruction.gEnter); generate(Integer.valueOf(1)); } moScope.setActive(1); setLine(); } ExpressionList() { yyTrace("FormCalculation: ExpressionList"); // // Generate code for exit of outermost scope // and stoppage of this execution thread. // generate(Instruction.gExit); generate(Integer.valueOf(moScope.exit())); generate(Instruction.gStop); } } int ExpressionList() : { int $$; } { $$ = Expression() { yyTrace("ExpressionList: Expression"); } ( LOOKAHEAD(Expression()) { generate(Instruction.gDeref); setLine(); } $$ = Expression() { yyTrace("ExpressionList: ExpressionList Expression"); // // Generate code for evaluation of expression list. // generate(Instruction.gList); } )* { return $$; } } int Var() : { int $$ = moCode.generate(); } { { if (mbInVarDeclaration) yyError(ResId.FC_ERR_SYNTAX); mbInVarDeclaration = true; if (moScope.isGlobal()) { // // Generate code for labelling of global variable. // $$ = generate(Instruction.gGbl); generate(Instruction.gStop); } } { return $$; } } CalcSymbol Variable() : { String $1; } { $1 = Identifier() { yyTrace("Variable: Identifier"); setLine(); CalcSymbol oSym = null; String sParam = msFunc; sParam += $1; if ((oSym = varExists($1, moScope)) != null) { // IsGlobal always returns false? Can we ever have global script? if (! moScope.isGlobal() || ! mbAllowDups) yyError(ResId.FC_ERR_VAR_DUP); else { // // Generate code for loading value of variable. // generate(Instruction.gLoad); generate(oSym); } } // watson bug 1352985 if we have params don't call VarExists else if (mbInFuncParameters) { // // Set attributes of this formal parameter's symbol table entry. // oSym = moData.install(sParam); oSym.setType(CalcSymbol.TypeParameter); oSym.setStore(CalcSymbol.StoreFroz | CalcSymbol.StorePrelim); } else if (mbInFuncDeclaration && (oSym = varExists(sParam, moScope)) != null) { // IsGlobal always returns false? Can we ever have global script? if (! moScope.isGlobal() || ! mbAllowDups) yyError(ResId.FC_ERR_VAR_DUP); else { // // Generate code for loading value of variable. // generate(Instruction.gLoad); generate(oSym); } } else if (mbInForeachLoop || mbInLoopDeclaration || mbInVarDeclaration) { // // Set attributes of this variable's symbol table entry. // oSym = moData.install($1); oSym.setType(CalcSymbol.TypeVariable); oSym.setScope(moScope.getScope()); oSym.setStringValue(""); if (mbInFuncDeclaration) oSym.setStore(CalcSymbol.StoreFroz | CalcSymbol.StorePrelim); else oSym.setStore(CalcSymbol.StorePerm | CalcSymbol.StorePrelim); // // Generate code for loading value of variable. // generate(Instruction.gLoad); generate(oSym); } return oSym; } } int EndVar() : { } { { mbInVarDeclaration = false; return moCode.generate(); } } int Func() : { int $$; } { { if (mbInFuncDeclaration) yyError(ResId.FC_ERR_SYNTAX); if (! moScope.isGlobal()) yyError(ResId.FC_ERR_FUNC_DECL); mbInFuncDeclaration = true; msFunc = ""; // // Generate code for declaration of function. // $$ = generate(Instruction.gFunc); generate(Instruction.gStop); generate(Instruction.gStop); return $$; } } CalcSymbol Function() : { CalcSymbol $$; String $1; } { $1 = Identifier() { yyTrace("Function: Identifier"); // // Upcase the identifier, and // StringBuilder sFunction = new StringBuilder($1); for (int i = 0; i < sFunction.length(); i++) { char c = sFunction.charAt(i); if ('a' <= c && c <= 'z') sFunction.setCharAt(i, (char) (c & ~0x20)); } // // Check if its the name of a builtin function. // CalcSymbol oSym = mBuiltin.lookup(sFunction.toString()); // // If not Then check if its the name of a user-defined function. // if (oSym == null) oSym = moData.lookup($1); if (oSym != null) { if (oSym.getType() == CalcSymbol.TypeBuiltin) yyError(ResId.FC_ERR_FUNC_USED); if (oSym.getType() == CalcSymbol.TypeFunction && ! mbAllowDups) yyError(ResId.FC_ERR_FUNC_DUP); msFunc = oSym.getName(); } else { msFunc = $1; // // Set attributes of this function's symbol table entry. // oSym = moData.install($1); oSym.setType(CalcSymbol.TypeFunction); oSym.setStore(CalcSymbol.StoreFroz | CalcSymbol.StorePrelim); oSym.setAddr(0); oSym.setCntValue(0); } msFunc += '`'; $$ = oSym; // // Generate code for entry to new scope. // generate(Instruction.gEnter); generate(Integer.valueOf(moScope.enter())); } { return $$; } } int Parameters() : { int $$; } { { mbInFuncParameters = true; } ( $$ = ParameterList() | { yyTrace("ParameterList:"); $$ = 0; } ) { mbInFuncParameters = false; return $$; } } int ParameterList() : { int $$; CalcSymbol $1, $3; } { $1 = Variable() { yyTrace("ParameterList: Variable"); $$ = 1; // // Set attribute of this formal parameter's symbol table entry. // if ($1 != null) $1.setIdxValue($$); } ( $3 = Variable() { yyTrace("ParameterList: ParameterList , Variable"); $$ += 1; // // Set attribute of this formal parameter's symbol table entry. // if ($3 != null) $3.setIdxValue($$); } )* { return $$; } } int EndFunc() : { int $$; } { { mbInFuncDeclaration = false; msFunc = ""; // // Generate code for exit of current scope. // generate(Instruction.gExit); generate(Integer.valueOf(moScope.exit())); // // Generate code for return from function call. // $$ = generate(Instruction.gRet); return $$; } } int Expression() : { int $$; } { ( $$ = DeclarationExpression() { yyTrace("Expression: DeclarationExpression"); } | LOOKAHEAD(AssignmentExpression()) $$ = AssignmentExpression() { yyTrace("Expression: AssignmentSimpleExpression"); } | $$ = BreakExpression() { yyTrace("Expression: ContinueExpression"); } | $$ = ContinueExpression() { yyTrace("Expression: ContinueExpression"); } | $$ = BlockExpression() { yyTrace("Expression: BlockExpression"); } | $$ = ForeachExpression() { yyTrace("Expression: ForeachExpression"); } | $$ = ForExpression() { yyTrace("Expression: ForExpression"); } | $$ = WhileExpression() { yyTrace("Expression: WhileExpression"); } | LOOKAHEAD(IfExpression()) $$ = IfExpression() { yyTrace("Expression: IfExpression"); } | $$ = SimpleExpression() { yyTrace("Expression: SimpleExpression"); } ) { return $$; } } int DeclarationExpression() : { int $$; int $1, $3, $5, $10; CalcSymbol $2; int nDecl; } { LOOKAHEAD(3) $1 = Var() Variable() SimpleExpression() EndVar() { yyTrace("DeclarationExpression: Var Variable = SimpleExpression"); // // Generate code for assignment to variable. // generate(Instruction.gAsgn); // // Backfix address part of any Gbl instruction. // Address is the relative offset within // instruction memory of EndVar - Var. // if (moScope.isGlobal()) { $5 = moCode.generate(); nDecl = moCode.getCodeStart() + $1; moCode.moCodeBase[nDecl + 1] = Integer.valueOf($5 - $1); // endvar part } $$ = $1; return $$; } | $1 = Var() Variable() EndVar() { yyTrace("DeclarationExpression: Var Variable"); // // Generate code for loading of the default value. // This symbol lives in instruction memory. // CalcSymbol oSym = new CalcSymbol(""); oSym.setStore(CalcSymbol.StorePerm); generate(Instruction.gLoad); generate(oSym); // // Generate code for assignment to variable. // generate(Instruction.gAsgn); // // Backfix address part of any Gbl instruction. // Address is the relative offset within // instruction memory of EndVar - Var. // if (moScope.isGlobal()) { $3 = moCode.generate(); nDecl = moCode.getCodeStart() + $1; moCode.moCodeBase[nDecl + 1] = Integer.valueOf($3 - $1); // endvar part } $$ = $1; return $$; } | $1 = Func() $2 = Function() $5 = Parameters() ExpressionList() $10 = EndFunc() { yyTrace("DeclarationExpression: Func Function ( ParameterList ) Do EndFunc"); // // Backfix name and address parts of Func instruction. // Name is a symbol containing the functions' name. // This symbol lives in instruction memory. // Address is the relative of offset within // instruction memory of EndFunc - Func. // nDecl = moCode.getCodeStart() + $1; moCode.moCodeBase[nDecl + 1] = $2; // function moCode.moCodeBase[nDecl + 2] = Integer.valueOf($10 - $1 + 1); // endfunc part // // Set attributes of this function's symbol table entry. // if ($2.getType() == CalcSymbol.TypeFunction) { $2.setAddr($1); $2.setCntValue($5); } $$ = $1; return $$; } } int AssignmentExpression() : { int $$; int $1; } { $1 = Accessor() SimpleExpression() { yyTrace("AssignmentExpression: Accessor = SimpleExpression"); // // Generate code for assignment to accessor. // generate(Instruction.gAsgn); $$ = $1; return $$; } } int BlockExpression() : { int $$; } { { // // Generate code for entry of new scope of block expression. // $$ = generate(Instruction.gEnter); generate(Integer.valueOf(moScope.enter())); } ExpressionList() { yyTrace("BlockExpression: Do ExpressionList End"); // // Generate code for exit of current scope // at end of block expression. // $$ = generate(Instruction.gExit); generate(Integer.valueOf(moScope.exit())); return $$; } } int Foreach() : { int $$; } { { // // Generate code for foreach instruction. // $$ = mnLoopOffset = generate(Instruction.gForeach); generate(Instruction.gStop); generate(Instruction.gStop); generate(Instruction.gStop); generate(Instruction.gStop); // // Generate code for entry of new scope. // generate(Instruction.gEnter); generate(Integer.valueOf(moScope.enter())); mbInForeachLoop = true; } Variable() { // // Generate code for assignment of foreach variable // and stoppage of this execution thread. // generate(Instruction.gAsgn2); generate(Instruction.gStop); return $$; } } int In() : { } { { return moCode.generate(); } } int Arguments() : { int $$; } { ( $$ = ArgumentList() | { yyTrace("ArgumentList:"); if (mbInForeachLoop) yyError(ResId.FC_ERR_LOOP_ARGS); $$ = 0; } ) { return $$; } } int ArgumentList() : { int $$; } { SimpleExpression() { yyTrace("ArgumentList: SimpleExpression"); generate(Instruction.gNoop); $$ = 1; } ( SimpleExpression() { yyTrace("ArgumentList: ArgumentList , SimpleExpression"); $$ += 1; } )* { return $$; } } int Do() : { int $$; } { { // // Generate code for stoppage of this execution thread. // $$ = generate(Instruction.gStop); // // Generate code for entry of new scope of while expression // or function declaration. // if (! mbInLoopDeclaration && ! mbInForeachLoop) { generate(Instruction.gEnter); generate(Integer.valueOf(moScope.enter())); } return $$; } } int EndFor() : { int $$; } { { // // Generate code for stoppage of this execution thread. // generate(Instruction.gStop); // // Generate code for exit of current scope // at end of for and foreach expressions. // $$ = generate(Instruction.gExit); generate(Integer.valueOf(moScope.exit())); return $$; } } int ForeachExpression() : { int $$; int $1, $2, $4, $6, $9; } { $1 = Foreach() $2 = In() $4 = Arguments() { if ($4 == 0 && mbInForeachLoop) yyError(ResId.FC_ERR_LOOP_ARGS); } $6 = Do() { mbInForeachLoop = false; } ExpressionList() $9 = EndFor() { yyTrace("ForeachExpression: Foreach Do EndFor"); // // Backfix argument count and address parts of // a Foreach instruction. // int nFor = moCode.getCodeStart() + $1; moCode.moCodeBase[nFor + 1] = Integer.valueOf($4); // arg count moCode.moCodeBase[nFor + 2] = Integer.valueOf($2 - $1); // list part moCode.moCodeBase[nFor + 3] = Integer.valueOf($6 - $1 + 1); // do part moCode.moCodeBase[nFor + 4] = Integer.valueOf($9 - $1); // endfor part $$ = $1; return $$; } } int For() : { int $$; int $2; } { { // // Generate code for for instruction. // $2 = mnLoopOffset = generate(Instruction.gFor); generate(Instruction.gStop); generate(Instruction.gStop); generate(Instruction.gStop); generate(Instruction.gStop); // // Generate code for entry of new scope. // generate(Instruction.gEnter); generate(Integer.valueOf(moScope.enter())); mbInLoopDeclaration = true; } Variable() SimpleExpression() { // // Generate code for assignment of for loop variable // and stoppage of this execution thread. // generate(Instruction.gAsgn); generate(Instruction.gStop); $$ = $2; return $$; } } int To() : { int $$; int $2; } { { mbInDowntoLoop = false; $2 = moCode.generate(); } SimpleExpression() { // // Generate code for less_than_or_equal instruction // and stoppage of this execution thread. // generate(Instruction.gLe); generate(Instruction.gStop); $$ = $2; return $$; } | { mbInDowntoLoop = true; $2 = moCode.generate(); } SimpleExpression() { // // Generate code for greater_than_or_equal instruction // and stoppage of this execution thread. // generate(Instruction.gGe); generate(Instruction.gStop); $$ = $2; return $$; } } int Step() : { int $$; int $2; int nForVar; } { { // // Generate code for twice loading of for loop variable. // nForVar = moCode.getCodeStart() + mnLoopOffset + 8; $2 = generate(Instruction.gLoad); generate(moCode.moCodeBase[nForVar]); generate(Instruction.gLoad); generate(moCode.moCodeBase[nForVar]); } SimpleExpression() { // // Generate code for sub/add instruction followed // by assignment to for loop variable. // if (mbInDowntoLoop) generate(Instruction.gSub); else generate(Instruction.gAdd); generate(Instruction.gAsgn); $$ = $2; return $$; } | { // // Generate code for twice loading of for loop variable. // nForVar = moCode.getCodeStart() + mnLoopOffset + 8; $$ = generate(Instruction.gLoad); generate(moCode.moCodeBase[nForVar]); generate(Instruction.gLoad); generate(moCode.moCodeBase[nForVar]); // // Generate code for loading default step value. // CalcSymbol oSym = new CalcSymbol(1); oSym.setStore(CalcSymbol.StorePerm); generate(Instruction.gLoad); generate(oSym); // // Generate code for sub/add instruction followed // by assignment to for loop variable. // if (mbInDowntoLoop) generate(Instruction.gSub); else generate(Instruction.gAdd); generate(Instruction.gAsgn); return $$; } } int ForExpression() : { int $$; int $1, $2, $3, $4, $7; } { $1 = For() $2 = To() $3 = Step() $4 = Do() { mbInLoopDeclaration = false; } ExpressionList() $7 = EndFor() { yyTrace("ForExpression: For Do EndFor"); // // Backfix address parts of For a instruction. // int nFor = moCode.getCodeStart() + $1; moCode.moCodeBase[nFor + 1] = Integer.valueOf($2 - $1); // to part moCode.moCodeBase[nFor + 2] = Integer.valueOf($3 - $1); // step part moCode.moCodeBase[nFor + 3] = Integer.valueOf($4 - $1 + 1); // do part moCode.moCodeBase[nFor + 4] = Integer.valueOf($7 - $1); // endfor part $$ = $1; return $$; } } int While() : { int $$; } { { // // Generate code for while instruction. // $$ = mnLoopOffset = generate(Instruction.gWhile); generate(Instruction.gStop); generate(Instruction.gStop); return $$; } } int Condition() : { int $$; int $2; } { $2 = SimpleExpression() { yyTrace("Condition: ( SimpleExpression )"); $$ = $2; return $$; } } int EndWhile() : { int $$; } { { // // Generate code for stoppage of this execution thread, // and for exit of current scope. // $$ = generate(Instruction.gStop); generate(Instruction.gExit); generate(Integer.valueOf(moScope.exit())); return $$; } } int WhileExpression() : { int $$; int $1, $3, $5; } { $1 = While() Condition() $3 = Do() ExpressionList() $5 = EndWhile() { yyTrace("WhileExpression: While Do EndWhile"); // // Backfix address parts of a While instruction. // int nWhile = moCode.getCodeStart() + $1; moCode.moCodeBase[nWhile + 1] = Integer.valueOf($3 - $1 + 1); // do part moCode.moCodeBase[nWhile + 2] = Integer.valueOf($5 - $1 + 1); // endwhile part $$ = $1; return $$; } } int If() : { int $$; } { { // // Generate code for if instruction. // $$ = generate(Instruction.gIf); generate(Instruction.gStop); generate(Instruction.gStop); generate(Instruction.gStop); return $$; } } int Then() : { int $$; } { { // // Generate code for stoppage of preceeding // execution thread and entry to new scope. // $$ = generate(Instruction.gStop); generate(Instruction.gEnter); generate(Integer.valueOf(moScope.enter())); setLine(); return $$; } } int Elif() : { int $$; } { { // // Generate code for exit of current scope. // generate(Instruction.gExit); generate(Integer.valueOf(moScope.exit())); // // Generate code for stoppage of preceeding execution thread. // $$ = generate(Instruction.gStop); // // Generate code for if instruction. // generate(Instruction.gIf); generate(Instruction.gStop); generate(Instruction.gStop); generate(Instruction.gStop); return $$; } } int Else() : { int $$; } { { // // Generate code for exit of current scope. // generate(Instruction.gExit); generate(Integer.valueOf( moScope.exit())); // // Generate code for stoppage of preceeding execution thread. // $$ = generate(Instruction.gStop); // // Generate code for entry of new scope. // generate(Instruction.gEnter); generate(Integer.valueOf(moScope.enter())); return $$; } } int EndIf() : { int $$; } { { // // Generate code for exit of current scope. // generate(Instruction.gExit); generate(Integer.valueOf(moScope.exit())); // // Generate code for stoppage of preceeding execution thread. // $$ = generate(Instruction.gStop); return $$; } } int IfExpression() : { int $1, $3, $5 = -1, $7; } { LOOKAHEAD(If() Condition() Then() ExpressionList() ElifExpression()) $1 = If() Condition() $3 = Then() ExpressionList() $5 = ElifExpression() { yyTrace("IfExpression: If Then ElseIf"); // // Backfix address parts of an If instruction. // int nIf = moCode.getCodeStart() + $1; int nElif = moCode.getCodeStart() + $5 + 1; assert(moCode.moCodeBase[nElif + 3] instanceof Integer); nElif = ((Integer) moCode.moCodeBase[nElif + 3]).intValue(); moCode.moCodeBase[nIf + 1] = Integer.valueOf($3 - $1 + 1); // then part moCode.moCodeBase[nIf + 2] = Integer.valueOf($5 - $1 + 1); // else part moCode.moCodeBase[nIf + 3] = Integer.valueOf(nElif + $5 - $1 + 2); // endif part return $1; } | $1 = If() Condition() $3 = Then() ExpressionList() [ $5 = Else() ExpressionList() ] $7 = EndIf() { yyTrace("IfExpression: If Then Else Endif"); int nIf = moCode.getCodeStart() + $1; moCode.moCodeBase[nIf + 1] = Integer.valueOf($3 - $1 + 1); // then part if ($5 >= 0) moCode.moCodeBase[nIf + 2] = Integer.valueOf($5 - $1 + 1); // else part moCode.moCodeBase[nIf + 3] = Integer.valueOf($7 - $1 + 1); // endif part return $1; } } int ElifExpression() : { int $1, $3, $5 = -1, $7; } { LOOKAHEAD(Elif() Condition() Then() ExpressionList() ElifExpression()) $1 = Elif() Condition() $3 = Then() ExpressionList() $5 = ElifExpression() { yyTrace("ElifExpression: Elseif Then Elseif"); // // Backfix address parts of an If instruction. // int nIf = moCode.getCodeStart() + $1 + 1; int nElif = moCode.getCodeStart() + $5 + 1; assert(moCode.moCodeBase[nElif + 3] instanceof Integer); nElif = ((Integer) moCode.moCodeBase[nElif + 3]).intValue(); moCode.moCodeBase[nIf + 1] = Integer.valueOf($3 - $1); // then part moCode.moCodeBase[nIf + 2] = Integer.valueOf($5 - $1); // elseif part moCode.moCodeBase[nIf + 3] = Integer.valueOf(nElif + $5 - $1); // endif part return $1; } | $1 = Elif() Condition() $3 = Then() ExpressionList() [ $5 = Else() ExpressionList() ] $7 = EndIf() { yyTrace("ElifExpression: Elseif Then Else EndIf"); // // Backfix address parts of an If instruction. // int nIf = moCode.getCodeStart() + $1 + 1; moCode.moCodeBase[nIf + 1] = Integer.valueOf($3 - $1); // then part if ($5 >= 0) moCode.moCodeBase[nIf + 2] = Integer.valueOf($5 - $1); // else part moCode.moCodeBase[nIf + 3] = Integer.valueOf($7 - $1); // endif part // // Generate code for stoppage of this execution thread -- an else // clause consisting of an If-Then-Else-Endif expression. // generate(Instruction.gStop); return $1; } } int BreakExpression() : { } { { yyTrace("BreakExpression: Break"); if (mnLoopOffset == 0) yyError(ResId.FC_ERR_LOOP); return generate(Instruction.gBreak); } } int ContinueExpression() : { } { { yyTrace("ContinueExpression: Continue"); if (mnLoopOffset == 0) yyError(ResId.FC_ERR_LOOP); return generate(Instruction.gCont); } } int SimpleExpression() : { int $$; } { $$ = LogicalOrExpression() { yyTrace("LogicalOrExpression: LogicalOrExpression"); return $$; } } int LogicalOrExpression() : { int $$; } { $$ = LogicalAndExpression() { yyTrace("LogicalOrExpression: LogicalAndExpression"); } ( Or() $$ = LogicalAndExpression() { yyTrace("LogicalOrExpression: LogicalOrExpression | LogicalAndExpression"); generate(Instruction.gOr); } )* { return $$; } } int LogicalAndExpression() : { int $$; } { $$ = EqualityExpression() { yyTrace("LogicalAndExpression: EqualityExpression"); } ( And() $$ = EqualityExpression() { yyTrace("LogicalAndExpression: LogicalAndExpression & EqualityExpression"); generate(Instruction.gAnd); } )* { return $$; } } int EqualityExpression() : { int $$; } { $$ = RelationalExpression() { yyTrace("EqualityExpression: RelationalExpression"); } ( Eq() $$ = RelationalExpression() { yyTrace("EqualityExpression: EqualityExpression == RelationalExpression"); generate(Instruction.gEq); } | Ne() $$ = RelationalExpression() { yyTrace("EqualityExpression: EqualityExpression <> RelationalExpression"); generate(Instruction.gNe); } )* { return $$; } } int RelationalExpression() : { int $$; } { $$ = AdditiveExpression() { yyTrace("RelationalExpression: AdditiveExpression"); } ( Gt() $$ = AdditiveExpression() { yyTrace("RelationalExpression: RelationalExpression > AdditiveExpression"); generate(Instruction.gGt); } | Ge() $$ = AdditiveExpression() { yyTrace("RelationalExpression: RelationalExpression >= AdditiveExpression"); generate(Instruction.gGe); } | Lt() $$ = AdditiveExpression() { yyTrace("RelationalExpression: RelationalExpression < AdditiveExpression"); generate(Instruction.gLt); } | Le() $$ = AdditiveExpression() { yyTrace("RelationalExpression: RelationalExpression <= AdditiveExpression"); generate(Instruction.gLe); } )* { return $$; } } int AdditiveExpression() : { int $$; Token $1; } { $$ = MultiplicativeExpression() { yyTrace("AdditiveExpression: MultiplicativeExpression"); } ( LOOKAHEAD( | ) ( $1 = | $1 = ) $$ = MultiplicativeExpression() { yyTrace("AdditiveExpression: AdditiveExpression - MultiplicativeExpression"); generate($1.kind == PLUS ? Instruction.gAdd : Instruction.gSub); } )* { return $$; } } int MultiplicativeExpression() : { int $$; } { $$ = UnaryExpression() { yyTrace("MultiplicativeExpression: UnaryExpression"); } ( $$ = UnaryExpression() { yyTrace("MultiplicativeExpression: MultiplicativeExpression * UnaryExpression"); generate(Instruction.gMul); } |
$$ = UnaryExpression() { yyTrace("MultiplicativeExpression: MultiplicativeExpression / UnaryExpression"); generate(Instruction.gDiv); } )* { return $$; } } int UnaryExpression() : { int $$; int $1, $2; } { $1 = PrimaryExpression() { yyTrace("UnaryExpression: PrimaryExpression"); $$ = $1; return $$; } | $2 = UnaryExpression() { yyTrace("UnaryExpression: + UnaryExpression"); generate(Instruction.gUplus); $$ = $2; return $$; } | $2 = UnaryExpression() { yyTrace("UnaryExpression: - UnaryExpression"); generate(Instruction.gUminus); $$ = $2; return $$; } | $2 = UnaryExpression() { yyTrace("UnaryExpression: not UnaryExpression"); generate(Instruction.gNot); $$ = $2; return $$; } } int PrimaryExpression() : { int $$; Token string; double value; CalcSymbol oSym; } { Null() { yyTrace("PrimaryExpression: NULL"); // // Generate code for loading a null literal. // This symbol lives in instruction memory. // setLine(); oSym = new CalcSymbol(); oSym.setStore(CalcSymbol.StorePerm); $$ = generate(Instruction.gLoad); generate(oSym); return $$; } | string = { yyTrace("PrimaryExpression: STRING"); // // Generate code for loading a string literal. // setLine(); String s = FormCalcUtil.interpolate(string.image); // // Javaport: not possible to support the legacy behaviour here. // Java strings won't allow it. // if (s == null) yyError(ResId.FC_ERR_SURROGATE); oSym = new CalcSymbol(s); oSym.setStore(CalcSymbol.StorePerm); $$ = generate(Instruction.gLoad); generate((Object) oSym); return $$; } | value = Number() { yyTrace("PrimaryExpression: Number"); // // Generate code for loading a numeric literal. // This symbol lives in instruction memory. // setLine(); oSym = new CalcSymbol(value); oSym.setStore(CalcSymbol.StorePerm); $$ = generate(Instruction.gLoad); generate((Object) oSym); return $$; } | LOOKAHEAD(FunctionCall()) $$ = FunctionCall() { yyTrace("PrimaryExpression: FunctionCall"); return $$; } | $$ = Accessor() { yyTrace("PrimaryExpression: Accessor"); return $$; } | $$ = SimpleExpression() { return $$; } } double Number() : { double $$; Token $1; } { ( $1 = { yyTrace("Number: INTEGER"); } | $1 = { yyTrace("Number: REAL"); } ) { try { $$ = Double.parseDouble($1.image); } catch (NumberFormatException e) { $$ = Double.NaN; } } { return $$; } } int FunctionCall() : { int $$; String $1; int $2, $3, $4; } { $1 = Identifier() { setLine(); $2 = moCode.generate(); } $4 = Arguments() { yyTrace("FunctionCall: Identifier ( ArgumentList )"); // // Upcase the identifier, and // StringBuilder sFunction = new StringBuilder($1); for (int i = 0; i < sFunction.length(); i++) { char c = sFunction.charAt(i); if ('a' <= c && c <= 'z') sFunction.setCharAt(i, (char) (c & ~0x20)); } // // Check if its the name of a builtin function. // CalcSymbol oFuncSym = mBuiltin.lookup(sFunction.toString()); // // If not Then check if its the name of a user-defined function. // if (oFuncSym == null) oFuncSym = moData.lookup($1); // // If neither Then error -- function unknown... // if (oFuncSym == null && ! mbInSyntaxCheckMode) { yyError(ResId.FC_ERR_FUNC_UNKN, $1); } else { // // Generate code for calling a function. // generate(Instruction.gCall); generate($1); generate(Integer.valueOf($4)); } return $2; } | $$ = If() $3 = Arguments() { // Javaport: try moving into IfExpression() yyTrace("FunctionCall: If ( ArgumentList )"); setLine(); // // Generate code for stoppage of this execution thread. // int nStopOffset = generate(Instruction.gStop); // // The IF keyword had caused us to previously generate code // for an if instruction, and in front of all instructions for // the argument list. However, this is the If builtin function, // so instead of backfixing the addresses of the if instruction, // supplant code for an iffunc instruction. It will take care // of evaluating the argument list and invoking the if builtin // function. // int nIf = moCode.getCodeStart() + $$; moCode.moCodeBase[nIf + 0] = Instruction.gIfFunc; moCode.moCodeBase[nIf + 1] = Integer.valueOf($3); moCode.moCodeBase[nIf + 3] = Integer.valueOf(nStopOffset - $$ + 1); // endif part return $$; } } int Accessor() : { int $$; String $1, $3; Method $2; int $5; CalcSymbol oSym; } { $1 = Identifier() { yyTrace("Accessor: Identifier"); oSym = null; // // Is identifier a formal parameter? // if (mbInFuncDeclaration) oSym = moData.lookup((msFunc + $1)); // // No. Is identifier a variable? // if (oSym == null) oSym = moData.lookup($1, moScope); // // No. Then identifier an accessor! // if (oSym == null) { oSym = new CalcSymbol(); oSym.setName($1); oSym.setType(CalcSymbol.TypeAccessor); oSym.setStore(CalcSymbol.StorePerm); } // // Generate code for loading of a formal parameter, // variable or accesssor. // Note: this symbol lives in instruction memory. // $$ = generate(Instruction.gLoad); generate(oSym); } ( ( LOOKAHEAD(DotOp() Identifier() Arguments()) $2 = DotOp() $3 = Identifier() $5 = Arguments() { yyTrace("Accessor: Accessor DotOp Identifier ( ArgumentList )"); // // Generate code for a method call instruction. // generate(Instruction.gForm); generate($3); generate(Integer.valueOf($5)); // // Generate code for dot operator instruction. // $$ = generate($2); } | $2 = DotOp() $3 = Identifier() { yyTrace("Accessor: Accessor DotOp Identifier"); // // Generate accessor symbol from right hand identifier. // oSym = new CalcSymbol(); oSym.setName($3); oSym.setType(CalcSymbol.TypeAccessor); oSym.setStore(CalcSymbol.StorePerm); // // Generate code for loading of identifier. // generate(Instruction.gLoad); generate(oSym); // // Generate code for dot operator instruction. // $$ = generate($2); } | { yyTrace("Accessor: Accessor .* "); $$ = generate(Instruction.gDotstar); } | ( { yyTrace("Accessor: Accessor [ * ]"); // // Generate accessor symbol who's name is '*'. // oSym = new CalcSymbol(); oSym.setName("*"); oSym.setType(CalcSymbol.TypeAccessor); oSym.setStore(CalcSymbol.StorePerm); // // Generate code for loading of accessor. // generate(Instruction.gLoad); generate(oSym); // // Generate code for indexing instruction. // $$ = generate(Instruction.gIndex); } | SimpleExpression() { yyTrace("Accessor: Accessor [ SimpleExpression ]"); $$ = generate(Instruction.gIndex); } ) ) )* { return $$; } } Method DotOp() : { Method $$; } { ( { $$ = Instruction.gDotdot; } | { $$ = Instruction.gDothash; } | { $$ = Instruction.gDot; } ) { return $$; } } String Identifier() : { Token $1; } { ( $1 = | $1 = ) { return $1.image; } } void Or() : { } { | } void And() : { } { | } void Eq() : { } { | } void Ne() : { } { | } void Le() : { } { | } void Lt() : { } { | } void Ge() : { } { | } void Gt() : { } { | } void Null() : { } { | }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy