使用PyParsing解析Python代码?

使用PyParsing解析Python代码?,parsing,abstract-syntax-tree,bnf,pyparsing,python,Parsing,Abstract Syntax Tree,Bnf,Pyparsing,Python,我正在尝试编写能够解析任何Python代码的PyParsing代码(我知道存在AST模块,但这只是一个起点——我最终想要解析的不仅仅是Python代码) 不管怎么说,我想我会先写一些能够解析经典的东西 print("Hello World!") 下面是我写的: from pyparsing import (alphanums, alphas, delimitedList, Forward, quotedString, removeQuotes, S

我正在尝试编写能够解析任何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))
从技术上讲,这是一个有效的
expr
——您可以将其键入REPL中,解析它不会有问题,即使它是无用的

所以我想也许我想要的是在我的
expr
定义中翻转
name
call
,所以它更喜欢将
call
s返回到
name
s,如下所示:

expr <<= string | call | name
E = E x y z | s | n

expr您的语法是左递归的:
expr
需要一个
调用
它需要一个
expr
它需要一个
调用
。。。如果PyParsing无法处理左递归,则需要将语法更改为PyParsing可以处理的语法

删除直接左递归的一种方法是更改gramar规则,例如:

A = A b | c
进入

在您的例子中,左递归是间接的:它不会发生在
expr
中,而是发生在子规则(
call
)中:

要删除间接左递归,您通常将子规则的定义“提升”到主规则。不幸的是,这从语法中删除了令人不快的子规则——换句话说,当你这样做的时候,你会失去一些结构性的表达能力

前面的示例删除了间接递归,如下所示:

expr <<= string | call | name
E = E x y z | s | n
在这一点上,您有直接的左递归,它更容易转换。当你处理这个问题时,结果会是这样的——在伪EBNF中:

E = (s | n) (x y z)*
在您的情况下,
Expr
的定义为:

Expr = (string | name) Args*
Args = "(" ExprList? ")"
ExprList = Expr ("," Expr)*

我的猜测是,您的代码无法使用终端,因此将反复解析相同的令牌,从而导致无限递归。我不知道pyparsing,但是pyparsing主页上的这个会消耗解析的终端;你必须处理很多很多问题,其中最不重要的是原子构成了你的语言。一旦你“解析”了一些东西,那么你就没有足够的时间在实践中做很多有用的事情。请参阅我关于“解析后的生活”的个人简介(也讨论了解析问题)。@IraBaxter-解析后的生活假设我想做比我更复杂的事情。我正在寻找编写工具,以便在AST和字符串之间来回切换——仅此而已。我不想对它做任何分析。此外,我需要以源代码的形式免费分发所有内容-我不会购买你的产品,无论它如何完美地满足我的需求。我不是要求你购买我的产品。我强调用代码执行复杂任务需要更多的“AST和字符串”。(只在AST和字符串之间来回移动没有什么意义,对于多种语言,您到底在做什么,只需要这样做就可以了?)。欢迎您以任何您喜欢的方式实现“更复杂”,包括从头开始构建,或为其他开源解决方案做出贡献。我认为这比你想象的要困难得多。即使你坚持使用“AST和字符串”,这个问题对于现代语言来说仍然很难解决,而且也不会变得容易。举个例子,如果您的意图仅限于那些“容易”解析的语言,我会感到惊讶。
Expr = (string | name) Args*
Args = "(" ExprList? ")"
ExprList = Expr ("," Expr)*