О том как я писал компилятор C на Python

от автора

Сегодня вы узнаете как же было хорошо что названия этой статьи было не «Как сделать компилятор C на Python» ведь когда я делал его то я не знал как сделать компилятор C на Python.

Информация о компиляторе

Вот все правила которые я запомнил:

  • Типы данных int и char (второй мне кажется багованный)

  • Куча циклов: do-while, while

  • Условие if-else

  • Функции только с помощью void

  • Если к char добавить строку «hello world» то сделайте с помощью переменных

  • Эти операторы: +, -, /, *, <, >, ==, !=

  • Присваивание переменных (имя = значение;)

  • Декларация с инициализацией (тип_данных имя = значение;)

  • А препроцессор… Ещё подумаю.

BNF для этого компилятора слишком сложное. Так что сразу кидаю пример кода:

void fac(n) {   int f = 1;   while (n > 1) {     f = f * n;     n = n - 1;   } }  void main() {   fac(5); }

Правда вывода не какого кроме Execution finished. Почему? Потому что когда виртуальная машина выводит результат работы программы то она выполняет с помощью eval переменную stdout которая уже есть автоматически.

А как вывести результат мы поговорим позже.

А вот как работает мой велосипед, тоже известно. Всего четыре этапа:

  1. Лексер возвращает токены

  2. Парсер строит AST

  3. Компиляция функций

  4. Выполнения байткода

Так и работает.

Примеры функций

Функция вывода (printf):

void printf(mes) {   stdout = stdout + mes; }

Функция просить строку из пайтона чтобы потом виртуальная машина выполнила сообщение из mes. Ну и остальное stdout.

Функция факториала:

void fac(n) {   int f = 1;   while (n > 1) {     f = f * n;     n = n - 1;   } }

В конец можно добавить строку stdout = stdout + "f"; чтобы выводить результат вычисления факториала.

Также можно реализовать Фибоначчи и много других функций. Но пока кроме printf, факториала и всех этих декрементов и инкрементов больше не нашел применения.

Более объясняющие примеры программ

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

Начнём с if-else. Вот пример (как работает):

if (условие) {   //блок кода } //если else нужен else {   //блок кода }

Как вы заметили комментарии здесь тоже есть.

Вот полный пример:

void main() {   int x = 5;   if (x < 10) {     x = 10;   }   else {     x = 5;   } }

Создаём переменную x. И проверяем: меньше 10? Тогда будет 10. Больше десяти или 10? Будет 5.

Всё легко. Да.

Теперь do-while. Вот пример работы:

do {   //блок кода } while (условие);

Пример:

void main() {   int a = 5;   do {     a = a - 1   } while (a > 6); }

Я специально сделал условие со значением false. Но «a» будет не 5 а 4. В этом весь смысл do-while.

Я думаю while можно не объяснять ведь я его показывал ранее.

Нормальный пример

Пример Фибоначчи 10:

//сама функция фибоначчи void fib(n) {   int n1 = 1;   int n2 = 1;   int n3 = 1;   int count = n - 2;   while (count) {     n3 = n1 + n2;     n1 = n2;     n2 = n3;     count = count - 1;   } }  //функция вывода void printf(mes) {   stdout = stdout + mes; }  //все эти вызовы void main() {   fib(10);   printf("'fibonacci of 10: '+str(n2)"); }

Вот так. И всё равно главное в этом примере это while.

А вывод:

Execution finished fibonacci of 10: 55

Вот так вот. В принципе я всё показал.

Давайте я расскажу как я писал этот компилятор.

Как я писал этот компилятор

Большое начало

Как всегда, когда я делаю такие проекты то думаю не о том что «я умею и мне будет легко» а «я умею но будет сложно» или «я пишу в первый раз так что ошибка неизбежна».

Скорее всего подойдет фраза 3. Потому что я в первый раз пишу полный нормальный компилятор с блоками кода и с функциями.

Но писать я стал сразу. И с начало я нагло скопировал код первого компилятора. А лексер я взял из ещё одного проекта. Просто переопределил регулярки. А начал писать я с присваивания. Просто a = 10; как нормально. В скором я начал писать для декларации. Изначально думал сделать все эти ваши return, декларация функций. Но потом понял что не смогу так быстро это сделать. И первым прорывом в моём компиляторе стал анализ типов данных для деклараций. Так что после этого я решил снять данный проект с второстепенного статуса и начал делать его больше чем что либо.

Дальше я сделал if-else и while. С начало сделать это было просто но потом это стало самым сложным. К тому времени когда мой велосипед заработал и начал выводить правильный результат то я написал свой первый пост про этот компилятора.

Потом я начал писать функции. Получение аргументов стало самым легким. Но дальше пошла порча кода парсера номер 1 чтобы добиться правильного результата. Своего я добился и потом написал пост о том что сделал функции.

Дальше я добавил ошибки и порешал баг типизации где int x = «h»; чувствовал себя правильно. А также с этими ошибками я сделал цикл do-while который я никогда не использовал на тестах.

Большая идея

Началось всё с того что я захотел сделать функцию printf но при этом не задевая парсер новым ключевым словом.

Долго думал, думал, думал… И придумал!

Я решил придумать поток номер 1. А точнее поток стандартного вывода (stdout).

Как я реализовал его? Просто! Засунул в переменные ‘stdout’ со значением ‘ ‘.

В конце работы выполнял значение stdout с помощью пайтоновского eval.

Вот так и закончилось продолжилось создания этого проекта.

Великая серия багов, из-за чего я чуть не удалил весь проект.

Когда я начал делать идею с stdout то компилятор тут же посыпался.

Ошибка с плюсом, ошибка с аргументами и остальная фигня…

Когда я начал исправлять это в первый раз то у меня была мысль «удали это» но потом я отбросил комп и про себя сказал: «я много сделал и исправил чтобы удалить это».

Потом вечерком я снова начал исправлять. И я много чего нашёл неработающего и много чего исправил. Так я добился (полу) стабильной работы компилятора.

Вот как я нахожу баги: тестирую с крутым лицом и случайно нахожу баг. В принципе так и есть. Вроде бы😅.

Заключение

Вот такой компилятор получился. Тот кто дочитал до этого момента молодец.

Всем пока!

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

Выкладывать на github?

66.67% Да4
33.33% Нет2

Проголосовали 6 пользователей. Воздержался 1 пользователь.

ссылка на оригинал статьи https://habr.com/ru/articles/904548/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *