package org.ripple.power.command; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import org.json.JSONArray; import org.json.JSONObject; import org.ripple.power.collection.Array; import org.ripple.power.collection.ArrayMap; import org.ripple.power.config.LSystem; import org.ripple.power.txns.Updateable; import org.ripple.power.utils.ReflectorUtils; import org.ripple.power.utils.StringUtils; public class ROCScript { private DMacros macros_executer = null; private ArrayList<IMacros> macros_listeners = new ArrayList<IMacros>(10); private final IScriptLog scriptLog; private static ArrayMap waitTimes = new ArrayMap(); static { waitTimes.put("mesc", LSystem.MSEC); waitTimes.put("second", LSystem.SECOND); waitTimes.put("minute", LSystem.MINUTE); waitTimes.put("hour", LSystem.HOUR); waitTimes.put("day", LSystem.DAY); } private void handleError(int error) throws ScriptException { String[] errors = new String[UNKNOWN + 1]; errors[SYNTAX] = "Syntax Error"; errors[UNBALPARENS] = "(... or ...)"; errors[DIVBYZERO] = "1/0"; errors[EQUALEXPECTED] = "Equal Expected"; errors[UNKOWN] = "For vars that have no value: assignments,loops"; errors[NOTABOOL] = "Not a boolean"; errors[NOTANUMB] = "Not a number"; errors[NOTASTR] = " Not a string"; errors[DUPFUNCTION] = "Two functions with same name"; errors[ENDEXPECTED] = "Reaches end of script without end"; errors[THENEXPECTED] = "No then after if"; errors[DOEXPECTED] = "No then after if"; errors[MISSQUOTE] = "Strings missing a quote"; errors[UNKFUNCTION] = "Unknown function"; errors[INVALIDEXP] = "Invalid Expression"; errors[UNEXPITEM] = "Unexpeced Item"; errors[FILENOTFOUND] = "Can't find file"; errors[INPUTIOERROR] = "Input that fails"; errors[EXPERR] = "For if, while and for"; errors[FILEIOERROR] = "Can't load file"; errors[UNKNOWN] = "Unknown error"; String err = errors[error] + ": " + textIdx + "\nLine number: " + textLine + "\nItem: " + item + "\nItem Type: " + itemType + "\ncommType: " + commType; if (scriptLog != null) { scriptLog.err(err); } throw new ScriptException(err); } private final static int MAX_TEXT_SIZE = 65535; // 参数类型 private final int NONE = 0; // 不存在 private final int DELIMITER = 1; // 任意特殊符号 private final int VARIABLE = 2; // 已经存在的变量 private final int COMMAND = 3; // 接下来的命令 private final int EOL = 4; // 结束一行 private final int EOP = 5; // 结束全部文本 // 判定参数类型 private final int STRING = 6; private final int NUMBER = 7; private final int BOOLEAN = 8; private final int FUNCT = 9; // 脚本指令 // 条件 private final int UNKNCOM = 0; private final int PRINT = 1; private final int INPUT = 2; private final int RETURN = 3; private final int THEN = 4; private final int END = 5; private final int BEGIN = 6; private final int ELSE = 7; // 分支 private final int IF = 8; private final int FOR = 9; private final int WHILE = 10; private final int FUNCTION = 11; // 延迟 private final int WAIT = 12; private final int PRINTLN = 13; // 错误 private final int SYNTAX = 0; private final int UNBALPARENS = 1; private final int DIVBYZERO = 2; private final int EQUALEXPECTED = 3; private final int UNKOWN = 4; private final int NOTABOOL = 5; private final int NOTANUMB = 6; private final int NOTASTR = 7; private final int DUPFUNCTION = 8; private final int ENDEXPECTED = 9; private final int THENEXPECTED = 10; private final int MISSQUOTE = 11; private final int DOEXPECTED = 12; private final int UNKFUNCTION = 13; private final int INVALIDEXP = 14; private final int UNEXPITEM = 15; private final int TOOMANYPARAMS = 16; private final int FILENOTFOUND = 17; private final int INPUTIOERROR = 18; private final int EXPERR = 19; private final int FILEIOERROR = 20; // 宏 private final int MACROS = 21; // 未知区域 private final int UNKNOWN = 22; // 宏指令设置 private boolean waitMacros = true; private boolean initNextMacros = true; // 脚本线程 private Thread commandThread; // 保存脚本用 private Array<Command> commands; // 变量 private Array<ArrayMap> vars; // 函数 private ArrayMap functs; private char[] contexts; private int textIdx; private int textLine; private String item; private int itemType; private int commType; private int macroType = -1; // <= private final char LE = 0; // >= private final char GE = 1; // == private final char EQ = 4; private final char rOps[] = { LE, GE, '<', '>', EQ }; private String relops = new String(rOps); private final char AND = 0; private final char OR = 1; private final char NOT = 2; private final char XOR = 3; private final char XAND = 4; private final char selectOpsId[] = { AND, OR, NOT, XOR, XAND }; private final String selectOps[] = { "and", "or", "not", "xor", "xand" }; private String[] commTable = { "", "print", "input", "return", "then", "end", "begin", "else", "if", "for", "while", "function", "wait", "println" }; private String[] macros = { "{", "}" }; private boolean debug = true; private final boolean DEBUG_E = false; @SuppressWarnings("serial") public class ScriptException extends Exception { String errStr; public ScriptException(String str) { this.errStr = str; } public String toString() { return errStr; } } class Command { int loc, comm = 0, line; public String toString() { return commTable[comm]; } } class ForLoop extends Command { String vName; int expLoc, itLoc; public ForLoop(String n, int exp, int it, int lo, int lin) { comm = FOR; vName = n; expLoc = exp; itLoc = it; loc = lo; line = lin; } public ForLoop() { comm = FOR; } } class WhileLoop extends Command { int expLoc, line; public WhileLoop(int exp, int lo, int lin) { comm = WHILE; expLoc = exp; loc = lo; line = lin; } public WhileLoop() { comm = WHILE; } } class Function extends Command { int backLoc; ArrayList<String> lists; public Function(int l, int bLoc, ArrayList<String> pars) { comm = FUNCTION; backLoc = bLoc; loc = l; lists = pars; } public Function() { comm = FUNCTION; } } class IfStat extends Command { boolean done; public IfStat(boolean d) { comm = IF; done = d; } } private void splitFlag(String src, StringBuffer out, char flag) { char[] chars = src.toCharArray(); for (int i = 0; i < chars.length; i++) { char ch = chars[i]; if (ch == flag) { out.append(flag); if (i + 1 < chars.length && chars[i + 1] != '\n') { out.append(LSystem.LS); } } else { out.append(ch); } } } private String filtrScript(String script) { StringBuffer out = new StringBuffer(); String[] context = script.split("[\r\n\t]"); for (String c : context) { if ((c.toLowerCase().startsWith("print") || c.toLowerCase() .startsWith("println")) && c.indexOf("\"") != -1 && c.indexOf(",") == -1) { char[] chars = c.toCharArray(); boolean flag = false; for (int i = 0; i < chars.length; i++) { if (chars[i] == '"') { flag = !flag; } if (!flag) { if (chars[i] == '+') { chars[i] = ','; } } } c = new String(chars); } if (c.indexOf('{') != -1) { splitFlag(c, out, '{'); } else { out.append(c); } out.append(LSystem.LS); } return out.toString(); } /** * 构建脚本 * * @param script * @param useFile * @throws ScriptException */ public ROCScript(String script, boolean useFile) throws ScriptException { this(new DefScriptLog(), script, useFile); } /** * 构建脚本 * * @param log * @param script * @param useFile * @throws ScriptException */ public ROCScript(IScriptLog log, String script, boolean useFile) throws ScriptException { scriptLog = log; char[] charlist = new char[MAX_TEXT_SIZE]; int size = 0; // 文件名导入 if (useFile) { size = fileToChars(charlist, script); } else { charlist = filtrScript(script).toCharArray(); size = charlist.length; } if (size > MAX_TEXT_SIZE) { size = MAX_TEXT_SIZE; } if (size != -1) { contexts = new char[size]; System.arraycopy(charlist, 0, contexts, 0, size); } } private void debug(String s) { if (debug) { if (commands != null) { for (int i = 0; i < commands.size(); i++) scriptLog.line("\t"); } scriptLog.err("> " + s); scriptLog.newline(); } } private void debug(String[] strs) { if (debug) { String str = ""; if (commands != null) { for (int i = 0; i < commands.size(); i++) str += "\t"; } for (String s : strs) { scriptLog.err(str + s); } scriptLog.newline(); } } public int fileToChars(char[] p, String fileName) throws ScriptException { debug("Loading file..."); int size = 0; try { FileReader fr = new FileReader(fileName); BufferedReader br = new BufferedReader(fr); size = br.read(p, 0, MAX_TEXT_SIZE); fr.close(); } catch (FileNotFoundException exc) { handleError(FILENOTFOUND); } catch (IOException exc) { handleError(FILEIOERROR); } // 当读取到文件尾部时,后退一位 if (p[size - 1] == (char) 26) { size--; } return size; } /** * 指定脚本程序 * * @param d * @throws ScriptException */ public void call(boolean d) { synchronized (ROCScript.class) { debug("Running script..."); debug = d; // 初始化寄存器 vars = new Array<ArrayMap>(); vars.add(new ArrayMap()); functs = new ArrayMap(); commands = new Array<Command>(); textIdx = 0; textLine = 1; Updateable update = new Updateable() { @Override public void action(Object o) { // 开始执行命令 try { running(); } catch (ScriptException e) { e.printStackTrace(); } } }; if (commandThread == null) { commandThread = LSystem.postThread(update); } else { try { commandThread.interrupt(); commandThread = null; } catch (Exception ex) { } commandThread = LSystem.postThread(update); } } } private boolean stop = false; public void stop() { stop = true; } /** * 执行脚本命令 * * @return * @throws ScriptException */ private Object running() throws ScriptException { debug("Starting script..."); while (nextItem() && !stop) { if (item != null) { item = item.trim(); } switch (itemType) { // 变量 case VARIABLE: assignVar(); break; // 函数 case FUNCT: execFunct(); nextItem(); break; // 具体表达式变量 case COMMAND: switch (commType) { case PRINT: print(); break; case PRINTLN: println(); break; case INPUT: input(); break; case IF: execIf(); break; case FOR: execFor(); break; case END: if (endCommand(false)) { return null; } break; case WHILE: execWhile(); break; case RETURN: debug("Returning"); nextItem(); Object o = analysis(); endCommand(true); return o; case FUNCTION: newFunction(); break; case ELSE: execElse(); break; case WAIT: debug("waiting"); break; } debug("Done with command"); break; // 宏指令 case MACROS: switch (macroType) { case 0: callMacros(); itemType = EOL; break; case 1: itemType = EOL; break; } break; } // 判定解析完毕 if (itemType != EOL && itemType != EOP) { handleError(UNEXPITEM); } } return null; } public boolean isWaitMacros() { return waitMacros; } public void setWaitMacros(boolean waitMacros) { this.waitMacros = waitMacros; } public void setCallMacros(boolean f) { this.initNextMacros = f; } public boolean isCallMacros() { return this.initNextMacros; } private void callMacros() throws ScriptException { nextItem(); debug("Macros:"); debug(item); macrosCommand(this.item, this.textLine); } public void setMacrosListener(ArrayList<IMacros> list) { if (list == null) { return; } this.macros_listeners = list; } public void setMacrosListener(IMacros... args) { if (args == null) { return; } for (int i = 0; i < args.length; i++) { this.macros_listeners.add(args[i]); } } public void setMacrosListener(IMacros macros) { addMacrosListener(macros); } public void addMacrosListener(IMacros macros) { if (this.macros_listeners != null && macros != null) { this.macros_listeners.add(macros); } } private void macrosCommand(String context, int id) { if (!initNextMacros) { return; } DMacros.resetCache(); String[] res = StringUtils.split(context, "\n"); if (macros_executer == null) { macros_executer = new DMacros("script" + id, res); } else { macros_executer.formatCommand("script" + id, res); } for (int i = 0; i < vars.size(); i++) { ArrayMap maps = vars.get(i); macros_executer.setVariables(maps); } if (scriptLog != null) { scriptLog.info("Syncing..."); } for (; macros_executer.next();) { String result = macros_executer.doExecute(); if (result == null) { continue; } if (macros_listeners != null) { for (IMacros macros_listener : macros_listeners) { macros_listener.call(scriptLog, textLine, macros_executer, result); if (waitMacros) { for (; macros_listener.isSyncing();) { try { Thread.sleep(1); } catch (InterruptedException e) { } } } } } } if (scriptLog != null) { scriptLog.info("Synchro is completed."); } vars.add(macros_executer.getVariables()); } private void println() throws ScriptException { debug("Println"); String lastDelim = ""; while (nextItem() && itemType != EOL && itemType != EOP) { scriptLog.info(analysis()); lastDelim = item; if (lastDelim.equals(",")) { scriptLog.line(" "); } else if (lastDelim.equals(";")) { scriptLog.line("\t"); } else if (itemType != EOL && itemType != EOP) { handleError(SYNTAX); } else { break; } } scriptLog.newline(); } private void print() throws ScriptException { debug("Print"); String lastDelim = ""; while (nextItem() && itemType != EOL && itemType != EOP) { scriptLog.line(analysis()); lastDelim = item; if (lastDelim.equals(",")) { scriptLog.line(" "); } else if (lastDelim.equals(";")) { scriptLog.line("\t"); } else if (itemType != EOL && itemType != EOP) { handleError(SYNTAX); } else { break; } } } private void input() throws ScriptException { debug("Get Input"); String str = ""; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); nextItem(); if (itemType == STRING) { scriptLog.line(item); nextItem(); if (!item.equals(",")) { handleError(SYNTAX); return; } nextItem(); } else { scriptLog.line("? "); } if (!Character.isLetter(item.charAt(0))) { handleError(UNKOWN); return; } try { str = br.readLine(); vars.last().put(item, str); } catch (IOException e) { handleError(INPUTIOERROR); return; } nextItem(); } private void execIf() throws ScriptException { debug("If select"); boolean result = false; nextItem(); try { Object o = analysis(); if (o instanceof Boolean) { result = (boolean) o; } else if (o instanceof Number) { result = Double.parseDouble(o.toString()) > 0; } } catch (ClassCastException exc) { handleError(NOTABOOL); return; } vars.add(new ArrayMap()); commands.add(new IfStat(result)); if (result) { if (commType != THEN) { handleError(THENEXPECTED); return; } nextItem(); } else { nextEnd(); } } private void execElse() throws ScriptException { debug("Else select"); Command c = commands.last(); if (c.comm != IF) { handleError(SYNTAX); return; } if (!((IfStat) c).done) { nextItem(); if (commType == IF) { nextItem(); boolean result; try { result = (boolean) analysis(); } catch (ClassCastException exc) { handleError(NOTABOOL); return; } if (result) { ((IfStat) c).done = true; if (commType != THEN) { handleError(THENEXPECTED); return; } nextItem(); } else { nextEnd(); } return; } } else { nextEnd(); } } // 循环执行 private void execFor() throws ScriptException { debug("For Loop"); double i; int expLoc, ittLoc, loc; String vname; nextItem(); vname = item; // = nextItem(); if (item.equals("=")) { nextItem(); try { i = (double) analysis(); } catch (ClassCastException exc) { handleError(EXPERR); return; } vars.last().put(vname, i); } // , if (!item.equals(",")) { handleError(SYNTAX); return; } expLoc = textIdx; nextItem(); try { if (!(boolean) analysis()) { vars.add(new ArrayMap()); commands.add(new ForLoop()); nextEnd(); return; } } catch (ClassCastException exc) { handleError(NOTABOOL); } if (!item.equals(",")) { handleError(SYNTAX); return; } ittLoc = textIdx; nextItem(); analysis(); if (commType != BEGIN) { handleError(DOEXPECTED); return; } loc = textIdx; nextItem(); ForLoop newfor; try { newfor = new ForLoop(vname, expLoc, ittLoc, loc, textLine); } catch (ClassCastException exc) { handleError(EXPERR); return; } vars.add(new ArrayMap()); commands.add(newfor); } private void execWhile() throws ScriptException { debug("While Loop"); int expLoc; expLoc = textIdx; nextItem(); try { if (!(boolean) analysis()) { vars.add(new ArrayMap()); commands.add(new WhileLoop()); nextEnd(); return; } } catch (ClassCastException exc) { handleError(NOTABOOL); } if (commType != BEGIN) { handleError(DOEXPECTED); return; } int loc = textIdx; nextItem(); WhileLoop loop = new WhileLoop(expLoc, loc, textLine); vars.add(new ArrayMap()); commands.add(loop); } private void newFunction() throws ScriptException { debug("New Function"); String fName; nextItem(); if (!(Character.isLetter(item.charAt(0)))) { handleError(UNKOWN); } fName = item; nextItem(); if (!item.equals("(")) { handleError(SYNTAX); } nextItem(); ArrayList<String> lists = new ArrayList<String>(); if (!item.equals(")")) { if (Character.isLetter(item.charAt(0))) { lists.add(item); while (nextItem() && item.equals(",")) { nextItem(); lists.add(item); } if (!item.equals(")")) { handleError(SYNTAX); } } else { handleError(UNKOWN); return; } } nextItem(); if (!(commType == BEGIN)) { handleError(SYNTAX); } Function f = new Function(textIdx, -1, lists); functs.put(fName.toLowerCase(), f); vars.add(new ArrayMap()); commands.add(f); nextEnd(); nextItem(); } private Object execFunct() throws ScriptException { debug("Execute Function"); if (ROCFunction.system_functs.contains(item.toLowerCase())) { String key = item; nextItem(); if (!item.equals("(")) { handleError(UNBALPARENS); return null; } nextItem(); String value = ""; if (!item.equals(")")) { while (item.indexOf(")") == -1) { value += item; nextItem(); } if (!item.equals(")")) { handleError(UNBALPARENS); return null; } } if (value.length() > 0 && value.indexOf(",") == -1) { if (value.indexOf("\"") == -1 && value.indexOf("/") == -1 && !isNumber(value)) { String tmp = getVarVal(value).toString(); if (!"unkown".equalsIgnoreCase(tmp)) { value = tmp; } } } else if (value.indexOf(",") != -1) { String[] split = StringUtils.split(value, ","); StringBuilder sbr = new StringBuilder(); for (String s : split) { if (s.indexOf("\"") == -1 && value.indexOf("/") == -1 && !isNumber(s)) { String tmp = getVarVal(s).toString(); if (!"unkown".equalsIgnoreCase(tmp)) { sbr.append(tmp.toString()); } else { sbr.append(s); } } else { sbr.append(s); } sbr.append(','); } value = sbr.toString(); if (value.endsWith(",")) { value = value.substring(0, value.length() - 1); } } Object reuslt = ROCFunction.getValue(key, value); return reuslt == null ? "unkown" : reuslt; } Function f = (Function) functs.get(item.toLowerCase()); nextItem(); if (!item.equals("(")) { handleError(UNBALPARENS); return null; } nextItem(); ArrayMap newVars = new ArrayMap(); int i = 0; if (!item.equals(")")) { newVars.put(f.lists.get(i++), analysis()); while (item.equals(",")) { nextItem(); newVars.put(f.lists.get(i++), analysis()); } if (f.lists.size() < i) { handleError(TOOMANYPARAMS); } if (!item.equals(")")) { handleError(UNBALPARENS); return null; } } f.backLoc = textIdx; vars.add(newVars); commands.add(f); textIdx = f.loc; return running(); } private boolean endCommand(boolean force) throws ScriptException { debug("End Command"); if (force) { while (commands.last().comm != FUNCTION) { commands.pop(); } } Command p = commands.last(); if (p == null) { handleError(SYNTAX); } switch (p.comm) { case IF: nextItem(); passBack(); commands.pop(); return false; case FOR: int loc = textIdx; ForLoop f = (ForLoop) p; if (f.loc > 0) { textIdx = f.itLoc; nextItem(); vars.last().put(f.vName, (double) analysis()); textIdx = f.expLoc; nextItem(); if ((boolean) analysis()) { textIdx = f.loc; textLine = f.line; } else { passBack(); commands.pop(); textIdx = loc; } } else { passBack(); commands.pop(); } nextItem(); return false; case WHILE: loc = textIdx; WhileLoop w = (WhileLoop) p; if (w.loc > 0) { textIdx = w.expLoc; nextItem(); if ((boolean) analysis()) { textIdx = w.loc; textLine = w.line; } else { passBack(); commands.pop(); textIdx = loc; } } else { passBack(); commands.pop(); } nextItem(); return false; case FUNCTION: loc = textIdx; Function funct = (Function) p; if (funct.backLoc > 0) { textIdx = funct.backLoc; } passBack(); commands.pop(); return true; } return false; } private void nextEnd() throws ScriptException { debug("Next end"); int count = 1; while (count > 0 && nextItem()) { if (commType > 7 && commType != PRINTLN) { count++; debug("Find End: " + count); } if (commType == END) { count--; debug("Find End: " + count); } if (commType == ELSE) { if (count == 1) { execElse(); return; } else if (nextItem() && commType == IF) { debug("Find End: " + count); } } } if (commType != END) { handleError(ENDEXPECTED); return; } endCommand(false); } /** * 单纯判定脚本命令是否存在,以及向下移动一次命令行 * * @return * @throws ScriptException */ private boolean nextItem() throws ScriptException { boolean result = nextCommand(); debug(new String[] { "Item: " + item, "CommandStack: " + commands, "Type: " + itemType }); return result; } /** * 分步检索脚本命令 * * @return * @throws ScriptException */ private boolean nextCommand() throws ScriptException { if (itemType == MACROS && macroType != -1) { char flag = macros[1].toCharArray()[0]; StringBuffer sbr = new StringBuffer(1024); while (textIdx < contexts.length) { char ch = contexts[textIdx++]; if (flag == ch) { break; } sbr.append(ch); } item = sbr.toString(); itemType = EOL; macroType = -1; return true; } char ch = ' '; item = ""; itemType = NONE; commType = UNKNCOM; macroType = -1; while (textIdx < contexts.length && isSpaceOrTab(contexts[textIdx])) { textIdx++; } if (textIdx >= contexts.length) { itemType = EOP; item = " "; return false; } if (contexts[textIdx] == '\r') { textIdx += 2; itemType = EOL; item = " "; textLine++; return true; } ch = contexts[textIdx]; if (ch == '#' || (ch == '/' && textIdx + 1 < contexts.length && contexts[textIdx + 1] == '/')) { while (textIdx < contexts.length && contexts[textIdx] != '\r') { textIdx++; } textIdx += 2; itemType = EOL; item = " "; textLine++; return true; } if (ch == '<' || ch == '>' || ch == '=') { switch (ch) { case '<': if (contexts[textIdx + 1] == '=') { item = String.valueOf(LE); textIdx += 2; } else { item = "<"; textIdx++; } break; case '>': if (contexts[textIdx + 1] == '=') { item = String.valueOf(GE); textIdx += 2; } else { item = ">"; textIdx++; } break; case '=': if (contexts[textIdx + 1] == '=') { item = String.valueOf(EQ); textIdx += 2; } else { item = "="; textIdx++; } break; } itemType = DELIMITER; return true; } if (isDelim(ch)) { item += contexts[textIdx]; textIdx++; itemType = DELIMITER; return true; } else if (ch == '"') { textIdx++; ch = contexts[textIdx]; while (ch != '"' && ch != '\r') { item += ch; textIdx++; ch = contexts[textIdx]; } if (ch == '\r') { handleError(MISSQUOTE); return false; } textIdx++; itemType = STRING; return true; } else { while (textIdx < contexts.length && !isDelim(contexts[textIdx])) { item += contexts[textIdx]; textIdx++; } if (isNumber(item)) { itemType = NUMBER; return true; } else if (isBoolean(item)) { itemType = BOOLEAN; return true; } else { // 匹配命令 itemType = lookup(item); if (itemType == UNKNCOM) { itemType = VARIABLE; } if (commType == WAIT) { item = ""; int count = 0; while (textIdx < contexts.length) { ch = contexts[textIdx]; if ((ch == ' ') || (ch == '\n') || (ch == '\t') || (ch == '\r')) { count++; } if (count > 1) { break; } if (ch != ' ') { item += contexts[textIdx]; } textIdx++; } long sleep = 0; if (isNumber(item)) { sleep = (long) Double.parseDouble(item); } else { sleep = (long) waitTimes.get(item.toLowerCase()); } if (sleep <= 0) { sleep = 1; } try { Thread.sleep(sleep); } catch (Exception e) { } nextItem(); } return true; } } } private Object analysis() throws ScriptException { debug("Analysis"); Object result; if (item.equals(EOL) || item.equals(EOP)) { handleError(EXPERR); } result = evalExp1(); debug("Analysis end: " + result); return result; } private Object evalExp1() throws ScriptException { Object result, pResult; double l_temp, r_temp; boolean lb, rb; String ls, rs; char op; String str; result = evalExp2(); op = item.charAt(0); str = item.toLowerCase(); while (isRelOp(op) || isBoolOp(str)) { nextItem(); if (isNumber(result)) { pResult = evalExp2(); if (isRelOp(op)) { if (isNumber(result)) { l_temp = (double) result; r_temp = (double) pResult; switch (op) { case '<': result = (l_temp < r_temp); break; case LE: result = (l_temp <= r_temp); break; case '>': result = (l_temp > r_temp); break; case GE: result = (l_temp >= r_temp); break; case EQ: result = (l_temp == r_temp); break; } } else { handleError(NOTANUMB); result = null; } } } else if (isBoolean(result)) { pResult = evalExp1(); if (isBoolOp(str)) { if (isBoolean(result)) { lb = (boolean) result; rb = (boolean) pResult; switch (str) { case "and": result = (lb && rb); break; case "or": result = (lb || rb); break; case "xor": result = (lb ^ rb); break; case "xand": result = (lb == rb); break; } } else { handleError(NOTABOOL); result = null; } } } else { if (isRelOp(op)) { pResult = evalExp2(); if (!isNumber(result)) { rs = (String) pResult; ls = (String) result; double test = (ls.compareTo(rs)); switch (op) { case '<': result = test < 0; break; case LE: result = test <= 0; break; case '>': result = test > 0; break; case GE: result = test >= 0; break; case EQ: result = test == 0; break; } } else { handleError(NOTASTR); result = null; } } } op = item.charAt(0); str = item.toLowerCase(); } if (DEBUG_E) { debug("1: " + result); } return result; } private Object evalExp2() throws ScriptException { char op; Object result; Object pResult; result = evalExp3(); while ((op = item.charAt(0)) == '+' || op == '-') { nextItem(); pResult = evalExp3(); if (isNumber(result)) { if (isNumber(pResult)) { switch (op) { case '-': result = (double) result - (double) pResult; break; case '+': result = (double) result + (double) pResult; break; } } else { handleError(NOTANUMB); return null; } } else if (!isBoolean(result)) { if (!isNumber(pResult) && !isBoolean(pResult)) { switch (op) { case '-': handleError(INVALIDEXP); case '+': result = (String) result + (String) pResult; break; } } else { handleError(NOTASTR); return null; } } } if (DEBUG_E) { debug("2: " + result); } return result; } private Object evalExp3() throws ScriptException { char op; Object result; Object partialResult; result = evalExp4(); while ((op = item.charAt(0)) == '*' || op == '/' || op == '%') { if (!isNumber(result)) { handleError(NOTANUMB); return null; } nextItem(); partialResult = evalExp4(); if (!isNumber(partialResult)) { handleError(NOTANUMB); return null; } switch (op) { case '*': result = (double) result * (double) partialResult; break; case '/': if ((double) partialResult == 0.0) handleError(DIVBYZERO); result = (double) result / (double) partialResult; break; case '%': if ((double) partialResult == 0.0) handleError(DIVBYZERO); result = (double) result % (double) partialResult; break; } } if (DEBUG_E) { debug("3: " + result); } return result; } private Object evalExp4() throws ScriptException { Object result; Object partialResult; double ex; double t; result = evalExp5(); if (item.equals("^")) { if (!isNumber(result)) { handleError(NOTANUMB); return null; } nextItem(); partialResult = evalExp4(); if (!isNumber(partialResult)) { handleError(NOTANUMB); return null; } ex = (double) result; if ((double) partialResult == 0.0) { result = 1.0; } else { for (t = (double) partialResult - 1; t > 0; t--) { result = (double) result * ex; } } } if (DEBUG_E) { debug("4: " + result); } return result; } private Object evalExp5() throws ScriptException { Object result; String op = item; if (item.equals("-") || item.toLowerCase().equals(selectOps[NOT])) { nextItem(); result = evalExp6(); if (isNumber(result)) { if (op.equals("-")) result = -(double) result; else { handleError(NOTABOOL); return null; } } else if (isBoolean(result)) { if (op.toLowerCase().equals(selectOps[NOT])) result = !(boolean) result; else { handleError(NOTANUMB); return null; } } else { handleError(INVALIDEXP); return null; } } else { result = evalExp6(); } if (DEBUG_E) { debug("5: " + result); } return result; } private Object evalExp6() throws ScriptException { Object result; if (item.equals("(")) { nextItem(); result = evalExp1(); if (!item.equals(")")) { handleError(UNBALPARENS); } nextItem(); return result; } else { result = atom(); nextItem(); } if (DEBUG_E) { debug("6: " + result); } return result; } private Object atom() throws ScriptException { switch (itemType) { case FUNCT: return execFunct(); case NUMBER: try { return Double.parseDouble(item); } catch (NumberFormatException exc) { handleError(NOTANUMB); } case VARIABLE: Object o = getVarVal(item); if (o instanceof Number) { return (Number) o; } else if (isNumber(o)) { if (DEBUG_E) { debug("atom: " + o.toString()); } return Double.parseDouble(o.toString()); } if (o instanceof Boolean) { return (boolean) o; } else if (isBoolean(o)) { return toBoolean((String) o); } return o; case BOOLEAN: return toBoolean(item); case STRING: return item; default: return null; } } private boolean isDelim(char c) { if ((" \r,<>+-/*%^=();#".indexOf(c) != -1)) { return true; } return false; } boolean isSpaceOrTab(char c) { if (c == ' ' || c == '\t') { return true; } return false; } protected boolean isRelOp(char c) { if (relops.indexOf(c) != -1) { return true; } return false; } protected boolean isBoolOp(String str) { for (int i = 0; i < selectOps.length; i++) { if (selectOps[i].equals(str)) { return true; } } return false; } protected boolean isBoolOpId(int id) { for (int i = 0; i < selectOpsId.length; i++) { if (selectOpsId[i] == id) { return true; } } return false; } protected boolean isBoolean(Object o) { String str = o.toString().toLowerCase(); return str.equals("true") || str.equals("false") || str.equals("yes") || str.equals("no") || str.equals("ok") || StringUtils.isNumber(str); } protected boolean toBoolean(Object o) { String str = o.toString().toLowerCase(); if (str.equals("true") || str.equals("yes") || str.equals("ok")) { return true; } else if (StringUtils.isNumber(str)) { return Double.parseDouble(str) > 0; } return false; } protected boolean isNumber(Object o) { String str = o.toString(); return StringUtils.isNumber(str); } private int lookup(String str) { int i; str = StringUtils.rtrim(str.toLowerCase()); // 判定是否已定义的变量 for (int j = 0; j < vars.size(); j++) { ArrayMap tm = vars.get(j); if (tm.containsKey(str)) { return VARIABLE; } } // 判定是否已定义的函数 if (functs.containsKey(str) || ROCFunction.system_functs.contains(str.toLowerCase())) { return FUNCT; } // 判定是否分支指令 for (i = 0; i < selectOps.length; i++) { if (selectOps[i].equals(str)) { return DELIMITER; } } // 判定是否存在于命令表中 for (i = 0; i < commTable.length; i++) { if (commTable[i].equals(str)) { commType = i; return COMMAND; } } // 判定是否为宏指令 for (i = 0; i < macros.length; i++) { if (macros[i].equals(str)) { macroType = i; return MACROS; } } return UNKNCOM; } private void assignVar() throws ScriptException { debug("Assign variable"); String var; var = item; if (!Character.isLetter(var.charAt(0))) { handleError(UNKOWN); return; } nextItem(); if (!item.equals("=")) { handleError(EQUALEXPECTED); return; } nextItem(); vars.last().put(var, analysis()); } private void passBack() { ArrayMap tvars = vars.pop(); for (int i = 0; i < tvars.size(); i++) { String str = (String) tvars.getKey(i); if (vars.last().containsKey(str)) { vars.last().put(str, tvars.get(str)); } } } private Object[] findVar(String vname) { Object o = null; int idx = vname.lastIndexOf('.'); if (idx == -1) { return null; } String name = vname.substring(0, idx); for (int i = 0; i < vars.size(); i++) { ArrayMap tm = vars.get(i); if (tm.containsKey(name)) { o = tm.get(name); break; } } if (o != null) { String method = vname.substring(idx + 1, vname.length()); return new Object[] { name, method, o }; } return findVar(name); } private Object getReflector(String method, Object value) { Object o = null; try { o = ReflectorUtils.getField(value, method); } catch (Exception e) { o = null; } if (o == null) { try { o = ReflectorUtils.getNotPrefixInvoke(value, method); return o; } catch (Exception e) { o = null; } } if (o == null) { try { o = ReflectorUtils.getInvoke(value, method); return o; } catch (Exception e) { o = null; } } return o; } /** * 查询指定的json对象元素(暂时未使用递归,预防有不愿展露的数据被穷举出来) * * @param value * @param vname * @param method * @return */ private Object queryJson(Object value, String vname, String method) { int start = 0; int end = 0; Object o = null; JSONObject json = (JSONObject) value; if (json.has(method)) { o = json.get(method); } if (!vname.equals(method)) { start = vname.indexOf(method); int size = start + method.length() + 1; String packName = ""; if (size >= vname.length()) { packName = method; } else { packName = vname.substring(size, vname.length()); } json = (JSONObject) o; if (packName.indexOf("[") != -1 && packName.indexOf("]") != -1) { if (packName.indexOf(".") == -1) { start = packName.indexOf('['); end = packName.indexOf(']'); String idxName = packName.substring(start + 1, end); packName = packName.substring(0, start); if (json.has(packName)) { o = json.get(packName); if (o != null && o instanceof JSONArray) { JSONArray arrays = (JSONArray) o; int idx = 0; try { idx = (int) Double.parseDouble(idxName); } catch (Exception ex) { idx = 0; } if (idx < arrays.length()) { o = arrays.get(idx); } else { o = null; } } } } else { String[] split = StringUtils.split(packName, "."); Object obj = null; for (String n : split) { if (obj == null) { if (n.indexOf("[") != -1 && n.indexOf("]") != -1) { if (n.indexOf(".") == -1) { start = n.indexOf('['); end = n.indexOf(']'); String idxName = n .substring(start + 1, end); n = n.substring(0, start); if (json.has(n)) { obj = json.get(n); if (obj != null && obj instanceof JSONArray) { JSONArray arrays = (JSONArray) obj; int idx = 0; try { idx = (int) Double .parseDouble(idxName); } catch (Exception ex) { idx = 0; } if (idx < arrays.length()) { obj = arrays.get(idx); } else { obj = null; } } } } } else { if (packName.indexOf(".") == -1) { if (o != null && o instanceof JSONObject) { if (json.has(packName)) { o = json.get(packName); } } } else { if (o != null && o instanceof JSONObject) { String[] splits = StringUtils.split( packName, ","); Object v = null; for (String s : splits) { if (v == null) { if (json.has(s)) { v = json.get(s); } } else { if (v instanceof JSONObject) { if (((JSONObject) v).has(s)) { v = ((JSONObject) v) .get(s); } } } } } } } } else { if (n.indexOf("[") != -1 && n.indexOf("]") != -1) { if (n.indexOf(".") == -1) { start = n.indexOf('['); end = n.indexOf(']'); String idxName = n .substring(start + 1, end); n = n.substring(0, start); if (((JSONObject) obj).has(n)) { obj = ((JSONObject) obj).get(n); if (obj != null && obj instanceof JSONArray) { JSONArray arrays = (JSONArray) obj; int idx = 0; try { idx = (int) Double .parseDouble(idxName); } catch (Exception ex) { idx = 0; } if (idx < arrays.length()) { obj = arrays.get(idx); } else { obj = null; } } } } } else if (n.indexOf(".") == -1) { if (obj != null && obj instanceof JSONObject) { if (((JSONObject) obj).has(n)) { obj = ((JSONObject) obj).get(n); } } } else { if (obj != null && obj instanceof JSONObject) { String[] splits = StringUtils.split(n, ","); Object v = null; for (String s : splits) { if (v == null) { if (((JSONObject) obj).has(s)) { v = ((JSONObject) obj).get(s); } } else { if (v instanceof JSONObject) { if (((JSONObject) v).has(s)) { v = ((JSONObject) v).get(s); } } } } } } } } o = obj; } } else { if (packName.indexOf(".") == -1) { if (o != null && o instanceof JSONObject) { if (json.has(packName)) { o = json.get(packName); } } } else { if (o != null && o instanceof JSONObject) { String[] split = StringUtils.split(packName, ","); Object v = null; for (String n : split) { if (v == null) { if (json.has(n)) { v = json.get(n); } } else { if (v instanceof JSONObject) { if (((JSONObject) v).has(n)) { v = ((JSONObject) v).get(n); } } } } } } } } return o; } private Object getVarVal(String vname) throws ScriptException { if (!Character.isLetter(vname.charAt(0))) { handleError(UNKOWN); return 0; } Object o = null; for (int i = 0; i < vars.size(); i++) { ArrayMap tm = vars.get(i); if (tm.containsKey(vname)) { o = tm.get(vname); } } if (o == null) { o = findVar(vname); int start = 0; int end = 0; if (o != null) { Object[] result = (Object[]) o; // String key = (String) result[0]; String method = (String) result[1]; Object value = result[2]; if (value instanceof JSONObject) { o = queryJson(value, vname, method); } else if (method.indexOf("|") == -1) { o = getReflector(method, value); } else { start = method.indexOf("|"); end = method.lastIndexOf("|"); if (end - start <= 1) { method = StringUtils.replace(method, "|", ""); o = getReflector(method, value); } else { String[] split = StringUtils.split( method.substring(start + 1, end), ","); method = method.substring(0, start); ArrayList<Object> objs = new ArrayList<Object>(5); for (String s : split) { s = StringUtils.rtrim(s); if (s.indexOf("\"") != -1 || s.indexOf("'") != -1) { s = s.replace("\"", "").replace("'", ""); objs.add(s); } else { if ("true".equalsIgnoreCase(s) || "yes".equalsIgnoreCase(s) || "ok".equalsIgnoreCase(s)) { objs.add(true); } else if ("false".equalsIgnoreCase(s) || "no".equalsIgnoreCase(s)) { objs.add(false); } else if (StringUtils.isNumber(s)) { objs.add(Double.parseDouble(s)); } else { Object var = getVarVal(s); if (var != null) { objs.add(var); } } } } o = ReflectorUtils.getNotPrefixInvoke(value, method, objs.toArray()); } } } } if (o == null) { o = "unkown"; } if (debug) { handleError(UNKOWN); } debug("Get var: " + o); return o; } }