antlr解析器的ast整形
antlr-ast的Python项目详细描述
antlr ast
这个包允许您使用antlr语法并使用解析器输出生成抽象语法树(ast)。
安装
pip install antlr-ast
注意:此软件包与python2不兼容。
运行测试
# may need:# pip install pytest py.test
用法
使用antlr ast需要四个步骤:
- 使用antlr定义语法并生成必要的python文件来解析此语法
- 使用
parse
根据生成的语法文件获取antlr运行时输出 - 在上一步的输出上使用
process_tree
- a
baseastvisitor
(通过提供子类可自定义)将antlr输出转换为basenode
s的可序列化树, 根据antlr语法中的规则动态创建 - 子类可以用来转换每种类型的节点
- "简化"选项可用于通过跳过只有一个子体的节点来缩短树中的路径
- a
- 使用生成的树
接下来的部分将详细介绍这些步骤。
要可视化创建和转换这些解析树的过程,可以使用此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将遍历从根节点到叶节点的树。 访问节点时,可以对其进行转换。 在继续遍历树之前,将使用转换后的节点更新树。
若要定义节点转换,请将静态方法添加到传递到 这是一个简单的示例: 自定义节点可以表示已解析语言的一部分,即ast中存在的一种节点。 为了便于返回自定义节点,可以定义 自定义节点的实例是从 这就是自定义节点的外观: 此代码定义一个自定义节点, 从 要使用此自定义节点,请向转换器添加一个方法: 与其在transformer类上定义方法以使用自定义节点,还可以自动执行此操作: 要使其工作,列表中的 这就是结果: 规则中的项也可以是元组。
在这种情况下,元组中的第一个项是一个 在上面的示例中,它并不有用,但它相当于: 很容易使用混合了 在树中搜索节点时,可以考虑节点的优先级。
默认情况下, 当编写代码使用树时,它可能会受到语法、转换和自定义节点的更改的影响。
语法最有可能改变。 要使语法更新对代码没有影响,请不要依赖打开 如果您确实依赖于basenodeprocess\u树的
basenodetransformer
子类中。
visit\lt;basenode>;
,
其中,<;basenode>;
应替换为要转换的basenode
子类的名称。classTransformer(BaseNodeTransformer):@staticmethoddefvisit_My_antlr_rule(node):returnnode.name_of_part
自定义节点
aliasnode
子类。
通常,aliasnode
s的字段类似于导航basenode
s的树的符号链接。basenode
创建的。
源basenode
的字段和标签也可以在aliasnode
上找到。
如果aliasnode
字段名与这些字段名冲突,则在访问该属性时优先。classNotExpr(AliasNode):_fields_spec=["expr","op=NOT"]
notexpr
带有expr
和op
字段。现场规格
\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)
pip install antlr-ast
0
aliasnode
类应该有一个\u rules
类属性
有了一个basenode
名称列表,它应该进行转换。pip install antlr-ast
1
basenode
名称
第二项是自定义节点的类方法的名称。pip install antlr-ast
2
使用最后一棵树
aliasnode
s和动态basenode
s的树:
整个树只是一个嵌套的python对象。basenode
s具有优先级3,而aliasnode
s具有优先级2。basenode
s。
您仍然可以检查basenode
的aliasnode
父节点是否设置了正确的字段
并在子树中搜索嵌套的别名节点。s,则可以通过添加
aliasnode
s来中断代码
如果字段名与已用
basenode
上的字段名冲突推荐PyPI第三方库