package ch.bfh.parser; import ch.bfh.CalculatorLexer; import ch.bfh.Token; import ch.bfh.exceptions.ParserException; import java.util.ArrayList; public class ExpressionParser extends Parser { protected ArrayList parsers = new ArrayList<>(); protected ArrayList ops = new ArrayList<>(); private boolean isParenthesised = false; public ExpressionParser(CalculatorLexer cl) { this.cl = cl; parse(); } protected ExpressionParser(CalculatorLexer cl, Token lastToken, boolean isParenthesised) { this.cl = cl; this.lastToken = lastToken; this.isParenthesised = isParenthesised; //If an expression starts with the lastToken set as '(' it could mean that the Expression first term will be a parenthesised expression parse(); //But it could also mean that this Expression is the parenthesised one, that is why this variable is required. } @Override protected void parse() { Token token; if(lastToken != null && !isParenthesised) token = lastToken; else token = cl.nextToken(); Parser l = null; Parser r = null; // left and right expressions Token op = null; // operation of the current l and right expressions loop: while (token != null && token.type != Token.EOL) { switch (token.type) { case Token.ADD: // '+' is not authorised if not op if (l != null && op == null) { // if the '+' sign is between two term (op) op = token; this.ops.add(op); } else if (l != null && r != null) { // if we already found a 'l op r' we roll l = r; r = null; op = token; this.ops.add(op); }else if (l == null) throw new ParserException("Factor cannot start with '+'."); else throw new ParserException("Invalid use of '+' was found in the Expression."); break; case Token.SUB: if (l != null && op == null) { // if the '-' sign is between two term (op) op = token; this.ops.add(op); break; } else if (l != null && r != null) { // if we already found a 'l op r' we roll l = r; r = null; op = token; this.ops.add(op); } // Then the '-' is the start of a new expression and not an operation case Token.PAL: case Token.ID: case Token.NUM: if (l == null) { l = new TermParser(cl, token); this.parsers.add(l); token = l.lastToken; } else { r = new TermParser(cl, token); this.parsers.add(r); token = r.lastToken; } continue loop; case Token.PAR: if (lastToken != null && lastToken.type == Token.PAL) { // if equal to '(' it means it was created by a Factor lastToken = token; break loop; } else throw new ParserException("No matching opening parenthesis were found."); default: //TODO - Replace default by each individual case throw new ParserException("Malformed Expression."); } token = cl.nextToken(); } if (op != null && r == null) throw new ParserException("Missing expression after last operation '"+op.str+"'"); } @Override public double getValue(){ double result = 0.0; if (!this.parsers.isEmpty()) { result = this.parsers.get(0).getValue(); for (int i = 1; i < this.parsers.size(); i++) { switch (this.ops.get(i-1).type){ case Token.ADD: result += this.parsers.get(i).getValue(); break; case Token.SUB: result -= this.parsers.get(i).getValue(); break; } } } return result; } }