compiler-construction - 使用读取宏编译 Lisp 代码

标签 compiler-construction lisp common-lisp interpreter reader-macro

在将 lisp 代码文件编译成字节码或原始程序集(或与此相关的 fasl 文件)时,我很难理解读取宏会变成什么。或者也许我确实理解它但不知道。我真的很困惑。

当您使用读取宏时,您不需要提供可用的源代码吗?

如果这样做,那么您必须执行构成读取宏功能的源代码。如果您不这样做,那么当您可以执行诸如 read-char 之类的操作时,它们如何工作?

要做到这一点,如果你想让读取宏使用预先定义的变量,你必须执行它之前的所有代码,所以这变成了运行时,它把一切都搞砸了。

如果你不运行它之前的代码,那么上面定义的东西将不可用。

定义读取宏的函数或编译器宏呢?我假设它们根本无法工作,除非您requireload 一个文件或未编译的东西。但是编译出来了,就不能用了?

如果我的某些猜测是正确的,那么这意味着“哪些数据可用于宏”和“哪些宏可用于函数”存在很大差异,具体取决于您是否将整个文件编译为稍后运行或一次一行地解释文件(即,读取、编译和评估一个又一个表达式)。

简而言之,似乎要将一行编译成无需进一步的宏处理或其他任何操作即可执行的形式,您必须阅读、编译和运行前面的行。

再次记住,这些问题适用于编译 lisp,而不是解释它,你可以在每一行输入时运行它。

对不起,我的胡言乱语,但我是 lisp 的新手,想知道更多它是如何工作的。

最佳答案

这实际上是一个有趣的问题,也是许多初学 Lisp 程序员的难题。造成这种情况的主要原因之一是一切都“按预期”工作,只有当您开始使用 Lisp 的更高级功能时,您才会真正开始考虑这些事情。

对您的问题的简短回答是,是的,为了正确编译代码,必须执行一些先前的代码。注意一些这个词,这是关键。让我们举一个小例子。考虑一个包含以下内容的文件:

(print 'a)

(defmacro bar (x) `(print ,x))

(bar 'b)

如您所知,如果您在此文件上运行 COMPILE-FILE,生成的 .fasl 文件将只包含以下代码的编译版本:

(print 'a)
(print 'b)

“但是”,您可能会问,“为什么在编译期间执行了 DEFMACRO 形式,而没有执行 PRINT 形式?”。 Hyperspec 部分解释了答案 3.2.3 .它包含以下句子:

Normally, the top level forms appearing in a file compiled with compile-file are evaluated only when the resulting compiled file is loaded, and not when the file is compiled. However, it is typically the case that some forms in the file need to be evaluated at compile time so the remainder of the file can be read and compiled correctly.

有一个表单可用于准确控制表单何时被评估。为此,您可以使用 EVAL-WHEN。事实上,这正是 Lisp 编译器自己实现 DEFMACRO 的方式。您可以通过从 REPL 中键入以下内容来查看您的 Lisp 是如何实现它的:

(macroexpand '(defmacro bar (x) `(print ,x)))

显然不同的 Lisp 实现会以不同的方式实现这一点,但关键重要的是它将定义包装在一种形式中:(eval-when (:compile-toplevel :load-toplevel :execute) ...) 。这告诉编译器应该在编译文件时和加载文件时评估表单。如果它不这样做,您将无法在定义它的同一个文件中使用该宏。如果仅在编译文件时评估表单,加载后您将无法在其他文件中使用宏。

关于compiler-construction - 使用读取宏编译 Lisp 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11550816/

相关文章:

performance - 在 Common Lisp 中,函数和宏之间有性能差异吗?

lisp - 列表中项目数量可变的格式的理由

lisp - 如何将两个相似的函数合并为一个函数

lisp - 语法从 'The Little Schemer' 中的示例更改为真实的 Scheme

compiler-construction - 仅将环境的相关子集传递给 eval 的方案解释器

lisp - 在 Lisp 和其他函数式语言中,为什么长度不是 O(1)

compiler-construction - 在 JDK 1.6 编译器中, "-source 1.6"启用什么(如果有)?

java - "The left hand side of an assignment must be a variable"由于额外的括号

gcc - gcc编译器不会在第一个错误时停止

visual-studio - Visual Studio 2010 Express 中的编译器的优化程度是否低于 Professional 版本的编译器?