/*------------------------------------------------
键入计算机的例子并使之能够工作. 不要"浪费时间"去使用已有的
正文文件. 你将会从发现并改正各种 "小而蠢的错误" 中学到许多
东西.
------------------------------------------------*/
#include <iostream>
#include <sstream> // include istringstream
#include <string>
#include <map>
#include <cctype>
using std::cout;
using std::cin;
using std::endl;
using std::cerr;
using std::string;
using std::map;
using std::istream;
using std::istringstream;
double expr(bool get);
double term(bool get);
double prim(bool get);
double error(const string& s);
enum Token_value get_token();
map<string, double> table;
enum Token_value
{
NAME, NUMBER, END,
PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
PRINT = ';', ASSIGN = '=', LP = '(', RP = ')'
};
Token_value curr_tok = PRINT;
// 函数expr()处理加和减
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()处理乘和除
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;
}
}
// 函数prim()处理初等式
double number_value;
string string_value;
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");
}
}
// 函数get_token()为输入函数
Token_value get_token()
{
char ch = 0;
cin >> ch;
switch (ch)
{
case 0:
return curr_tok = END;
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))
{
cin.putback(ch);
cin >> string_value;
return curr_tok = NAME;
}
error("bad token");
return curr_tok = PRINT;
}
}
// 错误处理
int no_of_errors;
double error(const string& s)
{
no_of_errors++;
cerr << "error: " << s << '\n';
return 1;
}
// 驱动程序
istream *input;
int main(int argc, char* argv[])
{
switch (argc)
{
case 1:
input = &cin;
break;
case 2:
input = new istringstream(argv[1]);
break;
default:
error ("too many arguments");
return 1;
}
table["pi"] = 3.1415926535897932385; // 插入预定义的名字
table["e"] = 2.7182818284590452354;
while (*input)
{
get_token();
if (curr_tok == END) break;
if (curr_tok == PRINT) continue;
cout << expr(false) << '\n';
}
if (input != &cin)
delete input;
return no_of_errors;
}