Common Lisp带有一个解析器(读取器),该解析器将其文本语法转换为s表达式。但是,它会丢弃注释,使其不适合使用往返Lisp代码的工具。
是否存在Common Lisp的现有解析器,用于保留注释?
答案 0 :(得分:8)
如评论中所述,您应该能够修改readtable,以将宏字符;
绑定到其他阅读器宏函数。例如,如果您定义:
(defun semicolon-reader (stream char)
(list 'my-comment
(concatenate 'string (string char)
(read-line stream nil #\Newline t))))
然后在顶级运行:
> (set-macro-character #\; #'semicolon-reader)
> (read)
用户输入:
(a b ; is b
c ; is c
)
将生成:
(A B (MY-COMMENT "; is b") C (MY-COMMENT "; is c"))
但是,真正的往返处理也将需要您保留空白。我对读者了解不足,不知道是否可以为空白字符定义一些巧妙的宏函数,或者是否必须编写某种预处理功能来用另一个宏字符对空白行进行预报价然后像上面的semicolon-reader
一样处理它。
答案 1 :(得分:2)
由于您正在制作代码格式化程序,因此您也许可以摆脱仅支持标准Common Lisp语法(with-standard-io-syntax
)并修改标准readtable以保留注释和空格(set-macro-character
)的麻烦。 。 readtable是CL读取器的主要数据结构,它告诉它在源代码中遇到特定字符时(例如,在遇到括号时如何读取列表)调用哪个函数来读取不同类型的对象。 >
您必须使用gensyms或结构/类来表示注释和空格,因为Lisp阅读器可以使用标准IO语法从源文件中读取其他类型的对象(例如列表和非gensym符号)。
下面是概念的快速证明。阅读器工作正常,但我无法使打印机工作(例如,重新打印从阅读器获得的内容以生成与输入足够接近的源文件)-它在我们的空白周围打印了额外的空白,可能是因为它认为我们的空白对象就像普通的Lisp对象(符号,列表等),并且在连续打印多个空白对象时(例如,如果打印1
和2
和{{ 1}}应该打印3
而不是1 2 3
)。深入阅读Common Lisp打印机的内容,以弄清楚如何改写此行为,这是读者的练习:p
还要仔细阅读Common Lisp HyperSpec的section 2.4, Standard Macro Characters。 Section 2.4.8 Sharpsign列出了以123
开头的所有语法。尤其要注意#
和#+
和#-
如果您可以在实际代码上正常使用它,请考虑将其作为开源软件包发布。
#.