ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ANTLR 4 语法选项与规则选项全解析:从 superClass 到 caseInsensitive 的配置实战

ANTLR 4 语法选项与规则选项全解析:从 superClass 到 caseInsensitive 的配置实战 ANTLR 4 语法选项与规则选项全解析从 superClass 到 caseInsensitive 的配置实战【免费下载链接】antlr4ANTLR (ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files.项目地址: https://gitcode.com/gh_mirrors/an/antlr4本文是 ANTLR 4ANTLR v4即本仓库 antlr4 所实现的工具与运行时中选项系统的完整技术指南。选项是用户在语法grammar层、规则rule层与规则元素rule element层给出的指令用于改变 ANTLR 生成代码的方式。读完本文你将掌握options {}块的书写语法、全部语法级选项superClass、language、tokenVocab、TokenLabelType、contextSuperClass、caseInsensitive、规则级caseInsensitive以及规则元素级选项assoc与fail的配置方式、底层实现与典型使用场景。Options 语法总览在哪里配置值能写什么ANTLR 的选项通过以下通用语法声明注意这是 ANTLR 语法不是目标语言语法options { name1value1; ... nameNvalueN; } // ANTLR not target language syntax其中value可以是以下五种形式之一标识符例如superClassMyBaseParser限定标识符qualified identifier例如a.b.c用于contextSuperClassorg.antlr.v4.runtime.RuleContextWithAltNum这类写法字符串例如languageJava中的值花括号包裹的多行字符串{...}整数。从源码结构看选项被组织成若干集合存放在 tool/src/org/antlr/v4/tool/Grammar.java 中parserOptions/lexerOptions记录语法级选项lexerRuleOptions记录词法规则级选项tokenOptions记录终结符token引用上的选项semPredOptions记录语义谓词上的选项。工具在解析与语义检查阶段会依据这些集合校验选项名是否合法非法选项会报ILLEGAL_OPTION错误。此外还有一个值得注意的细节doNotCopyOptionsToLexer集合superClass、TokenLabelType、tokenVocab表明在**合并语法combined grammar**中这些选项不会被复制到隐式生成的词法器上——这正是下面各节反复强调combined 语法中某些选项只作用于 parser的源码依据。语法级选项既可以在语法文件内用上述options语法设置也可以在命令行调用 ANTLR 工具时通过-D选项传入例如-DsuperClassXX Hi.g4。命令行-D的优先级更高会覆盖语法文件内的同名选项。其解析逻辑位于 tool/src/org/antlr/v4/Tool.java 的handleOptionSetArg方法工具截取-D与之间的选项名只有命中Grammar.parserOptions或Grammar.lexerOptions中的合法选项名才会被写入grammarOptions并最终应用到语法上。-D的完整说明可参见 ANTLR 工具命令行选项。语法级选项Grammar Options所有语法合并语法、纯解析器语法、纯词法器语法均可使用下列选项。在合并语法中除language外的所有选项仅作用于生成的解析器词法器相关的除外。下面逐项说明。superClass设置生成解析器/词法器的父类superClass用于设置生成 parser 或 lexer 的父类在合并语法中它设置的是parser的父类词法器仍默认继承Lexer。示例$ cat Hi.g4 grammar Hi; a : hi ; $ antlr4 -DsuperClassXX Hi.g4 $ grep public class HiParser.java public class HiParser extends XX { $ grep public class HiLexer.java public class HiLexer extends Lexer {从实现看代码生成模型在 tool/src/org/antlr/v4/codegen/model/Recognizer.java 中读取g.getOptionString(superClass)若非空则生成extends对应的父类声明而为空时该字段被置为null走默认继承链。测试框架也大量使用该选项例如 runtime-testsuite/test/org/antlr/v4/test/runtime/RuntimeRunner.java 中会以-DsuperClass...的形式把自定义父类注入到被测语法中。典型场景所有解析器共享一套公共基类如统一的错误处理、日志、上下文持有逻辑此时在语法中写options { superClassMyBaseParser; }或命令行传-DsuperClassMyBaseParser即可。language指定代码生成的目标语言language让 ANTLR 按指定语言生成代码。若 ANTLR 无法生成该语言的代码会看到类似下面的错误$ antlr4 -DlanguageC MyGrammar.g4 error(31): ANTLR cannot generate C code as of version 4.0这是 ANTLR 4 早期版本的示例错误消息C并非 ANTLR 工具直接支持的目标语言。本仓库自带language选项与多种目标语言运行时仓库 runtime 目录下包含 CSharp、Cpp、Dart、Go、JavaScript、Python3、Swift 等实现各目标的具体支持情况与构建方式可参考 目标语言总览 及各目标专属文档如 Java、Go、Python、JavaScript、TypeScript、C、C#、Swift、Dart、PHP。常见的正确用法是$ antlr4 -DlanguageJava T.g4 # Java 是默认目标与语法内options { language...; }相比命令行-Dlanguage...的优势是不改动语法文件即可切换目标语言——这正是 doc/tool-options.md 中强调的用途。tokenVocab从 .tokens 文件引入词法符号编号ANTLR 在解析语法文件时会按遇到 token 的顺序为它们分配 token 类型编号。当你希望采用另一套编号例如与独立词法器保持一致时用tokenVocab选项拉取对应的.tokens文件。ANTLR 会从每个语法生成一个语法名.tokens文件每行格式为TOKEN_NAMEtype。完整示例独立词法器 独立解析器如下$ cat SomeLexer.g4 lexer grammar SomeLexer; ID : [a-z] ; $ cat R.g4 parser grammar R; options {tokenVocabSomeLexer;} tokens {A,B,C} // normally, these would be token types 1, 2, 3 a : ID ; $ antlr4 SomeLexer.g4 $ cat SomeLexer.tokens ID1 $ antlr4 R.g4 $ cat R.tokens A2 B3 C4 ID1注意输出中的编号没有tokenVocab时tokens {A,B,C}会依次得到 1、2、3但因为R.g4通过tokenVocabSomeLexer引入了ID1A、B、C 顺延为 2、3、4而ID沿用词法器的编号 1从而保证两个文件对同一 token 的编号完全一致。这正是词法器与解析器分离时保持符号表同步的机制。从实现看.tokens文件的加载由 tool/src/org/antlr/v4/parse/TokenVocabParser.java 完成loadTokenVocab返回名称 → 类型号的映射而 Tool.java 中的sortGrammarByTokenVocab会按tokenVocab依赖对命令行中的多个语法排序确保被依赖的语法如SomeLexer.g4先被处理并产出.tokens文件。另外工具还会让生成目标对tokenVocab引用的文件建立构建依赖见 BuildDependencyGenerator.java。TokenLabelType自定义 token 变量的类型默认情况下ANTLR 在生成代码时凡是引用 token 的变量如规则参数、带标签的元素字段都使用Token类型。如果你向 parser/lexer 注入了自定义的TokenFactory使它们创建的是自定义 token 子类就应把TokenLabelType设为该具体类型这样上下文对象context objects的字段与方法返回值就能使用你的自定义类型。示例$ cat T2.g4 grammar T2; options {TokenLabelTypeMyToken;} a : xID ; $ antlr4 T2.g4 $ grep MyToken T2Parser.java public MyToken x;生成的T2Parser中标签x对应的字段类型即为MyToken。从源码结构看该选项通过 tool/src/org/antlr/v4/codegen/model/OutputFile.java 读取g.getOptionString(TokenLabelType)并同时用于TokenLabelType与InputSymbolType两个生成模型字段贯穿输出文件的类型声明。contextSuperClass解析树内部节点的父类contextSuperClass指定解析树内部节点rule context 类的父类默认是ParserRuleContext。该父类最终至少应派生自RuleContext。Java 目标可直接使用内置的contextSuperClassorg.antlr.v4.runtime.RuleContextWithAltNum来获得便利它为规则节点增加一个altNumber后备字段用于记录该规则节点实际匹配的分支编号。实现上代码生成模型在 tool/src/org/antlr/v4/codegen/model/ParserFile.java 中读取该选项并注入到生成类的继承声明中。此选项常用于需要精确区分匹配了哪一个 alternative的自定义遍历或解释器场景。caseInsensitive大小写不敏感词法器4.10 起支持自 ANTLR 4.10 起可用语法级选项让整个词法器对大小写不敏感。例如下面这个支持多语言关键词/词元的词法器lexer grammar L; options { caseInsensitive true; } ENGLISH_TOKEN: [a-z]; GERMAN_TOKEN: [äéöüß]; FRENCH_TOKEN: [àâæ-ëîïôœùûüÿ]; CROATIAN_TOKEN: [ćčđšž]; ITALIAN_TOKEN: [àèéìòù]; SPANISH_TOKEN: [áéíñóúü¡¿]; GREEK_TOKEN: [α-ω]; RUSSIAN_TOKEN: [а-я]; WS: [ ] - skip;它可以匹配诸如以下的大小写混合输入abcXYZ äéöüßÄÉÖÜß àâæçÙÛÜŸ ćčđĐŠŽ àèéÌÒÙ áéÚÜ¡¿ αβγΧΨΩ абвЭЮЯ需要明确两个边界只做单字符等价处理ANTLR 仅考虑一个字符 ↔ 一个字符的映射。例如德语小写ß不会被当作大写SS反之亦然ß与SS是多字符映射超出本机制范围输入无需预转换机制是自动把语法中对字符的引用改写为大/小写等价形式例如a变为[aA]因此你不必把输入字符先转成大写——token 的文本仍与输入流中的原始内容一致。底层原理源码级佐证tool/src/org/antlr/v4/automata/LexerATNFactory.java 的checkRangeAndAddToSet在caseInsensitive开启时会把一个字符区间拆成小写区间与大写区间两部分分别加入字符集随后createTransition同文件 L604 起针对单一区间生成码点范围转移对拆分后的情形生成SetTransition。这就是a自动变成[aA]的实际实现——它发生在 ATN 构造阶段而非运行时的字符串折叠。该行为的回归测试可参见 tool-testsuite/test/org/antlr/v4/test/tool/TestParserExec.java 中的testCaseInsensitiveInCombinedGrammar在合并语法中使用options { caseInsensitive true; }。规则级选项Rule Options规则级选项目前只有一个且仅适用于词法规则。caseInsensitive词法规则级工具支持在单个词法规则上使用caseInsensitive选项其语义与语法级caseInsensitive相同但作用域收窄到该规则并覆盖语法级的值。详细说明见 词法规则文档中的 caseInsensitive 一节。典型用法是在全局开启大小写不敏感的同时为个别规则关闭它例如options { caseInsensitivetrue; } STRING options { caseInsensitivefalse; } : N? \ (~\ | \\)* \; // lower n is not allowed即全局不区分大小写但STRING规则强制区分N前缀不再接受小写n。源码层面的支持体现在两处其一Grammar.java 的lexerRuleOptions集合只登记了caseInsensitive且每个词法规则对象持有独立的caseInsensitive布尔字段Rule.java其二语义检查阶段BasicSemanticChecks.java会检测规则级值与语法级值相同的冗余情况并给出警告REDUNDANT_CASE_INSENSITIVE_LEXER_RULE_OPTION参见 ErrorType.java。规则元素级选项Rule Element Options规则元素上的选项写在元素的尖括号中形如Tnamevalue。目前存在两类终结符引用上的assoc以及语义谓词上的fail。assoc控制结合性与优先级终结符选项目前只有assoc接受left与right两个值。下面是一个带左递归表达式规则的示例语法它把^幂运算符标记为右结合grammar ExprLR; expr : expr ^assocright expr | expr * expr // match subexpressions joined with * operator | expr expr // match subexpressions joined with operator | INT // matches simple integer atom ; INT : 0..9 ; WS : [ \n] - skip ;现代用法提示结合性说明现在更推荐写在整个 alternative 上而非单个 token 引用上例如|assocright e ? e : e详见 左递归与结合性文档。为兼容旧语法assocright仍然允许出现在 token 引用上但会被忽略并产生提示性警告警告编号 157见 TestToolSyntaxErrors.java 中的示例。源码结构佐证tokenOptions集合在 Grammar.java 中登记了assoc与tokenIndex后者供左递归规则重写内部使用语义检查在 BasicSemanticChecks.java 的checkElementOptions中校验assoc是否被放在合法的 alternative 位置否则报UNRECOGNIZED_ASSOC_OPTION。fail指定语义谓词失败时的报错消息语义谓词也接受选项参见《The Definitive ANTLR 4 Reference》关于捕获失败语义谓词的讨论目前唯一合法选项是fail。它接受两种值双引号字符串字面量谓词失败时直接发出该字符串作为消息返回字符串的 action谓词失败时执行该 action用其求值得到的字符串作为消息。示例带参数的规则限制整数列表长度ints[int max] locals [int i1] : INT ( , {$i;} {$i$max}?fail{exceeded max $max} INT )* ;当第i个整数超过max时谓词{$i$max}?失败随即报出消息exceeded max max 的值。fail的值也可以是函数调用形式例如{...}?fail{doSomethingAndReturnAString()}action 既执行函数又返回字符串。源码佐证tool/src/org/antlr/v4/codegen/model/SemPred.java 专门处理该选项若failNode是ActionAST则通过ActionTranslator.translateAction把 action 翻译成目标语言代码块failChunks若是字符串字面量则经getTargetStringLiteralFromANTLRStringLiteral转成目标语言的字符串常量msg。同时SemPred会剥离谓词两端的{与}?得到纯谓词表达式保证生成的sempred方法与报错逻辑分离。总结如何选择配置位置把语法级选项放入options {}块适合该语法本身就应如此的固定行为而用命令行-Doptionvalue覆盖则适合同一语法、多套生成要求的场景例如同一.g4分别生成 Java 与 Python 目标或临时切换superClass且-D的优先级高于语法内声明。规则级caseInsensitive用于在全局大小写不敏感的基础上做局部收窄元素级assoc与fail则把粒度进一步降到单个运算符与单个谓词。选项的合法集合由工具源码Grammar.java统一定义并校验非法选项会在工具执行阶段直接报错因此编写语法时务必对照本文与 tool-options.md 确认拼写与取值范围。【免费下载链接】antlr4ANTLR (ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files.项目地址: https://gitcode.com/gh_mirrors/an/antlr4创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表