【问题标题】:Parse string with "read" and ignore package namespaces用“read”解析字符串并忽略包命名空间
【发布时间】:2018-11-03 02:48:52
【问题描述】:

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

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

这里有一个例子说明我的意思:

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

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

  1. 让它如此“读取”将忽略包命名空间,因此我可以将任意源文件转换为符号列表。
  2. 使用具有类似行为的其他解析库来“读取”,但只能获取普通符号,方法是修改 : 或忽略冒号及其前面的所有内容。
  3. 预处理文件并使用正则表达式等来打包查找并用普通名称替换它们,例如将“some-package:foo”转换为简单的“foo”

所有这些的目的首先是制作一个函数调用依赖图。我知道存在质量更高的东西,但我想自己做这件事是为了好玩/学习。但是,我遇到了这个问题,不知道如何继续。

【问题讨论】:

  • case 3 会有问题 - 因为包名有助于区分名称冲突(如果您的代码使用另一个包的同名函数)所以最好将 "some-package:foo" 更改为 @987654328 @不是吗?但是,如果在 (in-package some-package) 之后有程序的一部分,则会出现错误 ...
  • read所遵循的策略a,这里解释cs.cmu.edu/Groups/AI/html/cltl/clm/node188.html
  • 如果您阅读norvig.com/lispy.html,您会看到如何在 python 中制作 lisp 阅读器 ...
  • 如果它把所有东西都解析成字符串标记呢?

标签: list parsing lisp common-lisp s-expression


【解决方案1】:

对于您的用例,您可以通过创建所需的包并重新启动来处理包错误情况。这也将保留符号身份。请注意,遇到in-package 表单时需要处理。

【讨论】:

    【解决方案2】:

    最简单的答案是告诉 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 相同,但您也许可以解决这个问题。

    【讨论】:

    • 他可以使用 (set-syntax-from-char #\A #\:) 将 ':' 设为组成字符,然后在需要进一步处理时在字符串中找到 ':' 字符。
    • @Leo:首先,您在set-syntax-from-char 调用中的 arg 顺序错误。其次,它不起作用,唉。
    猜你喜欢
    • 2011-02-17
    • 2016-11-25
    • 2012-09-27
    • 1970-01-01
    • 1970-01-01
    • 2015-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多