<?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=Parser-rules.md</id>
	<title>Parser-rules.md - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=Parser-rules.md"/>
	<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Parser-rules.md&amp;action=history"/>
	<updated>2026-04-07T18:27:46Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>http://wiki.foofun.cn//index.php?title=Parser-rules.md&amp;diff=680&amp;oldid=prev</id>
		<title>Zhang3：创建页面，内容为“{{MARKDOWN}} # Parser Rules（解析器中的规则）  Parsers由一组在parser/combined grammar 中的Parser Rules组成的。 Java应用程序通过调用由ANTLR生成的与所需启动rule相关联的rule function来启动Parser。 最基本的rule只是一个rule名称，后跟以分号终止的单个alternative:  ```  	/** Javadoc注释可以位于rule之前 */  	retstat : 'return' expr ';' ; ```  Rules也可以有由|分割  ``` operator:  	stat: retst…”</title>
		<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Parser-rules.md&amp;diff=680&amp;oldid=prev"/>
		<updated>2022-02-23T07:22:20Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“{{MARKDOWN}} # Parser Rules（解析器中的规则）  Parsers由一组在parser/combined grammar 中的Parser Rules组成的。 Java应用程序通过调用由ANTLR生成的与所需启动rule相关联的rule function来启动Parser。 最基本的rule只是一个rule名称，后跟以分号终止的单个alternative:  ```  	&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;* Javadoc注释可以位于rule之前：&lt;/span&gt;  	retstat : &amp;#039;return&amp;#039; expr &amp;#039;;&amp;#039; ; ```  Rules也可以有由|分割  ``` operator:  	stat: retst…”&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{MARKDOWN}}&lt;br /&gt;
# Parser Rules（解析器中的规则）&lt;br /&gt;
&lt;br /&gt;
Parsers由一组在parser/combined grammar 中的Parser Rules组成的。 Java应用程序通过调用由ANTLR生成的与所需启动rule相关联的rule function来启动Parser。 最基本的rule只是一个rule名称，后跟以分号终止的单个alternative:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
 	/** Javadoc注释可以位于rule之前 */&lt;br /&gt;
 	retstat : 'return' expr ';' ;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Rules也可以有由|分割&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
operator:&lt;br /&gt;
 	stat: retstat&lt;br /&gt;
 	| 'break' ';'&lt;br /&gt;
 	| 'continue' ';'&lt;br /&gt;
 	;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Alternatives要么是rule元素列表，要么是空的。 例如，这里有一个带有空替代项的rule，使整个规则成为可选规则：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
superClass&lt;br /&gt;
 	: 'extends' ID&lt;br /&gt;
 	| // 为空表示其他alternative是可选的&lt;br /&gt;
 	;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Alternative Labels （候选标记）&lt;br /&gt;
&lt;br /&gt;
正如我们在第7.4节中看到的那样，针对Precise Event Methods的Labeling Rule Alternatives，我们可以通过使用#符号来labeling一个rule的outermost alternatives来获得更精确的parse-tree listener事件。 Rule中的所有alternatives都必须labeled，或者一个都不labeled。 以下是两条带有labeled alternatives的Rules。&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
grammar T;&lt;br /&gt;
stat: 'return' e ';' # Return&lt;br /&gt;
 	| 'break' ';' # Break&lt;br /&gt;
 	;&lt;br /&gt;
e   : e '*' e # Mult&lt;br /&gt;
    | e '+' e # Add&lt;br /&gt;
    | INT # Int&lt;br /&gt;
    ;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Alternative labels不必在行的末尾，并且在#符号之后也不必有空格。&lt;br /&gt;
ANTLR为每个Label生成Rule上下文类定义。例如，以下是ANTLR生成的listener：&lt;br /&gt;
&lt;br /&gt;
```java&lt;br /&gt;
public interface AListener extends ParseTreeListener {&lt;br /&gt;
 	void enterReturn(AParser.ReturnContext ctx);&lt;br /&gt;
 	void exitReturn(AParser.ReturnContext ctx);&lt;br /&gt;
 	void enterBreak(AParser.BreakContext ctx);&lt;br /&gt;
 	void exitBreak(AParser.BreakContext ctx);&lt;br /&gt;
 	void enterMult(AParser.MultContext ctx);&lt;br /&gt;
 	void exitMult(AParser.MultContext ctx);&lt;br /&gt;
 	void enterAdd(AParser.AddContext ctx);&lt;br /&gt;
 	void exitAdd(AParser.AddContext ctx);&lt;br /&gt;
 	void enterInt(AParser.IntContext ctx);&lt;br /&gt;
 	void exitInt(AParser.IntContext ctx);&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
有与每个labeled alternative相关联的enter和exit方法。 这些方法的参数特定于alternatives。&lt;br /&gt;
&lt;br /&gt;
您可以在多个alternatives上重复使用相同的Label，以指示parse tree walker应该为这些alternatives触发相同的事件。 例如，以下是上述grammar A中Rule e的变体：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
 	e : e '*' e # BinaryOp&lt;br /&gt;
 	| e '+' e # BinaryOp&lt;br /&gt;
 	| INT # Int&lt;br /&gt;
 	;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ANTLR将为e生成以下listener方法:&lt;br /&gt;
&lt;br /&gt;
```java&lt;br /&gt;
 	void enterBinaryOp(AParser.BinaryOpContext ctx);&lt;br /&gt;
 	void exitBinaryOp(AParser.BinaryOpContext ctx);&lt;br /&gt;
 	void enterInt(AParser.IntContext ctx);&lt;br /&gt;
 	void exitInt(AParser.IntContext ctx);&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
如果alternative名称与rule名称冲突，ANTLR会给出错误。 下面是rule e的另一个重写，其中两个alternative labels与rule名称冲突：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
 	e : e '*' e # e&lt;br /&gt;
 	| e '+' e # Stat&lt;br /&gt;
 	| INT # Int&lt;br /&gt;
 	;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
从rule名称和Label生成的上下文对象大写，因此label Stat与rule stat冲突:（译者注：这里Stat是更前面的代码示例里面的）&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
 	$ antlr4 A.g4&lt;br /&gt;
 	error(124): A.g4:5:23: rule alt label e conflicts with rule e&lt;br /&gt;
 	error(124): A.g4:6:23: rule alt label Stat conflicts with rule stat&lt;br /&gt;
 	warning(125): A.g4:2:13: implicit definition of token INT in parser&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
##  Rule Context Objects（rule上下文对象）&lt;br /&gt;
&lt;br /&gt;
ANTLR会生成用于访问与每个rule reference相关联的rule context objects (parse tree nodes) 的方法。 对于具有单个rule reference的rule，ANTLR生成没有参数的方法。 考虑下面的rule。&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
 	inc : e '++' ;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ANTLR生成此上下文类：&lt;br /&gt;
