2011-04-11 149 views
8

我正在编译为基于口齿不清C++(方案的非常小的子集),我试图找出如何代表我们表达一个玩具语言,转化Lisp语言到C++

(let ((var 10) 
     (test 12)) 
    (+ 1 1) 
    var) 

在第一我认为执行所有的exprs然后返回最后一个,但是返回会杀死我嵌套让表达式的能力,那么代表let的方式是什么?

此外,源到源转换中的任何资源都是appriciated,我已经google了,但我所能做的只是90分钟的方案编译器。

+0

这里有一个博客文章,可能会帮助,这个博客已经写了一堆文章关于编译这个问题,这个与处理关闭有关。它只是发布给HN,让我回想起这个问题:http://matt.might.net/articles/closure-conversion/这是一个比我所描述的天真的技术更先进的技术,但它写得很清楚。 – spacemanaki 2011-04-29 12:31:54

回答

9

一种方法是把它当作一个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不同),所以这需要额外的实现。

-1

如果您正在寻找工具来帮助进行源代码翻译,我推荐使用ANTLR。这是最好的。但是,您需要考虑如何从松散类型的语言(lisp)转换为松散类型的语言(c)。例如,在你的问题中,10的类型是什么? A short?一个int? A double?扩大let

+0

我有我自己的对象系统10是一个int在c + +我知道它是什么在运行时 – 2011-04-11 19:52:20

4

我会尝试解释一个简单的方法来编译嵌套的 lambda s。由于扩大letlambda 的格雷格的解释是非常好的,我不会解决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章。因为我花时间写这个答案,所以我会发布它,但是如果它无可救药地混淆,我很抱歉。我们强烈推荐SICPLisp in Small Pieces

SICP涵盖了初学者的元环解释,以及解释器上的一些变体,以及我设法混淆和破解的字节代码编译器。这只是最后两章,前三章一样好。这是一本很棒的书。如果你还没有,绝对读它。

LiSP包括一些用Scheme编写的解释器,一个编译器用于字节码和一个用C编译器。我处于中间,可以自信地说这是一本深刻而丰富的书,非常值得每个人对Lisp的实现感兴趣。这一点可能有点过时,但对于像我这样的初学者来说,它仍然很有价值。虽然它比SICP更先进,但要小心。它包含了一个关于指称语义的章节,它基本上在我的头上。

其他一些注意事项:

Darius Bacon's self-hosting Lisp to C compiler

lambda lifting,这是一种更先进的技术,我认为马克·菲利使用

+1

+1强调这是一个整体比翻译'let'到'lambda' /应用程序更复杂 – acfoltzer 2011-04-12 03:28:42