Save
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
using Convention.RScript.Parser;
|
using Convention.RScript.Matcher;
|
||||||
|
using Convention.RScript.Parser;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace Convention.RScript
|
namespace Convention.RScript
|
||||||
{
|
{
|
||||||
@@ -35,10 +35,18 @@ namespace Convention.RScript
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Label,
|
Label,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 跳转到指定标签, 格式: goto(a,b,labelname)
|
/// 跳转到指定标签, 格式: goto(boolean,labelname)
|
||||||
/// <para>当a大于b时跳转到labelname</para>
|
/// <para>判断为真时跳转到labelname</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Goto,
|
Goto,
|
||||||
|
/// <summary>
|
||||||
|
/// 跳转到当前命名空间的结束位置, 格式: break(boolean);
|
||||||
|
/// </summary>
|
||||||
|
Breakpoint,
|
||||||
|
/// <summary>
|
||||||
|
/// 跳转到上次跳转的位置的后一个位置, 格式: back(boolean);
|
||||||
|
/// </summary>
|
||||||
|
Backpoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
public string content;
|
public string content;
|
||||||
@@ -46,6 +54,11 @@ namespace Convention.RScript
|
|||||||
public Mode mode;
|
public Mode mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IRSentenceMatcher
|
||||||
|
{
|
||||||
|
bool Match(string expression, ref RScriptSentence sentence);
|
||||||
|
}
|
||||||
|
|
||||||
public partial class RScriptContext
|
public partial class RScriptContext
|
||||||
{
|
{
|
||||||
public readonly RScriptImportClass Import;
|
public readonly RScriptImportClass Import;
|
||||||
@@ -54,7 +67,17 @@ namespace Convention.RScript
|
|||||||
private readonly Dictionary<string, int> Labels;
|
private readonly Dictionary<string, int> Labels;
|
||||||
private readonly Dictionary<int, int> Namespace;
|
private readonly Dictionary<int, int> Namespace;
|
||||||
|
|
||||||
private static RScriptSentence ParseToSentence(string expression)
|
public List<IRSentenceMatcher> SentenceParser = new()
|
||||||
|
{
|
||||||
|
new NamespaceMater(),
|
||||||
|
new DefineVariableMatcher(),
|
||||||
|
new LabelMatcher(),
|
||||||
|
new GotoMatcher(),
|
||||||
|
new BreakMatcher(),
|
||||||
|
new BackMatcher(),
|
||||||
|
};
|
||||||
|
|
||||||
|
private RScriptSentence ParseToSentence(string expression)
|
||||||
{
|
{
|
||||||
RScriptSentence result = new()
|
RScriptSentence result = new()
|
||||||
{
|
{
|
||||||
@@ -63,45 +86,10 @@ namespace Convention.RScript
|
|||||||
};
|
};
|
||||||
expression = expression.Trim();
|
expression = expression.Trim();
|
||||||
expression.TrimEnd(';');
|
expression.TrimEnd(';');
|
||||||
if (expression == "{")
|
SentenceParser.Any(matcher => matcher.Match(expression, ref result));
|
||||||
{
|
|
||||||
result.mode = RScriptSentence.Mode.EnterNamespace;
|
|
||||||
}
|
|
||||||
else if (expression == "}")
|
|
||||||
{
|
|
||||||
result.mode = RScriptSentence.Mode.ExitNamespace;
|
|
||||||
}
|
|
||||||
|
|
||||||
Regex DefineVariableRegex = new(@"^(string|int|double|float|bool|var)\s+([a-zA-Z_][a-zA-Z0-9_]*)$");
|
|
||||||
var DefineVariableMatch = DefineVariableRegex.Match(expression);
|
|
||||||
if (DefineVariableMatch.Success)
|
|
||||||
{
|
|
||||||
result.mode = RScriptSentence.Mode.DefineVariable;
|
|
||||||
result.info = new() { DefineVariableMatch.Groups[1].Value, DefineVariableMatch.Groups[2].Value };
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Regex LabelRegex = new(@"^label\s*\(\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\)$");
|
|
||||||
var LabelMatch = LabelRegex.Match(expression);
|
|
||||||
if (LabelMatch.Success)
|
|
||||||
{
|
|
||||||
result.mode = RScriptSentence.Mode.Label;
|
|
||||||
result.content = LabelMatch.Groups[1].Value;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Regex GotoRegex = new(@"^goto\s*\(\s*(.+)\s*,\s*(.*)\s*,([a-zA-Z_][a-zA-Z0-9_]*)\s*\)$");
|
|
||||||
var GotoMatch = GotoRegex.Match(expression);
|
|
||||||
if (GotoMatch.Success)
|
|
||||||
{
|
|
||||||
result.mode = RScriptSentence.Mode.Goto;
|
|
||||||
result.content = GotoMatch.Groups[3].Value;
|
|
||||||
result.info = new() { GotoMatch.Groups[1].Value, GotoMatch.Groups[2].Value, GotoMatch.Groups[3].Value };
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
private void BuildUpLabelsAndNamespace(ref Dictionary<string, int> labelIndicator, ref Dictionary<int, int> namespaceIndicator)
|
private void BuildUpLabelsAndNamespace(ref Dictionary<string, int> labelIndicator, ref Dictionary<int, int> namespaceIndicator)
|
||||||
{
|
{
|
||||||
Stack<int> namespaceLayers = new();
|
Stack<int> namespaceLayers = new();
|
||||||
@@ -142,18 +130,7 @@ namespace Convention.RScript
|
|||||||
|
|
||||||
public RScriptSentence CurrentSentence => Sentences[CurrentRuntimePointer];
|
public RScriptSentence CurrentSentence => Sentences[CurrentRuntimePointer];
|
||||||
|
|
||||||
private void RunNextStep(ExpressionParser parser)
|
private void DoDefineVariable(ExpressionParser parser, RScriptSentence sentence)
|
||||||
{
|
|
||||||
var sentence = CurrentSentence;
|
|
||||||
switch (sentence.mode)
|
|
||||||
{
|
|
||||||
case RScriptSentence.Mode.Expression:
|
|
||||||
{
|
|
||||||
// 执行表达式
|
|
||||||
parser.Evaluate(sentence.content);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RScriptSentence.Mode.DefineVariable:
|
|
||||||
{
|
{
|
||||||
// 定义变量
|
// 定义变量
|
||||||
var varTypeName = sentence.info[0];
|
var varTypeName = sentence.info[0];
|
||||||
@@ -189,7 +166,7 @@ namespace Convention.RScript
|
|||||||
else if (varTypeName == "var")
|
else if (varTypeName == "var")
|
||||||
{
|
{
|
||||||
varType = typeof(object);
|
varType = typeof(object);
|
||||||
varDefaultValue = null;
|
varDefaultValue = new object();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -207,8 +184,8 @@ namespace Convention.RScript
|
|||||||
throw new RScriptException($"Variable '{varName}' already defined on this namespace.", CurrentRuntimePointer);
|
throw new RScriptException($"Variable '{varName}' already defined on this namespace.", CurrentRuntimePointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case RScriptSentence.Mode.EnterNamespace:
|
private void DoEnterNamespace(ExpressionParser parser)
|
||||||
{
|
{
|
||||||
// 准备记录当前命名空间中定义的变量, 清空上层命名空间的变量
|
// 准备记录当前命名空间中定义的变量, 清空上层命名空间的变量
|
||||||
CurrentLocalSpaceVariableNames.Push(new());
|
CurrentLocalSpaceVariableNames.Push(new());
|
||||||
@@ -217,9 +194,11 @@ namespace Convention.RScript
|
|||||||
{
|
{
|
||||||
Variables.SetValue(varName, varValue);
|
Variables.SetValue(varName, varValue);
|
||||||
}
|
}
|
||||||
|
// 压栈
|
||||||
|
RuntimePointerStack.Push(CurrentRuntimePointer);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case RScriptSentence.Mode.ExitNamespace:
|
private void DoExitNamespace(ExpressionParser parser)
|
||||||
{
|
{
|
||||||
// 移除在本命名空间中定义的变量
|
// 移除在本命名空间中定义的变量
|
||||||
foreach (var local in CurrentLocalSpaceVariableNames.Peek())
|
foreach (var local in CurrentLocalSpaceVariableNames.Peek())
|
||||||
@@ -233,17 +212,18 @@ namespace Convention.RScript
|
|||||||
parser.context.Variables[local] = Variables[local].data;
|
parser.context.Variables[local] = Variables[local].data;
|
||||||
}
|
}
|
||||||
CurrentLocalSpaceVariableNames.Pop();
|
CurrentLocalSpaceVariableNames.Pop();
|
||||||
|
// 弹栈
|
||||||
|
RuntimePointerStack.Pop();
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case RScriptSentence.Mode.Goto:
|
private void DoGoto(ExpressionParser parser, RScriptSentence sentence)
|
||||||
{
|
{
|
||||||
// 检查并跳转到指定标签
|
// 检查并跳转到指定标签
|
||||||
var leftValue = parser.Evaluate<double>(sentence.info[0]);
|
if (parser.Evaluate<bool>(sentence.info[0]))
|
||||||
var rightValue = parser.Evaluate<double>(sentence.info[1]);
|
|
||||||
if (leftValue > rightValue)
|
|
||||||
{
|
{
|
||||||
if (Labels.TryGetValue(sentence.content, out var labelPointer))
|
if (Labels.TryGetValue(sentence.content, out var labelPointer))
|
||||||
{
|
{
|
||||||
|
GotoPointerStack.Push(CurrentRuntimePointer);
|
||||||
CurrentRuntimePointer = labelPointer;
|
CurrentRuntimePointer = labelPointer;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -252,6 +232,84 @@ namespace Convention.RScript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DoBreakpoint(ExpressionParser parser, RScriptSentence sentence)
|
||||||
|
{
|
||||||
|
// 检查并跳转到当前命名空间的结束位置
|
||||||
|
if (parser.Evaluate<bool>(sentence.content))
|
||||||
|
{
|
||||||
|
if (RuntimePointerStack.Count == 0)
|
||||||
|
{
|
||||||
|
CurrentRuntimePointer = Sentences.Length;
|
||||||
|
}
|
||||||
|
else if (Namespace.TryGetValue(RuntimePointerStack.Peek(), out var exitPointer))
|
||||||
|
{
|
||||||
|
CurrentRuntimePointer = exitPointer;
|
||||||
|
DoExitNamespace(parser);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"No namespace to break.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoBackpoint(ExpressionParser parser, RScriptSentence sentence)
|
||||||
|
{
|
||||||
|
// 检查并跳转到上次跳转的位置的后一个位置
|
||||||
|
if (parser.Evaluate<bool>(sentence.content))
|
||||||
|
{
|
||||||
|
if (GotoPointerStack.Count == 0)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"No position to back.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentRuntimePointer = GotoPointerStack.Pop() + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunNextStep(ExpressionParser parser)
|
||||||
|
{
|
||||||
|
var sentence = CurrentSentence;
|
||||||
|
switch (sentence.mode)
|
||||||
|
{
|
||||||
|
case RScriptSentence.Mode.Expression:
|
||||||
|
{
|
||||||
|
// 执行表达式
|
||||||
|
parser.Evaluate(sentence.content);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RScriptSentence.Mode.DefineVariable:
|
||||||
|
{
|
||||||
|
DoDefineVariable(parser, sentence);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RScriptSentence.Mode.EnterNamespace:
|
||||||
|
{
|
||||||
|
DoEnterNamespace(parser);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RScriptSentence.Mode.ExitNamespace:
|
||||||
|
{
|
||||||
|
DoExitNamespace(parser);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RScriptSentence.Mode.Goto:
|
||||||
|
{
|
||||||
|
DoGoto(parser, sentence);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RScriptSentence.Mode.Breakpoint:
|
||||||
|
{
|
||||||
|
DoBreakpoint(parser,sentence);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RScriptSentence.Mode.Backpoint:
|
||||||
|
{
|
||||||
|
DoBackpoint(parser, sentence);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Do nothing
|
// Do nothing
|
||||||
@@ -260,6 +318,7 @@ namespace Convention.RScript
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly Stack<int> RuntimePointerStack = new();
|
private readonly Stack<int> RuntimePointerStack = new();
|
||||||
|
private readonly Stack<int> GotoPointerStack = new();
|
||||||
private int CurrentRuntimePointer = 0;
|
private int CurrentRuntimePointer = 0;
|
||||||
private readonly Stack<HashSet<string>> CurrentLocalSpaceVariableNames = new();
|
private readonly Stack<HashSet<string>> CurrentLocalSpaceVariableNames = new();
|
||||||
|
|
||||||
@@ -267,6 +326,7 @@ namespace Convention.RScript
|
|||||||
{
|
{
|
||||||
CurrentLocalSpaceVariableNames.Clear();
|
CurrentLocalSpaceVariableNames.Clear();
|
||||||
RuntimePointerStack.Clear();
|
RuntimePointerStack.Clear();
|
||||||
|
GotoPointerStack.Clear();
|
||||||
CurrentLocalSpaceVariableNames.Clear();
|
CurrentLocalSpaceVariableNames.Clear();
|
||||||
CurrentLocalSpaceVariableNames.Push(new());
|
CurrentLocalSpaceVariableNames.Push(new());
|
||||||
for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++)
|
for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++)
|
||||||
|
@@ -16,11 +16,21 @@ double i;
|
|||||||
i = 2.0;
|
i = 2.0;
|
||||||
{
|
{
|
||||||
label(test);
|
label(test);
|
||||||
i = Pow(i,2.0);
|
goto(true,func1);
|
||||||
goto(100,i,test);
|
goto(100>i,test);
|
||||||
}
|
}
|
||||||
string result;
|
double result;
|
||||||
result = i.ToString()+i.ToString();
|
result = i;
|
||||||
|
|
||||||
|
goto(true,end);
|
||||||
|
|
||||||
|
{
|
||||||
|
label(func1);
|
||||||
|
i = Pow(i,2.0);
|
||||||
|
back(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
label(end);
|
||||||
", import);
|
", import);
|
||||||
Console.WriteLine($"Script executed successfully. Result: {result["result"].data}");
|
Console.WriteLine($"Script executed successfully. Result: {result["result"].data}");
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user