如何实现一个SQL解析器( 三 )

步骤二:定义语法规则文件(LibExpr.g4)

LibExpr.g4
如何实现一个SQL解析器

文章插图
// 定于语法规则grammar LibExpr;// 导入词法规则import CommonLexerRules;// 词法根prog:stat+ EOF?;// 定义声明stat:expr (NEWLINE)?# printExpr| ID '=' expr (NEWLINE)? # assign| NEWLINE# blank;// 定义表达式expr:expr op=('*'|'/') expr # MulDiv|expr op=('+'|'-') expr # AddSub|'(' expr ')'# Parens|ID# Id|INT# Int;步骤三:编译生成文件
如果是Maven工程,这里在pom文件中添加如下依赖:
ANTLR依赖JAR
如何实现一个SQL解析器

文章插图
<dependencies><dependency><groupId>org.antlr</groupId><artifactId>antlr4</artifactId><version>4.9.3</version></dependency><dependency><groupId>org.antlr</groupId><artifactId>antlr4-runtime</artifactId><version>4.9.3</version></dependency></dependencies>然后,执行Maven编译命令即可:
Maven编译命令
如何实现一个SQL解析器

文章插图
mvn generate-sources步骤四:编写简单的示例代码
待预算的示例文本:
示例文本

如何实现一个SQL解析器

文章插图
如何实现一个SQL解析器

文章插图
1+21+2*41+2*4-51+2*4-5+20/5(1+2)*4加减乘除逻辑类:
逻辑实现类
如何实现一个SQL解析器

文章插图
package com.vivo.learn.sql;import java.util.HashMap;import java.util.Map;/** * 重写访问器规则,实现数据计算功能 * 目标: *1+2 => 1+2=3 *1+2*4 => 1+2*4=9 *1+2*4-5 => 1+2*4-5=4 *1+2*4-5+20/5 => 1+2*4-5+20/5=8 *(1+2)*4 => (1+2)*4=12 */public class LibExprVisitorImpl extends LibExprBaseVisitor<Integer> {// 定义数据Map<String,Integer> data = https://www.huyubaike.com/biancheng/new HashMap();// expr (NEWLINE)?# printExpr@Overridepublic Integer visitPrintExpr(LibExprParser.PrintExprContext ctx) {System.out.println(ctx.expr().getText()+"="+visit(ctx.expr()));return visit(ctx.expr());}// ID '=' expr (NEWLINE)? # assign@Overridepublic Integer visitAssign(LibExprParser.AssignContext ctx) {// 获取idString id = ctx.ID().getText();// // 获取valueint value = https://www.huyubaike.com/biancheng/Integer.valueOf(visit(ctx.expr()));// 缓存ID数据data.put(id,value);// 打印日志System.out.println(id+"="+value);return value;}// NEWLINE# blank@Overridepublic Integer visitBlank(LibExprParser.BlankContext ctx) {return 0;}// expr op=('*'|'/') expr # MulDiv@Overridepublic Integer visitMulDiv(LibExprParser.MulDivContext ctx) {// 左侧数字int left = Integer.valueOf(visit(ctx.expr(0)));// 右侧数字int right = Integer.valueOf(visit(ctx.expr(1)));// 操作符号int opType = ctx.op.getType();// 调试// System.out.println("visitMulDiv>>>>> left:"+left+",opType:"+opType+",right:"+right);// 判断是否为乘法if(LibExprParser.MUL==opType){return left*right;}// 判断是否为除法return left/right;}// expr op=('+'|'-') expr # AddSub@Overridepublic Integer visitAddSub(LibExprParser.AddSubContext ctx) {// 获取值和符号// 左侧数字int left = Integer.valueOf(visit(ctx.expr(0)));// 右侧数字int right = Integer.valueOf(visit(ctx.expr(1)));// 操作符号int opType = ctx.op.getType();// 调试// System.out.println("visitAddSub>>>>> left:"+left+",opType:"+opType+",right:"+right);// 判断是否为加法if(LibExprParser.ADD==opType){return left+right;}// 判断是否为减法return left-right;}// '(' expr ')'# Parens@Overridepublic Integer visitParens(LibExprParser.ParensContext ctx) {// 递归下调return visit(ctx.expr());}// ID# Id@Overridepublic Integer visitId(LibExprParser.IdContext ctx) {// 获取idString id = ctx.ID().getText();// 判断ID是否被定义if(data.containsKey(id)){// System.out.println("visitId>>>>> id:"+id+",value:"+data.get(id));return data.get(id);}return 0;}// INT# Int@Overridepublic Integer visitInt(LibExprParser.IntContext ctx) {// System.out.println("visitInt>>>>> int:"+ctx.INT().getText());return Integer.valueOf(ctx.INT().getText());}}Main函数打印输出结果类:
package com.vivo.learn.sql;import org.antlr.v4.runtime.tree.ParseTree;import java.io.FileNotFoundException;import java.io.IOException;import org.antlr.v4.runtime.*;/** * 打印语法树 */public class TestLibExprPrint {// 打印语法树 input -> lexer -> tokens -> parser -> tree -> printpublic static void main(String args[]){printTree("E:\\smartloli\\hadoop\\sql-parser-example\\src\\main\\resources\\testCase.txt");}/*** 打印语法树 input -> lexer -> token -> parser -> tree* @param fileName*/private static void printTree(String fileName){// 定义输入流ANTLRInputStream input = null;// 判断文件名是否为空,若不为空,则读取文件内容,若为空,则读取输入流if(fileName!=null){try{input = new ANTLRFileStream(fileName);}catch(FileNotFoundException fnfe){System.out.println("文件不存在,请检查后重试!");}catch(IOException ioe){System.out.println("文件读取异常,请检查后重试!");}}else{try{input = new ANTLRInputStream(System.in);}catch(FileNotFoundException fnfe){System.out.println("文件不存在 , 请检查后重试!");}catch(IOException ioe){System.out.println("文件读取异常,请检查后重试!");}}// 定义词法规则分析器LibExprLexer lexer = new LibExprLexer(input);// 生成通用字符流CommonTokenStream tokens = new CommonTokenStream(lexer);// 语法解析LibExprParser parser = new LibExprParser(tokens);// 生成语法树ParseTree tree = parser.prog();// 打印语法树// System.out.println(tree.toStringTree(parser));// 生命访问器LibExprVisitorImpl visitor = new LibExprVisitorImpl();visitor.visit(tree);}}

推荐阅读