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

时间:2012-08-30 20:28:01

标签: compiler-construction common-lisp

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

修改

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

1 个答案:

答案 0 :(得分:3)

Rainer Joswig的第一条评论指出:

  

不在标准Common Lisp中。

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

如果您想自己实现这一目标,那么您将为输入和输出流实现一个非常低效的compile-file版本,以生成适用于load或您自己的版本的可加载表单。

使用with-compilation-unit包装编辑,您必须特别注意macroexpand顶级表单,确保将progn表单视为顶级表单, locallymacroletsymbol-macrolet形式建立绑定并将其表单作为顶层处理,具有非空词汇环境(其操作也不可移植),并且处理{ {1}}表单,其中某些表单可以被评估,处理或两者兼而有之。然后,生成可外化的表单,关注可以合并的内容和不能合并的内容(例如符号和包),为eval-whenmake-load-formstandard-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))))) 提供解压缩外部格式,并使您的实现能够打开URL(URI的,IRI,无论你关心什么)而不仅仅是路径名。 AFAIK,ABCL可以打开URL进行输入。然而,当用这样的外部资源调用时,compile-file的输出文件是什么?也许制作自己的compile-file,其中说明临时文件用于compile-and-load的{​​{1}}关键参数和compile-file