您的位置:首页 > 编程语言 > C语言/C++

C++ 计算器Calculator类实现

2012-01-17 20:35 281 查看
首先祝贺我会插入源代码了。。汗。。原来都不知道还有这个功能。。


然后是我今天实现的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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: