使用"read"分析字符串并忽略包命名空间



我正在编写一个程序,打开一个lisp文件,在流上调用"read",直到流为空,并处理它收集的列表。

这一直运行得很好,直到我发现"read"将执行包查找,例如,如果它遇到some-package:foo,它会抱怨Package SOME-PACKAGE does not exist.

下面是一个例子,展示了我的意思:

(read (make-string-input-stream "(list 'foo :foo some-package:foo)"))

所以我现在想要三件事中的一件:

  1. Make it so"read"将忽略包名称空间,这样我就可以将任意源文件转换为符号列表
  2. 使用其他一些与"读取"行为类似的解析库,但它只能通过损坏:或忽略冒号及其之前的所有内容来获得纯符号
  3. 预处理文件并使用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:BARFOO :BAR,但您可能可以解决这个问题。

相关内容

最新更新