zoukankan      html  css  js  c++  java
  • 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)
    • 语法分析器采用通常的递归下降的风格。终结符由词法分析程序get_token()识别,而非终结符由语法分析函数expr(),term()和prim()识别。一旦一个表达式的两个运算对象都知道,就立即对这个表达式求值。
    • 个人觉得分析器就像是定义程序能接受什么输入,而这里采用递归的形式,例如program代表程序,program可以接受END符号或者expr_list END,而expr_list又继续递归下去可以由其他的组成,直到可以得到一个结束情况。

    总代码

    #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)<<'
    ';
        }
        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 != '
    ' && isspace(ch));
    
        switch(ch) {
        case 0:
            return curr_tok=END;
        case '
    ':
            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<<'
    ';
        return 1;
    }

    扩展

    • 自己的代码只是简单的拼接,这里发现一个更好的博客
  • 相关阅读:
    Rainmeter 雨滴桌面 主题分享
    行人检測之HOG特征(Histograms of Oriented Gradients)
    const和readonly差别
    ADB命令解析
    Java实现 蓝桥杯VIP 算法训练 接水问题
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
  • 原文地址:https://www.cnblogs.com/zhengxingpeng/p/6685763.html
Copyright © 2011-2022 走看看