正文

桌面计算器2005-09-28 09:02:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/soliddream/5433.html

分享到:

程序是一个计算器,有4个部分组成:1.语法分析器(Parser),2.输入函数(input function),3.符号表(symbol table)4.驱动(driver).我是用的vc编译器,1,2,3用头文件,4用.cpp文件。第一部分Parser分析器,parser.h.作用是分析用户输入的语句的语法。用户可以在控制台输入以下内容:program:    END    expr_list ENDexpr_list:    expression PRINT    expression PRINT expr_listexpression:    expression+term    expression-term    termterm:    term*primary     term/primary    primaryprimary    NUMBER    NAME    NAME  = expression        注释:在vc中这中间好像必须有空格,不然不行,过一会再讨论这个    -primary    (expression)这里说明了语法,也可以说是给用户说明了使用规则,比如:你在控制台内输入 12*3 ;,计算器就会显示36,其中不管是什么符号(这里有12,*,3,;四个)都要从primary开始进行分析(具体实现后面说),分析器分析12是NUMBER然后再取*号,向上到term,12附给了term,进行*发运算,primary又要从输入继续取值,于是取了3,算出来了36以后再向上,这时候没有+,-,就直接把36给了term,这时候分析器遇到了;号后进行输出,然后继续等待输入的值,这样循环。这是一种递归的方式。以下是Parser.h。/********************************Cal_Parser.hthe Parser of the desk calculatorrecursive descend technique*********************************/#include<map>double prim(bool);        //声明double term(bool);double expr(bool);double expr(bool get){    //handle + and - operation        double left=term(get);    for(;;){        switch(curr_tok){        case PLUS:            left+=term(true);    //get a token to add            break;        case MINUS:            left-=term(true);                break;        default:            return left;        }    }}double term(bool get){    //handle * and / operation    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("devided by 0");        default:            return left;        }    }}double prim(bool get){    //handle primaries    if(get)get_token();    //get a token to decide which type and value it is        switch(curr_tok){    //type which is gotten in the get_token()    case NUMBER:        {        double v=number_value;//value gotten in get_token()        get_token();    //get next        return v;        }    case NAME:        {        double& v=table[string_value];        if(get_token()==ASSIGN)v=expr(true);    //if the input  is like "a=3"        return v;        }    case MINUS:        return -prim(true);        //"-3"    case LP:        {        double e=expr(true);        if(curr_tok!=RP)return error("where is )?");        get_token();        return e;        }    default:        return error("where is primary?");    }}程序只有3个函数,第1,第2个分别是+ -和* /,第3个是因子,都要经过prim()去取值。再来说地3个部分,符号表:我写的整个程序有4个全局变量:Token_Value curr_tok=PRINT;    //hold the input type,see enum:Token_Valuedouble number_value;        //hold the value the last NUMBER readstring string_value;        //hold the value the last NAME readint no_of_error;        //hold the number of error第一个的curr_tok是当前的输入字的类型,Token_Value是枚举型:enum Token_Value{        //input type.    NAME,    NUMBER,       END='!',    PLUS='+',    MINUS='-',      MUL='*',       DIV='/',    PRINT=';',    ASSIGN='=',      LP='(',       RP=')'    };表示的是输入字的类型,这里有11种类行,其中跟书上不一样的是END 我附了'!'的值,程序中输入!就退出。第二个是number_value,意思是如果类型是NUMBER,它就是number的值。第三个string_value,意思是如果类型是NAME,它就是name的制。比如说我输入35,number_value就等于35,curr_tok=NUMBER.又比如我输入a=90,识别a的时候,curr_tok就为NAME,string_value就为"a".第4个的no_of_error是错误的个数,用处相对来说不大。源代码,Cal_SymbolTable.h:/**********************************Cal_SymbolTable.hthe symbol table and all the global variables of desk calculator***********************************/#include <string>#include <map>using namespace std;enum Token_Value{        //input type.    NAME,    NUMBER,       END='!',    PLUS='+',    MINUS='-',      MUL='*',       DIV='/',    PRINT=';',    ASSIGN='=',      LP='(',       RP=')'    };//four global variableToken_Value curr_tok=PRINT;    //hold the input type,see enum:Token_Valuedouble number_value;        //hold the value the last NUMBER readstring string_value;        //hold the value the last NAME readint no_of_error;            //hold the number of error//mapmap<string,double>table;其中map是来存放初始化的一些固定常量如pi=3.1415926....等等,还有一个功能是存取NAME的值,比如你输入a=9 然后程序就会生成table["a"]=9,table是一个map。第2部分输入函数,get_token()这一个函数,就是取用户输入的值并且判断值得类型,是NAME?还是一个NUMBER,并且把类型给全局变量curr_tok,把number的值给number_value如果类型为NUMBER的话。原函数,Cal_Input.h:/**********************Cal_Input.hget the input from user***********************/#include<cctype>#include<iostream>using namespace std;Token_Value get_token(){    //get the value and type of value from input    char ch=0;    cin>>ch;    switch(ch){    case 0:        return curr_tok=END;        case ';':                                //if input is  operation    case '*':    case '/':    case '+':    case '-':    case '(':    case ')':    case '=':    case '!':        return curr_tok=Token_Value(ch);            case '0': case '1': case '2': case '3': case '4': //if number    case '5': case '6': case '7': case '8': case '9':     case '.':        cin.putback(ch);        cin>>number_value;                    //set value        return curr_tok=NUMBER;            //set type    default:        if(isalpha(ch)){                    //'a'-'Z'            cin.putback(ch);                    cin>>string_value;            return curr_tok=NAME;        }        error("bad token");        return curr_tok=PRINT;    }}因为输入字是以char的形式输入的,所以没有办法输入两位以上或者是小数,所以程序遇到一个数字的char的时候putback,在用cin把这个值输入完整,NAME也同样是如此第4个部分是驱动,也就是main函数。先看原文件:Cal_Driver.cpp#include "Cal_SymbolTable.h"#include "Cal_error.h"#include "Cal_Input.h"#include "Cal_Parser.h"#include <iostream>using namespace std;int main(){table["pi"]=3.1415926525897;table["e"]=2.71828182845904;while(cin){    get_token();    if(curr_tok==END)break;    if(curr_tok==PRINT)continue;    cout<<expr(false)<<'\n';}return no_of_error;}先预设了两个map,用table["pi"]和table["e"],都知道是什么意思吧。。。下面进行无止境的循环,除了用户输入“!”,也就是END的时候,先取数,再送到分析器分析。完

阅读(4423) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册