0001: package murlen.util.fscript;
0002:
0003: import java.io.*;
0004: import java.util.HashMap;
0005: import java.util.ArrayList;
0006:
0007: /**
0008: * <b>Parser - Does the parsing - i.e it's the brains of the code.</b>
0009: * <p>
0010: * <I>Copyright (C) 2000-2003 murlen.</I></p>
0011: * <p>
0012: * This library is free software; you can redistribute it and/or
0013: * modify it under the terms of the GNU Library General Public
0014: * License as published by the Free Software Foundation; either
0015: * version 2 of the License, or (at your option) any later version.</p>
0016: * <p>
0017: * This library is distributed in the hope that it will be useful,
0018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0020: * Library General Public License for more details.</p>
0021: *
0022: * <p>You should have received a copy of the GNU Library General Public
0023: * License along with this library; if not, write to the Free
0024: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA </p>
0025: * @author murlen
0026: * @author Joachim Van der Auwera
0027: * @version 1.12
0028: *
0029: * modifications by Joachim Van der Auwera
0030: * 14.08.2001 added support for indexed variables
0031: * 20.08.2001 -clean handling of setVar with null value
0032: * - cleaner handling of if with null condition
0033: * - make sure running empty script does nothing
0034: * - extra info when throwing an exception (with surrounding lines)
0035: * - changed operator prioritues for && and ||
0036: * - fixed bug in parseIf with handling of nesting of if clauses with else
0037: * - check for missing endif or endwhile (caused infinit loops)
0038: * - check for a null to prevernt excepion in parseExpr
0039: * 28.08.2001
0040: * - call to host.getVar() replaced by host.F() (and added
0041: * proper exception handling, in that case)
0042: * 31.08.2001
0043: * - test on if condition being of correct type re-introduced
0044: * 10.09.2001
0045: * - added < <= > >= on strings
0046: * 23.11.2001
0047: * - allow adding strings with anything
0048: * 04.12.2001
0049: * - allow add/subtract/multiply/divide int with double
0050: * 24.04.2002
0051: * - fixed a bug in parsing of nested if clause when one of the nested items contains a
0052: * "then" token with the statements on the next line(s) (test for TT_EOL instead of TT_EOF)
0053: * 30.04.2002
0054: * - handle all exceptions on all getVarEntry, setVarEntry and callFunctionEntry calls
0055: * 06.05.2002
0056: * - error messages now unique
0057: * - TT_EOF handled better in some cases
0058: * 05-06.08.2002
0059: * - removed some redundant code
0060: * - introduced parseFunctionEnd to catch functions without return (it worked before, so...)
0061: * 21.10.2002
0062: * - added == for FSObject instances
0063: * 30.10.2002 object now allowed as function parameter
0064: * 07.11.2002 better error handling when parsing an expression
0065: * 20.11.2002 make != work for objects
0066: * 15.03.2003 getContext() added JVDA
0067: * 17.09.2003 removed checking for mismatched quotes and brackets, and moved to LineLoader
0068: * 23.11.2003 recycle LexAnn objects (saves object allocation/release) JVDA
0069: * 24.11.2003 some extra (smallish) speed improvements (also to reduce garbage a little bit)
0070: * 25.02.2004
0071: * - proper evaluation of FSObject with contained boolean/integer for if/while
0072: * - more powerful compare for FSObject instance with something else
0073: * 14.04.2004 elsif opperator support
0074: */
0075: final class Parser {
0076: public static final Integer FS_TRUE = new Integer(1);
0077: public static final Integer FS_FALSE = new Integer(0);
0078:
0079: //simple data class used internally to store function defs
0080: class FuncEntry {
0081: int startLine; //start line of function
0082: int endLine; //end line of function
0083: ArrayList paramNames; //list of parameter names
0084: HashMap params; //hashmap of parameters
0085:
0086: FuncEntry() {
0087: startLine = 0;
0088: endLine = 0;
0089: paramNames = new ArrayList(4);
0090: params = new HashMap();
0091: }
0092:
0093: public String toString() {
0094: String s;
0095:
0096: s = startLine + " ";
0097: s = s + endLine + " ";
0098: s = s + paramNames + " ";
0099: s = s + params;
0100:
0101: return s;
0102: }
0103: }
0104:
0105: //exception that occurs when someone calls return
0106: class RetException extends Exception {
0107: }
0108:
0109: private LineLoader code; //the code
0110: private LexAnn tok; //tokenizer
0111:
0112: private int maxLine;
0113: private HashMap vars; //function local variables
0114: private HashMap gVars; //global variables
0115: private static HashMap opPrio; //operator priority table
0116: private FScript host; //link to hosting FScript object
0117: private HashMap funcs; //function map
0118: private Object retVal; //return value
0119:
0120: private Parser subParser; //nested parser, for callback routines in FSParserExtension
0121:
0122: private String error[];
0123:
0124: /** Public constructor
0125: * @param h a reference to the FScript object
0126: */
0127: Parser(FScript h) {
0128: vars = new HashMap();
0129: gVars = null;
0130: funcs = new HashMap();
0131: host = h;
0132:
0133: setPrio();
0134: }
0135:
0136: //only used for function calls - note it is private
0137: private Parser(FScript h, HashMap l, HashMap g, HashMap f) {
0138: vars = l;
0139: gVars = g;
0140: funcs = f;
0141: host = h;
0142: }
0143:
0144: /**
0145: * Sets the LineLoader clas to be used for input
0146: * @param in - the class
0147: */
0148: void setCode(LineLoader in) {
0149: code = in;
0150: }
0151:
0152: /**
0153: *The main parsing function
0154: *@param from - the start line number
0155: *@param to - the end line number
0156: *returns an Object (currently a Integer or String) depending
0157: *on the return value of the code parsed, or null if none.
0158: */
0159: Object parse(int from, int to) throws IOException, FSException {
0160:
0161: // nothing to do when starting beond the code end
0162: if (code.lineCount() <= from)
0163: return null;
0164:
0165: maxLine = to;
0166: code.setCurLine(from);
0167: tok = new LexAnn(code.getLine());
0168: getNextToken();
0169: while (tok.ttype != LexAnn.TT_EOF) {
0170:
0171: //a script must always start with a word...
0172:
0173: try {
0174: parseStmt();
0175: } catch (RetException e) {
0176: return retVal;
0177: }
0178:
0179: getNextToken();
0180: }
0181:
0182: return null;
0183:
0184: }
0185:
0186: /**
0187: * The main parsing function
0188: * @param line - the line to be parsed
0189: * @return an Object depending on the return value of the code parsed, or null if none.
0190: */
0191: Object parse(String line) throws IOException, FSException {
0192: int oldLine = code.curLine;
0193: try {
0194: code.curLine = -1;
0195: code.forError = line;
0196: char[] chars = line.toCharArray();
0197: LineLoader.checkLine(chars);
0198: tok = new LexAnn(chars);
0199: tok.nextToken();
0200: // a script must always start with a word...
0201: try {
0202: parseStmt();
0203: } catch (RetException e) {
0204: return retVal;
0205: }
0206: } finally {
0207: code.curLine = oldLine;
0208: }
0209: return null;
0210: }
0211:
0212: /**
0213: * Resets the parser state.
0214: */
0215: void reset() {
0216: if (vars != null) {
0217: vars.clear();
0218: }
0219: if (gVars != null) {
0220: gVars.clear();
0221: }
0222: }
0223:
0224: //builds the operator priority table
0225: private void setPrio() {
0226: if (opPrio == null) {
0227: opPrio = new HashMap();
0228: //from low to high
0229: Integer prio;
0230: prio = new Integer(1);
0231: opPrio.put(new Integer(LexAnn.TT_LOR), prio);
0232: prio = new Integer(2);
0233: opPrio.put(new Integer(LexAnn.TT_LAND), prio);
0234: prio = new Integer(5);
0235: opPrio.put(new Integer(LexAnn.TT_LEQ), prio);
0236: opPrio.put(new Integer(LexAnn.TT_LNEQ), prio);
0237: opPrio.put(new Integer(LexAnn.TT_LGR), prio);
0238: opPrio.put(new Integer(LexAnn.TT_LGRE), prio);
0239: opPrio.put(new Integer(LexAnn.TT_LLS), prio);
0240: opPrio.put(new Integer(LexAnn.TT_LLSE), prio);
0241: prio = new Integer(10);
0242: opPrio.put(new Integer(LexAnn.TT_PLUS), prio);
0243: opPrio.put(new Integer(LexAnn.TT_MINUS), prio);
0244: prio = new Integer(20);
0245: opPrio.put(new Integer(LexAnn.TT_MULT), prio);
0246: opPrio.put(new Integer(LexAnn.TT_DIV), prio);
0247: opPrio.put(new Integer(LexAnn.TT_MOD), prio);
0248: }
0249: }
0250:
0251: //statement - top level thing
0252: private void parseStmt() throws IOException, FSException,
0253: RetException {
0254:
0255: switch (tok.ttype) {
0256:
0257: case LexAnn.TT_DEFINT:
0258: case LexAnn.TT_DEFSTRING:
0259: case LexAnn.TT_DEFDOUBLE:
0260: case LexAnn.TT_DEFOBJECT: {
0261: parseVarDef();
0262: break;
0263: }
0264:
0265: case LexAnn.TT_IF: {
0266: parseIf();
0267: break;
0268: }
0269: case LexAnn.TT_WHILE: {
0270: parseWhile();
0271: break;
0272: }
0273: case LexAnn.TT_RETURN: {
0274: parseReturn();
0275: break;
0276: }
0277: case LexAnn.TT_DEFFUNC: {
0278: parseFunctionDef();
0279: break;
0280: }
0281: case LexAnn.TT_EDEFFUNC: {
0282: parseFunctionEnd();
0283: break;
0284: }
0285: case LexAnn.TT_EIF:
0286: throw new FSException("unexpected endif");
0287: case LexAnn.TT_EWHILE:
0288: throw new FSException("unexpected endwhile");
0289:
0290: case LexAnn.TT_FUNC: {
0291: parseFunc();
0292: break;
0293: }
0294: case LexAnn.TT_ARRAY: {
0295: parseArrayAssign();
0296: break;
0297: }
0298: case LexAnn.TT_WORD: {
0299: parseAssign();
0300: break;
0301: }
0302: case LexAnn.TT_EOL: {
0303: tok.nextToken();
0304: break;
0305: }
0306: case LexAnn.TT_EOF: {
0307: // all done
0308: break;
0309: }
0310: default: {
0311: parseError("Expected identifier " + tok);
0312:
0313: }
0314: }
0315:
0316: }
0317:
0318: private void parseFunc() throws IOException, FSException {
0319: String name;
0320:
0321: name = (String) tok.value;
0322:
0323: //should be a '('
0324: getNextToken();
0325:
0326: parseCallFunc(name);
0327: getNextToken();
0328: }
0329:
0330: private void parseArrayAssign() throws IOException, FSException {
0331: String name;
0332: Object index;
0333: Object val;
0334:
0335: name = (String) tok.value;
0336: getNextToken(); // should be a '['
0337: getNextToken(); // should be the index
0338: index = parseExpr();
0339: getNextToken(); // should be a ']'
0340:
0341: //getNextToken();
0342: if (tok.ttype != LexAnn.TT_EQ) {
0343: parseError("Expected '='");
0344: } else {
0345: getNextToken();
0346: val = parseExpr();
0347: try {
0348: host.setVarEntry(name, index, val);
0349: } catch (Exception e) {
0350: parseError(e.getMessage());
0351: }
0352: }
0353: }
0354:
0355: //handles 'return' statements
0356: private void parseReturn() throws IOException, FSException,
0357: RetException {
0358:
0359: getNextToken();
0360:
0361: retVal = parseExpr();
0362: throw new RetException();
0363: }
0364:
0365: // handle endif without return, just return 1 (or true)
0366: private void parseFunctionEnd() throws RetException {
0367: retVal = FS_TRUE;
0368: throw new RetException();
0369: }
0370:
0371: //Asignment parser
0372: private void parseAssign() throws IOException, FSException {
0373: String name;
0374: Object val;
0375:
0376: name = (String) tok.value;
0377: getNextToken();
0378:
0379: if (tok.ttype != LexAnn.TT_EQ) {
0380: parseError("Expected '='");
0381: } else {
0382:
0383: getNextToken();
0384: val = parseExpr();
0385:
0386: if (hasVar(name)) {
0387: setVar(name, val);
0388: } else {
0389: try {
0390: host.setVarEntry(name, null, val);
0391: } catch (Exception e) {
0392: parseError(e.getMessage());
0393: }
0394: }
0395: }
0396: }
0397:
0398: Object callFunction(String name, ArrayList params)
0399: throws IOException, FSException {
0400:
0401: FuncEntry fDef;
0402: int n;
0403: int oldLine;
0404: Parser oldSubParser;
0405: Object val;
0406:
0407: val = null;
0408:
0409: //Check we have a definition for the function
0410: if (funcs.containsKey(name)) {
0411:
0412: fDef = (FuncEntry) funcs.get(name);
0413:
0414: //Check params and def match
0415: if (fDef.paramNames.size() != params.size()) {
0416: parseError("Expected " + fDef.paramNames.size()
0417: + " parameters, Found " + params.size());
0418: }
0419:
0420: //Create a new parser instance to handle call
0421: Parser p;
0422: HashMap locals = new HashMap();
0423:
0424: //Push the params into the local scope
0425: for (n = 0; n < fDef.paramNames.size(); n++) {
0426: locals.put(fDef.paramNames.get(n), params.get(n));
0427: }
0428: //watch for recursive calls
0429: if (gVars == null) {
0430: p = new Parser(host, locals, vars, funcs);
0431: } else {
0432: p = new Parser(host, locals, gVars, funcs);
0433: }
0434: //cache the current execution point
0435: oldLine = code.getCurLine();
0436: p.setCode(code);
0437: oldSubParser = subParser;
0438: subParser = p;
0439:
0440: //let it rip
0441: val = p.parse(fDef.startLine + 1, fDef.endLine - 1);
0442:
0443: //reset execution point
0444: subParser = oldSubParser;
0445: code.setCurLine(oldLine);
0446:
0447: } else {//calls into super class code...}
0448: try {
0449: val = host.callFunctionEntry(name, params);
0450: } catch (Exception e) {
0451: parseError(e.getMessage());
0452: }
0453: }
0454:
0455: return val;
0456:
0457: }
0458:
0459: //Handle calls to a function
0460: private Object parseCallFunc(String name) throws IOException,
0461: FSException {
0462:
0463: ArrayList params = new ArrayList(4);
0464:
0465: //Set up the parameters
0466: do {
0467: getNextToken();
0468: if (tok.ttype == ',') {
0469: getNextToken();
0470: } else if (tok.ttype == ')') {
0471: break;
0472: }
0473: params.add(parseExpr());
0474: } while (tok.ttype == ',');
0475:
0476: return callFunction(name, params);
0477:
0478: }
0479:
0480: //handles function definitions
0481: private void parseFunctionDef() throws IOException, FSException {
0482:
0483: FuncEntry fDef = new FuncEntry();
0484: Object val;
0485: String name, fName;
0486:
0487: fDef.startLine = code.getCurLine();
0488:
0489: getNextToken();
0490:
0491: //should be the function name
0492: if (tok.ttype != LexAnn.TT_FUNC) {
0493: parseError("Expected function start identifier");
0494: }
0495: fName = (String) tok.value;
0496: getNextToken();
0497:
0498: //should be a '('
0499: if (tok.ttype != '(') {
0500: parseError("Expected (");
0501: }
0502:
0503: getNextToken();
0504: //parse the header...
0505: while (tok.ttype != ')') {
0506: val = null; //keep the compiler happy..
0507:
0508: if (tok.ttype == LexAnn.TT_DEFINT) {
0509: val = FS_FALSE;
0510: } else if (tok.ttype == LexAnn.TT_DEFSTRING) {
0511: val = new String("");
0512: } else if (tok.ttype == LexAnn.TT_DEFOBJECT) {
0513: val = new FSObject();
0514: } else {
0515: parseError("Expected type name");
0516: }
0517:
0518: getNextToken();
0519:
0520: if (tok.ttype != LexAnn.TT_WORD) {
0521: parseError("Expected function parameter name identifier");
0522: }
0523:
0524: name = (String) tok.value;
0525:
0526: fDef.paramNames.add(name);
0527: fDef.params.put(name, val);
0528:
0529: getNextToken();
0530: if (tok.ttype == ',')
0531: getNextToken();
0532: }
0533:
0534: //now we just skip to the endfunction
0535:
0536: while ((tok.ttype != LexAnn.TT_EDEFFUNC)
0537: && (tok.ttype != LexAnn.TT_EOF)) {
0538: getNextToken();
0539: if (tok.ttype == LexAnn.TT_DEFFUNC)
0540: parseError("Nested functions are illegal");
0541: }
0542:
0543: fDef.endLine = code.getCurLine();
0544: getNextToken();
0545:
0546: funcs.put(fName, fDef);
0547:
0548: }
0549:
0550: //Really process tthe expressions (internal recursive calls only), all
0551: //external calls call parseExpr()
0552: private Object parseExpr() throws IOException, FSException {
0553:
0554: ETreeNode curNode = null;
0555: boolean end = false;
0556: Object val;
0557: boolean negate = false; //flag for unary minus
0558: boolean not = false;//flag for unary not.
0559: boolean prevOp = true;//flag - true if previous value was an operator
0560:
0561: while (!end) {
0562:
0563: switch (tok.ttype) {
0564:
0565: //the various possible 'values'
0566: case LexAnn.TT_INTEGER:
0567: case LexAnn.TT_DOUBLE:
0568: case LexAnn.TT_STRING:
0569: case LexAnn.TT_WORD:
0570: case LexAnn.TT_FUNC:
0571: case LexAnn.TT_NULL:
0572: case LexAnn.TT_ARRAY: {
0573:
0574: if (!prevOp) {
0575: parseError("Expected Operator");
0576: } else {
0577:
0578: val = null;
0579: ETreeNode node = new ETreeNode();
0580: node.type = ETreeNode.E_VAL;
0581:
0582: switch (tok.ttype) {
0583: //numbers - just get them
0584: case LexAnn.TT_INTEGER: {
0585: val = tok.value;
0586: break;
0587: }
0588: case LexAnn.TT_DOUBLE: {
0589: val = tok.value;
0590: break;
0591: }
0592: //functions - evaluate them
0593: case LexAnn.TT_FUNC: {
0594: String name = (String) tok.value;
0595: getNextToken();
0596: val = parseCallFunc(name);
0597: break;
0598: }
0599: //arrays - evaluate them
0600: case LexAnn.TT_ARRAY: {
0601: String name = (String) tok.value;
0602: getNextToken(); //should be a '['
0603: getNextToken(); //should be the index
0604: Object index = parseExpr();
0605: try {
0606: val = host.getVarEntry(name, index);
0607: } catch (Exception e) {
0608: parseError(e.getMessage());
0609: }
0610: break;
0611: }
0612: //variables - resolve them
0613: case LexAnn.TT_WORD: {
0614: if (hasVar((String) tok.value)) {
0615: val = getVar((String) tok.value);
0616: } else {
0617: try {
0618: val = host.getVarEntry(
0619: (String) tok.value, null);
0620: } catch (Exception e) {
0621: parseError(e.getMessage());
0622: }
0623: }
0624: break;
0625: }
0626: //strings - just get again
0627: case LexAnn.TT_STRING: {
0628: val = tok.value;
0629: break;
0630: }
0631: //null
0632: case LexAnn.TT_NULL: {
0633: val = new FSObject(null);
0634: break;
0635: }
0636: }
0637:
0638: //unary not
0639: if (not) {
0640: if (val instanceof Integer) {
0641: if (((Integer) val).intValue() == 0) {
0642: val = FS_TRUE;
0643: } else {
0644: val = FS_FALSE;
0645: }
0646: not = false;
0647: } else if (val instanceof FSObject
0648: && ((FSObject) val).getObject() instanceof Boolean) {
0649: if (((FSObject) val).getObject().equals(
0650: Boolean.FALSE)) {
0651: val = FS_TRUE;
0652: } else {
0653: val = FS_FALSE;
0654: }
0655: } else if (val instanceof FSObject
0656: && ((FSObject) val).getObject() instanceof Integer) {
0657: if (((Integer) ((FSObject) val).getObject())
0658: .intValue() == 0) {
0659: val = FS_TRUE;
0660: } else {
0661: val = FS_FALSE;
0662: }
0663: } else {
0664: String msg = val.getClass().getName();
0665: if (val instanceof FSObject)
0666: msg = "FSObject with "
0667: + ((FSObject) val)
0668: .getNullClass()
0669: .getName();
0670: parseError("Type mismatch for ! " + msg);
0671: }
0672: }
0673:
0674: //unary minus
0675: if (negate) {
0676: if (val instanceof Integer) {
0677: val = new Integer(-((Integer) val)
0678: .intValue());
0679: } else if (val instanceof Double) {
0680: val = new Double(-((Double) val)
0681: .doubleValue());
0682: } else {
0683: parseError("Type mistmatch for unary -");
0684: }
0685: }
0686:
0687: node.value = val;
0688:
0689: if (curNode != null) {
0690: if (curNode.left == null) {
0691: curNode.left = node;
0692: node.parent = curNode;
0693: curNode = node;
0694:
0695: } else if (curNode.right == null) {
0696: curNode.right = node;
0697: node.parent = curNode;
0698: curNode = node;
0699:
0700: }
0701: } else {
0702: curNode = node;
0703: }
0704:
0705: prevOp = false;
0706: }
0707: break;
0708: }
0709: /*operators - have to be more carefull with these.
0710: We build an expression tree - inserting the nodes at the right
0711: points to get a reasonable approximation to correct operator
0712: precidence*/
0713: case LexAnn.TT_LEQ:
0714: case LexAnn.TT_LNEQ:
0715: case LexAnn.TT_MULT:
0716: case LexAnn.TT_DIV:
0717: case LexAnn.TT_MOD:
0718: case LexAnn.TT_PLUS:
0719: case LexAnn.TT_MINUS:
0720: case LexAnn.TT_LGR:
0721: case LexAnn.TT_LGRE:
0722: case LexAnn.TT_LLSE:
0723: case LexAnn.TT_LLS:
0724: case LexAnn.TT_NOT:
0725: case LexAnn.TT_LAND:
0726: case LexAnn.TT_LOR: {
0727: if (prevOp) {
0728: if (tok.ttype == LexAnn.TT_MINUS) {
0729: negate = true;
0730: } else if (tok.ttype == LexAnn.TT_NOT) {
0731: not = true;
0732: } else {
0733: parseError("Expected Expression");
0734: }
0735: } else {
0736:
0737: ETreeNode node = new ETreeNode();
0738:
0739: node.type = ETreeNode.E_OP;
0740: node.value = new Integer(tok.ttype);
0741:
0742: if (curNode.parent != null) {
0743:
0744: int curPrio = getPrio(tok.ttype);
0745: int parPrio = getPrio(((Integer) curNode.parent.value)
0746: .intValue());
0747:
0748: if (curPrio <= parPrio) {
0749: //this nodes parent is the current nodes grandparent
0750: node.parent = curNode.parent.parent;
0751: //our nodes left leg is now linked into the current nodes
0752: //parent
0753: node.left = curNode.parent;
0754: //hook into grandparent
0755: if (curNode.parent.parent != null) {
0756: curNode.parent.parent.right = node;
0757: }
0758:
0759: //the current nodes parent is now us (because of above)
0760: curNode.parent = node;
0761: //set the current node.
0762: curNode = node;
0763: } else {
0764: //current node's parent's right is now us.
0765: curNode.parent.right = node;
0766: //our nodes left is the current node.
0767: node.left = curNode;
0768: //our nodes parent is the current node's parent.
0769: node.parent = curNode.parent;
0770: //curent nodes parent is now us.
0771: curNode.parent = node;
0772: //set the current node.
0773: curNode = node;
0774: }
0775: } else {
0776: //our node's left is the current node
0777: node.left = curNode;
0778: //current node's parent is us now
0779: //we don't have to set our parent, as it is null.
0780: curNode.parent = node;
0781: //set current node
0782: curNode = node;
0783: }
0784: prevOp = true;
0785: }
0786: break;
0787: }
0788: case '(':
0789: //start of an bracketed expression, recursively call ourself
0790: //to get a value
0791: {
0792: getNextToken();
0793: val = parseExpr();
0794:
0795: if (negate) {
0796: if (val instanceof Integer) {
0797: val = new Integer(-((Integer) val).intValue());
0798: } else if (val instanceof Double) {
0799: val = new Double(-((Double) val).doubleValue());
0800: } else {
0801: parseError("Type mistmatch for unary -");
0802: }
0803: }
0804:
0805: ETreeNode node = new ETreeNode();
0806: node.value = val;
0807: node.type = ETreeNode.E_VAL;
0808:
0809: if (curNode != null) {
0810: if (curNode.left == null) {
0811: curNode.left = node;
0812: node.parent = curNode;
0813: curNode = node;
0814:
0815: } else if (curNode.right == null) {
0816: curNode.right = node;
0817: node.parent = curNode;
0818: curNode = node;
0819:
0820: }
0821: } else {
0822: curNode = node;
0823: }
0824: prevOp = false;
0825: break;
0826: }
0827:
0828: default: {
0829: end = true;
0830: }
0831:
0832: }
0833: if (!end) {
0834: tok.nextToken();
0835: }
0836: }
0837:
0838: //find the top of the tree we just built.
0839: if (curNode == null)
0840: parseError("Missing Expression");
0841: while (curNode.parent != null) {
0842: curNode = curNode.parent;
0843: }
0844:
0845: return evalETree(curNode);
0846:
0847: }
0848:
0849: //convenience function to get operator priority
0850: private int getPrio(int op) {
0851: return ((Integer) opPrio.get(new Integer(op))).intValue();
0852: }
0853:
0854: //evaluates the expression tree recursively
0855: private Object evalETree(ETreeNode node) throws FSException {
0856: Object lVal, rVal;
0857:
0858: if (node == null) {
0859: parseError("Malformed expression");
0860: // this is never reached, just for readability
0861: return null;
0862: }
0863:
0864: if (node.type == ETreeNode.E_VAL) {
0865: return node.value;
0866: }
0867: lVal = evalETree(node.left);
0868: rVal = evalETree(node.right);
0869:
0870: switch (((Integer) node.value).intValue()) {
0871: //call the various eval functions
0872: case LexAnn.TT_PLUS: {
0873: return evalPlus(lVal, rVal);
0874: }
0875: case LexAnn.TT_MINUS: {
0876: return evalMinus(lVal, rVal);
0877: }
0878: case LexAnn.TT_MULT: {
0879: return evalMult(lVal, rVal);
0880: }
0881: case LexAnn.TT_DIV: {
0882: return evalDiv(lVal, rVal);
0883: }
0884: case LexAnn.TT_LEQ: {
0885: return evalEq(lVal, rVal);
0886: }
0887: case LexAnn.TT_LNEQ: {
0888: return evalNEq(lVal, rVal);
0889: }
0890: case LexAnn.TT_LLS: {
0891: return evalLs(lVal, rVal);
0892: }
0893: case LexAnn.TT_LLSE: {
0894: return evalLse(lVal, rVal);
0895: }
0896: case LexAnn.TT_LGR: {
0897: return evalGr(lVal, rVal);
0898: }
0899: case LexAnn.TT_LGRE: {
0900: return evalGre(lVal, rVal);
0901: }
0902: case LexAnn.TT_MOD: {
0903: return evalMod(lVal, rVal);
0904: }
0905: case LexAnn.TT_LAND: {
0906: return evalAnd(lVal, rVal);
0907: }
0908: case LexAnn.TT_LOR: {
0909: return evalOr(lVal, rVal);
0910: }
0911: }
0912:
0913: return null;
0914: }
0915:
0916: //addition
0917: private Object evalPlus(Object lVal, Object rVal)
0918: throws FSException {
0919: if (lVal instanceof Integer && rVal instanceof Integer) {
0920: return new Integer(((Integer) lVal).intValue()
0921: + ((Integer) rVal).intValue());
0922: } else if (lVal instanceof Double && rVal instanceof Double) {
0923: return new Double(((Double) lVal).doubleValue()
0924: + ((Double) rVal).doubleValue());
0925: } else if (lVal instanceof String || rVal instanceof String) {
0926: return new String(lVal.toString() + rVal.toString());
0927: } else if (lVal instanceof Double && rVal instanceof Integer) {
0928: return new Double(((Double) lVal).doubleValue()
0929: + ((Integer) rVal).intValue());
0930: } else if (lVal instanceof Integer && rVal instanceof Double) {
0931: return new Double(((Integer) lVal).intValue()
0932: + ((Double) rVal).doubleValue());
0933: } else {
0934: parseError("Type Mismatch for operator +");
0935: }
0936:
0937: return null;
0938: }
0939:
0940: //subtraction
0941: private Object evalMinus(Object lVal, Object rVal)
0942: throws FSException {
0943: if (lVal instanceof Integer && rVal instanceof Integer) {
0944: return new Integer(((Integer) lVal).intValue()
0945: - ((Integer) rVal).intValue());
0946: } else if (lVal instanceof Double && rVal instanceof Double) {
0947: return new Double(((Double) lVal).doubleValue()
0948: - ((Double) rVal).doubleValue());
0949: } else if (lVal instanceof Double && rVal instanceof Integer) {
0950: return new Double(((Double) lVal).doubleValue()
0951: - ((Integer) rVal).intValue());
0952: } else if (lVal instanceof Integer && rVal instanceof Double) {
0953: return new Double(((Integer) lVal).intValue()
0954: - ((Double) rVal).doubleValue());
0955: } else {
0956: parseError("Type Mismatch for operator -");
0957: }
0958:
0959: return null;
0960: }
0961:
0962: //multiplication
0963: private Object evalMult(Object lVal, Object rVal)
0964: throws FSException {
0965: if (lVal instanceof Integer && rVal instanceof Integer) {
0966: return new Integer(((Integer) lVal).intValue()
0967: * ((Integer) rVal).intValue());
0968: } else if (lVal instanceof Double && rVal instanceof Double) {
0969: return new Double(((Double) lVal).doubleValue()
0970: * ((Double) rVal).doubleValue());
0971: } else if (lVal instanceof Double && rVal instanceof Integer) {
0972: return new Double(((Double) lVal).doubleValue()
0973: * ((Integer) rVal).intValue());
0974: } else if (lVal instanceof Integer && rVal instanceof Double) {
0975: return new Double(((Integer) lVal).intValue()
0976: * ((Double) rVal).doubleValue());
0977: } else {
0978: parseError("Type Mismatch for operator *");
0979: }
0980:
0981: return null;
0982: }
0983:
0984: //modulus
0985: private Object evalMod(Object lVal, Object rVal) throws FSException {
0986: if (lVal instanceof Integer && rVal instanceof Integer) {
0987: return new Integer(((Integer) lVal).intValue()
0988: % ((Integer) rVal).intValue());
0989: } else {
0990: parseError("Type Mismatch for operator %");
0991: }
0992:
0993: return null;
0994: }
0995:
0996: //Logical AND
0997: private Object evalAnd(Object lVal, Object rVal) throws FSException {
0998: if (lVal instanceof Integer && rVal instanceof Integer) {
0999: boolean b1, b2;
1000: b1 = ((Integer) lVal).intValue() != 0;
1001: b2 = ((Integer) rVal).intValue() != 0;
1002: if (b1 && b2) {
1003: return FS_TRUE;
1004: } else {
1005: return FS_FALSE;
1006: }
1007: } else {
1008: parseError("Type Mismatch for operator &&");
1009: }
1010:
1011: return null;
1012: }
1013:
1014: //Logical Or
1015: private Object evalOr(Object lVal, Object rVal) throws FSException {
1016: if (lVal instanceof Integer && rVal instanceof Integer) {
1017: boolean b1, b2;
1018: b1 = ((Integer) lVal).intValue() != 0;
1019: b2 = ((Integer) rVal).intValue() != 0;
1020: if (b1 || b2) {
1021: return FS_TRUE;
1022: } else {
1023: return FS_FALSE;
1024: }
1025: } else {
1026: parseError("Type Mismatch for operator ||");
1027: }
1028:
1029: return null;
1030: }
1031:
1032: //division
1033: private Object evalDiv(Object lVal, Object rVal) throws FSException {
1034: if (lVal instanceof Integer && rVal instanceof Integer) {
1035: return new Integer(((Integer) lVal).intValue()
1036: / ((Integer) rVal).intValue());
1037: } else if (lVal instanceof Double && rVal instanceof Double) {
1038: return new Double(((Double) lVal).doubleValue()
1039: / ((Double) rVal).doubleValue());
1040: } else if (lVal instanceof Double && rVal instanceof Integer) {
1041: return new Double(((Double) lVal).doubleValue()
1042: / ((Integer) rVal).intValue());
1043: } else if (lVal instanceof Integer && rVal instanceof Double) {
1044: return new Double(((Integer) lVal).intValue()
1045: / ((Double) rVal).doubleValue());
1046: } else {
1047: parseError("Type Mismatch for operator /");
1048: }
1049:
1050: return null;
1051: }
1052:
1053: //logical equal
1054: private Object evalEq(Object lVal, Object rVal) throws FSException {
1055: if (lVal instanceof Integer && rVal instanceof Integer) {
1056: if (lVal.equals(rVal)) {
1057: return FS_TRUE;
1058: } else {
1059: return FS_FALSE;
1060: }
1061: } else if (lVal instanceof Double && rVal instanceof Double) {
1062: if (lVal.equals(rVal)) {
1063: return FS_TRUE;
1064: } else {
1065: return FS_FALSE;
1066: }
1067: } else if (lVal instanceof String && rVal instanceof String) {
1068: if (lVal.equals(rVal)) {
1069: return FS_TRUE;
1070: } else {
1071: return FS_FALSE;
1072: }
1073: } else if (lVal instanceof FSObject) {
1074: if (lVal.equals(rVal)) {
1075: return FS_TRUE;
1076: } else {
1077: return FS_FALSE;
1078: }
1079: } else if (rVal instanceof FSObject) {
1080: if (rVal.equals(lVal)) {
1081: return FS_TRUE;
1082: } else {
1083: return FS_FALSE;
1084: }
1085: } else {
1086: parseError("Type Mismatch for operator ==");
1087: }
1088:
1089: return null;
1090: }
1091:
1092: //<
1093: private Object evalLs(Object lVal, Object rVal) throws FSException {
1094: if (lVal instanceof Integer && rVal instanceof Integer) {
1095: if (((Integer) lVal).intValue() < ((Integer) rVal)
1096: .intValue()) {
1097: return FS_TRUE;
1098: } else {
1099: return FS_FALSE;
1100: }
1101: } else if (lVal instanceof Double && rVal instanceof Double) {
1102: if (((Double) lVal).doubleValue() < ((Double) rVal)
1103: .doubleValue()) {
1104: return FS_TRUE;
1105: } else {
1106: return FS_FALSE;
1107: }
1108: } else if (lVal instanceof String && rVal instanceof String) {
1109: if (((String) lVal).compareTo((String) rVal) < 0) {
1110: return FS_TRUE;
1111: } else {
1112: return FS_FALSE;
1113: }
1114: } else {
1115: parseError("Type Mismatch for operator <");
1116: }
1117: return null;
1118: }
1119:
1120: //<=
1121: private Object evalLse(Object lVal, Object rVal) throws FSException {
1122: if (lVal instanceof Integer && rVal instanceof Integer) {
1123: if (((Integer) lVal).intValue() <= ((Integer) rVal)
1124: .intValue()) {
1125: return FS_TRUE;
1126: } else {
1127: return FS_FALSE;
1128: }
1129: } else if (lVal instanceof Double && rVal instanceof Double) {
1130: if (((Double) lVal).doubleValue() <= ((Double) rVal)
1131: .doubleValue()) {
1132: return FS_TRUE;
1133: } else {
1134: return FS_FALSE;
1135: }
1136: } else if (lVal instanceof String && rVal instanceof String) {
1137: if (((String) lVal).compareTo((String) rVal) <= 0) {
1138: return FS_TRUE;
1139: } else {
1140: return FS_FALSE;
1141: }
1142: } else {
1143: parseError("Type Mismatch for operator <=");
1144: }
1145: return null;
1146: }
1147:
1148: //>
1149: private Object evalGr(Object lVal, Object rVal) throws FSException {
1150: if (lVal instanceof Integer && rVal instanceof Integer) {
1151: if (((Integer) lVal).intValue() > ((Integer) rVal)
1152: .intValue()) {
1153: return FS_TRUE;
1154: } else {
1155: return FS_FALSE;
1156: }
1157: } else if (lVal instanceof Double && rVal instanceof Double) {
1158: if (((Double) lVal).doubleValue() > ((Double) rVal)
1159: .doubleValue()) {
1160: return FS_TRUE;
1161: } else {
1162: return FS_FALSE;
1163: }
1164: } else if (lVal instanceof String && rVal instanceof String) {
1165: if (((String) lVal).compareTo((String) rVal) > 0) {
1166: return FS_TRUE;
1167: } else {
1168: return FS_FALSE;
1169: }
1170: } else {
1171: parseError("Type Mismatch for operator >");
1172: }
1173: return null;
1174: }
1175:
1176: //>=
1177: private Object evalGre(Object lVal, Object rVal) throws FSException {
1178: if (lVal instanceof Integer && rVal instanceof Integer) {
1179: if (((Integer) lVal).intValue() >= ((Integer) rVal)
1180: .intValue()) {
1181: return FS_TRUE;
1182: } else {
1183: return FS_FALSE;
1184: }
1185: } else if (lVal instanceof Double && rVal instanceof Double) {
1186: if (((Double) lVal).doubleValue() >= ((Double) rVal)
1187: .doubleValue()) {
1188: return FS_TRUE;
1189: } else {
1190: return FS_FALSE;
1191: }
1192: } else if (lVal instanceof String && rVal instanceof String) {
1193: if (((String) lVal).compareTo((String) rVal) >= 0) {
1194: return FS_TRUE;
1195: } else {
1196: return FS_FALSE;
1197: }
1198: } else {
1199: parseError("Type Mismatch for operator >=");
1200: }
1201: return null;
1202: }
1203:
1204: //logical inequallity
1205: private Object evalNEq(Object lVal, Object rVal) throws FSException {
1206: if (evalEq(lVal, rVal) == FS_TRUE) {
1207: return FS_FALSE;
1208: } else {
1209: return FS_TRUE;
1210: }
1211: }
1212:
1213: /* private void printWTree(ETreeNode node){
1214: while(node.parent!=null){
1215: node=node.parent;
1216: }
1217: printETree(node);
1218: } */
1219:
1220: /* private void printETree(ETreeNode node){
1221:
1222: System.out.println(node);
1223: if (node.left!=null){
1224: System.out.print("Left");
1225: printETree(node.left);
1226: }
1227: if (node.right!=null){
1228: System.out.print("Right");
1229: printETree(node.right);
1230: }
1231: } */
1232:
1233: private void parseIf() throws IOException, FSException,
1234: RetException {
1235: Integer val;
1236: int depth;
1237: boolean then = false;
1238:
1239: getNextToken();
1240: Object obj = parseExpr();
1241: if (obj instanceof Integer)
1242: val = (Integer) obj;
1243: else {
1244: if (obj instanceof FSObject)
1245: obj = ((FSObject) obj).getObject();
1246: if (obj instanceof Boolean)
1247: val = ((Boolean) obj).booleanValue() ? FS_TRUE
1248: : FS_FALSE;
1249: else if (obj instanceof Integer) {
1250: // test needed a second time 'cause it may have been an FSObject before
1251: val = (Integer) obj;
1252: } else {
1253: parseError("If condition needs to be Integer");
1254: return; // just to make sure the compiler doesn't complain
1255: // as we know parseError throws an exception (stupid compiler)
1256: }
1257: }
1258:
1259: //handle the one line if-then construct
1260: if (tok.ttype == LexAnn.TT_THEN) {
1261: getNextToken();
1262: //is this a single line then (or just a optional then)
1263: if (tok.ttype != LexAnn.TT_EOL) {
1264: //single line if then construct - run separately
1265: //tok.pushBack();
1266: if (val.intValue() != 0) {
1267: parseStmt();
1268: } else {
1269: //consume to EOL
1270: while (tok.ttype != LexAnn.TT_EOL) {
1271: getNextToken();
1272: }
1273: }
1274: then = true;
1275: }
1276: }
1277:
1278: if (!then) {
1279: if (val.intValue() != 0) {
1280: getNextToken();
1281: while ((tok.ttype != LexAnn.TT_EIF)
1282: && (tok.ttype != LexAnn.TT_ELSE)
1283: && (tok.ttype != LexAnn.TT_EOF)
1284: && (tok.ttype != LexAnn.TT_ELSIF)) {
1285: //run the body of the if
1286: parseStmt();
1287: getNextToken();
1288: }
1289: if (tok.ttype == LexAnn.TT_ELSE
1290: || tok.ttype == LexAnn.TT_ELSIF) {
1291: //skip else clause -
1292: //have to do this taking into acount nesting
1293: depth = 1;
1294: do {
1295: getNextToken();
1296: if (tok.ttype == LexAnn.TT_IF)
1297: depth++;
1298: if (tok.ttype == LexAnn.TT_EOF)
1299: parseError("can't find endif");
1300: if (tok.ttype == LexAnn.TT_EIF)
1301: depth--;
1302:
1303: //A then could indicate a one line
1304: //if - then construct, then we don't increment
1305: //depth
1306: if (tok.ttype == LexAnn.TT_THEN) {
1307:
1308: getNextToken();
1309: if (tok.ttype != LexAnn.TT_EOL) {
1310: depth--;
1311: }
1312: tok.pushBack();
1313: }
1314:
1315: } while (depth > 0);
1316: getNextToken();
1317: } else {
1318: getNextToken();
1319: }
1320:
1321: } else {
1322: //skip to else clause
1323: depth = 1;
1324: do {
1325: getNextToken();
1326: if (tok.ttype == LexAnn.TT_IF)
1327: depth++;
1328: if (tok.ttype == LexAnn.TT_EOF)
1329: parseError("can't find endif");
1330: if ((tok.ttype == LexAnn.TT_EIF))
1331: depth--;
1332: if ((tok.ttype == LexAnn.TT_ELSE || tok.ttype == LexAnn.TT_ELSIF)
1333: && depth == 1)
1334: depth--;
1335: //A then could indicate a one line
1336: //if - then construct, then we don't increment
1337: //depth
1338: if (tok.ttype == LexAnn.TT_THEN) {
1339:
1340: getNextToken();
1341: if (tok.ttype != LexAnn.TT_EOL) {
1342: depth--;
1343: }
1344: tok.pushBack();
1345: }
1346:
1347: } while (depth > 0);
1348:
1349: if (tok.ttype == LexAnn.TT_ELSE) {
1350: getNextToken();
1351: getNextToken();
1352: //run else clause
1353:
1354: while (tok.ttype != LexAnn.TT_EIF) {
1355: parseStmt();
1356: getNextToken();
1357: }
1358: getNextToken();
1359: } else if (tok.ttype == LexAnn.TT_ELSIF) {
1360: parseIf();
1361: } else {
1362: getNextToken();
1363: }
1364: }
1365: }
1366:
1367: }
1368:
1369: private void parseWhile() throws IOException, FSException,
1370: RetException {
1371: //parses the while statement
1372:
1373: Integer val;
1374: boolean looping = true;
1375: int startLine;
1376: //int endPos;
1377: int depth;
1378:
1379: startLine = code.getCurLine();
1380:
1381: while (looping) {
1382: getNextToken(); // a 'while' you would imagine
1383: Object obj = parseExpr();
1384: if (obj instanceof Integer)
1385: val = (Integer) obj;
1386: else {
1387: if (obj instanceof FSObject)
1388: obj = ((FSObject) obj).getObject();
1389: if (obj instanceof Boolean)
1390: val = ((Boolean) obj).booleanValue() ? FS_TRUE
1391: : FS_FALSE;
1392: else if (obj instanceof Integer) {
1393: // test needed a second time 'cause it may have been an FSObject before
1394: val = (Integer) obj;
1395: } else {
1396: parseError("While condition needs to be Integer");
1397: return; // just to make sure the compiler doesn't complain
1398: // as we know parseError throws an exception (stupid compiler)
1399: }
1400: }
1401: getNextToken();
1402:
1403: if (val.intValue() == 0) {
1404: looping = false;
1405: } else {
1406: while ((tok.ttype != LexAnn.TT_EWHILE)
1407: && (tok.ttype != LexAnn.TT_EOF)) {
1408: parseStmt();
1409: getNextToken();
1410: }
1411:
1412: //reset to start of while loop....
1413: code.setCurLine(startLine);
1414: resetTokens();
1415: }
1416: }
1417: //skip to endwhile
1418: depth = 1;
1419: do {
1420: getNextToken();
1421: if (tok.ttype == LexAnn.TT_WHILE)
1422: depth++;
1423: if (tok.ttype == LexAnn.TT_EWHILE)
1424: depth--;
1425: if (tok.ttype == LexAnn.TT_EOF)
1426: parseError("can't find endwhile");
1427: } while (depth > 0);
1428:
1429: getNextToken();
1430: }
1431:
1432: private void parseVarDef() throws IOException, FSException {
1433:
1434: String name;
1435: int type = tok.ttype;
1436:
1437: do {
1438: getNextToken();
1439: if (tok.ttype != LexAnn.TT_WORD) {
1440: parseError("Expected variable name identifier,");
1441: }
1442:
1443: name = (String) tok.value;
1444:
1445: switch (type) {
1446: case LexAnn.TT_DEFINT: {
1447: addVar(name, FS_FALSE);
1448: break;
1449: }
1450: case LexAnn.TT_DEFSTRING: {
1451: addVar(name, new String(""));
1452: break;
1453: }
1454: case LexAnn.TT_DEFDOUBLE: {
1455: addVar(name, new Double(0));
1456: break;
1457: }
1458: case LexAnn.TT_DEFOBJECT: {
1459: addVar(name, new FSObject());
1460: break;
1461: }
1462: }
1463:
1464: getNextToken();
1465: if (tok.ttype == LexAnn.TT_EQ) {
1466: getNextToken();
1467: setVar(name, parseExpr());
1468: } else if (tok.ttype != ',' && tok.ttype != LexAnn.TT_EOL) {
1469: parseError("Expected ','");
1470: }
1471:
1472: } while (tok.ttype != LexAnn.TT_EOL);
1473:
1474: }
1475:
1476: //format an error message and throw FSException
1477: private void parseError(String s) throws FSException {
1478:
1479: // set up our error block
1480: error = new String[6];
1481: error[0] = s;
1482: error[1] = (new Integer(code.getCurLine())).toString();
1483: error[2] = code.getLineAsString();
1484: error[3] = tok.toString();
1485: ;
1486: error[4] = vars.toString();
1487: if (gVars != null)
1488: error[5] = (gVars == null) ? "" : gVars.toString();
1489:
1490: // build the display string
1491: s = "\n\t" + s + "\n" + getContext();
1492:
1493: throw new FSException(s);
1494: }
1495:
1496: /**
1497: * get the current context (executed line, variables etc)
1498: * @return
1499: */
1500: public String getContext() {
1501: int l = code.getCurLine();
1502: String s = "\t\t at line:" + l + " ";
1503: if (l > -1) {
1504: s += "\n\t\t\t " + code.getLineAsString(l - 2);
1505: s += "\n\t\t\t " + code.getLineAsString(l - 1);
1506: s += "\n\t\t\t> " + code.getLineAsString(l) + " <";
1507: s += "\n\t\t\t " + code.getLineAsString(l + 1);
1508: s += "\n\t\t\t " + code.getLineAsString(l + 2);
1509: s = s + "\n\t\t current token:" + tok.toString();
1510: ;
1511: s = s + "\n\t\t Variable dump:" + vars;
1512: if (gVars != null) {
1513: s = s + "\n\t\t Globals:" + gVars;
1514: }
1515: } else
1516: s += "\n\t\t\t> " + tok.getLine() + " <";
1517:
1518: return s;
1519: }
1520:
1521: //return the error block
1522: String[] getError() {
1523: return error;
1524: }
1525:
1526: // Other non SM related routines
1527:
1528: //misc token access routines
1529: private void getNextToken() throws IOException {
1530: if (tok.ttype == LexAnn.TT_EOL) {
1531: if (code.getCurLine() < maxLine) {
1532: code.setCurLine(code.getCurLine() + 1);
1533: tok.setString(code.getLine());
1534: tok.nextToken();
1535: } else {
1536: tok.ttype = LexAnn.TT_EOF; //the only place this gets set
1537: }
1538: } else {
1539: tok.nextToken();
1540: }
1541: }
1542:
1543: private void resetTokens() throws IOException {
1544: tok.setString(code.getLine());
1545: tok.nextToken();
1546: }
1547:
1548: //variable access routines
1549: void addVar(String name, Object value) throws FSException {
1550:
1551: if (vars.containsKey(name)) {
1552: parseError("Already defined in this scope: " + name);
1553: }
1554: vars.put(name, value);
1555: }
1556:
1557: public Object getVar(String name) {
1558: if (subParser != null)
1559: return subParser.getVar(name);
1560: if (vars.containsKey(name)) {
1561: return vars.get(name);
1562: } else {
1563: if (gVars != null) {
1564: if (gVars.containsKey(name)) {
1565: return gVars.get(name);
1566: }
1567: }
1568: }
1569:
1570: // variable not found, try extensions
1571: try {
1572: return host.getVarEntry(name, null);
1573: } catch (Exception e) {
1574: }
1575:
1576: return null; //shouldn't get here
1577: }
1578:
1579: // setVar allows assigning objects only when the objects are of the same type
1580: // OR you can assign a String, Integer or Double to an FSObject if the contained object already
1581: // has the same type. Note that you can change the type of the embedded object for "object" variables.
1582: public void setVar(String name, Object val) throws FSException {
1583:
1584: Object obj;
1585:
1586: if (val == null)
1587: parseError("set variable " + name + " with null value");
1588:
1589: if (subParser != null) {
1590: subParser.setVar(name, val);
1591: return;
1592: }
1593:
1594: if ((obj = vars.get(name)) != null) {
1595: if (val.getClass() != obj.getClass()) {
1596: //special case for FSObject allow asignment of either same
1597: //class or _any_ class if FSObject is already null
1598: //also allow assignment of null to any FSObject
1599: if (obj instanceof FSObject) {
1600: if (((FSObject) obj).getObject() == null) {
1601: val = new FSObject(val);
1602: } else if (((FSObject) obj).getObject().getClass() == val
1603: .getClass()) {
1604: val = new FSObject(val);
1605: } else {
1606: parseError("Incompatible types");
1607: }
1608: } else {
1609: parseError("Incompatible types");
1610: }
1611: }
1612: vars.remove(name);
1613: vars.put(name, val);
1614: } else if ((obj = gVars.get(name)) != null) {
1615: if (val.getClass() != obj.getClass()) {
1616: parseError("Incompatible types");
1617: }
1618: gVars.remove(name);
1619: gVars.put(name, val);
1620: }
1621:
1622: }
1623:
1624: public boolean hasVar(String name) {
1625: if (subParser != null)
1626: return subParser.hasVar(name);
1627: if (gVars == null) {
1628: return vars.containsKey(name);
1629: } else {
1630: return vars.containsKey(name) || gVars.containsKey(name);
1631: }
1632: }
1633:
1634: }
|