using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; using System.Runtime.InteropServices; namespace DataService { public class ExpressionEval : IDisposable { Expression _param1; List _tagList = new List(); public List TagList { get { return _tagList; } } IDataServer _server; public ExpressionEval(IDataServer server) { _server = server; _param1 = Expression.Constant(this); } public Delegate Eval(string expression) { if (string.IsNullOrEmpty(expression)) return null; var lambda = ComplieRpnExp(RpnExpression(expression)); if (lambda != null) return lambda.Compile(); return null; } public Delegate WriteEval(string expression) { if (_server == null || string.IsNullOrEmpty(expression)) return null; if (_server[expression.ToUpper()] != null) { return new Func((object value) => { return WriteTag(expression, value); }); } return null; } public Func WriteEval(string expression1, string expression2) { if (_server == null || string.IsNullOrEmpty(expression2)) return null; if (_server[expression1.ToUpper()] != null) { var dele = Eval(expression2); var funcbool = dele as Func; if (funcbool != null) return () => { return WriteTag(expression1, funcbool()); }; var funcint = dele as Func; if (funcint != null) return () => { return WriteTag(expression1, funcint()); }; var funcfloat = dele as Func; if (funcfloat != null) return () => { return WriteTag(expression1, funcfloat()); }; var funcstring = dele as Func; if (funcstring != null) return () => { return WriteTag(expression1, funcstring()); }; } return null; } public static bool ValidationExpression(string expression) { return true;//可加入正则表达式验证 } /// /// 操作符运算级别 /// /// 操作符 /// 操作运算符,空格返回0,出错返回-1 private static byte GetOperatorLevel(char strOperator) { switch (strOperator) { case '~': return 10; case '*': case '/': case '%': return 9; case '+': case '-': return 8; case '>': case '<': return 7; case '&': return 6; case '^': return 5; case '|': return 4; case '=': case '!': case '?': return 3; case '(': return 2; case ')': return 1; //case ':': default: return 0; } } /// /// 将中缀表达式转换为逆波兰表达式 /// /// 标准中缀表达式 /// 标准逆波兰表达式 public static List RpnExpression(string expression) { //加入结束标记 //定义出栈和入栈堆栈 string[] strNum = expression.Split('~', '%', '>', '<', '=', '!', '&', '|', '?', '#', '^', '+', '-', '*', '/', '(', ')'); if (strNum.Length < 2) return new List() { expression }; //操作运算符堆栈 Stack oper = new Stack(); //定义输出堆栈 List output = new List(); //定义前缀表达式字符读取指针 int i = 0; //定义当前读取数字数组指针 int n = -1; //定义操作运算符级别函数 Operator op = new Operator(); //输出堆栈的大小 int intStackCount = 0; //从左到右读取前缀表达式 while (i < expression.Length) { //读取一个字符 char strChar = expression[i]; //取字符的运算级别 if (strChar == '#') { i++; continue; } byte intLevel = GetOperatorLevel(strChar); if (intLevel == 0) //数字直接推入输出堆栈 { while (n++ < strNum.Length) { if (strNum[n] != "") { output.Add(strNum[n]); i += strNum[n].Length; //移动数组指针 break; } } } else //操作字符根据运算字符级别推入运算符堆栈 { if (oper.Count == 0) { //运算符堆栈为空,直接推入堆栈 oper.Push(new Operator(strChar, intLevel)); //移动字符读取指针 i++; } else { op = oper.Peek(); if (intLevel > op.Level || intLevel == 2) { //运算字符比运算符堆栈最后的级别高或者运算符为'('直接推入运算符堆栈 oper.Push(new Operator(strChar, intLevel)); //移动字符读取指针 i++; } else { //运算字符不高于运算符堆栈最后的级别,则将运算符堆栈出栈,直到比其高为止 intStackCount = oper.Count; for (int m = 0; m < intStackCount; m++) { op = oper.Peek(); if (op.Level >= intLevel) { //将操作符出栈并压入输入堆栈 char o = op.OperatorStack; if (!(o == ')' || o == '(')) { output.Add(o.ToString()); } oper.Pop(); if (op.Level == 2) { //如果操作符堆栈中最后的操作符为'('则停止出栈 i++; break; } } else { //直到运算符已经高出运算符栈中最后的级别,则入栈 oper.Push(new Operator(strChar, intLevel)); i++; break; } } } } } } intStackCount = oper.Count; for (int m = 0; m < intStackCount; m++) { op = oper.Peek(); output.Add(op.OperatorStack.ToString()); oper.Pop(); } return output; } /// /// 解逆波兰表达式 /// /// 标准逆波兰表达式 /// 逆波兰表达式的解 public LambdaExpression ComplieRpnExp(List strNum) { _tagList.Clear(); //拆分逆波兰表达式 int intLenth = strNum.Count; if (intLenth == 0) return null; //定义数字堆栈 try { Stack number = new Stack(); for (int i = 0; i < intLenth; i++) { string expr = strNum[i]; switch (expr) { case "~": if (number.Count > 0) { Expression left = number.Pop(); number.Push(Expression.Not(left)); } break; case "*": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); if (left.Type != right.Type) { if (left.Type != typeof(float)) left = Expression.Convert(left, typeof(float)); if (right.Type != typeof(float)) right = Expression.Convert(right, typeof(float)); } number.Push(Expression.Multiply(left, right)); } break; case "/": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); if (left.Type != right.Type) { if (left.Type != typeof(float)) left = Expression.Convert(left, typeof(float)); if (right.Type != typeof(float)) right = Expression.Convert(right, typeof(float)); } number.Push(Expression.Divide(left, right)); } break; case "%": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); if (left.Type != right.Type) { if (left.Type != typeof(int)) left = Expression.Convert(left, typeof(int)); if (right.Type != typeof(int)) right = Expression.Convert(right, typeof(int)); } number.Push(Expression.Modulo(left, right)); } break; case "+": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); if (left.Type == typeof(string) || right.Type == typeof(string)) { if (left.Type != typeof(string)) left = Expression.Convert(left, typeof(object)); if (right.Type != typeof(string)) right = Expression.Convert(right, typeof(object)); number.Push(Expression.Call(typeof(string).GetMethod("Concat", new Type[] { typeof(object), typeof(object) }), left, right)); } else { if (left.Type != right.Type) { if (left.Type != typeof(float)) left = Expression.Convert(left, typeof(float)); if (right.Type != typeof(float)) right = Expression.Convert(right, typeof(float)); } number.Push(Expression.Add(left, right)); } } break; case "-": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); if (left.Type != right.Type) { if (left.Type != typeof(float)) left = Expression.Convert(left, typeof(float)); if (right.Type != typeof(float)) right = Expression.Convert(right, typeof(float)); } number.Push(Expression.Subtract(left, right)); } break; case ">": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); if (left.Type != right.Type) { if (left.Type != typeof(float)) left = Expression.Convert(left, typeof(float)); if (right.Type != typeof(float)) right = Expression.Convert(right, typeof(float)); } number.Push(Expression.GreaterThan(left, right)); } break; case "<": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); if (left.Type != right.Type) { if (left.Type != typeof(float)) left = Expression.Convert(left, typeof(float)); if (right.Type != typeof(float)) right = Expression.Convert(right, typeof(float)); } number.Push(Expression.LessThan(left, right)); } break; case "&": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); number.Push(Expression.And(left, right)); } break; case "^": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); number.Push(Expression.ExclusiveOr(left, right)); } break; case "|": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); number.Push(Expression.Or(left, right)); } break; case "=": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); if (left.Type != right.Type) { if (left.Type != typeof(float)) left = Expression.Convert(left, typeof(float)); if (right.Type != typeof(float)) right = Expression.Convert(right, typeof(float)); } number.Push(Expression.Equal(left, right)); } break; case "!": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); if (left.Type != right.Type) { if (left.Type != typeof(float)) left = Expression.Convert(left, typeof(float)); if (right.Type != typeof(float)) right = Expression.Convert(right, typeof(float)); } number.Push(Expression.NotEqual(left, right)); } break; case "?": if (number.Count > 1) { Expression right = number.Pop(); Expression left = number.Pop(); if (left.Type != right.Type) { if (left.Type != typeof(float)) left = Expression.Convert(left, typeof(float)); if (right.Type != typeof(float)) right = Expression.Convert(right, typeof(float)); } Expression test = number.Pop(); number.Push(Expression.Condition(test, left, right)); } break; default: if (expr[0] == '@') { switch (expr.Substring(1).ToUpper()) { case "TIME": { Expression> f = () => DateTime.Now.ToShortTimeString(); number.Push(f.Body); } goto lab1; case "DATE": { Expression> f = () => DateTime.Now.ToShortDateString(); number.Push(f.Body); } goto lab1; case "DATETIME": { Expression> f = () => DateTime.Now.ToString(); number.Push(f.Body); } goto lab1; case "APP": { Expression> f = () => AppDomain.CurrentDomain.FriendlyName; number.Push(f.Body); } goto lab1; case "NAME": { Expression> f = () => Environment.MachineName; number.Push(f.Body); } goto lab1; case "PATH": { Expression> f = () => Environment.CurrentDirectory; number.Push(f.Body); } goto lab1; case "USER": { Expression> f = () => Environment.UserName; number.Push(f.Body); } goto lab1; case "REGION": { Expression> f = () => System.Globalization.CultureInfo.CurrentCulture.Name; number.Push(f.Body); } goto lab1; } } object result; if (IsConstant(expr, out result)) { number.Push(Expression.Constant(result)); } else { number.Push(GetTagExpression(expr)); } lab1: break; } } Expression d = number.Pop(); return Expression.Lambda(d); } catch (Exception e) { return null; } } MethodInfo _boolinfo = typeof(ExpressionEval).GetMethod("GetBool"); MethodInfo _floatinfo = typeof(ExpressionEval).GetMethod("GetFloat"); MethodInfo _intinfo = typeof(ExpressionEval).GetMethod("GetInt"); MethodInfo _stringinfo = typeof(ExpressionEval).GetMethod("GetString"); public Expression GetTagExpression(string tagName) { if (_server == null) return Expression.Empty(); ITag tag = _server[tagName]; switch (tag.Address.VarType) { case DataType.BOOL: return Expression.Call(_param1, _boolinfo, Expression.Constant(tagName)); case DataType.BYTE: case DataType.WORD: case DataType.SHORT: case DataType.TIME: case DataType.INT: return Expression.Call(_param1, _intinfo, Expression.Constant(tagName)); case DataType.FLOAT: return Expression.Call(_param1, _floatinfo, Expression.Constant(tagName)); case DataType.STR: return Expression.Call(_param1, _stringinfo, Expression.Constant(tagName)); default: return Expression.Empty(); } } public bool GetBool(string tagName) { if (_server == null) return false; ITag tag = _server[tagName]; switch (tag.Address.VarType) { case DataType.BOOL: return tag.Value.Boolean; case DataType.BYTE: return Convert.ToBoolean(tag.Value.Byte); case DataType.WORD: case DataType.SHORT: return Convert.ToBoolean(tag.Value.Int16); case DataType.TIME: case DataType.INT: return Convert.ToBoolean(tag.Value.Int32); case DataType.FLOAT: return Convert.ToBoolean(tag.Value.Single); case DataType.STR: return Convert.ToBoolean(tag.ToString()); default: return false; } } public float GetFloat(string tagName) { if (_server == null) return 0f; ITag tag = _server[tagName]; return tag.ScaleToValue(tag.Value); } public int GetInt(string tagName) { if (_server == null) return 0; ITag tag = _server[tagName]; switch (tag.Address.VarType) { case DataType.BOOL: return tag.Value.Boolean ? 1 : 0; case DataType.BYTE: return (int)tag.Value.Byte; case DataType.WORD: case DataType.SHORT: return (int)tag.Value.Int16; case DataType.TIME: case DataType.INT: return tag.Value.Int32; case DataType.FLOAT: return Convert.ToInt32(tag.Value.Single); case DataType.STR: return int.Parse(tag.ToString()); default: return 0; } } public string GetString(string tagName) { return _server == null ? null : _server[tagName].ToString(); } public int WriteTag(string tagName, object value) { if (_server == null || value == null) return -1; ITag tag = _server[tagName]; if (tag.Address.VarType == DataType.BOOL || tag.Address.VarType == DataType.STR) return tag.Write(value); else { float temp; string str = value as string; if (str == null) temp = Convert.ToSingle(value); else { if (!float.TryParse(str, out temp)) return -1; } return tag.Write(tag.ValueToScale(temp)); } } private bool IsConstant(string str, out object value) { if (str.Length > 1 & str[0] == '\'' && str[str.Length - 1] == '\'') { value = str.Trim('\''); return true; } string upp = str.ToUpper(); if (upp == "TRUE") { value = true; return true; } else if (upp == "FALSE") { value = false; return true; } if (_server != null) { var tag = _server[upp]; if (tag != null) { if (!_tagList.Contains(tag)) _tagList.Add(tag); value = null; return false; } } int dotcount = 0; for (int i = 0; i < str.Length; i++) { char opr = str[i]; if (opr < '0' || opr > '9') { if (opr != '.') { value = str; return true; } else { if (dotcount > 0) { value = str; return true; } dotcount++; } } } //value = (dotcount == 0 ? int.Parse(str) : float.Parse(str)); if (dotcount == 0) value = int.Parse(str); else value = float.Parse(str); return true; } public void Clear() { //_param1 = null; _tagList.Clear(); //_tagList = null; } public void Dispose() { _param1 = null; _tagList.Clear(); _tagList = null; _boolinfo = _floatinfo = _stringinfo = null; } } [StructLayout(LayoutKind.Sequential)] /// /// 操作符结构 /// public struct Operator { public char OperatorStack; public byte Level; public Operator(char OperatorStack, byte Level) { this.OperatorStack = OperatorStack; this.Level = Level; } } }