Разбор простой текстовой грамматики с Superpower

Я пытаюсь создать парсер с Superpower. Я уже посмотрел образцы, которые я нашел в репо, но их немного сложно понять, по крайней мере, для такого начинающего, как я:) Так что я пришел с этим небольшим испытанием.

Я изобрел очень простую грамматику, чтобы учиться. Я думал о лифте, который следует за списком инструкций, чтобы подняться, спуститься и ждать.

Пример:

(UP 100),
(DOWN 200),
(DOWN 100),
(DOWN @1),
(UP @3),
(WAIT),
(UP 300)

Как видите, он состоит из списка разделенных запятыми глаголов для перемещения, например, лифта.

  • Глаголы UP, DOWN или WAIT.
  • Каждый глагол заключен в круглые скобки: ()
  • ВВЕРХ и ВНИЗ требуется либо абсолютное число, либо относительное число, которое указывает этаж, на который должен подняться лифт. Относительные номера этажа идут со знаком @ перед номером.
  • ПОДОЖДИТЕ не принимает никакого числа, потому что останавливает лифт на некоторое время.

Я действительно хотел бы узнать, как создать синтаксический анализатор на основе токенов для этой грамматики, чтобы понять, как использовать SuperPower.

Кто-нибудь может помочь мне с этим?

Заранее спасибо!

2 ответа

Решение

Шаг 1 написания любого парсера Superpower состоит в том, чтобы выяснить, что такое токены. У вас есть что-то вроде:

// ECL - Elevator Control Language ;-)
enum EclToken {
    LParen,
    RParen,
    UpKeyword,
    DownKeyword,
    WaitKeyword,
    AtSymbol,
    Number,
    Comma
}

Шаг 2, напишите Tokenizer<EclToken>, Superpower v1 оставляет это как прямую задачу программирования - помощников не так много, нужно просто написать код, как в примерах.

Токенайзер берет входную строку, удаляет пробелы и выясняет, какова последовательность токенов.

Для вашего примера ввода первая строка будет:

// (UP 100),
LParen, UpKeyword, Number, RParen, Comma

Для токенов типа Number которые содержат контент, диапазон, связанный с Result<EclToken> будет указывать на часть входной строки, соответствующую токену. В этой строке число будет TextSpan покрытие 100,

Шаг 3 - выяснить, во что вы хотите разобрать входные данные. Для языков программирования с вложенными выражениями это обычно AST. В случае с примером ECL все довольно просто, поэтому вы можете сократить его до:

struct ElevatorCommand {        
    public int Distance; // + or -
    public bool IsRelative;
}

Шаг 4, парсер. Обычно это встроено в статический класс. Работа парсера заключается в создании более сложных результатов (ElevatorCommand[] здесь), из более простых результатов (число, движение).

Именно здесь Superpower делает тяжелую работу, особенно в отношении ожиданий и ошибок.

static class EclParser 
{
    static TokenListParser<EclToken, int> Number =
        Token.EqualTo(EclToken.Number).Apply(Numerics.IntegerInt32);
}

Первое, что мы делаем, это определяем парсер для чисел; этот применяет встроенный TextParser<int> к содержанию EclToken.Number пяди.

В этом примере вы можете увидеть больше машин для разбора.

Еще несколько подсказок, которые помогут вам найти способ (не проверенный синтаксис, не говоря уже о скомпилированном / протестированном):

    static TokenListParser<EclToken, ElevatorCommand> Up =
        from _ in Token.EqualTo(EclToken.UpKeyword)
        from distance in Number
        select new ElevatorCommand {
            Distance = distance,
            IsRelative = false
        };

    static TokenListParser<EclToken, ElevatorCommand> Command =
        from lp in Token.EqualTo(EclToken.LParen)
        from command in Up // .Or(Down).Or(Wait)
        from rp in Token.EqualTo(EclToken.RParen)
        select command;

    static TokenListParser<EclToken, ElevatorCommand[]> Commands =
        Command.ManyDelimitedBy(Token.EqualTo(EclToken.Comma));
}

Commands является законченным парсером, который вы можете применить для ввода.

Лучше всего создавать синтаксический анализатор постепенно, тестируя каждый меньший анализатор на порциях ввода, которые они должны анализировать.

Хорошо, я наконец-то получил это. Это было не так сложно с руководством @Nicholas Blumhardt:)

Я создал проект в GitHub, чтобы проиллюстрировать сценарий. Так как классы большие для поста, я делаю ссылки на файлы:

Другие вопросы по тегам