ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Antlr一个领域语言利器——入门篇

2022-05-25 18:32:04  阅读:262  来源: 互联网

标签:利器 Antlr expr ctx 语法 入门篇 Antlr4 规则 ID


  Antlr(Another Tool for Language Recognition)为开源的语法分析器,可以将输入的内容自动生成语法树;开发者可以使用它自定义自己的领域语言,只需创建语法规则文件,使用Antlr根据该规则文件生成相对应的类,再这些类的基础上我们可以用于实现自己的功能;Antlr4为Antlr的最新版本目前看到的基本也是Antlr4;
  这些类主要包括两个方面的内容:1、实现了对输入的内容进行词法分析(Lexer)部分;2、根据词法构建出对应的语法树(Syntax Tree);
  使用场景: 1、领域特定语言;2、文本解析;3、算术运算等等;在各类开源框架中也都有看到Antlr4的身影,如Hive、Spark、Presto、Hibernate 等等;

Antlr4基础语法

1、语法基本格式

//声明语法头,生成的Java类将使用此前缀,必须与xx.g4文件同名
grammar Name; 
options {}   //选项:语言选,输出选项等;项 
lnaguage=Java;output=AST      
import ... ;  //如g4文件过大可拆分,使用import引入

tokens {...}  //为那些没有关联词法规则的grammar定义tokens类型
channels {...} // 词法分析时才可定义
@actionName {...}   //动作:可将目标语言嵌入到g4中,有可调用对应外部代码

//规则,此语法文件所定义的规则,分为词法规则与语法规则
规则;
rule1
...
ruleN

三个基本动作:

@header { package co.linx.test.antlr; }

此动作可在运行脚本后,所生成的类中自动带上包路径,不用手动移动。

@members {}

将代码中变量或方法注入到recognizer类中

@after {System.out.println("after matching rule;");}

规则:

词法规则(lexer):以大写字母开头,用于词法分析;
语法规则(parser):以小写字母开头,用于语法分析,字符串与lexer组合匹配分析句子;
以 : 开始 ; 结束,用 | 分隔对多规则分隔

2、简单示例

+匹配前一个匹配项最少一次, * 匹配前一个匹配项0次或多次 ?可选 ~ 取反

grammar Hello;
init  :'hello' ID ;          // parser. 匹配关键字'hello'后⾯跟⼀个ID
ID :[a-z]+ ;             // lexer. 匹配⼩写字母组成的ID
WS :[ \t\r\n]+ -> skip ;   //lexer. 系统级规则匹配时跳过空格、tabs、换⾏符

一个Antlr4计算器

1、语法文件:

grammar Calc;

prog : stat+;
stat: expr NEWLINE          # printExpr
| ID '=' expr NEWLINE   # assign
| NEWLINE               # blank
;

expr: expr op=('*'|'/') expr    # MulDiv
| expr op=('+'|'-') expr        # AddSub
| INT                           # int
| ID                            # id
| '(' expr ')'                  # parens
;
MUL : '*' ; // assigns token name to '*' used above in grammar
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
ID : [a-zA-Z]+ ;
INT : [0-9]+ ;
NEWLINE:'\r'? '\n' ;
DELIMITER : ';';
WS : [ \t]+ -> skip;

  可使用Maven插件、IDEA插件、或Antlr4自带命令行工具生成相关词法、语法分析器类;
  Antlr4提供了两种方式可以访问语法树:观察者模式、访问者模式;

  观察者模式: 通过结点监听触发处理方法,无需定义遍历语法树顺序,动作与文法解耦,处理时需通过自定义map存储中间结果,继承:XXXBaseListener类实现;
  访问者模式: 主动遍历语法树,动作与文法解耦,visitor访问节点时有返回值,无需定义map存储中间结果,继承:XXXBaseVisitor类实现;

2、实现计算逻辑

  这里使用访问者模式实现计算器,继承:CalcBaseVisitor类,重写visitMulDiv与visitAddSub方法实现:加减乘除计算逻辑;

@Override 
public Integer visitMulDiv(CalcParser.MulDivContext ctx) {
    Integer left = ctx.expr(0).accept(this);
    Integer right = ctx.expr(1).accept(this);
    if (ctx.op.getType() == CalcParser.MUL){
        return left * right;
    }else{
        return left / right;
    }
}
@Override 
public Integer visitAddSub(CalcParser.AddSubContext ctx) {
    Integer left = ctx.expr(0).accept(this);
    Integer right = ctx.expr(1).accept(this);
    if (ctx.op.getType() == CalcParser.ADD){
        return left + right;
    }else{
        return left - right;
    }
}

3、使用该语法树计算器

CharStream input = CharStreams.fromString("22*3+12\r\n");
CalcLexer lexer=new CalcLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CalcParser parser = new CalcParser(tokens);
ParseTree tree = parser.prog(); // parse
EvalVisitor vt=new EvalVisitor();
System.out.printf("%s\n", vt.visit(tree));

  Antlr的实现可不只是计算器这种小玩意,我们通常有多个数据源,在没有统一的查询入口的时候通常只能打开各个客户端工具进行查询,有了Antlr我们可以很方便的实现一种称之为:XQL的语言,可实现通过XQL就可查询Kafka、Redis、MySQL、文件(csv、json、parquet)等数据源的数据;
  通过Antlr实现的统一XQL查询引擎:

图片1.png

文章首发地址:https://mp.weixin.qq.com/s/BcuiM3ifm-PCOBZUja7vJg
参考资料:
antlr4
语法规则

标签:利器,Antlr,expr,ctx,语法,入门篇,Antlr4,规则,ID
来源: https://www.cnblogs.com/softlin/p/16308992.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有