Написание простого DSL компилятора на Delphi (7. Компилятор AST)

Перевод поста Writing a Simple DSL Compiler with Delphi (7. AST Compiler).

Эта статья представляет собой описание компилятора AST используемого для проекта моего языка программирования. Если вы только начинаете читать эту серию, то я бы рекомендовал вам начать с этого поста. Как минимум вы должны прочитать предыдущий пост Intermezzo так как он разъясняет некоторые части компилятора которых я не касаюсь здесь.

В каркасе моего игрушечного компилятора, компилятор (или codegen, как он называется внутри) — часть кода которая реализует интерфейс ISimpleDSLCodegen. Этот интерфейс предоставляет только одну функцию, Generate, которая принимает абстрактное синтаксическое дерево и преобразует его в объект, который реализует интерфейс ISimpleDSLProgram, который позволяет вам вызывать любую функцию скомпилированной программы по имени.

Читать далее Написание простого DSL компилятора на Delphi (7. Компилятор AST)

Написание простого DSL компилятора на Delphi (Intermezzo)

Перевод поста Writing a Simple DSL Compiler with Delphi (Intermezzo).

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

Результатом всего этого является программа introduction.dpr, автономная программа которая содержит полностью язык (очень тривиальный) вместе с полной документацией, написанная в стиле Грамотного программирования. Упрощено — вы можете читать её сверху вниз как историю.

В качестве intermezzo и для упрощения моего объяснения компилятора, я опишу эту программу здесь полностью, отформатировав её как пост в блог.

Читать далее Написание простого DSL компилятора на Delphi (Intermezzo)

Написание простого DSL компилятора на Delphi (6. Дамп AST)

Перевод поста Writing a Simple DSL Compiler with Delphi (6. AST Dumper).

Эта статья представляет описание инструмента для тестирования моего игрушечного языка программирования. Если вы только начинаете читать эту серию, то я бы рекомендовал вам начать с этого поста.

Пожалуйста, имейте в виду, что эта статья описывают начальную реализацию парсера. Если вы хотите просматривать код во время чтения статьи, убедитесь, что вы переключились на ветку dsl_v1.

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

Тем не менее, написание модульных тестов для древовидных структур очень утомительная операция. В следующем посту я покажу тест для дерева в котором только пять листьев и это уже будет процесс который лучше пропустить. К счастью, мы можем сделать что-то более весёлое — мы можем написать код, который воссоздаст оригинальную программу из AST.

Читать далее Написание простого DSL компилятора на Delphi (6. Дамп AST)

Написание простого DSL компилятора на Delphi (5. Фреймворк)

Перевод поста Writing a Simple DSL Compiler with Delphi (5. Framework).

Эта статья представляет собой описание фреймворка используемого для проекта моего языка программирования. Если вы только начинаете читать эту серию, то я бы рекомендовал вам начать с этого поста.

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

Мой игрушечный компилятор использует очень простой фреймворк доступ к которому производится через интерфейс ISimpleDSLCompiler (модуль SimpleDSLCompiler). Уместная часть интерфейса показана ниже:

Читать далее Написание простого DSL компилятора на Delphi (5. Фреймворк)

Написание простого DSL компилятора на Delphi (4. Парсер)

Перевод поста Writing a Simple DSL Compiler with Delphi (4. Parser).

Эта статья представляет собой описание парсера используемого для моего игрушечного языка программирования. Если вы только начинаете читать эту серию, то я бы рекомендовал вам начать с этого поста.

Пожалуйста, имейте в виду, что эта статья описывают начальную реализацию парсера. Если вы хотите просматривать код во время чтения статьи, убедитесь, что вы переключились на ветку dsl_v1.

После перерыва я вернулся к серии про мой "игрушечный компилятор". Сейчас я опишу работу парсера — части кода которая читает входной поток (обычно в форме токенов) и генерирует внутреннее представление программы (в моём случае абстрактное синтаксическое дерево).

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

Мой парсер представлен как очень простой интерфейс. Он будет принимать код для разбора (как строку), ссылку на токинизатор которые должен использоваться для чтения входного потока и ссылку на корневой элемент результирующего AST. Функция вернёт False если разбор не удастся, в этом случае вызывающая сторона может преобразовать интерфейс парсера к ISimpleDSLErrorInfo для получения большей информации об ошибке.

Читать далее Написание простого DSL компилятора на Delphi (4. Парсер)

Написание простого DSL компилятора на Delphi (3. Токинезатор)

