From fdcef37be3fcf76009fac3a6e0e2edcd55b7d0f6 Mon Sep 17 00:00:00 2001 From: zengwenjie <1663900244@qq.com> Date: Thu, 16 Oct 2025 10:47:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E3=80=8CDodo=E3=80=8D?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E7=9A=84=E5=AE=9A=E4=B9=89=E4=B8=8E=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=85=B3=E9=94=AE=E9=80=BB=E8=BE=91=E7=9A=84=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DeedyDesigner/Deedy.Testing/App.xaml.cs | 20 + DeedyDesigner/Deedy.Testing/Dodo.cs | 1102 +++++++++++++++++++++++ 2 files changed, 1122 insertions(+) create mode 100644 DeedyDesigner/Deedy.Testing/Dodo.cs diff --git a/DeedyDesigner/Deedy.Testing/App.xaml.cs b/DeedyDesigner/Deedy.Testing/App.xaml.cs index cc36506..29ab6e5 100644 --- a/DeedyDesigner/Deedy.Testing/App.xaml.cs +++ b/DeedyDesigner/Deedy.Testing/App.xaml.cs @@ -1,6 +1,7 @@ using System.Configuration; using System.Data; using System.Windows; +using Deedy.Testing; namespace Deedy { @@ -9,6 +10,25 @@ namespace Deedy /// public partial class App : Application { + public App() + { + string script = +@" +VarP var1 111 +VarP var2 222 +Func Add var1 var2 + LetP AddResult -1 + math AddResult var1 var2 + + retu AddResult +EndF + +Call Add var1 var2 +PopV result +"; + Todo todo = new Todo(); + todo.Init(script); + todo.Redo(); + } } } diff --git a/DeedyDesigner/Deedy.Testing/Dodo.cs b/DeedyDesigner/Deedy.Testing/Dodo.cs new file mode 100644 index 0000000..8a77aa4 --- /dev/null +++ b/DeedyDesigner/Deedy.Testing/Dodo.cs @@ -0,0 +1,1102 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Deedy.Testing +{ + /// + /// 解释执行「DodoScript」脚本的引擎 + /// 仿照「C」语言执行逻辑实现 + /// + public class Todo + { + /// + /// 运行模式 + /// + public enum Mode + { + /// + /// 暂停运行状态 + /// + Waiting, + /// + /// 正常运行状态 + /// + Running, + /// + /// 当「Continue」或「Reentry」操作执行后的状态 + /// + Reentry, + /// + /// 当「Break」或「Return」操作执行后的状态 + /// + JumpOut, + } + /// + /// 脚本内部的方法定义 + /// + public struct Def_FuncDefine(string name, int line) + { + public string Name = name; + public int Line = line; + } + /// + /// 外部方法的引用记录 + /// + public struct Def_FuncImport(string name, Action> action) + { + public string Name = name; + public Action> Action = action; + } + /// + /// 脚本内方法调用记录 + /// + public struct Def_FuncInvoke(int returnLine) + { + public int ReturnLine = returnLine; + public Dictionary LocalParams = []; + } + /// + /// 外部参数的引用记录 + /// + public struct Def_ParamRefer(string name, object param) + { + public string Name = name; + public object Param = param; + } + /// + /// 当前要执行的脚本行号 + /// + private int Control_CurrentLine = 0; + /// + /// 脚本调度周期,等待指令每次的等待时间 + /// + private int Control_WakeupCycle = 10; + /// + /// 每条指令在开始执行时的时间,由脚本主解释逻辑负责记录 + /// + private DateTime Control_CurrentTime = DateTime.Now; + /// + /// 脚本运行模式,用于外部控制正在执行的脚本的行为 + /// + public Mode RunningMode { get; set; } = Mode.Waiting; + /// + /// 脚本内容 + /// + private readonly List Script = []; + + /// + /// 脚本内部的自定义方法映射表 + /// + private List FuncDefines = []; + /// + /// 外部引用的可执行方法映射表 + /// + private readonly List FuncImports = []; + + /// + /// 脚本内方法调用栈 + /// + private Stack Invoke_FuncStack = []; + /// + /// 调用外部方法时使用的参数栈 + /// + private Stack Invoke_ArgsStack = []; + + /// + /// 外部引用参数集合 + /// + private readonly List Param_Refers = []; + /// + /// 全局参数上下文 + /// + private Dictionary Param_Global = []; + + /// + /// 注册外部方法引用 + /// + /// 外部方法引用结构 + public void Reg_FuncImport(Def_FuncImport funcImport) + { + foreach (var func in this.FuncImports) + { + if (func.Name == funcImport.Name) + { + this.FuncImports.Remove(func); + break; + } + } + this.FuncImports.Add(funcImport); + } + /// + /// 注册外部参数引用 + /// + /// 外部参数引用结构 + public void Reg_ParamRefer(Def_ParamRefer paramRefer) + { + foreach (var param in this.Param_Refers) + { + if (param.Name == paramRefer.Name) + { + this.Param_Refers.Remove(param); + } + } + this.Param_Refers.Add(paramRefer); + } + /// + /// 使用脚本创建实例 + /// + /// 要执行的脚本 + public void Init(string script) + { + this.Script.Clear(); + + string[] cmdLines = script.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + for (int lineNum = 0; lineNum < cmdLines.Length; lineNum++) + { + string command = cmdLines[lineNum].Trim(); + if (!string.IsNullOrEmpty(command)) this.Script.Add(command); + } + } + /// + /// 临时执行一段脚本 + /// + /// 临时执行的脚本逻辑 + /// 执行完成后主逻辑的执行状态 + public void Exec(string script, Mode? returnMode = null) + { + //保存原有运行状态字 + Mode CurrentMode = returnMode ?? this.RunningMode; + int CurrentLine = this.Control_CurrentLine; + int WakeupCycle = this.Control_WakeupCycle; + this.RunningMode = Mode.Waiting; + //保存原有运行上下文 + List funcDefines = [.. this.FuncDefines]; + Dictionary param_Global = new(this.Param_Global); + Stack invoke_FuncStack = new(this.Invoke_FuncStack); + Stack invoke_ArgsStack = new(this.Invoke_ArgsStack); + //初始化并执行新脚本 + this.Init(script); + this.Redo(this.Control_WakeupCycle); + //还原原有运行上下文 + this.FuncDefines = funcDefines; + this.Param_Global = param_Global; + this.Invoke_FuncStack = invoke_FuncStack; + this.Invoke_ArgsStack = invoke_ArgsStack; + //恢复原有运行状态字 + this.Control_CurrentLine = CurrentLine; + this.Control_WakeupCycle = WakeupCycle; + this.RunningMode = CurrentMode; + } + /// + /// 停止上一个正在执行的线程,再开启一个新线程开始执行 + /// + /// 调度周期:用于控制等待指令每次等待的时间 + public void Redo(int cycle = 10) + { + this.RunningMode = Mode.Running; + this.Control_WakeupCycle = cycle; + + this.FuncDefines = []; + this.Param_Global = []; + this.Invoke_FuncStack = []; + this.Invoke_ArgsStack = []; + + this.Control_CurrentLine = 0; + this.Control_CurrentTime = DateTime.Now; + while (this.Control_CurrentLine < this.Script.Count) + { + switch (this.RunningMode) + { + case Mode.Running: + this.Control_CurrentTime = DateTime.Now; + string command = this.Script[Control_CurrentLine].Trim(); + int index = command.IndexOf(' '); + string cmdName, cmdArgs = ""; + if (index > 0) + { + cmdName = command[..index].Trim().ToLower(); + cmdArgs = command[index..].Trim(); + } + else cmdName = command.ToLower(); + + switch (cmdName) + { + case "brea": this.CmdC_Brea(); break; + case "cont": this.CmdC_Cont(); break; + case "endf": this.CmdC_EndF(); break; + case "endi": this.CmdC_EndI(); break; + case "endw": this.CmdC_EndW(); break; + case "reen": this.CmdC_Reen(); break; + + case "func": this.CmdI_Func(cmdArgs); break; + case "call": this.CmdI_Call(cmdArgs); break; + case "retu": this.CmdI_Retu(cmdArgs); break; + case "exec": this.CmdI_Exec(cmdArgs); break; + case "goto": this.CmdI_Goto(cmdArgs); break; + case "ifth": this.CmdI_IfTh(cmdArgs); break; + case "letp": this.CmdI_LetP(cmdArgs); break; + case "math": this.CmdI_Math(cmdArgs); break; + case "varp": this.CmdI_VarP(cmdArgs); break; + case "whil": this.CmdI_Whil(cmdArgs); break; + + case "push": this.CmdS_Push(cmdArgs); break; + case "popv": this.CmdS_PopV(cmdArgs); break; + + default: break; + } + break; + case Mode.Reentry: // 重启脚本逻辑 + this.Param_Global.Clear(); + this.Invoke_FuncStack.Clear(); + this.Invoke_ArgsStack.Clear(); + this.Control_CurrentLine = 0; + return; + case Mode.Waiting: // 等待一个调度周期 + Thread.Sleep(this.Control_WakeupCycle); + break; + default: return; // 退出脚本执行 + } + } + } + /// + /// 提取一个指令的指令名称 + /// + /// 指令行 + /// 当前指令行的指令名称 + private static string Pre_Hand(string command, bool toLower = true) + { + int index = command.IndexOf(' '); + string cmdName;//, cmdArgs; + if (index > 0) + { + cmdName = command[..index].Trim(); + } + else cmdName = command.Trim(); + return (toLower) ? cmdName.ToLower() : cmdName; + } + /// + /// 向下查找脚本中的「EndW」指令的行号并移动指令指针 + /// + protected void CmdC_Brea() + { + int index = this.Control_CurrentLine; + while (index < this.Script.Count) + { + index++; + string cmd = Pre_Hand(this.Script[index]); + if (cmd == "endw") + { + this.Control_CurrentLine = index; + return; + } + } + } + /// + /// 向上查找脚本中的「Whil」指令的行号并移动指令指针 + /// + protected void CmdC_Cont() + { + int index = this.Control_CurrentLine; + while (index >= 0) + { + index--; + string cmd = Pre_Hand(this.Script[index]); + if (cmd == "whil") + { + this.Control_CurrentLine = index + 1; + return; + } + } + } + /// + /// 重置调用栈、参数上下文等运行数据,重置指令指针 + /// + protected void CmdC_Reen() + { + this.FuncDefines.Clear(); + this.Param_Global.Clear(); + this.Invoke_FuncStack.Clear(); + this.Invoke_ArgsStack.Clear(); + this.Control_CurrentLine = 0; + this.Control_CurrentLine++; + } + /// + /// 将返回值压栈,向下查找「EndF」指令并移动指令指针 + /// + protected void CmdI_Retu(string cmdArgs) + { + string[] rets = (cmdArgs ?? "").Split(' ', options: StringSplitOptions.RemoveEmptyEntries); + foreach (string arg in rets) this.Invoke_ArgsStack.Push(this.ParamGetter(arg, 0)); + + int index = this.Control_CurrentLine; + while (index < this.Script.Count) + { + index++; + string cmd = Pre_Hand(this.Script[index]); + if (cmd == "endf") + { + this.Control_CurrentLine = index; + return; + } + } + } + /// + /// 结束「IfThen」控制段 + /// + protected void CmdC_EndI() + { + int index = this.Control_CurrentLine; + while (index >= 0) + { + index--; + string cmd = Pre_Hand(this.Script[index]); + if (cmd == "ifth") break; + else if (cmd == "letp") + { + //HACK:清除方法定义中使用「LetP」声明的所有局部变量 + } + } + //HACK:如果需要支持代码块级局部变量则需要在此处闭合代码块 + this.Control_CurrentLine++; + } + /// + /// 结束「While」控制段 + /// + protected void CmdC_EndW() + { + int index = this.Control_CurrentLine; + while (index >= 0) + { + index--; + string cmd = Pre_Hand(this.Script[index]); + if (cmd == "whil") + { + string cmdArgs = this.Script[index][4..].Trim(); + if (this.CmdP_Cond(cmdArgs)) + this.Control_CurrentLine = index + 1; + return; + } + else if (cmd == "letp") + { + //HACK:清除方法定义中使用「LetP」声明的所有局部变量 + } + } + //HACK:如果需要支持代码块级局部变量则需要在此处闭合代码块 + this.Control_CurrentLine++; + } + /// + /// 结束「Funcation」方法体 + /// + protected void CmdC_EndF() + { + int index = this.Control_CurrentLine; + if (this.Invoke_FuncStack.TryPop(out Def_FuncInvoke funcHandle)) + this.Control_CurrentLine = funcHandle.ReturnLine; + else this.Control_CurrentLine++; + while (index >= 0) + { + index--; + string cmd = Pre_Hand(this.Script[index]); + if (cmd == "func") break; + else if (cmd == "letp") + { + //HACK:清除方法定义中使用「LetP」声明的所有局部变量 + } + } + //HACK:如果需要支持代码块级局部变量则需要在此处闭合代码块 + } + /// + /// $>> 跳转到指定的指令序列位置 + /// 注意:跳转指令不会超出「Funcation」范围;如果超出,引擎会自动修正 + /// + /// 要跳转的行号 + protected void CmdI_Goto(string cmdArgs) + { + //HACK:向下跳转时执行所有「End*」指令来释放局部变量 + //HACK:向上跳转时倒置所有结构声明指令与其结束指令来释放局部变量和结构栈 + + //HACK:正式逻辑的「Goto」指令不允许超过「Funcation」范围 + this.Control_CurrentLine = int.Parse(cmdArgs); + } + /// + /// 将一个值表达式转换为一个值 + /// + /// 值表达式 + /// 类型比对优先级:bool、double、@ParamName|string + private object Val_Variant(string rawValue) + { + object result; + if (bool.TryParse(rawValue, out bool boolValue)) + result = boolValue; + else if (double.TryParse(rawValue, out double doubleValue)) + result = doubleValue; + else if (rawValue.StartsWith('@')) + result = this.ParamGetter(rawValue, 0); + else result = rawValue; + return result; + } + /// + /// $>> 声明全局变量或为全局变量赋值 + /// 示例:paramName [[@]value] + /// + /// 指令参数 + protected void CmdI_VarP(string cmdArgs) + { + string[] paramDefine = (cmdArgs ?? "").Split(' ', options: StringSplitOptions.RemoveEmptyEntries); + if (paramDefine.Length == 1) paramDefine = [paramDefine[0], "0"]; + if (paramDefine.Length > 1) + { + object paramValue = this.Val_Variant(paramDefine[1]); + + if (!Param_Global.TryAdd(paramDefine[0], paramValue)) + this.Param_Global[paramDefine[0]] = paramValue; + } + this.Control_CurrentLine++; + } + /// + /// $>> 声明局部变量或为局部变量赋值 + /// 示例:paramName [[@]value] + /// + /// 指令参数 + protected void CmdI_LetP(string cmdArgs) + { + string[] paramDefine = (cmdArgs ?? "").Split(' ', options: StringSplitOptions.RemoveEmptyEntries); + if (paramDefine.Length == 1) paramDefine = [paramDefine[0], "0"]; + if (paramDefine.Length > 1) + { + if (this.Invoke_FuncStack.TryPeek(out var funcHandle)) + { + object paramValue = this.Val_Variant(paramDefine[1]); + + if (!funcHandle.LocalParams.TryAdd(paramDefine[0], paramValue)) + funcHandle.LocalParams[paramDefine[0]] = paramValue; + } + else this.CmdI_VarP(cmdArgs ?? ""); + } + this.Control_CurrentLine++; + } + /// + /// $>> 根据条件执行逻辑 + /// 示例:false @Var1 3 > @Var2 == + /// + /// 条件表达式 + protected void CmdI_IfTh(string cmdArgs) + { + this.Control_CurrentLine++; + //HACK:如果需要支持块级变量则需要在此处声明变量空间 + if (!this.CmdP_Cond(cmdArgs)) + { + while (this.Control_CurrentLine < this.Script.Count) + { + string cmd = Pre_Hand(this.Script[this.Control_CurrentLine]); + if (cmd == "endI") break; + else if (cmd == "else") + { + this.Control_CurrentLine++; + break; + } + else this.Control_CurrentLine++; + } + } + } + /// + /// $>> 根据条件循环执行内部逻辑 + /// 示例:false @Var1 3 > @Var2 == + /// + /// 条件表达式 + protected void CmdI_Whil(string cmdArgs) + { + this.Control_CurrentLine++; + //HACK:如果需要支持块级变量则需要在此处声明变量空间 + if (!this.CmdP_Cond(cmdArgs)) + { + while (this.Control_CurrentLine < this.Script.Count) + { + if (Pre_Hand(this.Script[this.Control_CurrentLine]) == "endw") + break; + else this.Control_CurrentLine++; + } + } + } + /// + /// 等待指定的毫秒数 + /// + /// 等待时间,「double」类型的字符串形式 + protected void CmdI_Time(string cmdArgs) + { + if (double.TryParse(cmdArgs, out double workTime)) + { + while (this.RunningMode == Mode.Running && this.Control_CurrentTime.AddMilliseconds(workTime) > DateTime.Now) + Thread.Sleep(this.Control_WakeupCycle); + } + this.Control_CurrentLine++; + } + /// + /// 声明一个可调用过程 + /// + /// 可调用过程名称 + protected void CmdI_Func(string cmdArgs) + { + string funcName = Pre_Hand(cmdArgs ?? "", false); + int index = this.Control_CurrentLine; + do + { + index++; + string cmdName = Pre_Hand(this.Script[index]); + if (cmdName == "endf") + { + foreach (var funcDefine in this.FuncDefines) + { + if (funcDefine.Name == funcName) + { + this.FuncDefines.Remove(funcDefine); + break; + } + } + this.FuncDefines.Add(new Def_FuncDefine(funcName, this.Control_CurrentLine + 1)); + this.Control_CurrentLine = index + 1; + return; + } + } while (index < this.Script.Count); + this.Control_CurrentLine++; + } + /// + /// $>> 调用脚本内部定义的方法 + /// funcName [@args1...] + /// + /// 方法名及参数表,参数表可以为空 + protected void CmdI_Call(string cmdArgs) + { + string[] args = (cmdArgs ?? "").Split(' ', options: StringSplitOptions.RemoveEmptyEntries); + if (args.Length == 0) + { + this.Control_CurrentLine++; + return; + } + string funcName = args[0]; + for (int i = 1; i < args.Length; i++) this.Invoke_ArgsStack.Push(this.ParamGetter(args[i], 0)); + foreach (var func in this.FuncDefines) + { + if (func.Name == funcName) + { + this.Invoke_FuncStack.Push(new Def_FuncInvoke(this.Control_CurrentLine + 1)); + this.Control_CurrentLine = func.Line; + break; + } + } + } + /// + /// $>> 调用外部引用的方法 + /// execName [@args1...] + /// + /// 方法名及参数表,参数表可以为空 + protected void CmdI_Exec(string cmdArgs) + { + string[] argParts = (cmdArgs ?? "").Split(' ', options: StringSplitOptions.RemoveEmptyEntries); + if (argParts.Length > 0) + { + string procName = argParts[0]; + for (int i = 1; i < argParts.Length; i++) + this.Invoke_ArgsStack.Push(this.ParamGetter(argParts[i], 0)); + foreach (var func in this.FuncImports) + { + if (func.Name == procName) + { + func.Action.Invoke(this.Invoke_ArgsStack); + break; + } + } + } + this.Control_CurrentLine++; + } + /// + /// 从调用栈中弹出变量并存储到指定的参数中 + /// + /// 弹出数据的存放位置 + protected void CmdS_PopV(string cmdArgs) + { + if (this.Invoke_ArgsStack.TryPop(out var param)) + this.ParamSetter(cmdArgs, param); + this.Control_CurrentLine++; + } + /// + /// 对一个值表达式进行求职并压入到参数栈中 + /// + /// 值表达式:支持bool、double、@ParamName|string + protected void CmdS_Push(string cmdArgs) + { + this.Invoke_ArgsStack.Push(this.Val_Variant(cmdArgs)); + this.Control_CurrentLine++; + } + /// + /// $>> 执行数学表达式 + /// 示例:Math @VarX @VarO 24 + @VarT * ++ + /// 语义:将变量「VarO」的值与「24」相加,再与变量「VarT」的值做乘法,最后进行自加运算;结果存储与「VarX」变量中 + /// + /// 数学表达式:后缀表达式 + protected void CmdI_Math(string expression) + { + string paramName = ""; + object paramValue = 0; + Stack stack = []; + string[] cmdParts = expression.Split(' ', options: StringSplitOptions.RemoveEmptyEntries); + if (cmdParts.Length > 0) + { + paramName = cmdParts[0]; + int index = 1; + while (index < cmdParts.Length) + { + switch (cmdParts[index]) + { + case "+": Math_Add(stack); break; + case "-": Math_Sub(stack); break; + case "*": Math_Mul(stack); break; + case "/": Math_Div(stack); break; + case "^": Math_Pow(stack); break; + case "~": Math_Inv(stack); break; + case "%": Math_Mod(stack); break; + case "|": Math_Abs(stack); break; + case "!": Math_Int(stack); break; + case "++": Math_Inc(stack); break; + case "--": Math_Dec(stack); break; + case ">>": Math_ShR(stack); break; + case "<<": Math_ShL(stack); break; + default: + stack.Push(this.Val_Double(this.ParamGetter(cmdParts[index], 0))); + break; + } + index++; + }; + } + if (stack.Count > 0) paramValue = stack.Pop(); + this.ParamSetter(paramName, paramValue); + this.Control_CurrentLine++; + } + #region 数学计算「Math」指令辅助方法 + /// + /// 根据脚本语义请一个「原始值」映射为一个可以参与数学计算的数值 + /// + /// 原始值:可能是数值、数值表达式、参数表达式或其它表达式 + /// 如果原始值不是数值或等效的数值表达式则返回「0」 + private double Val_Double(object rawValue) + { + if (rawValue is double tValue) return tValue; + string paramExp = rawValue?.ToString() ?? "0"; + object valueExp = paramExp.StartsWith('@') ? this.ParamGetter(paramExp, 0) : paramExp; + if (valueExp is double pValue) return pValue; + if (double.TryParse(valueExp.ToString(), out double dValue)) return dValue; + return 0; + } + /// + /// 检查一个数学运算是否可以执行 + /// + /// 存储数值的栈 + /// 数学运算需要的参数数量 + /// 当前数值栈是否有足够的参数数量 + private static bool Pre_Math(Stack numStack, int count) + { + if (numStack.Count < count) + { + numStack.Clear(); + numStack.Push(0); + return false; + } + else return true; + } + /// + /// 加法 + /// + private static void Math_Add(Stack numStack) + { + if (Pre_Math(numStack, 2)) + { + double rParam = numStack.Pop(); + double lParam = numStack.Pop(); + numStack.Push(lParam + rParam); + } + } + /// + /// 减法 + /// + private static void Math_Sub(Stack numStack) + { + if (Pre_Math(numStack, 2)) + { + double rParam = numStack.Pop(); + double lParam = numStack.Pop(); + numStack.Push(lParam - rParam); + } + } + /// + /// 乘法 + /// + private static void Math_Mul(Stack numStack) + { + if (Pre_Math(numStack, 2)) + { + double rParam = numStack.Pop(); + double lParam = numStack.Pop(); + numStack.Push(lParam * rParam); + } + } + /// + /// 除法 + /// + private static void Math_Div(Stack numStack) + { + if (Pre_Math(numStack, 2)) + { + double rParam = numStack.Pop(); + double lParam = numStack.Pop(); + numStack.Push(lParam + rParam == 0 ? 1 : rParam); + } + } + /// + /// 幂运算 + /// + private static void Math_Pow(Stack numStack) + { + if (Pre_Math(numStack, 2)) + { + double rParam = numStack.Pop(); + double lParam = numStack.Pop(); + numStack.Push(System.Math.Pow(lParam, rParam)); + } + } + /// + /// 自加 + /// + private static void Math_Inc(Stack numStack) + { + if (Pre_Math(numStack, 1)) + { + double lParam = numStack.Pop(); + numStack.Push(lParam++); + } + } + /// + /// 自减 + /// + private static void Math_Dec(Stack numStack) + { + if (Pre_Math(numStack, 1)) + { + double lParam = numStack.Pop(); + numStack.Push(lParam--); + } + } + /// + /// 取反 + /// + private static void Math_Inv(Stack numStack) + { + if (Pre_Math(numStack, 1)) + { + double lParam = numStack.Pop(); + numStack.Push(-lParam); + } + } + /// + /// 取模 + /// + private static void Math_Mod(Stack numStack) + { + if (Pre_Math(numStack, 2)) + { + double rParam = numStack.Pop(); + double lParam = numStack.Pop(); + numStack.Push(lParam % rParam); + } + } + /// + /// 绝对值 + /// + private static void Math_Abs(Stack numStack) + { + if (Pre_Math(numStack, 1)) + { + double lParam = numStack.Pop(); + numStack.Push(System.Math.Abs(lParam)); + } + } + /// + /// 取整数 + /// + private static void Math_Int(Stack numStack) + { + if (Pre_Math(numStack, 1)) + { + double lParam = numStack.Pop(); + numStack.Push((int)lParam); + } + } + /// + /// 左移位 + /// + private static void Math_ShL(Stack numStack) + { + if (Pre_Math(numStack, 2)) + { + double rParam = numStack.Pop(); + double lParam = numStack.Pop(); + numStack.Push((int)lParam << (int)rParam); + } + } + /// + /// 右移位 + /// + private static void Math_ShR(Stack numStack) + { + if (Pre_Math(numStack, 2)) + { + double rParam = numStack.Pop(); + double lParam = numStack.Pop(); + numStack.Push((int)lParam >> (int)rParam); + } + } + #endregion + /// + /// 评估一个条件表达式的值 + /// 示例:false @Var1 3 > @Var2 == + /// + /// 条件表达式:后缀表达式 + /// 表达式的真值,如果表达式有误则返回指定的值 + private bool CmdP_Cond(string condition) + { + bool result = true; + Stack stack = []; + string[] conParts = condition.Split(' ', options: StringSplitOptions.RemoveEmptyEntries); + if (conParts.Length > 0) + { + result = bool.Parse(conParts[0].ToLower()); + int index = 0; + while (index < conParts.Length) + { + index++; + switch (conParts[index]) + { + case "!": this.Cond_Nega(stack); break; + + case "<": this.Cond_Less(stack); break; + case ">": this.Cond_Grea(stack); break; + + case "<=": this.Cond_NotG(stack); break; + case ">=": this.Cond_NotL(stack); break; + case "==": this.Cond_Equa(stack); break; + case "!=": this.Cond_NotE(stack); break; + + case "&&": this.Cond__And(stack); break; + case "||": this.Cond___Or(stack); break; + + default: stack.Push(conParts[index]); break; + } + } + } + if (stack.Count > 0) result = this.Val_Boolean(stack.Pop()); + return result; + } + #region 条件运算的辅助方法 + /// + /// 根据脚本语义将一个「原始值」映射成一个可以进行逻辑计算的布尔值 + /// + /// 原始值:可能是布尔表达式、参数表达式或其它表达式 + /// 如果不是等效的布尔表达式则返回「False」 + private bool Val_Boolean(object rawValue) + { + if (rawValue is bool tValue) return tValue; + string paramExp = rawValue?.ToString() ?? "false"; + object valueExp = paramExp.StartsWith('@') ? this.ParamGetter(paramExp, 0) : paramExp; + if (valueExp is bool pValue) return pValue; + if (bool.TryParse(valueExp.ToString(), out bool dValue)) return dValue; + return false; + } + /// + /// 检查一个逻辑运算是否可以执行 + /// + /// 存储逻辑表达式的栈 + /// 逻辑运算需要的参数数量 + /// 当前逻辑栈是否有足够的参数数量 + private static bool Pre_Cond(Stack condParts, int count) + { + if (condParts.Count < count) + { + condParts.Clear(); + condParts.Push(false); + return false; + } + return true; + } + /// + /// 小于 + /// + private void Cond_Less(Stack condParts) + { + if (Pre_Cond(condParts, 2)) + { + double rParam = this.Val_Double(condParts.Pop()); + double lParam = this.Val_Double(condParts.Pop()); + condParts.Push(lParam < rParam); + } + } + /// + /// 不小于 + /// + private void Cond_NotL(Stack condParts) + { + if (Pre_Cond(condParts, 2)) + { + double rParam = this.Val_Double(condParts.Pop()); + double lParam = this.Val_Double(condParts.Pop()); + condParts.Push(lParam >= rParam); + } + } + /// + /// 大于 + /// + private void Cond_Grea(Stack condParts) + { + if (Pre_Cond(condParts, 2)) + { + double rParam = this.Val_Double(condParts.Pop()); + double lParam = this.Val_Double(condParts.Pop()); + condParts.Push(lParam > rParam); + } + } + /// + /// 不大于 + /// + private void Cond_NotG(Stack condParts) + { + if (Pre_Cond(condParts, 2)) + { + double rParam = this.Val_Double(condParts.Pop()); + double lParam = this.Val_Double(condParts.Pop()); + condParts.Push(lParam <= rParam); + } + } + /// + /// 等于 + /// + private void Cond_Equa(Stack condParts) + { + if (Pre_Cond(condParts, 2)) + { + double rParam = this.Val_Double(condParts.Pop()); + double lParam = this.Val_Double(condParts.Pop()); + condParts.Push(lParam == rParam); + } + } + /// + /// 不等于 + /// + private void Cond_NotE(Stack condParts) + { + if (Pre_Cond(condParts, 2)) + { + double rParam = this.Val_Double(condParts.Pop()); + double lParam = this.Val_Double(condParts.Pop()); + condParts.Push(lParam != rParam); + } + } + /// + /// 取反 + /// + private void Cond_Nega(Stack condParts) + { + if (Pre_Cond(condParts, 1)) + { + bool lParam = this.Val_Boolean(condParts.Pop()); + condParts.Push(!lParam); + } + } + /// + /// 与逻辑 + /// + private void Cond__And(Stack condParts) + { + if (Pre_Cond(condParts, 2)) + { + bool lParam = this.Val_Boolean(condParts.Pop()); + bool rParam = this.Val_Boolean(condParts.Pop()); + condParts.Push(lParam && rParam); + } + } + /// + /// 或逻辑 + /// + private void Cond___Or(Stack condParts) + { + if (Pre_Cond(condParts, 2)) + { + bool lParam = this.Val_Boolean(condParts.Pop()); + bool rParam = this.Val_Boolean(condParts.Pop()); + condParts.Push(lParam || rParam); + } + } + #endregion + /// + /// 设置参数表中的一个参数 + /// 备注:先去局部变量中查找,再去全局变量中查找,最后去外部引用变量中查找 + /// + /// + /// + private void ParamSetter(string paramName, object paramValue) + { + //HACK:暂时不支持代码块级的局部变量 + if (this.Invoke_FuncStack.TryPeek(out var funcHandle)) + { + if (funcHandle.LocalParams.ContainsKey(paramName)) + { + funcHandle.LocalParams[paramName] = paramValue; + return; + } + } + if (this.Param_Global.ContainsKey(paramName)) + { + this.Param_Global[paramName] = paramValue; + return; + } + foreach (var paramRefer in this.Param_Refers) + { + if (paramRefer.Name == paramName) + { + this.Param_Refers.Remove(paramRefer); + this.Param_Refers.Add(new Def_ParamRefer(paramName, paramValue)); + return; + } + } + this.Param_Global.Add(paramName, paramValue); + } + /// + /// 从参数表中获取参数 + /// 备注:先去局部变量中查找,再去全局变量中查找,最后去外部引用变量中查找 + /// + /// + /// + /// + private object ParamGetter(string paramName, object @default) + { + //HACK:暂时不支持代码块级的局部变量 + if (this.Invoke_FuncStack.TryPeek(out var funcHandle)) + { + if (funcHandle.LocalParams.TryGetValue(paramName, out object? localValue)) + return localValue; + } + if (this.Param_Global.TryGetValue(paramName, out object? globalValue)) + { + return globalValue; + } + foreach (var paramRefer in this.Param_Refers) + { + if (paramRefer.Name == paramName) + { + return paramRefer.Param; + } + } + return @default; + } + } +}