本文主要是介绍ANTLR中自定义语法分析过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
自定义语法分析过程
语法中嵌入动作
除了使用监听器和访问器,我们还可以手动实现对语法分析树的访问
例如要对如下三列文本进行识别,打印指定的列,例如第一列为parrt tombu bke,列之间以Tab分割
parrt Terence Parr 101
tombu Tom Burns 020
bke Kevin Edgar 008
在语法文件Rows.g4中添加一些自定义的动作,通过members将RowParser注入到生成的语法分析器类中
grammar Rows;@parser::members { int col;public RowsParser(TokenStream input, int col) { // custom constructorthis(input);this.col = col;}
}file: (row NL)+ ;row
locals [int i=0] //使用locals定义局部变量$i: ( STUFF{$i++; if ( $i == col ) System.out.println($STUFF.text); //$STUFF.text获取词法符号匹配的文本})+;TAB : '\t' -> skip ; // match but don't pass to the parser
NL : '\r'? '\n' ; // match and pass to the parser
STUFF: ~[\t\r\n]+ ; // match any chars except tab, newline
接下来在主程序中调用语法分析器,这里传入为RowsParser
传入词法符号tokens和列号参数col,并且设置不自动生成语法分析树
public class Col {public static void main(String[] args) throws Exception {ANTLRInputStream input = new ANTLRInputStream(System.in);RowsLexer lexer = new RowsLexer(input);CommonTokenStream tokens = new CommonTokenStream(lexer);int col = Integer.valueOf(args[0]);RowsParser parser = new RowsParser(tokens, col); // 传递列好作为参数parser.setBuildParseTree(false); // 不需要自动生成语法树parser.file(); // parse}
}
构建项目并进行测试如下,可以看到输出了第一列的内容
D:\Code\antlr\demo\chapter4>antlr4 -no-listener Rows.g4D:\Code\antlr\demo\chapter4>javac Rows*.java Col.javaD:\Code\antlr\demo\chapter4>java Col 1 < t.rows
parrt
tombu
bke
语义判定
通过表达式{$i<=$n}?
可以对匹配条件进行判定,从而执行不同的语法分支
例如要对如下的数字序列进行匹配,第一个数字为2,则往后匹配两个数9、10,接下来为3,向后匹配三个数1、2、3
2 9 10 3 1 2 3
使用如下语法文件对数字序列进行匹配,通过判定表达式实现向后匹配n个整数
grammar Data;file : group+ ;group: INT sequence[$INT.int] ;sequence[int n]
locals [int i = 1;]: ( {$i<=$n}? INT {$i++;} )* // 匹配n个整数;INT : [0-9]+ ; // match integers
WS : [ \t\n\r]+ -> skip ; // toss out all whitespace
词法分析器特性
孤岛语法:输入文件中包含多种语言,需要将模板表达式之外的文本按照不同方式处理。
ANTLR的词法分析模式(lexical model)可以对不同格式数据的文件进行处理,例如对XML文件进行处理时,当看到<
时,词法分析器就会进入“标签内部”模式,看到>
或者/>
时就切回默认模式
重写输入流:TokenStreamRewriter
可以对词法输入流进行修改之后再输出,它只是修改词法符号流的“视图”而非其本身的内容。如下所示为一个Java类的输入流中添加指定代码public static final long serialVersionUID = 1L;
,重写监听器进入类的方法,在其中使用rewriter追加内容
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.TokenStreamRewriter;public class InsertSerialIDListener extends JavaBaseListener {TokenStreamRewriter rewriter;public InsertSerialIDListener(TokenStream tokens) {rewriter = new TokenStreamRewriter(tokens);}@Overridepublic void enterClassBody(JavaParser.ClassBodyContext ctx) {String field = "\n\tpublic static final long serialVersionUID = 1L;"; //对输入流添加指定内容rewriter.insertAfter(ctx.start, field);}
}
这篇关于ANTLR中自定义语法分析过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!