普通参考文章:
antlr4配置到Eclipse开发环境的文章:
Eclipse安装Antlr4_Alexxander_的博客-CSDN博客
anltr4的简单入门案例文章:
Eclipse中Antlr的示例练习_antlr eclipse_Alexxander_的博客-CSDN博客
核心技术参考文章:
Antlr4词法写法:
我写的用于识别Matlab嵌套矩阵的词法:
/**
* : 该语法用于识别 Matlab 的矩阵(含嵌套)
*/
/*
* 1. 带分隔符的序列模式: (',' x)*
*
* 2. 带终止符的序列模式: (x ';')*
*
* 3. 选择模式: field: INT | STRING ;
*
* 4. 词法符号依赖模式: vector: '[' INT+ ']' ;
*/
grammar MatlabMatrix ;
value : expr
| INTEGER
| FLOAT
| IDENTIFIER
;
expr : '[' value (',' value)* ']'
;
IDENTIFIER : ID_START_LETTER ID_MIDDLE_LETTER
; // 定义标识符
INTEGER : [0-9]+
; // 定义整数
FLOAT : [0-9]+ '.' [0-9]+
; // 定义浮点数(实数)
ID_MIDDLE_LETTER : [a-zA-Z_0-9]+
; // 定义标识符的中间字符
ID_START_LETTER : [a-zA-Z]+
; // 定义开始字符
WS : [ \t\r\n]+ -> skip
; // 跳过空白类字符
(下面关于监听器、访问器,是参考的核心技术参考文章)
监听器和访问器
ANTLR除能够自动构建语法分析树外,还能生成基于Listener(监听者模式,通过节点监听,触发处理方法)和Visitor(访问者模式,主动遍历)的树遍历器。访问者模式遍历语法树是一种更加灵活的方法,可以避免在文法文件中嵌入繁琐的动作,使解析与应用逻辑代码分离,这样不但文法的定义更加简洁清晰,而且可以在不重新编译生成语法分析器的情况下复用相同的语法,甚至能够采用不同的程序语言来实现这些动作。
Listener监听器
ANTLR为每个语法文件生成一个ParseTreeListener的子类,在该类中,语法中的每条规则都有对应的enter方法和exit方法,当访问到某节点时,就会调用相应的enter方法,访问完后就调用相应的exit方法。下图是ParseTreeWalker对一个简单语法分析树进行深度优先遍历的过程。
ParseTreeWalker对监听器方法的完整的调用顺序如下图所示:
Visitor访问器
访问者模式(Visitor Pattern)是一种将操作与对象结构分离的软件设计模式,提供作用于某种对象结构上各元素的操作,可以使我们在不改变元素结构的前提下,定义作用于元素的新操作。
这种模式的工作方法如下:假设有一个由许多元素Node构成的对象结构Tree,这些Node类都拥有一个accept方法用来接受访问者对象Visitor的访问;Visitor类是一个接口,它拥有一个visit方法,这个方法对访问到的Tree中不同类型的Node作出不同的反应;在对Tree的一次访问过程中会遍历整个Tree,对遍历到的每个Node都调用accept方法,在每个元素的accept方法中回调Visitor的visit方法,从而使Vistior得以处理Tree的每个Node;可以针对Tree设计不同的Visitor实现类来完成不同的操作。
测试代码
下面的代码是我自己的,文法使用的就是上面的Matlab嵌套数组识别文法:
1. 自己写一个监听器,继承自Antlr4生成的监听器MatlabMatrixBaseListener,如下图:
2. 将自己的监听器注册进语法解析器里即可使用我们自己定义的监听器监听表达式的遍历:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 从控制台输入字符串
// Scanner sc = new Scanner(System.in);
// String words = sc.nextLine();
String words = "[1,2, [3, 3]]";
// 构建字符流
// ANTLRInputStream input = new ANTLRInputStream(words);
CharStream input = CharStreams.fromString(words);
// 将字符流注入lexer
MatlabMatrixLexer lexer = new MatlabMatrixLexer(input);
// 使用lexer将字符流解析为token
CommonTokenStream tokens = new CommonTokenStream(lexer);
// 使用parser对token做语法分析
MatlabMatrixParser parser = new MatlabMatrixParser(tokens);
// ***: 将自己的语法分析树监听器添加到语法分析器中, 以便于在自动遍历过程中, 进行自定义的操作
MyParserTreeListener myParserTreeListener = new MyParserTreeListener();
parser.addParseListener(myParserTreeListener);
// 从parser获取语法分析树
ExprContext expr = parser.expr();
System.out.println(expr.toStringTree(parser));
// sc.close();
}