【编译原理】实现一个计算器

实现一个计算器,包括加减,乘除,括号,错误提示,id等,相当于一个小型的解释器。

其中重要的思想是

  • 把字符转换成token
  • 递归解析
//编译原理实现计算器
#include<bits/stdc++.h>
using namespace std;
//int factor(const char **) throw();

enum { //枚举:第一个元素=0,第二个就为1,依次类推
    TOKEN_UNKNOWN = 0,
    TOKEN_DIGITS,
    TOKEN_ADD,
    TOKEN_SUB,
    TOKEN_MUL,
    TOKEN_DIV,
    TOKEN_MOD,
    TOKEN_OPEN, 
    TOKEN_CLOSE, 
    TOKEN_SEMI,
    TOKEN_EQUA,
    TOKEN_ID,
};

struct Token {
    int type;
    int value;
    string id;
};

struct Exp {
    char *exps;
    Token t;
    map<string, int> m;  //存参数
} e;

    
class ed:public exception {
public:
    const char* what() const throw() {
        return "ERROR_TYPE_EXPECT_DIGIT";
    }    
};

class ecp:public exception {
public:
    const char* what() const throw() {
        return "ERROR_TYPE_EXPECT_CLOSE_PARENTHESIS";
    }    
};

class dbz:public exception {
public:
    const char* what() const throw() {
        return "ERROR_TYPE_DIVISION_BY_ZERO";
    }    
};

class rbz:public exception {
public:
    const char* what() const throw() {
        return "ERROR_TYPE_REMAINDER_BY_ZERO";
    }    
};

class un:public exception {
public:
    const char* what() const throw() {
        return "ERROR_TYPE_UNKNOWN";
    }    
};
/*
本代码的next函数虽然名为next,但是主要功能还是只有判断token,没有地址++
*/
void next(Exp *e) { //一边扫一边解析就可以 
    while (*(e->exps) == ' ') { //空格则忽略 
        (e->exps)++; 
    }
    char c = *(e->exps);
    if (isdigit(c)) {
        e->t.type = TOKEN_DIGITS;
        e->t.value = c - '0';
        while (isdigit(*(++(e->exps)))) {
            e->t.value = ( e->t.value ) * 10 + (*(e->exps) - '0');
        }
        (e->exps)--;
    }
    else if (isalpha(c) || c == '_') {
        string s;
        s.push_back(c);
        cout << s << endl;
        char *ch = ++(e->exps);
        while (isalpha(*ch) || isdigit(*ch) || *ch == '_') { //不能直接++(e->exps),会加三次
            s.push_back(*(e->exps));
            cout << "string=" << s << endl;
            ch = ++(e->exps);
        }
        (e->exps)--;
        e->t.id = s; //当前id
        e->t.type = TOKEN_ID;
        //cout << "first:id = " << e->t.id << " other:" << e->t.value <<" " <<  e->t.type << endl;
        if (e->m.find(s) == e->m.end()) {
            e->m[s] = 0; //默认值为0;
            //e->t.value = INT_MAX; //value = 0 代表以前未出现过,但是不能这样
            cout << "firstid = " << e->t.id << " value=:" << e->t.value <<" type=" <<  e->t.type << endl;
        }
        else {
            e->t.value = e->m[s];
            cout << "secondid="<<e->t.id << "value= " << e->t.value <<" type=" <<  e->t.type << endl;
        }
    }
    else if (c == '+') {
        e->t.type = TOKEN_ADD;
    }
    else if (c == '-') {
        e->t.type = TOKEN_SUB;
    }
    else if (c == '*') {
        e->t.type = TOKEN_MUL;
    }
    else if (c == '/') {
        e->t.type = TOKEN_DIV;
    }
    else if (c == '%') {
        e->t.type = TOKEN_MOD;
    }
    else if (c == '(') {
        e->t.type = TOKEN_OPEN;
    }
    else if (c == ')') {
        e->t.type = TOKEN_CLOSE;
    }
    else if (c == ';') {
        e->t.type = TOKEN_SEMI;
    }
    else if (c == '=') {
        e->t.type = TOKEN_EQUA;
    }
    /*不能有这一步,因为会使enter键变成unknown
    else {
        e->t.type = TOKEN_UNKNOWN; 
        throw un();
    }*/
}