Перевод поста [Writing a Simple DSL Compiler with Delphi (3. Tokenizer])](https://www.thedelphigeek.com/2017/09/writing-simple-dsl-compiler-with-delphi.html).

Эта статья представляет собой описание токинезатора используемого для представления "Языка". Если вы только начинаете читать эту серию, то я бы рекомендовал вам начать с этого поста.

Пожалуйста, имейте в виду, что эта статья описывает начальную реализацию токинезатора. Если вы хотите просматривать код во время чтения статьи, убедитесь, что вы переключились на ветку dsl_v1.

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

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

Читать далее Написание простого DSL компилятора на Delphi (3. Токинезатор)

Написание простого DSL компилятора на Delphi (2. Абстрактное синтаксическое дерево)

Перевод поста Writing a Simple DSL Compiler with Delphi (2. Abstract Syntax Tree).

Эта статья представляет собой описание абстрактного синтаксического дерева, используемого для представления "Языка". Если вы только начинаете читать эту серию, то я бы рекомендовал вам начать с этого поста.

Пожалуйста, имейте в виду, что эта статья описывают начальную реализацию AST. Если вы хотите просматривать код во время чтения статьи, убедитесь, что вы переключились на ветку dsl_v1.

Абстрактное синтаксическое дерево является, проще говоря, символическим представлением программы в виде дерева.

В то время как текстовое представление программы хорошо подходит для нас, людей, компьютерам тяжело с ним справляться. Поэтому специальная часть любого интерпретатора или компилятора, называемая парсер, читает входной поток и преобразует его в машиночитаемый формат — AST. Это дерево может использоваться для множества целей. Мы можем, например, скормить его интерпретатору который запустит программу для нас, или мы можем скормить его компилятору для генерации запускаемого модуля, или кросс-компилятору для генерации эквивалентной программы на другом языке программирования.

В действительности, этот процесс обычно еще более сложный. Парсер использует специальный входной модуль называемый токинизатор для чтения входного потока и компилятор обычно не создаёт исполняемый модуль напрямую, но производит несколько файлов, которые линкуются в конечную программу.

Читать далее Написание простого DSL компилятора на Delphi (2. Абстрактное синтаксическое дерево)

Написание простого DSL компилятора на Delphi (1. Язык)

Перевод поста Writing a Simple DSL Compiler with Delphi (1. The Language).

Эта статья представляет собой неформальное описание простого языка (далее я называю его "Язык") для которого я пишу компилятор. Если вы только начинаете читать эту серию, то я бы рекомендовал вам начать с этого поста.

Давайте начнём с простого примера который вычисляет i-тое число Фибоначчи

Код довольно прост. Первые два числа в последовательности Фибоначчи это единицы, а последующие являются суммой двух предыдущих числе в последовательности.

Следующие правила описывают язык (более или менее):

  • Язык относится к категории C-подобных языков.
  • Пробелы игнорируются.
  • Только один тип данных — целое число (integer)
  • Только три оператора: +, -, и <.
  • a < b возвращает 1 если a меньше чем b, и 0 в противоположном случае.
  • Только два оператора if и return.
  • Оператор if выполняет блок then если условное выражение не равно 0 и выполняет блок else в противном случае. Блок else обязателен.
  • Оператор return только устанавливает результат функции и не прерывает поток управления.
  • Нет оператора присваивания.
  • Каждая функция возвращает integer.
  • Параметры всегда передаются по значению.
  • Функции без оператора return возвращают 0.
  • Функции могут вызывать другие функции (или себя рекурсивно).

Как вы можете видеть, Язык ужасно ограничен, но в нем достаточно функционала для простых примеров. Язык также является функциональным, в терминах computer science. Мы будем использовать это в наших интересах намного позже в этой серии.

Немного более формальное (но всё ещё очень неформальное) описание синтаксиса:

Написание простого DSL компилятора на Delphi (0. Введение)

Перевод поста Writing a Simple DSL Compiler with Delphi (0. Introduction)

Некоторое время назад я слушал подкаст Hanselminutes (YOU should write an interpreter with Thorsten Ball) где парень описал как он написал простой интерпретатор на языке Go. В действительности, меня не очень интересовало написание интерпретатора — я уже делал это однажды — но мысль закралась мне в голову. Я спросил себя смогу ли я сделать что-то лучше — написать компилятор (или что-то похожее на компилятор, как вы увидите дальше).

То что я хотел сделать — это взять простой язык, распарить его, сгенерировать абстрактное синтаксическое дерево и затем конвертировать его в одну большую анонимную функцию вызывающую другие анонимные функции, которые вызывают другие анонимные функции и так далее. Это сложно объяснить, так что позвольте мне показать очень простой пример.

Скажем, у меня есть простоя программа написанная на моём языке которая складывает два числе вместе

Читать далее Написание простого DSL компилятора на Delphi (0. Введение)

Средства для автоматического форматирования кода Delphi

Несколько лет назад я зафиксировал на GitHub (GitBook) описание правил форматирования кода принятых в компании где я работаю. Описание не дописано, но часть со ссылками на форматеры кода для Delphi может быть кому-то полезна. Мне удалось найти только три которые более-менее развивались. Вроде, с того времени чего-то нового не появилось.

JEDI Code Format

JEDI Code Format - отдельное приложение для форматирования исходных кодов Object Pascal и Delphi.

Experimental GExperts Version

Это экспериментальная версия эксперта для IDE RAD Studio GExpert.

Поддерживаемые версии IDE: 6, 7, 2005, 2006, 2007, 2009, 2010, XE1, XE2.

Стандартное форматирование кода в Delphi 2010

Начиная с Delphi 2010 в IDE добавлено стандартное средство для автоматического форматирования исходного кода.