如何寫一個計算器?
考慮這樣一個問題,給定一個字串,“1+1+(3+4)-2*3+8/2”,如何將它轉化為如下形式:
“1+1=2”
“3+4=7”
“2+7=9”
“2*3=6”
“9-6=3”
“8/2=4”
“3+4=7”
換句話說,就是如何將字串按照四則運算計算出來,如何寫一個計算器。 拿 java 來舉例,並且為了簡單,我們只考慮個位數。這個過程大概分為這幾個步驟,首先需要掃描字串去除空白字元,其次將各個字元轉換成對應的操作符或運算元,然後按照四則運算規則逐次計算並輸出。
好,我們首先構造一個 scanner,它主要功能是順序掃描字串,返回字元並跳過其中的空白字元,如下 2015年就要結束了, ``` public class Scanner {
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;
}
``` //match 方法用來斷言 head 是什麼字元,如果為真,將讀取下一個字元賦值給 head public boolean match(char symbol){ if (symbol == head){ head = scanner.getNext(); return true; } throw new RuntimeException("syntax error at "+head); }
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();
}
}
如果回過頭來重新考慮這件事情,你會發現我們這個小程式的本質是將一段文字轉化成可以執行的程式,正如我們的編譯器一樣。而實際上編譯器要複雜的多,它的基本工作過程可以分為幾個步驟, 1,詞法分析 (scanning),讀入源程式字元流,將字元轉換成有意義的詞素 (lexeme) 的序列,並生成對應的詞法單元 (token) 2,語法分析 (parsing),主要目的是生成詞法單元的語法結構,一般會使用樹形結構來表示,稱為語法樹。 3,語義分析 (semantic analysis),使用語法樹檢查源程式是否和語言定義的語義一致。其中一個重要部分是型別檢查。 4,生成中間程式碼,語義分析完成後,編譯器會將語法樹生成為一種接近機器語言的中間程式碼。我們程式最後產生的一系列小的表示式與之類似。 5,程式碼優化,編譯器會嘗試改進中間程式碼,用以生成更高效的機器程式碼。 6,程式碼生成,將優化過對中間程式碼生成機器程式碼。
在這些過程中,遞迴的方法起到了非常重要的作用,有一句話說明了編譯器的本質,編譯器就是讓你的源程式變成可執行程式的另一個程式。你會發現這個定義本身就是遞迴的。透過這些編譯原理,可以讓我們更加深入的理解程式語言,甚至發明一種程式語言。
OneAPM Mobile Insight 以真實使用者體驗為度量標準進行 Crash 分析,監控網路請求及網路錯誤,提升使用者留存。訪問 OneAPM 官方網站感受更多應用效能優化體驗,想閱讀更多技術文章,請訪問 OneAPM 官方技術部落格。 本文轉自 OneAPM 官方部落格
相關文章
- Python編寫一個簡單計算器Python
- Flutter最佳入門方式——寫一個計算器Flutter
- bc : 一個命令列計算器命令列
- 一臺伺服器可以掛多少個網站?如何計算?伺服器網站
- 使用QT做一個簡易計算器QT
- c++控制檯寫一個計時器C++
- 請寫一個整數計算器,支援加減乘三種運算和括號。Python版本Python
- 如何用Java寫一個聊天機器人Java機器人
- 使用vue寫的計算器demoVue
- 如何設計一個流計算基準測試?
- HDU_1237 一個簡單的計算器
- Flutter實現一個較好看的計算器Flutter
- [前端漫談] 做一個四則計算器前端
- Java實現一個簡單的計算器Java
- 前端 JavaScript 實現一個簡易計算器前端JavaScript
- 編寫一個簡易計時器程式(edu)
- 如何寫一個js模組打包器(翻譯)JS
- [譯] 如何用 Python 寫一個 Discord 機器人Python機器人
- 用java實現一個簡單的計算器Java
- 動手做一個酷炫(並不)的計算器(一)
- JavaScript編寫計算器的發展史JavaScript
- rasa 如何寫一個故事
- html+css+js製作一個簡易計算器HTMLCSSJS
- 從0到1實現一個簡單計算器
- 手寫一個解析器
- Matlab AppDesigner程式設計教程第2章——介面介紹及編寫一個計算器(物件導向的方式)MatlabAPP程式設計物件
- C++簡易計算器自寫棧版C++
- 一個計算機學生計算機
- 如何編寫一個React元件React元件
- 也談如何寫一個Webserver(-)WebServer
- 動手做一個酷炫(並不)的計算器(二)
- 用JS點選事件做一個簡單的計算器JS事件
- 如何編寫一個使用Objective-C的下載器程式Object
- win10計算器怎麼用_win10如何開啟計算器Win10
- win10計算器在哪開啟_win10如何調出計算器Win10
- 如何設計一個高效能閘道器
- netty寫一個http伺服器NettyHTTP伺服器
- python——設計一個簡單的購房商貸月供計算器Python
- 畢業生如何寫好簡歷,如何寫好計算機專業簡歷?計算機