【问题标题】:How to implement a parser/interpreter using a list of predefined tokens?如何使用预定义令牌列表实现解析器/解释器?
【发布时间】:2020-08-04 22:36:04
【问题描述】:

我有这段代码可以根据与正则表达式匹配的内容生成字符串形式的标记:

public static List<Tuple<string, string>> GetTokens(string input)
    {
        List<Tuple<string, string>> ret = new List<Tuple<string, string>>();
        Regex r = new Regex("(?<Comma>\\,)" +
            "|(?<Dot>\\.)" +
            "|(?<SemiColon>\\;)" +
            "|(?<DoubleDot>\\:)" +
            "|(?<Increment>\\+\\+)" +
            "|(?<greater>\\>)" +
            "|(?<smaller>\\<)" +
            "|(?<Decrement>\\-\\-)" +
            "|(?<SystemCommand> *deviceListCount *| *deviceList *| *devices *| *device *| *str *| *int *| *dev *| *bool *| *print *| *wait *| *device *| *if *| *while *| *loop *)" +
            "|(?<OpenBracket>\\()" +
            "|(?<CloseBracket>\\))" +                
            "|(?<DeviceCommand> *On *| *Off *| *Open *| *Close *| *Move *| *Detect *)" +
            "|(?<Integer>\\d+)"+
            "|(?<equals> *[=] *)" +                
            "|(?<String>[aA-zZ0-9 ]*)");
        foreach (Match item in r.Matches(input))
        {
            for (int i = 1; i < item.Groups.Count; i++)
            {
                string v = item.Groups[i].Value;
                if (v != "")
                {
                    ret.Add(new Tuple<string, string>(r.GroupNameFromNumber(i), v));
                }
            }
        }
        return ret;
    }

简单来说,如何使用上面的方法创建打印命令:

print(hello world)

我想用这样的方式运行代码:

RunCode(GetTokens("print(Hello World)"))

这段代码应该产生与以下相同的效果:

Console.WriteLine("Hello World");

【问题讨论】:

  • 正则表达式只能是非常简单的构造。如果您了解上面发布的正则表达式,我会说您对它很好。要真正实现解析器,您需要了解 EBNF 语法。它们与正则表达式类似,但更强大。例如here 是一种非常简单的语言,称为 Lua。
  • 你能告诉我们你为什么要参加这个旅程吗?这纯粹是为了教育和爱好,还是出于专业目的需要它?如果爱好/教育那么欢迎。如果在工作中实际使用,那么你最好使用一些现成的东西。这条路将带您踏上几个月的旅程,然后才能真正开始工作。很抱歉让您失望了。但是解析器生成是计算机世界最臭名昭著的方面之一。
  • 我是一名有抱负的游戏开发人员,也是一名软件开发学生(二年级),大约 6 个月前我开始使用 unity,最近玩了一款名为“Else Heart.Break()”的游戏,它真的让我对制作一款黑客游戏产生了兴趣,您可以在其中潜入开放世界并破解各种系统/设备以访问地点等,
  • 我尝试使用正则表达式和非常基本的命令来实现自定义游戏内解释器,但我真的很喜欢编译器/解释器,以及如何真正为游戏和许多人制作动态且易于使用的语言对于现实世界的使用,我看到了一些关于 Lexers 和 Abstract tree Parsers 的文档和文章,但我无法很好地掌握它们如何相互作用以及如何正确实现它。抱歉重复评论,前半部分没有足够的字符。

标签: c# parsing console-application


【解决方案1】:

编辑更新! 我想我找到了一种方法。我使用以下两种方法创建了一种方法: 首先,此方法寻找并返回嵌套字符串以用于循环/while 循环和 if 语句:

public static string UntilNestedEnd(List<Tuple<string, string>> t, ref int i)
        {            
            string inner = "";
            int nested = 0;
            while (true)
            {
                if (i < t.Count-1)
                {
                    i++;
                    if (t[i].Item2 == ")")
                    {
                        nested--;
                        if (nested > 0)
                        {
                            inner += t[i].Item2;
                        }
                    }
                    else if (t[i].Item2 == "(")
                    {
                        if (nested > 0)
                        {
                            inner += t[i].Item2;
                        }
                        nested++;
                    }
                    else
                    {
                        inner += t[i].Item2;
                    }
                    if (nested == 0)
                    {
                        break;
                    }                    
                }
            }
            return inner;
        }

这是可以执行命令的代码,我所要做的就是说明在检索字符串之前它应该向前跳过多少步,它导致嵌套语句似乎有效,到目前为止我只有 2 个命令“打印”和“循环”的那一刻:

public static void RunCode(string input)
        {
            var g = GetTokens(input);
            for (int i = 0; i < g.Count; i++)
            {
                if (g[i].Item2 == "print")
                {
                    Console.WriteLine(UntilNestedEnd(g, ref i));
                }
                else if (g[i].Item2 == "loop")
                {
                    int cnt = int.Parse(g[i+2].Item2);
                    i +=2;
                    string nested = UntilNestedEnd(g,ref i);                    
                    for (int x = 0; x < cnt; x++)
                    {
                        RunCode(nested);
                    }
                }
            }
        }

这是运行它的代码:

static void Main(string[] args)
        {
            RunCode("loop:2(loop:2(loop:2(print(hello))))");
            Console.ReadLine();
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-25
    • 2018-08-29
    • 2012-10-09
    • 1970-01-01
    • 1970-01-01
    • 2021-04-24
    相关资源
    最近更新 更多