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对象 方法一: ...
随机推荐
- 2019-11-29-win10-uwp-关联文件
原文:2019-11-29-win10-uwp-关联文件 title author date CreateTime categories win10 uwp 关联文件 lindexi 2019-11- ...
- vs 发版时,在发版的文件夹中,找不到应该有的某个文件
检查:VS中,这个文件右击属性,查看生成操作.如果是“无”,改为“内容”.再重新发布就没问题了. 想看发版出来的内容包括哪些,可以从“发布”--“应用程序文件”查看
- mysql 查询数据库表信息,字段信息
#======================================================================= #查询表信息 select table_name, t ...
- ActionMq + mqttws3.1 实现持久化订阅
activemq版本:5.15.3 Eclipse Paho MQTT JavaScript library mqttws3.1:在amq安装目录下webapp-demo目录下可以找到 实现步骤请阅读 ...
- Golang中,Aes加解密
今天在用Golang解析php那边用Aes加密的一个key.网上大多是用base64将结果编码一下.而且用到了向量.我php 那边没有用到向量.所以golang这边也是要去掉的.参考网站的改了下.能够 ...
- 第一阶段:Java基础 1.JAVA开发介绍---1.常用的DOS命令
一,DOS使用常识 DOS的概况:DOS(Disk Operating System)是一个使用得十分广泛的磁盘操作系统.DOS的概况 常见的DOS有两种:IBM公司的PC-DOS和微软公司的MS-D ...
- sklearn聚类评价指标
sklearn中的指标都在sklearn.metric包下,与聚类相关的指标都在sklearn.metric.cluster包下,聚类相关的指标分为两类:有监督指标和无监督指标,这两类指标分别在skl ...
- 关于VS C++中项目属性的一些名称的含义
这个属性页(Alt + F7)界面下的$开头的内容的含义 $(Platform), X64或X86类似的. $(SolutionDir),.sln的位置 $(Configuration), Debug ...
- 类似hover的css伪类注解
a:link { font-size: 14pt; text-decoration: underline; color: blue; } /*设置a对象在未被访问前的样式表属性 .*/ a:hover ...
- vue+element下拉框样式的点击按钮
项目中点击按钮实在太多了,怎么办呢?我们就可以将它们制作成像下拉框那样的类似操作 1.HTML样式部分:关键点在于command 方法和属性 1 <el-dropdown 2 size=&quo ...