📄 parser.java
字号:
package murlen.util.fscript;import java.io.*;import java.util.HashMap;import java.util.ArrayList;/** * <b>Parser - Does the parsing - i.e it's the brains of the code.</b> * <p> * <I>Copyright (C) 2000-2003 murlen.</I></p> * <p> * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version.</p> * <p> * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details.</p> * * <p>You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA </p> * @author murlen * @author Joachim Van der Auwera * @version 1.12 * * modifications by Joachim Van der Auwera * 14.08.2001 added support for indexed variables * 20.08.2001 -clean handling of setVar with null value * - cleaner handling of if with null condition * - make sure running empty script does nothing * - extra info when throwing an exception (with surrounding lines) * - changed operator prioritues for && and || * - fixed bug in parseIf with handling of nesting of if clauses with else * - check for missing endif or endwhile (caused infinit loops) * - check for a null to prevernt excepion in parseExpr * 28.08.2001 * - call to host.getVar() replaced by host.F() (and added * proper exception handling, in that case) * 31.08.2001 * - test on if condition being of correct type re-introduced * 10.09.2001 * - added < <= > >= on strings * 23.11.2001 * - allow adding strings with anything * 04.12.2001 * - allow add/subtract/multiply/divide int with double * 24.04.2002 * - fixed a bug in parsing of nested if clause when one of the nested items contains a * "then" token with the statements on the next line(s) (test for TT_EOL instead of TT_EOF) * 30.04.2002 * - handle all exceptions on all getVarEntry, setVarEntry and callFunctionEntry calls * 06.05.2002 * - error messages now unique * - TT_EOF handled better in some cases * 05-06.08.2002 * - removed some redundant code * - introduced parseFunctionEnd to catch functions without return (it worked before, so...) * 21.10.2002 * - added == for FSObject instances * 30.10.2002 object now allowed as function parameter * 07.11.2002 better error handling when parsing an expression * 20.11.2002 make != work for objects * 15.03.2003 getContext() added JVDA * 17.09.2003 removed checking for mismatched quotes and brackets, and moved to LineLoader * 23.11.2003 recycle LexAnn objects (saves object allocation/release) JVDA * 24.11.2003 some extra (smallish) speed improvements (also to reduce garbage a little bit) * 25.02.2004 * - proper evaluation of FSObject with contained boolean/integer for if/while * - more powerful compare for FSObject instance with something else * 14.04.2004 elsif opperator support */final class Parser { public static final Integer FS_TRUE=new Integer(1); public static final Integer FS_FALSE=new Integer(0); //simple data class used internally to store function defs class FuncEntry { int startLine; //start line of function int endLine; //end line of function ArrayList paramNames; //list of parameter names HashMap params; //hashmap of parameters FuncEntry() { startLine=0; endLine=0; paramNames=new ArrayList(4); params=new HashMap(); } public String toString() { String s; s=startLine + " " ; s=s+endLine + " "; s=s+paramNames + " "; s=s+params; return s; } } //exception that occurs when someone calls return class RetException extends Exception {} private LineLoader code; //the code private LexAnn tok; //tokenizer private int maxLine; private HashMap vars; //function local variables private HashMap gVars; //global variables private static HashMap opPrio; //operator priority table private FScript host; //link to hosting FScript object private HashMap funcs; //function map private Object retVal; //return value private Parser subParser; //nested parser, for callback routines in FSParserExtension private String error[]; /** Public constructor * @param h a reference to the FScript object */ Parser(FScript h) { vars=new HashMap(); gVars=null; funcs=new HashMap(); host=h; setPrio(); } //only used for function calls - note it is private private Parser(FScript h,HashMap l,HashMap g, HashMap f) { vars=l; gVars=g; funcs=f; host=h; } /** * Sets the LineLoader clas to be used for input * @param in - the class */ void setCode(LineLoader in) { code=in; } /** *The main parsing function *@param from - the start line number *@param to - the end line number *returns an Object (currently a Integer or String) depending *on the return value of the code parsed, or null if none. */ Object parse(int from,int to) throws IOException, FSException { // nothing to do when starting beond the code end if (code.lineCount()<=from) return null; maxLine=to; code.setCurLine(from); tok=new LexAnn(code.getLine()); getNextToken(); while (tok.ttype!=LexAnn.TT_EOF) { //a script must always start with a word... try { parseStmt(); } catch (RetException e) { return retVal; } getNextToken(); } return null; } /** * The main parsing function * @param line - the line to be parsed * @return an Object depending on the return value of the code parsed, or null if none. */ Object parse(String line) throws IOException, FSException { int oldLine=code.curLine; try { code.curLine=-1; code.forError=line; char[] chars=line.toCharArray(); LineLoader.checkLine(chars); tok=new LexAnn(chars); tok.nextToken(); // a script must always start with a word... try { parseStmt(); } catch (RetException e) { return retVal; } } finally { code.curLine=oldLine; } return null; } /** * Resets the parser state. */ void reset(){ if (vars!=null){ vars.clear(); } if (gVars!=null){ gVars.clear(); } } //builds the operator priority table private void setPrio(){ if (opPrio==null){ opPrio=new HashMap(); //from low to high Integer prio; prio=new Integer(1); opPrio.put(new Integer(LexAnn.TT_LOR),prio); prio=new Integer(2); opPrio.put(new Integer(LexAnn.TT_LAND),prio); prio=new Integer(5); opPrio.put(new Integer(LexAnn.TT_LEQ),prio); opPrio.put(new Integer(LexAnn.TT_LNEQ),prio); opPrio.put(new Integer(LexAnn.TT_LGR),prio); opPrio.put(new Integer(LexAnn.TT_LGRE),prio); opPrio.put(new Integer(LexAnn.TT_LLS),prio); opPrio.put(new Integer(LexAnn.TT_LLSE),prio); prio=new Integer(10); opPrio.put(new Integer(LexAnn.TT_PLUS),prio); opPrio.put(new Integer(LexAnn.TT_MINUS),prio); prio=new Integer(20); opPrio.put(new Integer(LexAnn.TT_MULT),prio); opPrio.put(new Integer(LexAnn.TT_DIV),prio); opPrio.put(new Integer(LexAnn.TT_MOD),prio); } } //statement - top level thing private void parseStmt() throws IOException, FSException,RetException { switch(tok.ttype) { case LexAnn.TT_DEFINT: case LexAnn.TT_DEFSTRING: case LexAnn.TT_DEFDOUBLE: case LexAnn.TT_DEFOBJECT: { parseVarDef(); break; } case LexAnn.TT_IF: { parseIf(); break; } case LexAnn.TT_WHILE: { parseWhile(); break; } case LexAnn.TT_RETURN: { parseReturn(); break; } case LexAnn.TT_DEFFUNC: { parseFunctionDef(); break; } case LexAnn.TT_EDEFFUNC: { parseFunctionEnd(); break; } case LexAnn.TT_EIF: throw new FSException("unexpected endif"); case LexAnn.TT_EWHILE: throw new FSException("unexpected endwhile"); case LexAnn.TT_FUNC: { parseFunc(); break; } case LexAnn.TT_ARRAY: { parseArrayAssign(); break; } case LexAnn.TT_WORD: { parseAssign(); break; } case LexAnn.TT_EOL: { tok.nextToken(); break; } case LexAnn.TT_EOF: { // all done break; } default: { parseError("Expected identifier "+tok); } } } private void parseFunc() throws IOException,FSException { String name; name=(String)tok.value; //should be a '(' getNextToken(); parseCallFunc(name); getNextToken(); } private void parseArrayAssign() throws IOException,FSException { String name; Object index; Object val; name=(String)tok.value; getNextToken(); // should be a '[' getNextToken(); // should be the index index=parseExpr(); getNextToken(); // should be a ']' //getNextToken(); if (tok.ttype!=LexAnn.TT_EQ) { parseError("Expected '='" ); } else { getNextToken(); val=parseExpr(); try { host.setVarEntry(name,index,val); } catch (Exception e) { parseError(e.getMessage()); } } } //handles 'return' statements private void parseReturn() throws IOException,FSException,RetException { getNextToken(); retVal=parseExpr(); throw new RetException(); } // handle endif without return, just return 1 (or true) private void parseFunctionEnd() throws RetException { retVal=FS_TRUE; throw new RetException(); } //Asignment parser private void parseAssign() throws IOException, FSException { String name; Object val; name=(String)tok.value; getNextToken(); if (tok.ttype!=LexAnn.TT_EQ) { parseError("Expected '='" ); } else { getNextToken(); val=parseExpr(); if (hasVar(name)) { setVar(name,val); } else { try { host.setVarEntry(name,null,val); } catch (Exception e) { parseError(e.getMessage()); } } } } Object callFunction(String name,ArrayList params) throws IOException,FSException{ FuncEntry fDef; int n;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -