Vse*_*kin 6 compiler-construction common-lisp
有没有办法实现compile-file
磁盘上的常规文件的效果,但是没有,但是使用流或只是内存中的字符串?(即如果我没有文件,并且不想从此内存数据中创建临时文件)
编辑
我正在考虑以下用例:从文件系统的其他地方加载代码.例如,来自档案(类似于Java的jar或Python zip处理功能)或来自网络.也许可能有其他方法,而不仅仅是弯曲compile-file
机械.
Rainer Joswig 的第一条评论就说明了这一点:
不在标准 Common Lisp 中。
您可以在每个实现中搜索进行的调用,compile-file
以查看底层实现是否采用流。
如果您想自己实现这一点,您将实现一个非常低效的compile-file
输入和输出流版本,该版本会生成适合load
您自己的版本的可加载表单。
用 包装编译with-compilation-unit
,您必须在macroexpand
ing 顶级表单时特别小心,确保progn
表单被视为顶级表单,并且locally
和macrolet
表单symbol-macrolet
建立绑定并将其表单作为非顶级表单进行处理空词法环境(其操作也不可移植)和处理eval-when
表单,其中某些表单可以被评估、处理或两者兼而有之。然后,生成可外部化的形式,注意什么可以合并,什么不能合并(例如符号和包),调用和make-load-form
实例standard-object
,并特别注意符号和包,例如检查要编译的流是否有第一个非- 原子形式是否能够在使用不同值调用时发出错误信号。structure-object
condition
in-package
load
*package*
这只是最小化编译的最顶层步骤,或多或少,没有提及编译实际发生的时间(编译时或加载时)、load-time-value
形式和许多细节。有些步骤需要代码遍历。
我的建议:如果您想保留编译和加载语义,只需从压缩数据和套接字中提取并保存您拥有的任何源代码,然后调用,然后调用compile-file
。load
对于更简单的事情,你可以这样做:
(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
。