Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.io.IOException;
- import java.util.*;
- public class Calculator {
- public static void main(String[] args) {
- //String s = "5 + 3 - (2 ^ 3 * 3 + 3 * 4 - 15.00)"; // = - 13.00
- //String s = "2 + 3";
- //String s = "- 2 + 30";
- // String s = "()";
- // String s = "-(6 + 2)";
- //String s = "(6 + 2)";
- // String s = "-5*3*2 - 12*(0-1)";
- // String s = "1 + 2 +";
- // String s = "1 1 + 2";
- String s = new Scanner(System.in).nextLine();
- Calculator calc = new Calculator(s);
- try {
- System.out.printf("%.0f", calc.eval());
- } catch (Exception e) {
- e.printStackTrace();
- System.out.println("WRONG");
- }
- }
- public Calculator(String source) {
- this.lexer = new Lexer(source);
- }
- private Lexer lexer;
- private Stack<Token> store = new Stack<Token>();
- public double eval() throws MyNumberFormatException {
- while (true) {
- Token token = lexer.nextToken();
- if (token == null) {
- return unwind(true);
- }
- switch (token.getType()) {
- case Number: case LeftBrace:
- store.add(token);
- break;
- case RightBrace:
- double d = unwind(false);
- store.pop(); // remove corresponding left brace
- store.add(new Token(d));
- break;
- case Operation:
- store.add(new Token(conditionalUnwind(Operation.forLabel(token.getLabel()))));
- store.add(token);
- }
- }
- }
- private double conditionalUnwind(Operation op) throws MyNumberFormatException {
- // if (store.empty() || store.peek().getType() == TokenType.LeftBrace)
- // return 0; // unary minus becomes binary in a way: "0 - ..."
- while (true) {
- String op2 = store.pop().getLabel();
- if (store.empty())
- return Double.parseDouble(op2);
- Token prevToken = store.pop();
- Operation prevOp = null;
- String op1 = null;
- if (prevToken.getType() == TokenType.Operation) {
- prevOp = Operation.forLabel(prevToken.getLabel());
- op1 = store.pop().getLabel();
- }
- if (prevOp != null &&
- op.getAssoc() == Associativity.Left && op.getPriority() <= prevOp.getPriority() ||
- op.getAssoc() == Associativity.Right && op.getPriority() < prevOp.getPriority()) {
- double d = Operation.forLabel(prevToken.getLabel()).getApplier().apply(op1, op2);
- store.add(new Token(d));
- } else {
- if (op1 != null)
- store.add(new Token(TokenType.Number, op1));
- store.add(prevToken);
- return Double.parseDouble(op2);
- }
- }
- }
- private double unwind(boolean global) throws MyNumberFormatException {
- while (true) {
- String op2 = store.pop().getLabel();
- if (store.empty() && global || store.peek().getType() == TokenType.LeftBrace && !global)
- return Double.parseDouble(op2);
- String operation = store.pop().getLabel();
- //if (operation.equals("-") && (store.empty() || store.peek().getType() == TokenType.LeftBrace))
- //return -Double.parseDouble(op2);
- String op1 = store.pop().getLabel();
- double d = Operation.forLabel(operation).getApplier().apply(op1, op2);
- if (store.empty() || store.peek().getType() == TokenType.LeftBrace)
- return d;
- store.add(new Token(d));
- }
- }
- }
- class Lexer {
- private int pos;
- private String source;
- public Lexer(String source) {
- pos = 0;
- this.source = source;
- }
- public Token nextToken() {
- // skip leading spaces
- while (pos < source.length() && Character.isWhitespace(source.charAt(pos)))
- ++pos;
- // end of string -> no next token
- if (pos == source.length())
- return null;
- // braces...
- char next = source.charAt(pos);
- if (next == '(') {
- ++pos;
- return Token.leftBraceToken;
- }
- if (next == ')') {
- ++pos;
- return Token.rightBraceToken;
- }
- int endPos = pos;
- TokenType ttype;
- // number token
- if (Character.isDigit(next)) {
- do {
- ++endPos;
- if (endPos == source.length())
- break;
- next = source.charAt(endPos);
- } while (Character.isDigit(next));// || next == '.');
- ttype = TokenType.Number;
- } else { // operation token
- do {
- ++endPos;
- if (endPos == source.length())
- break;
- next = source.charAt(endPos);
- } while (!Character.isDigit(next) && !Character.isWhitespace(next)
- && next != '(' && next != ')');
- ttype = TokenType.Operation;
- }
- Token nextToken = new Token(ttype, source.substring(pos, endPos));
- pos = endPos;
- return nextToken;
- }
- }
- enum TokenType {
- LeftBrace, RightBrace, Number, Operation;
- }
- class Token {
- private TokenType type;
- private String label;
- public static final Token leftBraceToken = new Token(TokenType.LeftBrace, "(");
- public static final Token rightBraceToken = new Token(TokenType.RightBrace, ")");
- public Token(double d) {
- this(TokenType.Number, Double.toString(d));
- }
- public Token(TokenType type, String label) {
- this.type = type;
- this.label = label;
- }
- public TokenType getType() {
- return type;
- }
- public String getLabel() {
- return label;
- }
- }
- enum Associativity {
- Left, Right;
- }
- class Operation {
- private String label;
- private int priority;
- private OpApplier<Double> applier;
- private Associativity assoc; // default is Left
- // private constructor; client should use fabric method forLabel()
- private Operation(String label, int priority, OpApplier<Double> applier, Associativity assoc) {
- this.label = label;
- this.priority = priority;
- this.applier = applier;
- this.assoc = assoc;
- }
- private Operation(String label, int priority, OpApplier<Double> applier) {
- this(label, priority, applier, Associativity.Left);
- }
- public OpApplier<Double> getApplier() {
- return applier;
- }
- public int getPriority() {
- return priority;
- }
- public Associativity getAssoc() {
- return assoc;
- }
- static private Map<String, Operation> labelToOp;
- static private Map<String, OpApplier<Double>> labelToApplier;
- public static Operation forLabel(String opLabel) {
- if (labelToOp == null) {
- List<Operation> ops = new ArrayList<Operation>();
- // ----------------------------------------------- Set your operations, priority, appliers here:
- ops.add(new Operation("+", 1, new AddApplier()));
- ops.add(new Operation("-", 1, new SubApplier()));
- ops.add(new Operation("*", 2, new MultApplier()));
- ops.add(new Operation("/", 2, new DivApplier()));
- // ops.add(new Operation("^", 3, new PowApplier()));
- labelToOp = new HashMap<String, Operation>();
- labelToApplier = new HashMap<String, OpApplier<Double>>();
- for (Operation op : ops) {
- labelToOp.put(op.label, op);
- labelToApplier.put(op.label, op.applier);
- }
- }
- return labelToOp.get(opLabel);
- }
- public boolean isOpLabel(String s) {
- return forLabel(s) == null;
- }
- }
- interface OpApplier<T> {
- abstract public T apply(String op1, String op2) throws MyNumberFormatException;
- }
- class MyNumberFormatException extends IOException {
- MyNumberFormatException(Exception e) {
- super(e);
- }
- }
- class AddApplier implements OpApplier<Double> {
- @Override
- public Double apply(String op1, String op2) throws MyNumberFormatException {
- try {
- return Double.parseDouble(op1) + Double.parseDouble(op2);
- }
- catch (NumberFormatException e) {
- throw new MyNumberFormatException(e);
- }
- }
- }
- class SubApplier implements OpApplier<Double> {
- @Override
- public Double apply(String op1, String op2) throws MyNumberFormatException {
- try {
- return Double.parseDouble(op1) - Double.parseDouble(op2);
- }
- catch (NumberFormatException e) {
- throw new MyNumberFormatException(e);
- }
- }
- }
- class MultApplier implements OpApplier<Double> {
- @Override
- public Double apply(String op1, String op2) throws MyNumberFormatException {
- try {
- return Double.parseDouble(op1) * Double.parseDouble(op2);
- }
- catch (NumberFormatException e) {
- throw new MyNumberFormatException(e);
- }
- }
- }
- class DivApplier implements OpApplier<Double> {
- @Override
- public Double apply(String op1, String op2) throws MyNumberFormatException {
- try {
- return Double.parseDouble(op1) / Double.parseDouble(op2);
- }
- catch (NumberFormatException e) {
- throw new MyNumberFormatException(e);
- }
- }
- }
- class PowApplier implements OpApplier<Double> {
- @Override //Math.pow(Double.parseDouble(op1), op2val);
- public Double apply(String op1, String op2) throws MyNumberFormatException {
- try {
- return Math.pow(Double.parseDouble(op1), Double.parseDouble(op2));
- }
- catch (NumberFormatException e) {
- throw new MyNumberFormatException(e);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement