/** * Parses and returns a valid 'leftside' of an expression. If the left side starts with a prefix, * it consumes other expressions with a lower priority than itself. If the left side does not have * a prefix it must be an expr0. * * @param commaIsEndMarker used when the leftside is part of and argument list of expressions * @param maxPriority operators with a higher priority than this will effectivly end the * expression * @return a wrapper of: 1. term correctly structured and 2. the priority of its root operator * @throws InvalidTermException */ private IdentifiedTerm parseLeftSide(boolean commaIsEndMarker, int maxPriority) throws InvalidTermException, IOException { // 1. prefix expression Token f = tokenizer.readToken(); if (f.isOperator(commaIsEndMarker)) { int FX = opManager.opPrio(f.seq, "fx"); int FY = opManager.opPrio(f.seq, "fy"); if (f.seq.equals("-")) { Token t = tokenizer.readToken(); if (t.isNumber()) /*Michele Castagna 06/2011*/ // return new IdentifiedTerm(0, Parser.createNumber("-" + t.seq)); return identifyTerm(0, Parser.createNumber("-" + t.seq), tokenStart); /**/ else tokenizer.unreadToken(t); } // check that no operator has a priority higher than permitted if (FY > maxPriority) FY = -1; if (FX > maxPriority) FX = -1; // FX has priority over FY boolean haveAttemptedFX = false; if (FX >= FY && FX >= OperatorManager.OP_LOW) { IdentifiedTerm found = exprA(FX - 1, commaIsEndMarker); // op(fx, n) exprA(n - 1) if (found != null) /*Castagna 06/2011*/ // return new IdentifiedTerm(FX, new Struct(f.seq, found.result)); return identifyTerm(FX, new Struct(f.seq, found.result), tokenStart); /**/ else haveAttemptedFX = true; } // FY has priority over FX, or FX has failed if (FY >= OperatorManager.OP_LOW) { IdentifiedTerm found = exprA(FY, commaIsEndMarker); // op(fy,n) exprA(1200) or op(fy,n) exprA(n) if (found != null) /*Castagna 06/2011*/ // return new IdentifiedTerm(FY, new Struct(f.seq, found.result)); return identifyTerm(FY, new Struct(f.seq, found.result), tokenStart); /**/ } // FY has priority over FX, but FY failed if (!haveAttemptedFX && FX >= OperatorManager.OP_LOW) { IdentifiedTerm found = exprA(FX - 1, commaIsEndMarker); // op(fx, n) exprA(n - 1) if (found != null) /*Castagna 06/2011*/ // return new IdentifiedTerm(FX, new Struct(f.seq, found.result)); return identifyTerm(FX, new Struct(f.seq, found.result), tokenStart); /**/ } } tokenizer.unreadToken(f); // 2. expr0 return new IdentifiedTerm(0, expr0()); }
private static ArrayList<String> pushVariable(Token t) throws Exception { ArrayList<String> res = new ArrayList<>(); Variable v = Alzheimer.variables.get(t.valueWithoutIndex()); if (v == null) { if (!t.isNumber() && !t.isString() && !t.isCharacter()) { if (!t.isType()) { throw new CompilerException("Unknown variable " + t.value, t.file, t.line); } else { Type T = Alzheimer.types.get(t.valueBeforeFirstDot()); if (T == null) { throw new CompilerException("Unknown type " + t.valueBeforeFirstDot(), t.file, t.line); } else { switch (t.valueAfterFirstDot()) { case "size": exec("push " + T.size() + "; " + t.value, res); break; default: throw new CompilerException( "Type '" + t.valueBeforeFirstDot() + "' does not have property '" + t.valueAfterFirstDot() + "' ", t.file, t.line); } } } } else { exec("push " + t.value + ";", res); } } else { if (v.isArray && !t.isArray()) { res.addAll(pushArray(v, t.file, t.line)); } else { if (t.isArray()) { v = new Variable(); v.name = t.value; String alz = "" + v.accessVarName() + "=( " + v.arrayIndex() + " );\n"; res.addAll(Alzheimer.compile(alz)); res.addAll(v.type.push(v.nameWithoutIndex() + "[" + v.accessVarName() + "]")); } else { res.addAll(v.type.push(t.value)); } } } return res; }
private ArrayList<String> expression(ArrayList<Token> tokens) throws Exception { ArrayList<String> res = new ArrayList<>(); Token opTok = tokens.remove(0); if (tokens.size() < 1) { Variable v = Alzheimer.variables.get(opTok.valueWithoutIndex()); if (v == null && !opTok.isType()) { if (!opTok.isNumber()) { throw new CompilerException( "Number, variable or type property expected", opTok.file, opTok.line); } res.add("push " + opTok.value + ";"); return res; } res.addAll(pushVariable(opTok)); return res; } if (!opTok.value.equals("(")) { if (tokens.size() != 0) { Token tmp = tokens.remove(0); if (!tmp.value.equals("(")) { throw new CompilerException("( expected", tmp.file, tmp.line); } } else { throw new CompilerException("Something is wrong!", opTok.file, opTok.line); } } ArrayList<String> args = new ArrayList<>(); while (tokens.size() != 0) { Token t; if (tokens.size() > 1) { t = tokens.get(1); if (t.value.equals("(")) { res.addAll(expression(tokens)); args.add(""); } else { t = tokens.remove(0); if (t.value.equals(")")) { break; } if (t.isString()) { exec(t.pushString(), res); } else { res.addAll(pushVariable(t)); } } } else { t = tokens.remove(0); if (t.value.equals(")")) { break; } if (t.isString()) { exec(t.pushString(), res); } else { res.addAll(pushVariable(t)); } } } switch (opTok.value) { case "(": break; case "+": case "add": exec("add", res); break; case "-": case "sub": exec("sub", res); break; case "*": case "mul": exec("mul", res); break; case "/": case "div": exec("div", res); break; case "floor": exec("floor", res); break; case "ceil": exec("ceil", res); break; default: exec("call $" + opTok.value, res); } return res; }