grammars-v4 仓库中 Python3 目标语法生成指南:transformGrammar.py 与 ANTLR4 基类全解析
grammars-v4 仓库中 Python3 目标语法生成指南transformGrammar.py 与 ANTLR4 基类全解析【免费下载链接】grammars-v4Grammars written for ANTLR v4; expectation that the grammars are free of actions.项目地址: https://gitcode.com/gh_mirrors/gr/grammars-v4本篇指南围绕 grammars-v4 仓库中 python/python/Python3/README.md 所述的目标定制流程展开讲解如何在本地为 Python3 目标生成词法/语法分析器先运行transformGrammar.py完成语法文件的“目标化改写”再以-DlanguagePython3调用 ANTLR4 工具生成代码并配套使用仓库提供的PythonLexerBase/PythonParserBase基类。读完本文你将掌握这套“共享语法 目标定制脚本 语言基类”的完整流水线理解this.到self.改写背后的原理并能在自己的项目中复现同样流程。背景为什么需要“目标特定的语法指令”grammars-v4 仓库中 python/python 目录维护着一套支持 Python 2 / Python 3 的“通用语法”universal grammar。它的核心设计是一份.g4源语法通过不同语言子目录下的transformGrammar.py脚本与基类代码适配到不同的 ANTLR 运行时目标。从 python/python/desc.xml 可以看到该目录声明的目标语言为CSharp;Java;Python3而 python/python/Python3 子目录正是面向 Python3 运行时的那一份。其 README 开门见山地指出本目录包含“目标特定解析器的基类代码”使用时必须先在语法文件上执行一次“目标改写”transform再交给 ANTLR4 生成器。这正是本文要复现的两步流程。第一步运行 transformGrammar.py 改写语法文件命令与用法按照 python/python/Python3/README.md 的说明在python/python/Python3目录下依次执行python transformGrammar.py antlr4 -DlanguagePython3 -o gen *.g4第一条命令运行目标改写脚本第二条命令用 ANTLR4 工具生成 Python3 目标的代码输出到gen目录。注意命令中的*.g4会匹配当前目录下的PythonLexer.g4与PythonParser.g4两份语法文件。脚本内部做了什么查看 python/python/Python3/transformGrammar.py 源码核心逻辑非常简洁main()依次对PythonLexer.g4和PythonParser.g4调用fix()而fix()逐行扫描文件内容执行两类文本替换if !this. in x: x x.replace(!this., not self.) if this. in x: x x.replace(this., self.)也就是说脚本会把语法内嵌动作actions中的this.替换为self.把!this.替换为not self.。为什么要这样替换因为这份语法是多目标共享的语法文件里的动作代码最初是按 Java 等“类名引用自身”的语法书写的如this.IncIndentLevel()而 Python 对象方法内部访问自身必须使用self。脚本在生成前做一次机械替换就避免了为每个目标维护一份语法副本。另外两个细节值得注意实现事实见 transformGrammar.py脚本先把原文件shutil.move为xxx.g4.bak备份再写回xxx.g4因此执行后目录中会留下.bak备份文件脚本对每个被改写的文件打印Altering 文件名与Writing ...若找不到文件会报错并以退出码 1 终止。作为对照面向 C 目标的 python/python/Cpp/transformGrammar.py 除了把this.替换为this-之外还会把语法中的// Insert here header for C lexer./parser.占位注释替换为header {#include PythonLexerBase.h}/#include PythonParserBase.h。这说明transformGrammar.py是每个目标各有一份的定制脚本职责是“把共享语法改写为目标运行时能直接编译的形式”。第二步生成代码并接入基类ANTLR4 生成命令拆解antlr4 -DlanguagePython3 -o gen *.g4参数含义-DlanguagePython3指定生成目标为 Python3 运行时需已安装antlr4-python3-runtime-o gen把生成的词法/语法分析器代码输出到gen子目录*.g4输入语法文件。生成结束后按 python/python/README.md 的“How to use”说明还需要把生成的代码与基类代码一并加入项目——基类就是本目录下的 python/python/Python3/PythonLexerBase.py 与 python/python/Python3/PythonParserBase.py。语法文件通过options { superClass PythonLexerBase; }与options { tokenVocab PythonLexer; superClass PythonParserBase; }指定基类见 PythonLexer.g4 与 PythonParser.g4生成的类会继承这些基类。基类承担的“脏活”缩进与版本Python 词法分析最大的难点是缩进敏感INDENT/DEDENT不是文本字符而是由空白推导出的虚拟 token。这个逻辑被完整封装在 PythonLexerBase.py 中HandleNewLine()把换行转发为隐藏通道上的NEWLINEtoken并触发缩进处理HandleSpaces()在行首空白处按 Python 规范计算缩进量——注释中引用了官方规则“Tabs are replaced by one to eight spaces ... multiple of eight”即 Tab 按 8 列对齐计算随后调用__process_new_line()决定发射LINE_BREAK、INDENT或DEDENTIncIndentLevel()/DecIndentLevel()与语法中括号规则的 action 对应——PythonLexer.g4 中OPEN_PAREN、OPEN_BRACE、OPEN_BRACKET分别调用{this.IncIndentLevel();}闭合括号调用{this.DecIndentLevel();}用于记录“括号内无需缩进分析”的嵌套层级nextToken()覆写在遇到EOF且仍存在未闭合缩进栈时先补发LINE_BREAK再逐个弹出并发射DEDENT从而正确结束代码块。这类动作正是transformGrammar.py必须把this.改写为self.的原因——改写前的动作代码在 Python 运行时中无法直接执行。解析器侧 PythonParserBase.py 则承载“Python 2 / Python 3 版本自适应”PythonVersion枚举定义Autodetect 0、Python2 2、Python3 3version属性默认Autodetect可通过 setter 赋值PythonVersion或整数_check_version()在Autodetect时恒返回True否则比较指定版本set_version()在解析过程中把版本“钉死”为已确认的版本。解析器语法中大量使用了这些谓词与动作例如 PythonParser.g4 的except_clause规则except_clause : EXCEPT ( test ( {this.CheckVersion(2)}? COMMA name {this.SetVersion(2);} | {this.CheckVersion(3)}? AS name {this.SetVersion(3);} )? )? COLON suite ;except E, ePython 2 写法与except E as ePython 3 写法共享同一条规则靠谓词选择分支并在命中后把版本切换为对应值。类似地PRINT/EXECPython 2与NONLOCALPython 3语句也通过{this.CheckVersion(2)}/{this.CheckVersion(3)}谓词做版本门控见 PythonParser.g4。因此不手动设置版本时语法以Autodetect起步解析过程中遇到第一个版本特征语句即自动锁定若要强制指定可在创建解析器后直接设置Version属性对应 README 中Autodetect、Python2、Python3三个取值。另外python/python/README.md 还提到词法器侧有一个TabSize配置项README 示例为 8 空格Python3 目录的 PythonLexerBase.py 中tab_size 4不同目标基类的默认值以对应目录源码为准用于控制 Tab 折算为空格的对齐宽度可直接影响缩进计算与INDENT/DEDENT的判定结果。三步集成到自己的项目综合 README 与源码把这份 Python 语法接入 Python3 项目的完整步骤为生成代码进入 python/python/Python3 目录先执行python transformGrammar.py完成this.→self.改写再执行antlr4 -DlanguagePython3 -o gen *.g4生成到gen/引入代码将gen/下生成的词法/语法分析器连同 PythonLexerBase.py 与 PythonParserBase.py 一起复制进工程保证导入路径可见并确保安装了antlr4-python3-runtime按需配置默认使用缩进栈 Autodetect版本即可解析绝大多数代码如需固定版本通过解析器基类的version属性Python2/Python3显式指定如需调整 Tab 语义修改词法器基类的tab_size。仓库在 python/python/examples 提供了funcdef.py、classdef.py、with_stmt.py、try_stmt.py、yield_expr.py、comprehension.py等 27 个示例文件覆盖函数/类定义、语句块、推导式、异常与with语句等典型语法结构可作为生成后冒烟测试的输入验证INDENT/DEDENT与版本分支是否按预期工作。小结python/python/Python3/README.md 虽然简短却浓缩了 grammars-v4 多目标语法维护的核心思想一份语法文件 每目标一份 transform 脚本 每目标一份运行时基类。transformGrammar.py负责把this.机械改写为self.C 目标则改写为this-并注入headerPythonLexerBase负责缩进敏感的INDENT/DEDENT虚拟 token 生成PythonParserBase负责 Python 2/3 语法差异的自适应。理解这三者的分工你不仅能顺利复现本目录的生成流程也能把同样的“改写脚本 基类”模式迁移到其他目标语言如仓库中的 python/python/CSharp、python/python/Cpp、python/python/Java 目录或其他共享语法项目上。【免费下载链接】grammars-v4Grammars written for ANTLR v4; expectation that the grammars are free of actions.项目地址: https://gitcode.com/gh_mirrors/gr/grammars-v4创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考