Scala词法文法解析器 (一)解析SparkSQL的BNF文法
平台公式及翻译后的SparkSQL
平台公式的样子如下所示:
if (XX1_m001[D003]="邢おb7肮α䵵薇" || XX1_m001[H003]<"2") && XX1_m001[D005]!="wed" thenXX1_m001[H022,COUNT]
这里面字段值"邢おb7肮α䵵薇"为这个的目的是为了测试各种字符集是否都能匹配满足。
那么对应的SparkSQL应该是这个样子的,由于是使用的Hive on Spark,因而长得跟Oracle的SQL语句差不多:
SELECT COUNT(H022) FROM XX1_m001 WHERE (XX1_m001.D003='邢おb7肮α䵵薇' OR XX1_m001.H003<'2') ANDXX1_m001.D005<'wed'
总体而言比较简单,因为我只是想在这里做一个Demo。
平台公式的EBNF范式及词法解析设计
expr-condition ::= tableName "[" valueName "]" comparator Condition
expr-front ::= expr-condition (("&&"|"||")expr-front)*
expr-back ::= tableName "[" valueName "," operator "]"
expr ::= "if" expr-front "then" expr-back
其中词法定义如下
operator => [SUM,COUNT]
tableName,valueName =>ident #ident为关键字
comparator => ["=",">=","<=",">","<","!="]
Condition => stringLit #stringLit为字符串常量
使用Scala基于词法单元的解析器解析上述EBNF文法
Scala基于词法单元的解析器是需要继承StandardTokenParsers这个类的,该类提供了很方便的解析函数,以及词法集合。
我们可以通过使用lexical.delimiters列表来存放在文法翻译器执行过程中遇到的分隔符,使用lexical.reserved列表来存放执行过程中的关键字。
比如,我们参照平台公式,看到"=",">=","<=",">","<","!=","&&","||","[","]",",","(",")"这些都是分隔符,其实我们也可以把"=",">=","<=",">","<","!=","&&","||"当做是关键字,但是我习惯上将带有英文字母的单词作为关键字处理。因而,这里的关键字集合便是"if","then","SUM","COUNT"这些。
表现在代码中是酱紫的:
lexical.delimiters += ("=",">=","<=",">","<","!=","&&","||","[","]",",","(",")")
lexical.reserved += ("if","then","SUM","COUNT")
是不是so easy~。
我们再来看一下如何使用基于词法单元的解析器解析前面我们设计的EBNF文法呢。我在这里先上代码:
class ExprParsre extends StandardTokenParsers{
lexical.delimiters += ("=",">=","<=",">","<","!=","&&","||","[","]",",","(",")")
lexical.reserved += ("if","then","SUM","COUNT")
def expr: Parser[String] = "if" ~ expr_front ~ "then" ~ expr_back ^^{
case "if" ~ exp1 ~ "then" ~ exp2 => exp2 + " WHERE " +exp1
}
def expr_priority: Parser[String] = opt("(") ~ expr_condition ~ opt(")") ^^{
case Some("(") ~ conditions ~ Some(")") => "(" + conditions +")"
case Some("(") ~ conditions ~ None => "(" + conditions
case None ~ conditions ~ Some(")") => conditions +")"
case None ~ conditions ~ None => conditions
}
def expr_condition: Parser[String] = ident ~ "[" ~ ident ~ "]" ~ ("="|">="|"<="|">"|"<"|"!=") ~ stringLit ^^{
case ident1~"["~ident2~"]"~"="~stringList => ident1 + "." + ident2 +"='" + stringList +"'"
case ident1~"["~ident2~"]"~">="~stringList => ident1 + "." + ident2 +">='" + stringList +"'"
case ident1~"["~ident2~"]"~"<="~stringList => ident1 + "." + ident2 +"<='" + stringList +"'"
case ident1~"["~ident2~"]"~">"~stringList => ident1 + "." + ident2 +">'" + stringList +"'"
case ident1~"["~ident2~"]"~"<"~stringList => ident1 + "." + ident2 +"<'" + stringList +"'"
case ident1~"["~ident2~"]"~"!="~stringList => ident1 + "." + ident2 +"!='" + stringList +"'"
}
def comparator: Parser[String] = ("&&"|"||") ^^{
case "&&" => " AND "
case "||" => " OR "
}
def expr_front: Parser[String] = expr_priority ~ rep(comparator ~ expr_priority) ^^{
case exp1 ~ exp2 => exp1 + exp2.map(x =>{x._1 + " " + x._2}).mkString(" ")
}
def expr_back: Parser[String] = ident ~ "[" ~ ident ~ "," ~ ("SUM"|"COUNT") ~ "]" ^^ {
case ident1~"["~ident2~","~"COUNT"~"]" => "SELECT COUNT("+ ident2.toString() +") FROM " + ident1.toString()
case ident1~"["~ident2~","~"SUM"~"]" => "SELECT SUM("+ ident2.toString() +") FROM " + ident1.toString()
}
def parserAll[T]( p : Parser[T], input :String) = {
phrase(p)( new lexical.Scanner(input))
}
}
另参考:
Scala词法文法解析器 (二)分析C++类的声明
Scala词法文法解析器 (一)解析SparkSQL的BNF文法的更多相关文章
- CDATA(不应由XML解析器进行解析的文本数据)、CDATA的使用场景
1.1. CDATA: CDATA(Unparsed Character Data)指的是不应由XML解析器进行解析的文本数据. 因为XML解析器会将“<”(新元素的开始)和“&”(字符 ...
- dom4j解析器sax解析xml文件
1.使用dom4j解析器解析xml ***解析器dom4j是由dom4j组织提供的,针对xml进行解析.dom4j不是Javase的一部分,使用时需要导入dom4j的jar包(官网下载) 在eclip ...
- php 解析json失败,解析为空,json在线解析器可以解析,但是json_decode()解析失败(原)
$str2='{"code":200,"datas":{"id":1,"coupon_id":"123&quo ...
- Scala正则和抽取器:解析方法参数
在<正则表达式基础知识>中概括了正则表达式的基础知识, 本文讲解如何使用正则表达式解析方法参数,从而可以根据 DAO 自动生成 Service. 在做 Java 项目时,常常要根据 DAO ...
- Scala词法文法解析器 (二)分析C++类的声明
最近一直在学习Scala语言,偶然发现其Parser模块功能强大,乃为BNF而设计.啥是BNF,读大学的时候在课本上见过,那时候只觉得这个东西太深奥.没想到所有的计算机语言都是基于BNF而定义的一套规 ...
- boost之词法解析器spirit
摘要:解析器就是编译原理中的语言的词法分析器,可以按照文法规则提取字符或者单词.功能:接受扫描器的输入,并根据语法规则对输入流进行匹配,匹配成功后执行语义动作,进行输入数据的处理. C++ 程序员需要 ...
- 自己动手实现一个简单的JSON解析器
1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等.在 ...
- 利用 druid 解析器解析SQL
最近参与一个开源项目,一个功能的实现,用到了 druid 解析器来解析SQL,记录下如果使用 druid 来解析SQL,实现对SQL的拦截改写. 1. 对 insert 语句进行解析: private ...
- XML 解析器
所有现代浏览器都内建了供读取和操作 XML 的 XML 解析器.解析器把 XML 转换为 XML DOM 对象 - 可通过 JavaScript 操作的对象. 解析 XML 文档为DOM对象 方法一: ...
随机推荐
- 关于SQL server事务
- 2019 多点Dmalljava面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.多点Dmall等公司offer,岗位是Java后端开发,因为发展原因最终选择去了多点Dmall,入职一年时间了 ...
- make几个知识点
即时变量和延时变量 在下面代码中,定义了一个值为x的x变量,以延时变量的方式将它的值赋给y,以即时变量的方式将它的值赋给z. 因为y为延时变量,所以y的取值并不会立即计算,而是在整个文件解析完成之后才 ...
- 【转载】C#的ArrayList使用Contains方法判断是否包含某个元素
在C#的编程开发中,ArrayList集合是一个常用的非泛型类集合,在ArrayList集合中可以使用Contains方法判断是否包含某个元素数据,如果包含则返回true,否则返回false,Cont ...
- wc.exe个人项目
1.GitHub项目 https://github.com/Littlehui3/wc 2.用时表格 PSP2.1 任务内容 计划完成需要的时间(min) 实际完成需要的时间(min) Plannin ...
- Spring Boot集成Druid数据库连接池
1. 前言 Druid数据库连接池由阿里巴巴开源,号称是java语言中最好的数据库连接池,是为监控而生的.Druid的官方地址是:https://github.com/alibaba/druid 通过 ...
- 部署LNMP应用平台
一.LNMP应用平台概述 1.概述:LNMP代表的就是:Linux系统下Nginx+MySQL+PHP这种网站服务器架构.Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/ ...
- Nginx Rewrite相关功能-rewrite指令
Nginx Rewrite相关功能-rewrite指令 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.
- 并发编程 || Java线程详解
通用线程模型 在很多研发当中,实际应用是基于一个理论再进行优化的.所以,在了解JVM规范中的Java线程的生命周期之前,我们可以先了解通用的线程生命周期,这有助于我们后续对JVM线程生命周期的理解. ...
- Spring的感知能力 Aware
在 Spring 框架中有一个 org.springframework.beans.factory.Aware 接口, Aware 是感知感应的意思,那么此接口的作用就是为 Spring 中的 bea ...