001package edu.pdx.cs410J.whitlock;
002
003import com.google.common.annotations.VisibleForTesting;
004
005import java.util.ArrayList;
006import java.util.List;
007import java.util.Stack;
008import java.util.function.BinaryOperator;
009
010/**
011 * This class is represents a <code>Student</code>.
012 */
013public class RPNCalculator {
014
015  @VisibleForTesting
016  List<Object> parseExpression(String expression) {
017    List<Object> list = new ArrayList<>();
018
019    if (expression.equals("")) {
020      return list;
021    }
022
023    for (String token : expression.split(" ")) {
024      list.add(parseToken(token));
025    }
026
027    return list;
028  }
029
030  private Object parseToken(String token) {
031    Object value;
032
033    switch (token) {
034      case "+":
035        return Operation.ADDITION;
036
037      case "-":
038        return Operation.SUBTRACT;
039
040      case "*":
041        return Operation.MULTIPLY;
042
043      case "/":
044        return Operation.DIVIDE;
045    }
046
047    try {
048      value = Integer.parseInt(token);
049    } catch (NumberFormatException ex) {
050      throw new InvalidRPNExpressionException("Invalid expression: " + token);
051    }
052    return value;
053  }
054
055  int evaluate(String expression) {
056    List lexemes = parseExpression(expression);
057    if (lexemes.isEmpty()) {
058      return 0;
059    }
060
061    Stack<Object> stack = new Stack<>();
062
063    for (Object lexeme : lexemes) {
064      if (lexeme instanceof Integer) {
065        stack.push(lexeme);
066
067      } else if (lexeme instanceof Operation) {
068        Operation operation = (Operation) lexeme;
069        int right = popInt(stack);
070        int left = popInt(stack);
071        int result = operation.evaluate(left, right);
072        stack.push(result);
073      }
074    }
075
076    return (Integer) stack.pop();
077  }
078
079  private int popInt(Stack stack) {
080    return (Integer) stack.pop();
081  }
082
083  public static void main(String[] args) {
084    System.err.println("Missing command line arguments");
085    System.exit(1);
086  }
087
088  enum Operation {
089    SUBTRACT((l, r) -> l - r),
090    MULTIPLY((l, r) -> l * r),
091    DIVIDE((l, r) -> l / r),
092    ADDITION((l, r) -> l + r);
093
094    private final BinaryOperator<Integer> operation;
095
096    Operation(BinaryOperator<Integer> operation) {
097      this.operation = operation;
098    }
099
100    public int evaluate(int left, int right) {
101      return this.operation.apply(left, right);
102    }
103  }
104}