From a8cfb012fc30d5e1821e559792d082c607aa7534 Mon Sep 17 00:00:00 2001 From: ninemine <1371605831@qq.com> Date: Sat, 27 Sep 2025 22:05:04 +0800 Subject: [PATCH] EP RScript --- Convention/[RScript]/ScriptContent.cs | 325 ++++++++++++++++++++++++++ Convention/[RScript]/ScriptRunner.cs | 29 +++ [Test]/Program.cs | 15 +- 3 files changed, 355 insertions(+), 14 deletions(-) create mode 100644 Convention/[RScript]/ScriptContent.cs create mode 100644 Convention/[RScript]/ScriptRunner.cs diff --git a/Convention/[RScript]/ScriptContent.cs b/Convention/[RScript]/ScriptContent.cs new file mode 100644 index 0000000..e499b0b --- /dev/null +++ b/Convention/[RScript]/ScriptContent.cs @@ -0,0 +1,325 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; + +namespace Convention.RScript +{ + public partial class ScriptContent + { + public object RuntimeBindingTarget; + + public struct RuntimeContext + { + public int iterator; + public bool isResetIterator; + + public static RuntimeContext Create() + { + return new RuntimeContext() + { + iterator = 0, + isResetIterator = false + }; + } + + public RuntimeContext Clone() + { + return new() + { + iterator = iterator, + isResetIterator = isResetIterator + }; + } + } + + public class ScriptDataEntry + { + public string text; + + public string command; + public string[] parameters; + public int iterator; + + public Func actor; + } + + private List Commands = new(); + + // 预处理工具 + + public static int LastIndexOfNextTerminalTail(string text, int i, string terminal) + { + return text.IndexOf(terminal, i) + terminal.Length - 1; + } + + public static bool StartWithSpecialTerminal(string text,int i) + { + switch (text[i]) + { + case '{': + case '}': + return true; + default: + return false; + } + } + + public const string SingleLineTerminal = "//"; + public const string MultiLineBeginTerminal = "/*"; + public const string MultiLineEndTerminal = "*/"; + public const string TextTerminal = "\""; + + public static bool StartWithSingleLineTerminal(string text, int i) + { + int length = SingleLineTerminal.Length; + if (text.Length - i < length) + return false; + return string.Compare(text, i, SingleLineTerminal, 0, length) == 0; + } + + public static bool StartWithMultiLineTerminal(string text, int i) + { + int length = MultiLineBeginTerminal.Length; + if (text.Length - i < length) + return false; + return string.Compare(text, i, MultiLineBeginTerminal, 0, length) == 0; + } + + public static bool StartWithTextTerminal(string text, int i) + { + int length = TextTerminal.Length; + if (text.Length - i < length) + return false; + return string.Compare(text, i, TextTerminal, 0, length) == 0; + } + + public static int LastIndexOfNextTextTerminalTail(string text, int i,out string buffer) + { + char terminal = TextTerminal[0]; + int __head = i + 1; + buffer = ""; + for (int __tail = text.Length; __head < __tail && text[__head] != terminal;) + { + if (text[__head] == '\\') + { + switch (text[__head+1]) + { + case 'n': + { + buffer += '\n'; + } + break; + case 't': + { + buffer += '\t'; + } + break; + case 'r': + { + buffer += '\r'; + } + break; + case '0': + { + buffer += '\0'; + } + break; + default: + { + buffer += text[__head + 1]; + } + break; + } + __head += 2; + } + else + { + buffer += text[__head]; + __head++; + } + } + return __head; + } + + // 文本预处理 + private void ScriptTextPreprocessing(string script) + { + string buffer = ""; + void PushBuffer() + { + if (string.IsNullOrEmpty(buffer) == false) + { + Commands.Add(new() + { + text = buffer.Trim(), + iterator = Commands.Count + }); + } + buffer = ""; + } + Func loopPr = x => x < script.Length; + for (int i = 0; loopPr(i); i++) + { + // 切断语句\ + if (script[i] == ';') + { + PushBuffer(); + } + // 读入特殊标记符 + else if (StartWithSpecialTerminal(script, i)) + { + PushBuffer(); + buffer += script[i]; + PushBuffer(); + } + // 跳过单行注释 + else if (StartWithSingleLineTerminal(script, i)) + { + i = LastIndexOfNextTerminalTail(script, i, "\n"); + } + // 跳过多行注释 + else if (StartWithMultiLineTerminal(script, i)) + { + i = LastIndexOfNextTerminalTail(script, i, MultiLineEndTerminal); + } + // 读入文本 + else if (StartWithTextTerminal(script, i)) + { + i = LastIndexOfNextTextTerminalTail(script, i, out var temp); + buffer += temp; + } + // 读入 + else if (loopPr(i)) + buffer += script[i]; + } + // 存在未完成的语句 + if (string.IsNullOrEmpty(buffer) == false) + throw new ArgumentException("The script did not end with the correct terminator."); + } + + // 指令预处理工具 + + private Dictionary CommandIndexs = new(); + private Dictionary LabelIndexs = new(); + + public const string GotoTerminal = "goto"; + public const string LabelTerminal = "label"; + public const string IfTerminal = "if"; + + // 指令预处理 + private void CommandPreprocessing() + { + static GroupCollection Match(ScriptDataEntry entry, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern) + { + Match match = Regex.Match(entry.text, pattern); + if (!match.Success) + throw new ArgumentException($"Script: \"{entry.text}\" is invalid statement"); + return match.Groups; + } + + // 加入自由映射 + foreach (var entry in Commands) + { + CommandIndexs.Add(entry.iterator, entry); + } + // 匹配 + foreach (var entry in Commands) + { + if ( + // goto label-name; + entry.text.StartsWith(GotoTerminal)|| + // label label-name; + entry.text.StartsWith(LabelTerminal) + ) + { + var groups = Match(entry, @"^(\S*)\s+([^\s]+?)\s*;$"); + entry.command = groups[1].Value; + entry.parameters = new string[] { groups[2].Value }; + // touch label + if (entry.command == LabelTerminal) + { + LabelIndexs.Add(groups[2].Value, entry.iterator); + } + } + else if ( + // if(expr) + entry.text.StartsWith(IfTerminal) + ) + { + var groups = Match(entry, @"^(\S*)\s*(.*?)$"); + entry.command = groups[1].Value; + entry.parameters = new string[] { groups[2].Value }; + } + else + { + var groups = Match(entry, @"^(\w+)\s*\(\s*(.*?)\s*\)\s*;$"); + entry.command = groups[1].Value; + + static string[] ParseArguments(string argumentsString) + { + if (string.IsNullOrWhiteSpace(argumentsString)) + return new string[0]; + + // 处理字符串字面量和普通参数的正则表达式 + string argPattern = @"""(?:[^""\\]|\\.)*""|[^,]+"; + + return Regex.Matches(argumentsString, argPattern) + .Cast() + .Select(m => m.Value.Trim()) + .Where(arg => !string.IsNullOrEmpty(arg)) + .ToArray(); + } + + entry.parameters = ParseArguments(groups[2].Value); + } + } + } + + // 指令转化 + + private void LoopForTC2AC() + { + Dictionary cache = (from method in RuntimeBindingTarget.GetType().GetMethods() + select new KeyValuePair(method.Name, method)).ToDictionary(); + + for (int index = 0, e = Commands.Count; index < e; index++) + { + var entry = Commands[index]; + // Keywords + if (entry.command == GotoTerminal) + { + entry.actor = context => + { + var next = context.Clone(); + next.iterator = LabelIndexs[entry.parameters[0]]; + next.isResetIterator = true; + return next; + }; + } + // Custom Binding + else if(cache.TryGetValue(entry.command,out var methodInfo)) + { + entry.actor = context => + { + + return context.Clone(); + }; + } + else + { + + } + } + } + + public void LoadScript(string script) + { + ScriptTextPreprocessing(script); + CommandPreprocessing(); + LoopForTC2AC(); + } + } +} diff --git a/Convention/[RScript]/ScriptRunner.cs b/Convention/[RScript]/ScriptRunner.cs new file mode 100644 index 0000000..3a44379 --- /dev/null +++ b/Convention/[RScript]/ScriptRunner.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Convention.RScript +{ + public class ScriptRunner + { + public ScriptContent BuildNewContent(object target) + { + return new() + { + RuntimeBindingTarget = target, + }; + } + + public ScriptContent BuildNewContent() + { + return BuildNewContent(null); + } + + public void RunScriptFromContent(ScriptContent content) + { + + } + } +} diff --git a/[Test]/Program.cs b/[Test]/Program.cs index c3e1d5d..425a76a 100644 --- a/[Test]/Program.cs +++ b/[Test]/Program.cs @@ -1,23 +1,10 @@ using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using Convention; -using Convention.EasySave; -using Convention.Symbolization; using Convention.Test; public class Program { static void Main(string[] args) { - Console.WriteLine("Convention-CSharp 测试程序"); - Console.WriteLine("=========================="); - - // 运行文件功能测试 - FileTest.RunTests(); - - Console.WriteLine("\n按任意键退出..."); - Console.ReadKey(); + } } \ No newline at end of file