5

编译器一日一练(DIY系列之中间代码生成)

 1 year ago
source link: https://blog.csdn.net/feixiaoxing/article/details/127677493
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

编译器一日一练(DIY系列之中间代码生成)

嵌入式-老费 于 2022-11-03 20:41:00 发布 118

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        代码地址:https://github.com/feixiaoxing/DIYCompiler/blob/master/day09/Parse1.jj

        说到中间代码生成,目前来说用的比较多的一个方案就是llvm。也就是说,如果把ast语法树翻译成llvm支持的中间代码,那么后端的事情就不需要自己操心了。当然,如果开发的是商用编译器,确实可以这么做。

        但是今天我们翻译的是四则运算,所以可以做的简单一点。中间代码生成,说白了就是翻译ast。遍历到哪个节点,就翻译哪个节点。这个时候一般会出现两个问题,一个是中间变量的生成;一个是ast的递归。

        说到中间变量,主要是因为在计算的过程当中需要对中间变量进行命名。而这个中间变量原来在实际代码中是完全不存在的,是编译器本身为了自身的需要临时添加的。比如,可以这么处理,

        如上面代码所示,完全可以用tmp+index的形式来完成,这样生成的临时变量肯定不会发生重名的情况。

        解决了重命名,接下来就是处理递归代码的情况。这个时候一般是按照左、右、根的形式来进行的。即先翻译左子树的代码,再翻译右子树的代码,最后翻译根的代码,这也是符合翻译的基本逻辑。



newCodeMoreWhite.png

        上面这段代码的逻辑就是,如果有左子树,就先翻译左子树。如果右节点为空,则退出,这主要是防止只有一个数字出现的情况。接下里就是调用allocate_index,创建一个临时tmp变量,同时将这个名字赋值给节点。最后判断当前节点的类型,如果是单纯数字,则输出div 数字,数字即可;如果不是,则翻译成div 临时变量名,数字的格式。

        为了验证我们的翻译是否成功,可以测试一下,



newCodeMoreWhite.png

        如上述代码所示,分成两个部分,第一部分打印成中间代码,第二部分打印成语法树。语法树的部分上一节已经提过,这里只是将/换成了临时变量名。回过头来看中间代码生成。我们不妨看最后一个案例8/1/2/3/这个。首先,tmp1=8/1,接着就是tmp2=tmp1/2、tmp3=tmp2/3、tmp4=tmp3/1,这样就完成了所有的翻译动作。

        实际效果如何,大家最好自己跑一跑。这里贴出完成jj文件,供大家参考。



newCodeMoreWhite.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK