我决定是时候完成我一周前开始的小中缀计算器了,但在我的评估函数中遇到了问题。我的 switch 语句似乎与我通过运算符结构处理数组的方式存在问题。我不完全确定我做错了什么。这不是我遇到的唯一错误,但我确信如果我解决了这个问题,那么其他问题应该更容易解决。显然我的代码不完整,但考虑到我到目前为止所拥有的东西,我是否走在正确的轨道上?
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
bool die(const string &msg);
//stack class
class Stack{
public:
Stack();
void push(const double &val);
void push(const string &oper);
double popnum();
string popop();
double getopele();
double getnumele();
unsigned getarity(string token);
unsigned getprec(string token);
string topop();
private:
static const unsigned MAX=30;
string opstack[MAX];
double numstack[MAX];
unsigned opele;
unsigned numele;
};
//operators
bool add(double &r, double &x, double &y);
bool subtract(double &r, double &x, double &y);
bool multiply(double &r, double &x, double &y);
bool divide(double &r, double &x, double &y);
//operator type
struct OP{
string name;
void * func;
unsigned arity;
unsigned prec;
bool lass;
string descrip;
};
//operator table
OP op[]={{"+", add, 2, 4, true, "2+3 is 5"},
{"-", subtract, 2, 4, true, "2-3 is -1"},
{"*", multiply, 2, 6, true, "2*3 is 6"},
{"/", divide, 2, 6, true, "2/3 is 0.666666..., div by 0 illegal"}};
unsigned OPELE =sizeof(op)/sizeof(op[0]);
//Manip
unsigned findindex(string token);
bool parseval(double &t, const string &token);
double parseforeval(double &result, string line);
void evaluate(double &result, Stack &s);
bool weird(double x);
int main(){
for(string line; getline(cin, line);){
if(line=="QUIT") break;
if(line.empty()) continue;
if(line=="DOC")
for(unsigned i=0; i<OPELE; i++)
cout<<op[i].name<<" | "<<op[i].descrip<<'\n';
double result;
if(parseforeval(result, line)){
cout<<result<<'\n';
}else{
cout<<"Could not understand input\n\n";
}
}
}
Stack::Stack(){
opele=0;
numele=0;
}
void Stack::push(const double &val){
if(MAX) die("Stack Overflow");
numstack[numele++]=val;
}
void Stack::push(const string &oper){
if(MAX) die("Stack Overflow");
opstack[opele++]=oper;
}
double Stack::popnum(){
if(!numele) die("Stack Underflow");
return numstack[--numele];
}
string Stack::popop(){
if(!opele) die("Stack Underflow");
return opstack[--opele];
}
double Stack::getopele(){
return opele;
}
double Stack::getnumele(){
return numele;
}
unsigned Stack::getprec(string token){
unsigned i=findindex(token);
return op[i].prec;
}
unsigned Stack::getarity(string token){
unsigned i=findindex(token);
return op[i].arity;
}
string Stack::topop(){
if(!opele) die("Undeflow");
return opstack[opele-1];
}
double parsforeval(double &result, string line){
istringstream sin(line);
Stack s;
for(string token; sin>>token;){
double t;
if(parseval(t, token)){
s.push(t);
}else if(token=="("){
s.push(parsforeval(result, line));
}else if(s.getprec(s.topop()) >s.getprec(token)){
//write eval function
s.push(token);
}else if(token== ")"){
if(!s.getnumele()) die("Bad format");
return s.popnum();
}else{
s.push(token);
}
}
while(s.getopele()){
evaluate(result, s);
}
}
void evaluate(double &result, Stack &s){
unsigned i= findindex(s.popop());
switch(op[i].arity){
case 1:
if(s.getnumele()<1) die("Underflow");
double x = s.popnum();
if( !reinterpret_cast<bool (*)(double &, double &)> !op[i].func (result, x) ) die("No OP");
break;
case 2:
if(s.getnumele()<2) die("Underflow");
double y = s.popnum();
double x = s.popnum();
if( !reinterpret_cast<bool (*)(double &, double &,double &)> op[i].func (result, x, y) ) die("No OP");
break;
case 3:
if(s.getnumele()<3) die("Underflow");
double z = s.popnum();
double y = s.popnum();
double x = s.popnum();
if( !reinterpret_cast<bool (*)(double &, double & , double & , double &)>op[i].func (result, x, y, z) ) die("No OP");
break;
default:
die("uuuuuuhhhh i have no idea");
break;
}
s.push(result);
}
bool add(double &r, double &x, double &y){
double t = x + y;
if( weird(t) ) return false;
r = t;
return true;
}
bool subtract(double &r, double &x, double &y){
double t = x - y;
if( weird(t) ) return false;
r = t;
return true;
}
bool multiply( double & r, double& x, double &y ){
double t = x * y;
if( weird(t) ) return false;
r = t;
return true;
}
bool divide( double & result, double &x, double &y ){
double t = x / y;
if( weird(t) ) return false;
result = t;
return true;
}
unsigned findindex(string token){
for(unsigned i=0; i<OPELE; i++)
if(op[i].name==token)
return i;
return UINT_MAX;
}
bool parseval(double &val, const string &token){
istringstream sin( token );
double t;
if( !(sin >>t) ) return false;
char junk;
if( sin >>junk ) return false;
val = t;
return true;
}
bool weird( double x ){
return x != x || x != 0 && x == 2*x;
}
bool die(const string &msg){
cout<<"Error: "<<msg;
exit(EXIT_FAILURE);
}