我正在编写一个程序,打开一个lisp文件,在流上调用"read",直到流为空,并处理它收集的列表。
这一直运行得很好,直到我发现"read"将执行包查找,例如,如果它遇到some-package:foo
,它会抱怨Package SOME-PACKAGE does not exist.
下面是一个例子,展示了我的意思:
(read (make-string-input-stream "(list 'foo :foo some-package:foo)"))
所以我现在想要三件事中的一件:
- Make it so"read"将忽略包名称空间,这样我就可以将任意源文件转换为符号列表
- 使用其他一些与"读取"行为类似的解析库,但它只能通过损坏
:
或忽略冒号及其之前的所有内容来获得纯符号 - 预处理文件并使用regex或类似的方法来打包查找并用简单名称替换它们,例如将"some-package:foo"转换为简单的"foo">
所有这些首先的目的是创建一个函数调用依赖关系图。我知道存在着更高质量的东西,但我想自己做这件事是为了好玩/学习。然而,我遇到了这个问题,不知道如何继续。
对于您的用例,您可以通过创建所需的包并重新启动来处理包错误情况。这也将保留符号的身份。请注意,当遇到in-package
表单时,您需要处理它们。
最简单的答案是告诉Lisp读取器按如下方式读取冒号#:
:
(defun read-standalone-char (stream char)
(declare (ignore stream))
char)
(defun make-no-package-prefix-readtable (&optional (rt (copy-readtable)))
"Return a readtable for reading while ignoring package prefixes."
(set-syntax-from-char #: #Space rt)
(set-macro-character #: #'read-standalone-char nil rt)
rt)
(let ((*readtable* (make-no-package-prefix-readtable)))
(read-from-string "(list 'foo :foo some-package:foo)"))
==> (LIST 'FOO #: FOO SOME-PACKAGE #: FOO) ; 33
显而易见的问题是,这将读取相同的FOO:BAR
和FOO :BAR
,但您可能可以解决这个问题。