C++ 计算器Calculator类实现

首先祝贺我会插入源代码了。。汗。。原来都不知道还有这个功能。。尴尬

然后是我今天实现的Calculator类。。分享一下,基于C++程序设计语言第六章的计算器程序。计算器使用“递归下降”的算法(一种流行的直截了当的自顶向下技术),按照表达式-》子表达式-》项 这一顺序递归向下求值。然后首先项会返回这个项的类型,为数字、符号、变量等(枚举Token_value描述项的类型),接着将项向上返回给字表达式求值,最后字表达式的求值结果被用于整个表达式的最终结果求值中。除了核心算法的实现,我还添加了一个输入流指针istream*和输入和输出函数,使计算器可以分别从cin、命令行参数或程序里的字符串输入,以及输出到文件中。这里,字符串和命参数将被保存至一个istringstream流,该类是istream的派生类,将用输入流指针指向这个字符串输入流,读取输入。添加了一个异常类error,继承自标准库logic_error类(其实就是用logic_error实现的),以抛出计算过程中的逻辑错误。至此,这个计算器类已经相当完整了。

Calculator.h


#ifndef CALCULATOR_H
#define CALCULATOR_H

#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
#include <map>
#include <stdexcept>
class Calculator{
public:
	class error:public std::logic_error{
	public:
	    error(const std::string& s):
		    std::logic_error(s){}
	};
	enum Token_value{
		NUMBER,NAME,END,
		PLUS='+',MINUS='-',MUL='*',DIV='/',
		PRINT=';',ASSIGN='=',LP='(',RP=')'
	};
    Calculator(const std::string& s):
	    input(new std::istringstream(s)),curr_tok(PRINT)
	{
	    table["pi"]=3.1415926;
	    table["e"]=2.718218;
	}
    Calculator(std::istream& is):input(&is),curr_tok(PRINT)
    {
	    table["pi"]=3.1415926;
	    table["e"]=2.718218;
	}
    void output(std::ostream&);
private:
    double expr(bool);
    double term(bool);
    double prim(bool);
    Token_value get_token();
    
	std::istream* input;
	std::map<std::string,double> table;
	Token_value curr_tok;
	double number_value;
	std::string string_value;
};
void Calculator::output(std::ostream& os)
{
	while(*input){
		get_token();
		if(curr_tok==END) break;
		if(curr_tok==PRINT) continue;
		os<<expr(false)<<std::endl;
	}
}
double Calculator::expr(bool get)
{
	double left=term(get);
	while(true)
    	switch(curr_tok){
    	case PLUS:
    	    left+=term(true);
    	    break;
        case MINUS:
            left-=term(true);
            break;
        default:
            return left;
    	}
}
double Calculator::term(bool get)
{
	double left=prim(get);
	while(true)
    	switch(curr_tok){
    	case MUL:
    	    left*=prim(true);
    	    break;
        case DIV:
            if(double d=prim(true)){
                left/=d;
                break;
            }
            throw error("divide by 0");
        default:
            return left;
    	}
}
double Calculator::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) throw error(") expected");
        get_token();//吃掉 )
		return e;
	default:
	    throw error("primary expected");
	}
}
Calculator::Token_value Calculator::get_token()
{
	char ch;
	do{
		if(!input->get(ch)) return curr_tok=END;
	}while(ch!='\n'&&isspace(ch));
	
	switch(ch){
	case ';':
	case '\n':
	    return curr_tok=PRINT;
    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 '.':
        input->putback(ch);
        input->operator>>(number_value);
        return curr_tok=NUMBER;
    default:
        if(isalpha(ch)){
        	string_value=ch;
        	while(input->get(ch)&&isalnum(ch))
        	    string_value.push_back(ch);
    	    input->putback(ch);
    	    return curr_tok=NAME;
        }
        curr_tok=PRINT;
        throw error("bad token");
	}
}

#endif


main.cpp

//10.16 定义Calculator类
#include <iostream>
#include <fstream>
#include "Calculator.h"
int main(int argc,char* argv[])
{	
	Calculator calc(std::cin);
	try{
		calc.output(std::cout);
	}catch(Calculator::error e){
		std::cout<<e.what()<<std::endl;
		return -1;
	}
    return 0;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值