是否有Lisp本机代码编译器?

Hea*_*rab 32 lisp compiler-construction

是否有Lisp的本机代码编译器?它甚至可以编译到哪个程度,具有动态特性,垃圾收集,宏以及其他什么?

Rai*_*wig 53

许多Lisp编译器编译为"本机"代码.'Native'在这里意味着'机器代码'(x86在32位或64位模式下,PowerPC,SPARC,......).

其他问题:

  • '非本机代码'编译器可以生成单个文件可执行文件吗? - >是的.

  • 可以'本机代码'编译器生成单个文件可执行文件吗? - >是的.

  • "原生"是如何"原生"的? - > Lisp系统大部分时间都会有自己的内部数据结构布局(CLOS类),自己的错误处理('条件'),自己的内存管理(垃圾收集),自己的库,...

  • Lisp可以在没有GC的情况下运行吗? - >通常不是.也有例外.

  • 应用程序大小怎么样? - >默认情况下,生成Lisp应用程序的简单方法通常会导致大型可执行文件.可执行文件包括整个Lisp,包括其库,所有符号的名称,有关函数的参数列表的信息,编译器,调试器,源代码位置信息等.一些编译器也生成了大量的代码(SBCL就是一个例子).

  • 有缩小应用程序大小的方法吗? - >这取决于Lisp系统.像LispWorks和Allegro CL这样的商业Lisp系统可以.对于应用程序交付,他们可以删除未使用的代码,删除调试信息,删除部分Lisp(库,编译器......)等.

  • Common Lisp系统可以生成小的可执行文件.我的意思是真的很小. - >不是真的.可执行文件是大(CCL)或非常大(SBCL).一些Common Lisp系统可以生成中等大小的可执行文件.但没有一个能真正生成小的可执行文件.

  • 真的没有办法生成真正的小型可执行文件吗? - >多年前编写的编译器生成相对紧凑的C代码而没有大型库.但是这些编译器没有得到维护.

  • 还有其他方法来缩小可执行文件吗? - >如果要运行多个Lisp应用程序,在一个或多个共享库中重用运行时,编译器和库是有意义的.这样,当运行时已作为共享库(或类似库)安装时,要传递的代码将更小.

  • 我如何找出我正在使用的Lisp作为应用程序交付支持? - >阅读手册并询问其他用户.

  • 好吧,所以大多数Common Lisp系统都无法生成微小的应用程序.是否有其他Lisp方言可以生成较小的可执行文件. - >是的,一些Scheme编译器可以.

  • Common Lisp如何处理运行时错误? - >取决于您生成应用程序的方式.默认情况下,您将获得一个Lisp调试器(除非您已将其删除).但是,您可以在应用程序中使用自己的错误处理例程,并可以阻止调试器出现.

  • 什么是Common Lisp的特殊优势,当生成非常小的可执行文件时不是一个? - >你可以包含一个REPL来与应用程序交互,你可以使用一个包含的编译器在运行时编译新的(或更改的代码),你可以使用FASL(编译的Lisp代码)加载器在运行时加载其他本机代码(想一想)插件,补丁,扩展,...),复杂的错误处理,包括错误恢复是可能的,...

  • 但Lisp是动态的吗? - >是的,动态意味着它可以在运行时改变很多东西.例如,在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))
Run Code Online (Sandbox Code Playgroud)

...

  [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
Run Code Online (Sandbox Code Playgroud)

DISASSEMBLE的输出显然取决于处理器体系结构,操作系统,使用的Lisp编译器和当前的优化设置.


dmi*_*_vk 9

有许多Lisp编译器可以编译为本机代码.CMUCL,SBCL,ClozureCL在开源Lisp编译器中是众所周知的.

垃圾收集不是编译到本机代码的障碍.此外,在某些情况下,Lisp可以使用不需要GC的堆栈分配,并且可以大大提高性能(使用动态范围声明;至少SBCL支持这一点).

宏(以及在读取时运行的任何代码(读取宏和读取),编译时(宏,编译器宏,eval-when中的代码))需要增量编译(必须编译第一个宏函数,然后可以编译使用宏的代码.这有点使编译复杂化,但这不是一个问题.此外,宏和编译器宏甚至可以帮助编译过程,因为它们允许程序员编写代码生成器和代码优化器,实质上是自定义编译器.

因此编译器比一些更简单的语言(如C)更复杂,但复杂性是可管理的(参见CMU Common Lisp的设计).

Common Lisp的动态特性是可控的,并且可以有效地编译.与其他一些动态语言(例如Python)相比,动态受到限制(例如,您无法在运行时获取当前的词法环境),这使编译器可以自由地进行优化.

  • 嗯,java拖拽整个java运行时,.net拖拽整个clr,c ++拖拽整个c ++ rt,lisp拖拽整个lisp运行时.这是一回事 - 几乎每种语言都需要自己的运行时.Lisp的运行时很大,因为它的灵活性(jvm和clr也是如此).但是,代码仍然是本机的:即,指令不是针对VM,而是针对目标CPU. (10认同)

Ale*_*lli 6

有很多本地代码的Lisp编译器,请参阅http://www.thefreecountry.com/compilers/commonlisp.shtml和例如CMU Common Lisp编译器.