c++Postfix Notation Evaluator使用堆栈

c++ Postfix-Notation Evaluator using stacks

本文关键字:堆栈 Evaluator Notation c++Postfix      更新时间:2024-05-09

我的任务是创建一个后缀计算器,但问题是我无法将Token与任何东西进行比较。我知道评估修复后的伪代码是这样的,我正试图基于它来做我的程序:

来自生成文件:

测试:build/inifx_calculator build/postfix_calculator build/tokenize

/构建/标记化";2 3 4+*";

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

/构建/标记化";2*(3+4(〃;

/build/inifx_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
} 
} 

感谢任何反馈

下面是在线gdb的链接,可以亲自查看:

https://onlinegdb.com/BkIkaPzBO

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

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

src/PostfixCalculator.cpp:16:24:错误:"operator-"不匹配(操作数类型为"__gnu_cxx::__alloc_traitsstd::allocator<Token>:value_type{aka Token}"answers"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;
}

您不应该将该令牌转换为字符。处理字符是标记化器的工作,它已经完成了它的工作。停止思考字符,开始思考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');
}
}

错误清楚地说明了问题:

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是类型TokenBchar时,编译器需要知道如何处理表达式A >= B。您可以在Token类上定义运算符<==,以实现以下目的:

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课程。从您共享的代码来看,它似乎是字符上的包装器,并附加了一些元数据来表示其属性。在你的代码中,只有的使用

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';
}

输出(使用C++17(:

9 3 5 * + 

这只是一个基于与字符实现奇偶性问题的简单例子。