我有一个简单的操作:
k + 1
它的红外树表示是什么?
到目前为止,我提出了:
BINOP(+, MEM(NAME(k)), CONST(1))
但我不确定我是否需要为NAME提供MEM。欢迎任何帮助。
我们使用的符号与此PDF格式完全相同: http://www.computing.dcu.ie/~hamilton/teaching/CA449/notes/translate.pdf
答案 0 :(得分:2)
嗯,这实际上取决于您的IR表示方式。另外,作为pointed out的mrjoltcola,你所建议的看起来更像是一个AST(抽象语法树)。 AST是更高级别的,并且通常是直接从源生成的树结构。 IR通常更简单,更低级(代码通常表示为简单指令列表,而不是表达式树)。 AST通常对编译器具有高度特异性。 IR通常与编译器和/或语言无关(参见例如LLVM)。
如果您打算用文字表示,我认为
+(k,1)
会更简单,因为无论如何你都需要一个相当复杂的词法分析器/解析器,这对于人类来说会更具可读性(虽然计算机的可读性稍差)。没有必要使用MEM
或NAME
之类的东西,因为在这种情况下,标识符显然是一个变量访问(它确实依赖于编译器的语言和结构)。我绝对不会使用BINOP
这样的东西,因为它实际上只会使代码复杂化(你仍然需要与其他二进制操作分开处理)。
如果您只是将其保留在内存中,则取决于语言。在Haskell中,我会做这样的事情:
data Expr = Const Int | Variable String | Add Expr Expr | ...
然后你的例子就是:
Add (Variable "k") (Const 1)
在C ++ / C#/ Java中,您可能会使用类来模拟代数数据类型。
例如,在粗略的C ++中 - ish伪代码:
class Expr {};
class Const : Expr {int v; Const(int v) : v(v) {}};
class Variable : Expr {string n; Variable(string n) : n(n) {}};
class Add : Expr {Expr a, b; Add(Expr a, Expr b) : a(a), b(b) {}};
...
Add(Variable("k"), Const(1))
答案 1 :(得分:1)
我唯一能做的就是阅读他的IR树语言的作者(Appel)规则。
语法:
<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,name用于代码标签。
基于读取他的猜测是,如果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树,(我总是写一个文本的中级语言,汇编程序支持声明不同范围的变量,以及象征临时变量)我不能肯定他的意思,所以我建议你的教授确认因为他之前可能已经教过这本书,可能会更好地了解它。
希望有所帮助。