使用PyParsing解析Python代码?
我正在尝试编写能够解析任何Python代码的PyParsing代码(我知道存在AST模块,但这只是一个起点——我最终想要解析的不仅仅是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
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)*