using Island.StandardLib; using Island.StandardLib.Math; using System; using System.Collections.Generic; namespace EXTS { public class EXTSEngine { internal static EXTSEngine CompilingEngine; public const string ValError = "err"; public const string ValDefault = "non"; public Dictionary stdval; public Dictionary funcs; public Dictionary funcptrs; public BodyFuncStatement BodyStatement; public EXTSEngine() { stdval = new Dictionary(); funcs = new Dictionary(); BodyStatement = new BodyFuncStatement(new Statement[0]); } public T AddStatement(T statement) where T : Statement { BodyStatement.statements.Add(statement); return statement; } public FuncStatement AddStatement(string name, FuncStatement statement) { funcs.Add(name, statement); return statement; } internal Stack func_invoke_stack; void CheckStackSafe() { if (func_invoke_stack.Count > 256) { Console.WriteLine("\n-------------------- 运行时错误 --------------------"); Console.WriteLine("当前堆栈深度已超过堆栈的最大允许值为 256 ,程序中存在太多未回收的函数调用。请检查是否存在无限循环递归。"); Console.WriteLine("堆栈列表:"); Console.WriteLine(StkName(func_invoke_stack, true, " -> ")); throw new RuntimeException("当前堆栈深度已超过堆栈的最大允许值为 256 ,程序中存在太多函数调用。请检查是否存在无限循环递归。"); } } public EValue RunFuncPtr(string funcptr, EValue[] parameters) { if (!funcptrs.ContainsKey(funcptr)) throw new RuntimeException("funcptr not founded."); FuncStatement fs = funcptrs[funcptr]; fs.runfunc = true; func_invoke_stack.Push("{ AnonymousFunction }"); CheckStackSafe(); EValue ret = fs.Eval(parameters); func_invoke_stack.Pop(); fs.runfunc = false; return ret; } public EValue RunFuncBase(string funcName, EValue[] parameters) { if (funcName.Contains(":")) { string val = funcName.Split(':')[0]; string method = funcName.Split(':')[1]; EValue value = StatementList.runningStatement[val]; if (!value.Defined) throw new RuntimeException($"variable {val} not defined."); return value.Instance.PassCall(method, parameters); } switch (funcName) { case "Number": { if (parameters.Length == 0) return new EValue(new ENumber(0)); else if (parameters.Length == 1) { ENumber n = parameters[0].As(); if (n == null) throw new RuntimeException("Only can init CLASS with CLASS."); return new EValue(new ENumber(n.Value)); } throw new RuntimeException("Number init usage error."); } case "Vec3": { if (parameters.Length == 0) return new EValue(new EVec3(new Vector3(0, 0, 0))); else if (parameters.Length == 1) { EVec3 n = parameters[0].As(); if (n == null) throw new RuntimeException("Only can init CLASS with CLASS."); return new EValue(new EVec3(n.Value)); } else if (parameters.Length == 3) { ENumber[] xyz = parameters.Do((val) => val.As()); if (xyz.Contain(null)) throw new RuntimeException("[Vec3 x,y,z] Request Number parameters"); } throw new RuntimeException("Vec3 init usage error."); } case "String": { if (parameters.Length == 0) return new EValue(new EString("")); else if (parameters.Length == 1) { EString n = parameters[0].As(); if (n == null) throw new RuntimeException("Only can init CLASS with CLASS."); return new EValue(new EString(n.Value)); } throw new RuntimeException("Vec3 init usage error."); } case "static": { if (parameters.Length == 1) { EString v = parameters[0].As(); if (v == null) throw new RuntimeException("static varname request String class."); return stdval.Get(v.Value, new EValue()); } else if (parameters.Length == 2) { EString v = parameters[0].As(); if (v == null) throw new RuntimeException("static varname request String class."); stdval.Set(v.Value, parameters[1]); return parameters[1]; } else throw new RuntimeException("static Usage Error."); } case "callfuncptr": { if (parameters.Length == 0) throw new RuntimeException("callfuncptr request a parameters."); EString v = parameters[0].As(); if (v == null) throw new RuntimeException("callfuncptr usage error."); return RunFuncPtr(v.Value, parameters.Sub(1, parameters.Length)); } case "stackinfo": { return new EValue(new EString(StkName(func_invoke_stack, true, " -> "))); } default: { FuncStatement fs = funcs.Get(funcName); if (fs == null) throw new RuntimeException($"Func {funcName} Not founded"); func_invoke_stack.Push(funcName); CheckStackSafe(); EValue ret = fs.Eval(parameters); func_invoke_stack.Pop(); return ret; } } } string compilingCode; int compilingPos; const char EOF = (char)0; bool InList(char ch, char[] add) { for (int i = 0; i < add.Length; i++) if (ch == add[i]) return true; return false; } bool ChBlank(char ch) { if (ch == ' ' || ch == '\t' || ch == '\n') return true; else return false; } bool ChBlankTEOFA(char ch, char[] add) { if (ch == ' ' || ch == '\t' || ch == '\n' || ch == EOF || ch == ']') return true; return InList(ch, add); } char Peek() { if (compilingPos < compilingCode.Length) return compilingCode[compilingPos++]; else { compilingPos++; return EOF; } } const string symallowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; bool SymAllowed(char c, bool loc) { if (loc && (c == '.' || c == ':')) return true; for (int i = 0; i < symallowed.Length; i++) if (c == symallowed[i]) return true; return false; } /// /// 读取当前位置的字符,直到遇到空白字符和 excludelist 中的字符 /// /// 被识别为空白字符的附加字符 /// string PeekToBlank(params char[] excludelist) { string str = ""; char ch; while (!ChBlankTEOFA(ch = Peek(), excludelist)) str += ch; compilingPos--; return str; } /// /// 读取当前位置的字符,直到遇到空白字符和 excludelist 中的字符,只允许字母数字和下划线输入 /// /// 被识别为空白字符的附加字符 /// string PeekToBlankSym(params char[] excludelist) { string str = ""; char ch; while (!ChBlankTEOFA(ch = Peek(), excludelist)) { if (!SymAllowed(ch, false)) throw new SyntaxException("在符号定义中,不允许出现字符 " + ch, compilingPos); str += ch; } compilingPos--; return str; } string PeekToBlankLocSym(params char[] excludelist) { string str = ""; char ch; while (!ChBlankTEOFA(ch = Peek(), excludelist)) { if (!SymAllowed(ch, true)) throw new SyntaxException("在符号定义中,不允许出现字符 " + ch, compilingPos); str += ch; } compilingPos--; return str; } /// /// 跳过空白字符和 includelist 中的字符,转到下一个字的前一个位置 /// /// 被识别为空白字符的附加字符 void PeekToWord(params char[] includelist) { char ch; while (ChBlank(ch = Peek()) || InList(ch, includelist)) ; compilingPos--; } string PeekString() { string str = ""; char ch; while (true) { ch = Peek(); if (ch == '\\') { char ct = Peek(); switch (ct) { case 'n': str += '\n'; break; case 't': str += '\t'; break; case '\"': str += '\"'; break; case '\\': str += '\\'; break; default: throw new SyntaxException("未识别的转义符。", compilingPos); } } if (ch == EOF) throw new SyntaxException("字符串直到文件结尾都未结束,请检查引号是否完整。", compilingPos); if (ch == '\"') { break; } str += ch; } return str; } ImmediateStatement CompileImmediateStatementF() { string valstr = PeekToBlank(';'); ImmediateStatement statement = new ImmediateStatement(valstr); PeekToWord(); return statement; } ImmediateStatement CompileImmediateStatementS() { ImmediateStatement statement = new ImmediateStatement(PeekString()); PeekToWord(); return statement; } GetValStatement CompileGetValStatement() { GetValStatement statement = new GetValStatement(currentfunc.Peek(), PeekToBlankSym(';')); PeekToWord(); return statement; } CallFuncStatement CompileCallFuncStatement() { List pmts = new List(); PeekToWord(); string calName = PeekToBlankLocSym('['); if (calName.Length > 0) { if (calName[0] == '.') { calName = calName.Substring(1); func_compile_stack.Push(calName); calName = StkName(func_compile_stack, true); func_compile_stack.Pop(); } } PeekToWord(); while (true) { switch (Peek()) { case '[': pmts.Add(CompileCallFuncStatement()); break; case '$': pmts.Add(CompileImmediateStatementF()); break; case '\"': pmts.Add(CompileImmediateStatementS()); break; case ':': { compilingPos--; pmts.Add(CompileFuncStatement(currentfunc.Peek() as FuncStatement, true)); break; } case ']': return new CallFuncStatement(calName, pmts.ToArray()); case ';': throw new SyntaxException("在函数调用中,意外的语句结束。", compilingPos); case EOF: throw new SyntaxException("函数调用直到文件结尾都未结束,请检查方括号是否匹配。", compilingPos); default: compilingPos--; pmts.Add(CompileGetValStatement()); break; } PeekToWord(); } } SetValStatement CompileSetValStatement(string name) { PeekToWord(); Statement valst; switch (Peek()) { case '[': valst = CompileCallFuncStatement(); break; case '$': valst = CompileImmediateStatementF(); break; case '\"': valst = CompileImmediateStatementS(); break; case ']': throw new SyntaxException("在赋值语句中,意外的符号 ]。", compilingPos); case ';': throw new SyntaxException("在赋值语句中,意外的语句结束。", compilingPos); case EOF: throw new SyntaxException("赋值语句直到文件结尾都未结束,请检查方括号是否匹配。", compilingPos); default: compilingPos--; valst = CompileGetValStatement(); break; } PeekToWord(); char ch = Peek(); if (ch == ';') return new SetValStatement(currentfunc.Peek(), name, valst); throw new SyntaxException("赋值语句结束后仍然出现语句,请检查是否缺少分号。", compilingPos); } string StkName(Stack stk, bool reverse, string link = ".") { string b = ""; List r = new List(); foreach (string st in stk) r.Add(st); if (reverse) r.Reverse(); for (int i = 0; i < r.Count; i++) b += r[i] + link; if (b.Length != 0) b = b.Substring(0, b.Length - link.Length); return b; } Statement CompileStatement() { PeekToWord(); char ch = Peek(); switch (ch) { case EOF: throw new SyntaxException("语句直到文件结尾都未结束。", compilingPos); case ';': throw new SyntaxException("不可分析的语句结尾。", compilingPos); case '[': return CompileCallFuncStatement(); case '$': return CompileImmediateStatementF(); case '\"': return CompileImmediateStatementS(); default: { string name = ch + PeekToBlankSym('=', ';'); PeekToWord(); char p = Peek(); if (p == EOF) throw new SyntaxException("不可分析的文件结尾。", compilingPos); else if (p == '=') return CompileSetValStatement(name); else { compilingPos--; return new GetValStatement(currentfunc.Peek(), name); } } } } FuncStatement CompileFuncStatement(FuncStatement parent, bool isAnonymousFunc) { string funcname = PeekToBlankSym(':', '{'); FuncStatement func = new FuncStatement(); func.runfunc = !isAnonymousFunc; func.parentVarlst = parent; currentfunc.Push(func); func_compile_stack.Push(funcname); string fullfuncname = StkName(func_compile_stack, true); func.name = fullfuncname; PeekToWord(); char t = Peek(); if (t == ':') { int i = 0; while (true) { PeekToWord(); char p = Peek(); if (p == EOF) throw new SyntaxException("函数的参数列表直到文件结尾都未结束,请检查函数 " + funcname + " 的定义。", compilingPos); if (p == '{') break; compilingPos--; string varname = PeekToBlankSym(); func.AddStatement(new SetValStatement(func, varname, new GetValStatement(func, "pmt" + i))); i++; } PeekToWord(); } else if (t == '{') PeekToWord(); else throw new SyntaxException("错误的函数表达式形式。", compilingPos); char ch; while (true) { PeekToWord(); ch = Peek(); switch (ch) { case EOF: throw new SyntaxException("函数 " + funcname + " 直到文件结尾都未结束,请检查大括号是否匹配。", compilingPos); case '}': func_compile_stack.Pop(); currentfunc.Pop(); if (!isAnonymousFunc) { if (funcs.ContainsKey(fullfuncname)) throw new SyntaxException("有一个重复的函数 " + fullfuncname + " 。是否使用重载函数?", compilingPos); funcs.Add(fullfuncname, func); } return func; case '[': func.AddStatement(CompileCallFuncStatement()); PeekToWord(); if (Peek() != ';') throw new SyntaxException("函数调用结束后仍然出现语句,请检查是否缺少分号。", compilingPos); break; default: { string name = ch + PeekToBlankSym('=', ';'); PeekToWord(); char p = Peek(); if (p == EOF) throw new SyntaxException("不可分析的文件结尾。", compilingPos); else if (p == '=') func.AddStatement(CompileSetValStatement(name)); else { compilingPos--; if (name == "func") { if (isAnonymousFunc) throw new SyntaxException("当前EXTS版本中,在一个匿名函数中定义一个非匿名函数是没有意义的,因为无法确定这个函数的访问标识符,不排除以后的版本中xc会实现。", compilingPos); CompileFuncStatement(func, isAnonymousFunc); } else if (name == "return") { PeekToWord(); char e = Peek(); if (e == ';') { func.AddStatement(new ReturnStatement()); } else { compilingPos--; func.AddStatement(new SetValStatement(func, "return", CompileStatement())); func.AddStatement(new ReturnStatement()); } } } } break; } } } Stack currentfunc; Stack func_compile_stack; public void Compile(string str) { str = str.Replace("\0", "").Replace("\r", ""); CompilingEngine = this; compilingCode = str; compilingPos = 0; currentfunc = new Stack(); currentfunc.Push(BodyStatement); func_compile_stack = new Stack(); char ch; while (true) { PeekToWord(); ch = Peek(); switch (ch) { case EOF: CompilingEngine = null; return; case '[': currentfunc.Peek().AddStatement(CompileCallFuncStatement()); PeekToWord(); if (Peek() != ';') throw new SyntaxException("函数调用结束后仍然出现语句,请检查是否缺少分号。", compilingPos); break; default: { string name = ch + PeekToBlankSym('='); PeekToWord(); char p = Peek(); if (p == EOF) throw new SyntaxException("不可分析的文件结尾。", compilingPos); else if (p == '=') currentfunc.Peek().AddStatement(CompileSetValStatement(name)); else { compilingPos--; if (name == "func") { CompileFuncStatement(null, false); } } } break; } } } public void Reset() { BodyStatement = new BodyFuncStatement(); funcs = new Dictionary(); funcptrs = new Dictionary(); } public EValue Run(params KeyValuePair[] pmts) { stdval.Clear(); funcptrs = new Dictionary(); func_invoke_stack = new Stack(); EValue val = BodyStatement.Eval(pmts); StatementList.runningStatement = null; return val; } } }