ANTLR
一款强大的生成"语法解析器"的工具,可以用作读取、处理、执行或翻译结构化文本或二进制文件。广泛的用来构建新的语言、工具和框架。这个"语法解析器"创建和遍历语法树。
eg:Hive和Spark使用antlr生成词法语法解析器、Twitter使用antlr来解析用户输入的查询内容,Oracle把antlr的功能内嵌在SQL 开发IDE中,NetBeans IDE使用antlr解析C++语言,也有公司使用antlr来从文件中抽取信息
大致流程:
- 首先需要编写文法文件(g4后缀);
- 然后使用g4文法文件通过antlr工具生成lexer词法解析器、parser语法解析器、visitor和listener的runtime target文件(支持多种语言)
- 然后可以直接使用输出的runtime target文件模块进行开发工作
生成MySQL语法解析器
安装ANTLR工具:
cd /usr/local/lib
wget https://www.antlr.org/download/antlr-4.7.2-complete.jar
export CLASSPATH=".:/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH"
alias antlr4='java -jar /usr/local/lib/antlr-4.7.2-complete.jar'
alias grun='java org.antlr.v4.gui.TestRig'
根据mysql文法文件生成Python词法/语法解析器:
antlr4 -Dlanguage=Python2 MySqlLexer.g4
antlr4 -Dlanguage=Python2 MySqlParser.g4
安装Python runtime模块
pip install antlr4-python2-runtime
测试用例:
import sys
from antlr4 import *
from antlr4.InputStream import InputStream
from MySqlLexer import MySqlLexer
from MySqlParser import MySqlParser
class CaseChangingCharInputStream(InputStream):
def __init__(self, data, upper=True):
super(CaseChangingCharInputStream, self).__init__(data)
self.upper = upper
def LA(self, pos):
value = super(CaseChangingCharInputStream, self).LA(pos)
if 0 <= value < 256:
if pos <= 0: return value
str_value = chr(value)
return ord(str_value.upper()) if self.upper else ord(str_value.lower())
else:
return value
class CaseChangingCharFileStream(FileStream, CaseChangingCharInputStream):
def __init__(self, file, upper=True):
super(CaseChangingCharFileStream, self).__init__(file)
self.upper = upper
if __name__ == '__main__':
if len(sys.argv) > 1:
input_stream = CaseChangingCharFileStream(sys.argv[1])
else:
input_stream = CaseChangingCharInputStream('SeLeCT id FROM student')
lexer = MySqlLexer(input_stream)
token_stream = CommonTokenStream(lexer)
parser = MySqlParser(token_stream)
tree = parser.root()
问题
- mysql语句不区分大小写,但是目前官方提供的g4文件是区分大小写的,所以使用lexer/parser时会报错。
- 两种方案:一种是修改g4文件;一种是在喂给lexer之前,将所有字符转成大写。
- 官方解释
# 重写LA
class CaseChangingCharInputStream(InputStream):
def __init__(self, data, upper=True):
super(CaseChangingCharInputStream, self).__init__(data)
self.upper = upper
def LA(self, pos):
value = super(CaseChangingCharInputStream, self).LA(pos)
if 0 <= value < 256:
if pos <= 0: return value
str_value = chr(value)
return ord(str_value.upper()) if self.upper else ord(str_value.lower())
else:
return value
class CaseChangingCharFileStream(FileStream, CaseChangingCharInputStream):
def __init__(self, file, upper=True):
super(CaseChangingCharFileStream, self).__init__(file)
self.upper = upper
欢迎关注微信公众号(coder0x00)或扫描下方二维码关注,我们将持续搜寻程序员必备基础技能包提供给大家。
网友评论