CDM之ANTLR学习

网友投稿 646 2022-05-30

ANTLR是什么

ANTLR是一个解析器生成工具,可以根据你书写的文法文件,自动生成可以解析该文法的解析器(Parser).其强大的功能远不止这些.

文法文档(Grammar Lexicon)

Lexicon是按ANTLR规范书写的文件,在这个文件中指定你要解析的文法,ANTLR再根据这个文件生成对应的解析器.

标识符(Identifiers)

词法单元和词法规则通常以大写字母命名

解析规则(parser rule) 以小写字母开头命名(驼峰命名法)

例如:

1

2

ID, LPAREN, RIGHT_CURLY //token names/rule

expr, simpleDclarator, d2, header_file //rule names

ANTLR还支持unicode编码的字符命名

文字(Literals)

ANTLR不区分字符和字符串.所有的字符串(这里是指出现在源文件中的需要被识别的字符串)都是由单引号引用起来的字符,但是像这样的字符串中不包括正则表达式.支持unicode和转义符号例如

1

2

3

4

',' , 'if', '>=',

' \''//转义的单引号

'\u00E8' //法语中的字符è

'\n', '\r' //换行 回车

动作(Actions)

动作是用目标语言书写的代码块.嵌入的代码可以出现在:

@header @members这样的命名动作中

解析规则和词法规则中

异常捕获中

解析规则的属性部分(返回值,参数等)

一些规则可选元素中

关键字(Keywords)

ANTLR中有一些保留关键字,例如:

1

import, fragment, lexer, parser, grammar, returns, locals, throws, catch, finally, mode, options, tokens

语法结构(Grammar Structure)

语法结构如下

|Grammar |

| ————- |

| /Optional javadoc style comment*/|

| grammer Name; |

| options {…}; |

| import …; |

| tokens {…}; |

| channels {…}; |

| @actionName** {…}; |

| |

| rule1 //parser and lexer rules |

| … |

| ruleN |

文件命名必须和grammar命名相同,如 grammar T,文件名必须命名为T.g4.

options,imports,token,action的声明顺序没有要求,但一个文件中options,imports,token最多只能声明一次.grammar是必须声明的,同时必须至少声明一条规则(rule),其余的部分都是可选的.

规则(rules)

规则的声明遵循以下格式:

1

2

3

4

ruleName : alternative1 | ... | alternativeN ;

//定义类型

type : 'int' | 'unsigned' | 'long'

引入(imports)

ANTLR中的引入机制类似于OO中的继承.它会从引入的文件继承所有的规则,词法单元,动作.然后主文件中的元素会”覆盖”引入文件中的重名元素.

嵌套引用的合并规则比较复杂,详见官方文档

词法单元(Tokens Section)

CDM之ANTLR学习

1

tokens {Token1 ... TokenN}

例如为向量表示定义虚词法单元:

1

2

3

4

5

6

7

8

9

grammar VecMathAST

options{output=AST;}

tokens{VEC;}

statlist : stat+ ;

stat : ID '=' expr -> ^('=' ID expr)

| 'print' expr -> ^('print' expr);

expr : multExpr ('+' ^ multExpr)*;

multExpr : primary (('*'^|'.'^) primary)*;

primary : INT | ID | '[' expr (',' expr)* ']' -> ^(VEC expr+);

动作(Actions at the Grammar Level)

针对java,有两个已经定义好的action:header和members

@header在生成的目标代码中的类定义之前注入代码

@members在生成的目标代码中的类定义里注入代码(例如类的属性和方法)

1

2

3

4

5

6

7

8

9

10

11

12

13

grammar Count;

@header {

pacakage foo;

}

@members{

int count = 0;

}

list @after{System.out.println(count+"ints");} : INT {count++;} (',' INT {count++})*

;

INT: [0-9]+;

解析器规则(Parser Rules)

解析器由一组解析器规则组成.java应用通过调用生成的规则函数(每个规则会生成一个函数)来启动解析.

基本形式如下,用 | 操作符分割多个选项

1

stat : restat | 'break' ';' | 'continue' ';' ;

可选标签(Alternative Labels)

可以在规则中添加标签,ANTLR会根据标签生成与规则相关的解析树的事件监听函数,使我们更加精准的控制解析过程.用 # 操作符定义一个标签

用法如下:

1

2

3

grammar T;

stat: 'return' e ';' # Return

| 'break' ';' # Break

ANTLR会为每个标签生成一个rule-context类.

1

2

3

4

5

6

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);

}

同一个标签可以加在多个规则选项上(multiple alternatives),但是标签命名不可以和规则名冲突

规则上下文对象(Rule Context Objects)

ANTLR为每个规则生成一个上下文对象,通过这个对象可以访问规则定义中的其他规则的引用.根据规则定义中的其他规则的引用数量不同,生成对象中包含的方法也不同.例如:

1

2

3

4

5

6

7

inc : e '++';

//generates this context class

public static class IncContext extends ParserRuleContext {

public EContext e() { ... } // return context object associated with e

...

}

1

2

3

4

5

6

7

8

field : e '.' e;

//generates this context class

public static class FieldContext extends ParserRuleContext {

public EContext e(int i) { ... } // get ith e context

public List e() { ... } // return ALL e contexts

...

}

规则元素标签(Rule Element Labels)

可以用 = 操作符为规则中的元素添加标签,这样会在规则的上下文对象中添加元素的字段.

例如:

1

2

3

4

5

6

7

8

9

stat: 'return' value=e ';' # Return //将e的context作为一个字段添加到 ReturnContext中

| 'break' ';' # Break

;

//generates context class

public static class ReturnContext extends StatContext {

public EContext value;

...

}

+= 操作符可以很方便的记录大量的token或者规则的引用

1

2

3

4

5

6

array : '{' el+=INT (',' el+=INT)* '}' ;

//ANTLR generates a List field in the appropriate rule context class:

public static class ArrayContext extends ParserRuleContext {

public List el = new ArrayList();

...

}

规则元素(Rule ELements)

规则元素指定了解析器在具体时刻应该执行什么任务.元素可以是规则(rule), 词法单元(token), 字符串文字(string literal)等

T token

‘literal’      字符串文字

r      规则

r[args]      向规则函数中传递参数,参数的书写规则是目标语言,用逗号分隔

. 通配符

{action}      动作,在元素的间隔中执行

{p}      谓词

支持逻辑非操作符:~

子规则

规则中包含的可选块称为子规则(被封闭在括号中).子规则也可以看做规则(rule),但是没有显式的命名.子规则不能定义局部变量,也没有返回值.如果子规则只有一个元素,括号可以省略.

子规则有四种

例如:

(x|y|z)      只匹配一个选项

(x|y|z)?      匹配一个或者不匹配

(x|y|z)*      匹配零次或多次

(x|y|z)+      匹配一次或多次

参考:

https://developer.ibm.com/zh/articles/j-lo-antlr/

https://theantlrguy.atlassian.net/wiki/display/ANTLR4/ANTLR+4+Documentation

http://yijun1171.github.io/2015/03/30/ANTLR4%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E8%AF%AD%E6%B3%95%E5%AD%97%E5%85%B8-Grammar-Lexicon

云数据迁移 CDM 面向对象编程

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:《scikit-learn机器学习常用算法原理及编程实战》—2.6 scikit-learn简介
下一篇:一统江湖的大前端(2)—— Mock.js + Node.js 如何与后端潇洒分手
相关文章