我唯一能做的就是阅读作者 (Appel) 的 IR 树语言规则。
对于语法:
<ADDEXPR> ::= <EXPR> + <EXPR>
<EXPR> ::= IDENTIFIER
| LITERAL
AST 树可能是:
BINOPEXPR(+, EXPR(IDENTIFIER(k)), EXPR(LITERAL(1)))
或者可能包括 IdentifierExpression 和 LiteralExpression,所以它可能是:
BINOPEXPR(+, IDENT_EXPR(k), LITERAL_EXPR(1))
但是 AST 和 IR 树是不同的东西。所以根据 Appel 的书,在 C 版本的第 7.1 节中:
NAME(n) = Sumbolic 常数 n 对应于一个汇编语言标签。
MEM(e) = 从地址 e 开始的 wordSize 字节的内存内容。当 MEM() 用作 MOVE() 的左孩子时,它表示“存储”,但在其他任何地方都表示“获取”。
LABEL(n) = 将名称 n 的常量值定义为当前机器代码地址。这就像汇编语言中的标签定义。值 NAME(n) 可能是跳转、调用等的目标。
根据他的规则,NAME() 不是您想要的变量 k,名称用于代码标签。
根据他的阅读我的猜测是如果 k 是一个变量,在这种情况下它是一个 r 值,那么你可以简单地使用 MEM(e) 但 e 可以是一个局部变量(在局部堆栈帧中) ,或全局变量,甚至是临时变量。所以“k + 1”的翻译将取决于“k”的分配位置。如果它在本地栈帧中,那么 k 是:
MEM(BINOP(+, TEMP fp, CONST (address of k)))
所以 k + 1 将是:
BINOP(+, MEM(BINOP(+, TEMP fp, CONST (address of k))), 1)
因此,您需要清楚如何为变量分配存储空间。这将在标识符的符号表中。
我至少有 20 本编译器书籍,老实说,我发现 Appel 的书籍令人困惑,而且在某些方面过于简短。他做出了学生不遵循的概念飞跃,并且可以在某些地方使用更多的细节。因为我从来没有真正实现过 IR 树,(我总是写一个文本中间语言,它支持声明不同范围的变量和符号临时变量)我不能确定他的意思,所以我建议与你的教授确认因为他可能以前用这本书教过,并且可能更了解它。
希望对您有所帮助。