int expstr(Exp *e);
int expst(Exp *e);

/*
  简单加法减法 
  expstr => num expstr1
  expstr1 => '+' expstr | '-' expstr | null => '+' num expstr1 | '-' num expstr1 | null
  即while循环 
  简单乘除法
  明白为什么要使用指针的指针了, 因为expstr,term,num都要c++
  重要:将++放到number里 ,更加方便
  小括号即最高优先级 
  错误处理 
*/

int number(Exp *e) {
    if(e->t.type != TOKEN_DIGITS) throw ed();
    else {
        int ans = e->t.value;
        (e->exps)++;
        return ans;
    }
}

int factor(Exp *e) {
    next(e);
    int ans;
    if (e->t.type == TOKEN_OPEN) {
        (e->exps)++;
        ans = expst(e);
        if (e->t.type == TOKEN_CLOSE) {
            (e->exps)++;
        }
        else if (e->t.type != TOKEN_CLOSE) throw ecp();
    }
    else if (e->t.type == TOKEN_ID) {
        string s = e->t.id; 
        ans = e->m[s];
        cout << "canshu" << s << ans << endl;
        (e->exps)++;
    }
    else ans = number(e);
    return ans;
}

int term(Exp *e) { //乘除法 
    int ans = factor(e); //字符转换 
    next(e);
    while(e->t.type == TOKEN_MUL || e->t.type == TOKEN_DIV || e->t.type == TOKEN_MOD) { //循环而非递归 
        if (e->t.type == TOKEN_MUL) {
            (e->exps)++;
            ans *= factor(e);
        }
        else if (e->t.type == TOKEN_DIV) {
            (e->exps)++;
            int f = factor(e);
            if (f == 0) throw dbz();
            else ans /= f;
        }
        else if (e->t.type == TOKEN_MOD) {
            (e->exps)++;
            ans %= factor(e);
            int f = factor(e);
            if (f == 0) throw rbz();
            else ans %= f;
        }
    } 
    return ans;
}

int expstr(Exp *e) { //优先级最低的加减法 ,将所有的number()变成term() 
    int ans = term(e); //字符转换 
    next(e);
    while(e->t.type == TOKEN_ADD || e->t.type == TOKEN_SUB) { //循环而非递归 
        if (e->t.type == TOKEN_ADD) {
            (e->exps)++;
            ans += term(e);
        }
        else if (e->t.type == TOKEN_SUB) {
            (e->exps)++;
            ans -= term(e);
        }
    }
    return ans;
}

int expst (Exp *e) {
    int ans;
    next(e);
    if (e->t.type == TOKEN_ID) {
        string str = e->t.id; 
        cout << "here str" << str << endl;
        (e->exps)++;
        next(e);
        //cout << "ok1" << endl;
        if (e->t.type == TOKEN_EQUA) {
            //cout << "ok2" << endl;
            (e->exps)++;
            e->m[str]= expstr(e); 
            cout << "e->m[s]:" << e->m[str] << endl;
            ans = e->m[str];
        }
        
    }
    else {
        ans = expstr(e);
    }
    return ans;
}

int exp(Exp *e) {
    int ans = expst(e);
    next(e);
    while(e->t.type == TOKEN_SEMI) {
        cout << "OK" << endl;
        (e->exps)++;
        ans = expst(e);
        next(e);
    }
    return ans;
}

int main() {
    char s[100];
    gets(s);
    e.exps = s;
    try {
        printf("%d\n", exp(&e));
    }catch(ecp &m) {
        printf("%s\n", m.what());
    }catch(ed &m) {
        printf("%s\n", m.what());
    }catch(dbz &m) {
        printf("%s\n", m.what());
    }catch(rbz &m) {
        printf("%s\n", m.what());
    }/*catch(un &m) {
        printf("%s\n", m.what());
    }*/catch(...){
        printf("Unkown exception caught!\n");
    }
    return 0;
} 

参考教程:

https://blog.harrisonxi.com/2019/07/编译原理入门课:(前言)实现一个表达式解析计算器.html

https://lotabout.me/2015/write-a-C-interpreter-0/

 

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值