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
的类型为 Token
且 B
是一个 char
。您可以在 Token class 上定义运算符 <
和 ==
来实现如下内容:
bool Token::operator==(char c) const {
return (char)d == c;
}
bool Token::operator< (char c) const {
return (char)d < c;
}
但是,我会要求你通过比较 double
和 char
来思考你的实际意图,因为这就是你的代码似乎正在做的事情
tokens[i] >= '0'
我认为您可能需要重新考虑您的 Token
class。从您共享的代码来看,它似乎是一个 wrapper 字符,附加了一些元数据来表示它的属性。在你的代码中,只有
的用法
if (isalnum(ss.peek())) {
ss >> t.d;
t.tag = OPERAND;
}
和
t.d = 0;
Token
的 double
似乎从未用完它的容量和实际用于存储更高精度的浮点数。所有存储的都是纯数字。
#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');
}
}
我的任务是创建一个 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
src/PostfixCalculator.cpp:15:39: 错误:'operator<=' 不匹配(操作数类型为 '__gnu_cxx::__alloc_traitsstd::allocator
src/PostfixCalculator.cpp:16:24: 错误:'operator-' 不匹配(操作数类型为 '__gnu_cxx::__alloc_traitsstd::allocator
/**
* @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
的类型为 Token
且 B
是一个 char
。您可以在 Token class 上定义运算符 <
和 ==
来实现如下内容:
bool Token::operator==(char c) const {
return (char)d == c;
}
bool Token::operator< (char c) const {
return (char)d < c;
}
但是,我会要求你通过比较 double
和 char
来思考你的实际意图,因为这就是你的代码似乎正在做的事情
tokens[i] >= '0'
我认为您可能需要重新考虑您的 Token
class。从您共享的代码来看,它似乎是一个 wrapper 字符,附加了一些元数据来表示它的属性。在你的代码中,只有
if (isalnum(ss.peek())) {
ss >> t.d;
t.tag = OPERAND;
}
和
t.d = 0;
Token
的 double
似乎从未用完它的容量和实际用于存储更高精度的浮点数。所有存储的都是纯数字。
#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');
}
}