如何在中缀计算器语法中解析和评估表达式?我想到了两种方法。中缀计算器表达式解析器
第一个涉及使用两个堆栈。一个用于数字,另一个用于运营商,我会评估运营商的优先级和关联性,以便找出如何评估表达式。
第二种方法涉及将中缀表达式转换为后缀,我不知道该怎么做。这只是一个想法。目前,我设置了我的程序,目的是使用第一种方法。
#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();
private:
static const unsigned MAX=30;
string opstack[MAX];
double numstack[MAX];
unsigned opele;
unsigned numele;
};
//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]);
//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);
//Manip
unsigned findindex(string token, OP op[], unsigned OPELE);
bool parse(double &t, const string &token);
bool evaluate(double &result, string line);
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(evaluate(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;
}
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;
result = t;
return true;
}
bool multiply(double & r, double& x, double &y){
double t = x * y;
if(weird(t)) return false;
result = 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, OP op[], unsigned OPELE){
for(unsigned i=0l i<OPELE; i++)
if(op[i].name==token)
return i;
return UINT_MAX;
}
bool parse(double &t, const string &token){
istringstream sin(token);
double t;
if(!(sin >>t)) return false;
char junk;
if(sin >>junk) return false;
value = t;
return true;
}
bool evaluate(double &result, string line){
istringstream sin(line);
Stack s;
for(string token; sin>>token;){
double t;
if(parse(t, token)){
s.push(t);
}else if(
}
}
bool weird(double x){
return x != x || x != 0 && x == 2*x;
}
你可能有兴趣在[调度场算法(http://en.wikipedia.org/wiki/Shunting-yard_algorithm)到中缀转换表达式到后缀,或[自顶向下运算符优先解析](http://effbot.org/zone/tdop-index.htm)与Pratt解析器。 –
你也可以看看[GNU Bison](http://www.gnu.org/software/bison/)及其文档。本教程将教你很多关于LALR解析器的知识。 –