自定义表达式引擎

    某天,公司里在讨论表达式解析,经讨论他们选择了将表达式动态编译并反射实现。个人兴起,回家自己写了个简单的表达式解析程序,鼓励下自己要好好加油,在此做个记录以防自己以后忘记。

      

    源代码(对部分bug有所更改,2012年4月)

 

      对于一般的表达式的观察发现,表达式分运算符、参数、函数三部分。而运算符其实也是函数。如 +,其实+有两个参数和一个返回值即:object Add(parameter1,parameter2).参数是函数的输入。所以我将表达式定义成了函数对象的递归树。于是定义了如下接口及抽象类。

  函数抽象:

        

  

 1    public abstract class FunctionBase:IFunFactory 

 2     {
 3         /// <summary>
 4         /// 如果为Int32.MaxValue表示不限定参数个数
 5         /// </summary>
 6         public abstract ParameterCount NeedParameterCount
 7         {
 8             get;
 9         }
10 
11         public abstract string KeyWord
12         {
13             get;
14         }
15 
16         protected  List<object> _inArguments = new List<object>();
17 
18         public abstract object Excute();
19 
20         public abstract void PushArguments(object argument);
21 
22         public abstract object PopArgument();
23 
24         public virtual IEnumerator<object> GetArgumentItor();
25 
26         public virtual void ReplaceArgument(int index, object v);
27 
28         public virtual bool IsParamertEnough(out FunctionBase notEnoughFun);
29 
30         public virtual FunctionBase Clone();
31 
32         public abstract FunctionBase Create();
33 
34         internal bool Check();
35         
36     }

   区分运算符的标识接口(运算符有优先级概念)

   

1 public interface IOperator
2 {
3 float Level
4 {
5 get;
6 }
7 }

 

  

   以下列举一个 +和Sin函数的实现。

  +号:

      

  1 /// <summary>
2 /// 加法
3 /// </summary>
4 public class Add : FunctionBase, IOperator, IFunFactory
5 {
6 //实现
151
152 }

 

  Sin函数的实现

     

 1 /// <summary>
2 /// 以角度求Sin值
3 /// </summary>
4 public class Sin : FunctionBase, IFunFactory
5 {
6 public override string KeyWord
7 {
8 get
9 {
10 return "Sin";
11 }
12 }
13
14 private List<object> _inArguments = new List<object>();
15
16 public override void PushArguments(object argument)
17 {
18 if (null == argument)
19 {
20 throw new ArgumentNullException();
21 }
22
23 if (_inArguments.Count == 1)
24 {
25 throw new ArgumentNotMatchException("argument is more");
26 }
27 _inArguments.Add(argument);
28 }
29
30 public override object PopArgument()
31 {
32 int last = _inArguments.Count - 1;
33 if (last >= 0)
34 {
35 object o = _inArguments[last];
36 _inArguments.RemoveAt(last);
37 return o;
38 }
39 return null;
40 }
41
42 public override object Excute()
43 {
44 if (_inArguments.Count > 1)
45 {
46 throw new ArgumentNotMatchException("argument is more");
47 }
48
49 if (_inArguments.Count < 1)
50 {
51 throw new ArgumentNotMatchException("argument is not enough");
52 }
53
54 double a1 = 0;
55 object arg0 = _inArguments[0];
56
57 if (arg0 is FunctionBase)
58 {
59 arg0 = ((FunctionBase)arg0).Excute();
60 }
61
62 if (!double.TryParse(arg0.ToString(), out a1))
63 {
64 throw new ArgumentNotMatchException("argument's type is not match");
65 }
66
67 return Math.Sin(a1);
68
69 }
70
71 FunctionBase IFunFactory.Create()
72 {
73 return new Sin();
74 }
75 }

 

    关键部分,ExpCompile类,将表达式String解析成fun对象。

       使用ExpExcuteContext可以缓存表达式解析后的对象;并且该类主要是想实现表达式中绑定外部变量的赋值。当然这以被注释,实际已应用。

       主要是通过函数名(关键字),得到函数起始部分和结束部分,然后以逗号为分隔取参数。

       注意:参数可能是函数执行的结果,如果此种情况要递归分析。继续Compile(ref FunctionBase rootFun,string exp)

    原型如下:

   

  1 public class ExpCompile
2 {
3
28 public void Compile(ref FunctionBase rootFun,string exp);
          //.....
499     }

 

  

     


posted @ 2011-12-30 22:05  HQL  阅读(531)  评论(0)    收藏  举报