转化Lisp语言到C++
我正在编译为基于口齿不清C++(方案的非常小的子集),我试图找出如何代表我们表达一个玩具语言,转化Lisp语言到C++
(let ((var 10)
(test 12))
(+ 1 1)
var)
在第一我认为执行所有的exprs然后返回最后一个,但是返回会杀死我嵌套让表达式的能力,那么代表let的方式是什么?
此外,源到源转换中的任何资源都是appriciated,我已经google了,但我所能做的只是90分钟的方案编译器。
一种方法是把它当作一个lambda
:
((lambda (var test) (+ 1 1) var) 10 12)
然后,变换这一个功能,并在C对应的呼叫++:
int lambda_1(int var, int test) {
1 + 1;
return var;
}
lambda_1(10, 12);
所以,在更大范围内:
(display (let ((var 10)
(test 12))
(+ 1 1)
var))
变成
display(lambda_1(10, 12));
还有很多更多的细节,例如需要从let
之内访问let
以外的词汇变量。由于C++没有词汇嵌套函数(例如,与Pascal不同),所以这需要额外的实现。
如果您正在寻找工具来帮助进行源代码翻译,我推荐使用ANTLR。这是最好的。但是,您需要考虑如何从松散类型的语言(lisp)转换为松散类型的语言(c)。例如,在你的问题中,10
的类型是什么? A short
?一个int
? A double
?扩大let
我有我自己的对象系统10是一个int在c + +我知道它是什么在运行时 – 2011-04-11 19:52:20
我会尝试解释一个简单的方法来编译嵌套的 lambda
s。由于扩大let
成lambda
的格雷格的解释是非常好的,我不会解决let
可言,我假设let
是 派生形式或宏,并扩展为lambda
形式,是 立即调用。
由于其他海报引发的问题,将Lisp或Scheme函数直接编译为C或C++函数 将会非常棘手。根据 的方法,生成的C或C++将无法识别(甚至不可读)。
我在完成计算机程序的结构和解释之后编写了一个Lisp-to-C编译器(这是最后一个练习,实际上我欺骗了并且只是写了一个从SICP字节码到C的翻译器)。它发出的C子集根本不使用C函数来处理Lisp函数。这是因为SICP第5章中的 注册机器语言的真实水平比C低 。
假设您有某种形式的将名称绑定到值的环境,您可以像这样定义函数调用的关键:使用绑定到参数的形式参数扩展函数定义的环境,然后评估这个新环境中的功能主体。
在SICP的编译器中,环境保存在一个全局变量中,并且还有其他的全局变量持有函数调用的参数列表,如 以及被调用的过程对象(过程对象包括一个指向它所定义的环境的指针)以及函数返回时跳转到的标签。
请记住,当你正在编译lambda
表达,有 你知道在编译时二句法成分:正式 参数和lambda
的身体。
当一个函数被编译时,所发出的代码看起来像这样 伪代码:
some-label
*env* = definition env of *proc*
*env* = extend [formals] *argl* *env*
result of compiling [body]
...
jump *continue*
...其中*env*
和*argl*
是存放 环境和参数列表中的全局变量和extend
一些函数(这可以是 是一个合适的C++函数),它扩展了环境*env*
将*argl*
中的名称与[formals]
中的值配对。
然后,当编译代码运行,并且有这个 lambda
别的地方在你的代码的调用,调用约定是把 参数列表评估到*argl*
变量的结果,把回报标签在*continue*
变量中,然后跳转到some-label
。
在嵌套lambda
S的情况下,发出的代码看起来 这样的:
some-label
*env* = definition env of *proc*
*env* = extend [formals-outer] *argl* *env*
another-label
*env* = definition env of *proc*
*env* = extend [formals-inner] *argl* *env*
result of compiling [body-inner]
...
jump *continue*
rest of result of compiling [body-outer]
... somewhere in here there might be a jump to another-label
jump *continue*
这是一个有点难以解释,我敢肯定,我已经做了糊涂 工作的。我想不出一个体面的例子,它基本上没有描述SICP的第5章。因为我花时间写这个答案,所以我会发布它,但是如果它无可救药地混淆,我很抱歉。我们强烈推荐SICP和Lisp in Small Pieces。
SICP涵盖了初学者的元环解释,以及解释器上的一些变体,以及我设法混淆和破解的字节代码编译器。这只是最后两章,前三章一样好。这是一本很棒的书。如果你还没有,绝对读它。
LiSP包括一些用Scheme编写的解释器,一个编译器用于字节码和一个用C编译器。我处于中间,可以自信地说这是一本深刻而丰富的书,非常值得每个人对Lisp的实现感兴趣。这一点可能有点过时,但对于像我这样的初学者来说,它仍然很有价值。虽然它比SICP更先进,但要小心。它包含了一个关于指称语义的章节,它基本上在我的头上。
其他一些注意事项:
Darius Bacon's self-hosting Lisp to C compiler
lambda lifting,这是一种更先进的技术,我认为马克·菲利使用
+1强调这是一个整体比翻译'let'到'lambda' /应用程序更复杂 – acfoltzer 2011-04-12 03:28:42
这里有一个博客文章,可能会帮助,这个博客已经写了一堆文章关于编译这个问题,这个与处理关闭有关。它只是发布给HN,让我回想起这个问题:http://matt.might.net/articles/closure-conversion/这是一个比我所描述的天真的技术更先进的技术,但它写得很清楚。 – spacemanaki 2011-04-29 12:31:54