parser
parser - 访问Python解析树
该parser
模块为Python的内部解析器和字节码编译器提供了一个接口。该接口的主要目的是允许Python代码编辑Python表达式的分析树并从中创建可执行代码。这比试图将任意Python代码片段解析并修改为字符串更好,因为解析是以与形成应用程序的代码相同的方式执行的。它也更快。
注意
从Python 2.5开始,使用ast
模块在抽象语法树(AST)生成和编译阶段切入更为方便。
该parser
模块导出记录在这里也有“ST”的“AST”代替姓名; 这是从没有其他AST开始的遗留问题,与Python 2.5中的AST无关。这也是函数关键字参数被称为ast的原因
,而不是st
。Python 3中的“ast
”函数已被删除。
关于这个模块有几点需要注意,这对使用创建的数据结构很重要。这不是编辑Python代码的分析树的教程,但提供了使用parser
模块的一些示例。
最重要的是,需要理解内部解析器处理的Python语法。有关语言语法的完整信息,请参阅Python语言参考。解析器本身是Grammar/Grammar
根据标准Python发行版中文件中定义的语法规范创建的。存储在由该模块创建的ST对象中的解析树是由expr()
or suite()
函数创建的内部解析器的实际输出,如下所述。ST创建的对象sequence2st()
忠实地模拟这些结构。请注意,由于该语言的形式语法被修改,所以被认为“正确”的序列的值将因Python的不同版本而异。然而,作为源文本将代码从一个Python版本传输到另一个版本将始终允许在目标版本中创建正确的分析树,唯一的限制是迁移到较老版本的解释器将不支持更新的语言结构。解析树通常不是从一个版本到另一个版本兼容,而源代码始终是向前兼容的。
由st2list()或st2tuple()返回的序列的每个元素都有一个简单的形式。代表文法中非终端元素的序列总长度大于1。第一个元素是一个整数,用于标识语法中的产品。这些整数在C头文件Include / graminit.h和Python模块符号中给出了符号名称。序列中的每个附加元素都代表输入字符串中可识别的生产组件:它们总是与父代具有相同形式的序列。这个结构中应该注意的一个重要方面是,用于标识父节点类型的关键字(如if_stmt中的关键字)包含在节点树中,无需任何特殊处理。例如,if关键字由元组(1,'if')表示,其中1是与所有名称标记关联的数值,包括用户定义的变量和函数名称。在请求行号信息时返回的替代形式中,相同的标记可表示为(1,'if',12),其中12表示找到终端符号的行号。
终端元素的表示方式大致相同,但没有任何子元素,并添加了已识别的源文本。if
以上关键字的例子是有代表性的。C头文件Include/token.h
和Python模块中定义了各种类型的终端符号token
。
ST对象不需要支持这个模块的功能,但是有三个目的:允许应用程序分摊处理复杂分析树的代价,提供一个分析树表示,与Python相比,可以节省内存空间列表或元组表示,并且简化在C中创建附加模块来操纵分析树。一个简单的“包装”类可以在Python中创建,以隐藏ST对象的使用。
该parser
模块为几个不同的目的定义函数。最重要的目的是创建ST对象并将ST对象转换为其他表示形式,例如解析树和编译代码对象,但也有函数用于查询由ST对象表示的解析树的类型。
扩展内容
Module
symbol
表示分析树内部节点的常用常量。 Module
token
表示分析树的叶节点和用于测试节点值的函数的有用常量。
1.创建ST对象
ST对象可以从源代码或分析树中创建。从源创建ST对象时,将使用不同的函数来创建'eval'
和'exec'
表单。
parser.expr(source)
该expr()
函数将参数源
解析为它的输入compile(source, 'file.py', 'eval')
。如果解析成功,则会创建ST对象来保存内部分析树表示形式,否则会引发适当的异常。
parser.suite(source)
该suite()
函数将参数源
解析为它的输入compile(source, 'file.py', 'exec')
。如果解析成功,则会创建ST对象来保存内部分析树表示形式,否则会引发适当的异常。
parser.sequence2st(sequence)
该函数接受一个表示为序列的分析树,并尽可能构建内部表示。如果它可以验证该树符合Python语法,并且所有节点都是Python主机版本中的有效节点类型,则会从内部表示形式创建一个ST对象并将其返回给被调用的对象。如果在创建内部表示时出现问题,或者树无法验证,ParserError
则会引发异常。不应该假定以这种方式创建的ST对象能够正确编译; 当ST对象被传递时,编译引发的正常异常仍可能启动compilest()
。这可能表明问题与语法无关(例如MemoryError
异常),但也可能由于解析结果等结构del f(0)
,它转义了Python解析器,但是由字节码编译器检查。
表示终端令牌的序列可以表示为表单的两元素列表(1, 'name')
或者表单的三元素列表(1, 'name', 56)
。如果第三个元素存在,则假定它是有效的行号。行号可以为输入树中的任何终端符号子集指定。
parser.tuple2st(sequence)
这与sequence2st()
功能相同。此入口点保持向后兼容。
2.转换ST对象
无论用于创建它们的输入,ST对象都可以转换为表示为列表或元组树的解析树,也可以编译为可执行代码对象。可以使用或不使用行号信息来提取分析树。
parser.st2list(ast[, line_info])
该函数从ast 中
的调用方接受ST对象,并返回表示等效分析树的Python列表。得到的列表表示可用于检查或以列表形式创建新的分析树。只要内存可用于构建列表表示,该函数就不会失败。如果分析树仅用于检查,则st2tuple()
应该使用分析树来减少内存消耗和碎片。当需要列表表示时,此函数比检索元组表示并将其转换为嵌套列表快得多。
如果line_info
为true,则所有终端令牌都将包含行号信息,作为表示令牌的列表的第三个元素。请注意,提供的行号指定了令牌结束的行
。如果该标志为错误或省略,则该信息被省略。
parser.st2tuple(ast[, line_info])
该函数从ast中
的调用方接受ST对象,并返回表示等效分析树的Python元组。除了返回一个元组而不是一个列表之外,这个函数与之相同st2list()
。
如果line_info
为true,则所有终端令牌都将包含行号信息,作为表示令牌的列表的第三个元素。如果该标志为错误或省略,则该信息被省略。
parser.compilest(ast, filename='<syntax-tree>')
可以在ST对象上调用Python字节编译器来生成可用作exec
语句或调用内置eval()
函数的一部分的代码对象。该函数为编译器提供接口,使用由filename
参数指定的源文件名
将内部分析树从ast
传递到解析器。为文件名
提供的默认值指示源是ST对象。
编译ST对象可能会导致与编译相关的异常; 一个例子可能是SyntaxError
由分析树引起的del f(0)
:这个语句在Python的形式语法中被认为是合法的,但不是一个合法的语言结构。所述SyntaxError
凸起此条件实际上是由Python字节编译器通常,这就是为什么它可以在此时通过提高生成parser
模块。编译失败的大多数原因可以通过检查分析树来以编程方式进行诊断。
3.对ST对象的查询
提供了两个函数,它们允许应用程序确定ST是作为表达式还是套件创建的。既不这些功能可以被用来确定是否有ST,从源代码经由创建expr()
或suite()
或从经由解析树sequence2st()
。
parser.isexpr(ast)
当ast
表示一个'eval'
表单时,该函数返回true,否则返回false。这很有用,因为通常使用现有的内置函数不能查询代码对象的信息。请注意,由此创建的代码对象compilest()
也不能像这样查询,并且与由内置compile()
函数创建的代码对象相同。
parser.issuite(ast)
这个函数反映了isexpr(),它报告ST对象是否代表'exec'形式,通常称为“套件”。假设这个函数等同于isexpr(ast)并不安全,因为附加的语法 片段可能会在未来得到支持。
4.异常和错误处理
解析器模块定义了一个异常,但也可能会从Python运行时环境的其他部分传递其他内置异常。查看每个函数以获取有关它可能引发的异常的信息。
exception parser.ParserError
解析器模块内发生故障时引发异常。这通常是针对验证失败产生的,而不是SyntaxError
在正常解析期间产生的内置。异常参数可以是描述失败原因的字符串,也可以是包含导致传递给解析树的故障的序列的元组sequence2st()
以及解释性字符串。调用sequence2st()
需要能够处理任何一种类型的异常,而对模块中其他功能的调用只需要知道简单的字符串值。
请注意,函数compilest()
,expr()
并suite()
可能引发解析和编译过程通常引发的异常。这些措施包括内置的例外MemoryError
,OverflowError
,SyntaxError
,和SystemError
。在这些情况下,这些例外具有通常与其相关的所有含义。有关详细信息,请参阅每个功能的说明。
5. ST对象
ST对象之间支持有序和等式比较。酸洗ST对象(使用pickle
模块)也被支持。
parser.STType
返回的对象的类型expr()
,suite()
和sequence2st()
。
ST对象具有以下方法:
ST.compile([filename])
Same as compilest(st, filename)
.
ST.isexpr()
和isexpr(st)
一样
ST.issuite()
和 issuite(st)
.一样
ST.tolist([line_info])
等同于 st2list(st, line_info)
.
ST.totuple([line_info])
等同于 st2tuple(st, line_info)
.
6.例子:compile()的模拟
虽然许多有用的操作可能发生在解析和字节码生成之间,但最简单的操作是什么都不做。为此,使用parser
模块产生中间数据结构就相当于代码
>>> code = compile('a + 5', 'file.py', 'eval')
>>> a = 5
>>> eval(code)
10
使用该parser
模块的等效操作稍长一些,并允许将中间内部分析树保留为ST对象:
>>> import parser
>>> st = parser.expr('a + 5')
>>> code = st.compile('file.py')
>>> a = 5
>>> eval(code)
10
一个需要ST和代码对象的应用程序可以将这些代码打包成一些可用的函数:
import parser
def load_suite(source_string):
st = parser.suite(source_string)
return st, st.compile()
def load_expression(source_string):
st = parser.expr(source_string)
return st, st.compile()