主题: tt
查看单个帖子
  #1 (permalink)  
旧 2003-10-08
polyrandom 的头像
polyrandom polyrandom 当前离线
超级版主
 
注册日期: 2002-09-03
帖子: 3,135
文章: 20
polyrandom 正向着好的方向发展
默认 tt

代码:
#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; }
回复时引用此帖