作者在 2011-04-24 09:03:32 发布以下内容
#include "stdafx.h"
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
class Computer
{
double result;//保存运算结果
istringstream expr; //保存表达示
int paren; /*'(' paren加1,')'paren减1。一旦paren为负时就肯定是输入有错,运算全部结束后其值不为零也是出错。可以增加一个小类来做为paren的类型*/
protected:
int getSign();//获取运算符号
double getDouble();//提取一个整数,供下面两个函数调用
double getLeftV(bool);//bool这个参数的作用是用来说明获取的操作数能不能马上返回
double getRightV(bool);
double comput(double lv);//计算的核心函数
public:
operator double()
{
return result;
}
Computer(const std::string);
};
Computer::Computer(const std::string str):expr(str),result(0),paren(0)
{
result = comput(getLeftV(true));
}
int Computer::getSign()
{
return expr.get();
}
//每遇到一个左括号都会当成一个新的表达示来调用comput(double),所以在comput(double)里不用考虑括号的情况
double Computer::comput(double lv)
{
int sign = 0;
while((sign = getSign()) != EOF)//控制运行
{
//char sign = expr[index++];//获取运算符号
switch(sign)
{
case '-':
return comput(lv - getRightV(false));
case '+':
return comput(lv + getRightV(false));
case '*':
return comput(lv * getRightV(true));//设置成true是因为乘除的优先级高,可以马上获取右操作数
case '/':
{
double rv = getRightV(true);
if(rv)
return comput(lv / rv);
else
;//出错处理
}
default:
;
//错误处理
}
}
return lv;
}
double Computer::getDouble()
{
double r = 0;
expr >> r;
return r;
}
double Computer::getLeftV(bool t)
{
int c = expr.get();
double lv = 0;
if(c == '.' || isdigit(c))
c = 0;
const int NUM = 0;
switch(c)
{
case NUM:
{
expr.unget();
lv = getDouble();
if(t)
break;
switch(getSign())
{
case EOF:
break;
case '+':
case '-':
expr.unget();
break;
case ')':
--paren;
break;
case '*':
case '/':
expr.unget();
lv = comput(lv);
break;
}//switch (sign)
}//end case NUM
break;
case '-':
lv = -getLeftV(true);//通过传递参数true让getLeftV()尽可能快的返回它获取的值
break;
case '(':
++paren;//括号的处理
lv = comput(getLeftV(true));//调用comput()是把括号里的表达看成一个新的表达示。
break;
default:
;//error
}//end switch
return lv;
}
double Computer::getRightV(bool t)//参看getLeftV(bool)
{
return getLeftV(t);
}
int main()
{
string str;
cin >> str;
cout << Computer(str) <<endl;
return 0;
}
在VC2008中编译通过。#include<iostream>
#include<string>
#include<sstream>
using namespace std;
class Computer
{
double result;//保存运算结果
istringstream expr; //保存表达示
int paren; /*'(' paren加1,')'paren减1。一旦paren为负时就肯定是输入有错,运算全部结束后其值不为零也是出错。可以增加一个小类来做为paren的类型*/
protected:
int getSign();//获取运算符号
double getDouble();//提取一个整数,供下面两个函数调用
double getLeftV(bool);//bool这个参数的作用是用来说明获取的操作数能不能马上返回
double getRightV(bool);
double comput(double lv);//计算的核心函数
public:
operator double()
{
return result;
}
Computer(const std::string);
};
Computer::Computer(const std::string str):expr(str),result(0),paren(0)
{
result = comput(getLeftV(true));
}
int Computer::getSign()
{
return expr.get();
}
//每遇到一个左括号都会当成一个新的表达示来调用comput(double),所以在comput(double)里不用考虑括号的情况
double Computer::comput(double lv)
{
int sign = 0;
while((sign = getSign()) != EOF)//控制运行
{
//char sign = expr[index++];//获取运算符号
switch(sign)
{
case '-':
return comput(lv - getRightV(false));
case '+':
return comput(lv + getRightV(false));
case '*':
return comput(lv * getRightV(true));//设置成true是因为乘除的优先级高,可以马上获取右操作数
case '/':
{
double rv = getRightV(true);
if(rv)
return comput(lv / rv);
else
;//出错处理
}
default:
;
//错误处理
}
}
return lv;
}
double Computer::getDouble()
{
double r = 0;
expr >> r;
return r;
}
double Computer::getLeftV(bool t)
{
int c = expr.get();
double lv = 0;
if(c == '.' || isdigit(c))
c = 0;
const int NUM = 0;
switch(c)
{
case NUM:
{
expr.unget();
lv = getDouble();
if(t)
break;
switch(getSign())
{
case EOF:
break;
case '+':
case '-':
expr.unget();
break;
case ')':
--paren;
break;
case '*':
case '/':
expr.unget();
lv = comput(lv);
break;
}//switch (sign)
}//end case NUM
break;
case '-':
lv = -getLeftV(true);//通过传递参数true让getLeftV()尽可能快的返回它获取的值
break;
case '(':
++paren;//括号的处理
lv = comput(getLeftV(true));//调用comput()是把括号里的表达看成一个新的表达示。
break;
default:
;//error
}//end switch
return lv;
}
double Computer::getRightV(bool t)//参看getLeftV(bool)
{
return getLeftV(t);
}
int main()
{
string str;
cin >> str;
cout << Computer(str) <<endl;
return 0;
}
使用了标准库中的istringstream类。大大减化了double Computer::getDouble()的代码。
对于异常处理这次也是没写出来。有兴趣的朋友自己添上~