c ++ Postfix-Notation Evaluator 使用堆栈

c++ Postfix-Notation Evaluator using stacks

我的任务是创建一个 postfix 计算器,但问题是我无法将 Token 与任何东西进行比较。我知道用于评估 post 修复的伪代码是这样的,我正在尝试基于此执行我的程序:

来自生成文件:

测试:build/infix_calculatorbuild/postfix_calculatorbuild/tokenize

./build/tokenize "2 3 4 + *"

./build/postfix_calculator "2 3 4 + *"

./build/tokenize "2 * (3 + 4)"

./build/infix_calculator "2 * (3 + 4)"


for ( each character ch in the string) 
{ 
if (ch is an operand) 
Push the value of the operand ch onto the stack
else // ch is an operator named op
 { 
// Evaluate and push the result 
 operand2 = top of stack
Pop the stack
 operand1 = top of stack
Pop the stack
 result = operand1 op operand2 
Push result onto the stack
 } 
} 

欢迎任何反馈

这里link到网上gdb亲自看:

https://onlinegdb.com/BkIkaPzBO

错误: src/PostfixCalculator.cpp:15:19: 错误:'operator>=' 不匹配(操作数类型为 '__gnu_cxx::__alloc_traitsstd::allocator::value_type {aka Token}' 和 'char') 如果(令牌[i] >= '0' && 令牌[i] <= '9' ){

src/PostfixCalculator.cpp:15:39: 错误:'operator<=' 不匹配(操作数类型为 '__gnu_cxx::__alloc_traitsstd::allocator ::value_type {又名令牌}' 和 'char') 如果(令牌[i] >= '0' && 令牌[i] <= '9' ){

src/PostfixCalculator.cpp:16:24: 错误:'operator-' 不匹配(操作数类型为 '__gnu_cxx::__alloc_traitsstd::allocator ::value_type {又名令牌}' 和 'char') s.push(代币[i] - '0');



/**
 * @file PostfixCalculator.cpp
 */
 #include "PostfixCalculator.h"
 #include<stack>
 #include<iostream>
 #include<stack>
 #include<string>


double PostfixCalculator::eval(std::vector<Token> tokens) {
  std::stack<double>s;

  for (unsigned int i = 0; i < tokens.size(); i++){
    if (tokens[i] >= '0' && tokens[i] <= '9' ){
      s.push(tokens[i] - '0');
    }
  }

  return 0;
}

/**
 * @file PostfixCalculator.h
 */
#ifndef POSTFIX_CALCULATOR_H
#define POSTFIX_CALCULATOR_H

#include<vector>

#include "EvalInterface.h"

class PostfixCalculator : public EvalInterface<double>
{
public:
    double eval(std::vector<Token> expr);
};

#endif


/**
 * @file Token.h
 */
#ifndef TOKEN_H
#define TOKEN_H
#include <iostream>

/**
 * Tag represents a categories of token types
 */
enum Tag { OPERATOR, OPERAND, LPAREN, RPAREN };

/**
 * @brief Operator represents types of binary operations
 */
enum Operator { ADD, SUBTRACT, MULTIPLY, DIVIDE };

/**
 * @brief A data structure to represent a token parsed from a string.
 */
struct Token {
    /** a numeric value -- only valid if the tag is OPERAND */
    double d;
    /** an operator type -- only valid if the tag is OPERATOR */
    Operator o;
    /** the category of the token */
    Tag tag;
};

/**
 * @brief convert an Operator to a std::string
 * @param o the operator
 * @return a string representation of the operator
 */
std::string opToString(Operator o);

/**
 * @brief An overloaded stream insertion operator for the Token type.
 * @param os the output stream object
 * @param t the Token to be inserted into the stream
 * @return the same ostream that was passed in
 */
std::ostream& operator<<(std::ostream& os, const Token& t);

/**
 * @brief parse a string representing a simple arithmetic expression
 * into sequence of tokens.
 * @param s the string to parse
 * @return the result of parsing the string into tokens
 */
std::vector<Token> tokenize(std::string s);

#endif




/**
 * @file Token.cpp
 */
#include <sstream>
#include <string>
#include <vector>
#include <stdexcept>
#include "Token.h"

std::string opToString(Operator o) {
    std::string result;
    switch(o) {
        case ADD:
            result = "ADD";
            break;
        case SUBTRACT:
            result = "SUBTRACT";
            break;
        case MULTIPLY:
            result = "MULTIPLY";
            break;
        case DIVIDE:
            result = "DIVIDE";
            break;
    }
    return result;
}

std::ostream& operator<<(std::ostream& os, const Token& t) {
    std::string type;
    switch (t.tag) {
        case OPERATOR:
            os << "OPERATOR: " << opToString(t.o) << std::endl;
            break;
        case OPERAND:
            os << "OPERAND: " << t.d << std::endl;
            break;
        case LPAREN:
            os << "LPAREN" << std::endl;
            break;
        case RPAREN:
            os << "RPAREN" << std::endl;
            break;
        default:
            throw std::logic_error("Invalid token");
            break;
    }
    return os;
}

std::vector<Token> tokenize(std::string s) {
    std::stringstream ss(s);
    std::vector<Token> result; 

    while (ss) {
        Token t;
        if (ss.peek() == ' ') {
            ss.get();
            continue;
        }
        if (isalnum(ss.peek())) {
            ss >> t.d;
            t.tag = OPERAND;
        }
        else {
            char op;
            ss >> op;
            t.d = 0;
            if (op == '(') {
                t.tag = LPAREN;
            }
            else if (op == ')') {
                t.tag = RPAREN;
            }
            else if (op == '*') {
                t.o = MULTIPLY;
                t.tag = OPERATOR;
            }
            else if (op == '/') {
                t.o = DIVIDE;
                t.tag = OPERATOR;
            }
            else if (op == '+') {
                t.o = ADD;
                t.tag = OPERATOR;
            }
            else if (op == '-') {
                t.o = SUBTRACT;
                t.tag = OPERATOR;
            }
            else {
                throw std::logic_error("Invalid token");
            }
        }
        result.push_back(t);
    }
    result.pop_back();
    return result;
}


报错明确指出问题所在:

PostfixCalculator.cpp: In member function ‘virtual double PostfixCalculator::eval(std::vector<Token>)’: PostfixCalculator.cpp:15:19: error: no match for ‘operator>=’ (operand types are ‘__gnu_cxx::__alloc_traits >::value_type {aka Token}’ and ‘char’)
     if (tokens[i] >= '0' && tokens[i] <= '9' ){
                     PostfixCalculator.cpp:15:39: error: no match for ‘operator<=’ (operand types are ‘__gnu_cxx::__alloc_traits
>::value_type {aka Token}’ and ‘char’)
     if (tokens[i] >= '0' && tokens[i] <= '9' ){
                                         PostfixCalculator.cpp:16:24: error: no match for ‘operator-’ (operand types are ‘__gnu_cxx::__alloc_traits >::value_type {aka Token}’ and ‘char’)
       s.push(tokens[i] - '0');

Token 是用户定义的数据类型,当 A 的类型为 TokenB 是一个 char。您可以在 Token class 上定义运算符 <== 来实现如下内容:

bool Token::operator==(char c) const {
    return (char)d == c;
}

bool Token::operator< (char c) const {
    return (char)d < c;
}

但是,我会要求你通过比较 doublechar 来思考你的实际意图,因为这就是你的代码似乎正在做的事情

tokens[i] >= '0'

我认为您可能需要重新考虑您的 Token class。从您共享的代码来看,它似乎是一个 wrapper 字符,附加了一些元数据来表示它的属性。在你的代码中,只有

的用法
if (isalnum(ss.peek())) {
    ss >> t.d;
    t.tag = OPERAND;
}

t.d = 0;

Tokendouble 似乎从未用完它的容量和实际用于存储更高精度的浮点数。所有存储的都是纯数字。

#include <iostream>
#include <cctype>
#include <algorithm>
#include <string>
#include <cstdint>
#include <vector>

struct Token {
    enum class Tag : uint8_t { OPERATOR, OPERAND, LPAREN, RPAREN };
    static constexpr char OPERANDS[] = {'/', '*', '+', '-'};
    explicit Token(char);
    /** a numeric value -- only valid if the tag is OPERAND */
    char unit;
    /** the category of the token */
    Tag tag;
    char operator()() const;
};

Token::Token(char c): unit(c){
    if(std::isdigit(unit)){ //Numbers are for sure operands
        tag = Tag::OPERAND;
    } else if(unit == '('){
        tag = Tag::LPAREN;
    } else if(unit == ')') {
        tag = Tag::RPAREN;
    } else if(std::any_of(std::begin(OPERANDS), std::end(OPERANDS),
        [&](char c){return c == unit;})) {
        tag = Tag::OPERATOR;
        //Then classify what's the operator if required.
    }
}

char Token::operator()() const {
    return unit;
}

int main()
{
    std::vector<Token> tokenVector;
    std::string inp = "935*+";
    for(char c: inp){
        //Weed out whatever Token doesn't support
        if(c != ' ') {
            tokenVector.emplace_back(c);
        }
    }
    for(const auto& token: tokenVector){
        std::cout<<token()<<' ';
    }
    std::cout<<'\n';
}

Output(使用C++17):

9 3 5 * + 

这只是一个简单的示例,基于实现与字符的奇偶校验的问题。

您不应该将该标记转换为字符。处理字符是标记器的工作,它已经完成了它的工作。停止考虑字符,开始考虑 OPERAND、OPERATOR、LPAREN 和 RPAREN 这些标记的种类。

你显然需要一些类似

的东西
for (auto tkn : tokens) {        // was for (unsigned int i = 0; i < tokens.size(); i++){
  if (tkn.Tag == Tag::OPERAND) { //        if (tokens[i] >= '0' && tokens[i] <= '9' ){
    s.push(tkn.d);               //            s.push(tokens[i] - '0');
  }
}