革命尚未成功,同志仍需努力。
关于那个计算器编译器的问题:
我从BS(Bjarne Stroustrup)的课本上总结了一下,将他的那个程序整和了出来。
大概有200行,程序如下:
#include"StaHead.h"
/*#include<iostream>#include<string>#include<map>#include<cctype>#include<sstream>
using namespace std; (StaHead header file include these header files )*/
double expr(bool get); // This function is used by “get_token()”
double number_value;
string string_value;
map<string,double>table;
int no_of_errors;
enum Token_value{
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN ='=', LP='(', RP=')'
};
Token_value curr_tok = PRINT;
double error(const string& s) //used as a sign of error
{
no_of_errors ++;
cerr<<"error:"<<s<<'/n';
return 1;
}
Token_value get_token() //deal with iuput contents such as number,char and so on
{
char ch;
do {
if(!cin.get(ch))
return curr_tok = END;
}
while(ch!='/n' && isspace(ch));
switch (ch){
case ';':
case '/n':
return curr_tok = END;
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;
}
}
double prim(bool get) // deal with primary input
{
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");
}
}
double term(bool get) // deal with operator “*” and “/”
{
double left = prim(get);
for(; ;)
{
switch(curr_tok){
case MUL:
left *= term(true);
break;
case DIV:
if(double d = prim(true))
{
left /= d;
break;
}
return error("divide by 0");
default:
return left;
}
}
}
double expr(bool get) //deal with operator “+”and”-”
{
double left = term(get);
for(; ;)
{
switch(curr_tok){
case PLUS:
left += term(true);
break;
case MINUS:
left -= term(true);
break;
default:
return left;
}
}
}
istream* input;
int main(int argc, char*argv[]) // drive fuction
{
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;
} 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;
}
在完成这个程序的过程中,我自己有一些体会:
1. 就程序本身而言,并没有多大难度。因为大部分的内容在课本有,我只是把它整和了以下。但是这个程序的确有它精妙的地方,特别是递归的巧妙运用,真是令人赞叹。在这里要说明的是,在他的main 函数里有一个这样的用法“cout<<expr(false)<<'/n'”真是要仔细体会以下,有人说可以不用(false)这个参数去实现,的确可以用其他方式达到相同的目的,但是没有必要,“cout<<expr(false)<<'/n“是为了让”get_token();“先执行,也可以在“prim()”里面先执行,其实这是一样的。
2. 在函数与函数之间的交互方式有好多种,全局变量,行参,返回值。这个函数中的curr_tok变量就用的很妙。
3. 在调试这个程序的过程中,我犯了一个很大的错误。本来是由于vc没有装好,编译器一直报错说:找不到头文件,文件不存在。而我打开vc98下面的include 文件夹,查找头文件,有些的却没有,我就在msdn找了,自己加进去,有些就改名字(因为有些头文件名字不一致)。的确这样做,减少了报错数量,但是这个问题还是没有解决,知道现在我重装了vc,才没有这个问题。真正的原因是这样的,我的电脑没有装杀毒软件和防火墙,电脑中毒了(在当时调这个程序的时候,我还不知道),vc里面的东西就变了(有的被删了,有的被改了,不仅仅是include里面的文件),这样程序就调试不出来。现在的确要装杀毒软件和防火墙了,哎,这也是没有办法的事啊。
4. 还有一个问题,在设计程序是要把接口定义好,而且怎么安排内容也很重要,说具体一点,就是定义接口,头文件要有几个,每个里面放些什么,全局变量放字哪之累的问题。
5. 其实这个我这个程序虽然可以运行,但还是有不完美的地方,在实现get_token()函数是在改进用<<读入字符时,如遇到空白回引起问题,本来可以用课本上的那种一次读一个,直到遇到非字母非数字时,用特殊方式解决,原课本改进程序如下:default:
if(isalpha()){
string_value = ch;
while(cin.get(ch) && isalnum(ch))
sting_value.push.back(ch);
cin.putback(ch);
return curr_tok = NAME;
} 我在调试是,他总是报错说 string 类没有push_back()这个函数,在msdn 上查sringl,的确没有push_back()这个函数,查push_back()只有list vector sequence这三个里面才有。于是我就没有用这个改进,暂时只求对。对于这个问题,我还没有解决。
6.编完这个程序的最深的一个感想就是:我所知道的真是太少了——路漫漫其修远兮,
吾将上下而求索。