C++順序設計與言語(特別版) -- 一個桌面計算器。本站提示廣大學習愛好者:(C++順序設計與言語(特別版) -- 一個桌面計算器)文章只能為提供參考,不一定能成為您想要的結果。以下是C++順序設計與言語(特別版) -- 一個桌面計算器正文
program:
END
expr_list END //END表示輸出完畢
expr_list:
expression PRINT // PRINT表示分號
expression PRINT expr_list
expression:
expression + term
expression - term
term
term:
term / primary
term * primary
primary
primary:
NUMBER
NAME
NAME = expression
- primary
(expression)
#include<iostream>
#include<string>
#include<map>
#include<cctype>
using namespace std;
// 將token用他們的字符所對應的整數表示,這樣做既方便無效,
// 又能協助運用排錯零碎的人。
enum Token_value {
NAME, NUMBER, END, PLUS='+',
MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')',
};
Token_value curr_tok = PRINT;
double expr(bool);
double term(bool);
double prim(bool);
Token_value get_token();
double error(const string&);
map<string, double> table;
int no_of_errors;
int main()
{
table["pi"] = 3.1415924535;
table["e"] = 2.178;
while(cin) {
get_token();
if(curr_tok == END) break;
if(curr_tok == PRINT) continue;
cout<<expr(false)<<'\n';
}
return no_of_errors;
}
// 每個剖析器都有一個bool參數,
// 指明該函數能否需求調用get_token()去獲得下一個參數
// expr處置加減,不斷到不是加減前往left
double expr(bool get) {
double left = term(get);
for(;;) {
switch (curr_tok){
case PLUS:
left += term(true);
break;
case MINUS:
left += term(true);
break;
default:
return left;
}
}
}
// 函數term處置乘除,采用的方式與expr()處置辦法一樣
double term(bool get) {
double left = prim(get);
for(;;) {
switch (curr_tok){
case MUL:
left *= prim(true);
break;
case DIV:
if (double d = prim(true)) {
left /= d;
break;
}
return error("divide by 0");
default:
return left;
}
}
}
double number_value;
string string_value;
// prim處置初等項的方式很像expr和term
double prim(bool get) {
if (get) get_token();
switch(curr_tok) {
case NUMBER: {
double v = number_value;
get_token();
return v;
}
case NAME: {
double& v = table[string_value];
if (get_token() == ASSIGN) v = expr(true);
return v;
}
case MINUS:
return -prim(true);
case LP: {
double e = expr(true);
if (curr_tok != RP) return error(" ) expected");
get_token();
return e;
}
default:
return error("primary expected");
}
}
Token_value get_token() {
char ch;
do { // 低級輸出,改良輸出
if(!cin.get(ch)) return curr_tok = END;
} while(ch != '\n' && isspace(ch));
switch(ch) {
case 0:
return curr_tok=END;
case '\n':
return curr_tok=PRINT;
case '+':
case '-':
case '*':
case '/':
case ';':
case '(':
case ')':
case '=':
return curr_tok = Token_value(ch);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
cin.putback(ch);
cin>>number_value;
return curr_tok = NUMBER;
default:
if (isalpha(ch)) {
string_value = ch;
while(cin.get(ch) && isalnum(ch)) string_value.push_back(ch);
cin.putback(ch);
return curr_tok = NAME;
}
error("bad token");
return curr_tok = PRINT;
}
}
double error(const string& s) {
no_of_errors ++;
cerr<<"error: "<<s<<'\n';
return 1;
}
擴展