Это несложно, но требует огромной работы, чтобы сделать полученный инструмент практичным.
Во-первых, забудьте о синтаксисе — это в основном решённая проблема, почти в любом языке есть 1+ библиотека для создания синтаксических анализаторов. Если вам нравится Python, библиотека PLY предоставляет вам полный набор поддержки любого синтаксиса. Более того, вы можете полностью отказаться от синтаксического анализатора, используя свой хост-язык (язык реализации) для построения деревьев AST или любой другой интерпретируемой структуры данных по вашему выбору.
Далее, избегайте написания классического компилятора, это скучный и очень ограниченный языковой шаблон. Присмотритесь к C++, изначально он был чистым компилятором, но в последнее десятилетие он превратился в свихнутый интерпретатор, работающий поверх движка шаблонов/типов. Именно, он запускает какой-то код во время компиляции, но «язык» для метапрограммирования с его семантикой и синтаксисом сжигает ваш мозг, и у вас всё еще нет инструментов для его отладки.
Не забывайте: любой интерпретатор языка программирования может компилировать самый быстрый машинный код, или код на любом другом языке программирования, который вы хотите использовать (ассемблер, LLVM, C/C ++, Java, ..., все, что вы хотите, включая скрипты сборки и SQL): достаточно писать в текстовые файлы, и компилировать их с помощью любого backend-компилятора.
.compile_to _ *()
для этой структуры данных, которые могут компилировать каждый тип узла объектного графа в язык, который вы хотите использовать (LLVM, ассемблер, C, код Python для стека Django + JavaScript,..) — теперь вы можете скомпилировать структуру данных в целевой язык. Обратите внимание, что ваши модели могут компилировать сами себя через генерацию кода.AST.compile()
и получать код C ++ для backend-компиляции. На данный момент у вас уже есть рабочая версия вашего собственного языка, даже без синтаксического анализатора (хост-язык делает это для вас).Итак, давайте в целом.
Недостаток: сложность метода. Да, огромная, но только на более поздних этапах. На начальных этапах вы просто копипастите некоторые части кода на целевом языке в виде обычных строк (в большинстве программных проектов используется несколько языков: код, скрипты сборки/развертывания/обслуживания, JS/HTML, SQL, ...), иногда заменяя крошечные элементы в этих строках используя Python-код, и пишете их в текстовые файлы. Это выглядит просто даже для новичка: только интерполяция строк и запись текстового файла.
Следующий этап развития вас как программиста — это вязание структур данных. Также выглядит как типовой навык любого программиста: манипулирование графом объектов, которые ссылаются друг на друга, иногда циклически. Это не страшно, используется практически в любой зрелой программной системе. У вас даже есть преимущество: объектный граф -- это унифицированная структура данных, любой узел это экземпляр, унаследованный от базового класса Object
, и вы можете работать с ними через унифицированный интерфейс. Каждый унаследованный класс имеет собственное поведение, но все они разделяют одну и ту же концепт: дерево (граф) атрибутной грамматики . Каждый объект является контейнером данных (даже Primitive
), каждый узел может иметь произвольные атрибуты, привязанные к другим объектным графам, и каждый узел может иметь упорядоченные подграфы:
## @brief базовый класс узла объектного графа
## @ingroup object
class Object:
## конструктор
## @param[in] V заданное скалярное значение
def __init__(self, V):
if isinstance(V, Object): V = V.val
## имя символа / скалярное значение (строка, число,..)
self.val = V
## слоты = атрибуты = словарь = environment
self.slot = {}
## вложенные AST = вектор = стек = очередь
self.nest = []
## глобальный storage id
## @ingroup persist
self.gid = self.sync().gid