Compiler construction 在类似于编译器的方案中创建闭包
我正在实现一个类似lisp的方案,它将在某个时刻被编译成某种形式的字节码,可以看到。不幸的是,我把自己编码成了一个小洞,不知道如何走出这个洞。本质上,给定一个看起来像这样的lambda(外部b是故意不使用的): 我的代码生成以下语法树:Compiler construction 在类似于编译器的方案中创建闭包,compiler-construction,elixir,Compiler Construction,Elixir,我正在实现一个类似lisp的方案,它将在某个时刻被编译成某种形式的字节码,可以看到。不幸的是,我把自己编码成了一个小洞,不知道如何走出这个洞。本质上,给定一个看起来像这样的lambda(外部b是故意不使用的): 我的代码生成以下语法树: [ type: :lambda, args: [[type: :word, val: 'a'], [type: :word, val: 'b']], body: [ [ type: :lambda, args: [[t
[
type: :lambda,
args: [[type: :word, val: 'a'], [type: :word, val: 'b']],
body: [
[
type: :lambda,
args: [[type: :word, val: 'c']],
body: [
[
type: :expr,
val: [
[type: :word, val: '+'],
[type: :word, val: 'a'],
[type: :word, val: 'c']
]
]
]
]
]
]
不幸的是,当我真正开始生成字节码时,创建这些lambda所需的闭包并不容易(据我所知)。理想情况下,我希望生成一棵如下所示的树:
[
type: :lambda,
args: [[type: :word, val: 'a'], [type: :word, val: 'b']],
closure: [],
body: [
[
type: :lambda,
args: [[type: :word, val: 'c']],
closure: [[type: :word, val: 'a']],
body: [
[
type: :expr,
val: [
[type: :word, val: '+'],
[type: :word, val: 'a'],
[type: :word, val: 'c']
]
]
]
]
]
]
但是,通过查看给定参数是否显示在env中,很容易判断它是否应该是闭包的一部分,因为我只是通过调用
Enum.map
,我不确定如何将该信息返回到lambda对象。我不需要特定的代码来解决这个问题,但是一个通用的指导方针/提示/向正确的方向推进会很好(我知道这有点模糊,但我不太确定如何为这个问题创建更具体的测试用例) 您可以遍历AST,在每个节点上构建绑定标识符列表
例如,lambda
节点绑定其参数(如果这些名称已经在绑定列表中,请随意重写),以及let
和let*
。在返回此树时,还可以为每个AST节点构建一个引用的空闲标识符列表
lambda
,let
和let*
从这些自由变量列表中删除标识符
剩下的很简单:在每个lambda
节点上,计算引用列表和绑定列表之间的交集,结果将是这个闭包必须捕获的环境。如果为空,则这是一个没有环境的简单函数
在您的示例中,它将是:
[b:()f:()](lambda(ab)[b:(ab)f:(a)](lambda(c)[b:(ab)f:(ac)](+ac)))
如您所见,内部lambda在其b:
和f:
列表之间有a
的共同点,因此您必须在这里发出闭包分配指令,构建一个元素a
的环境
您可以将此过程与变量重命名相结合(例如,将lambda参数名称转换为参数编号)。您可以在AST中遍历,在每个节点上构建绑定标识符列表 例如,
lambda
节点绑定其参数(如果这些名称已经在绑定列表中,请随意重写),以及let
和let*
。在返回此树时,还可以为每个AST节点构建一个引用的空闲标识符列表
lambda
,let
和let*
从这些自由变量列表中删除标识符
剩下的很简单:在每个lambda
节点上,计算引用列表和绑定列表之间的交集,结果将是这个闭包必须捕获的环境。如果为空,则这是一个没有环境的简单函数
在您的示例中,它将是:
[b:()f:()](lambda(ab)[b:(ab)f:(a)](lambda(c)[b:(ab)f:(ac)](+ac)))
如您所见,内部lambda在其b:
和f:
列表之间有a
的共同点,因此您必须在这里发出闭包分配指令,构建一个元素a
的环境
您可以将此过程与变量重命名相结合(例如,将lambda参数名称转换为参数编号)。您可能需要查看。您可能需要查看。
[
type: :lambda,
args: [[type: :word, val: 'a'], [type: :word, val: 'b']],
closure: [],
body: [
[
type: :lambda,
args: [[type: :word, val: 'c']],
closure: [[type: :word, val: 'a']],
body: [
[
type: :expr,
val: [
[type: :word, val: '+'],
[type: :word, val: 'a'],
[type: :word, val: 'c']
]
]
]
]
]
]