关于那个计算器编译器的问题

革命尚未成功,同志仍需努力。

关于那个计算器编译器的问题:

 

  我从BSBjarne 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.编完这个程序的最深的一个感想就是:我所知道的真是太少了——路漫漫其修远兮,

吾将上下而求索。

          

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值