是否有Lisp的本机代码编译器?它甚至可以编译到哪个程度,具有动态特性,垃圾收集,宏和其他什么?
答案 0 :(得分:53)
许多Lisp编译器编译为“本机”代码。 'Native'在这里意味着'机器代码'(x86在32位或64位模式下,PowerPC,SPARC,......)。
其他问题:
'非本地代码'编译器可以生成单个文件可执行文件吗? - >是
“本机代码”编译器可以生成单个文件可执行文件吗? - >是
'原生'是如何'原生'的? - > Lisp系统大多数时候都有自己的内部数据结构布局(CLOS类),自己的错误处理('条件'),自己的内存管理(垃圾收集),自己的库,......
< / LI>Lisp可以在没有GC的情况下运行吗? - &GT;通常不是。也有例外。
应用程序大小怎么样? - &GT;默认情况下,生成Lisp应用程序的简单方法通常会导致大型可执行文件。可执行文件包括整个Lisp,包括其库,所有符号的名称,有关函数的参数列表的信息,编译器,调试器,源代码位置信息等。一些编译器也生成了大量的代码(SBCL就是一个例子)。
有缩小应用程序大小的方法吗? - &GT;这取决于Lisp系统。像LispWorks和Allegro CL这样的商业Lisp系统可以。对于应用程序交付,他们可以删除未使用的代码,删除调试信息,删除部分Lisp(库,编译器......)等。
Common Lisp系统可以生成小的可执行文件。我的意思是真的很小。 - &GT;并不是的。可执行文件是大(CCL)或非常大(SBCL)。一些Common Lisp系统可以生成中等大小的可执行文件。但是没有人能真正生成小的可执行文件。
真的没有办法生成真正小的可执行文件吗? - &GT;多年前编写的编译器生成相对紧凑的C代码而没有大型库。但是这些编译器没有得到维护。
还有其他缩小可执行文件的方法吗? - &GT;如果要运行多个Lisp应用程序,则在一个或多个共享库中重用运行时,编译器和库是有意义的。这样,当运行时已作为共享库(或类似库)安装时,要传递的代码将更小。
如何找出我正在使用的Lisp支持的应用程序交付? - &GT;阅读手册并询问其他用户。
好的,所以大多数Common Lisp系统都无法生成微小的应用程序。是否有其他Lisp方言可以生成较小的可执行文件。 - &GT;是的,一些Scheme编译器可以。
Common Lisp如何处理运行时错误? - &GT;取决于您生成应用程序的方式。默认情况下,您将获得一个Lisp调试器(除非您已将其删除)。但是,您可以在应用程序中使用自己的错误处理例程,并可以阻止调试器出现。
Common Lisp的特殊优势是什么,当生成非常小的可执行文件时不是一个? - &GT;你可以包含一个REPL来与应用程序交互,你可以使用一个包含的编译器在运行时编译新的(或更改的代码),你可以使用FASL(编译的Lisp代码)加载器在运行时加载其他本机代码(想想插件,补丁,扩展,...),复杂的错误处理,包括错误恢复,...
但Lisp是动态的吗? - &GT;是的,动态意味着它可以在运行时改变很多东西。例如,在Common Lisp中,您可以在运行时更改CLOS类,并且类的实例将采用更改。但各种Lisp系统有不同的方法来删除一些动态功能。结构的动态性低于CLOS类。您可以声明类型并使用不同的优化设置进行编译(速度,安全性,调试......)。您可以内联函数。还有更多。
查看函数编译代码的一种简单方法是使用Common Lisp函数DISASSEMBLE。在x86-64 Mac上的Clozure CL中的示例
? (defun foo (x y) (if (= x y) (sin x) (* y (cos x))))
FOO
? (disassemble 'foo)
L0
[0] (leaq (@ (:^ L0) (% rip)) (% fn))
[7] (cmpl ($ 16) (% nargs))
[10] (jne L209)
[16] (pushq (% rbp))
[17] (movq (% rsp) (% rbp))
...
[172] (pushq (@ 77752))
[179] (jmpq (@ 10 (% temp0)))
L189
[189] (leaq (@ (:^ L0) (% rip)) (% fn))
[196] (jmpq (@ .SPNVALRET))
L209
[209] (uuo-error-wrong-number-of-args)
NIL
DISASSEMBLE的输出显然取决于处理器架构,操作系统,使用的Lisp编译器和当前的优化设置。
答案 1 :(得分:9)
有许多Lisp编译器可以编译为本机代码。 CMUCL,SBCL,ClozureCL在开源Lisp编译器中是众所周知的。
垃圾收集不是编译到本机代码的障碍。此外,在某些情况下,Lisp可以使用不需要GC的堆栈分配,并且可以大大提高性能(使用动态范围声明;至少SBCL支持这一点)。
宏(以及在读取时运行的任何代码(读取宏和读取),编译时(宏,编译器宏,eval-when中的代码))需要增量编译(第一个宏函数必须编译,然后编译使用宏的代码)。这有点使编译复杂化,但这不是一个问题。此外,宏和编译器宏甚至可以帮助编译过程,因为它们允许程序员编写代码生成器和代码优化器,实质上是自定义编译器。
因此编译器比一些更简单的语言(如C)更复杂,但复杂性是可管理的(参见Design of CMU Common Lisp)。
Common Lisp的动态特性是可控的,旨在有效地编译。与其他一些动态语言(例如Python)相比,动态受到限制(例如,您无法在运行时获取当前的词法环境),这使编译器可以自由地进行优化。
答案 2 :(得分:6)
本机代码中有大量的Lisp编译器,请参阅http://www.thefreecountry.com/compilers/commonlisp.shtml,例如CMU Common Lisp编译器。
答案 3 :(得分:4)
答案 4 :(得分:4)
不要忘记Chicken Scheme。
答案 5 :(得分:3)
是。见http://en.wikipedia.org/wiki/Common_Lisp。它提到Steel Bank Common Lisp(一种相当流行的实现)默认情况下将所有内容编译为本机。垃圾收集等使用的事实不是本机代码的障碍。这只意味着需要某种运行时。但那又怎么样?甚至C也有运行时。