LambdaParser的实现
之前在GoogleCode里创建的项目LambdaParser,好久没管了,前两天进去一看,居然PR值是4,很是奇怪,搜了一下,几乎没任何反向链接,搞不懂PR值为什么会这么高。
既然Google这么看重它,那我也不能把它荒废了:)最近.NET4.0已经出来了,Expression已经支持代码块了(以前只支持表达式,区别就是以前不能写多个语句,现在可以了),像if、while、switch等等这些都已经支持了,那么现在的Expression理论上讲已经可以表达任何方法体了。只可惜不知微软出于什么考虑(也许是担心LINQ这边误用吧,这个功能是用来为Dynamic Language Runtime 即DLR服务的,不是LINQ),不能直接将代码块转换成表达式树。如:
Expression<Action<string>> action = (m=>
{
MessageBox.Show(m.Length);
MessageBox.Show(m);
});
这种写法以前不行,现在仍然不行。因为这是个代码块。(对表达式树不熟悉的可以看看这篇文章:表达式树基础)
那么,想要构造代码块就得用Expression手动慢慢拼了。这是件痛苦的事情。当然,LambdaParser的下一步就是要解决它,有了BlockExpression、SwitchExpression
这些的东西,实现这个功能相信不是难事。如果有人愿意加入进来共同完成这个功能,可以联系我。
本文主要想讲讲目前的LambdaParser的实现。
解决方案截图:
“Demo”是自己用来简单试用的。“Test_Zhucai.LambdaParser”是基于VSTS的单元测试项目,新接触的人看这个比较容易理解这个项目是干什么的。“Zhucai.LambdaParser”是核心模块。
下面是主要的几个类:
CodeParser类:负责解析代码。从前向后读取代码,通过ReadString方法每次读取一个代码单元。
代码单元:这是个自创的名词,用来表示代码的最小单元,如代码MessageBox.Show(m);对应的代码单元是:
1 MessageBox
2 .
3 Show
4 (
5 m
6 )
7 ;
那么ReadString方法会成功读取7次,直到第8次返回null结束。
ExpressionParserCore<TDelegate>类:这个类负责将代码解析为表达式树。它通过构造函数得到字符串代码,通过唯一的公共方法ToLambdaExpression()输出解析结果Expression。
此类内部先通过输入的字符串代码构造一个CodeParser对象,然后通过泛型参数(将要构造出的委托类型)得到代码的参数类型,之后便开始用CodeParser对象遍历分析代码。
分析代码的过程:
1. 首先检查是否有Lambda表达式的前置符号=>,若有,则分析出参数列表。
2. 通过ReadExpression方法递归读取表达式。
ReadExpression方法是整个模块的核心方法,方法的大致思路如下:
将表达式看成A(+B)*n模式,即先读取表达式的A部分,再用循环读取接下来的n个+B部分。A部分表示表达式的第一个子表达式,+B部分表示一个操作符后面跟一个子表达式,而*n表示可能有0个或多个+B部分。
那么ReadExpression方法的伪代码大致便是这样:
读取第一个子表达式;
while()
{
读取二元/三元操作符;
读取下一个子表达式;
用指定操作符操作两个表达式,得到新表达式;
}
返回最新的表达式;
大致便是这样了,这里略去了很多需要处理的细节问题,如操作符优先级、类型判断等等。但有个问题是不能略过的,那便是子表达式又可能包含多个子表达式。
如果把平行连接的表达式操作看作横向操作,那么多层的子表达式包含便是纵向操作。横向问题是用while循环来解决,纵向问题用递归是最直观的。事实上,由于操作符优先级的问题,这里的横向操作也会有递归调用,或者说,是横向还是纵向变得不那么明确。
于是,读取子表达式的时候,调用ReadExpression来递归读取。
最终,ReadExpression方法的函数签名是三个参数:
int priorityLevel:当前操作(或者说方法外部)的优先级。递归情况下使用。当方法内的下个操作优先级低于此值时直接返回。
string wrapStart:当前操作的前置括号。如(或[或{等。递归情况下使用。
out bool isClosedWrap:告诉方法外面是否在里面遇到了与前置括号匹配的结束符号。递归情况下使用。
ExpressionParser类:作为此模块向外暴露的接口,其内部调用ExpressionParserCore<TDelegate>类,提供一系列方法来编译执行代码。
这便是这个项目目前的大致情况。有时间了便考虑实现在.NET4.0下的代码块功能,那么这个项目也许就会有意义些了。
转载需注明出处:http://cnblogs.com/zhucai/