第1关:赋值语句的三地址代码产生
引言
在编译原理中,三地址代码(Three-Address Code, TAC)是一种常见的中间代码形式,用于桥接源语言与目标机器代码之间的转换。本文以“赋值语句三地址代码产生”为例,介绍如何在递归下降解析的框架下,基于属性文法插入语义动作,生成正确的三地址代码,并给出完整的修正后代码,方便大家参考。
问题描述
给定一个简单的赋值语句文法:
<赋值语句> ::= <标识符> := <表达式>
<表达式> ::= [+|-]<项>{<加法运算符><项>}
<项> ::= <因子>{<乘法运算符><因子>}
<因子> ::= <标识符> | <无符号整数> | '(' <表达式> ')'
要求在原有的递归下降分析框架中,补充属性和动作代码,输出形如以下格式的三地址代码:
T1:=c*d
T2:=b+T1
a:=T2
- “减法同加法,除法同乘法”
- 临时变量通过
newTemp()生成 - 在完成
expression、item、factor函数逻辑后,综合属性E_val、T_val、F_val保存子树计算结果或中间临时变量
原始框架代码未包含 treeNode 类型定义,导致编译期 “treeNode 未定义” 和“不完整类型”错误。此外,三地址码生成逻辑需插入到恰当位置,并用注释标注以便维护。
解决思路
- 补充
treeNode定义
在函数原型之前添加完整的treeNode类定义,保证解析树节点操作可用。 - 引入综合属性
声明全局字符串变量E_val、T_val、F_val,分别对应表达式、项、因子的计算结果或临时变量名。 - 插入语义动作
- 在
factor函数中,将标识符或数字赋值给F_val; - 在
item函数循环中,每次乘除运算后生成临时变量并输出对应三地址码,更新T_val; - 在
expression函数中,处理一元加减、二元加减,生成相应的三地址码并更新E_val; - 在
assi_sen函数末尾,输出最终的赋值三地址码:变量 := E_val。
- 在
- 严格保留框架代码
原有注释和逻辑结构不作任何修改,仅在允许位置新增代码,并用// === 新增 ... ===标注。
运行示例
假设输入文件 demo.txt 内容为:
a:=b+c*d;
运行输出:
T1:=c*d
T2:=b+T1
a:=T2
总结
本文演示了如何在已有递归下降分析框架中,通过补充属性和语义动作,生成赋值语句的三地址代码。同时,保留了原框架代码和注释,仅在允许位置新增代码,并用 // === 新增...=== 标注,确保可读性与可维护性。读者可直接参考此示例,将类似方法推广到更复杂的语法和中间代码生成场景中。
提示:登录后即可查看修正后完整代码。