|
|||||||
Что такое фронтэнд компилятора (Compiler Frontend)
Время создания: 13.05.2021 11:08
Текстовые метки: компилятор, теория, фроинэнд, compiler, frontend
Раздел: Компьютер - Программирование - Теория программирования - Теория компиляции
Запись: xintrea/mytetra_syncro/master/base/1620893316s6l9p318sx/text.html на raw.github.com
|
|||||||
|
|||||||
Compiler Frontend — первый из двух ключевых компонентов компилятора, о котором можно сказать следующее:
Интересный факт: в интерпретаторах тоже есть Frontend, а вот Backend может не существовать — для интерпретации достаточно выполнить обход AST, последовательно вычисляя значения в нелистовых узлах. В интерпретаторах промышленного уровня качества Backend есть, и он генерирует байткод виртуальной машины. Три стадии: лексический, синтаксический, семантический анализИсходя из иерархии грамматик Хомского, языки делятся на четыре уровня. Выпишем последние три в обратном порядке:
К сожалению, все промышленные языки программирования относятся к контекстно-зависимым грамматикам. Поэтому в ход идут две хитрости: 1. из языка выделяют синтаксис (syntax) - его контекстно-свободную часть, и семантику (semantic) - дополнительные правила, которые дополняют синтаксис до полноценного языка
2. поскольку контекстно-свободная грамматика всё ещё остаётся сложной, из неё выделяют регулярную подграмматику
Разделение синтаксиса и семантики необходимо - потому что не существует эффективных алгоритмов разбора контекстно-зависимых грамматик. Разделение на синтаксический и лексический анализ не обязательно с точки зрения теории, но всегда используется на практике: это упрощает парсер грамматики, уменьшает объём работ и количество ошибок в компиляторе. Синтаксический анализСинтаксический анализ — ядро фронтенда, в самых простых языках (уровня калькулятора с переменными) это вообще единственный этап обработки текста во фронтенде. Формальный язык имеет грамматику, которая описывает файл с исходным кодом как набор рекурсивных конструкций (заданных правилами грамматики). Обычно грамматика делится на следующие уровни:
Цель синтаксического анализа - построить AST. Этой цели добиваются, соединяя парсер грамматики (grammar parser) и семантические действия (semantic actions). Лексический анализЦель лексического анализа - превратить поток символов в поток токенов (токены - это идентификаторы, литералы и так далее). В коде компилятора токен обычно представляют каким-либо value-типом, например, структурой в языке C++. Разобрать текст на токены можно с помощью ДКА (теория гласит, что это можно сделать одним проходом по строке без возвратов - и генераторы лексических анализаторов именно так и делают). Хороший класс, представляющий лексический анализатор, хранит ссылку на исходный код (в виде строки или потока) и по запросу возвращает очередной токен. Семантический анализСемантический анализ обычно реализуют как серию обходов по AST, т.е. обычных проходов по дереву с выполнением каких-либо действий в каждом узле. Реализовать каждый обход, не меняя постоянно классы AST, можно с помощью паттерна проектирования Visitor. В этом случае семантический анализ выполняется несколькими классами, каждый из которых реализует одну проверку путём обхода дерева. Набор семантических проверок может быть очень широким. Примеры:
Важная часть семантического анализа - области видимости (scopes). В современных областях области видимости обычно лексические (lexical scopes). Чтобы понять, как работают области видимости, достаточно хорошо освоить механизм замыканий (closures). Что надо знать до разработки фронтендаДля реализации фронтенда простейшего, процедурного языка понадобится:
Для реализации бекенда объектно-ориентированного языка также нужно:
Обработка ошибок во фронтендеВ пользовательском коде могут быть ошибки. Компилятор должен хорошо их обрабатывать: с ошибками компилятора программист сталкивается постоянно, и непонятные ошибки могут привести к долгим часам и даже дням, проведённым в поиске причины. Кроме того, компилятор должен сразу браковать код, нарушающий стандарт языка: если вместо ошибки компилятор сгенерирует неправильный код, отладка программы станет совершенно невыносимой. Современные компиляторы практикую восстановление после ошибок для того, чтобы пользователь мог сразу определить и исправить больше одной ошибки. Кроме того, многие современные компиляторы обслуживают задачи IDE по анализу кода. Для IDE восстановление после ошибки просто необходимо: едва ли вы обрадуетесь, если одна лишняя запятая в вашем коде напрочь уничтожит подсветку и автодополнение. Для обработки ошибочных конструкций во фронтенде есть всего несколько подходов: 1) Добавлять правила, порождающие ошибки.
2) Пропускать ввод и восстанавливаться по специальным символам и токенам
Пример кода с пропущенной кавычкой: let str = "Hello, World! alert(str); Парсер может восстанавливаться по-разному в зависимости от контекста:
|
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|