【发布时间】:2015-09-28 20:06:12
【问题描述】:
我正在尝试编写能够解析任何 Python 代码的 PyParsing 代码(我知道存在 AST 模块,但这只是一个起点 - 我最终想要解析的不仅仅是 Python 代码。)
无论如何,我想我会先写一些能够解析经典的东西
print("Hello World!")
所以这是我写的:
from pyparsing import (alphanums, alphas, delimitedList, Forward,
quotedString, removeQuotes, Suppress, Word)
expr = Forward()
string = quotedString.setParseAction(removeQuotes)
call = expr + Suppress('(') + Optional(delimitedList(expr)) + Suppress(')')
name = World(alphas + '_', alphanums + '_')
expr <<= string | name | call
test = 'print("Hello World!")'
print(expr.parseString(test))
但是,当我这样做时,它就会吐出来:
['print']
这在技术上是一个有效的expr - 你可以将它输入到 REPL 中并且解析它没有问题,即使它没用。
所以我想也许我想要的是在我的expr 定义中翻转name 和call,所以它更愿意将calls 返回到names,如下所示:
expr <<= string | call | name
现在我得到一个最大递归深度超出错误。这也是有道理的:
- 检查是否为
expr。- 检查是不是
string,不是。 - 检查是否为
call。- 它必须以
expr开头,返回到外部列表的开头。
- 它必须以
- 检查是不是
所以我的问题是...我如何定义 call 和 expr 以便我不会以无限递归结束,而且它不会在看到名称时停止忽略论点?
Python 代码是否过于复杂,PyParsing 无法处理?如果没有,PyParsing 可以处理的内容是否有任何限制?
(注意 - 我已经包含了通用标签 parsing、abstract-syntax-tree 和 bnf,因为我怀疑这是一个通用的递归语法定义问题,不一定特定于 pyparsing。)
【问题讨论】:
-
我的猜测是您的代码无法使用终端,因此会一遍又一遍地解析相同的标记,从而导致无限递归。我不知道 pyparsing,但是 PyParsing 主页上的这个 sample of a Python parser 确实会消耗已解析的终端。
-
解析任意(“不仅仅是 Python”)源代码实际上很困难;您必须处理很多很多问题,其中最少的是原子构成了您的语言。一旦你“解析”了一些东西,那么你将没有足够的东西在实践中做很多有用的事情。请参阅我关于“解析后的生活”的简历(其中也谈到了解析问题)。
-
@IraBaxter - 解析后的生活假设我想做比我更复杂的事情。我正在寻找在 AST 和字符串之间来回切换的工具——仅此而已。我不想对它做任何类型的分析。此外,我需要以源代码形式免费分发所有内容 - 无论您的产品多么完美地满足我的需求,我都不会购买。
-
我不是要你购买我的产品。我的重点是使用代码执行复杂的任务需要更多的“AST 和字符串”。 (仅在 AST 和字符串之间来回切换没有什么意义,对于多种语言,您到底在做什么,仅此而已?)。欢迎您以任何您喜欢的方式实现“更复杂”,包括从头开始构建它,或为其他一些开源解决方案做出贡献。我会建议这比你想象的要困难得多。
-
即使你只坚持“AST 和字符串”,对于现代语言来说,这个问题仍然非常困难,而且不会变得更容易。例如,请参阅stackoverflow.com/questions/243383/… 如果您的意图仅限于那些“易于”解析的语言,我会感到惊讶。
标签: parsing abstract-syntax-tree bnf pyparsing python parsing abstract-syntax-tree pyparsing bnf