编译原理学习笔记(二)翻译程序的实现

上一节所学的主要是语法到语义的内容,通过手动构造语法树来理解编译过程。
在3.5节,书中给出了后缀表达式翻译程序的java实现。根据前面的内容,今天对NC代码编译给出简易的实现。

在实现前,需要几个准备内容用以简化代码:
1. 正则表达式
正则表达式能够对一个字符串进行模式匹配,可以对符合模式的字符串进行检索、替换。
2. 宏
c++中使用宏可以对代码进行批量预处理,对于某些重复的代码可以用宏进行代替。
3. 哈希表

在得到一行代码后,需要对其词法单元进行读入,书中使用的是一个单字符lookahead。这里也使用lookahead,但是每次读入的一个字符串,因为NC代码每个部分都是空格隔开的。
对于每个字符串(即词法单元),都要进行模式判断检查语法是否正确(match),这里需要用到正则表达式,然后用对应的函数进行处理,处理对象过多且代码单一则需要用到宏。
在书中提到,抽象语法树的结点是程序,对应于分析树的非终结符。即是说每个非终结符对应一个函数,用以执行对应的内容。

词法匹配部分如下:


class regs{
    map<string, regex> mesh;
    smatch m;
    string temp;
public:
    regs(string file){//从文件读正则表达式
        ifstream fin(file);
        string str1,str2;
        while (!fin.eof()){
            fin >> str1 >> str2;
            mesh[str1] = regex(str2);
        }
    }
    int match(string pat,string str){//用非终结符pat代表的结构匹配str
        temp = str;//必须用temp暂存str 否则会丢失匹配信息
        if (mesh.find(pat)!=mesh.end()){
            auto pp = mesh[pat];
            if (!regex_match(temp, pp))return -1;
            regex_search(temp, m, pp);
            if (m.size() >= 0){
                return m.position();
            }
        }
        return -1;
    }
    string match_result(){//获取上次匹配的结果(仅限有分组)
        return m[1].str();//*!这里需要扩展
    }
};

这个类的使用方法是,构造时传入文件名,文件中内容是非终结符和其模式的正则表达式。它以非终结符名作为关键字、正则表达式作为值,构造一个哈希表,用以查询。

翻译器主体如下:


class NCpaser{//手工编写
    string cur;
    regs pattern;
    char code_type;
    string lookahead;
public:
    NCpaser():pattern("NC\\regs.txt"){//初始化哈希表
        ;
    }
    //非终结符列表:stmt id G X Y Z M S T F 
    void _stmt(){//检验基本语法
        if (pattern.match("stmt", cur)>=0){
            cur = pattern.match_result();
        }
        else{
            ;//报错
        }
        string temp = cur;
        istringstream strin(temp);
        while (strin >> lookahead){
#define stmt_pat(s)if (pattern.match(#s, lookahead) >= 0){\
                cur = pattern.match_result();\
                _##s();\
            }
            stmt_pat(G)else
            stmt_pat(M)else
            stmt_pat(X)else
            stmt_pat(Y)else
            stmt_pat(Z)else
            stmt_pat(S)else
            stmt_pat(T)else
            stmt_pat(F)

        }

    }
    void _N(){
        ;
    }
    void _G(){
        cout << "执行G指令" << cur << endl;
    }
    void _M(){
        cout << "执行M指令" << cur << endl;
    }
    void _X(){
        cout << "X轴方向" << cur << endl;
    }
    void _Y(){
        cout << "Y轴方向" << cur << endl;
    }
    void _Z(){
        cout << "Z轴方向" << cur << endl;
    }
    void _S(){
        cout << "主轴转速:" << cur << endl;
    }
    void _T(){
        cout << "刀号:" << cur << endl;
    }
    void _F(){
        cout << "进给量:" << cur << endl;
    }


    void compile(string filename){
        ifstream fin(filename);

        //预处理,暂空

        char buf[512];
        ;//按行读取
        while (fin.getline(buf, 512)){
            cur = string(buf);
            _stmt();
        }

    }

};

正则表达式文件regs.txt内容:
stmt N[0-9]+(.*);
N N([0-9]+)
G G([0-9]+)
M M([0-9]+)
T T([0-9]+)
F F([0-9]+)
S S([0-9]+)
X X([+-]?[0-9]+)
Y Y([+-]?[0-9]+)
Z Z([+-]?[0-9]+)

输入code.txt文件内容:
N001 G01 X-100 Y20 Z+35 M03 S40 T50 F40;
N002 G01 X35 Y-29 Z30 M03 S40 T50 F40;
运行结果:
这里写图片描述

总结:这个简易程序主要给出了简单NC语法的翻译,而且在某种意义上并没有实现上一节构造的语法树,因为这里使用了regex库作为辅助。这里的语义动作是输出显示,相当于直接运行代码。事实上代码必须经过语法检验,像之前一篇文章中提到的(http://blog.csdn.net/u011602557/article/details/66979730),指令间存在互斥性,也没有表现出这个语法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值