Архитектура

Описание архитектуры компилятора для и конкретных технических решений

Doxygen

На память

clang-17 не поддерживает:

Feature Proposal Available
Coroutines P0912R5 Partial Fully supported on all targets except Windows, which still has some stability and ABI issues.
Extended floating-point types and standard names P1467R9 No
Concepts P0848R3 Clang 16 (Partial)
Modules No

Начиная с C++ should adopt the same characters for C++26.

  • Add @, $, and ` to the basic character set P2558R2 Yes

Система классов реализации

RunTime - единственный класс для приложения (процесса) - интерфейс для взаимодействия с операционной системой

  • Загружат и выгружает модули и является их владельцем (shared_ptr)
  • Хранит сслыки на глобальные объекты (WeakPtr) и непосредственно глобальные объекты (встроенные типы и функции). Ключем явялется строка с внутренним именем объекта
  • Хранит список глобальных объектов (типы данных и прототипы функций, которые создаются на этапе компиляции). Используется парсером и компилятором для разбора исходного текста и создания исполняемого файла.

Module - класс для модуля

  • Хранение объектов модуля (shared_ptr) и добавляет weak_ptr в глобальный список объектов в RunTime

Context - класс для хранения временных данных при выполнении программы

  • Один класс создается сразу при создании RunTime
  • В дальнейшем создается по одному объекту для каждого нового потока (:Thread)
  • Хранение списка объектов (weak_ptr)
  • Хранение локальных объектов (ObjPtr), которые создаются на этапе выполнения

Исходный текст -> Парсинг -> AST (TermPtr) -+-> Компиляция в модуль (LLVM) -> Выполнение модуля | +-> Интерпретация (Выполнение AST)

Obj - Универсальный класс для хранения данных любого типа. VarData - класс для реалиазации переменных с возможностью хранения нативных типов в чистом виде без использования класса Obj (для увеличения производительсости)

Реализация загрузки модулей и пакетов

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

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

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

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

Загрузка пакета обработывается точто таким же образом, как и загрузка моделя.

Шаги сборки компилятора

  • Сборка nlc
  • Генерация с помощью nlc --no-runtime --no-dsl -emit-cpp модуля dsl
  • Сборка модуля dsl
  • Генерация с помощью nlc --no-runtime -emit-cpp пакета runtime
  • Сборка пакета runtime

В результате имеем готовый nlc с модулями runtime.nlm и dsl.nlm, а заодно и проверяем:

  • генерацию С++ кода без макросов
  • сборку модуля
  • загрузку модуля
  • генерацию С++ кода с макросами
  • сборку пакета
  • загрузку пакета

Выполнение тестов с модулями runtime.nlm и dsl.nlm

Опции компилятора

  • -no-dsl - не использовать автоматически загружаемый модуль dsl
  • -no-runtime - не использовать автоматически загружаемый модуль runtime
  • -emit-cpp - генерировать выходной *.cpp файл

Эта инициализация позаимствована из C. Инициализируемые члены могут быть опущены и не только в конце, для них гарантируется инициализация по умолчанию. В отличие от C, порядок членов изменять нельзя, он должен быть таким же, как и при объявлении.