Обработка ошибок и проектирование компилятора
Перевод статьи Error Handling in Compiler Designopen in new window.
Задача по обработке ошибок (Error Handling) включает в себя: обнаружение ошибок, сообщения об ошибках пользователю, создание стратегии восстановления и реализации обработки ошибок. Кроме того система обработки ошибок должна работать быстро.
Типы источников ошибок
Источники ошибок делятся на два типа: ошибки времени выполнения (run-time error) и ошибки времени компиляции (compile-time error).
Ошибки времени выполнения возникают когда программа запущена. Обычно они связаны с неверными входными данными. Примеры таких ошибок: недостаток памяти, конфликт с другим приложением, логические ошибки. Логическая ошибка означает что запуск программы не приводит к ожидаемому результату. Логические ошибки лучше всего обрабатывать тщательным тестированием и отладкой программы.
Ошибки времени компиляции возникают во время компиляции, до запуска программы. Примеры таких ошибок: синтаксическая ошибка или отсутствие файла с кодом на который есть ссылка.
Типы ошибок времени компиляции
Ошибки компиляции разделяются на:
- Лексические (Lexical): включают в себя опечатки идентификаторов, ключевых слов и операторов
- Синтаксические (Syntactical): пропущенная точка с запятой или незакрытая скобка
- Семантические (Semantical): несовместимое значение при присвоении или несовпадение типов между оператором и операндом
- Логические (Logical): недостижимый код, бесконечный цикл
Парсер, обрабатывая текст, пытается как можно раньше обнаружить ошибку. В современных средах разработки синтаксические ошибки отображаются прямо в редакторе кода, предотвращая последующий неверный ввод. Обнажение ошибки происходит когда введённый префикс не совпадает с префиксами строк верными в выбранном языке программирования. Например префикс for(;)
может привести к сообщению об ошибке, так как обычно внутри for
должно быть две точки с запятой.
Восстановление после ошибок
Базовое требование к компилятору — прервать компиляцию и выдать сообщение при появлении ошибки. Кроме этого есть несколько методов восстановления после ошибки.
Panic mode recovery
Это самый простой способ восстановления после ошибок и он предотвращает бесконечные циклы в компиляторе при попытках исправить ошибку. Парсер отклоняет следующие за ошибкой символы до того как будет обнаружен специальный символ (например, разделитель команд, точка с запятой). Такой подход адекватен если низкая вероятность нескольких ошибок в одной конструкции.
Пример: рассмотрим выражение с ошибкой (1 + + 2) + 3
. При обнаружении второго +
пропускаются все символы до следующего числа.
Phase level recovery
Производится локальное изменение входного потока чтобы исправить ошибку.
Error productions
Разработчики компиляторов знают часто встречаемые ошибки. При появлении таких ошибок могут применяться расширения грамматики для их обработки. Например: написание 5x
вместо 5*x
.
Global correction
Производится как можно меньше изменений чтобы преобразовать код с ошибкой в корректный код. Эту стратегию дорого реализовывать.