<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=Grammars.md</id>
	<title>Grammars.md - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=Grammars.md"/>
	<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Grammars.md&amp;action=history"/>
	<updated>2026-04-05T01:52:34Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>http://wiki.foofun.cn//index.php?title=Grammars.md&amp;diff=679&amp;oldid=prev</id>
		<title>2022年2月23日 (三) 02:58 Zhang3</title>
		<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Grammars.md&amp;diff=679&amp;oldid=prev"/>
		<updated>2022-02-23T02:58:39Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;http://wiki.foofun.cn//index.php?title=Grammars.md&amp;amp;diff=679&amp;amp;oldid=675&quot;&gt;显示更改&lt;/a&gt;</summary>
		<author><name>Zhang3</name></author>
	</entry>
	<entry>
		<id>http://wiki.foofun.cn//index.php?title=Grammars.md&amp;diff=675&amp;oldid=prev</id>
		<title>2022年2月22日 (二) 08:48 Zhang3</title>
		<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Grammars.md&amp;diff=675&amp;oldid=prev"/>
		<updated>2022-02-22T08:48:26Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2022年2月22日 (二) 08:48的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;第1行：&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;第1行：&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;{{MARKDOWN}}&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;#语法结构&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;#语法结构&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Zhang3</name></author>
	</entry>
	<entry>
		<id>http://wiki.foofun.cn//index.php?title=Grammars.md&amp;diff=674&amp;oldid=prev</id>
		<title>Zhang3：创建页面，内容为“#语法结构  语法本质上是语法声明，后跟规则列表，但具有一般形式:  ``` /** 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。 选项、导入和…”</title>
		<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Grammars.md&amp;diff=674&amp;oldid=prev"/>
		<updated>2022-02-22T08:47:41Z</updated>

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