代码之家  ›  专栏  ›  技术社区  ›  PowerApp101

添加!运算符和sqrt()、pow()等,用于计算器示例应用程序

c++
  •  29
  • PowerApp101  · 技术社区  · 17 年前

    我在做斯特劳斯鲁新书里的练习 "Programming Principles and Practice Using C++" 想知道是否有人这样做,愿意分享知识?特别是关于第6章和第7章中开发的计算器。关于添加的问题!operator和sqrt()、pow()等。我已经完成了这些工作,但我不知道我所拥有的解决方案是否是“好”的做法,而且在bjarne的网站上没有发布过任何解决方案。我想知道我是否走对了。也许我们可以为练习制作一个wiki?

    基本上我有一个令牌解析器。它一次从CIN读取一个字符。它是用来标记表达式的,比如5*3+1,它的效果非常好。其中一个练习是添加sqrt()函数。所以我修改了标记化代码来检测“sqrt”(“然后返回一个表示sqrt的标记对象)。在这种情况下,我使用字符“s”。其他人会这样做吗?如果我需要实现sin()呢?案件陈述会变得混乱。

    char ch;
    cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)
    
    switch (ch) {
        case ';':    // for "print"
        case 'q':    // for "quit"
        case '(': 
        case ')': 
        case '+': 
        case '-': 
        case '*': 
        case '/': 
        case '!':
            return Token(ch);        // let each character represent itself
        case '.':
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
            {    
                cin.putback(ch);         // put digit back into the input stream
                double val;
                cin >> val;              // read a floating-point number
                return Token('8',val);   // let '8' represent "a number"
            }
        case 's': 
            {
                char q, r, t, br;
                cin >> q >> r >> t >> br;
                if (q == 'q' && r == 'r' && t == 't' && br == '(') {
                    cin.putback('(');   // put back the bracket
                    return Token('s');  // let 's' represent sqrt
                }
    
            }
    
        default:
            error("Bad token");
    }
    
    4 回复  |  直到 10 年前
        1
  •  212
  •   iammilind    10 年前
    • 发布的解决方案很少 Stroustrup - Programming 随着时间的推移会有更多的人来。

    • 尝试只使用书中目前为止介绍的语言特性和图书馆设施来解决练习——真正的新手用户不能做任何其他事情。然后稍后返回查看如何改进解决方案。

        2
  •  10
  •   PowerApp101    17 年前

    我认为字符串到函数指针的映射可能是一种简洁的方式来表示像sqrt、sin、cos等接受单个double并返回double的内容:

    map<std::string, double (*)(double)> funcs;
    funcs["sqrt"] = &sqrt;
    funcs["sin"] = &sin;
    funcs["cos"] = &cos;
    

    然后,当解析器检测到正确的字符串(str)时,它可以使用参数(arg)调用函数,如下所示:

    double result = funcs[str](arg);
    

    使用此方法,单个调用可以处理所有类型的函数。

    实际上,我不确定这是否是正确的语法,有人能证实吗?

    这似乎是一种有用的方法吗?

        3
  •  4
  •   csiz    17 年前

    使用派生类和虚拟函数更容易:每个专门的类读取自己的输入…

    class base{public:
    virtual double calc()=0;
    };
    class get_sqrt:public base{
    int useless;
    public:
    virtual double calc(){cin>>number;return sqrt(number);}
    }get_sqrt;
    

    现在我们把这些组织在地图中,我们只使用它们的指针:

    map<string,base*> func;
    func["sqrt"]=&get_sqrt;
    

    还有一个专门的方法,巫婆只看下一个字符:peek();

    char c=cin.peek();
    

    您可以通过使用1 if和putting来摆脱开关!+…在func中;(为了简单起见,它们应该在左边的参数上操作

     if (c>='0'&&c<='9') cin>>right_param; //get a number, you don't have to put the character back as it hasn't been removed
     else{string s; cin>>s;right_param=func[s]->calc();}
    

    所以基本上是某种函数指针,但是如果没有混乱的sintax和witch,您可以在计算之间存储数据。

    编辑:我考虑过空白的问题;它可以在开始计算之前添加,我也认为有一种方法可以设置不同的分隔符,比如数字,但我不知道如何设置。

        4
  •  0
  •   dma    17 年前

    我将把“sqrt”检测转移到另一种函数检测方法中。本质上,我将删除“s”检测,并在默认情况下添加一些内容,以便将字符串读取到“(”。

    如果未检测到“(”,则为错误。

    如果您成功地读取了一个字符串,请将其传递给使用字符串比较的函数名分析器,以生成一个表示对sqrt或sin或您喜欢的任何函数的调用的标记。如果方法读取的字符串无法识别,则检查函数名的方法也可能出错。