数据结构课的作业。利用两个堆栈,一个存放输入的操作数和操作符,一个用来实现后缀自动机,包括了正负号的识别。基于”Data Strctures and Probem Solving Using C++“。
// // Evaluator.h // Calculator // // Created by Z on 12-11-26. // Copyright (c) 2012年 Z. All rights reserved. // #ifndef __Calculator__Evaluator__ #define __Calculator__Evaluator__ #include <iostream> #include <stdlib.h> #include <math.h> #include <fstream> #include <sstream> #include <vector> #include <string> using namespace std; enum TokenType {EOL, VALUE, OPAREN, CPAREN, EXP, MULT, DIV, PLUS, MINUS, NEGATIVE, POSITIVE}; //PREC_TABLE matches order of TokenType enum struct Precedence { int inputSymbol; int topOfStack; }PREC_TABLE[] = { { 0, -1 }, { 0, 0 }, // EOL, VALUE { 100, 0 }, { 0, 99 }, // OPAREN, CPAREN { 6, 5 }, // EXP { 3, 4 }, { 3, 4 }, // MULT, DIV { 1, 2 }, { 1, 2 }, // PLUS, MINUS { 90, 90}, { 90, 90} //NEGATIVE, POSITIVE }; /*Token Class: stores both a TokenType, and if the token is a VALUE, its numeric value // //Construction: with a TokenType and a NumericType // //Public Operations: //TokenType getType() --> Return the type of the Tokenizer //const NumericType & getValue() const --> Return the numeric value if the type is VALUE */ template <class NumericType> class Token { private: TokenType theType; NumericType theValue; public: Token(TokenType tt = EOL, const NumericType &nt = 0): theType(tt), theValue(nt){} TokenType getType() const{ return theType; } const NumericType & getValue() const{ return theValue; } }; /* */ template <class NumericType> class Tokenizer { istream & is; public: Tokenizer(istream & input) : is(input){} Token<NumericType> getToken(TokenType previousType); }; template <class NumericType> class Evaluator { private: vector<TokenType> opStack; //Operator stack for conversion. converts infix to postfix vector<NumericType> postFixStack; //Postfix machine stack, stores operands istringstream str; //The character stream NumericType getTop(); //Get top of postfix stack void binaryOp(TokenType topOp); //Process a binary operator void unaryOp(TokenType topOp); //Process an unary operator void processToken(const Token<NumericType> &lastToken); public: Evaluator(const string & s) : str(s){ opStack.push_back(EOL); } NumericType getValue(); //Do the evaluation }; //Find the next token, skipping blanks, and return it. //Print error message if input is unrecognized. template <class NumericType> Token<NumericType> Tokenizer<NumericType> :: getToken(TokenType previousType){ char ch1; NumericType theValue; //Skip blanks while (is.get(ch1) && ch1 == ' ') ; if (is.good() && ch1 != '\n' && ch1 != '\0') { switch (ch1) { case '^': return EXP;//返回一个TokenType,通过只有一个参数的Token的构造函数进行隐式类型转换 case '/': return DIV; case '*': return MULT; case '(': return OPAREN; case ')': return CPAREN; case '+': if (previousType == VALUE || previousType == CPAREN) {//只有当之前输入的是数字或者是右括号时认为+是加号,否则认为+是正号 return PLUS; }else{ return POSITIVE; } case '-': if (previousType == VALUE || previousType == CPAREN) {//只有当之前输入的是数字或者是右括号时认为-是减号,否则认为-是负号 return MINUS; }else{ return NEGATIVE; } default: is.putback(ch1); if (!(is >> theValue)) {//if the input is not a number, show error info cerr << "Parse error" <<endl; return EOL; } return Token<NumericType>(VALUE,theValue); //the Token contains type VALUE and its numeric value } } return EOL; } template <class NumericType> NumericType Evaluator<NumericType> :: getValue(){ Tokenizer<NumericType> tok(str); Token<NumericType> lastToken; TokenType previousType = EOL; do { lastToken = tok.getToken(previousType); previousType = lastToken.getType(); processToken(lastToken); } while (lastToken.getType() != EOL); if (postFixStack.empty()) { cerr << "Missing operand!" << endl; return 0; } NumericType theResult = postFixStack.back(); postFixStack.pop_back(); if (!postFixStack.empty()) { cerr << "Warning: missing operators!" << endl; } return theResult; } template <class NumericType> NumericType Evaluator<NumericType>::getTop( ) { if( postFixStack.empty( ) ) { cerr << "Missing operand" << endl; return 0; } NumericType tmp = postFixStack.back( ); postFixStack.pop_back( ); return tmp; } /* * Handles the binary operator case */ template <class NumericType> void Evaluator<NumericType> :: binaryOp(TokenType topOp){ if (topOp == OPAREN) { cerr << "Unbalanced parentheses" << endl; opStack.pop_back(); return; } NumericType rhs = getTop(); NumericType lhs = getTop(); if (topOp == EXP) { postFixStack.push_back(pow(lhs, rhs)); } if (topOp == PLUS) { postFixStack.push_back(rhs + lhs); } if (topOp == MINUS) { postFixStack.push_back(lhs - rhs); } if (topOp == MULT) { postFixStack.push_back(lhs * rhs); } if (topOp == DIV) { if (rhs != 0) { postFixStack.push_back(lhs / rhs); }else{ cerr << "Division by zero" << endl; postFixStack.push_back(lhs); } } opStack.pop_back(); } /* * Handles the unary operator case */ template <class NumericType> void Evaluator<NumericType> :: unaryOp(TokenType topOp){ if (topOp == OPAREN) { cerr << "Unbalanced parentheses" << endl; opStack.pop_back(); return; } NumericType rhs = getTop(); if (topOp == POSITIVE) { postFixStack.push_back(rhs); } if (topOp == NEGATIVE) { postFixStack.push_back(-rhs); } opStack.pop_back(); } // After token is read, use operator precedence parsing // algorithm to process it; missing opening parentheses // are detected here. template <class NumericType> void Evaluator<NumericType>::processToken( const Token<NumericType> & lastToken ) { TokenType topOp; TokenType lastType = lastToken.getType( ); switch( lastType ) { case VALUE: postFixStack.push_back( lastToken.getValue( ) ); return; case CPAREN: while( ( topOp = opStack.back( ) ) != OPAREN && topOp != EOL) if (topOp != NEGATIVE && topOp != POSITIVE) { binaryOp( topOp ); }else{ unaryOp(topOp); } if( topOp == OPAREN ) opStack.pop_back( ); // Get rid of opening parentheseis else cerr << "Missing open parenthesis" << endl; break; default: // General operator case while( PREC_TABLE[ lastType ].inputSymbol <= PREC_TABLE[ topOp = opStack.back( ) ].topOfStack ){ if (topOp == NEGATIVE || topOp == POSITIVE) { unaryOp(topOp); }else{ binaryOp( topOp ); } } if( lastType != EOL ) opStack.push_back( lastType ); break; } } #endif /* defined(__Calculator__Evaluator__) */