Как я могу создать интерактивный парсер с ANTLR?

Я смотрел на Java и ANTRL4, очень хорошая комбинация для создания парсеров. Однако, тестируя их, я заметил, что синтаксический анализ не начинается, пока я не отправлю на вход EOF (например, CMD-D на Mac). Это нормально для анализа файла, но я могу легко представить, как очень быстро создавать инструменты, такие как оболочки / процессоры командной строки, с помощью ANTLR. Но это невыполнимо, если я не могу заставить его анализировать по мере ввода символов (чтобы что-то происходило после RETURN или даже после TAB, если, скажем, нужно выполнить завершение команды).

Кто-нибудь знает, как это сделать?


person David    schedule 09.09.2015    source источник
comment
Можете ли вы опубликовать код?   -  person Andy Turner    schedule 10.09.2015


Ответы (1)


Самый простой способ использовать Antlr4 «в интерактивном режиме» — признать, что операция синтаксического анализа выполняется довольно быстро и что в «теплой» виртуальной машине повторное создание экземпляра синтаксического анализатора также выполняется довольно быстро. Действительно, более чем достаточно быстро, чтобы повторно анализировать весь вводимый текст между каждым нажатием клавиши.

Основная стратегия заключается в том, чтобы из ключевого события получить весь текущий входной текст и обработать его в потоке без отображения. Если обработка не завершится до следующего ключевого события, отмените поток обработки и запустите новый. Когда итерация обработки завершается, установите следующее ключевое событие в буфер (при необходимости) и примените результаты к входному тексту.

Непрерывный поток нажатий клавиш вряд ли будет быстрее 100 мс на одно нажатие клавиши (около 80 слов в минуту). В моей системе повторный простой анализ «страницы» кода редактора с использованием грамматики Java.g4 занимает в среднем около 5 мс. Даже при довольно значительной обработке фоновому потоку редко требуется более 25 мс для завершения. Конечно, YMWV.

Обновить

Если требуется непрерывная обработка потока, а не «интерактивная», то Antlr можно адаптировать для этой цели. Для этого потребуется минимальный настраиваемый лексер, соответствующий интерфейсам Lexer и TokenStream, но ожидающий фактических входных данных в ответ на getCurrentToken() синтаксического анализатора — основная функция синтаксического анализатора для извлечения следующего токена из лексера.

    StreamLexer tokens = new StreamLexer(yourInputStream); // custom lexer
    YourParser parser = new YourParser(tokens);
    parser.removeErrorListeners(); // remove ConsoleErrorListener
    parser.addErrorListener(new YourErrorListener());
    parser.setErrorHandler(new YourParserErrorStrategy());
    parser.start();

Настоящей грамматики лексера не существует — пользовательский лексер просто оборачивает каждый входной символ как отдельный токен, и правила парсера записываются соответствующим образом.

По сути, это превращает стандартный анализатор Antlr в определяемый грамматикой «Push-Parser». Скорость будет ограничена временем выполнения соответствующих функций парсера или скоростью передачи данных входного потока, в зависимости от того, что медленнее.

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

person GRosenberg    schedule 10.09.2015
comment
Да, я думал о том, чтобы самому читать символы и вызывать анализатор снова и снова, но это казалось очень неуклюжим хаком. Кроме того, у меня были некоторые идеи, как использовать его для синтаксического анализа и последующего ответа на данные в реальном времени, что будет происходить намного быстрее, чем нажатия клавиш, поэтому перезапуск синтаксического анализатора здесь не сработает. Тем не менее, я читал несколько других потоков в stackoverflow, и кажется, что небуферизованный ввод на самом деле не очень хорошо поддерживается. - person David; 10.09.2015
comment
Нет нет. Это очень элегантный хак. В любом случае, ответ обновлен. - person GRosenberg; 10.09.2015