2

我正在用 C# 编写一个非常简单的脚本解释器。该语言中没有If/Else语句或用户可编程子程序;唯一的控制流是goto关键字。

如果我使用foreach循环逐行解析脚本,如何使程序“跳转”到GoTo()块中参数指定的行号?

static void Main(string[] args)
{
    string testLines = "SomeCommand(34,32)\n" +
    "SomeCommand(1)\n" +
    "GoTo(5)\n" +
    "This(\"Will\",\"Be\",\"Skipped\")\n" +
    "Destination(\"OfTheGoToKeyWord\")";
    Regex r = new Regex("^(?<cmd>\\w+)[(](?<params>\\S+)[)]", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
    string[] lines = testLines.Split('\n');
    foreach (string line in lines)
    {
        try
        {
            string[] matches = r.Split(line);
            if (matches[1].Equals("GoTo"))
            {
                GoToLineSpecifiedByMatchesElement2();
            }
        }
        catch (Exception)
        {

        }
    }
}
4

3 回答 3

6

您将无法为此使用 foreach 。您将需要一个while循环并按索引跳转。

看起来这可能只是你想做的事情的冰山一角。如果是这样,您将很快超越正则表达式。阅读编译器设计,特别是如何分离词法、句法和语义阶段,以及如何重用可以在每个步骤中为您提供帮助的现有工具。

在我看来,在阅读了一些内容之后,您可能会很快理解为什么您当前的方法可能还不够,而且成熟的编译器也可能是矫枉过正。在这种情况下,.Net 内置了一些很好的特性来帮助定义所谓的“领域特定语言”,这可能正是您所需要的。

于 2013-03-04T18:26:25.243 回答
3

改用while循环:

    private static void Main(string[] args)
    {
        string testLines = "SomeCommand(34,32)\n" +
                           "SomeCommand(1)\n" +
                           "GoTo(5)\n" +
                           "This(\"Will\",\"Be\",\"Skipped\")\n" +
                           "Destination(\"OfTheGoToKeyWord\")";
        Regex r = new Regex(
            "^(?<cmd>\\w+)[(](?<params>\\S+)[)]", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);

        List<string> lines = testLines.Split('\n').ToList();
        int i = 0;

        while (i < lines.Count)
        {
            try
            {
                var input = lines[i];
                var matches = r.Split(input);
                if (matches[1].Equals("GoTo"))
                {
                    i = testLines.IndexOf(input);
                }
                else
                {
                    i++;
                }
            }
            catch (Exception)
            {

            }
        }
于 2013-03-04T18:35:56.223 回答
2

使用 for 循环。该变量i可以跟踪您当前的行,您可以在循环内更改它,模拟 goto。

 for (int i = 0; i < lines.Length; i++)
{
    try
    {
        string[] matches = r.Split(lines[i]);
        if (matches[1].Equals("GoTo"))
        {
            i = matches[2] - 1; // -1 because for loop will do i++
        }
    }
    catch (Exception)
    {

    }
}
于 2013-03-04T18:29:40.080 回答