package de.bse.prgm.parse.arithmetical; import de.bse.util.ParserException; import de.bse.util.Tokenizer; import de.bse.util.Tokenizer.Token; import de.bse.vm.Machine; import de.bse.vm.var.DynamicVariable; import de.bse.vm.var.IVariable; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; /** * Arithmetical Parser which can parse arithmetical terms * @author Elias Groll * @version 2.15 */ public class ArithmeticalParser { private static final int EPSILON = 0; private static final int OPERATOR = 1; private static final int VARIABLE = 2; private static final int NUMBER = 3; private static Tokenizer tokenizer = null; LinkedList<Token> tokens; Token lookahead; private static Map<String, ArithmeticalOperator> knownOperators = null; private void nextToken() { if (!tokens.isEmpty()) { lookahead = tokens.removeLast(); } else { lookahead = tokenizer.new Token(EPSILON, null); } } /** * Parses an arithmetical expression depending on a machine supplied. * @param calc (string) to be calculated * @param machine used to lookup variables * @return IVariable containing the result of the calculation */ public IVariable parseArithmeticalOperation(String calc, Machine machine) { if (tokenizer == null) { String allFormattersAndHashTag = machine.getAllFormattersAndHashTag(); tokenizer = new Tokenizer(); tokenizer .add( "\\+|-|/(?!/)|//|\\*(?!\\*)|\\*\\*|&(?!/)|\\^(?!/)|\\|(?!/)|MAX|MIN|&/|\\|/|\\^/", OPERATOR); tokenizer.add(allFormattersAndHashTag + "*\\w[\\w\\d]*", VARIABLE); tokenizer.add("\\d+", NUMBER); knownOperators = new HashMap<String, ArithmeticalOperator>(); knownOperators.put("+", new Addition()); knownOperators.put("-", new Subtraction()); knownOperators.put("*", new Product()); knownOperators.put("**", new HighProduct()); knownOperators.put("/", new Division()); knownOperators.put("&", new BAND()); knownOperators.put("|", new BOR()); knownOperators.put("^", new BXOR()); knownOperators.put("|/", new BNOR()); knownOperators.put("&/", new BNAND()); knownOperators.put("^/", new BNXOR()); knownOperators.put("//", new Modulo()); knownOperators.put("MIN", new Min()); knownOperators.put("MAX", new Max()); } tokenizer.tokenize(calc); tokens = tokenizer.getTokens(); IVariable retVal = parseTerm(machine); if (lookahead.token != EPSILON) { throw new ParserException("Unexpected symbol found"); } return retVal; } /** * Parses a term on the machine. * @param machine used to parse on * @return IVariable with the result (relies on parseLeftTerm()) */ private IVariable parseTerm(Machine machine) { boolean allowUnary = (lookahead != null) && (lookahead.sequence.equals("-")); nextToken(); if (lookahead.token == VARIABLE || lookahead.token == NUMBER) { IVariable val = parseValue(lookahead.sequence, machine); return parseLeftTerm(val, machine); } else if (allowUnary && lookahead.token == EPSILON) { IVariable val = new DynamicVariable(16); val.setValue(0); return parseLeftTerm(val, machine); } else if (lookahead.token == EPSILON) { throw new ParserException("Nothing to parse"); } else { throw new ParserException("Unexpected symbol found"); } } /** * Parses the left side of the term depending on a given machine. * @param val to be parsed * @param machine to parse on * @return operator instance found in the left term */ private IVariable parseLeftTerm(IVariable val, Machine machine) { nextToken(); if (lookahead.token == OPERATOR) { ArithmeticalOperator operator = knownOperators.get(lookahead.sequence) .create(); operator.init(parseTerm(machine), val); return operator; } else if (lookahead.token == EPSILON) { return val; } else { throw new ParserException("Unexpected symbol found"); } } /** * Parses a value depending on the machine. * @param val to be parsed * @param machine to be parsed on * @return IVariable with value on machine */ private IVariable parseValue(String val, Machine machine) { IVariable retVal = machine == null ? null : machine.parseIVariable(val); if (retVal == null) { retVal = new DynamicVariable(16); try { retVal.setValue(Integer.parseInt(val)); } catch (NumberFormatException e) { throw new ParserException("Unexpected symbol found"); } } return retVal; } // public static void main(String args[]) { // ArithmeticalParser psr = new ArithmeticalParser(); // Machine machine = new Machine(null, null); // machine.B0.setValue(10); // IVariable op = psr.parseArithmeticalOperation("-3 MAX 2 + B0 * 2", // machine); // IVariable op2 = psr.parseArithmeticalOperation("B0-5", machine); // System.out.println(op.getValue()); // machine.B0.setValue(11); // System.out.println(op.getValue()); // } }