# 如何写一个计算器？

“1+1=2”

“3+4=7”

“2+7=9”

“2*3=6”

“9-6=3”

“8/2=4”

“3+4=7”

``public Scanner(String source){    this.source = source.toCharArray(); }  private char[] source; private int index = 0; private static char END = '/n'; public char getNext(){     char result;      do{         if (index >= source.length){             return END;         }         result = source[index];         index += 1;     }while (Character.isWhitespace(result));      return result; } ``

} `在进行下一步之前，让我们思考一下这个算式的规律，算式中存在两种对象，一种是数字，一种是操作符，由于存在运算的优先级，我们分成三种对象，并用下面的形式来说明.`

expr —> term + expr | term – expr | term term —> factor * term | factor/term | factor factor—> digit ｜(expr) `‘—>’的意思是’由...组成’，’｜’ 代表’或关系’，expr 代表加减法运算式，term 代表乘除法运算式，factor 代表操作的最小元素，最后一句的意思就是 factor 由数字或者带括号的 expr 组成。这三个定义式是递归的，它可以代表任意深度的算式。让我们用树的形式来观察一下， ![如何写一个计算器](http://news.oneapm.com/content/images/2015/12/-----2015-12-22---6-21-06-1.png) 有了这三种抽象对象我们可以写出对应方法了，我们在parser类里定义三个函数，来代表三种对象的产生过程，并且定义char类型变量head代表正在被扫描的字符。` public class Parser { private Scanner scanner; public Parser(Scanner scanner){ this.scanner = scanner; }

``private char head;  public void parse(){     if (Scanner.END != (head = scanner.getNext())){         expr();     }     if (head != Scanner.END){         throw new RuntimeException(“syntax error at "+head);     } }  public int expr(){     int result = term();     int tempResult;     char operate;     while ((operate = head) == '+' || operate == '-') {         head = scanner.getNext();         tempResult = term();         switch (operate) {             case '+':                 System.out.println(result + "+" + tempResult + "=" + (result + tempResult));                 result += tempResult;                 break;             case '-':                 System.out.println(result + "-" + tempResult + "=" + (result - tempResult));                 result -= tempResult;         }     }     return result; } public int term(){     int result = factor();     int tempResult;     char operate ;     while ((operate=head) == '*' ||operate == '/') {         head = scanner.getNext();         tempResult = factor();         switch (operate) {             case '*':                 System.out.println(result + "*" + tempResult + "=" + (result * tempResult));                 result *= tempResult;                 break;             case '/':                 System.out.println(result + "/" + tempResult + "=" + (result / tempResult));                 result /= tempResult;         }     }     return result; }  public int factor(){     int factor;      if (Character.isDigit(head)){         factor = head - 48; //字符变量－48可以转换成对应的字面数字         head = scanner.getNext();     } else {         match('(');         factor = expr();         match(')');      }     return factor; } ``

``public static void main(String... args){     Scanner scanner = new Scanner("1+1+(3+4)-2*3+8/2");     Parser parser = new Parser(scanner);     parser.parse(); } ``

}

OneAPM Mobile Insight 以真实用户体验为度量标准进行 Crash 分析 ，监控网络请求及网络错误，提升用户留存。访问 OneAPM 官方网站 感受更多应用性能优化体验，想阅读更多技术文章，请访问 OneAPM 官方技术博客 本文转自 OneAPM 官方博客