查看“Grammars.md”的源代码
←
Grammars.md
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
#语法结构 语法本质上是语法声明,后跟规则列表,但具有一般形式: ``` /** Optional javadoc style comment */ grammar Name; ① options {...} import ... ; tokens {...} channels {...} // lexer only @actionName {...} rule1 // parser and lexer rules, possibly intermingled ... ruleN ``` 包含语法“X”的文件名必须称为“X.g4”。 您可以按任意顺序指定选项、导入、token规范和actions。 选项、导入和token规格最多可以有一个。 除标题外,所有这些元素都是可选的① 至少有一条Rule。 Rule采用基本形式: ``` ruleName : alternative1 | ... | alternativeN ; ``` 解析器规则名称必须以小写字母开头,而lexer规则必须以大写字母开头。 在“grammar”头上没有前缀的语法是组合语法,可以包含词法规则和语法分析器规则。 要创建只允许解析器规则的解析器语法,请使用以下标头。 ``` parser grammar Name; ... ``` 而且,自然地,纯词法语法看起来像这样: ``` lexer grammar Name; ... ``` 只有lexer语法可以包含'mode'规范。 只有词法分析器语法可以包含自定义通道规范 ``` channels { WHITESPACE_CHANNEL, COMMENTS_CHANNEL } ``` 然后可以像lexer规则中的枚举一样使用这些通道: ``` WS : [ \r\t\n]+ -> channel(WHITESPACE_CHANNEL) ; ``` Sections 15.5, [Lexer Rules](http://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference) and Section 15.3, [Parser Rules](http://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference) 包含有关规则语法的详细信息。 15.8节,选项描述了语法选项,15.4节,操作和属性提供了有关语法级操作的信息。 ## 语法导入 语法“imports”允许您将语法分解为逻辑和可重用的块,正如我们在[Importing Grammars]中看到的那样(http://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference). ANTLR对待导入的语法非常类似于面向对象的编程语言对待超类。 语法继承了导入语法中的所有规则,令牌规范和命名操作。 “主语法”中的规则覆盖导入语法中的规则以实现继承。 可以将`import`看作是一条智能的include语句(它不包含已经定义的规则)。 所有导入的结果都是单一的组合语法; ANTLR代码生成器看到了完整的语法,并且不知道有导入的语法。 为了处理主语法,ANTLR工具将所有导入的语法加载到从属语法对象中。 然后,它将规则、令牌类型和命名操作从导入的语法合并到主语法中。 在下图中,右侧的语法说明了语法 'MyELang' 导入语法 'ELang' 的效果。 <img src=images/combined.png width=400> `MyELang`继承规则'stat'、'WS'和'ID',但重写规则'expr'并添加'INT'。 下面的示例构建和测试运行表明,`MyELang`可以识别整数表达式,而原始的`ELang`不能。 第三个错误的输入语句会触发一条错误消息,该消息还表明解析器正在寻找 'myelang' 的expr而不是 'elang'。 ``` $ antlr4 MyELang.g4 $ javac MyELang*.java $ grun MyELang stat => 34; => a; => ; => EOF <= line 3:0 extraneous input ';' expecting {INT, ID} ``` 如果主语法或任何导入的语法中存在模式,那么导入过程将导入这些模式,并在不覆盖它们的地方合并它们的规则。 如果任何模式变为空,因为其所有规则都已被该模式外的规则覆盖,则该模式将被丢弃。 如果有任何 “令牌” 规范,则主要语法将合并令牌集。 如果有任何“通道”规范,主语法将合并通道集。 任何命名的操作(如`@embers`)都将被合并。 通常,您应该避免在导入语法中的规则中指定操作和操作,因为这限制了它们的重用。 ANTLR也会忽略导入语法中的任何选项。 导入的语法也可以导入其他语法。 ANTLR以深度优先的方式追求所有进口语法。 如果两个或多个导入的语法定义了规则“r”,ANTLR将选择它找到的“r”的第一个版本。 在下图中,ANTLR按照`嵌套`、`G1`、`G3`、`G2`的顺序检查语法。 <img src=images/nested.png width=350> “嵌套” 包括来自 “G3” 的 “r” 规则,因为它在 “G2” 中的 “r” 之前看到该版本。 并非每种语法都能导入其他语法: *词法分析器语法可以导入词法分析器,包括包含模式的词法分析器。 * 解析器可以导入解析器。 *组合语法可以导入没有模式的解析器或词法分析器。 ANTLR在主要词法分析器语法中将导入的规则添加到规则列表的末尾。 这意味着主语法中的词法规则优先于导入规则。 例如,如果主语法定义了规则'if:'if';'导入的语法定义了规则“ID:[a-z]+;”(它还识别'if'),导入的'ID'不会隐藏主语法的'if'标记定义。 ## Tokens Section “tokens”部分的目的是定义没有相关词汇规则的语法所需的标记类型。基本语法是: ``` tokens { Token1, ..., TokenN } ``` 大多数情况下,令牌部分用于定义语法中的操作所需的令牌类型,如第10.3节所示。 [Recognizing Languages whose Keywords Aren’t Fixed](http://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference): ``` // 显式定义关键字token类型,避免隐式定义警告 tokens { BEGIN, END, IF, THEN, WHILE } @lexer::members { // lexer中用于分配令牌类型的关键字映射 Map<String,Integer> keywords = new HashMap<String,Integer>() {{ put("begin", KeywordsParser.BEGIN); put("end", KeywordsParser.END); ... }}; } ``` The `tokens` section really just defines a set of tokens to add to the overall set. ``` $ cat Tok.g4 grammar Tok; tokens { A, B, C } a : X ; $ antlr4 Tok.g4 warning(125): Tok.g4:3:4: implicit definition of token X in parser $ cat Tok.tokens A=1 B=2 C=3 X=4 ``` ##语法层面的Action 当前,在语法规则之外仅使用两个定义的命名操作 (用于Java目标): “头” 和 “成员”。 前者在识别器类定义之前将代码注入生成的识别器类文件,后者将代码作为字段和方法注入识别器类定义。 对于组合语法,ANTLR将操作注入解析器和词法分析器。 要将操作限制为生成的解析器或词法程序,请使用 “@ parser:: name” 或“ @ lexer:: name”。 下面是一个语法为生成的代码指定包的示例: ``` grammar Count; @header { package foo; } @members { int count = 0; } list @after {System.out.println(count+" ints");} : INT {count++;} (',' INT {count++;} )* ; INT : [0-9]+ ; WS : [ \r\t\n]+ -> skip ; ``` 语法本身应该在目录`foo`中,以便ANTLR在同一个`foo`目录中生成代码(至少在不使用`-o‘ANTLR工具选项时): ``` $ cd foo $ antlr4 Count.g4 # generates code in the current directory (foo) $ ls Count.g4 CountLexer.java CountParser.java Count.tokens CountLexer.tokens CountBaseListener.java CountListener.java $ javac *.java $ cd .. $ grun foo.Count list => 9, 10, 11 => EOF <= 3 ints ``` Java编译器希望包 “foo” 中的类位于目录 “foo” 中。
返回至“
Grammars.md
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
变体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息