antlr4 入门小结
1. 包的引入(使用maven):
<plugin> <groupId>org.antlr</groupId> <artifactId>antlr4-maven-plugin</artifactId> <version>4.9.2</version> <configuration> <sourceDirectory>src/main/antlr</sourceDirectory> <outputDirectory>src/main/java/net/rainforwind/antlr/gen</outputDirectory> </configuration> <executions> <execution> <goals> <goal>antlr4</goal> </goals> </execution> </executions> </plugin>
2. 代码生成(需要第三步的词法语法定义)
mvn antlr4:antlr4
3. 词法语法定义示例文件:
DemoLexer.g4
lexer grammar DemoLexer;
@header {
package net.rainforwind.antlr.gen;
}
WS: [ \t\r\n]+ -> skip ;
ID: [A-Za-z_] [A-Za-z0-9_]* ;
//String: '\'' (~'\'')* '\'' ;
Lquote: '\'' -> more, pushMode(STR) ;
Comma: ',';
Lparen: '(';
Rparen: ')';
mode STR ;
String: '\'' -> popMode ;
TEXT: . -> more ;
DemoParser.g4
parser grammar DemoParser;
options { tokenVocab=DemoLexer; }
@header {
package net.rainforwind.antlr.gen;
}
func: funcName Lparen (arg moreArg*)? Rparen ;
funcName: ID ;
arg: func | string ;
string: String;
moreArg: Comma arg ;
也可以在一个文件里面进行词法语法的混合声明,对应上面两个文件,文件名叫 Demo.g4,生成的代码会自动加Lexer/Parser后缀,结果和上面保持一致。
其中的文件开头改为
grammar Demo;
@header {
package net.rainforwind.antlr.gen;
}
生成的结果文件示例:
DemoLexer.java // 词法分析类 DemoLexer.interp // 词法符号表 DemoLexer.tokens // token表 DemoParser.java // 语法分析类 DemoParser.interp // 语法符号表 DemoParser.tokens // token表(同上) DemoParserBaseListener.java // 预发分析监听接口缺省实现(空实现) DemoParserListner.java // 语法分析监听接口
4. 生产Java类的使用:
先上示例:
@Test public void testLexing() { DemoLexer lexer = new DemoLexer(CharStreams.fromString("hello('world', foo('bar'))")); lexer.addErrorListener(new BaseErrorListener(){ @Override public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { throw new RuntimeException("lexer syntax error."); } }); DemoParser parser = new DemoParser(new CommonTokenStream(lexer)); parser.addParseListener(new DemoParserBaseListener(){ @Override public void enterFuncName(FuncNameContext ctx) { super.enterFuncName(ctx); System.out.println("enter funcName: " + ctx.toString()); } }); try { FuncContext r = parser.func(); System.out.println(contextToString(r)); } catch (RuntimeException e) { System.err.println(e.getMessage()); } } private String contextToString(ParserRuleContext ctx) { StringBuilder result = new StringBuilder(getContextPrefix(ctx)); result.append("("); boolean first = true; for (ParseTree child : ctx.children) { if (first) { first = false; } else { result.append(","); } result.append(contextToString(child)); } result.append(")"); return result.toString(); } private String contextToString(ParseTree tree) { if (tree instanceof TerminalNode) { return "" + ((TerminalNode) tree).getSymbol().getText() + ""; } else if (tree instanceof ParserRuleContext) { StringBuilder result = new StringBuilder(getContextPrefix((ParserRuleContext) tree)).append("("); boolean first = true; for (ParseTree child : ((ParserRuleContext) tree).children) { if (first) { first = false; } else { result.append(","); } result.append(contextToString(child)); } result.append(")"); return result.toString(); } else { return "ERROR: tree type not handled: " + tree.getClass(); } } private String getContextPrefix(ParserRuleContext ctx) { String className = ctx.getClass().getSimpleName(); return className.substring(0, className.length() - 7); }
示例输出:
enter funcName: [10]
enter funcName: [10 25 32 13]
Func(FuncName(hello),(,Arg(String('world')),MoreArg(,,Arg(Func(FuncName(foo),(,Arg(String('bar')),)))),))
说明:
- Lexer实例化时使用CharStreams来转化输入,Parser实例化时使用CommonTokenStream来引入lexer实例。
- Parser中的任何一个规则都对应生产了一个方法,直接调用该方法就执行了语法解析功能,返回一个对应类型的Context对象,即为结果语法树的跟。
- 如果要在解析过程中进行回调,实现Listener接口中对应语法规则的enter/exit方法即可。
- 解析错误默认会忽略,所以如果要拦截错误语法,则需要添加ErrorListener监听器来处理,如抛出异常。 more, mode, 属性, returns,type,channel 等语法参考官方文档,因为文档写的比较绕,所以补充几句。
- more 用在词法定义中,代表本条规则不规约,将其匹配到的内容合并到后续执行中第一个非more且非skip的规则结果中。
- mode、pushMode、PopMode 用在词法定义中,代表模式切换(缺省为
DEFAULT_MODE) - 语法规则的头部(冒号之前的部分)不止可以有规则名称,还可以声明属性、返回值(returns)、局部变量(locals),属性和返回值可以在其他规则引用该规则是使用。
- 词法分析中,type可以声明实际规约到哪个token,在一个token有多种case的情况下,就不需要用或的关系来一次性写全,而是可以随时补充。
- channel,将分析结果发送到其他通道,可以处理注释等内容。

浙公网安备 33010602011771号