又一种求四则运算的好方法
LLVM toylanguage真的是一个非常好的学习资料。
#include <iostream>
#include <stdio.h>
#include <queue>
#include <algorithm>
#include <map>
#include <string>
#include <assert.h>
#include <memory>
using namespace std;
class ExprAst {
public:
virtual void update()=0;
virtual double getvalue()=0;
virtual ~ExprAst() = default;
};
// 单个数字节点
class NumExprAst : public ExprAst {
private:
double value;
public:
NumExprAst(double value) : value(value) {}
double getvalue() override;
void update() override;
};
double NumExprAst::getvalue() {
return value;
}
void NumExprAst::update() {
}
// 二元运算符节点
class BinaryExprAst : public ExprAst {
private:
unique_ptr<ExprAst> left;
unique_ptr<ExprAst> right;
char op;
double value;
public:
BinaryExprAst(char op, unique_ptr<ExprAst> left, unique_ptr<ExprAst> right) : op(op), left(move(left)),
right(move(right)), value(0) {}
void update() override;
double getvalue() override;
};
double BinaryExprAst::getvalue() {
return value;
}
void BinaryExprAst::update() {
switch (op) {
case '+':
value = left->getvalue() + right->getvalue();
break;
case '-':
value = left->getvalue() - right->getvalue();
break;
case '*':
value = left->getvalue() * right->getvalue();
break;
case '/':
value = left->getvalue() / right->getvalue();
default:
break;
}
cout << value << "=" << left->getvalue() << op << right->getvalue() << endl;
}
// 定义token
// token 分为四种
// 数字 , '(', ')', 运算符
class Token {
public:
Token(char ch) : kind(ch), value(0) {}
Token(char ch, double value) : kind(ch), value(value) {}
Token() : kind(0), value(0) {}
char kind;
double value;
};
static Token gettoken() {
char ch;
cin >> ch;
if (isdigit(ch)) {
cin.putback(ch);
double val;
cin >> val;
return {0, val};
}
return {ch};
}
static Token curtoken;
static map<char, int> precedentmap;
static Token getnexttoken() {
return curtoken = gettoken();
}
static int getprecedent(char ch) {
if (precedentmap.find(ch) != precedentmap.end()) {
return precedentmap[ch];
}
return -1;
}
static unique_ptr<ExprAst> parseexp();
static unique_ptr<ExprAst> parseparen() {
getnexttoken(); // eat the '(';
auto v = parseexp();
assert(curtoken.kind == ')');
getnexttoken();
return v;
}
static unique_ptr<ExprAst> parseprimary() {
if (curtoken.kind == '(')
return parseparen();
else {
auto res = make_unique<NumExprAst>(curtoken.value);
getnexttoken();
return move(res);
}
}
/**
* ( op, exp)
* @param ExprPre 操作符号的优先级
* @param LHS 右表达式
* @return
*/
static unique_ptr<ExprAst> parseBinopRHS(int ExprPre, unique_ptr<ExprAst> LHS) {
while (true) {
int curpre = getprecedent(curtoken.kind);
if (ExprPre > curpre)
return LHS;
// consume the op
char binop = curtoken.kind;
getnexttoken();
// get the next primary
auto RHS = parseprimary();
int nextopPre = getprecedent(curtoken.kind);
if (nextopPre > curpre) {
RHS = parseBinopRHS(curpre + 1, move(RHS));
}
// merge the LHS and RHS
// and update the value
LHS = make_unique<BinaryExprAst>(binop, move(LHS), move(RHS));
// update the value
LHS->update();
}
}
static unique_ptr<ExprAst> parseexp() {
// 首先先解析一个数字或者括号表达式
auto LHS = parseprimary();
auto res = parseBinopRHS(0, move(LHS));
return res;
}
void MainLoop(){
while (!cin.eof()){
switch (curtoken.kind){
case 'q':
return;
case ';':
getnexttoken();
break;
default:
parseexp();
cout<<"========================"<<endl;
break;
}
}
}
int main() {
freopen("../in.txt", "r", stdin);
precedentmap['+'] = 10;
precedentmap['-'] = 10;
precedentmap['*'] = 20;
precedentmap['/'] = 20;
getnexttoken();
MainLoop();
}