Книга рассказывает о том, как разрабатывать уникальные языки программирования, чтобы сократить время и стоимость создания приложений для новых или специализированных областей применения вычислительной техники. Вы начнете с реализации интерфейса компилятора для вашего языка, включая лексический и синтаксический анализатор, а к концу чтения сможете разрабатывать и воплощать в коде свои собственные языки, позволяющие компилировать и запускать программы.
Издание адресовано разработчикам программного обеспечения, заинтересованным в создании собственного языка. Для изучения материала потребуется опыт программирования на языке высокого уровня, таком как Java или C++.
Author(s): Клинтон Л. Джеффери
Edition: 1
Publisher: ДМК Пресс
Year: 2022
Language: Russian
Commentary: Publisher's PDF
Pages: 408
City: М.
Tags: Syntactic Analysis; Domain-Specific Languages; Code Generation; Compilers; Lexical Analysis; Translators; Garbage Collection; Syntax Trees
Об авторах
О рецензентах
Предисловие
Для кого эта книга
Что скрывает обложка
Как получить от этой книги максимальную пользу
Загрузка примеров
Видео
Цветные иллюстрации
Используемые сокращения
Список опечаток
Нарушение авторских прав
Часть I
Интерфейсы языка программирования
Глава 1
Зачем создавать еще один язык программирования?
Итак, вы хотите создать свой собственный язык программирования...
Типы реализации языков программирования
Организация реализации языка байт-кода
Языки, используемые в примерах
Язык и библиотека – в чем разница?
Применимость к другим задачам разработки программного обеспечения
Определение требований к вашему языку
Тематическое исследование – требования, которые вдохновили на создание языка Unicon
Требование Unicon № 1 – сохранять то, что люди любят в Icon
Требование Unicon № 2 – поддержка крупномасштабных программ, работающих с большими данными
Требование Unicon № 3 – высокоуровневый ввод/вывод для современных приложений
Требование Unicon № 4 – обеспечить универсально реализуемые системные интерфейсы
Заключение
Вопросы
Глава 2
Дизайн языка программирования
Определение видов слов и пунктуации в вашем языке
Определение потока управления
Решение о том, какие типы данных поддерживать
Атомарные типы
Составные типы
Типы, специфичные для конкретной области
Общая структура программы
Завершение определения языка Jzero
Тематическое исследование – проектирование графических объектов в Unicon
Поддержка языка для графики 2D
Добавление поддержки трехмерной графики
Заключение
Вопросы
Глава 3
Сканирование исходного кода
Технические требования
Лексемы, лексические категории и токены
Регулярные выражения
Правила регулярных выражений
Примеры регулярных выражений
Использование UFlex и JFlex
Раздел заголовка
Раздел регулярных выражений
Написание простого сканера исходного кода
Запуск сканера
Токены и лексические атрибуты
Расширение нашего примера для построения токенов
Написание сканера для Jzero
Спецификация Jzero flex
Код Unicon Jzero
Код Java Jzero
Запуск сканера Jzero
Заключение
Вопросы
Глава 4
Вопросы
Заключение
Улучшение сообщений об ошибках синтаксиса
Добавление деталей в сообщения Unicon об ошибках синтаксиса
Добавление деталей в сообщения Java об ошибках синтаксиса
Использование Merr для создания лучших сообщений об ошибках синтаксиса
Запуск парсера Jzero
Код парсера Jzero на языке Java
Код Unicon Jzero
Спецификация yacc в Jzero
Спецификация Jzero lex
Составление раздела бесконтекстной грамматики yacc
Глава 5
Деревья синтаксиса
Технические требования
Использование GNU make
Изучение деревьев
Определение типа дерева синтаксиса
Деревья разбора в сравнении с деревьями синтаксиса
Создание листьев из терминальных символов
Обертывание токенов в листья
Работа со стеком значений YACC
Обертка листьев для стека значений парсера
Определение нужных вам листьев
Построение внутренних узлов из правил производства
Доступ к узлам дерева в стеке значений
Использование фабричного метода узла дерева
Формирование деревьев синтаксиса для языка Jzero
Отладка и тестирование вашего дерева синтаксиса
Предотвращение распространенных ошибок в дереве синтаксиса
Распечатка вашего дерева в текстовом формате
Печать дерева с помощью dot
Заключение
Вопросы
Часть II
Обходы дерева синтаксиса
Глава 6
Таблицы символов
Технические требования
Создание основы для таблиц символов
Объявления и области видимости
Присваивание и разыменование переменных
Выбор подходящего обхода дерева для работы
Создание и заполнение таблиц символов для каждой области видимости
Добавление семантических атрибутов к деревьям синтаксиса
Определение классов для таблиц символов и записей в таблицах символов
Создание таблиц символов
Заполнение таблиц символов
Синтез атрибута isConst
Проверка наличия необъявленных переменных
Идентификация тел методов
Выявление использования переменных в теле метода
Поиск повторно объявленных переменных
Вставка символов в таблицу символов
Сообщение о семантических ошибках
Обработка пакетов и областей видимости классов в Unicon
Искажение имен
Вставка self для ссылок на переменные-члены
Вставка self в качестве первого параметра в вызовы методов
Тестирование и отладка таблиц символов
Заключение
Вопросы
Глава 7
Проверка базовых типов
Технические требования
Представление типов в компиляторе
Определение базового класса для представления типов
Подклассификация базового класса для сложных типов
Присвоение информации о типе объявленным переменным
Синтез типов из зарезервированных слов
Наследование типов в списке переменных
Определение типа в каждом узле дерева синтаксиса
Определение типа в листьях
Вычисление и проверка типов во внутренних узлах
Проверка типов во время выполнения и вывод типов в Unicon
Заключение
Вопросы
Глава 8
Проверка типов в массивах, вызовах методов и доступах к структурам
Технические требования
Операции проверки типов массивов
Управление объявлениями переменных в массивах
Проверка типов при создании массива
Проверка типов при обращении к массиву
Проверка вызовов методов
Вычисление параметров и информации о возвращаемом типе
Проверка типов в каждом месте вызова метода
Проверка типов в операторах возврата
Проверка обращений к структурированным типам
Обработка объявлений переменных экземпляра
Проверка типов при создании экземпляра
Проверка типов при обращении к экземпляру
Заключение
Вопросы
Глава 9
Генерация промежуточного кода
Технические требования
Подготовка к генерации кода
Зачем генерировать промежуточный код?
Изучение областей памяти в созданной программе
Представление типов данных для промежуточного кода
Добавление атрибутов промежуточного кода в дерево
Генерация меток и временных переменных
Набор инструкций промежуточного кода
Инструкции
Декларации
Аннотирование деревьев синтаксиса метками для потока управления
Генерация кода для выражений
Генерация кода для потока управления
Генерация целевых меток для выражений условий
Генерация кода для циклов
Генерация промежуточного кода для вызовов методов
Проверка сгенерированного промежуточного кода
Заключение
Глава 10
Раскраска синтаксиса в IDE
Загрузка примеров IDE, используемых в этой главе
Интеграция компилятора в редактор программиста
Анализ исходного кода из среды IDE
Отправка выходных данных компилятора в IDE
Предотвращение повторного разбора всего файла при каждом изменении
Использование лексической информации для раскрашивания токенов
Расширение компонента EditableTextList для поддержки цвета
Раскрашивание отдельных токенов по мере их создания
Подсветка ошибок с использованием результатов разбора
Добавление поддержки Java
Заключение
Часть III
Генерация кода и среды выполнения
Глава 11
Интерпретаторы байт-кода
Технические требования
Понимание, что такое байт-код
Сравнение байт-кода с промежуточным кодом
Построение набора инструкций байт-кода для Jzero
Определение формата файла байт-кода Jzero
Понимание основ работы стековой машины
Реализация интерпретатора байт-кода
Загрузка байт-кода в память
Инициализация состояния интерпретатора
Выборка инструкций и продвижение указателя инструкции
Декодирование инструкций
Выполнение инструкций
Запуск интерпретатора Jzero
Написание среды выполнения для Jzero
Запуск программы Jzero
Изучение iconx, интерпретатора байт-кода Unicon
Понимание целенаправленного байт-кода
Сохранение информации о типе во время выполнения
Выборка, декодирование и выполнение инструкций
Создание остальной части среды выполнения
Заключение
Вопросы
Глава 12
Генерация байт-кода
Технические требования
Преобразование промежуточного кода в байт-код Jzero
Добавление класса для инструкций байт-кода
Соответствие адресов промежуточного кода адресам байт-кода
Реализация метода генератора байт-кода
Генерация байт-кода для простых выражений
Генерация кода для обработки указателей
Генерация байт-кода для безусловных и условных переходов
Генерация кода для вызовов методов и возвратов
Обработка меток и других псевдоинструкций промежуточного кода
Сравнение ассемблера байт-кода с двоичными форматами
Вывод байт-кода в формате ассемблера
Вывод байт-кода в двоичном формате
Линковка, загрузка и включение среды выполнения
Пример Unicon – генерация байт-кода в icont
Заключение
Вопросы
Глава 13
Генерация собственного кода
Технические требования
Принятие решения о генерации собственного кода
Знакомство с набором инструкций x64
Добавление класса для инструкций x64
Соответствие областей памяти регистровым режимам адресации x64
Использование регистров
Начинаем с нулевой стратегии
Преобразование промежуточного кода в код x64
Соответствие адресов промежуточного кода местоположению в x64
Реализация метода генератора кода x64
Генерация кода x64 для простых выражений
Генерация кода для обработки указателей
Генерация собственного кода для безусловных и условных переходов
Генерация кода для вызовов методов и возвратов
Обработка меток и псевдоинструкций
Генерация выходных данных x64
Запись кода x64 в формате ассемблера
Переход от ассемблера к объектному файлу
Линковка, загрузка и включение среды выполнения
Заключение
Вопросы
Глава 14
Реализация операторов и встроенных функций
Реализация операторов
Подразумевают ли операторы аппаратную поддержку, и наоборот
Добавление конкатенации строк в генерацию промежуточного кода
Добавление конкатенации строк в интерпретатор байт-кода
Добавление конкатенации строк в собственную среду выполнения
Написание встроенных функций
Добавление встроенных функций в интерпретатор байт-кода
Написание встроенных функций для использования в реализации собственного кода
Интеграция встроенных функций со структурами управления
Разработка операторов и функций для Unicon
Написание операторов в Unicon
Разработка встроенных функций Unicon
Заключение
Вопросы
Глава 15
Структуры управления доменами
Понимание необходимости новой структуры управления
Определение структуры управления
Устранение избыточных параметров
Сканирование строк в Icon и Unicon
Среды сканирования и их примитивные операции
Устранение избыточных параметров с помощью структуры управления
Рендеринг областей в Unicon
Отображение 3D-графики из списка отображения
Указание областей рендеринга с помощью встроенных функций
Изменение графических уровней детализации с помощью вложенного рендеринга областей
Создание структуры управления рендерингом областей
Добавление зарезервированного слова для рендеринга областей
Добавление правила грамматики
Проверка wsection на семантические ошибки
Генерация кода для структуры управления wsection
Заключение
Вопросы
Глава 16
Сборка мусора
Оценка важности сборки мусора
Подсчет ссылок на объекты
Добавление подсчета ссылок в Jzero
Генерация кода для распределения кучи
Изменение сгенерированного кода для оператора присваивания
Учет недостатков и ограничений, связанных с подсчетом ссылок
Пометка реальных данных и очистка остальных
Организация областей памяти кучи
Обход базиса для пометки живых данных
Восстановление живой памяти и размещение ее в непрерывных фрагментах
Заключение
Вопросы
Глава 17
Заключительные размышления
Размышления о том, что изучено при написании этой книги
Решение о том, куда двигаться дальше
Изучение дизайна языков программирования
Изучение реализации интерпретаторов и машин байт-кода
Приобретение опыта в оптимизации кода
Мониторинг и отладка выполнения программ
Проектирование и реализация IDE и построителей GUI
Изучение ссылок для дальнейшего чтения
Изучение дизайна языков программирования
Изучение реализации интерпретаторов и машин байт-кода
Приобретение опыта работы с собственным кодом и оптимизации кода
Мониторинг и отладка выполнения программ
Проектирование и реализация IDE и построителей GUI
Заключение
Часть IV
Приложение
Приложение
Основы Unicon
Запуск Unicon
Использование объявлений и типов данных Unicon
Объявление различных типов компонентов программы
Использование атомарных типов данных
Организация нескольких значений с помощью структурных типов
Оценка выражений
Формирование базовых выражений с помощью операторов
Вызов процедур, функций и методов
Итерации и выбор того, что и как выполнять
Генераторы
Отладка и вопросы окружения
Изучение основ отладчика UDB
Переменные окружения
Препроцессор
Мини-справочник функций
Избранные ключевые слова
Оценки
Глава 1
Глава 2
Глава 3
Глава 4
Глава 5
Глава 6
Глава 7
Глава 8
Глава 11
Глава 12
Глава 13
Глава 14
Глава 16