antlr解析器的ast整形

antlr-ast的Python项目详细描述


antlr ast

生成状态

这个包允许您使用antlr语法并使用解析器输出生成抽象语法树(ast)。

安装

pip install antlr-ast

注意:此软件包与python2不兼容。

运行测试

# may need:# pip install pytest
py.test

用法

使用antlr ast需要四个步骤:

  1. 使用antlr定义语法并生成必要的python文件来解析此语法
  2. 使用parse根据生成的语法文件获取antlr运行时输出
  3. 在上一步的输出上使用process_tree
    1. abaseastvisitor(通过提供子类可自定义)将antlr输出转换为basenodes的可序列化树, 根据antlr语法中的规则动态创建
    2. 子类可以用来转换每种类型的节点
    3. "简化"选项可用于通过跳过只有一个子体的节点来缩短树中的路径
  4. 使用生成的树

接下来的部分将详细介绍这些步骤。

要可视化创建和转换这些解析树的过程,可以使用此ast查看器。

使用antlr

注意:对于本教程的这一部分,您需要知道如何解析代码
如果您从未安装过antlr,请参阅antlr《入门指南》。 antlr mega教程有一些有用的python示例。

本页介绍如何编写antlr解析器规则
下面的规则定义是一个具有重要antlr解析器语法元素的描述性名称的示例:

rule_name: rule_element? rule_element_label='literal'    #RuleAlternativeLabel
         | TOKEN+                                        #RuleAlternativeLabel
         ;

规则元素和可选标签是可选的。
+*()与regex中的含义相同。

下面,我们将使用一个简单的语法来解释antlr ast是如何工作的。 这个语法可以在/tests/expr.g4

中找到。
grammar Expr;

// parser

expr:   left=expr op=('+'|'-') right=expr       #BinaryExpr
    |   NOT expr                                #NotExpr
    |   INT                                     #Integer
    |   '(' expr ')'                            #SubExpr
    ;

// lexer

INT :   [0-9]+ ;         // match integers
NOT :   'not' ;

WS  :   [ \t]+ -> skip ; // toss out whitespace

antlr可以使用上面的语法以多种语言生成解析器。 要生成python解析器,可以使用以下命令。

antlr4 -Dlanguage=Python3 -visitor /tests/Expr.g4

这将在/tests/目录中生成许多文件,包括一个lexer(exprlexer.py), 一个解析器(exprparser.py)和一个访问者(exprvisitor.py)。

您可以在python中直接使用和导入它们。例如,从本回购协议的根目录:

from tests import ExprVisitor

为了方便使用生成的文件,它们被放在antlr_py包中。 py文件以不包含语法名称的别名导出生成的文件。

基本节点

子类在其相应的语法规则中有所有规则元素的字段和所有规则元素标签的标签。 字段和标签都可用作basenode实例的属性。 如果名称冲突,标签优先于字段。

basenode的名称是相应antlr语法规则的名称,但以大写字符开头。 如果为antlr规则指定了规则替换标签,则使用这些标签而不是规则名称。

转换节点

< Typic >ally,在antlr规则和语言概念之间没有一对一的映射:规则层次结构更加嵌套。 转换可用于使基于antlr规则的基节点的初始树更类似于ast。

变压器

basenodetransformer将遍历从根节点到叶节点的树。 访问节点时,可以对其进行转换。 在继续遍历树之前,将使用转换后的节点更新树。

若要定义节点转换,请将静态方法添加到传递到process\u树的basenodetransformer子类中。

  • 您应该定义的方法的名称遵循以下模式:visit\lt;basenode>;, 其中,<;basenode>;应替换为要转换的basenode子类的名称。
  • 方法应返回转换后的节点。

这是一个简单的示例:

classTransformer(BaseNodeTransformer):@staticmethoddefvisit_My_antlr_rule(node):returnnode.name_of_part

自定义节点

自定义节点可以表示已解析语言的一部分,即ast中存在的一种节点。

为了便于返回自定义节点,可以定义aliasnode子类。 通常,aliasnodes的字段类似于导航basenodes的树的符号链接。

自定义节点的实例是从basenode创建的。 源basenode的字段和标签也可以在aliasnode上找到。 如果aliasnode字段名与这些字段名冲突,则在访问该属性时优先。

这就是自定义节点的外观:

classNotExpr(AliasNode):_fields_spec=["expr","op=NOT"]

此代码定义一个自定义节点,notexpr带有exprop字段。

现场规格

\u fields\u spec类属性是一个列表,用于定义自定义节点应具有的字段。

basenode(源节点)创建自定义节点时,如何使用此列表中的字段规范:

  • 如果源节点上不存在字段规范,则将其设置为none
  • 如果多个字段规格定义同一个字段,则使用第一个不none的字段
  • 如果字段规范只是名称,则从源节点复制它
  • 如果字段规范是赋值,则左侧是别名节点上字段的名称 右边是从源节点开始获取节点的路径 这应该是自定义节点上字段的值。 此路径的部分使用
  • 分隔
连接到变压器

要使用此自定义节点,请向转换器添加一个方法:

classTransformer(BaseNodeTransformer):# ...# here the BaseNode name is the same as the custom node name# but that isn't required@staticmethoddefvisit_NotExpr(node):returnNotExpr.from_spec(node)

与其在transformer类上定义方法以使用自定义节点,还可以自动执行此操作:

pip install antlr-ast
0

要使其工作,列表中的aliasnode类应该有一个\u rules类属性 有了一个basenode名称列表,它应该进行转换。

这就是结果:

pip install antlr-ast
1

规则中的项也可以是元组。 在这种情况下,元组中的第一个项是一个basenode名称 第二项是自定义节点的类方法的名称。

在上面的示例中,它并不有用,但它相当于:

pip install antlr-ast
2

使用最后一棵树

很容易使用混合了aliasnodes和动态basenodes的树: 整个树只是一个嵌套的python对象。

在树中搜索节点时,可以考虑节点的优先级。 默认情况下,basenodes具有优先级3,而aliasnodes具有优先级2。

当编写代码使用树时,它可能会受到语法、转换和自定义节点的更改的影响。 语法最有可能改变。

要使语法更新对代码没有影响,请不要依赖打开basenodes。 您仍然可以检查basenodealiasnode父节点是否设置了正确的字段 并在子树中搜索嵌套的别名节点。

如果您确实依赖于basenodes,则可以通过添加aliasnodes来中断代码 如果字段名与已用basenode上的字段名冲突

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java 401在API URL上带有声明性Http客户端,并带有@Secured(SecurityRule.IS_ANONYMOUS)注释   java如何在Android中创建计时器?   Java8WebStart安全弹出窗口   java会通过以下两种方式导致堆空间耗尽吗?   java项目调度GA:染色体的高效数据结构   java Apache POI:如何在Excel文件中插入列   java在JRE系统库中每个jar扮演什么角色   java如何在抽象类中执行@mock(不是注入mock)   java如何使用opensearch和Lucene发送搜索查询?   java在ApachePOI中处理空列   java广播接收器未接收到目标   java错误ELF类:ELF类64(可能原因:体系结构字宽不匹配)   java调用Web服务(SSL)时出错   用于iot集线器设备固件更新的java Rest API   通过xslt将xml转换为文本文件时引发java异常   Java linux打印问题   Java XML转换器重复行   java从另一个类的方法将数组导入mainActivity类   多线程选择与Java交互的线程   我想在java程序中打印以下格式的文件: