antlr-基础-解析规则
解析规则
Parser Rules
Parsers包含一系列语法分析规则
java通过使用ANTLR生成的rule函数启动解析
最简单的规则是一个规则名,后跟单一的可选项,最后用分号
/** Javadoc comment can precede rule */
retstat : 'return' expr ';' ;
可以使用可选择的分隔符|
stat: retstat
    | 'break' ';'
    | 'continue' ';'
    ;
可选的规则可以是一系列的规则元素,或者是空
superClass
    : 'extends' ID
    | // empty means other alternative(s) are optional
    ;
Alternative Labels
通过设置最外层的,alternatives #符号,可以获得更精确的parse-tree监听器,所有的选择都是labeled
grammar T;
stat: 'return' e ';' # Return
    | 'break' ';' # Break
    ;
e   : e '*' e # Mult
    | e '+' e # Add
    | INT # Int
    ;
生成的监听器如下
public interface AListener extends ParseTreeListener {
    void enterReturn(AParser.ReturnContext ctx);
    void exitReturn(AParser.ReturnContext ctx);
    void enterBreak(AParser.BreakContext ctx);
    void exitBreak(AParser.BreakContext ctx);
    void enterMult(AParser.MultContext ctx);
    void exitMult(AParser.MultContext ctx);
    void enterAdd(AParser.AddContext ctx);
    void exitAdd(AParser.AddContext ctx);
    void enterInt(AParser.IntContext ctx);
    void exitInt(AParser.IntContext ctx);
}
每一个labeled alternative有一个enter和一个exit
在多个选择中,可以服用同一个label,这样那些任务会触发同一个事件
 e : e '*' e 		# BinaryOp
    | e '+' e 		# BinaryOp
    | INT		    # Int
    ;
生成如下监听器
void enterBinaryOp(AParser.BinaryOpContext ctx);
void exitBinaryOp(AParser.BinaryOpContext ctx);
void enterInt(AParser.IntContext ctx);
void exitInt(AParser.IntContext ctx);
alternative的名字和rule的名字相同会起冲突
  e : e '*' e # e
    | e '+' e # Stat
    | INT # Int
    ;
context对象
Rule Context Objects
就是解析树的节点
ANTLR会生成方法,访问和规则关联的规则上下文对象
 inc : e '++' ;
ANTLR 生成下面的context类
public static class IncContext extends ParserRuleContext {
    public EContext e() { ... } // return context object associated with e
    ...
}
field : e '.' e ;
生成多余一个引用
public static class FieldContext extends ParserRuleContext {
    public EContext e(int i) { ... } // get ith e context
    public List<EContext> e() { ... } // return ALL e contexts
    ...
}
如果有另一个规则s,一个嵌入的action,可以访问规则list
s : field
    {
	    List<EContext> x = $field.ctx.e();
	    ...
    }
;
listener和visitor也可以做这个,指向FieldContext对象
Rule Element Labels
可以使用=操作符,加载fields到rule context objects中
stat: 'return' value=e ';' # Return
    | 'break'          ';' # Break
    ;
value是返回值e的一个标签,e在其他地方定义,Labels在特定的parse node类中,在这里value成为了ReturnContext 的一部分,因为后面的Return标签
public static class ReturnContext extends StatContext {
    public EContext value;
    ...
}
很方变去追踪tokens,可以使用+= list标签操作符,比如下面的规则创建一个token对象的列表,符合一个array结构
array : '{' el+=INT (',' el+=INT)* '}' ;
在rule context class中生成List域
array结构
public static class ArrayContext extends ParserRuleContext {
	public List<Token> el = new ArrayList<Token>();
	...
}
这些list标签同样适合于规则引用
elist : exprs+=e (',' exprs+=e)* ;
ANTLR 生成一个成员,保存context objects列表
public static class ElistContext extends ParserRuleContext {
	public List<EContext> exprs = new ArrayList<EContext>();
	...
}
Rule Elements
规则元素指定了parser应该在给定的时刻做什么事,元素可以是:rule、token、expression、ID、return
下面是完整的规则元素表,后面会详细描述actions和predicates;
| Syntax | Description | 
|---|---|
| T | 当前输入位置匹配token T,token一般是大写字母开头 | 
| 'literal' | 在当前的位置匹配字符串literal,固定字符串的token | 
| r | 当前位置匹配规则r,以为着类似函数调用 | 
| r [«args»] | |
| $x、和$x.y | |
| {«p»}? | |
| . | 通配符,匹配任何内容 | 
是否定符号,比如INT是匹配非INT的内容
~(INT|ID)匹配除了INT或者ID的内容
子规则
子规则扩上圆括号,没有名字,可以有更多的选项,不能定义attributes,有四种子规则
(x|y|z)只要有一种满足就可
returnType : (type | 'void') ;

(x|y|z)?一个都不男足,或者任意
classDeclaration : 'class' ID (typeParameters)? ('extends' type)? ('implements' typeList)? classBody ; 

(x|y|z)* 满足0或更多个条件
annotationName : ID ('.' ID)* ;

(x|y|z)+满足一次或更多次
annotations : (annotation)+ ; 

?, *, +
??, *?, +? 在后面加上?是非贪婪模式
也可以省略括号作为缩写形式,比如:ID+、annotation+
捕获异常
语法出错之后,ANTLR会捕获异常
void r() throws RecognitionException {
    try {
        rule-body
    }
    catch (RecognitionException re) {
        _errHandler.reportError(this, re);
        _errHandler.recover(this, re);
    }
    finally {
        exitRule();
    }
}
Section 9.5讲解如何利用策略对象处理错误,修改错误异常处理,在定义之后指定异常
单个规则指定异常
r : ...
  ;
  catch[RecognitionException e] { throw e; }
也可以指定其他的异常
r : ...
  ;
  catch[FailedPredicateException fpe] { ... }
  catch[RecognitionException e] { ... }
也可以指定finally
r : ...
  ;
  // catch blocks go first
  finally { System.out.println("exit rule r"); }
异常列表
RecognitionException		
NoViableAltException
LexerNoViableAltException
InputMismatchException
FailedPredicateException
Rule Attribute Definitions
rule可以输入参数、返回值、本地变量像函数;
Antlr收集定义的变量,放到rule context对象中,这些变量被称为attributes,下面的语法演示了可能定义属性的位置
rulename[args] returns [retvals] locals [localvars] : ... ;
比如
// Return the argument plus the integer value of the INT token
add[int x] returns [int result] : '+=' INT {$result = $x + $INT.int;} ;
args、locals、return都用目标语言编写,但是有些限制[...]是逗号分隔的列表,不同语言的有些区别..
例子:
/** Derived from rule "row : field (',' field)* '\r'? '\n' ;" */
row[String[] columns]
   returns [Map<String,String> values]
   locals [int col=0]
    @init {
    $values = new HashMap<String,String>();
    }
    @after {
    if ($values!=null && $values.size()>0) {
    System.out.println("values = "+$values);
    }
    }
    : ...
    ;
规则行获取columns、返回值values、定义的本地变量col;
方括号中的actions直接拷贝到生成的代码中
public class CSVParser extends Parser {
    ...
    public static class RowContext extends ParserRuleContext {
        public String [] columns;
        public Map<String,String> values;
        public int col=0;
        ...
    }
    ...
}
生成的规则函数也指定规则参数,作为函数参数,但是也很快的拷贝到本地的RowContext对象中;
public class CSVParser extends Parser {
    ...
    public final RowContext row(String [] columns) throws RecognitionException {
        RowContext _localctx = new RowContext(_ctx, 4, columns);
        enterRule(_localctx, RULE_row);
        ...
    }
    ...
}
多属性的情况
a[Map<String,String> x, int y] : ... ;
结果
public final AContext a(Map<String,String> x, int y)
    throws RecognitionException {
    AContext _localctx = new AContext(_ctx, 0, x, y);
    enterRule(_localctx, RULE_a);
    ...
}
Start Rules and EOF
start rule是第一个执行的rule,任何的rule都可以作为start rule;
start rule不必消费全部的输入,如下
s : ID
  | ID '+'
  | ID '+' INT
  ;
a+3匹配第三条
a+b匹配第二条,忽略b字母
如果不加EOF,会尽量匹配,如果没有匹配的则返回
如果加上EOF,出错则不会立即返回
config : element*; // can "match" even with invalid input.
file : element* EOF; // don't stop early. must match all input
 
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号