0
Antlr是一个比较老的项目了,最新的版本是4.7。个人觉得,这个项目现在之所以成功,还是因为开源以后,很多人都来贡献Antlr的语法文件。在github上,你可以找到主流编程语言的语法文件(https://github.com/antlr/grammars-v4/)。有了语法文件,你就可以直接通过简单的教程使用Antlr。
我们在使用Antlr的时候,已经有了TSQL.g4文件了。语法不是很完整,但我们可以自己贡献代码去帮助其更加完整。可以预见的是,这些语法文件会越来越完整的。
此外,中文的可以参考https://dohkoos.gitbooks.io/antlr4-short-course/content/getting-started.html。
通常,我们会看微软自己有没有开发的工具或者API用来分析TSQL。最好的情况就是SSMS里面有个语法分析的组件单独分离出来使用。其实后来我也找到了这样的工具,叫 microsoft.sqlserver.transactsql.scriptdom。但是后来我们考虑到可能还要支持其他类型的数据库,所以我还是选择了Antlr。
在Github上面找到tsql的语法文件,再按照快速入门的步骤,配置好环境,执行下面的命令,就可以拿到整个语法树了。
比如,我们要求在存储过程中,不能够使用PRINT语句,因为我们不希望存储过程返回除了respond code之外的信息。用Listener的话,我只需要在进入和退出存储过程的时候,设置一个flag。然后再判断所有的PRINT语句,如果当前flag为true,就表明这个PRINT是在存储过程里面。
Posted on
Wednesday, April 26, 2017
by
醉·醉·鱼
and labeled under
antlr
Antlr的全程是ANother Tool for Language Recognition,可以用来实现编程语言的解析。由于项目的需要,最近一个月和同事完成了一个针对TSQL的语法分析,进而创建一些规则去审查代码(连这都自动化掉,我实在是太懒了!)。Antlr是一个比较老的项目了,最新的版本是4.7。个人觉得,这个项目现在之所以成功,还是因为开源以后,很多人都来贡献Antlr的语法文件。在github上,你可以找到主流编程语言的语法文件(https://github.com/antlr/grammars-v4/)。有了语法文件,你就可以直接通过简单的教程使用Antlr。
我们在使用Antlr的时候,已经有了TSQL.g4文件了。语法不是很完整,但我们可以自己贡献代码去帮助其更加完整。可以预见的是,这些语法文件会越来越完整的。
学习Antlr
最经典的还是这个工具开发者自己写的书《The Definitive ANTLR 4 Reference》。快速入门,可以参考https://tomassetti.me/antlr-mega-tutorial/#working-with-a-listener 以及 http://jakubdziworski.github.io/java/2016/04/01/antlr_visitor_vs_listener.html此外,中文的可以参考https://dohkoos.gitbooks.io/antlr4-short-course/content/getting-started.html。
分析TSQL
这个项目的目的就是分析TSQL,进而审查代码,以便开发避免一些坏的编程习惯。要分析TSQL,我们第一反应都是用正则表达式。很不幸,在这个事情上,正则表达式简直是弱爆了!我找到一个比较成熟的语法分析工具,不过是针对pg数据库的。https://pganalyze.com/blog/parse-postgresql-queries-in-ruby.html。文中作者在无数次尝试以后,也发现正则表达式的无力。通常,我们会看微软自己有没有开发的工具或者API用来分析TSQL。最好的情况就是SSMS里面有个语法分析的组件单独分离出来使用。其实后来我也找到了这样的工具,叫 microsoft.sqlserver.transactsql.scriptdom。但是后来我们考虑到可能还要支持其他类型的数据库,所以我还是选择了Antlr。
在Github上面找到tsql的语法文件,再按照快速入门的步骤,配置好环境,执行下面的命令,就可以拿到整个语法树了。
antlr4 tsql.g4 && javac *.java && grun tsql tsql_file -gui test.sql
Vistior 和 Listener之争
这只是分析语法的两种不同方式而已,看自己的情况选择。一般来说,如果你只想分析某一个rule以及他下面的rule,可以考虑用Visitor。用Listener的话,可以自动的遍历所有的rule。个人而言,还是喜欢Listener。比如,我们要求在存储过程中,不能够使用PRINT语句,因为我们不希望存储过程返回除了respond code之外的信息。用Listener的话,我只需要在进入和退出存储过程的时候,设置一个flag。然后再判断所有的PRINT语句,如果当前flag为true,就表明这个PRINT是在存储过程里面。