代码:
#include <iostream>
#include <stack>
#include <functional>
#include <cmath>
#include <string>
#include <sstream>
#include <fstream>
#include <exception>
using namespace std;
class calcerror:public runtime_error
{
public:
calcerror(const string& what_arg)
:runtime_error(what_arg)
{};
};
typedef double Operand;
typedef char OperatorCode;
typedef int OperatorPriority;
typedef struct _Op
{
OperatorCode mCode;
OperatorPriority mPrio;
}
Operator;
class NumStack:public stack<Operand>
{
public:
operator Operand() const
{
if(size()==0)
throw calcerror("no number in stack");
return top();
}
template<typename U> void executeU(U u)
{
if(size()==0)
throw calcerror("not enough operand");
top()=u(top());
}
template<typename B> void executeB(B b)
{
if(size()<2)
throw calcerror("not enough operand");
Operand n=top();
pop();
top()=b(top(),n);
}
};
class OpStack:public stack<Operator>
{
public:
void execute(NumStack& numStack)
{
while(size())
{
OperatorCode code=top().mCode;
OperatorPriority prio=top().mPrio;
switch(code)
{
case '+':
prio==3?(void)0:numStack.executeB(plus<Operand>());
break;
case '-':
prio==3?numStack.executeU(negate<Operand>()):
numStack.executeB(minus<Operand>());
break;
case '*':
numStack.executeB(multiplies<Operand>());
break;
case '/':
if(numStack.top()==(Operand)0)
throw calcerror("divide by 0");
numStack.executeB(divides<Operand>());
break;
case '(':
throw calcerror("more ( than )");
return;
case ')':
throw calcerror(") is in bad position");
break;
}
pop();
}
}
void execute(NumStack& numStack,Operator op)
{
while(size()&&abs(op.mPrio)<=top().mPrio)
{
OperatorCode code=top().mCode;
OperatorPriority prio=top().mPrio;
switch(code)
{
case '+':
prio==3?(void)0:numStack.executeB(plus<Operand>());
break;
case '-':
prio==3?numStack.executeU(negate<Operand>()):
numStack.executeB(minus<Operand>());
break;
case '*':
numStack.executeB(multiplies<Operand>());
break;
case '/':
if(numStack.top()==(Operand)0)
throw calcerror("divide by 0");
numStack.executeB(divides<Operand>());
break;
case '(':
if(op.mCode!=')')
push(op);
return;
case ')':
throw calcerror(") is in bad position");
break;
}
pop();
}
if(op.mCode==')'&&size()&&top().mCode=='(')
pop();
else
push(op);
}
};
class Token
{
enum LastState
{
LASTSTATE_OPERATOR=0,
LASTSTATE_LEFTPAREN,
LASTSTATE_RIGHTPAREN,
LASTSTATE_OPERAND
};
bool mIsOperator;
LastState mLastState;
Operand mOperand;
Operator mOperator;
OperatorPriority getOperatorPrio(OperatorCode code)
{
if((code=='+'||code=='-')&&mLastState==LASTSTATE_LEFTPAREN)
return 3;
if((code=='*'||code=='/')&&
(mLastState==LASTSTATE_OPERAND||mLastState==LASTSTATE_RIGHTPAREN))
return 2;
if((code=='+'||code=='-')&&
(mLastState==LASTSTATE_OPERAND||mLastState==LASTSTATE_RIGHTPAREN))
return 1;
if(code=='('&&
(mLastState==LASTSTATE_OPERATOR||mLastState==LASTSTATE_LEFTPAREN))
return -4;
if(code==')'&&
(mLastState==LASTSTATE_OPERAND||mLastState==LASTSTATE_RIGHTPAREN))
return 0;
throw calcerror(string("unknown operator or unexpected condition: ")+code);
return 0;
}
NumStack& mNumStack;
OpStack& mOpStack;
public:
Token(NumStack& numStack,OpStack& opStack)
:mNumStack(numStack),mOpStack(opStack)
{
mLastState=LASTSTATE_LEFTPAREN;
}
istream& operator>>(istream& is)
{
while(!is.eof()&&isspace(is.peek()))
is.get();
if(is.eof())
{
mOpStack.execute(mNumStack);
is.exceptions(ios::goodbit);
is.setstate(ios::failbit);
}
else if(isdigit(is.peek())||is.peek()=='.')
{
is>>mOperand;
is.exceptions(ios::failbit);
if(mLastState==LASTSTATE_OPERAND)
{
ostringstream oss;
oss<<"unexpected operand: "<<mOperand;
throw calcerror(oss.str());
}
mNumStack.push(mOperand);
mLastState=LASTSTATE_OPERAND;
}
else
{
is.clear();
is>>mOperator.mCode;
is.exceptions(ios::failbit);
mOperator.mPrio=getOperatorPrio(mOperator.mCode);
mOpStack.execute(mNumStack,mOperator);
mLastState=mOperator.mCode=='(' ? LASTSTATE_LEFTPAREN:
mOperator.mCode==')' ? LASTSTATE_RIGHTPAREN:
LASTSTATE_OPERATOR;
}
return is;
}
};
inline istream& operator>>(istream& is,Token& t)
{
return t>>is;
}
void calc(istream& is,ostream& os)
{
NumStack numStack;
OpStack opStack;
Token t(numStack,opStack);
try
{
is>>skipws;
while(is>>t)
0;
if(opStack.size())
throw calcerror("operator format error, need more");
os<<numStack<<endl;
}
catch(const calcerror& e)
{
os<<"meet expression error: "<<e.what()<<endl;
}
catch(const ios::failure& e)
{
os<<"meet ios error: "<<e.what()<<endl;
}
}
istream& easyline(istream& is,string& s)
{
s.resize(0);
while(!is.eof()&&is.peek()=='\n')
is.get();
int ch;
while(!is.eof()&&(ch=is.peek())!=EOF)
{
is.get();
if(ch=='\n')
break;
s+=ch;
}
if(s[s.size()-1]=='\r')
s.resize(s.size()-1);
if(s.size()==0)
is.get();
return is;
}
void calcMulti(istream& is,ostream& os)
{
string s;
while(easyline(is,s))
calc(istringstream(s),os);
}
int main(int argc, char* argv[])
{
if(argc==2)
calcMulti(ifstream(argv[1]),cout);
else if(argc==3)
calcMulti(ifstream(argv[1]),ofstream(argv[2]));
else
calcMulti(cin,cout);
return 0;
}