antrl语法简单学习

antlr语言是诸多解析语言里边比较方便便捷的,以下只是个人在使用时学习的一些语法记录;

1、标识符(Identifiers)
词法单元和词法规则通常以大写字母命名
解析规则(parser rule) 以小写字母开头命名(驼峰命名法)

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

3、关键字(Keywords)

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

antlr解析mysql语句 antlbacterial_词法


xxxx.g4文件详解:

1. grammar Name 这是词法跟语法都在同一个文件声明的写法,称之为combined。若要分开,可以使用lexer grammar Name和parser grammar Name。
	2. options 可以是如下四个选项。
superClass:用于生成xxxLexer.java、xxxParser.java的父类
language:目标语句,如java
tokenVocab:toekn词库
TokenLabelType:默认的是antlr的Token类型,这里可以使用自定义的token类,如MyToken。需要配合TokenFactory使用
	3. import 可以导入各个独立的lexer、parser文件。
	actionName 可以是如下内容
@header:定义类文件头。比如嵌入java的package、import声明
@member:定义类文件内容。比如类成员、方法
	4. WS:代表是一个词法规则中的空白字符
		如果要指定在lexer或者parser中,可以使用 @lexer::membere、@parser::member。
		文件命名必须和grammar命名相同,如 grammar T,文件名必须命名为T.g4.  options,imports,token,action的声明顺序没有要求,但一个文件中options,imports,token最多只能声明一次.grammar是必须声明的,同时必须至少声明一条规则(rule),其余的部分都是可选的.
		@header、@member可以在前面加上@parser::或者@lexer::,就会被限定;

解析过程:

分为俩个阶段:

①:词法分析(lexical analysis):对应的分析程序叫做lexer,负责将符号(token)分组成符号类(token class or token type)。

②:语法解析(parse analysis):根据词法,构建出一棵分析树(parse tree)或叫语法树(syntax tree)。

antlr解析mysql语句 antlbacterial_ANTLR_02


代码实践:

antlr解析mysql语句 antlbacterial_java_03


词法规则:

1、 若输入串能被多个词法规则匹配,那么声明在词法文件最前面的规则生效。

2、输入串将被最长匹配的词法规则匹配。例如:ABCD肯定会被能完全匹配ABCD的词法规则匹配,而不是将ABCD拆开分别被匹配,例如被两个词法ABC、D匹配。

遍历模式
1、Listener (观察者模式,通过结点监听,触发处理方法)
①、程序员不需要显示定义遍历语法树的顺序,实现简单
②、缺点,不能显示控制遍历语法树的顺序
③、动作代码与文法产生式解耦,利于文法产生式的重用
④、没有返回值,需要使用map、栈等结构在节点间传值
2、Visitor (访问者模式,主动遍历)
①、程序员可以显示定义遍历语法树的顺序
②、不需要与antlr遍历类ParseTreeWalker一起使用,直接对tree操作
③、动作代码与文法产生式解耦,利于文法产生式的重用
④、visitor方法可以直接返回值,返回值的类型必须一致,不需要使用map这种节点间传值方式,效率高

ANTLR 4开始会生成监听器(Listener)与访问者(Visitor),将语法定义与目标代码完全的解耦。监听器可以被动的接受语法分析树遍历的事件,对于每一个语法节点,都会生成进入enterSomeNodeName与退出exitSomeNodeName两个方法。访问者机制生成对语法节点的访问方法visitSomeNodeName,在访问方法中需要手动调用visit方法来对子节点进行遍历,使用访问者模式可以控制语法树的遍历,略过某些的分枝。ANTLR默认只生成监听器,生成访问者类需要在生成时添加-visitor选项。

ALL(*)语法分析器
LR()与LL()
现在主流的语法分析器分两大阵营,LR()与LL()。
LR是自低向上(bottom-up)的语法分析方法,其中的L表示分析器从左(Left)至右单向读取每行文本,R表示最右派生(Rightmost derivation),可以生成LR语法分析器的工具有YACC、Bison等,它们生成的是增强版的LR,叫做LALR。

LL是自顶向下(top-down)的语法分析方法,其中的第一个L表示分析器从左(Left)至右单向读取每行文本,第二个L表示最左派生(Leftmost derivation),ANTLR生成的就是LL分析器。

两类分析器各有其优势,适用不同的场景,很难说谁要更好一些。普遍的说法是LR可以解析的语法形式更多,LL的语法定义更简单易懂。

Antlr 4文件夹解析:

ArrayInitParser.java:包含了专用于 ArrayInit 语法的解析器(parser)类的定义。
ArrayInitLexer.java:包含专用的词法分析程序(lexer)类的定义。
ArrayInit.Tokens:对于我们定义的每个 token,ANTLR 分配了一个 token 类型码(token type number)并将这些值保存在 ArrayInit.tokens。因     为这个文件的存在,当我们将较大规模的语法分割为各种小型的语法表达时,ANTLR 能够使同种 token 的类型码保持一致。
ArrayInitListener.java, ArrayInitBaseListener.java:ANTLR 生成的解释器会默认根据输入构建一棵树。通过遍历这棵树,一个遍历器可以将事件(回调函数)传递给我们提供的监听者对象(listener object)。
ArrayInitListener: 是描述我们可以实现的回调函数的接口。

ArrayInitBaseListener: 是默认空实现的集合,使我们可以方便的重写(override)那些我们感兴趣的回调函数。通过-visitor命令行参数,ANTLR 也可以为我们生成树的 visitors。

语法规则:

antlr解析mysql语句 antlbacterial_ANTLR_04

****此处在生成语法树时报了个错:
生成语法树报错:
Exception in thread “Thread-9” java.lang.NoClassDefFoundError: org/antlr/v4/runtime/BaseErrorListener
原因:由于类的加载在运行时找不到对应的类,所以报错;
解决方法:
1. 对应的Class在java的classpath中不可用
2. 你可能用jar命令运行你的程序,但类并没有在jar文件的manifest文件中的classpath属性中定义
3. 可能程序的启动脚本覆盖了原来的classpath环境变量
4. 因为NoClassDefFoundError是java.lang.LinkageError的一个子类,所以可能由于程序依赖的原生的类库不可用而导致
5. 检查日志文件中是否有java.lang.ExceptionInInitializerError这样的错误,NoClassDefFoundError有可能是由于静态初始化失败导致的
如果你工作在J2EE的环境,有多个不同的类加载器,也可能导致NoClassDefFoundError