在C#中使用Irony实现SQL语句的解析

在上一篇博文 LogoSharp:Logo语言的C#实现中,我介绍了LOGO语言的C#实现,在该项目中,我使用了.NET下的语法解析框架:Irony。Irony框架最开始的时候是由Roman Ivantsov发布在codeplex上的一个开源项目,它使用MIT协议开源。由于2017年的时候,微软关闭了codeplex服务,为了让这个优秀的项目能够继续为人所用,我将其复制到了我的Github账号下,并将其移植到NET Standard 2.0,地址是:https://github.com/daxnet/irony。于是,Irony目前可以在.NET Core下使用了。事实上,Github中有很多Irony的版本,但大多数都不支持.NET Core。

不仅如此,我还在Azure DevOps上配置了持续集成,因此,你可以通过NuGet很方便地使用Irony。Irony相关的NuGet包有两个,你需要在你的项目中同时安装以下两个NuGet包:

1
2
Install-Package Irony.NetCore -Version 1.1.11
Install-Package Irony.Interpreter.NetCore -Version 1.1.11

接下来,我介绍一下如何用Irony实现一个语法解析器,我们以SQL语句为例进行介绍。

所有使用Irony框架的语法定义,都必须继承于Grammar类,并加上Language特性。以下就是我定义的一个SQL语句的语法,我称之为“Mini SQL”,因为它目前只支持SELECT语句,而且不支持WHERE子句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[Language( "Mini SQL" , "1.0" , "A SQL Sample" )]
public class MiniSqlGrammar : Grammar
{
     public MiniSqlGrammar()
         : base ( false )
     {
         var identifier = new IdentifierTerminal( "Identifier" );
         var table = new NonTerminal( "table" );
         var fields = new NonTerminal( "fields" );
         var sql_statement = new NonTerminal( "SQL" );
 
         table.Rule = identifier;
         fields.Rule = "*" | MakePlusRule(fields, ToTerm( "," ), identifier);
 
         sql_statement.Rule = "SELECT" + fields + "FROM" + table;
 
         Root = sql_statement;
     }
}

代码非常简单,也很容易理解,它可以使用人类比较容易读懂的语法定义规则进行语法定义。这里简单介绍一下上面的代码:

  • Language特性用于描述我们自定义的语法

  • 语法类需要继承于Grammar类

  • 基类构造函数的false参数表示我们的语言是大小写不敏感的

  • 所有的程序语言标识符都可以用IdentifierTerminal进行定义,Irony已经自带了标识符的识别逻辑,非常简单

  • table是一个标识符

  • fields可以是*,也可以是由一些标识符通过逗号分隔的一个列表

  • SQL语句由四个部分组成:SELECT关键字、fields字段列表、FROM关键字以及table数据表名

  • Root=sql_statement表示语言的解析入口就是SQL语句

编译通过后,我们就可以使用这个语法进行SELECT语句的解析了。

Irony有一个非常不错的功能,就是它提供一个用户界面,用来测试我们定义的语法。这个用户界面是一个Windows Forms的应用程序,我也将其发布到我的Github账号下,地址是:https://github.com/daxnet/irony-explorer。下载以后编译执行GrammarExplorer项目,就可以打开这个测试界面。在测试界面中,打开包含有自定义语法的.NET DLL,就可以将其添加到Grammar Explorer中。例如,下图展示了我用Grammar Explorer测试上面的SQL语法的界面效果:

640?wx_fmt=png

在Grammar Explorer中,你可以看到我们自定义语法是否存在错误,还可以使用一个具有代码着色功能的编辑器进行测试,点击Parse按钮,即可生成语法解析树。

使用Irony进行语法解析的基本步骤是:

  1. 基于语法(Grammar)定义,创建语言数据(Language Data)

  2. 基于语言数据,产生解析器(Parser)

  3. 使用解析器,解析输入的字符串,生成语法树

  4. 遍历语法树,执行相应的程序逻辑

下面的代码展示了这一过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
sealed class SqlParser
{
     private static readonly LanguageData languageData = new LanguageData( new MiniSqlGrammar());
     private static readonly Parser parser = new Parser(languageData);
     private readonly List< string > parsedFields = new List< string >();
 
     public void Execute( string command)
     {
         var tree = parser.Parse(command);
         if (tree.HasErrors())
         {
             return ;
         }
 
         ParseTree(tree.Root);
     }
 
     private void ParseTree(ParseTreeNode node)
     {
         switch (node.Term.Name)
         {
             case "SQL" :
                 foreach ( var child in node.ChildNodes)
                 {
                     ParseTree(child);
                 }
                 break ;
             case "fields" :
                 foreach ( var child in node.ChildNodes)
                 {
                     parsedFields.Add(child.Token.Text);
                 }
                 break ;
             case "table" :
                 ParsedTable = node.ChildNodes[0].Token.Text;
                 break ;
         }
     }
 
     public IEnumerable< string > ParsedFields => parsedFields;
     public string ParsedTable { get ; private set ; }
}