&lt;br /&gt;
```java&lt;br /&gt;
public static class IncContext extends ParserRuleContext {&lt;br /&gt;
 	public EContext e() { ... } // 返回与e关联的上下文对象&lt;br /&gt;
 	...&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
当对rule有多个reference时，ANTLR还提供访问上下文对象的支持:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
field : e '.' e ;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ANTLR生成一个方法，该方法具有访问第i个元素的索引，以及获取该规则所有引用的上下文的方法：&lt;br /&gt;
&lt;br /&gt;
```java&lt;br /&gt;
public static class FieldContext extends ParserRuleContext {&lt;br /&gt;
 	public EContext e(int i) { ... } // get ith e context&lt;br /&gt;
 	public List&amp;lt;EContext&amp;gt; e() { ... } // return ALL e contexts&lt;br /&gt;
 	...&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
如果我们有另一个rule s，references到field，则嵌入式action可以访问e rule匹配项列表，该列表可由field使用：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
s : field&lt;br /&gt;
 	{&lt;br /&gt;
 	List&amp;lt;EContext&amp;gt; x = $field.ctx.e();&lt;br /&gt;
 	...&lt;br /&gt;
 	}&lt;br /&gt;
;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
listener或visitor也可以做同样的事情。 指向FieldContext的f对象后，f.e()将返回List&amp;lt;EContext&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
## Rule Element Labels（Rule元素标记）&lt;br /&gt;
&lt;br /&gt;
您可以使用=符号来label rule元素（译者注：label做动词，标记），以向rule上下文对象添加字段：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
stat: 'return' value=e ';' # Return&lt;br /&gt;
 	| 'break' ';' # Break&lt;br /&gt;
 	;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
这里，value是对rule e返回值的label，该返回值已在其他地方定义。&lt;br /&gt;
Labels成为适当的解析树节点类中的字段。 在这种情况下，由于使用ReturnContext替代Label，Label Value将成为ReturnContext中的一个字段：&lt;br /&gt;
&lt;br /&gt;
```java&lt;br /&gt;
public static class ReturnContext extends StatContext {&lt;br /&gt;
 	public EContext value;&lt;br /&gt;
 	...&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
跟踪大量令牌通常很方便，可以使用+=“list label”操作符来完成。 例如，以下规则创建与简单数组结构匹配的令牌对象列表：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
 	array : '{' el+=INT (',' el+=INT)* '}' ;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ANTLR在适当的Rule上下文类中生成列表字段:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
 	public static class ArrayContext extends ParserRuleContext {&lt;br /&gt;
 	public List&amp;lt;Token&amp;gt; el = new ArrayList&amp;lt;Token&amp;gt;();&lt;br /&gt;
 	...&lt;br /&gt;
 	}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
这些Label列表也适用于rule references：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
 	elist : exprs+=e (',' exprs+=e)* ;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ANTLR生成一个保存上下文对象列表的字段：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
 	public static class ElistContext extends ParserRuleContext {&lt;br /&gt;
 	public List&amp;lt;EContext&amp;gt; exprs = new ArrayList&amp;lt;EContext&amp;gt;();&lt;br /&gt;
 	...&lt;br /&gt;
 	}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Rule元素&lt;br /&gt;
&lt;br /&gt;
Rule元素指定parser在给定时刻应该做什么，就像编程语言中的语句一样。 元素可以是rule、token、string literal，如表达式、ID和‘return’。 以下是rule元素的完整列表 (稍后我们将详细介绍actions和predicates):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;th&amp;gt;Syntax&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;T&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
在当前输入位置匹配TokenT。Token始终以大写字母开头。&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;’literal’&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
在当前输入位置匹配string literal。string literal只是带有固定字符串的token&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;r&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
在当前输入位置匹配Rule r，这相当于像调用函数一样调用Rule。Parser rule名称始终以小写字母开头。&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;r [«args»]&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
在当前输入位置匹配Rule r，传递参数列表就像函数调用一样。 方括号内的参数采用目标语言的语法，通常是一个逗号分隔的表达式列表&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;{«action»}&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
在备选元素之前或之后的执行一个action。 该action符合目标语言的语法。 除了替换$x和$x.y等属性和token引用之外，ANTLR会将操作代码逐字复制到生成的类中。&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;{«p»}?&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
运行语义谓词 «p»。 如果«p»在运行时的计算结果为false，则不要继续分析谓词。 预测期间遇到的谓词，当ANTLR区分备选方案时，启用或禁用谓词周围的备选方案。&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;.&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
匹配除文件结尾以外的任何单个Token。“点” 运算符称为通配符。&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
如果要匹配除特定Token或Token集之外的所有内容，请使用`~` “非”运算符。 此操作符在解析器中很少使用，但可用。 '~ INT' 匹配除 'INT' Token以外的任何Token。' ~ '，''匹配除逗号以外的任何Token。 `~（INT | ID）`匹配除INT或ID之外的任何Token。&lt;br /&gt;
&lt;br /&gt;
Token、string literal和semantic predicate rule元素可以接受选项。 请参阅规则元素选项。&lt;br /&gt;
&lt;br /&gt;
## Subrules（子规则）&lt;br /&gt;
&lt;br /&gt;
Rule可以包含称为Subrules的alternative块（在扩展BNF Notation：EBNF中允许）。 subrule类似于缺少名称并用括号括起来的规则。 Subrules可以在括号内有一个或多个alternatives。 Subrules不能像rules一样使用局部变量定义属性和返回值。 有四种子规则(x、y和z表示语法片段)：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;th&amp;gt;Syntax&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;img src=images/xyz.png&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;(x|y|z).&lt;br /&gt;
精确匹配子规则中的任何选项一次。例子：&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
returnType : (type | 'void') ;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;img src=images/xyz_opt.png&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;(x|y|z)?&lt;br /&gt;
子规则中不匹配任何项或任何alternative。示例：&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;	&lt;br /&gt;
classDeclaration&lt;br /&gt;
    : 'class' ID (typeParameters)? ('extends' type)?&lt;br /&gt;
      ('implements' typeList)?&lt;br /&gt;
 	   classBody&lt;br /&gt;
    ;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;img src=images/xyz_star.png&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;(x|y|z)*&lt;br /&gt;
在子零次或更多次内匹配alternative。示例:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
annotationName : ID ('.' ID)* ;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;	&lt;br /&gt;
&amp;lt;td&amp;gt;&amp;lt;img src=images/xyz_plus.png&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;(x|y|z)+&lt;br /&gt;
将subrule中的alternative匹配一次或多次。例子：&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
annotations : (annotation)+ ;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
您可以将 `?`, `*`, 和 `+`  subrule运算符加上非贪心匹配运算符后缀，和正则表达式一样也是一个问号: `??`, `*?`, 和 `+?`。 参见第15.6节，Wildcard Operator and Nongreedy Subrules（通配符运算符和非通配符子规则）。&lt;br /&gt;
&lt;br /&gt;
作为速记，您可以省略由具有单个Rule元素引用的单个alternative组成的subrole的括号。 例如`annotation+` 与 `(annotation)+` 相同，`ID+` 与 `(ID)+` 相同。 Labels也可以使用简写法。`ids+=INT+`产生`INT`token对象列表。&lt;br /&gt;
&lt;br /&gt;
## 捕获异常&lt;br /&gt;
&lt;br /&gt;
当规则中出现语法错误时，ANTLR会捕获异常，报告错误，尝试恢复(可能通过使用更多Token)，然后从rule返回。 每个rule都包装在 “try/catch/finalally” 语句中:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
void r() throws RecognitionException {&lt;br /&gt;
 	try {&lt;br /&gt;
 		rule-body&lt;br /&gt;
 	}&lt;br /&gt;
 	catch (RecognitionException re) {&lt;br /&gt;
	 	_errHandler.reportError(this, re);&lt;br /&gt;
	 	_errHandler.recover(this, re);&lt;br /&gt;
 	}&lt;br /&gt;
 	finally {&lt;br /&gt;
		exitRule();&lt;br /&gt;
 	}&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
在第9.5节“改变ANTLR的错误处理策略”中，我们看到了如何使用Strategy对象来改变ANTLR的错误处理。 但是，替换strategy会更改所有rule的strategy。 要更改单个rule的异常处理，请在rule定义后指定异常:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
r : ...&lt;br /&gt;
  ;&lt;br /&gt;
  catch[RecognitionException e] { throw e; }&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
该示例演示了如何避免默认错误报告和恢复。 r重新抛出异常，当需要对更高级别的rule报告更有意义的错误时，这很有用。 指定任何exception子句会阻止ANTLR生成子句来处理`RecognitionException`。&lt;br /&gt;
&lt;br /&gt;
您也可以指定其他异常:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
r : ...&lt;br /&gt;
  ;&lt;br /&gt;
  catch[FailedPredicateException fpe] { ... }&lt;br /&gt;
  catch[RecognitionException e] { ... }&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
大括号内的代码片段和异常“参数”操作必须用目标语言编写； 以上是Java的写法。&lt;br /&gt;
当你即使发生异常，也需要执行操作，可以把它到 'finaly' 子句中:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
r : ...&lt;br /&gt;
  ;&lt;br /&gt;
  // catch blocks go first&lt;br /&gt;
  finally { System.out.println(&amp;quot;exit rule r&amp;quot;); }&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
finally子句在规则触发`exitRule`之前执行，然后返回。 如果您想要在rule匹配完alternatives之后，但在它执行清理工作之前执行某个操作，请使用`after`操作。&lt;br /&gt;
&lt;br /&gt;
以下是例外的完整列表:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;th&amp;gt;Exception name&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;RecognitionException&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
ANTLR生成的识别器引发的所有异常的超类。 它是RuntimeException的子类，以避免检查异常的麻烦。 此异常记录了识别器 (lexer或parser) 在输入中的位置，它在ATN (表示语法的内部图形数据结构) 中的位置，规则调用堆栈以及发生了什么样的问题。&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;NoViableAltException&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
指示parser无法通过查看剩余的输入来决定采用两条或多条路径中的哪一条。 此异常跟踪违规输入的起始Token，并且还知道错误发生时parser在各种路径中的位置。&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;LexerNoViableAltException&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
相当于NoViableAltException，但仅适用于lexers。&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;InputMismatchException&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
当前输入Token与parser预期的不匹配。&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;FailedPredicateException&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;br /&gt;
在预测(predicting)期间计算为False的语义谓词将使周围的alternative不可用。 当一条规则正在预测(predicting)采取哪种替代方案时，就会发生Prediction。 如果所有可行的路径都消失了，parser将抛出NoViableAltException。 在匹配Token和调用Rule的正常解析过程中，当语义谓词在预测之外评估为false时，解析器会抛出此谓词。&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
## Rule Attribute Definitions（规则属性定义）&lt;br /&gt;
&lt;br /&gt;
有许多action相关的语法元素和rule相关需要注意。 Rules可以有参数、返回值和局部变量，就像编程语言中的函数一样。 (Rule可以在Rule元素中嵌入action，正如我们将在第15.4节 “操作和属性” 中看到的那样。) ANTLR收集您定义的所有变量，并将它们存储在Rule上下文对象中。 这些变量通常称为属性。 下面是显示所有可能的属性定义位置的通用语法:&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
rulename[args] returns [retvals] locals [localvars] : ... ;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
这些[…]中定义的属性可以像任何其他变量一样使用。 以下是复制参数以返回值的示例rule：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
// 返回参数加上INT Token的整数值&lt;br /&gt;
add[int x] returns [int result] : '+=' INT {$result = $x + $INT.int;} ;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
参数，局部变量和返回值`[...]`通常是使用目标语言，但有一些限制。 `[...]`字符串是一个逗号分隔的声明列表，可以使用前缀或后缀类型表示法，也可以不使用类型表示法。 元素可以有`[int x = 32, float y]`这样的初始值设定项，但是不要太疯狂，因为我们正在用[ScopeParser](https://github.com/antlr/antlr4/blob/master/tool/src/org/antlr/v4/parse/ScopeParser.java).手动解析这个泛型文本  &lt;br /&gt;
&lt;br /&gt;
* Java，CSharp，C++ 使用 `int x` 表示法，但C++必须对数组引用 `int[] x` 使用稍微更改的表示法，以适合 *type* *id* 语法。&lt;br /&gt;
* Go和Swift在变量名后给出类型，但Swift需要在两者之间加一个`:`。 Go `i int`, Swift `i:int`.  Go目标必须使用`int i`或`i：int`。&lt;br /&gt;
* Python和JavaScript不指定静态类型，因此操作只是标识符列表，例如 “[i，j]”。&lt;br /&gt;
&lt;br /&gt;
从技术上讲，任何目标都可以使用这两种符号。 有关示例，请参见[TestScopeParsing](https://github.com/antlr/antlr4/blob/master/tool-testsuite/test/org/antlr/v4/test/tool/TestScopeParsing.java).&lt;br /&gt;
&lt;br /&gt;
与grammar级别一样，您可以指定rule级别的命名操作。 对于rules，有效名称是`init`和`after`。 顾名思义，parsers在尝试匹配关联rule之前立即执行init操作，在匹配rule之后立即执行after操作。 ANTLR中的after操作不会作为生成的rule函数的最终代码块的一部分执行。 使用ANTLR finally操作将代码放入生成的规则函数finally 代码块中。&lt;br /&gt;
&lt;br /&gt;
这些操作位于任何参数、返回值或本地属性定义操作之后。 第10.2节 “访问Token和rule属性” 中的 `row` rule前导码很好地说明了语法: actions/CSV.g4&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
/** Derived from rule &amp;quot;row : field (',' field)* '\r'? '\n' ;&amp;quot; */&lt;br /&gt;
row[String[] columns]&lt;br /&gt;
   returns [Map&amp;lt;String,String&amp;gt; values]&lt;br /&gt;
   locals [int col=0]&lt;br /&gt;
	@init {&lt;br /&gt;
	$values = new HashMap&amp;lt;String,String&amp;gt;();&lt;br /&gt;
	}&lt;br /&gt;
	@after {&lt;br /&gt;
	if ($values!=null &amp;amp;&amp;amp; $values.size()&amp;gt;0) {&lt;br /&gt;
	System.out.println(&amp;quot;values = &amp;quot;+$values);&lt;br /&gt;
	}&lt;br /&gt;
	}&lt;br /&gt;
	: ...&lt;br /&gt;
	;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Rule row包含参数columns，返回值，并定义局部变量col。 方括号中的“actions”被直接复制到生成的代码中：&lt;br /&gt;
&lt;br /&gt;
```java&lt;br /&gt;
public class CSVParser extends Parser {&lt;br /&gt;
	...&lt;br /&gt;
	public static class RowContext extends ParserRuleContext {&lt;br /&gt;
		public String [] columns;&lt;br /&gt;
		public Map&amp;lt;String,String&amp;gt; values;&lt;br /&gt;
		public int col=0;&lt;br /&gt;
		...&lt;br /&gt;
	}&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
生成的rule函数还将rule参数指定为函数参数，并且它们会快速复制到本地RowContext对象中:&lt;br /&gt;
&lt;br /&gt;
```java&lt;br /&gt;
public class CSVParser extends Parser {&lt;br /&gt;
 	...&lt;br /&gt;
 	public final RowContext row(String [] columns) throws RecognitionException {&lt;br /&gt;
	 	RowContext _localctx = new RowContext(_ctx, 4, columns);&lt;br /&gt;
	 	enterRule(_localctx, RULE_row);&lt;br /&gt;
	 	...&lt;br /&gt;
 	}&lt;br /&gt;
 	...&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ANTLR在action中跟踪嵌套的“[…]”，以便正确解析`String[]` column。 它还跟踪尖括号，以便泛型类型参数中的逗号不表示另一个属性的开始。 `Map&amp;lt;String,String&amp;gt;`值是一个属性定义。&lt;br /&gt;
&lt;br /&gt;
每个动作中可以有多个属性，即使是返回值也是如此。 使用逗号分隔同一action中的属性：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
a[Map&amp;lt;String,String&amp;gt; x, int y] : ... ;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ANTLR解释该action为定义两个参数x和y:&lt;br /&gt;
&lt;br /&gt;
```java&lt;br /&gt;
public final AContext a(Map&amp;lt;String,String&amp;gt; x, int y)&lt;br /&gt;
	throws RecognitionException&lt;br /&gt;
{&lt;br /&gt;
	AContext _localctx = new AContext(_ctx, 0, x, y);&lt;br /&gt;
	enterRule(_localctx, RULE_a);&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Start Rules and EOF（起始和结尾Rule）&lt;br /&gt;
&lt;br /&gt;
start rule是parser最先使用的rule；它是语言应用程序调用的rule函数。 例如，解析为Java代码的语言应用程序可能是一个`JavaParser`类的对象名为`parser`，它可以调用`parser.compilationUnit()`方法 grammar中的任何rule都可以作为起始rule。&lt;br /&gt;
&lt;br /&gt;
起始Rule不一定消耗所有输入。 它们仅消耗所需的输入，以匹配Rule的alternative。 例如，考虑下面的Rule，根据输入，匹配一个、两个或三个Token。&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
s : ID&lt;br /&gt;
  | ID '+'&lt;br /&gt;
  | ID '+' INT&lt;br /&gt;
  ;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
在`a+3`时，rule`s`匹配第三个选项。 在`a+b`时，它与第二种选择匹配，并忽略最终的 `b` token。 在`a b`时，它匹配第一个alternative，忽略`b`标记。 在后两种情况下，parser不会使用完整的输入，因为rule`s‘没有显式地说明文件结尾必须在匹配rule的alternative之后才会出现。&lt;br /&gt;
&lt;br /&gt;
这个默认功能对于构建像ide这样的东西非常有用。 假设IDE想在大java文件中间解析某个方法。 调用rule`method Declaration`应该尝试只匹配一个方法，而忽略接下来发生的任何事情。&lt;br /&gt;
&lt;br /&gt;
另一方面，描述整个输入文件的规则应引用特殊的预定义令牌 `EOF`。 如果他们没有，你可能会挠头想一想，为什么不管你给出什么，起始rule都不会报告任何输入的错误。 以下是读取配置文件的语法的一部分：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
config : element*; // 即使输入无效，也可以 “匹配”。&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
无效输入将导致`config`立即返回，而不匹配任何输入，也不报告错误。 以下是适当的specification：&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
file : element* EOF; // 不要过早的停止。必须匹配所有输入&lt;br /&gt;
```&lt;/div&gt;</summary>
		<author><name>Zhang3</name></author>
	</entry>
</feed>