平台公式及翻译后的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文法的更多相关文章

  1. CDATA(不应由XML解析器进行解析的文本数据)、CDATA的使用场景

    1.1. CDATA: CDATA(Unparsed Character Data)指的是不应由XML解析器进行解析的文本数据. 因为XML解析器会将“<”(新元素的开始)和“&”(字符 ...

  2. dom4j解析器sax解析xml文件

    1.使用dom4j解析器解析xml ***解析器dom4j是由dom4j组织提供的,针对xml进行解析.dom4j不是Javase的一部分,使用时需要导入dom4j的jar包(官网下载) 在eclip ...

  3. php 解析json失败,解析为空,json在线解析器可以解析,但是json_decode()解析失败(原)

    $str2='{"code":200,"datas":{"id":1,"coupon_id":"123&quo ...

  4. Scala正则和抽取器:解析方法参数

    在<正则表达式基础知识>中概括了正则表达式的基础知识, 本文讲解如何使用正则表达式解析方法参数,从而可以根据 DAO 自动生成 Service. 在做 Java 项目时,常常要根据 DAO ...

  5. Scala词法文法解析器 (二)分析C++类的声明

    最近一直在学习Scala语言,偶然发现其Parser模块功能强大,乃为BNF而设计.啥是BNF,读大学的时候在课本上见过,那时候只觉得这个东西太深奥.没想到所有的计算机语言都是基于BNF而定义的一套规 ...

  6. boost之词法解析器spirit

    摘要:解析器就是编译原理中的语言的词法分析器,可以按照文法规则提取字符或者单词.功能:接受扫描器的输入,并根据语法规则对输入流进行匹配,匹配成功后执行语义动作,进行输入数据的处理. C++ 程序员需要 ...

  7. 自己动手实现一个简单的JSON解析器

    1. 背景 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着诸多优点.比如易读性更好,占用空间更少等.在 ...

  8. 利用 druid 解析器解析SQL

    最近参与一个开源项目,一个功能的实现,用到了 druid 解析器来解析SQL,记录下如果使用 druid 来解析SQL,实现对SQL的拦截改写. 1. 对 insert 语句进行解析: private ...

  9. XML 解析器

    所有现代浏览器都内建了供读取和操作 XML 的 XML 解析器.解析器把 XML 转换为 XML DOM 对象 - 可通过 JavaScript 操作的对象. 解析 XML 文档为DOM对象 方法一: ...

随机推荐

  1. Java学习:方法的引用

    方法引用(Method references) lambda表达式允许我们定义一个匿名方法,并允许我们以函数式接口的方式使用它.我们也希望能够在已有的方法上实现同样的特性. 方法引用和lambda表达 ...

  2. Redis-2-五种基本类型及相关命令

    目录 1.字符串类型:string 1.1 命令 1.2 实践 2.散列类型:hash 2.1命令 2.2 实践 3.列表类型:list 3.1 命令 3.2 实践 4.集合类型:set 4.1 命令 ...

  3. 记Flask的一种设置项目配置的方法!

    在做项目时,碰到的一种设置配置的方式,主要是因为公司将所有的配置写成了一个公司专有的配置库(各种资源地址,账号等),上线后的项目需要什么配置是从这个配置库的读取.但在开发时不能使用,所以在开发时需要自 ...

  4. excel批量添加超链接

    使用 Hyperlink(Link-location,Friendly-name)

  5. (二)RFB协议具体通信说明

    .   消息说明  8.1     握手消息 8.1.1       RFB协议版本号 1.vnc服务器发送所能够支持的最高RFB协议版本号给客户端,格式如下: “RFB xxx.yyy\n”共12b ...

  6. 自己对Thread的一些看法;

    Thread thread= new Thread(new ThreadStart(name);     与 Thread thread= new Thread(name); thread.star( ...

  7. ElasticSearch 查询索引

    GET iis_qr_2019-07/_search #查询iis_qr_2019-07索引下的所有日志 GET iis_qr_2019-07/_search?_source=c-ip,time #只 ...

  8. requests方法中content和text区别

    requests对象的get和post方法都会返回一个Response对象,这个对象里面存的是服务器返回的所有信息,包括响应头,响应状态码等.其中返回的网页部分会存在.content和.text两个对 ...

  9. python列表推导式及其简单应用

    列表推导式(又称列表解析式)提供了一种简明扼要的方法来创建列表 一个简单平方 普通for循环 for i in range(1,5): print(i*i,end='') 列表推导式 res = [x ...

  10. eclipse 离线安装activiti

    1. 下载activiti离线安装包, activiti-designer-1.8.zip 2. 将上图4个jar包放在eclipse的features文件夹中 3. 打开eclipse-->H ...