SqlParser会基于我们自定义的语法类,生成一个Irony的Parser对象,然后使用Parse方法来解析传入的SQL语句,并产生语法解析树。之后,就可以根据树状结构来解析语句中的每一个部分,并执行相应的操作。

最后,就是使用这个SqlParser类来解析SQL语句并得到结果。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
static void Main( string [] args)
{
     var sqlParser = new SqlParser();
     sqlParser.Execute( "SELECT firstName, LastName FROM tbl_students" );
 
     Console.WriteLine($ "获得的数据表: {sqlParser.ParsedTable}" );
     Console.WriteLine( "获得的字段:" );
     foreach ( var field in sqlParser.ParsedFields)
     {
         Console.WriteLine(field);
     }
}

代码很简单:调用SqlParser的Execute方法来解析给定的SQL语句,解析结果会分别保存在SqlParser的ParsedTable和ParsedFields两个属性中,上面的控制台程序只需要输出这两个结果就行了。在实际应用中,可以通过ParsedTable来获取某一种类型的对象列表,然后通过ParsedFields来投影列表中每个对象的属性,从而得到基于C#的一系列对象来执行SQL查询的效果。

本案例执行结果如下:

640?wx_fmt=png

本文简要介绍了.NET语法解析框架Irony的使用,并通过SQL语句解析的案例,介绍了Irony使用的一些技巧与步骤。就SQL语句而言,它的定义还是相对比较复杂的,不可能单靠一篇博客就能完全覆盖所有内容,也是因为这个原因,本文也没有涉及WHERE子句的设计,但Irony框架是完全可以做到这一点的。事实上,在Irony Explorer项目中,就有一个IronyExplorer.Samples的工程,其中包含了很多编程语言语法定义的案例代码,比如Java、C#、SQL等,有兴趣的可以参考。Irony框架本身已经帮我们做了很多工作,比如大小写敏感的特性,比如运算符优先级的定义,比如标识符、整数、小数、正负数的定义,再比如块注释与行注释的处理等等。在我用C#实现LOGO语言时,基本上也是按照上面所述步骤进行编写和测试,因此,我就不再另起篇幅来介绍LOGO语言的语法定义了。

原文地址:https://sunnycoding.cn/2019/07/11/sql-parser-with-irony-in-csharp/


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 

640?wx_fmt=jpeg

目录 绪论…………………………………………………………………………………………2 第一章.项目背景…………………………………………………………………………3 1.1 用户发展战略…………………………………………………………………………3 1.1 项目整体目标…………………………………………………………………………4 第二章.财务管理…………………………………………………………………………5 2.1 财务管理的任务………………………………………………………………………5 2.2 会计学的理论基础…………………………………………………………………….6 第三章.财务管理系统需求分析…………………………………………………………11 3.1 基础资料维护…………………………………………………………………………13 3.2 凭证管理………………………………………………………………………………13 3.3 帐簿管理……………………………………………………………………………….13 3.4 报表管理………………………………………………………………………………14 3.5 期末处理………………………………………………………………………………14 3.6 往来管理………………………………………………………………………………15 3.7 出纳管理………………………………………………………………………………15 3.8 工资管理………………………………………………………………………………16 3.9 固定资产管理…………………………………………………………………………16 3.10 财务分析……………………………………………………………………………17 第四章.财务管理系统数据库分析………………………………………………………17 4.1 财务管理系统E-R图…………………………………………………………………18 4.2 财务管理系统数据表清单……………………………………………………………19 第五章.实例制作介绍……………………………………………………………………19 5.1 实例功能………………………………………………………………………………20 5.2 系统流程图……………………………………………………………………………20 第六章.数据库设计………………………………………………………………………21 6.1 创建“科目表”数据表………………………………………………………………21 6.2 创建“凭证表”和“分录表”数据表………………………………………………21 6.3 创建其他关键数据表…………………………………………………………………22 6.4创建主键及外键等表约束…………………………………………………………….22 6.5创建储存过程………………………………………………………………………….23 6.6 创建存储过程…………………………………………………………………………………………24 第七章.程序开发…………………………………………………………………………30 7.1 程序运行结果…………………………………………………………………………30 7.2 创建工程………………………………………………………………………………38 7.3 创建系统主窗体………………………………………………………………………38 7.4 完成会计科目设置功能………………………………………………………………41 7.5 完成帐户设置功能……………………………………………………………………46 7.6 完成凭证输入功能……………………………………………………………………55 7.7 完成凭证过帐功能……………………………………………………………………67 7.8 完成总分类帐查询功能………………………………………………………………67 7.9 完成明细帐查询功能…………………………………………………………………70 7.10 完成试算平衡表功能…………………………………………………………………73 7.11 完成期末结帐功能……………………………………………………………………73 7.12 完成资产负债表报表输出功能………………………………………………………73 7.13 编译并运行系统………………………………………………………………………76 第八章.系统发布……………………………………………………………………………76 第九章.系统扩展……………………………………………………………………………76 第十章.小结…………………………………………………………………………………77 结束语.……………………………………………………………………………………… 77 致谢……………………………………………………………………………………………78 参考文献……………………………………………………………………………………79
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值