c++写的计算器

这篇博客介绍了如何使用C++编程实现一个计算器,通过两个堆栈分别处理操作数和操作符,实现了后缀表达式计算,同时能正确处理正负号。内容基于《Data Structures and Problem Solving Using C++》一书。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构课的作业。利用两个堆栈,一个存放输入的操作数和操作符,一个用来实现后缀自动机,包括了正负号的识别。基于”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__) */


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值