The Definitive Antlr 4 Reference 2nd Edition 第4章第一小节 学习笔记
匹配算数表达式语言
本例中,只使用基本的算数运算(加,减,乘,除),括号表达式,整数,及变量。例如有如下的表达式。
193 a = 5 b = 6 a+b*2 (1+2)*3
在这里介绍的表达式语言,是由换行符所分割的一组语句构成。语句可以是表达式、赋值运算、或是一个空行。下面是用于解析上述语句及表达式的Antlr文法。
grammar expr; prog : stat+; stat : expr NEWLINE | ID '=' expr NEWLINE | NEWLINE ; expr: expr ('*' | '/') expr | expr ('+' | '-') expr | INT | ID | '(' expr ')' ; ID : [a-zA-Z]+; INT : [0-9]+; NEWLINE: '\r'?'\n';
首先说明Antlr文法概念中的一些关键概念。
- 文法由一组描述语法的规则组成。其中包括词法与语法规则。
- 语法规则是以小写字母组成。如prog,stat。
- 词法规则由大写字母组成。如ID:[a-zA-Z]+。
- 通过使用 | 运算符来将不同的规则分割,还可以使用括号构成子规则。例如(‘*’ | ‘/’)会匹配多个乘号或除号。
上面的文法中 –> skip是一个指示符,用来告诉词法分析器来匹配,并丢弃这些空白符。
此外Antlr v4 的一个重要的特性是能够处理大多数的左递归规则。
文法文件写完后 鼠标右键文法文件 -> Generate Antlr...... 随后会在指定的目录下生成XXparser 与 XXLexer文件。通过这些文件就可以完成分析任务了。
public class Main { public static void main(String[] args) { String expr = "(1+2*3/2-7))"; ANTLRInputStream input = new ANTLRInputStream(expr); exprLexer lexer = new exprLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); exprParser parser = new exprParser(tokens); ParseTree tree = parser.prog(); System.out.println(tree.toStringTree(parser)); } }
代码中创建了字符输入流对象,用作创建词法分析对象的输入。随后创建词法(ExprLexer)分析对象、符号流对象(CommonTokenStream)、及语法(ExprParser)分析对象。CommonTokenStream将ExprParser与ExprLexer串联在了一起。代码最后打印出分析树。
导入文法
若将所有内容写在一个文件内,则不便于管理,因此可以将文法文件分解。其中一种办法是将文法与词法分开定义。通过lexer grammar定义词法文件,最后在语法文件中用import关键字将词法定义导入。
定义文法文件,该文件内的词法定义已经移入CommonLexerRules.g4文件中,并通过import导入该文件内容。
expr.g4文件
grammar expr; import CommonLexerRules; prog : stat+; stat : expr NEWLINE | ID '=' expr NEWLINE | NEWLINE ; expr: expr ('*' | '/') expr | expr ('+' | '-') expr | INT | ID | '(' expr ')' ;
CommonLexerRules.g4
lexer grammar CommonLexerRules; ID : [a-zA-Z]+; INT : [0-9]+; NEWLINE: '\r'?'\n'; WS : [\t]+ -> skip;
时间: 2024-11-07 20:39:13