Как остановить ANTLR от подавления синтаксических ошибок?

Поэтому я пишу компилятор на Java с использованием ANTLR, и я немного озадачен тем, как он работает с ошибками.

Поведение по умолчанию, по-видимому, состоит в том, чтобы напечатать сообщение об ошибке, а затем попытаться с помощью вставки токена и т. Д. Восстановиться после ошибки и продолжить анализ. Мне нравится это в принципе; это означает, что (в лучшем случае), если пользователь допустил более одной синтаксической ошибки, он получит одно сообщение на ошибку, но в нем будут указаны все ошибки, вместо того, чтобы заставлять их перекомпилировать для обнаружения следующей. Сообщение об ошибке по умолчанию подходит для моих целей. Беда в том, что все токены закончились.

Я, конечно, использую конструкторы дерева ANTLR для построения абстрактных синтаксических деревьев. Хотя синтаксический анализ может продолжаться через синтаксические ошибки, чтобы пользователь мог видеть все ошибки, после завершения синтаксического анализа я хочу получить исключение или какое-либо указание на то, что входные данные были синтаксически недействительными; таким образом я могу остановить компиляцию и сказать пользователю "извините, исправьте ваши синтаксические ошибки и попробуйте снова". Я не хочу, чтобы он выплевывал неполное AST на основе того, что, по его мнению, пользователь пытался сказать, и переходил к следующему этапу компиляции без указания того, что что-то пошло не так (кроме сообщений об ошибках, которые на консоль и я не вижу). И все же по умолчанию это именно так.

Определяющая ссылка ANTLR предлагает метод, позволяющий остановить синтаксический анализ при обнаружении синтаксической ошибки: переопределить mismatch а также recoverFromMismatchedSet методы бросить RecognitionExceptionи добавить @rulecatch действие, чтобы сделать то же самое. Казалось бы, это теряет преимущество восстановления после ошибок разбора, но, что более важно, это работает только частично. Если необходимый токен отсутствует (например, если бинарный оператор имеет выражение только с одной стороны от него), он генерирует исключение, как и ожидалось, но если добавляется посторонний токен, ANTLR вставляет токен, который, по его мнению, принадлежит ему и продолжает свой веселый путь, производя AST без указания синтаксической ошибки, кроме сообщения консоли. (Что еще хуже, вставленный токен был EOF, так что остальная часть файла даже не была проанализирована.)

Я уверен, что мог бы это исправить, скажем, добавив что-то вроде isValid поле для синтаксического анализатора и переопределение методов и добавление действий, чтобы в конце анализа он выдавал исключение, если были какие-либо ошибки. Но есть ли лучший способ? Я не могу себе представить, что то, что я пытаюсь сделать, является необычным для пользователей ANTLR.

1 ответ

Решение

... [o] После того как он завершен, я хочу получить исключение или какое-то указание на то, что входные данные не были синтаксически допустимыми; таким образом я могу остановить компиляцию...

Ты можешь позвонить getNumberOfSyntaxErrors как на лексере, так и на синтаксическом анализаторе после синтаксического анализа, чтобы определить, была ли ошибка, которая была скрытно учтена ANTLR. Очевидно, это не говорит о том, что это были за ошибки, но я думаю, что эти методы обращаются к части вашего вопроса "как только анализ завершится... остановите компиляцию".

Ссылка Definitive ANTLR предлагает метод, позволяющий прекратить синтаксический анализ при обнаружении синтаксической ошибки: переопределить методы несоответствия и recoverFromMismatchedSet, чтобы вызвать исключения RecognitionExceptions, и добавить действие @rulecatch, чтобы сделать то же самое.

Я не думаю, что вы упомянули, какую версию ANTLR вы используете, но документация в коде ANTLR v3.4 для метода recoverFromMismatchedSet говорит, что это "в настоящее время не используется", и сканирование "глобального использования" Eclipse не нашло абонентов. Ни здесь, ни там нет вашей главной проблемы, но я хотел упомянуть об этом для записи. Это может быть правильный метод для переопределения для вашей версии.

Если необходимый токен отсутствует... [переопределенный код] выдает исключение, как и ожидалось, но если добавляется посторонний токен, ANTLR вставляет токен, который, по его мнению, принадлежит ему, и продолжает свой веселый путь...

метод recoverFromMismatchedToken тесты для восстановления отсутствующего и постороннего токена путем делегирования методам mismatchIsMissingToken а также mismatchIsUnwantedToken соответственно. Если соответствующий метод определяет, что вставка или удаление решит проблему, recoverFromMismatchedToken делает соответствующую коррекцию. Если определено, что ни одна операция не решает проблему несоответствующего токена, recoverFromMismatchedToken бросает MismatchedTokenException,

Если операция восстановления имеет место, reportError называется, который вызывает displayRecognitionError с деталями.

Это относится к ANTLR v3.4 и, возможно, более ранним версиям.

Это дает вам как минимум два варианта:

  • Override recoverFromMismatchedToken и обрабатывать ошибки на детальном уровне. Отсюда вы можете делегировать вызов супер реализации, развернуть свой собственный код восстановления или выручить за исключением. В любом случае, ваш код будет вызван и, следовательно, будет знать, что произошла ошибка несоответствия, исправляемая или нет. Эта опция, вероятно, эквивалентна переопределению recoverFromMismatchedSet,

  • Override displayRecognitionError и обрабатывать ошибки на уровне курса. метод reportError выполняет некоторое жонглирование состояния, поэтому я бы не рекомендовал переопределять его, если только переопределенная реализация не вызывает супер-реализацию. метод displayRecognitionError представляется одним из последних вызовов в цепочке вызовов восстановленных токенов, поэтому было бы разумно определить, продолжать или нет. Я бы предпочел, чтобы у него было название, которое указывало, что это было разумное место для этого, ну да ладно. Вот ответ, который демонстрирует эту опцию.

Я неравнодушен к переопределению displayRecognitionError потому что он предоставляет текст сообщения об ошибке достаточно легко, и потому что я знаю, что он будет вызываться только после операции восстановления токена и необходимости жонглирования состояния - моему анализатору не нужно выяснять, как восстанавливать себя. Это в сочетании с getNumberOfSyntaxErrors кажется, чтобы дать вам варианты, которые вы ищете, предполагая, что вы работаете с соответствующей версией ANTLR и что я полностью понял вашу проблему.

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