在没有所有可用软件包或加载所有内容的情况下,从lisp读取/解析常见的lisp文件

时间:2019-05-18 21:04:50

标签: parsing lisp common-lisp reader

我正在做一个项目,其中涉及解析常见Lisp存储库的历史记录。我需要将它们解析为列表列表或类似的内容。理想情况下,我想以某种方式保留尽可能多的原始源文件语法。例如,在文本#+sbcl <something>的情况下,我认为这意味着“如果我们当前的大写字母是sbcl,请阅读<something>,否则跳过它”,我想得到类似{{1 }}。

我最初用Python编写了LALR解析器,这种解析器可以工作,但是由于许多原因,它并不理想。我很难获得正确的输出,并且要添加大量特殊情况。

我认为我真正应该做的是使用lisp本身,因为它已经内置了lisp解析器。如果我可以将文件读入sexps,我可以将其转储为某种东西(cl-json可以)以便进一步处理。

不幸的是,当我尝试阅读https://github.com/fukamachi/woo/blob/master/src/woo.lisp时,我得到了错误消息

(#+ 'sbcl <something>)

这当然来自该文件的第80行,因为该包是在There is no package with the name WOO.EV.TCP中定义的,而我们尚未阅读。

从根本上讲,是否可以将文件读入sexps而不关心包是否已定义或它们是否包含相关符号?如果是这样,怎么办?我曾尝试查看hyperspec阅读器文档,但没有发现任何听起来相关的内容。

我实际上没有写普通的Lisp练习,但是似乎有可能可能通过创建具有该名称的空白包并处理no来解决未定义的包条件只需对给定符号进行intern,即可在打包条件中使用该符号。我。我不知道该怎么做,不知道是否可行,不知道涉及多少特殊情况。暂时,第一个条件称为src/ev/tcp.lisp,但是第二个条件(至少在sbcl中)称为no-such-package,所以我什至不知道如何确定这个特定的simple-error是否为包中没有这样的符号错误,更不用说如何从条件中提取相关名称,修复它并重新启动了。我真的很想听听一位普通的Lisp专家的意见,这是在我尝试以这种方式进行之前,在这里要做的正确的事,因为这将涉及很多学习。

在我看来,我可以通过在读取文件之前先对文件进行修复来解决此问题。例如。将simple-error变成woo.ev.tcp:start-listening-socket。我不太喜欢这种解决方案,也不清楚我不会遇到更多丑陋的特殊情况,但是如果没有更好的答案,它可能会起作用。

2 个答案:

答案 0 :(得分:2)

我几乎可以肯定,出于多种原因,没有一种简便的便携式方法可以做到这一点。

(现在仅将事情限制在不存在的包装问题中。)

首先,无法通过便携式方式访问读取器的位,该位确定令牌将成为符号,然后查找包标记&c:这只是根据2.3中的规则发生的。因此,您不能轻易干预。

其次,在任何情况下,读者可能会发信号表示无法处理足够多的信息。

解决此问题有几种可能的方法。

如果您觉得自己足够英勇,则可以告诉读者所有令牌起始字符实际上都是您控制的东西,然后编写令牌读取器以某种方式通过返回某个对象来处理整个包装物不是符号。但是要做到这一点,您需要处理数字,如果您认为这很简单,那么事实并非如此。

如果您不那么英勇,您可以编写一个更原始的令牌读取器,该令牌读取器甚至不尝试处理任何事情,只是获取所有需要的字符并返回某种包装字符串的对象。这样可以避免丢失整数的问题,从而避免了整数问题。

如果您不关心可移植性,请找到一个实现,了解其阅读器是如何实现的,然后对其进行修改。有更多的开放源代码或可用的源代码实现比我可以轻易数出的(也许我不太擅长数数),所以这是一个非常不错的方法。当然是我要做的。


但这只是问题的开始。 CL阅读器毛茸茸,在其标准配置(除非人们另行安排,否则用于compile-file之类的配置)在阅读时可以运行完全任意的代码,包括修改阅读器本身的代码,可以通过与实现相关的方式来实现。人们使用这种语言:Lisp被称为“可编程编程语言”的原因是人们对其进行编程。

答案 1 :(得分:0)

我已决定使用sed(实际上是Python的re.sub,但有谁在数呢?)解决此问题,因为它适用于我的实际用例,而且很简单。

对于未来的读者:人们普遍认为这是不可能的,这可能是正确的。 @Svante发表的其他问题看起来是解决部分问题的简便方法。通过将#.#+#-等的阅读器宏替换为仅列出内容的宏,可以更优雅地解决问题的其他部分来自@tfb,但我没有时间做这些事。