使用内存数据编译文件而不是Common Lisp中的实际文件

Vse*_*kin 6 compiler-construction common-lisp

有没有办法实现compile-file磁盘上的常规文件的效果,但是没有,但是使用流或只是内存中的字符串?(即如果我没有文件,并且不想从此内存数据中创建临时文件)

编辑

我正在考虑以下用例:从文件系统的其他地方加载代码.例如,来自档案(类似于Java的jar或Python zip处理功能)或来自网络.也许可能有其他方法,而不仅仅是弯曲compile-file机械.

ace*_*ent 3

Rainer Joswig 的第一条评论就说明了这一点:

不在标准 Common Lisp 中。

您可以在每个实现中搜索进行的调用,compile-file以查看底层实现是否采用流。

如果您想自己实现这一点,您将实现一个非常低效的compile-file输入和输出流版本,该版本会生成适合load您自己的版本的可加载表单。

用 包装编译with-compilation-unit,您必须在macroexpanding 顶级表单时特别小心,确保progn表单被视为顶级表单,并且locallymacrolet表单symbol-macrolet建立绑定并将其表单作为非顶级表单进行处理空词法环境(其操作也不可移植)和处理eval-when表单,其中某些表单可以被评估、处理或两者兼而有之。然后,生成可外部化的形式,注意什么可以合并,什么不能合并(例如符号和包),调用和make-load-form实例standard-object,并特别注意符号和包,例如检查要编译的流是否有第一个非- 原子形式是否能够在使用不同值调用时发出错误信号。structure-objectconditionin-packageload*package*

这只是最小化编译的最顶层步骤,或多或少,没有提及编译实际发生的时间(编译时或加载时)、load-time-value形式和许多细节。有些步骤需要代码遍历。

我的建议:如果您想保留编译和加载语义,只需从压缩数据和套接字中提取并保存您拥有的任何源代码,然后调用,然后调用compile-fileload对于更简单的事情,你可以这样做:

(let* ((*package* *package*)
       (*readtable* *readtable*)
       (eof (copy-symbol 'eof))
       (form nil))
  (loop
    (setf form (read stream nil eof))
    (when (eq form eof)
      (return))
    (funcall (compile nil `(lambda () ,form)))))
Run Code Online (Sandbox Code Playgroud)

如果您不太关心可移植性,请使您的实现能够处理压缩文件,例如,通过向 提供解压缩外部格式compile-file,并使您的实现能够打开 URL(URI、IRI,无论您关心什么)而不仅仅是路径名。AFAIK,ABCL 可以打开 URL 进行输入。compile-file然而,当使用这样的外部资源调用时,输出文件会是什么?也许您自己制作compile-and-load一个临时文件,其中指定了用于关键compile-file参数output-file和 的临时文件load