Как реализовать синтаксический анализатор / интерпретатор, используя список предопределенных токенов? - PullRequest
3 голосов
/ 22 апреля 2020

У меня есть этот код, который генерирует токены в строковой форме на основе того, что сопоставляется с Regex:

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");

1 Ответ

0 голосов
/ 23 апреля 2020

Редактировать обновление! Я думаю, что нашел способ сделать это. Я создал способ сделать это, используя следующие 2 метода: во-первых, этот метод, который ищет и возвращает вложенную строку для использования в циклах / циклах и в случае статов:

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 команды 'print' и 'l oop ':

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();
        }
...