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

com.adobe.xfa.formcalc.Instruction Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
 * ADOBE CONFIDENTIAL
 *
 * 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 com.adobe.xfa.Obj;
import com.adobe.xfa.ut.MsgFormat;
import com.adobe.xfa.ut.ResId;

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.text.Collator;
import java.util.Locale;

/**
 * The class Instruction defines all the instructions that the
 * FormCalc virtual machine is capable of executing, as a collection
 * of static methods.  Each instruction corresponds to an opcode of
 * this virtual machine.
 *
 * 

An execution path of the virtual machine is just a sequence of * instructions stored in FormCalc's virtual code space. Each sequence * is terminated with an Stop instruction, to represent the end of an * execution path. * *

All instructions have a common interface, consisting of: * a the FormCalc YYPARSENAME. Since the FormCalc * virtual machine is a stack machine, i.e., its fetches its operand(s) * from a runtime stack, and pushes its result back onto the runtime stack, * most instructions are single word instructions. A few instructions, * like Load, In, Out and Call are multi-word instructions -- some of their * operands are stored in the words following the opcode. * Other instructions, like If, For and While, also multi-word instructions, * contain control flow information to the different execution paths * inherent of conditional and iterative instructions. * * @author Mike P. Tardif. * * @exclude from published api. */ public final class Instruction { Instruction() { // empty } /** * A useful constant. Every instruction sequence ends with this instruction. */ static final Method gStop = getDeclaredMethod("Stop"); static final Method gOr = getDeclaredMethod("Or"); static final Method gAnd = getDeclaredMethod("And"); static final Method gEq = getDeclaredMethod("Eq"); static final Method gNe = getDeclaredMethod("Ne"); static final Method gGt = getDeclaredMethod("Gt"); static final Method gGe = getDeclaredMethod("Ge"); static final Method gLt = getDeclaredMethod("Lt"); static final Method gLe = getDeclaredMethod("Le"); static final Method gAdd = getDeclaredMethod("Add"); static final Method gSub = getDeclaredMethod("Sub"); static final Method gMul = getDeclaredMethod("Mul"); static final Method gDiv = getDeclaredMethod("Div"); static final Method gUminus = getDeclaredMethod("Uminus"); static final Method gUplus = getDeclaredMethod("Uplus"); static final Method gNot = getDeclaredMethod("Not"); static final Method gNoop = getDeclaredMethod("Noop"); static final Method gDeref = getDeclaredMethod("Deref"); static final Method gLoad = getDeclaredMethod("Load"); static final Method gGbl = getDeclaredMethod("Gbl"); static final Method gFunc = getDeclaredMethod("Func"); static final Method gCall = getDeclaredMethod("Call"); static final Method gRet = getDeclaredMethod("Ret"); static final Method gForm = getDeclaredMethod("Form"); static final Method gAsgn = getDeclaredMethod("Asgn"); static final Method gAsgn2 = getDeclaredMethod("Asgn2"); static final Method gDot = getDeclaredMethod("Dot"); static final Method gDotdot = getDeclaredMethod("Dotdot"); static final Method gDothash = getDeclaredMethod("Dothash"); static final Method gDotstar = getDeclaredMethod("Dotstar"); static final Method gIndex = getDeclaredMethod("Index"); static final Method gList = getDeclaredMethod("List"); static final Method gForeach = getDeclaredMethod("Foreach"); static final Method gFor = getDeclaredMethod("For"); static final Method gWhile = getDeclaredMethod("While"); static final Method gIf = getDeclaredMethod("If"); static final Method gIfFunc = getDeclaredMethod("IfFunc"); static final Method gBreak = getDeclaredMethod("Break"); static final Method gCont = getDeclaredMethod("Cont"); static final Method gEnter = getDeclaredMethod("Enter"); static final Method gExit = getDeclaredMethod("Exit"); private static Method getDeclaredMethod(String name) { try { return Instruction.class.getDeclaredMethod(name, CalcParser.class); } catch (NoSuchMethodException ignored) { assert false; return null; } } /** * Create storage for this Instruction object. Allocate an * initial chunk of instruction space. * * @param nCodeSize an initial size for instruction space. * @return integer 1 upon success, and 0 otherwise. */ int create(int nCodeSize) { mnCodeSize = nCodeSize; moCodeBase = new Object[mnCodeSize]; mnCodePtr = 0; mnProgEnd = mnProgBase = mnProgCtr = mnCodePtr; // Javaport: Not required! // moDebugLineNo = null; // mnDebugPrevLine = 0; // mnDebugPrevStoppedAtLine = 0; // mnDebugStopAtStackDepth = -1; // -1 means don't stop // mnDebugPollCounter = 0; return 1; } /** * (Re-)Initialize this Instruction object. When not caching code, the * instruction code pointer is reset to the instruction space base address. * The instruction program counter is reset to the instruction code pointer. */ void init(CalcParser oParser) { if (oParser.mbSyntaxErrorSeen) mnCodePtr = mnProgBase; else if (oParser.mbWasInSaveMode) mnCodePtr = mnProgEnd; else mnCodePtr = 0; mnProgCtr = mnCodePtr; mnProgBase = mnCodePtr; } /** * Get this object's instruction space base address. * * @return the instruction space base address. */ int getCodeStart() { return 0; } /** * Get this object's program start address. * * @return the address of the start instruction. */ int getProgStart() { return mnProgBase; } /** * Get this object's program start address. */ void setProgStart() { mnProgBase = mnCodePtr; } /** * Get this object's instruction space code size. * * @return the instruction space code size. */ int getCodeSize() { return mnCodeSize; } /** * Get the relative address of this object's next address instruction. * Use this method to get program counter-based relative addresses * (also called PC-relative addressing). * * @return this instruction's relative address. */ int generate() { return mnCodePtr; } /** * Generate the next instruction word in this object's instruction space. * Because instruction space is allowed to grow as needed, all instruction * must be position independent, i.e., only PC-relative addresses are allowed. * * @param nInstruction an instruction word. If many cases, several * instruction words need to be generated to complete an instruction. * @return this instruction's relative address. */ int generate(Object nInstruction) { // // Grow code space as needed. When full, grow code by two. // if (mnCodePtr >= mnCodeSize) { int nProgEndOffset = mnProgEnd; int nCodeSize = mnCodePtr; int nProgSize = mnProgBase; int nProgCtrSize = mnProgCtr; mnCodeSize <<= 1; Object[] oNewBase = new Object[mnCodeSize]; System.arraycopy(moCodeBase, 0, oNewBase, 0, mnCodeSize >> 1); moCodeBase = oNewBase; // Javaport: Not required! // if (moDebugLineNo != null) // moDebugLineNo = (DebugLineInfo *) // Realloc(moDebugLineNo, mnCodeSize * sizeof(DebugLineInfo)); mnCodePtr = nCodeSize; mnProgCtr = nProgCtrSize; mnProgBase = nProgSize; mnProgEnd = nProgEndOffset; } int pInstruction = mnCodePtr; moCodeBase[mnCodePtr++] = nInstruction; return pInstruction; } // Javaport: Not required! // /** // * Generate the next instruction word, with source line for debugging. // * It maintains the moDebugLineNo array, which is an array of line // * numbers parallel to the moCodeBase array. // * // * @param nInstruction an instruction word. If many cases, several // * instruction words need to be generated to complete an instruction. // * @param nLine line of source code. // * @return this instruction's relative address. // */ // int generate(int nInstruction, int nScriptID, int nLine) { // if (moDebugLineNo == null) // moDebugLineNo = (DebugLineInfo *) Calloc(mnCodeSize, sizeof(DebugLineInfo)); // int nLastInstr = Generate(nInstruction); // moDebugLineNo[nLastInstr].mnScriptID = nScriptID; // moDebugLineNo[nLastInstr].mnLineNo = nLine; // moDebugLineNo[nLastInstr].bBreakPointSet = false; // return nLastInstr; // } /** * Execute a sequence of instructions. All sequences are terminated with * a Stop instruction. * * @param oParser the FormCalc parser. * @param nStartAddr the start address of an instruction sequence. */ void execute(CalcParser oParser, int nStartAddr) { // // Protect against misuse, e.g., // calling execute without having parsed anything. // assert(mnCodePtr > 0); // // If not debugging Then ... // // if (oParser.moDebugHost == null /* || moDebugLineNo == null */) { mnProgCtr = nStartAddr; while (moCodeBase[mnProgCtr] != gStop) { if(null != oParser.moScriptHost && oParser.moScriptHost.cancelActionOccured()){ oParser.mbCancelStatus = true; if(oParser.mbCancelStatus) break; } else{ Object oObj = moCodeBase[mnProgCtr++]; // assert(oObj instanceof Method); try { Method func = (Method) oObj; func.invoke(null, oParser); } catch(IllegalAccessException e) { assert (e != null); } catch(InvocationTargetException e) { assert (e != null); } } } // } // Javaport: Not required! // else { // // Debugging // if (nStartAddr == GetCodeStart()) { // mnDebugPrevLine = 0; // mnDebugPrevStoppedAtLine = 0; // mnDebugStopAtStackDepth = -1; // -1 means don't stop // mnDebugPollCounter = 0; // } // mnProgCtr = nStartAddr; // while (moCodeBase[mnProgCtr] != gStop) { // // Call the Poll() callback periodically. // if (!(mnDebugPollCounter++ & 1023)) // oParser.moDebugHost.poll(); // // int nPC = mnProgCtr - GetCodeStart(); // int nLine = moDebugLineNo[nPC].mnLineNo; // // // If the current line changes, clear mnDebugPrevStoppedAtLine // // (otherwise we couldn't break twice on a line inside a loop). // if (mnDebugPrevLine != nLine) // mnDebugPrevStoppedAtLine = 0; // // // Never stop at the same line twice (multiple // // instructions share a single source line number). // // Don't stop on the two expression-separator instructions. // // This is primarily so that we can step over function calls // // without stopping twice on the same line of source (since // // one or both of these instructions will follow the Call // // instruction and is on the same line). // if (mnDebugPrevStoppedAtLine != nLine && // mnCodeBae[mnProgCtr] != gList && // mnCodeBae[mnProgCtr] != gDeref) { // // If a break-point is hit, OR mnDebugStopAtStackDepth // // is greater than or equal to the current stack depth, // // then stop. // if (moDebugLineNo[nPC].bBreakPointSet || // mnDebugStopAtStackDepth >= // (int)oParser.moFrame.getDepth()) { // // mnDebugPrevStoppedAtLine = nLine; // // reset mnDebugStopAtStackDepth (-1 means don't stop) // mnDebugStopAtStackDepth = -1; // int nScriptID = moDebugLineNo[nPC].mnScriptID; // oParser.moDebugHost.stopped(nScriptID, nLine); // } // } // mnDebugPrevLine = nLine; // (*(moCodeBase[mnProgCtr++]))(oParser); // } // } } /** * Release resources held in this object's instruction space. * Traverse the entire instruction space, as though it were just a * sequence of words, deleting symbols from Load instructions, * and function names form Call instructions. * *

Syntax errors are the reason we can't traverse instructions * in the conventional manner. Upon discovery of a syntax error, * incomplete instructions with control flow, may exist, but be * unreachable. The syntax error may have prevented the parser from * connecting all the sequences. But such sequences may contain * resources which need freeing. Hence this approach. * *

This approach is safe because Load and Call instructions live in * this processor's code space whereas as symbols and function names * live in the heap. * * @param oParser the FormCalc parser. * @param nStartAddr the start address of an instruction * @param bFinal boolean flag indicating finality of release. * sequence to start releasing. */ void release(CalcParser oParser, int nStartAddr) { int nInstruction = nStartAddr; Object[] oBase = oParser.moCode.moCodeBase; while (nInstruction < mnCodePtr) { // // Free resources within Load instructions. // if (oBase[nInstruction] == gLoad) { CalcSymbol oSym = (CalcSymbol) oBase[nInstruction + 1]; if (oSym != null) { switch(oSym.getType()) { case CalcSymbol.TypeVariable: case CalcSymbol.TypeParameter: break; case CalcSymbol.TypeReference: break; default: CalcSymbol.delete(oSym, oParser); break; } } oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } // // Free resources within Call instructions. // else if (oBase[nInstruction] == gCall) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } // // Free resources within Form instructions. // else if (oBase[nInstruction] == gForm) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } // // Ignore all other instructions. // else if (oBase[nInstruction] == gFor) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } else if (oBase[nInstruction] == gForeach) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } else if (oBase[nInstruction] == gIf) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } else if (oBase[nInstruction] == gIfFunc) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } else if (oBase[nInstruction] == gWhile) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } else if (oBase[nInstruction] == gFunc) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } else if (oBase[nInstruction] == gGbl) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } else if (oBase[nInstruction] == gEnter) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } else if (oBase[nInstruction] == gExit) { oBase[nInstruction++] = gStop; oBase[nInstruction++] = gStop; } else { oBase[nInstruction++] = gStop; } } } /** * Relocate this object's instruction space. Traverse the entire * instruction space, preserving and relocating all Gbl and Func * instruction sequences, and purging most everything else. * * @param oParser the FormCalc parser. */ void relocate(CalcParser oParser) { int oDstInstr = 0; int oSrcInstr = 0; Object[] oBase = oParser.moCode.moCodeBase; // // preserve leading Enter instruction. // oBase[oDstInstr++] = oBase[oSrcInstr++]; oBase[oDstInstr++] = oBase[oSrcInstr++]; int nSavedDecl = 0; while (oSrcInstr < mnCodePtr) { // // Relocate Gbl instruction sequences. // if (oBase[oSrcInstr] == gGbl) { int nEnd = oSrcInstr + ((Integer) oBase[oSrcInstr + 1]).intValue(); while (oSrcInstr < nEnd) oBase[oDstInstr++] = oBase[oSrcInstr++]; nSavedDecl++; } // // Relocate Func instruction sequences. // else if (oBase[oSrcInstr] == gFunc) { // // Adjust relocated function address. // CalcSymbol oSym = (CalcSymbol) oBase[oSrcInstr + 1]; if (oSym != null && oSym.getType() == CalcSymbol.TypeFunction) oSym.setAddr(oDstInstr); int nEnd = oSrcInstr + ((Integer) oBase[oSrcInstr + 2]).intValue(); while (oSrcInstr < nEnd) oBase[oDstInstr++] = oBase[oSrcInstr++]; nSavedDecl++; } // // Otherwise free resources within Load instructions. // else if (oBase[oSrcInstr] == gLoad) { CalcSymbol oSym = (CalcSymbol) oBase[oSrcInstr + 1]; if (oSym != null && oSym.getType() != CalcSymbol.TypeVariable && oSym.getType() != CalcSymbol.TypeReference && oSym.getType() != CalcSymbol.TypeParameter) CalcSymbol.delete(oSym, oParser); oSrcInstr += 2; } // // And free resources within Call instructions. // else if (oBase[oSrcInstr] == gCall) { oSrcInstr += 3; } // // And free resources within Form instructions. // else if (oBase[oSrcInstr] == gForm) { oSrcInstr += 3; } // // And ignore all other instructions. // else { oSrcInstr++; } } // // Add trailing Exit instruction. // mnProgEnd = oDstInstr; oBase[oDstInstr++] = gExit; oBase[oDstInstr++] = Integer.valueOf(1); // // Clear out anything remaining. // while (oDstInstr < mnCodePtr) oBase[oDstInstr++] = gStop; mnCodePtr = mnProgEnd + 2; // // Record whether we've relocated something. // oParser.mnSavedDecl += (nSavedDecl > 0) ? 1 : 0; } /** * Set or clear a debug break-point. * It sets or clears a flag in the moDebugLineNo array, which * is an array of line numbers parallel to the moCodeBase array. * * @param nLine line of source code. * @param bSet true to set a break-point, false to clear it. * @return true if successful. */ public boolean debugBreakPoint(int nScriptID, int nLine, boolean bSet) { return false; // Javaport: Not required! // if (moDebugLineNo == null) // return false; // boolean bRC = false; // int nCodeSize = mnCodePtr; // for (int i = 0; i < nCodeSize; i++) { // if (moDebugLineNo[i].mnScriptID == nScriptID) { // // func basically means "jump over this // // function declaration". Don't set a break-point on // // it, because the intent would be to stop inside the // // function, not when simply passing by a cached function. // if (moCodeBase[i] == func) // continue; // if (moDebugLineNo[i].mnLineNo == nLine) { // bRC = true; // moDebugLineNo[i].bBreakPointSet = bSet; // } // else if (moDebugLineNo[i].mnLineNo > (int) nLine) { // break; // } // } // } // return bRC; } /** * Set internal state to enable either step-over, step-into * or step-out. The debug-mode execution loop calls the * debug host's Stopped method when mnDebugStopAtStackDepth * is greater than or equal to the current stack depth. * * @param oParser the FormCalc parser. * @param eCmd a value of the CalcDebugCommand enum * representing step-over, step-into or step-out. * @return true if successful. */ public boolean debugCommand(CalcParser oParser, int eCmd) { // Javaport: Not required! // int nStackDepth = (int)oParser.moFrame.getDepth(); // if (eCmd == DebugHost.STEP_OVER) { // mnDebugStopAtStackDepth = nStackDepth; // return true; // } // else if (eCmd == DebugHost.STEP_INTO) { // mnDebugStopAtStackDepth = nStackDepth + 1; // return true; // } // else if (eCmd == DebugHost.STEP_OUT) { // mnDebugStopAtStackDepth = nStackDepth - 1; // return true; // } // else if (eCmd == DebugHost.STOP) { // oParser.mbInterrupted = true; // return true; // } return false; } /** * Stop instruction. * * @param oParser the FormCalc parser. */ static void Stop(CalcParser oParser) { // empty } /** * Or instruction. * *

A single word instruction. Pop two operands off the stack, or * their values into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void Or(CalcParser oParser) { Binary(oParser, gOr); } /** * And instruction. * *

A single word instruction. Pop two operands off the stack, and * their values into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void And(CalcParser oParser) { Binary(oParser, gAnd); } /** * Eq instruction. * *

A single word instruction. Pop two operands off the stack, compare * their values for equality into a resulting operand that's pushed * back onto the stack. * * @param oParser the FormCalc parser. */ static void Eq(CalcParser oParser) { Relational(oParser, gEq); } /** * Ne instruction. * *

A single word instruction. Pop two operands off the stack, compare * their values for inequality into a resulting operand that's pushed * back onto the stack. * * @param oParser the FormCalc parser. */ static void Ne(CalcParser oParser) { Relational(oParser, gNe); } /** * Gt instruction. * *

A single word instruction. Pop two operands off the stack, compare * their values for greater than into a resulting operand that's pushed * back onto the stack. * * @param oParser the FormCalc parser. */ static void Gt(CalcParser oParser) { Relational(oParser, gGt); } /** * Ge instruction. * *

A single word instruction. Pop two operands off the stack, compare * their values for greater than or equality into a resulting operand * that's pushed back onto the stack. * * @param oParser the FormCalc parser. */ static void Ge(CalcParser oParser) { Relational(oParser, gGe); } /** * Lt instruction. * *

A single word instruction. Pop two operands off the stack, compare * their values for lesser than into a resulting operand that's pushed * back onto the stack. * * @param oParser the FormCalc parser. */ static void Lt(CalcParser oParser) { Relational(oParser, gLt); } /** * Le instruction. * *

A single word instruction. Pop two operands off the stack, compare * their values for lesser than or equality into a resulting operand * that's pushed back onto the stack. * * @param oParser the FormCalc parser. */ static void Le(CalcParser oParser) { Relational(oParser, gLe); } /** * Add instruction. * *

A single word instruction. Pop two operands off the stack, add * their values into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void Add(CalcParser oParser) { Binary(oParser, gAdd); } /** * Sub instruction. * *

A single word instruction. Pop two operands off the stack, subtract * their values into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void Sub(CalcParser oParser) { Binary(oParser, gSub); } /** * Mul instruction. * *

A single word instruction. Pop two operands off the stack, multiply * their values into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void Mul(CalcParser oParser) { Binary(oParser, gMul); } /** * Div instruction. * *

A single word instruction. Pop two operands off the stack, divide * their values into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void Div(CalcParser oParser) { Binary(oParser, gDiv); } /* * List instruction. * *

A single word instruction. Pop two operands off the stack, * and use the value of the right symbol as the resulting operand * that's pushed back onto the stack. * * @param oParser the FormCalc parser. */ static void List(CalcParser oParser) { Binary(oParser, gList); } /** * Uminus instruction. * *

A single word instruction. Pop one operand off the stack, negate * its value into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void Uminus(CalcParser oParser) { Unary(oParser, gUminus); } /** * Uplus instruction. * *

A single word instruction. Pop one operand off the stack, affirm * its value into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void Uplus(CalcParser oParser) { Unary(oParser, gUplus); } /** * Not instruction. * *

A single word instruction. Pop one operand off the stack, not * its value into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void Not(CalcParser oParser) { Unary(oParser, gNot); } /* * Deref instruction. * *

A single word instruction. Pop one operand off the stack, de-reference * its value into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void Deref(CalcParser oParser) { Unary(oParser, gDeref); } /* * Noop instruction. * *

A single word instruction. Pop one operand off the stack, reference * its value into a resulting operand that's pushed back onto * the stack. * * @param oParser the FormCalc parser. */ static void Noop(CalcParser oParser) { Unary(oParser, gNoop); } /* * Asgn instruction. * *

A single word instruction. Pop two operands off the stack, * assign the r-value of the first symbol to the l-value of the * second and copy the r-value of the first as a resulting operand * that's pushed back onto the stack. * * @param oParser the FormCalc parser. */ static void Asgn(CalcParser oParser) { Assign(oParser, gAsgn); } /* * Asgn2 instruction. * *

A single word instruction. Pop one operand off the stack, * assign the r-value of the second symbol to the l-value of the * first and copy the r-value of the second as a resulting operand * that's pushed back onto the stack. * * @param oParser the FormCalc parser. */ static void Asgn2(CalcParser oParser) { Assign(oParser, gAsgn2); } /* * Dot instruction. * *

A single word instruction. Pop two accessor symbols off the stack, * concatenate their names together (as per the dot notation) into a * resulting accessor symbol that's pushed back onto the stack. * * @param oParser the FormCalc parser. */ static void Dot(CalcParser oParser) { Concat(oParser, gDot); } /* * Dotdot instruction. * *

A single word instruction. Pop two accessor symbols off the stack, * concatenate their names together (as per the dot dot notation) into a * resulting accessor symbol that's pushed back onto the stack. * * @param oParser the FormCalc parser. */ static void Dotdot(CalcParser oParser) { Concat(oParser, gDotdot); } /* * Dothash instruction. * *

A single word instruction. Pop two accessor symbols off the stack, * concatenate their names together (as per the dot hash notation) into a * resulting accessor symbol that's pushed back onto the stack. * * @param oParser the FormCalc parser. */ static void Dothash(CalcParser oParser) { Concat(oParser, gDothash); } /* * Dotstar instruction. * *

A single word instruction. Pop one accessor symbol off the stack, * append a dot star operator (as per the dot star notation) into a * resulting accessor symbol that's pushed back onto the stack. * * @param oParser the FormCalc parser. */ static void Dotstar(CalcParser oParser) { CalcSymbol lSym = oParser.mStack.pop(); // Pop first operand CalcSymbol oRetSym = null; try { if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.getExceptions(lSym); oRetSym = new CalcSymbol(0); } else { String lContainer = (lSym.getType() == CalcSymbol.TypeReference) ? "#0" : lSym.getName(); // // Concatenate the two accessors using the dot notation // and push the result as an accessor CalcSymbol onto the stack. // StringBuilder sResult = new StringBuilder(lContainer.length() + 2); sResult.append(lContainer); sResult.append('.'); sResult.append('*'); oRetSym = new CalcSymbol(); oRetSym.setName(sResult.toString()); if (lSym.getType() == CalcSymbol.TypeReference) oRetSym.setObjValue(lSym.getObjValue()); oRetSym.setType(CalcSymbol.TypeAccessor); } } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } CalcSymbol.delete(lSym, oParser); oParser.mStack.push(oRetSym); } /* * Index instruction. * *

A single word instruction. Pop two accessor symbols off the stack, * construct a SOM index expression from their values into a * resulting accessor symbol that's pushed back onto the stack. * * @param oParser the FormCalc parser. */ static void Index(CalcParser oParser) { CalcSymbol rSym = oParser.mStack.pop(); // Pop second operand CalcSymbol lSym = oParser.mStack.pop(); // Pop first operand CalcSymbol oRetSym = null; try { if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.getExceptions(rSym); oParser.getExceptions(lSym); oRetSym = new CalcSymbol(0); } else { String lAccessor = lSym.getName(); CalcSymbol oSym = new CalcSymbol(rSym); StringBuilder rIndex = new StringBuilder(); do { int nIndex; String sStr = null; switch (oSym.getType()) { case CalcSymbol.TypeAccessor: if ("*".equals(oSym.getName())) { rIndex.append('*'); } else { CalcSymbol oTmpSym = oParser.getOneValue(oSym); CalcSymbol.delete(oSym, oParser); oSym = oTmpSym; continue; } break; case CalcSymbol.TypeReference: CalcSymbol oTmpSym = oParser.getRefValue(oSym); CalcSymbol.delete(oSym, oParser); oSym = oTmpSym; continue; case CalcSymbol.TypeDouble: nIndex = (int) oParser.getNumeric(oSym); rIndex.append(nIndex); break; case CalcSymbol.TypeString: case CalcSymbol.TypeVariable: sStr = oSym.getStringValue(); if (sStr != null && FormCalcUtil.strIsNumeric(sStr)) { rIndex.append(sStr); int nRadix = rIndex.indexOf("."); if (nRadix >= 0) rIndex.setLength(nRadix); } else { nIndex = (int) oParser.getNumeric(oSym); rIndex.append(nIndex); } break; case CalcSymbol.TypeNull: rIndex.append('0'); break; case CalcSymbol.TypeError: case CalcSymbol.TypeReturn: CalcException e = new CalcException(oSym); CalcSymbol.delete(oSym, oParser); throw e; default: assert (true); break; } break; } while (true); CalcSymbol.delete(oSym, oParser); StringBuilder sResult = new StringBuilder(lAccessor.length() + 2 + rIndex.length()); sResult.append(lAccessor); sResult.append('['); sResult.append(rIndex); sResult.append(']'); oRetSym = new CalcSymbol(); oRetSym.setName(sResult.toString()); oRetSym.setType(CalcSymbol.TypeAccessor); } } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } CalcSymbol.delete(rSym, oParser); CalcSymbol.delete(lSym, oParser); oParser.mStack.push(oRetSym); } /* * Break instruction. * *

A single word instruction. Because BreakExpressions return * a value (all FormCalc Expressions return a value), push a zero * value onto the stack. * * @param oParser the FormCalc parser. */ static void Break(CalcParser oParser) { CalcSymbol oRetSym = null; // // If there are any value of the stack Then make sure they are // fully evaluated before acknowledging the break expression. // if (oParser.mStack.getOffset() > 0) { CalcSymbol oSym = oParser.mStack.pop(); // Pop operand try { if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.getExceptions(oSym); oRetSym = new CalcSymbol(0); } else { double dVal = oParser.getNumeric(oSym); oRetSym = new CalcSymbol(dVal); } } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } CalcSymbol.delete(oSym, oParser); oParser.mStack.push(oRetSym); // Push back operand } // // Push break expression value. // oRetSym = new CalcSymbol(0); oParser.mbInBreak = true; oParser.mStack.push(oRetSym); } /* * Cont instruction. * *

A single word instruction. Because ContinueExpressions return * a value (all FormCalc Expressions return a value), push a zero * value onto the stack. * * @param oParser the FormCalc parser. */ static void Cont(CalcParser oParser) { CalcSymbol oRetSym = null; // // If there are any value of the stack Then make sure they are // fully evaluated before acknowledging the continue expression. // if (oParser.mStack.getOffset() > 0) { CalcSymbol oSym = oParser.mStack.pop(); // Pop operand try { if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.getExceptions(oSym); oRetSym = new CalcSymbol(0); } else { double dVal = oParser.getNumeric(oSym); oRetSym = new CalcSymbol(dVal); } } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } CalcSymbol.delete(oSym, oParser); oParser.mStack.push(oRetSym); // Push back operand } // // Push break expression value. // oRetSym = new CalcSymbol(0); oParser.mbInContinue = true; oParser.mStack.push(oRetSym); } /* * Enter instruction. * *

A double word instruction. When entering a scope block, activate * the scope that's is indicated by the second word of this instruction. * * @param oParser the FormCalc parser. */ static void Enter(CalcParser oParser) { Object oScope = oParser.moCode.moCodeBase[oParser.moCode.mnProgCtr++]; int nScope = ((Integer) oScope).intValue(); if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) return; oParser.moScope.setActive(nScope); } /* * Exit instruction. * *

A double word instruction. When exiting a scope block, de-activate * the scope that's is indicated by the second word of this instruction. * * @param oParser the FormCalc parser. */ static void Exit(CalcParser oParser) { Object oScope = oParser.moCode.moCodeBase[oParser.moCode.mnProgCtr++]; int nScope = ((Integer) oScope).intValue(); if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) return; oParser.moScope.clearActive(nScope); } /* * Load instruction. * *

A double word instruction. Push the symbol that's in the * second word of this instruction onto the stack. * * @param oParser the FormCalc parser. */ static void Load(CalcParser oParser) { Object oObj = oParser.moCode.moCodeBase[oParser.moCode.mnProgCtr++]; CalcSymbol oSym = (CalcSymbol) oObj; // // For formal parameters, actually retrieve the symbol that // corresponds to the actual parameter and push it onto the stack. // if (oSym.getType() == CalcSymbol.TypeParameter) { int nStackAddr = oParser.moFrame.peek().getStackAddr(); int nArgCount = oParser.moFrame.peek().getArgCount(); int nStackIdx = oSym.getIdxValue(); oSym = oParser.mStack.peek(nStackAddr - nArgCount + nStackIdx); oSym = new CalcSymbol(oSym); } // else if (oSym.getType() == CalcSymbol.TypeReference) { // jfObjImpl::addRef(pSym->GetObjValue()); // } oParser.mStack.push(oSym); // // Implement ability to interrupt execution. Currently // this can only be actived by DebugCommand(CalcDebugStop). // if (oParser.mbInterrupted) { oParser.mbInterrupted = false; oParser.mbInThrow = true; // // Discard the just-pushed value, and // replace it with the error value. // oSym = oParser.mStack.pop(); CalcSymbol.delete(oSym, oParser); MsgFormat sErrMsg = new MsgFormat(ResId.FC_ERR_INTERRUPTED); oSym = new CalcSymbol(sErrMsg.toString(), true, 0, 0); oParser.mStack.push(oSym); } } /* * Gbl instruction. * *

A double word instruction that preceeds every declaration * of global scope. Its a NOP instruction used to delineate all global * declarations. Delineating variable/reference declarations makes * relocating cached code easier. * *

The second word of this instruction is the PC-relative address of the * instruction following the variable declaration. * * @param oParser the FormCalc parser. */ static void Gbl(CalcParser oParser) { int nPC = oParser.moCode.mnProgCtr - 1; // // If past program start, i.e., not in cached code Then advance // the program counter to start of the variable assignment, so // as to execute the variable assignment. // if (oParser.moCode.mnProgCtr >= oParser.moCode.mnProgBase) { oParser.moCode.mnProgCtr = nPC + 2; } // // Else (for cached code) simply advance program counter to end // of the function definition, so a to ignore the original variable // assignment. // else { oParser.moCode.mnProgCtr = nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 1]).intValue(); } } /* * Func instruction. * *

A triple word instruction that preceeds every function declaration. * *

The second word of this instruction is a symbol containing the * function name. * *

The third word of this instruction is the PC-relative address of the * instruction following the function declaration. * * @param oParser the FormCalc parser. */ static void Func(CalcParser oParser) { int nPC = oParser.moCode.mnProgCtr - 1; // // If past program start, i.e., not in cached code Then execute // the function body. // if (oParser.moCode.mnProgCtr >= oParser.moCode.mnProgBase) { CalcSymbol oSym = (CalcSymbol) oParser.moCode.moCodeBase[nPC + 1]; CalcSymbol oRetSym = null; try { oParser.getExceptions(oSym); oRetSym = new CalcSymbol(0); } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } oParser.mStack.push(oRetSym); } // // Advance program counter to end of the function definition. // oParser.moCode.mnProgCtr = nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 2]).intValue(); } /* * Call instruction. * *

A triple word instruction. Pop a number of operand arguments * off the stack given by the third word of this instruction, * and call the user-defined or builtin function given * by the second word of this instruction. * *

Push the resulting operand back onto the stack. * * @param oParser the FormCalc parser. */ static void Call(CalcParser oParser) { int nPC = oParser.moCode.mnProgCtr - 1; // // Get the identifier name and the argument count. // String sIdent = (String) oParser.moCode.moCodeBase[nPC + 1]; int nArgs = ((Integer) oParser.moCode.moCodeBase[nPC + 2]).intValue(); // // Upcase the identifier and check // if its the name of a builtin function. // String sFunction = sIdent.toUpperCase(Locale.US); CalcSymbol oFuncSym = oParser.mBuiltin.lookup(sFunction); // // If not Then check if its the name of a user-defined function. // if (oFuncSym == null) oFuncSym = oParser.moData.lookup(sIdent); // // If identifier is name of a builtin function Then ... // if (oFuncSym.getType() == CalcSymbol.TypeBuiltin) { // // Load the arguments into an array to be passed to the builtin // function. The function arguments are on the stack in reversed // order, so populate the array bottom up. // CalcSymbol[] oArgs = new CalcSymbol[nArgs]; for (int i = nArgs; i > 0; i--) oArgs[i - 1] = oParser.mStack.pop(); // // If a break or continue seen, then just loop through arguments // looking for exceptions. Be sure to push something back onto // the stack. // if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { CalcSymbol oRetSym = null; try { for (int i = nArgs - 1; i >= 0; i--) oParser.getExceptions(oArgs[i]); oRetSym = new CalcSymbol(0); } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } oParser.mStack.push(oRetSym); } // // Call the builtin function. Remember it is responsible // for pushing a result onto the stack. // else { oFuncSym.getFuncValue(oParser, oArgs); } // // Free all allocated resources. // for (int i = nArgs - 1; i >= 0; i--) CalcSymbol.delete(oArgs[i], oParser); oParser.moCode.mnProgCtr = nPC + 3; } // // Else if is identifier is a user function Then ... // else if (oFuncSym.getType() == CalcSymbol.TypeFunction) { // // If actual parameters dont match formal parameters // Then do insist on it! // if (oFuncSym.getCntValue() != (int) nArgs) { // // Pop actual arguments of the stack, // ignoring exception-valued arguments. // and free all allocated resources. // for (int i = nArgs; i > 0; i--) { CalcSymbol oArg = oParser.mStack.pop(); CalcSymbol.delete(oArg, oParser); } // // Push error exception onto the stack, // oParser.mbInThrow = true; MsgFormat sErr = new MsgFormat(ResId.FC_ERR_PARAMETER); CalcSymbol oRetSym = new CalcSymbol(sErr.toString(), true, 0, 0); oParser.mStack.push(oRetSym); oParser.moCode.mnProgCtr = nPC + 3; } // // Else if a break or continue seen, then just loop through arguments // in order, looking for exception-valued arguments. Be sure to // push something back onto the stack. // else if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { // // Load the arguments into an array. The function arguments // are on the stack in reversed order, so populate the array // bottom up. // CalcSymbol[] oArgs = new CalcSymbol[nArgs]; for (int i = nArgs; i > 0; i--) oArgs[i - 1] = oParser.mStack.pop(); CalcSymbol oRetSym = null; try { for (int i = nArgs - 1; i >= 0; i--) oParser.getExceptions(oArgs[i]); oRetSym = new CalcSymbol(0); } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } // // Free all allocated resources. // for (int i = nArgs - 1; i >= 0; i--) CalcSymbol.delete(oArgs[i], oParser); oParser.mStack.push(oRetSym); oParser.moCode.mnProgCtr = nPC + 3; } // // Else ... // else { // // Initialize and push new stack frame. // Frame oFrame = new Frame(); oFrame.setFuncSym(oFuncSym); oFrame.setStackAddr(oParser.mStack.getOffset() - 1); oFrame.setReturnAddr(nPC + 3); oParser.moFrame.push(oFrame); // // Invoke the user function by executing code at function's // start address. User function will execute a Ret instruction // which will pop arguments, pop the frame and set the program // counter to the caller's return address. // oParser.moCode.execute(oParser, oFuncSym.getAddr() + 3); } } } /* * Ret instruction. * *

A single word instruction. When exiting a function, the actual * function arguments are popped of the stack, the stack frame * is deactivated, the function's return value pushed onto the * stack, and the program counter reset to the caller's return address. * * @param oParser the FormCalc parser. */ static void Ret(CalcParser oParser) { Frame oFrame = oParser.moFrame.pop(); int nArgs = oFrame.getArgCount(); CalcSymbol oRetSym = oParser.mStack.pop(); for (int i = nArgs; i > 0; i--) { CalcSymbol oArg = oParser.mStack.pop(); CalcSymbol.delete(oArg, oParser); } oParser.mStack.push(oRetSym); oParser.moCode.mnProgCtr = oFrame.getReturnAddr(); } /* * Form instruction. * *

A triple word instruction. Pop a number of operand arguments * off the stack given by the third word of this instruction, * and call the method given by the second word of this instruction. * Note: methods aren't actually called, just formulated. * *

Push the resulting operand back onto the stack. * * @param oParser the FormCalc parser. */ static void Form(CalcParser oParser) { int nPC = oParser.moCode.mnProgCtr - 1; // // Get the identifier name and the argument count. // String sIdent = (String) oParser.moCode.moCodeBase[nPC + 1]; int nArgs = ((Integer) oParser.moCode.moCodeBase[nPC + 2]).intValue(); // // Load the arguments into an array to be passed to the method // call. The function arguments are on the stack in reversed // order, so populate the array bottom up. // CalcSymbol[] oArgs = new CalcSymbol[nArgs]; for (int i = nArgs; i > 0; i--) oArgs[i - 1] = oParser.mStack.pop(); // // If a break or continue seen, then just loop through arguments // looking for exceptions. Be sure to push something back onto // the stack. // if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { CalcSymbol oRetSym = null; try { for (int i = nArgs - 1; i >= 0; i--) oParser.getExceptions(oArgs[i]); oRetSym = new CalcSymbol(0); } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } oParser.mStack.push(oRetSym); } // // Otherwise formulate the method call... // else { // // Concatenate the method arguments in an argument list. // Obj[] oObj = new Obj[nArgs + 1]; CalcSymbol oRetSym; try { StringBuilder sFormula = new StringBuilder(sIdent); sFormula.append('('); for (int i = 0; i < nArgs; i++) { // // Loop until all accessor arguments have been evaluated. // do { CalcSymbol[] oSyms = null; String sStr = null; switch (oArgs[i].getType()) { case CalcSymbol.TypeAccessor: int nSyms = 0; try { oSyms = oParser.moScriptHost.getItemValue( oArgs[i].getName(), oArgs[i].getObjValues()); nSyms = oSyms.length; CalcSymbol.delete(oArgs[i], oParser); oArgs[i] = oSyms[0]; Builtins.limitExceptionArgs(oSyms); for (int j = nSyms - 1; j > 0; j--) CalcSymbol.delete(oSyms[j], oParser); } catch (CalcException e) { for (int j = nSyms - 1; j > 0; j--) CalcSymbol.delete(oSyms[j], oParser); throw e; } continue; case CalcSymbol.TypeReference: sFormula.append('#'); sFormula.append((char) ('0' + i + 1)); oObj[i + 1] = oArgs[i].getObjValue(); break; case CalcSymbol.TypeString: case CalcSymbol.TypeVariable: sStr = oArgs[i].getStringValue(); sFormula.append('\"'); if (sStr != null) { String sEsc = FormCalcUtil.strToEscStr(sStr); sFormula.append(sEsc); } sFormula.append('\"'); break; case CalcSymbol.TypeDouble: sStr = FormCalcUtil.dblToStr( oArgs[i].getNumericValue(), 11); StringBuilder sBuf = new StringBuilder(sStr); FormCalcUtil.trimZeroes(sBuf); FormCalcUtil.trimRadix(sBuf); FormCalcUtil.trimSign(sBuf); sFormula.append('\"'); sFormula.append(sBuf); sFormula.append('\"'); break; case CalcSymbol.TypeNull: sFormula.append("%null%"); break; case CalcSymbol.TypeReturn: case CalcSymbol.TypeError: default: throw new CalcException(oArgs[i]); } break; } while (true); if (i < nArgs - 1) sFormula.append(','); } sFormula.append(')'); // // Push the resulting method call as an accessor CalcSymbol // onto the stack. // oRetSym = new CalcSymbol(); oRetSym.setName(sFormula.toString()); oRetSym.setObjValues(oObj); oRetSym.setType(CalcSymbol.TypeAccessor); } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } oParser.mStack.push(oRetSym); } // // Free all allocated resources. // for (int i = nArgs - 1; i >= 0; i--) CalcSymbol.delete(oArgs[i], oParser); oParser.moCode.mnProgCtr = nPC + 3; } /* * IfFunc instruction. * *

A triple word instruction. Its a long story! In FormCalc, where 'if' is * both a keyword and the name of a builtin function, keywords have precedence. * Which means a If instruction has already been generated. This instruction * takes the contents of an If instruction and executes a call to the builtin * If function instead. * * @param oParser the FormCalc parser. */ static void IfFunc(CalcParser oParser) { int nPC = oParser.moCode.mnProgCtr - 1; int nArgs = ((Integer) oParser.moCode.moCodeBase[nPC + 1]).intValue(); // // Do evaluate the expr list, which in this case is the first argument // of the If function. // oParser.moCode.execute(oParser, nPC + 4); // // Load the arguments into an array to be passed to the builtin // function. The function arguments are on the stack in reversed // order, so populated the array bottom up. // CalcSymbol[] oArgs = new CalcSymbol[nArgs]; for (int i = nArgs; i > 0; i--) oArgs[i - 1] = oParser.mStack.pop(); // // If a break or continue seen, then just loop through arguments // looking for exceptions. Be sure to push something back onto // the stack. // if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { CalcSymbol oRetSym = null; try { for (int i = nArgs - 1; i >= 0; i--) oParser.getExceptions(oArgs[i]); oRetSym = new CalcSymbol(0); } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } oParser.mStack.push(oRetSym); } // // Call the builtin if function. It will push a // result back onto the stack. // else { BuiltinLogical.If(oParser, oArgs); } // // Free all allocated resources. // for (int i = nArgs - 1; i >= 0; i--) CalcSymbol.delete(oArgs[i], oParser); // // Advance program counter to end of if function call. // oParser.moCode.mnProgCtr = nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 3]).intValue(); } /* * While instruction. * *

A triple word instruction, containing the addresses needed to execute * a while expression. * *

The second word of this instruction is the PC-relative address to the * Enter instruction, which is the start of this while expression's * do-part. * *

The third word of this instruction is the PC-relative address to the * Exit instruction, which is the end of this while expression's do-part. * *

The instruction following this instruction is always the start of * this while expression's expr-part. * * @param oParser the FormCalc parser. */ static void While(CalcParser oParser) { int nPC = oParser.moCode.mnProgCtr - 1; if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.mStack.push(new CalcSymbol()); } else { // // Execute the expr-part and pop the result off the stack. // oParser.moCode.execute(oParser, nPC + 3); CalcSymbol oSym = oParser.mStack.pop(); CalcSymbol oDoSym = new CalcSymbol(0); try { double nVal = oParser.getNumeric(oSym); // // While the expr-part's result is non-zero Do ... // while (nVal != 0.) { // // Execute the do-part. // oParser.moCode.execute(oParser, nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 1]).intValue()); CalcSymbol.delete(oSym, oParser); oDoSym = oParser.mStack.pop(); String sVal = oParser.getString(oDoSym); CalcSymbol.delete(oSym, oParser); oDoSym = new CalcSymbol(sVal); if (oParser.mbInBreak) break; else if (oParser.mbInContinue) oParser.mbInContinue = false; // // Re-execute the expr-part. // oParser.moCode.execute(oParser, nPC + 3); // // Pop the result off the stack. // CalcSymbol.delete(oSym, oParser); oSym = oParser.mStack.pop(); nVal = oParser.getNumeric(oSym); } oParser.mStack.push(oDoSym); } catch (CalcException e) { CalcSymbol.delete(oSym, oParser); oParser.mStack.push(e.getSymbol()); } CalcSymbol.delete(oSym, oParser); if (oParser.mbInBreak) oParser.mbInBreak = false; } oParser.moCode.mnProgCtr = nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 2]).intValue(); } /* * If instruction. * *

A quad word instruction, containing the addresses needed to execute * an if expression. * *

The second word of this instruction is the PC-relative address to the * start of this if expression's then-part. * *

The third word of this instruction is the PC-relative address to the * end of this if expression's else-part. * *

The fourth word of this instruction is the PC-relative address to the * instruction following this if expression's endif-part. * *

The instruction following this instruction is always the start of * this if expression's expr-part. * * @param oParser the FormCalc parser. */ static void If(CalcParser oParser) { int nPC = oParser.moCode.mnProgCtr - 1; if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.mStack.push(new CalcSymbol()); } else { // // Execute the expr-part and pop the result off the stack. // oParser.moCode.execute(oParser, nPC + 4); CalcSymbol oSym = oParser.mStack.pop(); try { double nVal = oParser.getNumeric(oSym); // // If the result is non-zero then execute the then-part. // if (nVal != 0.) oParser.moCode.execute(oParser, nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 1]).intValue()); // // Else if there's an else-part then execute it. // else if (oParser.moCode.moCodeBase[nPC + 2] != gStop) oParser.moCode.execute(oParser, nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 2]).intValue()); // // Else push the value 0 on the stack. // else oParser.mStack.push(new CalcSymbol(0)); } catch (CalcException e) { oParser.mbInThrow = true; oParser.mStack.push(e.getSymbol()); } CalcSymbol.delete(oSym, oParser); } oParser.moCode.mnProgCtr = nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 3]).intValue(); } /* * For instruction. * *

A quint word instruction, containing the addresses needed to execute * an for expression. * *

The second word of this instruction is the PC-relative address to the * start of this for expression's to-part, which, is always a Load * instruction of the loop variable. * *

The third word of this instruction is the PC-relative address to the * start of this for expression's step-part, which again, is always a Load * instruction of the loop variable. * *

The fourth word of this instruction is the PC-relative address to the * start of this for expression's do-part. * *

The fifth word of this instruction is the PC-relative address to the * instruction preceding this for expression's endfor-part. It will always * be an Exit instruction. * *

The instruction following this instruction is always the start of * this for expression's init-part. It will always be an Enter * instruction. * * @param oParser the FormCalc parser. */ static void For(CalcParser oParser) { int nPC = oParser.moCode.mnProgCtr - 1; if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.mStack.push(new CalcSymbol()); } else { // // Execute the init-part and leave the result on the stack. // oParser.moCode.execute(oParser, nPC + 5); // // Execute the to-part and pop the result off the stack. // oParser.moCode.execute(oParser, nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 1]).intValue()); CalcSymbol oSym = oParser.mStack.pop(); CalcSymbol oDoSym = new CalcSymbol(0); try { double nVal = oParser.getNumeric(oSym); // // While the to-part's result is non-zero Do ... // while (nVal != 0.) { // // Execute the do-part. // oParser.moCode.execute(oParser, nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 3]).intValue()); CalcSymbol.delete(oSym, oParser); oDoSym = oParser.mStack.pop(); String sVal = oParser.getString(oDoSym); CalcSymbol.delete(oSym, oParser); oDoSym = new CalcSymbol(sVal); if (oParser.mbInBreak) break; else if (oParser.mbInContinue) oParser.mbInContinue = false; // // Execute the step-part. // oParser.moCode.execute(oParser, nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 2]).intValue()); // // Re-execute the to-part. // oParser.moCode.execute(oParser, nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 1]).intValue()); // // Pop the result off the stack. // CalcSymbol.delete(oSym, oParser); oSym = oParser.mStack.pop(); nVal = oParser.getNumeric(oSym); } oParser.mStack.push(oDoSym); } catch (CalcException e) { CalcSymbol.delete(oSym, oParser); oParser.mbInThrow = true; oParser.mStack.push(e.getSymbol()); } CalcSymbol.delete(oSym, oParser); if (oParser.mbInBreak) oParser.mbInBreak = false; if (oParser.mbInContinue) oParser.mbInContinue = false; } oParser.moCode.mnProgCtr = nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 4]).intValue(); } /* * Foreach instruction. * *

A quint word instruction, containing argument counts and addresses * needed to execute an foreach expression. * *

The second word of this instruction is a count of the number of * compile time arguments in this foreach expression's in-part. * *

The third word of this instruction is the PC-relative address to the * start of the arguments in this foreach expression's in-part. The * instructions comprising the arguments in this foreach's expression's * in-part are execute once, and all resulting values are pushed onto * the stack. * *

The fourth word of this instruction is the PC-relative address to the * start of this foreach expression's do-part. * *

The fifth word of this instruction is the PC-relative address to the * instruction preceding this foreach expression's endfor-part. It will * always be an Exit instruction. * *

The instruction following this instruction is always the start of * this foreach expression's init-part. It will always be an Enter * instruction, followed by a Load instruction of the loop variable. * The loop variable is iteratively assigned the values of the arguments * in the in-part, that are will be residing on top of the stack. * * @param oParser the FormCalc parser. */ static void Foreach(CalcParser oParser) { int nPC = oParser.moCode.mnProgCtr - 1; if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.mStack.push(new CalcSymbol()); } else { int nInArgs = ((Integer) oParser.moCode.moCodeBase[nPC + 1]).intValue(); // // Make room to NOLOOPARGS error symbol. // if (nInArgs == 0) nInArgs++; CalcSymbol[] oInSym = new CalcSymbol[nInArgs]; // // Execute the argument list once and push values onto the stack. // oParser.moCode.execute(oParser, nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 2]).intValue()); // // Pop the arguments off the stack into an array to that we can // iterate through it in reverse order. // for (int i = 0; i < nInArgs; ) { CalcSymbol oArg = oParser.mStack.pop(); // // If non-accessor Then simply store into the array. // if (oArg.getType() != CalcSymbol.TypeAccessor) { oInSym[i++] = oArg; } // // Else accessor So insert all retuned values into the array. // else { CalcSymbol[] oSyms = null; try { oSyms = oParser.moScriptHost.getItemValue( oArg.getName(), oArg.getObjValues()); int nSyms = oSyms.length; if (nSyms > 1) { nInArgs += nSyms - 1; CalcSymbol[] oNewSym = new CalcSymbol[nInArgs]; System.arraycopy(oInSym, 0, oNewSym, 0, nInArgs - nSyms + 1); oInSym = oNewSym; for (int j = 0; j < nSyms; j++) oInSym[i++] = oSyms[j]; } else { oInSym[i++] = oSyms[0]; } } catch (CalcException e) { oParser.mbInThrow = true; oInSym[i++] = e.getSymbol(); } CalcSymbol.delete(oArg, oParser); } } CalcSymbol oSym = new CalcSymbol(0); CalcSymbol oDoSym = new CalcSymbol(0); try { // // From the last argument in the array to the first Do ... // for (int i = nInArgs - 1; i >= 0; i--) { oParser.mStack.push(oInSym[i]); // // Execute the step-part and pop the result off the stack. // oParser.moCode.execute(oParser, nPC + 5); CalcSymbol.delete(oSym, oParser); oSym = oParser.mStack.pop(); oParser.getNumeric(oSym); // // Execute the do-part. // oParser.moCode.execute(oParser, nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 3]).intValue()); CalcSymbol.delete(oDoSym, oParser); oDoSym = oParser.mStack.pop(); String sVal = oParser.getString(oDoSym); CalcSymbol.delete(oDoSym, oParser); oDoSym = new CalcSymbol(sVal); if (oParser.mbInBreak) break; else if (oParser.mbInContinue) oParser.mbInContinue = false; } oParser.mStack.push(oDoSym); } catch (CalcException e) { CalcSymbol.delete(oSym, oParser); oParser.mbInThrow = true; oParser.mStack.push(e.getSymbol()); } CalcSymbol.delete(oSym, oParser); if (oParser.mbInBreak) oParser.mbInBreak = false; if (oParser.mbInContinue) oParser.mbInContinue = false; } oParser.moCode.mnProgCtr = nPC + ((Integer) oParser.moCode.moCodeBase[nPC + 4]).intValue(); } /** * Unary operator. A utility function to deal with most unary operators. * *

Pop one operands off the stack, apply unary operator on * its values and push the resulting operand back onto the stack. * * @param oParser the FormCalc parser. * @param oUnop the unary operator method. */ static void Unary(CalcParser oParser, Method oUnop) { CalcSymbol oSym = oParser.mStack.pop(); // Pop operand CalcSymbol oRetSym = new CalcSymbol(); try { if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.getExceptions(oSym); oRetSym = new CalcSymbol(0); } else { if (oUnop == gUminus) { double nVal = oParser.getNumeric(oSym); if (nVal < 0) { oRetSym = new CalcSymbol(- nVal); } else { StringBuilder sVal = new StringBuilder("-"); sVal.append(FormCalcUtil.dblToStr(nVal, 11)); FormCalcUtil.trimZeroes(sVal); FormCalcUtil.trimRadix(sVal); oRetSym = new CalcSymbol(sVal.toString()); } } else if (oUnop == gUplus) { double nVal = oParser.getNumeric(oSym); if (nVal < 0) { oRetSym = new CalcSymbol(nVal); } else { StringBuilder sVal = new StringBuilder("+"); sVal.append(FormCalcUtil.dblToStr(nVal, 11)); FormCalcUtil.trimZeroes(sVal); FormCalcUtil.trimRadix(sVal); oRetSym = new CalcSymbol(sVal.toString()); } } else if (oUnop == gNot) { double nVal = oParser.getNumeric(oSym); oRetSym = new CalcSymbol((nVal == 0.) ? 1. : 0.); } else if (oUnop == gNoop) { oRetSym = new CalcSymbol(oSym); } else if (oUnop == gDeref) { oRetSym = new CalcSymbol(oSym); if (oRetSym.getType() == CalcSymbol.TypeAccessor) { CalcSymbol oTmpSym = oParser.getOneValue(oRetSym); CalcSymbol.delete(oRetSym, oParser); oRetSym = oTmpSym; } } if (oRetSym.getType() == CalcSymbol.TypeError) oParser.mbInThrow = true; } } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } CalcSymbol.delete(oSym, oParser); oParser.mStack.push(oRetSym); } /** * Binary operator. A utility function to deal with most binary operators. * *

Pop two operands off the stack, apply binary operator on * their values and push the resulting operand back onto the stack. * * @param oParser the FormCalc parser. * @param oBinop the binary operator method. */ private static void Binary(CalcParser oParser, Method oBinop) { CalcSymbol rSym = oParser.mStack.pop(); // Pop second operand CalcSymbol lSym = oParser.mStack.pop(); // Pop first operand CalcSymbol oRetSym = null; try { if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.getExceptions(lSym); oParser.getExceptions(rSym); oRetSym = new CalcSymbol(0); } else { if (oBinop != gList) { int lSymType = lSym.getType(); if (lSymType == CalcSymbol.TypeAccessor) { CalcSymbol oSym = oParser.getOneValue(lSym); CalcSymbol.delete(lSym, oParser); lSym = oSym; lSymType = lSym.getType(); } if (lSymType == CalcSymbol.TypeVariable && lSym.getStringValue() == null) { lSymType = CalcSymbol.TypeNull; } int rSymType = rSym.getType(); if (rSymType == CalcSymbol.TypeAccessor) { CalcSymbol oSym = oParser.getOneValue(rSym); CalcSymbol.delete(rSym, oParser); rSym = oSym; rSymType = rSym.getType(); } if (rSymType == CalcSymbol.TypeVariable && rSym.getStringValue() == null) { rSymType = CalcSymbol.TypeNull; } if (lSymType == CalcSymbol.TypeNull && rSymType == CalcSymbol.TypeNull) { oRetSym = new CalcSymbol(); } else { double lVal = oParser.getNumeric(lSym); double rVal = oParser.getNumeric(rSym); double nRetVal = Double.NaN; if (oBinop == gOr) nRetVal = (lVal != 0. || rVal != 0.) ? 1. : 0.; else if (oBinop == gAnd) nRetVal = (lVal != 0. && rVal != 0.) ? 1. : 0.; else if (oBinop == gAdd) nRetVal = lVal + rVal; else if (oBinop == gSub) nRetVal = lVal - rVal; else if (oBinop == gMul) nRetVal = lVal * rVal; else if (oBinop == gDiv) nRetVal = lVal / rVal; oRetSym = new CalcSymbol(nRetVal); if (oRetSym.getType() == CalcSymbol.TypeError) oParser.mbInThrow = true; } } else /* if (oBinop == gList) */ { oParser.getExceptions(lSym); oRetSym = oParser.getOneValue(rSym); } } } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } CalcSymbol.delete(lSym, oParser); CalcSymbol.delete(rSym, oParser); oParser.mStack.push(oRetSym); } /** * Relational operator. A utility function to deal with the relational * operators. * *

Pop two operands off the stack, apply relational operator * on their values and push the resulting operand back onto the stack. * * @param oParser the FormCalc parser. * @param oRelop the relational operator method. */ private static void Relational(CalcParser oParser, Method oRelop) { CalcSymbol rSym = oParser.mStack.pop(); // Pop second operand CalcSymbol lSym = oParser.mStack.pop(); // Pop first operand CalcSymbol oRetSym = null; try { if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.getExceptions(rSym); oParser.getExceptions(lSym); oRetSym = new CalcSymbol(0); } else { double nRetVal = 0; // // deal with error-valued and return-valued args. // CalcSymbol oSymArg[] = { lSym, rSym }; Builtins.limitExceptionArgs(oSymArg); // // deal with accessor-valued args. // int lSymType = lSym.getType(); if (lSymType == CalcSymbol.TypeAccessor) { CalcSymbol oSym = oParser.getOneValue(lSym); CalcSymbol.delete(lSym, oParser); lSym = oSym; lSymType = lSym.getType(); } int rSymType = rSym.getType(); if (rSymType == CalcSymbol.TypeAccessor) { CalcSymbol oSym = oParser.getOneValue(rSym); CalcSymbol.delete(rSym, oParser); rSym = oSym; rSymType = rSym.getType(); } // // Applied a modification to previous fix for Watson 2523207, // essentially guarding it with a legacy flag, as this fix // potentially results in form DOM changes. // int lActualSymType; int rActualSymType; if (oParser.moLegacyScripting.contains(CalcParser.LegacyVersion.V32_SCRIPTING)){ lActualSymType = lSymType; rActualSymType = rSymType; } else { lActualSymType = oParser.getActualType(lSym).getType(); rActualSymType = oParser.getActualType(rSym).getType(); } // // deal with reference args. // if ((oRelop == gEq || oRelop == gNe) && lSymType == CalcSymbol.TypeReference && rSymType == CalcSymbol.TypeReference) { if (oRelop == gEq) nRetVal = (lSym.getObjValue() == rSym.getObjValue()) ? 1. : 0.; else if (oRelop == gNe) nRetVal = (lSym.getObjValue() != rSym.getObjValue()) ? 1. : 0.; } // // deal with numeric-valued string args. // else if (lSym.isNumeric() && rSym.isNumeric()) { double rVal = oParser.getNumeric(rSym); double lVal = oParser.getNumeric(lSym); if (oRelop == gEq) nRetVal = (lVal == rVal) ? 1. : 0.; else if (oRelop == gNe) nRetVal = (lVal != rVal) ? 1. : 0.; else if (oRelop == gGt) nRetVal = (lVal > rVal) ? 1. : 0.; else if (oRelop == gGe) nRetVal = (lVal >= rVal) ? 1. : 0.; else if (oRelop == gLt) nRetVal = (lVal < rVal) ? 1. : 0.; else if (oRelop == gLe) nRetVal = (lVal <= rVal) ? 1. : 0.; } // // deal with string-valued args. // else if ((lSymType == CalcSymbol.TypeString || lSymType == CalcSymbol.TypeVariable) && (rSymType == CalcSymbol.TypeString || rSymType == CalcSymbol.TypeVariable)) { String rStr = oParser.getString(rSym); String lStr = oParser.getString(lSym); Collator oCol = Collator.getInstance(); if (oRelop == gEq) nRetVal = (oCol.compare(lStr, rStr) == 0) ? 1. : 0.; else if (oRelop == gNe) nRetVal = (oCol.compare(lStr, rStr) != 0) ? 1. : 0.; else if (oRelop == gGt) nRetVal = (oCol.compare(lStr, rStr) > 0) ? 1. : 0.; else if (oRelop == gGe) nRetVal = (oCol.compare(lStr, rStr) >= 0) ? 1. : 0.; else if (oRelop == gLt) nRetVal = (oCol.compare(lStr, rStr) < 0) ? 1. : 0.; else if (oRelop == gLe) nRetVal = (oCol.compare(lStr, rStr) <= 0) ? 1. : 0.; } // // deal with null-valued args. // else if (lActualSymType == CalcSymbol.TypeNull || rActualSymType == CalcSymbol.TypeNull) { oParser.getNumeric(rSym); oParser.getNumeric(lSym); if (oRelop == gEq) nRetVal = (lActualSymType == rActualSymType) ? 1. : 0.; else if (oRelop == gNe) nRetVal = (lActualSymType != rActualSymType) ? 1. : 0.; else if (oRelop == gGt) nRetVal = 0.; else if (oRelop == gGe) nRetVal = (lActualSymType == rActualSymType) ? 1. : 0.; else if (oRelop == gLt) nRetVal = 0.; else if (oRelop == gLe) nRetVal = (lActualSymType == rActualSymType) ? 1. : 0.; } else { double rVal = oParser.getNumeric(rSym); double lVal = oParser.getNumeric(lSym); if (oRelop == gEq) nRetVal = (lVal == rVal) ? 1. : 0.; else if (oRelop == gNe) nRetVal = (lVal != rVal) ? 1. : 0.; else if (oRelop == gGt) nRetVal = (lVal > rVal) ? 1. : 0.; else if (oRelop == gGe) nRetVal = (lVal >= rVal) ? 1. : 0.; else if (oRelop == gLt) nRetVal = (lVal < rVal) ? 1. : 0.; else if (oRelop == gLe) nRetVal = (lVal <= rVal) ? 1. : 0.; } oRetSym = new CalcSymbol(nRetVal); if (oRetSym.getType() == CalcSymbol.TypeError) oParser.mbInThrow = true; } } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } CalcSymbol.delete(rSym, oParser); CalcSymbol.delete(lSym, oParser); oParser.mStack.push(oRetSym); } /** * Concat operator. A utility function to deal with the dot, dot dot * and dot hash operators. * *

Pop two operands off the stack, apply concatenation operator * on their names and push the resulting operand back onto the stack. * * @param oParser the FormCalc parser. * @param oCatop the concatenation operator method. */ private static void Concat(CalcParser oParser, Method oCatop) { CalcSymbol rSym = oParser.mStack.pop(); // Pop second operand CalcSymbol lSym = oParser.mStack.pop(); // Pop first operand CalcSymbol oRetSym = null; try { if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { oParser.getExceptions(rSym); oParser.getExceptions(lSym); oRetSym = new CalcSymbol(0); } else { if (rSym.getType() == CalcSymbol.TypeError) { oParser.mbInThrow = true; throw new CalcException(rSym); } else if (rSym.getType() == CalcSymbol.TypeVariable) { oParser.mbInThrow = true; MsgFormat sFmt = new MsgFormat(ResId.FC_ERR_VAR_USED); sFmt.format(rSym.getName()); CalcSymbol oSym = new CalcSymbol(sFmt.toString(), true, 0, 0); throw new CalcException(oSym); } else if (rSym.getType() == CalcSymbol.TypeReference) { oParser.mbInThrow = true; MsgFormat sFmt = new MsgFormat(ResId.FC_ERR_REF_USED); sFmt.format(rSym.getName()); CalcSymbol oSym = new CalcSymbol(sFmt.toString(), true, 0, 0); throw new CalcException(oSym); } String rContainer = rSym.getName(); String lContainer = (lSym.getType() == CalcSymbol.TypeReference) ? "#0" : lSym.getName(); // // Concatenate the two containers using the dot notation. // StringBuilder sResult = new StringBuilder(lContainer.length() + 2 + rContainer.length()); sResult.append(lContainer); sResult.append('.'); if (oCatop == gDotdot) sResult.append('.'); else if (oCatop == gDothash) sResult.append('#'); sResult.append(rContainer); // // Push the result as a reference or accessor CalcSymbol // onto the stack. // oRetSym = new CalcSymbol(); oRetSym.setName(sResult.toString()); if (lSym.getType() == CalcSymbol.TypeAccessor) { if (rSym.getObjs() > 1) { Obj[] oObj = rSym.getObjValues(); oObj[0] = lSym.getObjValue(); oRetSym.setObjValues(oObj); } else { oRetSym.setObjValue(lSym.getObjValue()); } } else if (lSym.getType() == CalcSymbol.TypeReference) { if (rSym.getObjs() > 1) { Obj[] oObj = rSym.getObjValues(); oObj[0] = lSym.getObjValue(); oRetSym.setObjValues(oObj); } else { oRetSym.setObjValue(lSym.getObjValue()); } } oRetSym.setType(CalcSymbol.TypeAccessor); } } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } CalcSymbol.delete(rSym, oParser); CalcSymbol.delete(lSym, oParser); oParser.mStack.push(oRetSym); } /** * Assign operator. A utility function to deal with the assignment * operators. * *

Pop two operands off the stack, apply the assignment operator * and push the resulting operand back onto the stack. * * @param oParser the FormCalc parser. * @param oAsgnop the assign operator method. */ private static void Assign(CalcParser oParser, Method oAsgnop) { CalcSymbol rSym = new CalcSymbol(); CalcSymbol lSym = new CalcSymbol(); if (oAsgnop == gAsgn) { rSym = oParser.mStack.pop(); // Pop source value lSym = oParser.mStack.pop(); // Pop target value } else if (oAsgnop == gAsgn2) { lSym = oParser.mStack.pop(); // Pop target value rSym = oParser.mStack.pop(); // Pop source value } CalcSymbol oRetSym = null; if (oParser.mbInThrow || oParser.mbInBreak || oParser.mbInContinue) { try { oParser.getExceptions(rSym); oParser.getExceptions(lSym); oRetSym = new CalcSymbol(0); } catch (CalcException e) { oParser.mbInThrow = true; oRetSym = e.getSymbol(); } } else { oRetSym = new CalcSymbol(rSym); // // Loop until all RHS accessors have been evaluated. // do { CalcSymbol oVarSym = null; switch (oRetSym.getType()) { case CalcSymbol.TypeAccessor: CalcSymbol oTmpSym = oParser.getOneValue(oRetSym); CalcSymbol.delete(oRetSym, oParser); oRetSym = oTmpSym; continue; case CalcSymbol.TypeDouble: oRetSym.setTypeToString(); break; case CalcSymbol.TypeString: break; case CalcSymbol.TypeVariable: oVarSym = oParser.moData.lookup(oRetSym); if (oVarSym != oRetSym) oRetSym.setStringValue(oVarSym.getStringValue()); break; case CalcSymbol.TypeReturn: break; case CalcSymbol.TypeNull: break; case CalcSymbol.TypeError: break; case CalcSymbol.TypeReference: break; default: assert(true); break; } break; } while (true); switch (oRetSym.getType()) { // // Having dealt with these above, panic if seen again. // case CalcSymbol.TypeAccessor: case CalcSymbol.TypeDouble: assert (true); break; // // Assign only non-error/non-return values // case CalcSymbol.TypeError: case CalcSymbol.TypeReturn: oParser.mbInThrow = true; break; case CalcSymbol.TypeVariable: case CalcSymbol.TypeString: case CalcSymbol.TypeNull: if (lSym.getType() == CalcSymbol.TypeReference) { try { if (lSym.getObjValue() != null) { oParser.moScriptHost.putItem(lSym.getObjValues(), oRetSym); } else { oParser.mbInThrow = true; MsgFormat sFmt = new MsgFormat(ResId.FC_ERR_REF_NULL); sFmt.format(lSym.getName()); oRetSym = new CalcSymbol(sFmt.toString(), true, 0, 0); } } catch (CalcException e) { CalcSymbol.delete(oRetSym, oParser); oParser.mbInThrow = true; oRetSym = e.getSymbol(); } } else if (lSym.getType() == CalcSymbol.TypeAccessor) { if (oRetSym.getType() == CalcSymbol.TypeVariable) oRetSym.setTypeToString(); else if (oRetSym.getType() == CalcSymbol.TypeDouble) oRetSym.setTypeToString(); else if (oRetSym.getType() == CalcSymbol.TypeString) oRetSym.setTypeToString(); try { oParser.moScriptHost.putItemValue(lSym.getName(), lSym.getObjValues(), oRetSym); } catch (CalcException e) { CalcSymbol.delete(oRetSym, oParser); oParser.mbInThrow = true; oRetSym = e.getSymbol(); } } else if (lSym.getType() == CalcSymbol.TypeVariable) { lSym.setStringValue(oRetSym.getStringValue()); } else if (lSym.getType() == CalcSymbol.TypeError) { CalcSymbol.delete(oRetSym, oParser); oRetSym = lSym; } break; case CalcSymbol.TypeReference: if (lSym.getType() == CalcSymbol.TypeAccessor) { try { CalcSymbol oTmpSym = oParser.getRefValue(oRetSym); CalcSymbol.delete(oRetSym, oParser); oRetSym = oTmpSym; oParser.moScriptHost.putItemValue(lSym.getName(), lSym.getObjValues(), oRetSym); } catch (CalcException e) { CalcSymbol.delete(oRetSym, oParser); oParser.mbInThrow = true; oRetSym = e.getSymbol(); } } else if (lSym.getType() == CalcSymbol.TypeVariable) { lSym.setScope(0); lSym.setStringValue(null); lSym.setObjValue(oRetSym.getObjValue()); lSym.setType(CalcSymbol.TypeReference); } else if (lSym.getType() == CalcSymbol.TypeReference) { Obj oObj = oRetSym.getObjValue(); lSym.setObjValue(oObj); if (oObj == null) { lSym.setScope(oParser.moScope.getScope()); lSym.setStringValue(""); lSym.setType(CalcSymbol.TypeVariable); } } break; default: assert (true); break; } } CalcSymbol.delete(rSym, oParser); CalcSymbol.delete(lSym, oParser); oParser.mStack.push(oRetSym); } Object[] moCodeBase; // the instruction space code base. private int mnProgCtr; // the instruction space program counter. private int mnProgBase; // the instruction space program start base. private int mnProgEnd; // the instruction space program end base. private int mnCodePtr; // the instruction space code pointer. private int mnCodeSize; // the instruction space code size. // Javaport: Not required! // private DebugLineInfo moDebugLineNo; // the line number to moCodeBase). // private int mnDebugPrevLine; // last line executed // private int mnDebugPrevStoppedAtLine; // last line stopped at. // private int mnDebugStopAtStackDepth; // stack depth that should trigger a stop // private int mnDebugPollCounter; // periodically poll debugger interface }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy