Advertisement
ulysses4ever

parse-arithmetic

Apr 9th, 2012
120
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5 8.48 KB | None | 0 0
  1. import java.io.IOException;
  2. import java.util.*;
  3.  
  4. public class Calculator {
  5.    
  6.     public static void main(String[] args) {
  7.         //String s = "5 + 3 - (2 ^ 3 * 3 + 3 * 4 - 15.00)"; // = - 13.00
  8.         //String s = "2 + 3";
  9.         //String s = "- 2 + 30";
  10. //      String s = "()";
  11. //      String s = "-(6 + 2)";
  12.         //String s = "(6 + 2)";
  13. //      String s = "-5*3*2 - 12*(0-1)";
  14. //      String s = "1 + 2 +";
  15. //      String s = "1 1 + 2";
  16.         String s = new Scanner(System.in).nextLine();
  17.  
  18.         Calculator calc = new Calculator(s);       
  19.         try {
  20.             System.out.printf("%.0f", calc.eval());
  21.         } catch (Exception e) {
  22.             e.printStackTrace();
  23.             System.out.println("WRONG");
  24.         }
  25.     }
  26.    
  27.     public Calculator(String source) {
  28.         this.lexer = new Lexer(source);
  29.     }
  30.  
  31.     private Lexer lexer;
  32.    
  33.     private Stack<Token> store = new Stack<Token>();
  34.    
  35.     public double eval() throws MyNumberFormatException {
  36.         while (true) {
  37.             Token token = lexer.nextToken();
  38.             if (token == null) {
  39.                 return unwind(true);
  40.             }
  41.             switch (token.getType()) {
  42.             case Number: case LeftBrace:
  43.                 store.add(token);
  44.                 break;
  45.  
  46.             case RightBrace:
  47.                 double d = unwind(false);
  48.                 store.pop(); // remove corresponding left brace
  49.                 store.add(new Token(d));
  50.                 break;
  51.            
  52.             case Operation:
  53.                 store.add(new Token(conditionalUnwind(Operation.forLabel(token.getLabel()))));
  54.                 store.add(token);
  55.             }
  56.         }
  57.     }
  58.  
  59.     private double conditionalUnwind(Operation op) throws MyNumberFormatException {
  60. //      if (store.empty() || store.peek().getType() == TokenType.LeftBrace)
  61. //          return 0; // unary minus becomes binary in a way: "0 - ..."
  62.         while (true) {
  63.             String op2 = store.pop().getLabel();
  64.             if (store.empty())
  65.                 return Double.parseDouble(op2);
  66.             Token prevToken = store.pop();
  67.             Operation prevOp = null;
  68.             String op1 = null;
  69.             if (prevToken.getType() == TokenType.Operation) {
  70.                 prevOp = Operation.forLabel(prevToken.getLabel());
  71.                 op1 = store.pop().getLabel();
  72.             }
  73.             if (prevOp != null &&
  74.                     op.getAssoc() == Associativity.Left && op.getPriority() <= prevOp.getPriority() ||
  75.                     op.getAssoc() == Associativity.Right && op.getPriority() < prevOp.getPriority()) {
  76.                 double d = Operation.forLabel(prevToken.getLabel()).getApplier().apply(op1, op2);
  77.                 store.add(new Token(d));
  78.             } else {
  79.                 if (op1 != null)
  80.                     store.add(new Token(TokenType.Number, op1));
  81.                 store.add(prevToken);
  82.                 return Double.parseDouble(op2);
  83.             }
  84.         }
  85.     }
  86.  
  87.     private double unwind(boolean global) throws MyNumberFormatException {
  88.         while (true) {
  89.             String op2 = store.pop().getLabel();
  90.             if (store.empty() && global || store.peek().getType() == TokenType.LeftBrace && !global)
  91.                 return Double.parseDouble(op2);
  92.             String operation = store.pop().getLabel();
  93.             //if (operation.equals("-") && (store.empty() || store.peek().getType() == TokenType.LeftBrace))
  94.                 //return -Double.parseDouble(op2);
  95.             String op1 = store.pop().getLabel();
  96.             double d = Operation.forLabel(operation).getApplier().apply(op1, op2);
  97.             if (store.empty() || store.peek().getType() == TokenType.LeftBrace)
  98.                 return d;
  99.             store.add(new Token(d));
  100.         }
  101.     }
  102. }
  103.  
  104. class Lexer {
  105.     private int pos;
  106.    
  107.     private String source;
  108.    
  109.     public Lexer(String source) {
  110.         pos = 0;
  111.         this.source = source;
  112.     }
  113.  
  114.     public Token nextToken() {
  115.        
  116.         // skip leading spaces
  117.         while (pos < source.length() && Character.isWhitespace(source.charAt(pos)))
  118.             ++pos;
  119.        
  120.         // end of string -> no next token
  121.         if (pos == source.length())
  122.             return null;
  123.        
  124.         // braces...
  125.         char next = source.charAt(pos);
  126.         if (next == '(') {
  127.             ++pos;
  128.             return Token.leftBraceToken;
  129.         }
  130.         if (next == ')') {
  131.             ++pos;
  132.             return Token.rightBraceToken;
  133.         }
  134.        
  135.         int endPos = pos;
  136.         TokenType ttype;
  137.         // number token
  138.         if (Character.isDigit(next)) {         
  139.             do {
  140.                 ++endPos;
  141.                 if (endPos == source.length())
  142.                     break;
  143.                 next = source.charAt(endPos);
  144.             } while (Character.isDigit(next));// || next == '.');
  145.             ttype = TokenType.Number;
  146.            
  147.         } else { // operation token
  148.             do {
  149.                 ++endPos;
  150.                 if (endPos == source.length())
  151.                     break;
  152.                 next = source.charAt(endPos);
  153.             } while (!Character.isDigit(next) && !Character.isWhitespace(next)
  154.                     && next != '(' && next != ')');
  155.             ttype = TokenType.Operation;
  156.         }
  157.         Token nextToken = new Token(ttype, source.substring(pos, endPos));
  158.         pos = endPos;
  159.         return nextToken;
  160.     }
  161.    
  162. }
  163.  
  164. enum TokenType {
  165.     LeftBrace, RightBrace, Number, Operation;
  166. }
  167.  
  168. class Token {
  169.     private TokenType type;
  170.     private String label;
  171.    
  172.     public static final Token leftBraceToken = new Token(TokenType.LeftBrace, "(");
  173.    
  174.     public static final Token rightBraceToken = new Token(TokenType.RightBrace, ")");
  175.    
  176.     public Token(double d) {
  177.         this(TokenType.Number, Double.toString(d));
  178.     }  
  179.    
  180.     public Token(TokenType type, String label) {
  181.         this.type = type;
  182.         this.label = label;
  183.     }
  184.  
  185.     public TokenType getType() {
  186.         return type;
  187.     }
  188.  
  189.     public String getLabel() {
  190.         return label;
  191.     }
  192. }
  193.  
  194. enum Associativity {
  195.     Left, Right;
  196. }
  197.  
  198. class Operation {
  199.    
  200.     private String label;
  201.    
  202.     private int priority;
  203.    
  204.     private OpApplier<Double> applier;
  205.    
  206.     private Associativity assoc; // default is Left
  207.  
  208.     // private constructor; client should use fabric method forLabel()
  209.     private Operation(String label, int priority, OpApplier<Double> applier, Associativity assoc) {
  210.         this.label = label;
  211.         this.priority = priority;
  212.         this.applier = applier;
  213.         this.assoc = assoc;
  214.     }
  215.  
  216.     private Operation(String label, int priority, OpApplier<Double> applier) {
  217.         this(label, priority, applier, Associativity.Left);
  218.     }
  219.     public OpApplier<Double> getApplier() {
  220.         return applier;
  221.     }
  222.  
  223.     public int getPriority() {
  224.         return priority;
  225.     }
  226.    
  227.     public Associativity getAssoc() {
  228.         return assoc;
  229.     }
  230.  
  231.     static private Map<String, Operation> labelToOp;
  232.    
  233.     static private Map<String, OpApplier<Double>> labelToApplier;
  234.    
  235.     public static Operation forLabel(String opLabel) {
  236.         if (labelToOp == null) {
  237.             List<Operation> ops = new ArrayList<Operation>();
  238.            
  239.             // ----------------------------------------------- Set your operations, priority, appliers here:
  240.             ops.add(new Operation("+", 1, new AddApplier()));
  241.             ops.add(new Operation("-", 1, new SubApplier()));
  242.             ops.add(new Operation("*", 2, new MultApplier()));
  243.             ops.add(new Operation("/", 2, new DivApplier()));
  244. //          ops.add(new Operation("^", 3, new PowApplier()));
  245.            
  246.             labelToOp = new HashMap<String, Operation>();
  247.             labelToApplier = new HashMap<String, OpApplier<Double>>();
  248.             for (Operation op : ops) {
  249.                 labelToOp.put(op.label, op);
  250.                 labelToApplier.put(op.label, op.applier);
  251.             }
  252.         }
  253.        
  254.         return labelToOp.get(opLabel);
  255.     }
  256.    
  257.     public boolean isOpLabel(String s) {
  258.         return forLabel(s) == null;
  259.     }
  260. }
  261.  
  262. interface OpApplier<T> {
  263.     abstract public T apply(String op1, String op2) throws MyNumberFormatException;
  264. }
  265.  
  266. class MyNumberFormatException extends IOException {
  267.    
  268.     MyNumberFormatException(Exception e) {
  269.         super(e);
  270.     }
  271. }
  272.  
  273. class AddApplier implements OpApplier<Double> {
  274.  
  275.     @Override
  276.     public Double apply(String op1, String op2) throws MyNumberFormatException {
  277.         try {
  278.             return Double.parseDouble(op1) + Double.parseDouble(op2);
  279.         }
  280.         catch (NumberFormatException e) {
  281.             throw new MyNumberFormatException(e);
  282.         }
  283.     }
  284. }
  285.  
  286. class SubApplier implements OpApplier<Double> {
  287.  
  288.     @Override
  289.     public Double apply(String op1, String op2) throws MyNumberFormatException {
  290.         try {
  291.             return Double.parseDouble(op1) - Double.parseDouble(op2);
  292.         }
  293.         catch (NumberFormatException e) {
  294.             throw new MyNumberFormatException(e);
  295.         }
  296.     }
  297. }
  298.  
  299. class MultApplier implements OpApplier<Double> {
  300.  
  301.     @Override
  302.     public Double apply(String op1, String op2) throws MyNumberFormatException {
  303.         try {
  304.             return Double.parseDouble(op1) * Double.parseDouble(op2);
  305.         }
  306.         catch (NumberFormatException e) {
  307.             throw new MyNumberFormatException(e);
  308.         }
  309.     }
  310. }
  311.  
  312. class DivApplier implements OpApplier<Double> {
  313.  
  314.     @Override
  315.     public Double apply(String op1, String op2) throws MyNumberFormatException {
  316.         try {
  317.             return Double.parseDouble(op1) / Double.parseDouble(op2);
  318.         }
  319.         catch (NumberFormatException e) {
  320.             throw new MyNumberFormatException(e);
  321.         }
  322.     }
  323. }
  324.  
  325. class PowApplier implements OpApplier<Double> {
  326.  
  327.     @Override //Math.pow(Double.parseDouble(op1), op2val);
  328.     public Double apply(String op1, String op2) throws MyNumberFormatException {
  329.         try {
  330.             return Math.pow(Double.parseDouble(op1), Double.parseDouble(op2));
  331.         }
  332.         catch (NumberFormatException e) {
  333.             throw new MyNumberFormatException(e);
  334.         }
  335.     }
  336. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement