package ch.bfh.parser; import ch.bfh.lexer.CalculatorLexer; import ch.bfh.lexer.Token; import java.util.ArrayList; class ExpressionParser extends Parser { protected ArrayList parsers = new ArrayList<>(); protected ArrayList ops = new ArrayList<>(); private boolean isParenthesised = false; 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(); TermParser l = null; TermParser r = null; // left and right Terms 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("Redundant use of '+' is forbidden."); else throw new ParserException(token, "repetition of operator -> a term was expected."); 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 if(parsers.size() == 0) throw new ParserException("Empty parenthesis were found."); lastToken = token; break loop; } else throw new ParserException("No matching opening parenthesis were found."); case Token.MUL: case Token.DIV: throw new ParserException(token,"a term was expected."); case Token.EQU: case Token.LET: throw new ParserException("The inputted token '"+token.str+"' can only be placed in a variable declaration context (let var = Expression)."); case Token.END: throw new ParserException("The keyword 'exit' can only be placed at the beginning of an expression."); } token = cl.nextToken(); } if (op != null && r == null) throw new ParserException("Missing term after the last operator '"+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; } }