Сегодня я дошел до первого принципиального успеха: с помощью нового компилятора получил код одной команды инструмента и проверил, что инструмент и команда работают.
В более понятных терминах, это приблизительно так: код для одного из методов класса построен новым компилятором (на другом языке программирования) и класс и метод после этого работает.
Новый компилятор построен по такой схеме:
- Front-end строит синтаксическое дерево
- Далее второй проход строит LLVM IR (в текстовом виде)
- Далее запускается LLVM LLC (static compiler), который порождает объектный файл по IR
- Дальше начинается время быстрого хака: из объектного файла извлекается код, и меняется формат, чтобы дальше работал Вировский линкер
Как все мы понимаем, в дальнейшем схема немного изменится, после 2-го шага будет запускаться LLVM оптимизатор, и в репозиторий будет попадать оптимизированный IR. А код для конкретного процессора/платформы будет до-компилироваться по необходимости.
На первый этап ушло примерно 5-6 полноценных рабочих дней, естественно растянутых, так как работаю в свободное (от основной работы) время.
Необходимое замечание: все три сделанных инструмента (front-end, построитель IR и инструмент извлечения кода) сделаны в достаточном для этапа объеме, а не полностью.
Я использую наиболее комфортный для себя способ работы, который можно назвать вертикальным программированием, то есть сначала выкладываю основу программы и основу всех инструментов, проверяя по ходу раскладку на инструменты и взаимодействие. Обязательным так же является изготовление тестового окружения и дополнительных инструментов для тестирования, в данном случае таким инструментом является визуализатор синтаксического дерева. После того, как основа выложена и проверены, наступает пора наращивать «мясо» — функционал инструментов, с постоянной проверкой того, что все работает.
Чтобы было понятно, компилятор сейчас понимает всего несколько синтаксических конструкций:
- Описание команды (функции) без параметров
- Оператор присваивания
- Оператор завершения (return)
а также всего один тип: int32 и только целые константы.
Вот собственно текст команды на языке А1, которая компилируется в тесте:
«Выполнить»: Т-ЦЕЛ32;
150 → переменная: Т-ЦЕЛ32
3 → вторая-переменная: Т-ЦЕЛ32
завершить переменная + вторая-переменная
Здесь два присваивания (→) с созданием переменных и возврат с результатом.
Далее, я буду двигаться в сторону создания полноценных А1 инструментов, с возможность взаимодействия со всем имеющимся хозяйством.
Постоянная ссылка