├── .gitignore ├── примеры ├── 01-привет.хуя.вывод ├── 03-имя.хуя.вывод ├── 08-структуры.хуя.вывод ├── 02-цикл.хуя ├── 05-фибоначчи.хуя.вывод ├── 07-рекурсия.хуя.вывод ├── 05-фибоначчи.хуя ├── 08-структуры.хуя ├── 04-физз-базз.хуя ├── 07-рекурсия.хуя ├── 03-имя.хуя ├── 02-цикл.хуя.вывод ├── 09-правило110.хуя ├── 04-физз-базз.хуя.вывод ├── 09-правило110.хуя.вывод ├── 01-привет.хуя ├── 10-игра-жизнь.хуя ├── 06-рейлиб.хуя └── 10-игра-жизнь.хуя.вывод ├── модули ├── libraylib.a ├── рейлиб.хуя └── прелюдия.хуя ├── собрать.sh ├── записать.sh ├── ЛИЦЕНЗИЯ ├── тесты ├── тест.хуя.вывод └── тест.хуя ├── редакторы └── режим-хуя.el ├── README.md ├── исходники ├── типизация.rs ├── диагностика.rs ├── хуяк.rs ├── синтаксис.rs ├── лексика.rs ├── фазм.rs └── интерпретатор.rs ├── ПЛАН.txt └── тест.sh /.gitignore: -------------------------------------------------------------------------------- 1 | сборка/ -------------------------------------------------------------------------------- /примеры/01-привет.хуя.вывод: -------------------------------------------------------------------------------- 1 | Привет, Мир! 2 | hello, world! 3 | -------------------------------------------------------------------------------- /примеры/03-имя.хуя.вывод: -------------------------------------------------------------------------------- 1 | Как вас зовут? Привет, Алексей! 2 | -------------------------------------------------------------------------------- /примеры/08-структуры.хуя.вывод: -------------------------------------------------------------------------------- 1 | Строка = 69 2 | Столбец = 420 3 | -------------------------------------------------------------------------------- /модули/libraylib.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsoding/good_training_language/HEAD/модули/libraylib.a -------------------------------------------------------------------------------- /собрать.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -xe 4 | 5 | mkdir -p ./сборка/ 6 | rustc -o ./сборка/хуяк -g исходники/хуяк.rs 7 | -------------------------------------------------------------------------------- /примеры/02-цикл.хуя: -------------------------------------------------------------------------------- 1 | вкл прелюдия; 2 | 3 | про главная() нч 4 | конст РАЗМЕР := 100; 5 | для а := 1..РАЗМЕР то печать(а-1, «\н»); 6 | кц 7 | -------------------------------------------------------------------------------- /примеры/05-фибоначчи.хуя.вывод: -------------------------------------------------------------------------------- 1 | 0 2 | 1 3 | 1 4 | 2 5 | 3 6 | 5 7 | 8 8 | 13 9 | 21 10 | 34 11 | 55 12 | 89 13 | 144 14 | 233 15 | 377 16 | 610 17 | 987 18 | -------------------------------------------------------------------------------- /примеры/07-рекурсия.хуя.вывод: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | 6 7 | 7 8 | 8 9 | 9 10 | 10 11 | 11 12 | 12 13 | 13 14 | 14 15 | 15 16 | -------------------------------------------------------------------------------- /примеры/05-фибоначчи.хуя: -------------------------------------------------------------------------------- 1 | вкл прелюдия; 2 | 3 | конст ЛИМИТ := 1000; 4 | 5 | про главная() нч 6 | пер а: цел := 0; 7 | пер б: цел := 1; 8 | пока а -? ЛИМИТ нч 9 | печать(а, «\н»); 10 | пер в: цел := а + б; 11 | а := б; 12 | б := в; 13 | кц 14 | кц 15 | -------------------------------------------------------------------------------- /примеры/08-структуры.хуя: -------------------------------------------------------------------------------- 1 | вкл прелюдия; 2 | 3 | структ Координата нч 4 | строка: цел; 5 | столбец: цел; 6 | кц 7 | 8 | про главная() нч 9 | пер позиция: Координата; 10 | позиция.строка := 69; 11 | позиция.столбец := 420; 12 | печать(«Строка = », позиция.строка, «\н»); 13 | печать(«Столбец = », позиция.столбец, «\н»); 14 | кц 15 | -------------------------------------------------------------------------------- /примеры/04-физз-базз.хуя: -------------------------------------------------------------------------------- 1 | вкл прелюдия; 2 | 3 | про главная() нч 4 | для счет := 1..100 нч 5 | если счет ост 15 = 0 то печать(«ФиззБазз\н»); 6 | // СДЕЛАТЬ: подумать как сократить конструкцию «иначе то если» 7 | иначе то если счет ост 3 = 0 то печать(«Физз\н»); 8 | иначе то если счет ост 5 = 0 то печать(«Базз\н»); 9 | иначе то печать(счет, «\н»); 10 | кц 11 | кц 12 | -------------------------------------------------------------------------------- /примеры/07-рекурсия.хуя: -------------------------------------------------------------------------------- 1 | вкл прелюдия; 2 | 3 | конст МАКС_ГЛУБИНА := 3; 4 | пер счетчик: цел; 5 | 6 | про отступ(ширина: цел) то для индекс := 1..ширина то печать(« »); 7 | 8 | про дерево(глубина: цел) нч 9 | если глубина +? МАКС_ГЛУБИНА то вернуть; 10 | дерево(глубина + 1); 11 | отступ(глубина*2); 12 | счетчик := счетчик + 1; 13 | печать(счетчик, «\н»); 14 | дерево(глубина + 1); 15 | кц 16 | 17 | про главная() нч 18 | счетчик := 0; 19 | дерево(0); 20 | кц 21 | -------------------------------------------------------------------------------- /примеры/03-имя.хуя: -------------------------------------------------------------------------------- 1 | // Еще одна классическая программа, которая спрашивает ваше имя и 2 | // приветствует вас по нему. Цель данной программы продемонстрировать 3 | // не только вывод, но и ввод. 4 | 5 | про главная() нч 6 | печать(«Как вас зовут? »); 7 | конст ОБЪЁМ := 64; 8 | пер имя: массив(ОБЪЁМ, нат8); 9 | // СДЕЛАТЬ: как обрабатывать ошибки ввода? 10 | // Можно генерить какой-нибудь рантайм, который проверяет результат сисвызова read. 11 | пер длинна: нат := ввод(имя); 12 | // СДЕЛАТЬ: Логические операции с коротким замыканиям 13 | // Нужны ли они вообще? 14 | если длинна +? 0нат то если имя(длинна-1нат) = 10нат как нат8 то длинна := длинна - 1нат; 15 | // СДЕЛАТЬ: Однобайтовые литералы 10нат8 16 | печать(«Привет, », срез(имя, 0нат, длинна), «!\н»); 17 | кц 18 | -------------------------------------------------------------------------------- /примеры/02-цикл.хуя.вывод: -------------------------------------------------------------------------------- 1 | 0 2 | 1 3 | 2 4 | 3 5 | 4 6 | 5 7 | 6 8 | 7 9 | 8 10 | 9 11 | 10 12 | 11 13 | 12 14 | 13 15 | 14 16 | 15 17 | 16 18 | 17 19 | 18 20 | 19 21 | 20 22 | 21 23 | 22 24 | 23 25 | 24 26 | 25 27 | 26 28 | 27 29 | 28 30 | 29 31 | 30 32 | 31 33 | 32 34 | 33 35 | 34 36 | 35 37 | 36 38 | 37 39 | 38 40 | 39 41 | 40 42 | 41 43 | 42 44 | 43 45 | 44 46 | 45 47 | 46 48 | 47 49 | 48 50 | 49 51 | 50 52 | 51 53 | 52 54 | 53 55 | 54 56 | 55 57 | 56 58 | 57 59 | 58 60 | 59 61 | 60 62 | 61 63 | 62 64 | 63 65 | 64 66 | 65 67 | 66 68 | 67 69 | 68 70 | 69 71 | 70 72 | 71 73 | 72 74 | 73 75 | 74 76 | 75 77 | 76 78 | 77 79 | 78 80 | 79 81 | 80 82 | 81 83 | 82 84 | 83 85 | 84 86 | 85 87 | 86 88 | 87 89 | 88 90 | 89 91 | 90 92 | 91 93 | 92 94 | 93 95 | 94 96 | 95 97 | 96 98 | 97 99 | 98 100 | 99 101 | -------------------------------------------------------------------------------- /примеры/09-правило110.хуя: -------------------------------------------------------------------------------- 1 | вкл прелюдия; 2 | 3 | конст РАЗМЕР := 32; 4 | пер мир0: массив(РАЗМЕР, нат); 5 | пер мир1: массив(РАЗМЕР, нат); 6 | 7 | // СДЕЛАТЬ: передача массива по ссылке 8 | про печать_мира(мир: массив(РАЗМЕР, нат)) нч 9 | для индекс := 1..РАЗМЕР то 10 | если мир(индекс - 1) = 0нат 11 | то печать(«_»); 12 | иначе то печать(«%»); 13 | печать(«\н»); 14 | кц 15 | 16 | про главная() нч 17 | если РАЗМЕР -? 3 то вернуть; 18 | 19 | мир0(РАЗМЕР - 2) := 1нат; 20 | печать_мира(мир0); 21 | 22 | для _ := 1..РАЗМЕР-3 нч 23 | пер окно: нат := (мир0(0) лбс 1нат) или мир0(1); 24 | для индекс := 2..РАЗМЕР-1 нч 25 | окно := ((окно лбс 1нат) или мир0(индекс)) и 7нат; 26 | мир1(индекс - 1) := (110нат пбс окно) и 1нат; 27 | кц 28 | для индекс := 1..РАЗМЕР то мир0(индекс - 1) := мир1(индекс - 1); 29 | печать_мира(мир0); 30 | кц 31 | кц 32 | -------------------------------------------------------------------------------- /примеры/04-физз-базз.хуя.вывод: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | Физз 4 | 4 5 | Базз 6 | Физз 7 | 7 8 | 8 9 | Физз 10 | Базз 11 | 11 12 | Физз 13 | 13 14 | 14 15 | ФиззБазз 16 | 16 17 | 17 18 | Физз 19 | 19 20 | Базз 21 | Физз 22 | 22 23 | 23 24 | Физз 25 | Базз 26 | 26 27 | Физз 28 | 28 29 | 29 30 | ФиззБазз 31 | 31 32 | 32 33 | Физз 34 | 34 35 | Базз 36 | Физз 37 | 37 38 | 38 39 | Физз 40 | Базз 41 | 41 42 | Физз 43 | 43 44 | 44 45 | ФиззБазз 46 | 46 47 | 47 48 | Физз 49 | 49 50 | Базз 51 | Физз 52 | 52 53 | 53 54 | Физз 55 | Базз 56 | 56 57 | Физз 58 | 58 59 | 59 60 | ФиззБазз 61 | 61 62 | 62 63 | Физз 64 | 64 65 | Базз 66 | Физз 67 | 67 68 | 68 69 | Физз 70 | Базз 71 | 71 72 | Физз 73 | 73 74 | 74 75 | ФиззБазз 76 | 76 77 | 77 78 | Физз 79 | 79 80 | Базз 81 | Физз 82 | 82 83 | 83 84 | Физз 85 | Базз 86 | 86 87 | Физз 88 | 88 89 | 89 90 | ФиззБазз 91 | 91 92 | 92 93 | Физз 94 | 94 95 | Базз 96 | Физз 97 | 97 98 | 98 99 | Физз 100 | Базз 101 | -------------------------------------------------------------------------------- /записать.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -xe 4 | 5 | ./собрать.sh 6 | 7 | ./сборка/хуяк интер ./примеры/01-привет.хуя > ./примеры/01-привет.хуя.вывод 8 | ./сборка/хуяк интер ./примеры/02-цикл.хуя > ./примеры/02-цикл.хуя.вывод 9 | echo 'Алексей' | ./сборка/хуяк интер ./примеры/03-имя.хуя > ./примеры/03-имя.хуя.вывод 10 | ./сборка/хуяк интер ./примеры/04-физз-базз.хуя > ./примеры/04-физз-базз.хуя.вывод 11 | ./сборка/хуяк интер ./примеры/05-фибоначчи.хуя > ./примеры/05-фибоначчи.хуя.вывод 12 | #./сборка/хуяк интер ./примеры/06-рейлиб.хуя > ./примеры/06-рейлиб.хуя.вывод 13 | ./сборка/хуяк интер ./примеры/07-рекурсия.хуя > ./примеры/07-рекурсия.хуя.вывод 14 | ./сборка/хуяк интер ./примеры/08-структуры.хуя > ./примеры/08-структуры.хуя.вывод 15 | ./сборка/хуяк интер ./примеры/09-правило110.хуя > ./примеры/09-правило110.хуя.вывод 16 | ./сборка/хуяк интер ./примеры/10-игра-жизнь.хуя > ./примеры/10-игра-жизнь.хуя.вывод 17 | ./сборка/хуяк интер ./тесты/тест.хуя > ./тесты/тест.хуя.вывод 18 | 19 | -------------------------------------------------------------------------------- /примеры/09-правило110.хуя.вывод: -------------------------------------------------------------------------------- 1 | ______________________________%_ 2 | _____________________________%%_ 3 | ____________________________%%%_ 4 | ___________________________%%_%_ 5 | __________________________%%%%%_ 6 | _________________________%%___%_ 7 | ________________________%%%__%%_ 8 | _______________________%%_%_%%%_ 9 | ______________________%%%%%%%_%_ 10 | _____________________%%_____%%%_ 11 | ____________________%%%____%%_%_ 12 | ___________________%%_%___%%%%%_ 13 | __________________%%%%%__%%___%_ 14 | _________________%%___%_%%%__%%_ 15 | ________________%%%__%%%%_%_%%%_ 16 | _______________%%_%_%%__%%%%%_%_ 17 | ______________%%%%%%%%_%%___%%%_ 18 | _____________%%______%%%%__%%_%_ 19 | ____________%%%_____%%__%_%%%%%_ 20 | ___________%%_%____%%%_%%%%___%_ 21 | __________%%%%%___%%_%%%__%__%%_ 22 | _________%%___%__%%%%%_%_%%_%%%_ 23 | ________%%%__%%_%%___%%%%%%%%_%_ 24 | _______%%_%_%%%%%%__%%______%%%_ 25 | ______%%%%%%%____%_%%%_____%%_%_ 26 | _____%%_____%___%%%%_%____%%%%%_ 27 | ____%%%____%%__%%__%%%___%%___%_ 28 | ___%%_%___%%%_%%%_%%_%__%%%__%%_ 29 | __%%%%%__%%_%%%_%%%%%%_%%_%_%%%_ 30 | _%%___%_%%%%%_%%%____%%%%%%%%_%_ 31 | -------------------------------------------------------------------------------- /ЛИЦЕНЗИЯ: -------------------------------------------------------------------------------- 1 | Авторские права © 2024 Алексей Кутепов 2 | 3 | Данная лицензия разрешает лицам, получившим копию данного программного 4 | обеспечения и сопутствующей документации (далее — Программное 5 | обеспечение), безвозмездно использовать Программное обеспечение без 6 | ограничений, включая неограниченное право на использование, 7 | копирование, изменение, слияние, публикацию, распространение, 8 | сублицензирование и/или продажу копий Программного обеспечения, а 9 | также лицам, которым предоставляется данное Программное обеспечение, 10 | при соблюдении следующих условий: 11 | 12 | Указанное выше уведомление об авторском праве и данные условия должны 13 | быть включены во все копии или значимые части данного Программного 14 | обеспечения. 15 | 16 | ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ 17 | КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ 18 | ГАРАНТИИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ 19 | НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. НИ В КАКОМ 20 | СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО 21 | КАКИМ-ЛИБО ИСКАМ, ЗА УЩЕРБ ИЛИ ПО ИНЫМ ТРЕБОВАНИЯМ, В ТОМ ЧИСЛЕ, ПРИ 22 | ДЕЙСТВИИ КОНТРАКТА, ДЕЛИКТЕ ИЛИ ИНОЙ СИТУАЦИИ, ВОЗНИКШИМ ИЗ-ЗА 23 | ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ 24 | ОБЕСПЕЧЕНИЕМ. -------------------------------------------------------------------------------- /тесты/тест.хуя.вывод: -------------------------------------------------------------------------------- 1 | Печать чисел: 0, 69, 1234567890 2 | Печать логических: истина, ложь 3 | Передача аргументов функции: 69 4 | Порядок передачи аргументов функции: 1 2 3 4 5 | Тест возврата значения: 69 6 | Вещественная арифметика: 69 7 | Вещественное отрицание: истина 8 | Вещественная сравнение: истина ложь 9 | Индексация сложных выражений: 69 10 | Печать отрицательных чисел: -69 11 | логическое и: 12 | ложь и ложь == ложь 13 | истина и ложь == ложь 14 | ложь и истина == ложь 15 | истина и истина == истина 16 | Взаимодействие «ёлочек» и "лапок" 17 | "" 18 | «» 19 | Чтение нат8: 81 20 | Проверка вилки: 21 | ноль 22 | один 23 | два 24 | много 25 | много 26 | Индексация массивов вложенных в структуру: 27 | (1, 1) 28 | (2, 2) 29 | (3, 3) 30 | (4, 4) 31 | (5, 5) 32 | (6, 6) 33 | (7, 7) 34 | (8, 8) 35 | (9, 9) 36 | (10, 10) 37 | Итерация строки «Hello, World» по байтам: 38 | 72 39 | 101 40 | 108 41 | 108 42 | 111 43 | 44 44 | 32 45 | 87 46 | 111 47 | 114 48 | 108 49 | 100 50 | подбрить_строку_слева(« Привет ») = «Привет » 51 | подбрить_строку_слева(« ») = «» 52 | подбрить_строку_слева(«») = «» 53 | Индексация срезов внутри структуры: ALEXEY 54 | Сравнение структур: 55 | (число: 69, еще_число: 420) = (число: 69, еще_число: 420) => истина 56 | (число: 69, еще_число: 420) = (число: 69, еще_число: 1337) => ложь 57 | Сравнение строк: 58 | «Hello» = «World» => ложь 59 | «Foo» = «Foo» => истина 60 | Проверить логические конвертации: 61 | ложь 62 | истина 63 | истина 64 | истина 65 | 1 66 | Индексирование срезу из процедуры: 69 67 | Индексация срезов слева и справа: ALEXEY 68 | Отрицательный остаток: -1 69 | Отрицательное деление: 0 70 | Отрицательное умножение: -100 71 | Знаковое деление: 40 72 | Конвертация вещ в нат: 127 73 | -------------------------------------------------------------------------------- /примеры/01-привет.хуя: -------------------------------------------------------------------------------- 1 | /* 2 | Классическая программа «Привет, Мир» (анг. «Hello, World»), с 3 | которой начинается знакомство с любым языком программирования. 4 | 5 | Коммандная строка для компиляции и последующего запуска программы: 6 | 7 | $ хуяк комп -пуск ./примеры/01-привет.хуя 8 | 9 | Данная команда создаст исполняемый файл ./примеры/01-привет и тут 10 | же запустит его. Чтобы скомпилировать без последующего запуска 11 | опустите флаг «-пуск». 12 | 13 | Точкой вход в программу является процедура с названием 14 | «главная». Определение процедуры начинается с ключевого слова 15 | «про». 16 | */ 17 | про главная() нч 18 | // Тело процедуры окружено ключевыми словами «нч» и «кц» (от слов 19 | // «начало» и «конец»). «нч»-«кц» образуют операционные скобки 20 | // наподобие фигурных скобок {} в Си-подобных языках 21 | // программирования. Мы не используем {} потому, что их набор 22 | // требует переключения раскладки клавиатуры на английскую, что 23 | // крайне неудобно при программировании на языке, который 24 | // использует кириллицу. 25 | // 26 | // Все синтаксические решения языка были приняты с учетом 27 | // минимизации переключения раскладки клавиатуры. Так что, если 28 | // что-то выглядит необычно, скорее всего это из-за этого. 29 | // 30 | // Язык чувствителен к регистру. 31 | 32 | 33 | // Процедура печать() работает по тому же принципу, что и Write() 34 | // из классического языка Pascal 35 | // https://www.freepascal.org/docs-html/rtl/system/write.html 36 | // Процедура вариантивна (принимает переменное число аргументов, в 37 | // английском языке известна как «variadic») и для каждого 38 | // аргумента печатает его строковое представление в соответствии с 39 | // его типом на стандартный поток вывода. 40 | печать(«Привет, Мир!\н»); 41 | // Строки обрамляются «ёлочками». Экранированная 42 | // последовательность «\н» обозначает символ новой строки. 43 | 44 | 45 | // Английские "лапки" для обрамления строк тоже работают. 46 | печать("hello, world!\н"); 47 | кц 48 | -------------------------------------------------------------------------------- /примеры/10-игра-жизнь.хуя: -------------------------------------------------------------------------------- 1 | вкл прелюдия; 2 | 3 | конст ВЫСОТА := 10; 4 | конст ШИРИНА := 20; 5 | 6 | пер поле: массив(ВЫСОТА, массив(ШИРИНА, лог)); 7 | пер скрытое_поле: массив(ВЫСОТА, массив(ШИРИНА, лог)); 8 | 9 | про инициализировать_поле() нч 10 | для строка := 1..ВЫСОТА то 11 | для столбец := 1..ШИРИНА то 12 | поле(строка - 1)(столбец - 1) := ложь; 13 | поле(0)(1) := истина; 14 | поле(1)(2) := истина; 15 | поле(2)(0) := истина; 16 | поле(2)(1) := истина; 17 | поле(2)(2) := истина; 18 | кц 19 | 20 | про отобразить_поле() нч 21 | для строка := 1..ВЫСОТА нч 22 | для столбец := 1..ШИРИНА нч 23 | если поле(строка - 1)(столбец - 1) 24 | то печать(«%»); 25 | иначе то печать(«_»); 26 | кц 27 | печать(«\н»); 28 | кц 29 | кц 30 | 31 | про подсчитать_соседей(строка0: цел, столбец0: цел): цел нч 32 | пер соседи : цел := 0; 33 | для дстр := -1..1 то 34 | для дстл := -1..1 то 35 | если дстр != 0 или дстл != 0 нч 36 | пер строка: цел := строка0 + дстр; 37 | пер столбец: цел := столбец0 + дстл; 38 | если 0 -?= строка и строка -? ВЫСОТА то 39 | если 0 -?= столбец и столбец -? ШИРИНА то 40 | если поле(строка)(столбец) то соседи := соседи + 1; 41 | кц 42 | вернуть соседи; 43 | кц 44 | 45 | про следующее_поле() нч 46 | для строка := 1..ВЫСОТА то 47 | для столбец := 1..ШИРИНА нч 48 | пер соседи: цел := подсчитать_соседей(строка - 1, столбец - 1); 49 | если поле(строка - 1)(столбец - 1) 50 | то скрытое_поле(строка - 1)(столбец - 1) := соседи = 2 или соседи = 3; 51 | иначе то скрытое_поле(строка - 1)(столбец - 1) := соседи = 3; 52 | кц 53 | кц 54 | 55 | про перевернуть_поле() нч 56 | для строка := 1..ВЫСОТА то 57 | для столбец := 1..ШИРИНА то 58 | поле(строка - 1)(столбец - 1) := скрытое_поле(строка - 1)(столбец - 1); 59 | кц 60 | 61 | про главная() нч 62 | инициализировать_поле(); 63 | отобразить_поле(); 64 | 65 | для _ := 1..10 нч 66 | следующее_поле(); 67 | перевернуть_поле(); 68 | печать(«\н»); 69 | отобразить_поле(); 70 | кц 71 | кц 72 | -------------------------------------------------------------------------------- /модули/рейлиб.хуя: -------------------------------------------------------------------------------- 1 | // Здесь определены некоторые процедуры из библиотеки raylib: https://www.raylib.com/ 2 | 3 | библ c; 4 | библ raylib; 5 | библ m; 6 | 7 | конст КЛАВИША_ПРОБЕЛ := 32; 8 | 9 | // СДЕЛАТЬ: Текущий синтаксис для определения «foreign» 10 | // («иностранных»?, «чужих»?) процедур несколько сбивает с толку. 11 | // 12 | // Ключ «внешняя» может быть интерпретирован как «импортируемая» либо 13 | // как «экспортируемая». Причем для экспортируемых процедур нам тоже 14 | // нужно иметь возможность задавать внешний символ, чтобы использовать 15 | // в таких языках как Си. Так что они даже синтаксически будут 16 | // похожи. Единственная разница между ними будет в том, что 17 | // экспортируемые процедуры имеют тело. 18 | про открыть_окно(ширина: цел, высота: цел, заголовок: нат) внешняя «InitWindow»; 19 | // СДЕЛАТЬ: «заголовок» в функции открыть_окно() должен быть строкой а не целым числом. 20 | // 21 | // Через целое число мы передаем адрес памяти на сишную строку. 22 | // 23 | // Тут пока не понятно как семантически разрешить 24 | // противоречие. Функция рейлиб хочет сишную строку, а наши строки 25 | // размерные. Т.е. нам нужен какой-то семантически трюк, который для 26 | // внешних процедур делают какую-то ковертацию? 27 | // 28 | // Пока что планируется использовать так: 29 | // 30 | // открыть_окно(800, 600, адрес(«Заголовок»)); 31 | // 32 | // Строковые литералы гарантируют в конце нулл-терминатор, так что 33 | // это должно работать. 34 | про закрыть_окно() внешняя «CloseWindow»; 35 | про пора_закрыть_окно(): лог внешняя «WindowShouldClose»; 36 | про начать_рисовать() внешняя «BeginDrawing»; 37 | про закончить_рисовать() внешняя «EndDrawing»; 38 | про очистить_фон(цвет: нат) внешняя «ClearBackground»; 39 | про нарисовать_прямоугольник(икс: цел, игрек: цел, ширина: цел, высота: цел, цвет: нат) внешняя «DrawRectangle»; 40 | про установить_целевую_частоту_кадров(частота_кадров: цел) внешняя «SetTargetFPS»; 41 | про получить_время_кадра(): вещ внешняя «GetFrameTime»; 42 | про получить_ширину_экрана(): цел внешняя «GetScreenWidth»; 43 | про получить_высоту_экрана(): цел внешняя «GetScreenHeight»; 44 | про получить_случайное_число(мин: цел, макс: цел): цел внешняя «GetRandomValue»; 45 | про установить_случайное_семя(семя: нат) внешняя «SetRandomSeed»; 46 | про нажата_клавиша(клавиша: цел): лог внешняя «IsKeyPressed»; 47 | -------------------------------------------------------------------------------- /модули/прелюдия.хуя: -------------------------------------------------------------------------------- 1 | // Здесь находится «стандартная» библиотека Хорошего Учебного Языка. 2 | 3 | // СДЕЛАТЬ: ввести функцию печать_строки, которая делает системный вызов SYS_write 4 | // Хотя, мы тогда теряем возможность печатать строки в режиме интерпретации. 5 | 6 | про печать_нат(число: нат) нч 7 | если число = 0нат нч 8 | печать(«0»); 9 | вернуть; 10 | кц 11 | 12 | конст ОБЪЁМ := 32; 13 | пер буфер: массив(ОБЪЁМ, нат8); 14 | пер размер: нат := 0нат; 15 | 16 | пока число +? 0нат нч 17 | // СДЕЛАТЬ: размер += 1; 18 | размер := размер + 1нат; 19 | буфер(ОБЪЁМ как нат - размер) := (число ост 10нат + 48нат) как нат8; // СДЕЛАТЬ: буквенные литералы 20 | // СДЕЛАТЬ: число /= 10; 21 | число := число / 10нат; 22 | кц 23 | 24 | печать(срез(буфер, ОБЪЁМ как нат - размер, размер)); 25 | кц 26 | 27 | про печать_цел(число: цел) нч 28 | если число -? 0 нч 29 | печать(«-»); 30 | число := -число; 31 | кц 32 | печать_нат(число как нат); 33 | кц 34 | 35 | про печать_лог(условие: лог) нч 36 | если условие нч 37 | печать(«истина»); 38 | вернуть; 39 | кц 40 | печать(«ложь»); 41 | кц 42 | 43 | про это_пробел(символ: нат8): лог нч 44 | пер таблица: строка := « \т\н»; 45 | для индекс := 0..размер(таблица)-1 46 | то если таблица(индекс) = символ 47 | то вернуть истина; 48 | вернуть ложь; 49 | кц 50 | 51 | про подбрить_строку_слева(стр: строка): строка нч 52 | пер начало: цел := 0; 53 | пока начало -? размер(стр) и это_пробел(стр(начало)) нч 54 | начало := начало + 1; 55 | кц 56 | вернуть срез(стр, начало как нат, (размер(стр) - начало) как нат); 57 | кц 58 | 59 | про верхний_регистр_аскии(символ: нат8): нат8 нч 60 | конст МАЛЕНЬКАЯ_ЭЙ := 97; 61 | конст МАЛЕНЬКАЯ_ЗЕТ := 122; 62 | конст БОЛЬШАЯ_ЭЙ := 65; 63 | если МАЛЕНЬКАЯ_ЭЙ -?= символ как цел и символ как цел -?= МАЛЕНЬКАЯ_ЗЕТ нч 64 | вернуть (символ как цел - МАЛЕНЬКАЯ_ЭЙ + БОЛЬШАЯ_ЭЙ) как нат8; 65 | кц 66 | вернуть символ; 67 | кц 68 | 69 | про строки_равны(одна: строка, другая: строка): лог нч 70 | если размер(одна) != размер(другая) то вернуть ложь; 71 | для индекс := 1..размер(одна) то 72 | если одна(индекс-1) != другая(индекс-1) то 73 | вернуть ложь; 74 | вернуть истина; 75 | кц 76 | -------------------------------------------------------------------------------- /редакторы/режим-хуя.el: -------------------------------------------------------------------------------- 1 | ;; СДЕЛАТЬ: расширения для vim 2 | (defconst синтаксическая-таблица-режима-хуя 3 | (with-syntax-table (copy-syntax-table) 4 | ;; Комментарии в стиле Си/Си++ 5 | (modify-syntax-entry ?/ ". 124b") 6 | (modify-syntax-entry ?* ". 23") 7 | (modify-syntax-entry ?\n "> b") 8 | 9 | ;; Строковые литералы 10 | (modify-syntax-entry ?« "(»") 11 | (modify-syntax-entry ?» ")«") 12 | (modify-syntax-entry ?\" ".") 13 | 14 | (syntax-table)) 15 | "Синтаксическая таблица для `режим-хуя'.") 16 | 17 | (eval-and-compile 18 | (defconst ключевые-слова-хуя 19 | '("пер" "про" "конст" "пока" "нч" "кц" "для" 20 | "если" "то" "иначе" "вернуть" "замкнуть" "пропустить" 21 | "структ" "союз" "как" "вкл" "внешняя" "библ" "или" 22 | "и" "истина" "ложь" "лбс" "пбс" "ост" "вилка" "когда" "любое" 23 | "либо"))) 24 | 25 | (defun строковый-литерал-хуя (придел) 26 | (while (and (< (point) придел) 27 | (not (or (eq (char-after) ?«) (eq (char-after) ?\")))) 28 | (forward-char)) 29 | (cond 30 | ((eq (char-after) ?«) 31 | (let ((начало (point))) 32 | (forward-char) 33 | (let ((вложенность 1)) 34 | (while (and (< (point) придел) (> вложенность 0)) 35 | (cond 36 | ;; СДЕЛАТЬ: поддержка экранирования внутри «ёлочных» литералов 37 | ((eq (char-after) ?«) (incf вложенность)) 38 | ((eq (char-after) ?») (decf вложенность))) 39 | (forward-char))) 40 | (set-match-data (list начало (point)) t) 41 | (point))) 42 | ((eq (char-after) ?\") 43 | (let ((начало (point))) 44 | (forward-char) 45 | (let ((кончили nil)) 46 | (while (and (< (point) придел) (not кончили)) 47 | ;; СДЕЛАТЬ: поддержка экранирования внутри "лапочных" литералов 48 | (when (eq (char-after) ?\") 49 | (setq кончили t)) 50 | (forward-char))) 51 | (set-match-data (list начало (point)) t) 52 | (point))))) 53 | 54 | ;; СДЕЛАТЬ: подсветка многострочных «ёлочных» литералов. 55 | ;; Она почему-то не работает из коробки 56 | (defconst подсветка-хуя 57 | `((строковый-литерал-хуя . font-lock-string-face) 58 | (,(regexp-opt ключевые-слова-хуя 'symbols) . font-lock-keyword-face))) 59 | 60 | ;;;###autoload 61 | (define-derived-mode режим-хуя prog-mode "хуя" 62 | "Основной режим (анг. Major mode) для редактирования исходных файлов на языке ХУЯ." 63 | :syntax-table синтаксическая-таблица-режима-хуя 64 | (setq font-lock-defaults '(подсветка-хуя)) 65 | (setq-local comment-start "// ")) 66 | 67 | ;;;###autoload 68 | (add-to-list 'auto-mode-alist '("\\.хуя\\'" . режим-хуя)) 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Хороший Учебный Язык (ХУЯ) 2 | 3 | *Если Вам не нравится название языка, можете опустить букву Х, и называть его просто Учебным Языком. Но знайте — в таком случае язык уже не будет «Хорошим»! ;)* 4 | 5 | Проект по большей части вдохновлён, но не основан на Учебном Алгоритмическом Языке Андрея Петровича Ершова. Рекомендую не воспринимать данный проект всерьёз, т.к. он готовился как шутка к Первому Апреля. Не смотря на свою шуточность, это более менее полноценный язык, на котором можно даже что-то писать (см. папку [примеры](./примеры/)). 6 | 7 | Имейте ввиду, что т.к. у меня не было много времени, проект разрабатывался второпях, и содержит много багов и не законченых частей. Также заранее извиняюсь за отсутствие какой-либо нормальной документации. Если у меня будет время, я её добавлю в каком-нибудь виде. Наслаждайтесь! 8 | 9 | ## Быстрый Старт 10 | 11 | Вам потребуется установить компилятор [Rust](https://www.rust-lang.org/) и [fasm](https://flatassembler.net/). 12 | 13 | ```console 14 | $ rustc ./исходники/хуяк.rs 15 | ``` 16 | 17 | ### Компиляция в Исполняемый Файл 18 | 19 | На данный момент поддерживается только платформа Linux x86_64. 20 | 21 | ```console 22 | $ ./хуяк комп ./примеры/01-привет.хуя 23 | $ ./примеры/01-привет 24 | ``` 25 | 26 | Для других платформ можно попробовать Интерпретацию. 27 | 28 | ### Интерпретация 29 | 30 | Интерпретация просто опускает стадию генерации машинного кода из промежуточного представления (ПП) и тупо интерпретирует ПП. По идее, это должно быть кроссплатформенным, но я не гарантирую, что не добавлю что-нибудь платформо-зависимое в ПП в будущем. 31 | 32 | ```console 33 | $ ./хуяк интер ./примеры/01-привет.хуя 34 | ``` 35 | 36 | ## Источники 37 | 38 | - Wikipedia - Учебный алгоритмический язык - https://ru.wikipedia.org/wiki/Учебный_алгоритмический_язык (рус.) - проект по-большей части вдохновлён, но не основан на Учебном Алгоритмическом Языке Андрея Петровича Ершова. 39 | - Tsoding - Porth - https://gitlab.com/tsoding/porth (анг.) - очень много идей реализации были разработаны и опробованны мною еще в Porth. 40 | - flat assembler - https://flatassembler.net/ (анг.) - простой ассемблер способный генерировать минималистичные статические исполняемые файлы. 41 | - Félix Cloutier - x86 and amd64 instruction reference - https://www.felixcloutier.com/x86/ (анг.) - онлайн справочник по инструкциям процессора Intel x86. 42 | - ChromiumOS - Linux System Call Table - https://chromium.googlesource.com/chromiumos/docs/+/HEAD/constants/syscalls.md (анг.) - Таблица системных вызовов операционной системы Linux. 43 | - compiler.su - Шестнадцатиричные и двоичные константы http://compiler.su/shestnadtsatirichnye-i-dvoichnye-konstanty.php (рус.) - идея шестнадцатиричных литералов была взята от сюда. 44 | -------------------------------------------------------------------------------- /примеры/06-рейлиб.хуя: -------------------------------------------------------------------------------- 1 | вкл рейлиб; 2 | 3 | конст ЦВЕТ_ФОНА := 16%ФФ181818нат; 4 | конст ЦВЕТ_КРАСНЫЙ := 16%ФФ0000ФФнат; 5 | 6 | конст ШИРИНА := 50; 7 | конст ВЫСОТА := 50; 8 | 9 | // ВАЖНО! Т.к. мы не выравниваем структуры так, как это делает Си, эта 10 | // структура не может быть передана в Рейлиб. 11 | структ Вектор2 нч 12 | икс: вещ; 13 | игрек: вещ; 14 | кц 15 | 16 | конст ОБЪЁМ := 10; 17 | пер позиции: массив(ОБЪЁМ, Вектор2); 18 | пер дельты: массив(ОБЪЁМ, Вектор2); 19 | 20 | про случайное_вещественное(): вещ то 21 | вернуть получить_случайное_число(0, 100) как вещ / 100.0; 22 | 23 | про главная() нч 24 | установить_случайное_семя(69нат); 25 | 26 | для индекс := 0..ОБЪЁМ-1 нч 27 | позиции(индекс).икс := случайное_вещественное()*50.0; 28 | позиции(индекс).игрек := случайное_вещественное()*10.0; 29 | дельты(индекс).икс := случайное_вещественное()*400.0; 30 | дельты(индекс).игрек := случайное_вещественное()*200.0; 31 | кц 32 | 33 | открыть_окно(800, 600, адрес(«Привет, Raylib!»)); 34 | установить_целевую_частоту_кадров(60); 35 | пер пауза: лог := ложь; 36 | пока !пора_закрыть_окно() нч 37 | пер дельта_времени : вещ := получить_время_кадра(); 38 | пер ширина_экрана : вещ := получить_ширину_экрана() как вещ; 39 | пер высота_экрана : вещ := получить_высоту_экрана() как вещ; 40 | 41 | если нажата_клавиша(КЛАВИША_ПРОБЕЛ) то пауза := !пауза; 42 | 43 | начать_рисовать(); 44 | очистить_фон(ЦВЕТ_ФОНА); 45 | для индекс := 0..ОБЪЁМ-1 нч 46 | если !пауза нч 47 | пер новая_позиция: Вектор2; 48 | новая_позиция.икс := позиции(индекс).икс + дельты(индекс).икс*дельта_времени; 49 | если новая_позиция.икс -? 0.0 или новая_позиция.икс + ШИРИНА как вещ +? ширина_экрана 50 | то дельты(индекс).икс := -(дельты(индекс).икс); // СДЕЛАТЬ: можно ли как-то распарсить чтобы не нужны были скобки? 51 | иначе то позиции(индекс).икс := новая_позиция.икс; 52 | 53 | новая_позиция.игрек := позиции(индекс).игрек + дельты(индекс).игрек*дельта_времени; 54 | если новая_позиция.игрек -? 0.0 или новая_позиция.игрек + ВЫСОТА как вещ +? высота_экрана 55 | то дельты(индекс).игрек := -(дельты(индекс).игрек); 56 | иначе то позиции(индекс).игрек := новая_позиция.игрек; 57 | кц 58 | 59 | нарисовать_прямоугольник(позиции(индекс).икс как цел, 60 | позиции(индекс).игрек как цел, 61 | ШИРИНА, ВЫСОТА, ЦВЕТ_КРАСНЫЙ); 62 | 63 | кц 64 | закончить_рисовать(); 65 | кц 66 | закрыть_окно(); 67 | кц 68 | -------------------------------------------------------------------------------- /примеры/10-игра-жизнь.хуя.вывод: -------------------------------------------------------------------------------- 1 | _%__________________ 2 | __%_________________ 3 | %%%_________________ 4 | ____________________ 5 | ____________________ 6 | ____________________ 7 | ____________________ 8 | ____________________ 9 | ____________________ 10 | ____________________ 11 | 12 | ____________________ 13 | %_%_________________ 14 | _%%_________________ 15 | _%__________________ 16 | ____________________ 17 | ____________________ 18 | ____________________ 19 | ____________________ 20 | ____________________ 21 | ____________________ 22 | 23 | ____________________ 24 | __%_________________ 25 | %_%_________________ 26 | _%%_________________ 27 | ____________________ 28 | ____________________ 29 | ____________________ 30 | ____________________ 31 | ____________________ 32 | ____________________ 33 | 34 | ____________________ 35 | _%__________________ 36 | __%%________________ 37 | _%%_________________ 38 | ____________________ 39 | ____________________ 40 | ____________________ 41 | ____________________ 42 | ____________________ 43 | ____________________ 44 | 45 | ____________________ 46 | __%_________________ 47 | ___%________________ 48 | _%%%________________ 49 | ____________________ 50 | ____________________ 51 | ____________________ 52 | ____________________ 53 | ____________________ 54 | ____________________ 55 | 56 | ____________________ 57 | ____________________ 58 | _%_%________________ 59 | __%%________________ 60 | __%_________________ 61 | ____________________ 62 | ____________________ 63 | ____________________ 64 | ____________________ 65 | ____________________ 66 | 67 | ____________________ 68 | ____________________ 69 | ___%________________ 70 | _%_%________________ 71 | __%%________________ 72 | ____________________ 73 | ____________________ 74 | ____________________ 75 | ____________________ 76 | ____________________ 77 | 78 | ____________________ 79 | ____________________ 80 | __%_________________ 81 | ___%%_______________ 82 | __%%________________ 83 | ____________________ 84 | ____________________ 85 | ____________________ 86 | ____________________ 87 | ____________________ 88 | 89 | ____________________ 90 | ____________________ 91 | ___%________________ 92 | ____%_______________ 93 | __%%%_______________ 94 | ____________________ 95 | ____________________ 96 | ____________________ 97 | ____________________ 98 | ____________________ 99 | 100 | ____________________ 101 | ____________________ 102 | ____________________ 103 | __%_%_______________ 104 | ___%%_______________ 105 | ___%________________ 106 | ____________________ 107 | ____________________ 108 | ____________________ 109 | ____________________ 110 | 111 | ____________________ 112 | ____________________ 113 | ____________________ 114 | ____%_______________ 115 | __%_%_______________ 116 | ___%%_______________ 117 | ____________________ 118 | ____________________ 119 | ____________________ 120 | ____________________ 121 | -------------------------------------------------------------------------------- /исходники/типизация.rs: -------------------------------------------------------------------------------- 1 | use super::Результат; 2 | use std::collections::HashMap; 3 | use диагностика::*; 4 | use лексика::*; 5 | 6 | #[derive(Clone)] 7 | pub struct Поле { 8 | pub имя: Лексема, 9 | pub тип: Тип, 10 | pub смещение: usize, 11 | } 12 | 13 | #[derive(Clone)] 14 | pub struct Структура { 15 | pub имя: Лексема, 16 | pub размер: usize, 17 | pub поля: HashMap, 18 | } 19 | 20 | #[derive(PartialEq, Debug, Clone)] 21 | pub enum Тип { 22 | Нат8, 23 | Нат64, 24 | Цел64, 25 | Вещ32, 26 | Лог, 27 | Массив { размер: usize, тип_элемента: Box<Тип> }, 28 | Срез { тип_элемента: Box<Тип> }, 29 | Структура(String), 30 | } 31 | 32 | pub const СРЕЗ_РАЗМЕР_СМЕЩЕНИЕ: usize = 0; 33 | pub const СРЕЗ_АДРЕС_СМЕЩЕНИЕ: usize = 8; 34 | 35 | impl Тип { 36 | pub fn примитивный(&self) -> bool { 37 | match self { 38 | Тип::Цел64 | Тип::Нат8 | Тип::Нат64 | Тип::Вещ32 | Тип::Лог => true, 39 | Тип::Массив {..} | Тип::Срез {..} | Тип::Структура {..} => false, 40 | } 41 | } 42 | 43 | pub fn примитивное_знаковое_чтение(&self) -> Option { 44 | match self { 45 | Тип::Цел64 => Some(true), 46 | Тип::Нат8 | Тип::Нат64 | Тип::Вещ32 | Тип::Лог => Some(false), 47 | Тип::Массив {..} | Тип::Срез {..} | Тип::Структура {..} => None, 48 | } 49 | } 50 | 51 | pub fn текст(&self) -> String { 52 | match self { 53 | Тип::Цел64 => "цел64".to_string(), 54 | Тип::Нат8 => "нат8".to_string(), 55 | Тип::Нат64 => "нат64".to_string(), 56 | Тип::Вещ32 => "вещ32".to_string(), 57 | Тип::Лог => "лог".to_string(), 58 | Тип::Массив {тип_элемента, размер} => format!("массив({размер}, {тип_элемента})", тип_элемента = тип_элемента.текст()), 59 | Тип::Срез {тип_элемента} => format!("срез({тип_элемента})", тип_элемента = тип_элемента.текст()), 60 | Тип::Структура(имя) => имя.clone(), 61 | } 62 | } 63 | 64 | pub fn размер(&self, структуры: &HashMap) -> usize { 65 | match self { 66 | Тип::Нат8 => 1, 67 | Тип::Нат64 => 8, 68 | Тип::Цел64 => 8, 69 | Тип::Вещ32 => 4, 70 | Тип::Лог => 8, 71 | Тип::Массив {тип_элемента, размер} => тип_элемента.размер(структуры) * размер, 72 | Тип::Срез {..} => 16, // Два 64-х битных числа: указатель на начало и размер. 73 | Тип::Структура (имя) => { 74 | структуры 75 | .get(имя) 76 | .expect("Существование структуры должно быть уже проверено на этапе компиляции типа") 77 | .размер 78 | } 79 | } 80 | } 81 | } 82 | 83 | pub fn проверить_типы(лок: &Лок, ожидаемый_тип: &Тип, действительный_тип: &Тип) -> Результат<()> { 84 | if ожидаемый_тип == действительный_тип { 85 | Ok(()) 86 | } else { 87 | диагностика!(лок, "ОШИБКА", "Несоответствие типов данных. Ожидался тип «{ожидаемый}», но повстречался тип «{действительный}»", 88 | ожидаемый = ожидаемый_тип.текст(), 89 | действительный = действительный_тип.текст()); 90 | Err(()) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /исходники/диагностика.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | #[derive(Debug, Clone, PartialEq)] 4 | pub struct Лок { 5 | pub путь_к_файлу: PathBuf, 6 | pub строка: usize, 7 | pub столбец: usize, 8 | } 9 | 10 | macro_rules! здесь { 11 | () => {{ 12 | use std::path::PathBuf; 13 | ::диагностика::Лок { 14 | путь_к_файлу: PathBuf::from(file!()), 15 | строка: line!() as usize, 16 | столбец: column!() as usize, 17 | } 18 | }} 19 | } 20 | 21 | macro_rules! диагностика { 22 | ($лок:expr, $уровень:literal, $($аргы:tt)*) => {{ 23 | let ::диагностика::Лок{путь_к_файлу, строка, столбец} = $лок; 24 | let уровень = $уровень; 25 | eprint!("{путь_к_файлу}:{строка}:{столбец}: {уровень}: ", путь_к_файлу = путь_к_файлу.display()); 26 | eprintln!($($аргы)*); 27 | }}; 28 | } 29 | 30 | macro_rules! сделать { 31 | ($лок:expr, $($аргы:tt)*) => {{ 32 | диагностика!($лок, "СДЕЛАТЬ", $($аргы)*); 33 | диагностика!(&здесь!(), "СДЕЛАТЬ", "реализация находится здесь"); 34 | }}; 35 | } 36 | 37 | pub enum Род { 38 | Муж, 39 | Жен, 40 | Сред, 41 | } 42 | 43 | /// Существительное. 44 | pub struct Сущ { 45 | pub род: Род, 46 | pub текст: &'static str, 47 | } 48 | 49 | /// Числительные с существительными 50 | pub struct Чисущ { 51 | pub один: &'static str, 52 | pub два_три_четыре: &'static str, 53 | pub ноль_пять_много: &'static str, 54 | } 55 | 56 | impl Чисущ { 57 | pub fn текст(&self, число: usize) -> &'static str { 58 | // СДЕЛАТЬ: удостовериться, что учтены все случаи (я не говорю по-русски). 59 | match число { 60 | 1 => self.один, 61 | 2 | 3 | 4 => self.два_три_четыре, 62 | _ => if число < 20 { 63 | self.ноль_пять_много 64 | } else { 65 | self.текст(число%10) 66 | } 67 | } 68 | } 69 | } 70 | 71 | /// Глагол в прошедшем времени. 72 | /// 73 | /// Глаголы в прошелшем времени имеют разные окончания в зависимости 74 | /// от рода существительного, к которому они пренадлежат. Данный тип 75 | /// был создать чтобы учесть эту особенность. 76 | pub struct ПрошлыйГлагол { 77 | pub муж: &'static str, 78 | pub жен: &'static str, 79 | pub сред: &'static str, 80 | } 81 | 82 | impl ПрошлыйГлагол { 83 | pub fn отобразить(&self, род: &Род) -> &str { 84 | match род { 85 | Род::Муж => self.муж, 86 | Род::Жен => self.жен, 87 | Род::Сред => self.сред, 88 | } 89 | } 90 | } 91 | 92 | // СДЕЛАТЬ: Рассмотреть вариант использования стеммеров для генерации глаголов в прошедшем времени. 93 | // Можно взять стеммер из Snowball. 94 | 95 | pub const ГЛАГОЛ_ОЖИДАЛСЯ: ПрошлыйГлагол = ПрошлыйГлагол { 96 | муж: "ожидался", 97 | жен: "ожидалась", 98 | сред: "ожидалось", 99 | }; 100 | 101 | pub const ГЛАГОЛ_ПОВСТРЕЧАЛСЯ: ПрошлыйГлагол = ПрошлыйГлагол { 102 | муж: "повстречался", 103 | жен: "повстречалася", 104 | сред: "повстречалось", 105 | }; 106 | 107 | pub const _ГЛАГОЛ_НАЙДЕН: ПрошлыйГлагол = ПрошлыйГлагол { 108 | муж: "найден", 109 | жен: "найдена", 110 | сред: "найдено", 111 | }; 112 | 113 | pub const ЧИСУЩ_АРГУМЕНТ: Чисущ = Чисущ { 114 | один: "аргумент", 115 | два_три_четыре: "аргумента", 116 | ноль_пять_много: "аргументов", 117 | }; 118 | 119 | pub const ЧИСУЩ_ПАРАМЕТР: Чисущ = Чисущ { 120 | один: "параметр", 121 | два_три_четыре: "параметра", 122 | ноль_пять_много: "параметров", 123 | }; 124 | 125 | pub const ЧИСУЩ_БАЙТ: Чисущ = Чисущ { 126 | один: "байт", 127 | два_три_четыре: "байта", 128 | ноль_пять_много: "байт", 129 | }; 130 | 131 | pub const ЧИСУЩ_ИНСТРУКЦИЙ: Чисущ = Чисущ { 132 | один: "инструкция", 133 | два_три_четыре: "инструкции", 134 | ноль_пять_много: "инструкций", 135 | }; 136 | -------------------------------------------------------------------------------- /ПЛАН.txt: -------------------------------------------------------------------------------- 1 | - [x] Исправить порядок записи чтения параметров функции (см. тесты/тест.хуя) 2 | - [x] Реализовать возврат значений из процедур (см. тесты/тест.хуя) 3 | - [x] Реализовать ./примеры/06-рейлиб.хуя 4 | - [x] Синтаксис линковки библиотек 5 | - [x] Поддержка «вещ32» для ./примеры/06-рейлиб.хуя 6 | - [x] Исправить тест_вещественных_чисел() (см. тесты/тест.хуя) 7 | - [x] Реализовать тест_вещественных_чисел() для кодогенерации эльфа 8 | - [x] Приоритет бинопов 9 | - [x] Добавить отскакивание от стенок в ./примеры/06-рейлиб.хуя 10 | - [x] Вещественные литералы 11 | - [x] Инструкция останова 12 | - Правда, кодогенерации без неё и так хорошо. Возможно она будет полезна только для констатного исполнения. 13 | - [x] Кастомизируемый размер стека для интерпретации 14 | - [x] Индексировать массивы круглыми скобками 15 | - Так мы 100% избавляемся от переключения раскладки для набора квадратных скобок. 16 | - Плюс такой же синтаксис имеет Ada. 17 | - [x] Оба вида инструкций вызова функций должны подчищать за собой аргументы. 18 | - В данный момент так делает только вызов внешней процедуры, что создает кучу проблем для компилятора. 19 | - Скомпилировать такую процедуру не сложно, а вот интерпретация усложняется. 20 | - А может тогда в теле функции сбрасывать элементы? Не получится, у нас там адрес возврата лежит. 21 | - Походу надо снова рассматривать идею второго стека. 22 | - Реализовал второй стек. Проблема иррелевантна. 23 | - [x] Строки и срезы как временные объекты. 24 | - [x] Рекурсия 25 | - [x] Присваивание со сложными левосторонними выражениями 26 | - [x] Структуры 27 | - [x] Локальные переменные 28 | - [x] Инициализация локальных переменных 29 | - [x] Локальные массивы 30 | - [x] Локальные константы 31 | - [x] Циклы «для» 32 | - [x] Объявление переменных в цикле «для» 33 | - [x] Исправить сегфолт при выделении локальной переменной в цикле «для» 34 | - [x] Вложенное индексирование 35 | - [x] Отрицательные числа (Знаковые целые) 36 | - [x] Типизированные литералы 37 | - [x] Game of Life 38 | - [x] Rule110 39 | - [x] Типизированные константы 40 | - [x] Через интерпретацию ПП 41 | - [x] Многострочные комментарии 42 | - [x] Не забудь избавиться от прямого доступа к символам, чтобы случайно не крашнуться. 43 | - [x] «для» должен неявно объявлять переменную 44 | - [x] Операторы сравнения 45 | - [x] Экранирование «ёлочек» 46 | - [x] Switch-case-ы в каком-виде виде («вилка») 47 | - [x] Шестнадцатеричные литералы (для примера рейлиб) 48 | - [x] Выражение::ЦепочкаВызовов 49 | - [x] Массивы в полях структур 50 | - [x] Все бинопы для всех релевантных типов в правой части 51 | - [x] НеРавно/Равно 52 | - [x] Меньше/Больше/МеньшеРавно/БольшеРавно 53 | - [x] и/или, добавить «либо» (исключающее или) 54 | - [x] сложение/вычитание/умножение/деление/остаток 55 | - [x] конвертация между типами («как») 56 | - [x] знаковые битовые смещения 57 | - [x] унарный минус 58 | - [x] Все бинопы для всех релевантных типов в левой части 59 | - [x] Интерпретация всех недостающих инструкций 60 | - [x] Кодогенерация всех недостающих инструкций 61 | - [x] сделать!(вызываемое.лок(), "Индексация срезов из сложных выражений"); 62 | - [x] сделать!(&имя.лок, "Индексация срезов в левой части присваивания"); 63 | - [ ] Доработать интринсики 64 | - [ ] «ввод» 65 | - [ ] «срез» 66 | - [ ] «сисвызов» 67 | - [ ] «печать» 68 | - [ ] Создание новых срезов по адресу и типу элементов 69 | - [ ] ... 70 | - [ ] Поддержка всех релевантных примитивных параметров для внешних процедур 71 | - [ ] Печать вещественных чисел 72 | - [ ] Что дальше? 73 | 74 | - Низкий приоритет 75 | - [ ] Небесполезные операции сравнения срезов. 76 | - [ ] Аналоги операций выхода из циклов (continue, break) 77 | - [ ] Провека, что все потоки исполнения возвращают значение. 78 | - [ ] Выравнивание структур как в Си 79 | - [ ] WebAssembly 80 | - [ ] Не прерывай компиляцию из-за одной лишь ошибки. 81 | - [ ] Перечисления в каком-нибудь виде 82 | - [ ] Динамическая память в каком-нибудь виде 83 | - [ ] Передача переменных по ссылке 84 | - [ ] Индексирование строковых литералов (печать(«Q»(0) как нат8)); 85 | - [ ] Индексирование строковых констант (конст ы := «Q»; печать(ы(0) как нат8);); 86 | - Это пока невозможно в силу того, что строковый литерал выделяется в памяти временной машины и теряется 87 | - [ ] Переменная «результат» как в Паскале. 88 | - Если есть передача аргументов по-ссылке, то оно особо и не нужно. 89 | -------------------------------------------------------------------------------- /тест.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -xe 4 | 5 | ./собрать.sh 6 | mkdir -p ./сборка/примеры/ 7 | mkdir -p ./сборка/тесты/ 8 | 9 | test_fasm() { 10 | ./сборка/хуяк комп -вывод ./сборка/примеры/01-привет ./примеры/01-привет.хуя 11 | ./сборка/хуяк комп -вывод ./сборка/примеры/02-цикл ./примеры/02-цикл.хуя 12 | ./сборка/хуяк комп -вывод ./сборка/примеры/03-имя ./примеры/03-имя.хуя 13 | ./сборка/хуяк комп -вывод ./сборка/примеры/04-физз-базз ./примеры/04-физз-базз.хуя 14 | ./сборка/хуяк комп -вывод ./сборка/примеры/05-фибоначчи ./примеры/05-фибоначчи.хуя 15 | ./сборка/хуяк комп -вывод ./сборка/примеры/06-рейлиб ./примеры/06-рейлиб.хуя 16 | ./сборка/хуяк комп -вывод ./сборка/примеры/07-рекурсия ./примеры/07-рекурсия.хуя 17 | ./сборка/хуяк комп -вывод ./сборка/примеры/08-структуры ./примеры/08-структуры.хуя 18 | ./сборка/хуяк комп -вывод ./сборка/примеры/09-правило110 ./примеры/09-правило110.хуя 19 | ./сборка/хуяк комп -вывод ./сборка/примеры/10-игра-жизнь ./примеры/10-игра-жизнь.хуя 20 | ./сборка/хуяк комп -вывод ./сборка/тесты/тест ./тесты/тест.хуя 21 | 22 | ./сборка/примеры/01-привет > ./сборка/примеры/01-привет.хуя.вывод.фазм && diff -u ./примеры/01-привет.хуя.вывод ./сборка/примеры/01-привет.хуя.вывод.фазм 23 | ./сборка/примеры/02-цикл > ./сборка/примеры/02-цикл.хуя.вывод.фазм && diff -u ./примеры/02-цикл.хуя.вывод ./сборка/примеры/02-цикл.хуя.вывод.фазм 24 | echo 'Алексей' | ./сборка/примеры/03-имя > ./сборка/примеры/03-имя.хуя.вывод.фазм && diff -u ./примеры/03-имя.хуя.вывод ./сборка/примеры/03-имя.хуя.вывод.фазм 25 | ./сборка/примеры/04-физз-базз > ./сборка/примеры/04-физз-базз.хуя.вывод.фазм && diff -u ./примеры/04-физз-базз.хуя.вывод ./сборка/примеры/04-физз-базз.хуя.вывод.фазм 26 | ./сборка/примеры/05-фибоначчи > ./сборка/примеры/05-фибоначчи.хуя.вывод.фазм && diff -u ./примеры/05-фибоначчи.хуя.вывод ./сборка/примеры/05-фибоначчи.хуя.вывод.фазм 27 | #./сборка/примеры/06-рейлиб > ./сборка/примеры/06-рейлиб.хуя.вывод.фазм && diff -u ./примеры/06-рейлиб.хуя.вывод ./сборка/примеры/06-рейлиб.хуя.вывод.фазм 28 | ./сборка/примеры/07-рекурсия > ./сборка/примеры/07-рекурсия.хуя.вывод.фазм && diff -u ./примеры/07-рекурсия.хуя.вывод ./сборка/примеры/07-рекурсия.хуя.вывод.фазм 29 | ./сборка/примеры/08-структуры > ./сборка/примеры/08-структуры.хуя.вывод.фазм && diff -u ./примеры/08-структуры.хуя.вывод ./сборка/примеры/08-структуры.хуя.вывод.фазм 30 | ./сборка/примеры/09-правило110 > ./сборка/примеры/09-правило110.хуя.вывод.фазм && diff -u ./примеры/09-правило110.хуя.вывод ./сборка/примеры/09-правило110.хуя.вывод.фазм 31 | ./сборка/примеры/10-игра-жизнь > ./сборка/примеры/10-игра-жизнь.хуя.вывод.фазм && diff -u ./примеры/10-игра-жизнь.хуя.вывод ./сборка/примеры/10-игра-жизнь.хуя.вывод.фазм 32 | ./сборка/тесты/тест > ./сборка/тесты/тест.хуя.вывод.фазм && diff -u ./тесты/тест.хуя.вывод ./сборка/тесты/тест.хуя.вывод.фазм 33 | } 34 | 35 | test_inter() { 36 | ./сборка/хуяк интер ./примеры/01-привет.хуя > ./сборка/примеры/01-привет.хуя.вывод.интер && diff -u ./примеры/01-привет.хуя.вывод ./сборка/примеры/01-привет.хуя.вывод.интер 37 | ./сборка/хуяк интер ./примеры/02-цикл.хуя > ./сборка/примеры/02-цикл.хуя.вывод.интер && diff -u ./примеры/02-цикл.хуя.вывод ./сборка/примеры/02-цикл.хуя.вывод.интер 38 | echo 'Алексей' | ./сборка/хуяк интер ./примеры/03-имя.хуя > ./сборка/примеры/03-имя.хуя.вывод.интер && diff -u ./примеры/03-имя.хуя.вывод ./сборка/примеры/03-имя.хуя.вывод.интер 39 | ./сборка/хуяк интер ./примеры/04-физз-базз.хуя > ./сборка/примеры/04-физз-базз.хуя.вывод.интер && diff -u ./примеры/04-физз-базз.хуя.вывод ./сборка/примеры/04-физз-базз.хуя.вывод.интер 40 | ./сборка/хуяк интер ./примеры/05-фибоначчи.хуя > ./сборка/примеры/05-фибоначчи.хуя.вывод.интер && diff -u ./примеры/05-фибоначчи.хуя.вывод ./сборка/примеры/05-фибоначчи.хуя.вывод.интер 41 | #./сборка/хуяк интер ./примеры/06-рейлиб.хуя > ./сборка/примеры/06-рейлиб.хуя.вывод.интер && diff -u ./примеры/06-рейлиб.хуя.вывод ./сборка/примеры/06-рейлиб.хуя.вывод.интер 42 | ./сборка/хуяк интер ./примеры/07-рекурсия.хуя > ./сборка/примеры/07-рекурсия.хуя.вывод.интер && diff -u ./примеры/07-рекурсия.хуя.вывод ./сборка/примеры/07-рекурсия.хуя.вывод.интер 43 | ./сборка/хуяк интер ./примеры/08-структуры.хуя > ./сборка/примеры/08-структуры.хуя.вывод.интер && diff -u ./примеры/08-структуры.хуя.вывод ./сборка/примеры/08-структуры.хуя.вывод.интер 44 | ./сборка/хуяк интер ./примеры/09-правило110.хуя > ./сборка/примеры/09-правило110.хуя.вывод.интер && diff -u ./примеры/09-правило110.хуя.вывод ./сборка/примеры/09-правило110.хуя.вывод.интер 45 | ./сборка/хуяк интер ./примеры/10-игра-жизнь.хуя > ./сборка/примеры/10-игра-жизнь.хуя.вывод.интер && diff -u ./примеры/10-игра-жизнь.хуя.вывод ./сборка/примеры/10-игра-жизнь.хуя.вывод.интер 46 | ./сборка/хуяк интер ./тесты/тест.хуя > ./сборка/тесты/тест.хуя.вывод.интер && diff -u ./тесты/тест.хуя.вывод ./сборка/тесты/тест.хуя.вывод.интер 47 | } 48 | 49 | test_fasm 50 | test_inter 51 | -------------------------------------------------------------------------------- /тесты/тест.хуя: -------------------------------------------------------------------------------- 1 | вкл прелюдия; 2 | 3 | про тест_передачи_аргументов_функции(а: нат, б: нат) то 4 | печать(«Передача аргументов функции: », а + б, «\н»); 5 | 6 | про тест_порядка_передачи_аргументов_функции(а: нат, б: нат, в: нат, г: нат) то 7 | печать(«Порядок передачи аргументов функции: », а, « », б, « », в, « », г, « », «\н»); 8 | 9 | про тест_возврата_значения(а: нат, б: нат, в: нат): нат то 10 | вернуть а + б*в; 11 | 12 | про тест_вещественных_чисел() нч 13 | печать(«Вещественная арифметика: », (17.0*2.0 + 35.0) как нат, «\н»); 14 | печать(«Вещественное отрицание: », -69.0 -? 0.0, «\н»); 15 | печать(«Вещественная сравнение: », 69.0 -? 420.0, « », 69.0 +? 420.0, «\н»); 16 | кц 17 | 18 | про баг_при_выделении_локальной_переменной_в_цикле_для() то // некорректно обозначались области видимости 19 | для _ := 1..3 то пер а: нат; 20 | 21 | про вернуть_массив(): массив(10, нат) нч 22 | пер результат: массив(10, нат); 23 | результат(0) := 69нат; 24 | вернуть результат; 25 | кц 26 | 27 | про печать_отрицательных_чисел(число: цел) нч 28 | печать(«Печать отрицательных чисел: », число, «\н»); 29 | кц 30 | 31 | про логическое_и() нч 32 | печать(«логическое и:\н»); 33 | печать(« ложь и ложь == », ложь и ложь, «\н»); 34 | печать(« истина и ложь == », истина и ложь, «\н»); 35 | печать(« ложь и истина == », ложь и истина, «\н»); 36 | печать(« истина и истина == », истина и истина, «\н»); 37 | кц 38 | 39 | про взаимодействие_лапок_и_ёлочек() нч 40 | печать(«Взаимодействие «ёлочек» и "лапок"\н»); 41 | печать(« », «""», «\н»); 42 | печать(« », "«»", «\н»); 43 | кц 44 | 45 | про чтение_нат8() нч 46 | пер ы : строка := «Q»; 47 | печать(«Чтение нат8: », ы(0) как нат, «\н»); 48 | кц 49 | 50 | про печать_человекочитаемого_числа(число: цел) нч 51 | печать(« »); 52 | вилка число нч 53 | когда 0 то печать(«ноль\н»); 54 | когда 1 то печать(«один\н»); 55 | когда 2 то печать(«два\н»); 56 | когда любое то печать(«много\н»); 57 | кц 58 | кц 59 | 60 | про проверить_вилку() нч 61 | печать(«Проверка вилки:\н»); 62 | печать_человекочитаемого_числа(0); 63 | печать_человекочитаемого_числа(1); 64 | печать_человекочитаемого_числа(2); 65 | печать_человекочитаемого_числа(3); 66 | печать_человекочитаемого_числа(69); 67 | кц 68 | 69 | конст ОБЪЁМ_ПОЗИЦИЙ := 10; 70 | 71 | структ Вектор2 нч 72 | икс: вещ; 73 | игрек: вещ; 74 | кц 75 | 76 | про печать_вектор2(поз: Вектор2) нч 77 | печать(«(», поз.икс как цел, «, », поз.игрек как цел, «)»); 78 | кц 79 | 80 | структ Позиции нч 81 | позиции: массив(ОБЪЁМ_ПОЗИЦИЙ, Вектор2); 82 | кц 83 | 84 | про индексация_массивов_вложенных_в_структуру() нч 85 | пер позиции: Позиции; 86 | 87 | для индекс := 1..ОБЪЁМ_ПОЗИЦИЙ нч 88 | позиции.позиции(индекс - 1).икс := индекс как вещ; 89 | позиции.позиции(индекс - 1).игрек := индекс как вещ; 90 | кц 91 | 92 | печать(«Индексация массивов вложенных в структуру:\н»); 93 | для индекс := 1..ОБЪЁМ_ПОЗИЦИЙ нч 94 | печать(« »); 95 | печать_вектор2(позиции.позиции(индекс - 1)); 96 | печать(«\н»); 97 | кц 98 | кц 99 | 100 | про итерация_строки_по_байтам(сообщение: строка) нч 101 | печать("Итерация строки «",сообщение,"» по байтам: \н"); 102 | для индекс := 1..размер(сообщение) нч 103 | печать(« », сообщение(индекс-1) как нат64, «\н»); 104 | кц 105 | кц 106 | 107 | про тест_подбрить_строку_слева(сообщение: строка) то 108 | печать("подбрить_строку_слева(«",сообщение,"») = «", подбрить_строку_слева(сообщение), "»\н"); 109 | 110 | структ Человек нч 111 | имя: строка; 112 | кц 113 | 114 | про индексация_срезов_внутри_структуры() нч 115 | пер человек: Человек; 116 | человек.имя := «alexey»; 117 | для индекс := 1..размер(человек.имя) нч 118 | человек.имя(индекс-1) := верхний_регистр_аскии(человек.имя(индекс-1)); 119 | кц 120 | печать(«Индексация срезов внутри структуры: », человек.имя, «\н»); 121 | кц 122 | 123 | структ Какая_То_Структура нч 124 | число: цел; 125 | еще_число: цел; 126 | кц 127 | 128 | про печать_какой_то_структуры(структура: Какая_То_Структура) нч 129 | печать(«(число: », структура.число, «, еще_число: », структура.еще_число, «)»); 130 | кц 131 | 132 | про сравнить_какие_то_структуры(одна: Какая_То_Структура, вторая: Какая_То_Структура) нч 133 | печать(« »); 134 | печать_какой_то_структуры(одна); 135 | печать(« = »); 136 | печать_какой_то_структуры(вторая); 137 | печать(« => »); 138 | печать(одна = вторая, «\н»); 139 | кц 140 | 141 | про сравнение_структур() нч 142 | пер одна: Какая_То_Структура; 143 | одна.число := 69; 144 | одна.еще_число := 420; 145 | 146 | пер вторая: Какая_То_Структура; 147 | вторая.число := 69; 148 | вторая.еще_число := 420; 149 | 150 | печать(«Сравнение структур:\н»); 151 | сравнить_какие_то_структуры(одна, вторая); 152 | 153 | вторая.еще_число := 1337; 154 | сравнить_какие_то_структуры(одна, вторая); 155 | кц 156 | 157 | про тест_строки_равны(одна: строка, другая: строка) то 158 | печать(" «",одна,"» = «",другая,"» => ",строки_равны(одна, другая),«\н»); 159 | 160 | про сравнение_строк() нч 161 | печать(«Сравнение строк:\н»); 162 | тест_строки_равны(«Hello», «World»); 163 | тест_строки_равны(«Foo», «Foo»); 164 | кц 165 | 166 | про проверить_логические_конвертации() нч 167 | печать(«Проверить логические конвертации:\н»); 168 | печать(« », 0 как лог, «\н»); 169 | печать(« », 1 как лог, «\н»); 170 | печать(« », -1 как лог, «\н»); 171 | печать(« », 69 как лог, «\н»); 172 | печать(« », 69 как лог как цел, «\н»); 173 | кц 174 | 175 | про вернуть_строку(): строка то вернуть «E»; 176 | 177 | про индексация_срезов_слева_и_справа() нч 178 | пер имя: строка := «alexey»; 179 | для индекс := 1..размер(имя) нч 180 | имя(индекс-1) := верхний_регистр_аскии(имя(индекс-1)); 181 | кц 182 | печать(«Индексация срезов слева и справа: », имя, «\н»); 183 | кц 184 | 185 | про главная() нч 186 | печать(«Печать чисел: », 0, «, », 69, «, », 1234567890, «\н»); 187 | печать(«Печать логических: », 69 = 69, «, », 69 = 420, «\н»); 188 | тест_передачи_аргументов_функции(34нат, 35нат); 189 | тест_порядка_передачи_аргументов_функции(1нат, 2нат, 3нат, 4нат); 190 | печать(«Тест возврата значения: », тест_возврата_значения(35нат, 17нат, 2нат), «\н»); 191 | тест_вещественных_чисел(); 192 | баг_при_выделении_локальной_переменной_в_цикле_для(); 193 | печать(«Индексация сложных выражений: », вернуть_массив()(0), «\н»); 194 | печать_отрицательных_чисел(-69); 195 | логическое_и(); 196 | взаимодействие_лапок_и_ёлочек(); 197 | чтение_нат8(); 198 | проверить_вилку(); 199 | индексация_массивов_вложенных_в_структуру(); 200 | итерация_строки_по_байтам(«Hello, World»); 201 | тест_подбрить_строку_слева(« Привет »); 202 | тест_подбрить_строку_слева(« »); 203 | тест_подбрить_строку_слева(«»); 204 | индексация_срезов_внутри_структуры(); 205 | сравнение_структур(); 206 | сравнение_строк(); 207 | проверить_логические_конвертации(); 208 | печать(«Индексирование срезу из процедуры: », вернуть_строку()(0) как нат, «\н»); 209 | индексация_срезов_слева_и_справа(); 210 | печать(«Отрицательный остаток: », (-1) ост 100, «\н»); 211 | печать(«Отрицательное деление: », (-1) / 100, «\н»); 212 | печать(«Отрицательное умножение: », (-1) * 100, «\н»); 213 | печать(«Знаковое деление: », (800.0 / 20.0) как цел, «\н»); 214 | печать(«Конвертация вещ в нат: », (255.0 - 128.0) как нат, «\н»); 215 | кц 216 | -------------------------------------------------------------------------------- /исходники/хуяк.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::env; 3 | use std::io; 4 | use std::process::{Command, ExitCode, Stdio}; 5 | use std::path::{Path, PathBuf}; 6 | 7 | #[path="./диагностика.rs"] 8 | #[macro_use] 9 | mod диагностика; 10 | #[path="./лексика.rs"] 11 | mod лексика; 12 | #[path="./синтаксис.rs"] 13 | mod синтаксис; 14 | #[path="./компилятор.rs"] 15 | mod компилятор; 16 | #[path="./интерпретатор.rs"] 17 | mod интерпретатор; 18 | #[path="./типизация.rs"] 19 | mod типизация; 20 | #[path="./фазм.rs"] 21 | mod фазм; 22 | 23 | use диагностика::Лок; 24 | use лексика::Лексер; 25 | use компилятор::{Программа, ТочкаВхода}; 26 | use интерпретатор::Машина; 27 | 28 | type Результат<Тэ> = Result<Тэ, ()>; 29 | 30 | fn прочитать_содержимое_файла(путь_к_файлу: &Path, лок: Option<Лок>) -> Результат> { 31 | fs::read_to_string(путь_к_файлу) 32 | .map(|содержимое| содержимое.chars().collect()) 33 | .map_err(|ошибка| { 34 | // СДЕЛАТЬ: локализировать те ошибки, которые возможно. 35 | match ошибка.kind() { 36 | io::ErrorKind::NotFound => match лок { 37 | Some(лок) => диагностика!(лок, "ОШИБКА", "файл «{путь_к_файлу}» не найден", путь_к_файлу = путь_к_файлу.display()), 38 | None => eprintln!("ОШИБКА: файл «{путь_к_файлу}» не найден", путь_к_файлу = путь_к_файлу.display()), 39 | } 40 | _ => match лок { 41 | Some(лок) => диагностика!(лок, "ОШИБКА", "не получилось прочитать файл «{путь_к_файлу}»: {ошибка}", путь_к_файлу = путь_к_файлу.display()), 42 | None => eprintln!("ОШИБКА: не получилось прочитать файл «{путь_к_файлу}»: {ошибка}", путь_к_файлу = путь_к_файлу.display()), 43 | } 44 | } 45 | }) 46 | } 47 | 48 | struct Команда { 49 | имя: &'static str, 50 | сигнатура: &'static str, 51 | описание: &'static str, 52 | запустить: fn(программа: &str, аргы: env::Args) -> Результат<()>, 53 | } 54 | 55 | // СДЕЛАТЬ: может имеет смысл реализовать генерацию бинарников из 56 | // ассемблера ПП? Будет очень удобно отлаживать генерацию машинного 57 | // кода, когда должный синтаксис еще не реализован. 58 | 59 | const КОМАНДЫ: &[Команда] = &[ 60 | Команда { 61 | имя: "комп", 62 | сигнатура: "[-пуск] [-вывод <файл-вывода>] <файл-ввода>", 63 | описание: "Скомпилировать файлы исходного кода в исполняемый файл для платформы Linux x86_64.", 64 | запустить: |программа, mut аргы| { 65 | let mut пуск = false; 66 | let mut файл_ввода = None; 67 | let mut файл_вывода = None; 68 | 69 | loop { 70 | match аргы.next() { 71 | Some(арг) => match арг.as_str() { 72 | "-пуск" => пуск = true, 73 | "-вывод" => { 74 | match аргы.next() { 75 | Some(арг) => файл_вывода = Some(арг), 76 | None => { 77 | eprintln!("ОШИБКА: Флаг «{арг}» требует значение."); 78 | return Err(()) 79 | } 80 | } 81 | } 82 | _ => { 83 | if файл_ввода.is_some() { 84 | пример(программа); 85 | eprintln!("ОШИБКА: Неизвестный флаг «{арг}»."); 86 | return Err(()) 87 | } else { 88 | файл_ввода = Some(арг) 89 | } 90 | } 91 | } 92 | None => break, 93 | } 94 | } 95 | 96 | let файл_ввода = if let Some(файл_ввода) = файл_ввода { 97 | PathBuf::from(файл_ввода) 98 | } else { 99 | пример(программа); 100 | eprintln!("ОШИБКА: требуется файл с программой!"); 101 | return Err(()); 102 | }; 103 | 104 | let mut программа = Программа::default(); 105 | let содержимое: Vec = прочитать_содержимое_файла(&файл_ввода, None)?; 106 | let mut лекс = Лексер::новый(&файл_ввода, &содержимое); 107 | программа.скомпилировать_лексемы(&mut лекс)?; 108 | программа.завершить_компиляцию(); 109 | let процедура_точки_входа = "главная"; 110 | if let Some(процедура) = программа.имена.процедуры.get(процедура_точки_входа) { 111 | let точка_входа = match процедура.точка_входа { 112 | ТочкаВхода::Внутреняя{адрес} => адрес, 113 | ТочкаВхода::Внешняя{..} => { 114 | диагностика!(&процедура.имя.лок, "ОШИБКА", "точкой входа в программу не может быть внешняя процедура"); 115 | return Err(()) 116 | } 117 | }; 118 | 119 | let путь_к_исполняемому = файл_вывода 120 | .map(|файл_вывода| PathBuf::from(файл_вывода)) 121 | .unwrap_or_else(|| Path::new("./").join(&файл_ввода).with_extension("")); 122 | фазм::сгенерировать_исполняемый_файл(&путь_к_исполняемому, &программа.пп, точка_входа)?; 123 | 124 | if пуск { 125 | println!("ИНФО: запускаем «{путь_к_исполняемому}»", путь_к_исполняемому = путь_к_исполняемому.display()); 126 | let код_выхода = Command::new(&путь_к_исполняемому) 127 | .stdout(Stdio::inherit()) 128 | .spawn() 129 | .map_err(|ошибка| { 130 | eprintln!("ОШИБКА: не получилось запустить дочерний процесс {путь_к_исполняемому}: {ошибка}", 131 | путь_к_исполняемому = путь_к_исполняемому.display()); 132 | })? 133 | .wait() 134 | .map_err(|ошибка| { 135 | eprintln!("ОШИБКА: что-то пошло не так пока мы ждали завершения дочернего процесса {путь_к_исполняемому 136 | }: {ошибка}", 137 | путь_к_исполняемому = путь_к_исполняемому.display()); 138 | })?; 139 | #[cfg(all(unix))] { 140 | use std::os::unix::process::ExitStatusExt; 141 | if let Some(сигнал) = код_выхода.signal() { 142 | eprintln!("ОШИБКА: дочерний процесс принудительно завершен сигналом {сигнал}"); 143 | return Err(()) 144 | } 145 | } 146 | match код_выхода.code() { 147 | Some(0) => {} 148 | Some(код) => if код != 0 { 149 | eprintln!("ОШИБКА: дочерний процесс завершился с кодом {код}"); 150 | return Err(()) 151 | } 152 | None => unreachable!() 153 | } 154 | } 155 | Ok(()) 156 | } else { 157 | eprintln!("ОШИБКА: процедура точки входа «{процедура_точки_входа}» не найдена! Пожалуйста определите её!"); 158 | Err(()) 159 | } 160 | }, 161 | }, 162 | Команда { 163 | имя: "интер", 164 | сигнатура: "[-отлад] <путь_к_файлу>", 165 | описание: "Интерпретировать Промежуточное Представление скомпилированного файла", 166 | запустить: |программа, mut аргы| { 167 | let mut режим_отладки = false; 168 | let mut путь_к_файлу = None; 169 | 170 | loop { 171 | match аргы.next() { 172 | Some(арг) => match арг.as_str() { 173 | "-отлад" => режим_отладки = true, 174 | _ => { 175 | if путь_к_файлу.is_some() { 176 | пример(программа); 177 | eprintln!("ОШИБКА: неизвестный флаг «{арг}»"); 178 | return Err(()) 179 | } else { 180 | путь_к_файлу = Some(арг) 181 | } 182 | } 183 | } 184 | None => break, 185 | } 186 | } 187 | 188 | let путь_к_файлу = if let Some(путь_к_файлу) = путь_к_файлу { 189 | PathBuf::from(путь_к_файлу) 190 | } else { 191 | пример(программа); 192 | eprintln!("ОШИБКА: требуется файл с программой!"); 193 | return Err(()); 194 | }; 195 | 196 | let содержимое: Vec = прочитать_содержимое_файла(&путь_к_файлу, None)?; 197 | let mut лекс = Лексер::новый(&путь_к_файлу, &содержимое); 198 | let mut программа = Программа::default(); 199 | программа.скомпилировать_лексемы(&mut лекс)?; 200 | программа.завершить_компиляцию(); 201 | let процедура_точки_входа = "главная"; 202 | if let Some(процедура) = программа.имена.процедуры.get(процедура_точки_входа) { 203 | let точка_входа = match процедура.точка_входа { 204 | ТочкаВхода::Внутреняя{адрес} => адрес, 205 | ТочкаВхода::Внешняя{..} => { 206 | диагностика!(&процедура.имя.лок, "ОШИБКА", "точкой входа в программу не может быть внешняя процедура"); 207 | return Err(()) 208 | } 209 | }; 210 | let объём_второго_стека = 1_000_000; 211 | let mut машина = Машина::новая(&программа.пп, объём_второго_стека); 212 | машина.интерпретировать(&программа.имена, точка_входа, режим_отладки) 213 | } else { 214 | eprintln!("ОШИБКА: процедура точки входа «{процедура_точки_входа}» не найдена! Пожалуйста определите её!"); 215 | Err(()) 216 | } 217 | }, 218 | }, 219 | Команда { 220 | имя: "пп", 221 | сигнатура: "<путь_к_файлу>", 222 | описание: "Напечатать Промежуточное Представление скомпилированной программы", 223 | запустить: |программа, mut аргы| { 224 | let путь_к_файлу = if let Some(путь_к_файлу) = аргы.next() { 225 | PathBuf::from(путь_к_файлу) 226 | } else { 227 | пример(программа); 228 | eprintln!("ОШИБКА: требуется файл с программой!"); 229 | return Err(()); 230 | }; 231 | let содержимое: Vec = прочитать_содержимое_файла(&путь_к_файлу, None)?; 232 | let mut лекс = Лексер::новый(&путь_к_файлу, &содержимое); 233 | let mut программа = Программа::default(); 234 | программа.скомпилировать_лексемы(&mut лекс)?; 235 | программа.завершить_компиляцию(); 236 | let процедура_точки_входа = "главная"; 237 | if let Some(процедура) = программа.имена.процедуры.get(процедура_точки_входа) { 238 | let точка_входа = match процедура.точка_входа { 239 | ТочкаВхода::Внутреняя{адрес} => адрес, 240 | ТочкаВхода::Внешняя{..} => { 241 | диагностика!(&процедура.имя.лок, "ОШИБКА", "точкой входа в программу не может быть внешняя процедура"); 242 | return Err(()) 243 | } 244 | }; 245 | 246 | программа.пп.вывалить(точка_входа); 247 | Ok(()) 248 | } else { 249 | eprintln!("ОШИБКА: процедура точки входа «{процедура_точки_входа}» не найдена! Пожалуйста определите её!"); 250 | Err(()) 251 | } 252 | }, 253 | }, 254 | Команда { 255 | имя: "справка", 256 | сигнатура: "[команда]", 257 | описание: "Напечатать справку по программе и командам", 258 | запустить: |программа, mut аргы| { 259 | if let Some(_имя_команды) = аргы.next() { 260 | todo!("СДЕЛАТЬ: справка по отдельным командам"); 261 | } else { 262 | пример(программа); 263 | Ok(()) 264 | } 265 | }, 266 | }, 267 | ]; 268 | 269 | fn пример(программа: &str) { 270 | eprintln!("Пример: {программа} <команда> [аргументы]"); 271 | eprintln!("Команды:"); 272 | let ширина_столбца_имени = КОМАНДЫ.iter().map(|команда| { 273 | команда.имя.chars().count() 274 | }).max().unwrap_or(0); 275 | let ширина_столбца_сигнатуры = КОМАНДЫ.iter().map(|команда| { 276 | команда.сигнатура.chars().count() 277 | }).max().unwrap_or(0); 278 | for Команда{имя, сигнатура, описание, ..} in КОМАНДЫ.iter() { 279 | // СДЕЛАТЬ: переносить длинные описания на новую строку. 280 | eprintln!(" {имя:ширина_столбца_имени$} {сигнатура:ширина_столбца_сигнатуры$} - {описание}"); 281 | } 282 | } 283 | 284 | fn главная() -> Результат<()> { 285 | let mut аргы = env::args(); 286 | let программа = аргы.next().expect("программа"); 287 | 288 | let имя_команды = if let Some(имя_команды) = аргы.next() { 289 | имя_команды 290 | } else { 291 | пример(&программа); 292 | eprintln!("ОШИБКА: требуется команда!"); 293 | return Err(()); 294 | }; 295 | 296 | if let Some(команда) = КОМАНДЫ.iter().find(|команда| имя_команды == команда.имя) { 297 | (команда.запустить)(&программа, аргы) 298 | } else { 299 | пример(&программа); 300 | eprintln!("ОШИБКА: неизвестная команда «{имя_команды}»"); 301 | Err(()) 302 | } 303 | } 304 | 305 | fn main() -> ExitCode { 306 | match главная() { 307 | Ok(()) => ExitCode::SUCCESS, 308 | Err(()) => ExitCode::FAILURE, 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /исходники/синтаксис.rs: -------------------------------------------------------------------------------- 1 | use std::num::{IntErrorKind}; 2 | use лексика::*; 3 | use диагностика::*; 4 | use super::Результат; 5 | 6 | #[derive(Clone)] 7 | pub struct Переменная { 8 | pub имя: Лексема, 9 | pub тип: Выражение, 10 | } 11 | 12 | impl Переменная { 13 | pub fn разобрать(лекс: &mut Лексер) -> Результат<Переменная> { 14 | let имя = лекс.вытащить_лексему_вида(&[ВидЛексемы::Идент])?; 15 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::Двоеточие])?; 16 | let тип = Выражение::разобрать(лекс)?; 17 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::ТочкаЗапятая])?; 18 | Ok(Переменная{имя, тип}) 19 | } 20 | } 21 | 22 | #[derive(Debug, Clone)] 23 | pub enum ВидБинопа { 24 | Меньше, 25 | Больше, 26 | МеньшеРавно, 27 | БольшеРавно, 28 | Сложение, 29 | Вычитание, 30 | Умножение, 31 | Деление, 32 | Остаток, 33 | Или, 34 | И, 35 | Либо, 36 | Равно, 37 | НеРавно, 38 | Как, 39 | Поле, 40 | ЛевоеБитовоеСмещение, 41 | ПравоеБитовоеСмещение, 42 | } 43 | 44 | impl ВидБинопа { 45 | const МАКС_ПРИОРИТЕТ: usize = 7; 46 | 47 | fn приоритет(&self) -> usize { 48 | use self::ВидБинопа::*; 49 | match self { 50 | Или | Либо => Self::МАКС_ПРИОРИТЕТ - 7, 51 | И => Self::МАКС_ПРИОРИТЕТ - 6, 52 | Меньше | Больше | МеньшеРавно | БольшеРавно | Равно | НеРавно => Self::МАКС_ПРИОРИТЕТ - 5, 53 | Сложение | Вычитание => Self::МАКС_ПРИОРИТЕТ - 4, 54 | Умножение | Деление | Остаток => Self::МАКС_ПРИОРИТЕТ - 3, 55 | // СДЕЛАТЬ: какой приоритет лучше всего для битовых смещений? 56 | ЛевоеБитовоеСмещение | ПравоеБитовоеСмещение => Self::МАКС_ПРИОРИТЕТ - 2, 57 | Как => Self::МАКС_ПРИОРИТЕТ - 1, 58 | Поле => Self::МАКС_ПРИОРИТЕТ, 59 | } 60 | } 61 | 62 | fn по_виду_лексемы(вид: &ВидЛексемы) -> Option<ВидБинопа> { 63 | match вид { 64 | ВидЛексемы::Равно => Some(ВидБинопа::Равно), 65 | ВидЛексемы::Меньше => Some(ВидБинопа::Меньше), 66 | ВидЛексемы::Больше => Some(ВидБинопа::Больше), 67 | ВидЛексемы::МеньшеРавно => Some(ВидБинопа::МеньшеРавно), 68 | ВидЛексемы::БольшеРавно => Some(ВидБинопа::БольшеРавно), 69 | ВидЛексемы::НеРавно => Some(ВидБинопа::НеРавно), 70 | ВидЛексемы::Плюс => Some(ВидБинопа::Сложение), 71 | ВидЛексемы::Минус => Some(ВидБинопа::Вычитание), 72 | ВидЛексемы::Звёздочка => Some(ВидБинопа::Умножение), 73 | ВидЛексемы::ПрямаяНаклонная => Some(ВидБинопа::Деление), 74 | ВидЛексемы::КлючОст => Some(ВидБинопа::Остаток), 75 | ВидЛексемы::КлючКак => Some(ВидБинопа::Как), 76 | ВидЛексемы::КлючИли => Some(ВидБинопа::Или), 77 | ВидЛексемы::КлючИ => Some(ВидБинопа::И), 78 | ВидЛексемы::КлючЛибо => Some(ВидБинопа::Либо), 79 | ВидЛексемы::Точка => Some(ВидБинопа::Поле), 80 | ВидЛексемы::КлючЛбс => Some(ВидБинопа::ЛевоеБитовоеСмещение), 81 | ВидЛексемы::КлючПбс => Some(ВидБинопа::ПравоеБитовоеСмещение), 82 | _ => None 83 | } 84 | } 85 | } 86 | 87 | #[derive(Debug, Clone)] 88 | pub struct Аргументы { 89 | pub ключ: Лексема, 90 | pub выражения: Vec<Выражение>, 91 | } 92 | 93 | #[derive(Debug, Clone)] 94 | pub enum Выражение { 95 | ЦелЧисло(Лексема, i64), 96 | НатЧисло(Лексема, u64), 97 | ВещЧисло(Лексема, f32), 98 | Лог(Лексема, bool), 99 | Строка(Лексема), 100 | Идент(Лексема), 101 | ЦепочкаВызовов{имя: Лексема, цепочка_аргументов: Vec<Аргументы>}, 102 | УнарныйМинус { 103 | ключ: Лексема, 104 | выражение: Box<Выражение>, 105 | }, 106 | Биноп { 107 | ключ: Лексема, 108 | вид: ВидБинопа, 109 | левое: Box<Выражение>, 110 | правое: Box<Выражение>, 111 | }, 112 | Отрицание { 113 | ключ: Лексема, 114 | выражение: Box<Выражение>, 115 | } 116 | } 117 | 118 | impl Выражение { 119 | pub fn лок(&self) -> &Лок { 120 | match self { 121 | Выражение::ЦелЧисло(лексема, _) | 122 | Выражение::НатЧисло(лексема, _) | 123 | Выражение::ВещЧисло(лексема, _) | 124 | Выражение::Лог(лексема, _) | 125 | Выражение::Строка(лексема) | 126 | Выражение::Идент(лексема) => &лексема.лок, 127 | Выражение::Биноп{ключ, ..} => &ключ.лок, 128 | Выражение::ЦепочкаВызовов{имя, ..} => &имя.лок, 129 | Выражение::Отрицание{ключ, ..} => &ключ.лок, 130 | Выражение::УнарныйМинус{ключ, ..} => &ключ.лок, 131 | } 132 | } 133 | 134 | fn разобрать_первичное(лекс: &mut Лексер) -> Результат<Выражение> { 135 | let лексема = лекс.вытащить_лексему_вида(&[ 136 | ВидЛексемы::ЦелЧисло, 137 | ВидЛексемы::ЦелШестЧисло, 138 | ВидЛексемы::ВещЧисло, 139 | ВидЛексемы::Идент, 140 | ВидЛексемы::Строка, 141 | ВидЛексемы::ОткрытаяСкобка, 142 | ВидЛексемы::Не, 143 | ВидЛексемы::КлючИстина, 144 | ВидЛексемы::КлючЛожь, 145 | ВидЛексемы::Минус, 146 | ])?; 147 | match лексема.вид { 148 | ВидЛексемы::ЦелШестЧисло => { 149 | if лексема.текст.len() == 0 { 150 | диагностика!(&лексема.лок, "ОШИБКА", "Нет цифр для шестнадцатеричного литерала"); 151 | return Err(()); 152 | } 153 | 154 | let mut число: i64 = 0; 155 | for цифра in лексема.текст.chars().map(|знак| шестнадцатеричная_цифра(&знак).expect("Все шестнадцатеричные цифры должны быть проверены на этапе лексического анализа")) { 156 | число = число*16 + цифра; 157 | } 158 | if лекс.подсмотреть_лексему()?.вид == ВидЛексемы::Идент { 159 | if лекс.подсмотреть_лексему()?.текст == "нат" { 160 | let _ = лекс.вытащить_лексему()?; 161 | return Ok(Выражение::НатЧисло(лексема, число as u64)); 162 | } 163 | } 164 | Ok(Выражение::ЦелЧисло(лексема, число as i64)) 165 | } 166 | ВидЛексемы::ЦелЧисло => { 167 | let число: u64 = match лексема.текст.parse() { 168 | Ok(число) => число, 169 | Err(ошибка) => match ошибка.kind() { 170 | IntErrorKind::PosOverflow => { 171 | диагностика!(&лексема.лок, "ОШИБКА", "Слишком большое целое"); 172 | return Err(()); 173 | } 174 | IntErrorKind::Empty => unreachable!(), 175 | IntErrorKind::InvalidDigit => unreachable!(), 176 | IntErrorKind::NegOverflow => unreachable!(), 177 | IntErrorKind::Zero => unreachable!(), 178 | _ => { 179 | диагностика!(&лексема.лок, "ОШИБКА", "Некорректное целое число"); 180 | return Err(()); 181 | } 182 | } 183 | }; 184 | if лекс.подсмотреть_лексему()?.вид == ВидЛексемы::Идент { 185 | if лекс.подсмотреть_лексему()?.текст == "нат" { 186 | let _ = лекс.вытащить_лексему()?; 187 | return Ok(Выражение::НатЧисло(лексема, число)); 188 | } 189 | } 190 | Ok(Выражение::ЦелЧисло(лексема, число as i64)) 191 | } 192 | ВидЛексемы::ВещЧисло => { 193 | match лексема.текст.parse() { 194 | Ok(число) => Ok(Выражение::ВещЧисло(лексема, число)), 195 | Err(_ошибка) => { 196 | диагностика!(&лексема.лок, "ОШИБКА", "Некорректное вещественное число"); 197 | Err(()) 198 | } 199 | } 200 | } 201 | ВидЛексемы::Идент => { 202 | let mut цепочка_аргументов = Vec::new(); 203 | while лекс.подсмотреть_лексему()?.вид == ВидЛексемы::ОткрытаяСкобка { 204 | let ключ = лекс.вытащить_лексему().unwrap(); 205 | цепочка_аргументов.push(Аргументы { 206 | ключ, 207 | выражения: разобрать_список_аргументов_вызова(лекс)? 208 | }); 209 | } 210 | if цепочка_аргументов.len() == 0 { 211 | Ok(Выражение::Идент(лексема)) 212 | } else { 213 | Ok(Выражение::ЦепочкаВызовов { 214 | имя: лексема, 215 | цепочка_аргументов, 216 | }) 217 | } 218 | }, 219 | ВидЛексемы::Строка => Ok(Выражение::Строка(лексема)), 220 | ВидЛексемы::ОткрытаяСкобка => { 221 | let выражение = Выражение::разобрать(лекс)?; 222 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::ЗакрытаяСкобка])?; 223 | Ok(выражение) 224 | } 225 | ВидЛексемы::Не => { 226 | let ключ = лексема; 227 | let выражение = Box::new(Выражение::разобрать(лекс)?); 228 | Ok(Выражение::Отрицание{ключ, выражение}) 229 | } 230 | ВидЛексемы::Минус => { 231 | let ключ = лексема; 232 | let выражение = Box::new(Выражение::разобрать_первичное(лекс)?); 233 | Ok(Выражение::УнарныйМинус{ключ, выражение}) 234 | } 235 | ВидЛексемы::КлючИстина => Ok(Выражение::Лог(лексема, true)), 236 | ВидЛексемы::КлючЛожь => Ok(Выражение::Лог(лексема, false)), 237 | _ => unreachable!(), 238 | } 239 | } 240 | 241 | fn разобрать_биноп(лекс: &mut Лексер, приоритет: usize) -> Результат<Выражение> { 242 | if приоритет > ВидБинопа::МАКС_ПРИОРИТЕТ { 243 | return Выражение::разобрать_первичное(лекс); 244 | } 245 | 246 | let mut левое = Выражение::разобрать_биноп(лекс, приоритет + 1)?; 247 | while let Some(вид) = ВидБинопа::по_виду_лексемы(&лекс.подсмотреть_лексему()?.вид) { 248 | if вид.приоритет() != приоритет { 249 | break; 250 | } 251 | let ключ = лекс.вытащить_лексему().unwrap(); 252 | let правое = Выражение::разобрать_биноп(лекс, приоритет + 1)?; 253 | левое = Выражение::Биноп { 254 | вид, 255 | ключ, 256 | левое: Box::new(левое), 257 | правое: Box::new(правое), 258 | } 259 | } 260 | Ok(левое) 261 | } 262 | 263 | pub fn разобрать(лекс: &mut Лексер) -> Результат<Выражение> { 264 | Выражение::разобрать_биноп(лекс, 0) 265 | } 266 | } 267 | 268 | #[derive(Debug)] 269 | pub struct ВеткаВилки { 270 | pub ключ: Лексема, 271 | pub выражение: Выражение, 272 | pub тело: Vec<Утверждение>, 273 | } 274 | 275 | #[derive(Debug)] 276 | pub enum Утверждение { 277 | Присваивание{ключ: Лексема, левое: Выражение, правое: Выражение}, 278 | Выражение{выражение: Выражение}, 279 | Пока{ключ: Лексема, условие: Выражение, тело: Vec<Утверждение>}, 280 | Для{ключ: Лексема, индекс: Лексема, нижняя_граница: Выражение, верхняя_граница: Выражение, тело: Vec<Утверждение>}, 281 | Если{ключ: Лексема, условие: Выражение, тело: Vec<Утверждение>, иначе: Vec<Утверждение>}, 282 | Вернуть{ключ: Лексема, выражение: Option<Выражение>}, 283 | ДекларацияПеременной{ключ: Лексема, имя: Лексема, тип: Выражение, значение: Option<Выражение>}, 284 | ДекларацияКонстанты{ключ: Лексема, имя: Лексема, значение: Выражение}, 285 | Вилка {ключ: Лексема, выражение: Выражение, ветки: Vec<ВеткаВилки>, любое: Option<(Лексема, Vec<Утверждение>)>}, 286 | } 287 | 288 | #[derive(Debug)] 289 | pub struct Параметр { 290 | pub имя: Лексема, 291 | pub тип: Выражение, 292 | } 293 | 294 | #[derive(Debug)] 295 | pub enum ТелоПроцедуры { 296 | Внутренее { блок: Vec<Утверждение> }, 297 | Внешнее { символ: Лексема }, 298 | } 299 | 300 | #[derive(Debug)] 301 | pub struct Процедура { 302 | pub имя: Лексема, 303 | pub параметры: Vec<Параметр>, 304 | pub тип_результата: Option<Выражение>, 305 | pub тело: ТелоПроцедуры, 306 | } 307 | 308 | fn разобрать_утверждение(лекс: &mut Лексер) -> Результат<Утверждение> { 309 | match лекс.подсмотреть_лексему()?.вид { 310 | ВидЛексемы::КлючЕсли => { 311 | let ключ = лекс.вытащить_лексему().unwrap(); 312 | let условие = Выражение::разобрать(лекс)?; 313 | let тело = разобрать_блок_кода(лекс)?; 314 | let иначе; 315 | if лекс.подсмотреть_лексему()?.вид == ВидЛексемы::КлючИначе { 316 | let _ = лекс.вытащить_лексему()?; 317 | иначе = разобрать_блок_кода(лекс)?; 318 | } else { 319 | иначе = vec![] 320 | } 321 | Ok(Утверждение::Если{ключ, условие, тело, иначе}) 322 | } 323 | ВидЛексемы::КлючПока => { 324 | let ключ = лекс.вытащить_лексему().unwrap(); 325 | let условие = Выражение::разобрать(лекс)?; 326 | let тело = разобрать_блок_кода(лекс)?; 327 | Ok(Утверждение::Пока{ключ, условие, тело}) 328 | } 329 | ВидЛексемы::КлючДля => { 330 | let ключ = лекс.вытащить_лексему().unwrap(); 331 | let индекс = лекс.вытащить_лексему_вида(&[ВидЛексемы::Идент])?; 332 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::Присваивание])?; 333 | let нижняя_граница = Выражение::разобрать(лекс)?; 334 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::ТочкаТочка])?; 335 | let верхняя_граница = Выражение::разобрать(лекс)?; 336 | let тело = разобрать_блок_кода(лекс)?; 337 | Ok(Утверждение::Для{ключ, индекс, нижняя_граница, верхняя_граница, тело}) 338 | } 339 | ВидЛексемы::КлючВернуть => { 340 | let ключ = лекс.вытащить_лексему().unwrap(); 341 | if лекс.подсмотреть_лексему()?.вид == ВидЛексемы::ТочкаЗапятая { 342 | let _ = лекс.вытащить_лексему().unwrap(); 343 | Ok(Утверждение::Вернуть{ключ, выражение: None}) 344 | } else { 345 | let выражение = Some(Выражение::разобрать(лекс)?); 346 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::ТочкаЗапятая])?; 347 | Ok(Утверждение::Вернуть{ключ, выражение}) 348 | } 349 | } 350 | ВидЛексемы::КлючПер => { 351 | let ключ = лекс.вытащить_лексему().unwrap(); 352 | let имя = лекс.вытащить_лексему_вида(&[ВидЛексемы::Идент])?; 353 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::Двоеточие])?; 354 | let тип = Выражение::разобрать(лекс)?; 355 | let значение = match лекс.вытащить_лексему_вида(&[ВидЛексемы::ТочкаЗапятая, ВидЛексемы::Присваивание])?.вид { 356 | ВидЛексемы::ТочкаЗапятая => None, 357 | ВидЛексемы::Присваивание => { 358 | let значение = Выражение::разобрать(лекс)?; 359 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::ТочкаЗапятая])?; 360 | Some(значение) 361 | } 362 | _ => unreachable!() 363 | }; 364 | Ok(Утверждение::ДекларацияПеременной{ключ, имя, тип, значение}) 365 | } 366 | ВидЛексемы::КлючКонст => { 367 | let ключ = лекс.вытащить_лексему().unwrap(); 368 | let имя = лекс.вытащить_лексему_вида(&[ВидЛексемы::Идент])?; 369 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::Присваивание])?; 370 | let значение = Выражение::разобрать(лекс)?; 371 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::ТочкаЗапятая])?; 372 | Ok(Утверждение::ДекларацияКонстанты{ключ, имя, значение}) 373 | } 374 | ВидЛексемы::КлючВилка => { 375 | let ключ = лекс.вытащить_лексему().unwrap(); 376 | let выражение = Выражение::разобрать(лекс)?; 377 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::КлючНч])?; 378 | let mut ветки = Vec::new(); 379 | let mut любое = None; 380 | 'разбор_веток: loop { 381 | let ключ_ветки = лекс.вытащить_лексему_вида(&[ 382 | ВидЛексемы::КлючКогда, 383 | ВидЛексемы::КлючКц, 384 | ])?; 385 | match ключ_ветки.вид { 386 | ВидЛексемы::КлючКогда => { 387 | if лекс.подсмотреть_лексему()?.вид == ВидЛексемы::КлючЛюбое { 388 | let _ = лекс.вытащить_лексему().unwrap(); 389 | любое = Some((ключ_ветки, разобрать_блок_кода(лекс)?)); 390 | лекс.вытащить_лексему_вида(&[ВидЛексемы::КлючКц])?; 391 | break 'разбор_веток; 392 | } else { 393 | ветки.push(ВеткаВилки { 394 | ключ: ключ_ветки, 395 | выражение: Выражение::разобрать(лекс)?, 396 | тело: разобрать_блок_кода(лекс)?, 397 | }); 398 | } 399 | } 400 | ВидЛексемы::КлючКц => break 'разбор_веток, 401 | _ => unreachable!(), 402 | } 403 | } 404 | Ok(Утверждение::Вилка{ключ, выражение, ветки, любое}) 405 | } 406 | _ => { 407 | let левое = Выражение::разобрать(лекс)?; 408 | let ключ = лекс.вытащить_лексему_вида(&[ 409 | ВидЛексемы::Присваивание, 410 | ВидЛексемы::ТочкаЗапятая, 411 | ])?; 412 | match ключ.вид { 413 | ВидЛексемы::Присваивание => { 414 | let правое = Выражение::разобрать(лекс)?; 415 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::ТочкаЗапятая])?; 416 | Ok(Утверждение::Присваивание {ключ, левое, правое}) 417 | } 418 | ВидЛексемы::ТочкаЗапятая => Ok(Утверждение::Выражение {выражение: левое}), 419 | _ => unreachable!(), 420 | } 421 | } 422 | } 423 | } 424 | 425 | fn разобрать_блок_кода(лекс: &mut Лексер) -> Результат> { 426 | let mut блок = Vec::new(); 427 | let ключ = лекс.вытащить_лексему_вида(&[ВидЛексемы::КлючНч, ВидЛексемы::КлючТо])?; 428 | match ключ.вид { 429 | ВидЛексемы::КлючНч => loop { 430 | if лекс.подсмотреть_лексему()?.вид == ВидЛексемы::КлючКц { 431 | let _ = лекс.вытащить_лексему()?; 432 | break; 433 | } 434 | блок.push(разобрать_утверждение(лекс)?); 435 | } 436 | ВидЛексемы::КлючТо => блок.push(разобрать_утверждение(лекс)?), 437 | _ => unreachable!() 438 | } 439 | Ok(блок) 440 | } 441 | 442 | fn разобрать_список_аргументов_вызова(лекс: &mut Лексер) -> Результат> { 443 | let mut аргументы = Vec::new(); 444 | 445 | // СДЕЛАТЬ: ввести идиому лекс.вытащить_лексему_если() 446 | if лекс.подсмотреть_лексему()?.вид == ВидЛексемы::ЗакрытаяСкобка { 447 | let _ = лекс.вытащить_лексему()?; 448 | } else { 449 | 'разбор_аргументов: loop { 450 | аргументы.push(Выражение::разобрать(лекс)?); 451 | let лексема = лекс.вытащить_лексему_вида(&[ 452 | ВидЛексемы::ЗакрытаяСкобка, 453 | ВидЛексемы::Запятая 454 | ])?; 455 | if лексема.вид == ВидЛексемы::ЗакрытаяСкобка { 456 | break 'разбор_аргументов 457 | } 458 | } 459 | } 460 | Ok(аргументы) 461 | } 462 | 463 | fn разобрать_список_параметров_процедуры(лекс: &mut Лексер) -> Результат> { 464 | let mut параметры: Vec<Параметр> = Vec::new(); 465 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::ОткрытаяСкобка])?; 466 | if лекс.подсмотреть_лексему()?.вид == ВидЛексемы::ЗакрытаяСкобка { 467 | let _ = лекс.вытащить_лексему()?; 468 | } else { 469 | 'разбор_параметров: loop { 470 | let имя = лекс.вытащить_лексему_вида(&[ВидЛексемы::Идент])?; 471 | if let Some(существующий_параметр) = параметры.iter().find(|параметр| параметр.имя.текст == имя.текст) { 472 | диагностика!(&имя.лок, "ОШИБКА", "переопределение параметра «{имя}»", 473 | имя = имя.текст); 474 | диагностика!(&существующий_параметр.имя.лок, "ИНФО", "параметр с тем же именем определен тут"); 475 | return Err(()); 476 | } 477 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::Двоеточие])?; 478 | let тип = Выражение::разобрать(лекс)?; 479 | параметры.push(Параметр {имя, тип}); 480 | let лексема = лекс.вытащить_лексему_вида(&[ 481 | ВидЛексемы::ЗакрытаяСкобка, 482 | ВидЛексемы::Запятая 483 | ])?; 484 | if лексема.вид == ВидЛексемы::ЗакрытаяСкобка { 485 | break 'разбор_параметров 486 | } 487 | } 488 | } 489 | Ok(параметры) 490 | } 491 | 492 | impl Процедура { 493 | pub fn разобрать(лекс: &mut Лексер) -> Результат<Процедура> { 494 | let имя = лекс.вытащить_лексему_вида(&[ВидЛексемы::Идент])?; 495 | let параметры = разобрать_список_параметров_процедуры(лекс)?; 496 | let тип_результата = if лекс.подсмотреть_лексему()?.вид == ВидЛексемы::Двоеточие { 497 | let _ = лекс.вытащить_лексему().unwrap(); 498 | let тип = Выражение::разобрать(лекс)?; 499 | Some(тип) 500 | } else { 501 | None 502 | }; 503 | let тело = if лекс.подсмотреть_лексему()?.вид == ВидЛексемы::КлючВнешняя { 504 | let _ = лекс.вытащить_лексему().unwrap(); 505 | let символ = лекс.вытащить_лексему_вида(&[ВидЛексемы::Строка])?; 506 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::ТочкаЗапятая])?; 507 | ТелоПроцедуры::Внешнее {символ} 508 | } else { 509 | let блок = разобрать_блок_кода(лекс)?; 510 | ТелоПроцедуры::Внутренее {блок} 511 | }; 512 | Ok(Процедура{имя, параметры, тело, тип_результата}) 513 | } 514 | } 515 | 516 | #[derive(Debug)] 517 | pub struct Константа { 518 | pub имя: Лексема, 519 | pub выражение: Выражение, 520 | } 521 | 522 | impl Константа { 523 | pub fn разобрать(лекс: &mut Лексер) -> Результат<Константа> { 524 | let имя = лекс.вытащить_лексему_вида(&[ВидЛексемы::Идент])?; 525 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::Присваивание])?; 526 | let выражение = Выражение::разобрать(лекс)?; 527 | let _ = лекс.вытащить_лексему_вида(&[ВидЛексемы::ТочкаЗапятая])?; 528 | Ok(Константа{имя, выражение}) 529 | } 530 | } 531 | -------------------------------------------------------------------------------- /исходники/лексика.rs: -------------------------------------------------------------------------------- 1 | use super::диагностика::*; 2 | use super::Результат; 3 | use std::fmt::Write; 4 | use std::path::Path; 5 | 6 | pub const ПРИСТАВКИ_ПРЕПИНАНИЙ: &[(&[char], ВидЛексемы)] = &[ 7 | (&['('], ВидЛексемы::ОткрытаяСкобка), 8 | (&[')'], ВидЛексемы::ЗакрытаяСкобка), 9 | (&[';'], ВидЛексемы::ТочкаЗапятая), 10 | (&['.', '.'], ВидЛексемы::ТочкаТочка), 11 | (&['.'], ВидЛексемы::Точка), 12 | (&[':', '='], ВидЛексемы::Присваивание), 13 | (&[':'], ВидЛексемы::Двоеточие), 14 | (&[','], ВидЛексемы::Запятая), 15 | (&['+', '?', '='], ВидЛексемы::БольшеРавно), 16 | (&['+', '?'], ВидЛексемы::Больше), 17 | (&['+'], ВидЛексемы::Плюс), 18 | (&['-', '?', '='], ВидЛексемы::МеньшеРавно), 19 | (&['-', '?'], ВидЛексемы::Меньше), 20 | (&['-'], ВидЛексемы::Минус), 21 | (&['*'], ВидЛексемы::Звёздочка), 22 | (&['/'], ВидЛексемы::ПрямаяНаклонная), 23 | (&['='], ВидЛексемы::Равно), 24 | (&['!', '='], ВидЛексемы::НеРавно), 25 | (&['!'], ВидЛексемы::Не), 26 | ]; 27 | 28 | pub const КЛЮЧЕВЫЕ_СЛОВА: &[(&str, ВидЛексемы)] = &[ 29 | ("пер", ВидЛексемы::КлючПер), 30 | ("про", ВидЛексемы::КлючПро), 31 | ("конст", ВидЛексемы::КлючКонст), 32 | ("если", ВидЛексемы::КлючЕсли), 33 | ("то", ВидЛексемы::КлючТо), 34 | ("иначе", ВидЛексемы::КлючИначе), 35 | ("пока", ВидЛексемы::КлючПока), 36 | ("для", ВидЛексемы::КлючДля), 37 | ("вернуть", ВидЛексемы::КлючВернуть), 38 | ("или", ВидЛексемы::КлючИли), 39 | ("и", ВидЛексемы::КлючИ), 40 | ("либо", ВидЛексемы::КлючЛибо), 41 | ("нч", ВидЛексемы::КлючНч), 42 | ("кц", ВидЛексемы::КлючКц), 43 | ("как", ВидЛексемы::КлючКак), 44 | ("вкл", ВидЛексемы::КлючВкл), 45 | ("внешняя", ВидЛексемы::КлючВнешняя), 46 | ("библ", ВидЛексемы::КлючБибл), 47 | ("структ", ВидЛексемы::КлючСтрукт), 48 | ("истина", ВидЛексемы::КлючИстина), 49 | ("ложь", ВидЛексемы::КлючЛожь), 50 | ("лбс", ВидЛексемы::КлючЛбс), 51 | ("пбс", ВидЛексемы::КлючПбс), 52 | ("ост", ВидЛексемы::КлючОст), 53 | ("вилка", ВидЛексемы::КлючВилка), 54 | ("когда", ВидЛексемы::КлючКогда), 55 | ("любое", ВидЛексемы::КлючЛюбое), 56 | // СДЕЛАТЬ: оператор «мод». 57 | ]; 58 | 59 | #[derive(Debug, Clone, Copy, PartialEq)] 60 | pub enum ВидЛексемы { 61 | Конец, 62 | Идент, 63 | 64 | КлючПер, 65 | КлючПро, 66 | КлючКонст, 67 | КлючЕсли, 68 | КлючТо, 69 | КлючИначе, 70 | КлючПока, 71 | КлючДля, 72 | КлючВернуть, 73 | КлючНч, 74 | КлючИли, 75 | КлючИ, 76 | КлючЛибо, 77 | КлючКц, 78 | КлючКак, 79 | КлючВкл, 80 | КлючВнешняя, 81 | КлючБибл, 82 | КлючСтрукт, 83 | КлючИстина, 84 | КлючЛожь, 85 | КлючЛбс, 86 | КлючПбс, 87 | КлючОст, 88 | КлючВилка, 89 | КлючКогда, 90 | КлючЛюбое, 91 | 92 | ОткрытаяСкобка, 93 | ЗакрытаяСкобка, 94 | ТочкаЗапятая, 95 | Точка, 96 | ТочкаТочка, 97 | Двоеточие, 98 | Запятая, 99 | Плюс, 100 | Минус, 101 | Звёздочка, 102 | ПрямаяНаклонная, 103 | Присваивание, 104 | Равно, 105 | Меньше, 106 | МеньшеРавно, 107 | Больше, 108 | БольшеРавно, 109 | Не, 110 | НеРавно, 111 | 112 | ЦелЧисло, 113 | ЦелШестЧисло, 114 | ВещЧисло, 115 | Строка, 116 | } 117 | 118 | impl ВидЛексемы { 119 | pub fn сущ(&self) -> Сущ { 120 | match self { 121 | ВидЛексемы::Конец => Сущ{текст: "конец ввода", род: Род::Муж}, 122 | ВидЛексемы::Идент => Сущ{текст: "идентификатор", род: Род::Муж}, 123 | 124 | // Ключевые слова 125 | ВидЛексемы::КлючПер => Сущ{текст: "«пер»", род: Род::Сред}, 126 | ВидЛексемы::КлючПро => Сущ{текст: "«про»", род: Род::Сред}, 127 | ВидЛексемы::КлючКонст => Сущ{текст: "«конст»", род: Род::Сред}, 128 | ВидЛексемы::КлючЕсли => Сущ{текст: "«если»", род: Род::Сред}, 129 | ВидЛексемы::КлючТо => Сущ{текст: "«то»", род: Род::Сред}, 130 | ВидЛексемы::КлючИначе => Сущ{текст: "«иначе»", род: Род::Сред}, 131 | ВидЛексемы::КлючПока => Сущ{текст: "«пока»", род: Род::Сред}, 132 | ВидЛексемы::КлючДля => Сущ{текст: "«для»", род: Род::Сред}, 133 | ВидЛексемы::КлючВернуть => Сущ{текст: "«вернуть»", род: Род::Сред}, 134 | ВидЛексемы::КлючЛибо => Сущ{текст: "«либо»", род: Род::Сред}, 135 | ВидЛексемы::КлючИли => Сущ{текст: "«или»", род: Род::Муж}, 136 | ВидЛексемы::КлючИ => Сущ{текст: "«и»", род: Род::Муж}, 137 | ВидЛексемы::КлючНч => Сущ{текст: "«нч»", род: Род::Сред}, 138 | ВидЛексемы::КлючКц => Сущ{текст: "«кц»", род: Род::Муж}, 139 | ВидЛексемы::КлючКак => Сущ{текст: "«как»", род: Род::Муж}, 140 | ВидЛексемы::КлючВкл => Сущ{текст: "«вкл»", род: Род::Муж}, 141 | ВидЛексемы::КлючВнешняя => Сущ{текст: "«внешняя»", род: Род::Жен}, 142 | ВидЛексемы::КлючБибл => Сущ{текст: "«библ»", род: Род::Муж}, 143 | ВидЛексемы::КлючСтрукт => Сущ{текст: "«структ»", род: Род::Муж}, 144 | ВидЛексемы::КлючИстина => Сущ{текст: "«истина»", род: Род::Жен}, 145 | ВидЛексемы::КлючЛожь => Сущ{текст: "«ложь»", род: Род::Жен}, 146 | ВидЛексемы::КлючЛбс => Сущ{текст: "«лбс»", род: Род::Муж}, 147 | ВидЛексемы::КлючПбс => Сущ{текст: "«пбс»", род: Род::Муж}, 148 | ВидЛексемы::КлючОст => Сущ{текст: "«ост»", род: Род::Муж}, 149 | ВидЛексемы::КлючВилка => Сущ{текст: "«вилка»", род: Род::Жен}, 150 | ВидЛексемы::КлючКогда => Сущ{текст: "«когда»", род: Род::Сред}, 151 | ВидЛексемы::КлючЛюбое => Сущ{текст: "«любое»", род: Род::Сред}, 152 | 153 | // Знаки препинания 154 | ВидЛексемы::ОткрытаяСкобка => Сущ{текст: "открытая скобка", род: Род::Жен}, 155 | ВидЛексемы::ЗакрытаяСкобка => Сущ{текст: "закрытая скобка", род: Род::Жен}, 156 | ВидЛексемы::ТочкаЗапятая => Сущ{текст: "точка с запятой", род: Род::Жен}, 157 | ВидЛексемы::Точка => Сущ{текст: "точка", род: Род::Жен}, 158 | ВидЛексемы::ТочкаТочка => Сущ{текст: "точка точка", род: Род::Жен}, 159 | ВидЛексемы::Двоеточие => Сущ{текст: "двоеточие", род: Род::Сред}, 160 | ВидЛексемы::Запятая => Сущ{текст: "запятая", род: Род::Жен}, 161 | ВидЛексемы::Плюс => Сущ{текст: "плюс", род: Род::Муж}, 162 | ВидЛексемы::Минус => Сущ{текст: "минус", род: Род::Муж}, 163 | ВидЛексемы::Звёздочка => Сущ{текст: "звёздочка", род: Род::Жен}, 164 | ВидЛексемы::ПрямаяНаклонная => Сущ{текст: "прямая наклонная черта", род: Род::Жен}, 165 | ВидЛексемы::Присваивание => Сущ{текст: "присваивание", род: Род::Сред}, 166 | ВидЛексемы::Равно => Сущ{текст: "равно", род: Род::Сред}, 167 | ВидЛексемы::Меньше => Сущ{текст: "меньше", род: Род::Сред}, 168 | ВидЛексемы::Больше => Сущ{текст: "больше", род: Род::Сред}, 169 | ВидЛексемы::МеньшеРавно => Сущ{текст: "меньше либо равно", род: Род::Сред}, 170 | ВидЛексемы::БольшеРавно => Сущ{текст: "больше либо равно", род: Род::Сред}, 171 | ВидЛексемы::Не => Сущ{текст: "отрицание", род: Род::Сред}, 172 | ВидЛексемы::НеРавно => Сущ{текст: "не равно", род: Род::Сред}, 173 | 174 | ВидЛексемы::ЦелШестЧисло => Сущ{текст: "целое шестнадцатеричное число", род: Род::Сред}, 175 | ВидЛексемы::ЦелЧисло => Сущ{текст: "целое число", род: Род::Сред}, 176 | ВидЛексемы::ВещЧисло => Сущ{текст: "вещественное число", род: Род::Сред}, 177 | ВидЛексемы::Строка => Сущ{текст: "строка", род: Род::Жен}, 178 | } 179 | } 180 | } 181 | 182 | #[derive(Debug, Clone)] 183 | pub struct Лексема { 184 | pub вид: ВидЛексемы, 185 | pub текст: String, 186 | pub лок: Лок, 187 | } 188 | 189 | pub struct Лексер<'ы> { 190 | pub символы: &'ы [char], 191 | pub путь_к_файлу: &'ы Path, 192 | pub позиция: usize, 193 | pub начало_строки: usize, 194 | pub строка: usize, 195 | pub буфер: Option<Результат<Лексема>> 196 | } 197 | 198 | pub fn шестнадцатеричная_цифра(знак: &char) -> Option { 199 | if знак.is_digit(10) { 200 | Some(*знак as i64 - '0' as i64) 201 | } else { 202 | match знак { 203 | 'А' | 'а' => Some(10), 204 | 'Б' | 'б' => Some(11), 205 | 'Ц' | 'ц' => Some(12), 206 | 'Д' | 'д' => Some(13), 207 | 'Е' | 'е' => Some(14), 208 | 'Ф' | 'ф' => Some(15), 209 | _ => None, 210 | } 211 | } 212 | } 213 | 214 | impl<'a> Лексер<'a> { 215 | pub fn новый(путь_к_файлу: &'a Path, символы: &'a [char]) -> Лексер<'a> { 216 | Лексер { 217 | символы, 218 | путь_к_файлу, 219 | позиция: 0, 220 | начало_строки: 0, 221 | строка: 0, 222 | буфер: None, 223 | } 224 | } 225 | 226 | pub fn текущий_символ(&self) -> Option<&char> { 227 | self.символы.get(self.позиция) 228 | } 229 | 230 | pub fn имеет_приставку(&self, приставка: &[char]) -> bool { 231 | self.символы 232 | .get(self.позиция..) 233 | .map(|строка| строка.starts_with(приставка)) 234 | .unwrap_or(false) 235 | } 236 | 237 | pub fn отрезать_символы(&mut self, mut количество: usize) { 238 | while количество > 0 && self.текущий_символ().is_some() { 239 | self.отрезать_символ(); 240 | количество -= 1; 241 | } 242 | } 243 | 244 | pub fn отрезать_символ(&mut self) { 245 | if let Some(&символ) = self.текущий_символ() { 246 | self.позиция += 1; 247 | if символ == '\n' { 248 | self.начало_строки = self.позиция; 249 | self.строка += 1; 250 | } 251 | } 252 | } 253 | 254 | pub fn подбрить_пробелы(&mut self) { 255 | while self.текущий_символ().map(|сим| сим.is_whitespace()).unwrap_or(false) { 256 | self.отрезать_символ(); 257 | } 258 | } 259 | 260 | fn следующая_строка(&mut self) { 261 | while let Some(x) = self.текущий_символ().cloned() { 262 | self.отрезать_символ(); 263 | if x == '\n' { 264 | break; 265 | } 266 | } 267 | } 268 | 269 | fn лок(&self) -> Лок { 270 | Лок { 271 | строка: self.строка + 1, 272 | столбец: self.позиция - self.начало_строки + 1, 273 | путь_к_файлу: self.путь_к_файлу.to_path_buf(), 274 | } 275 | } 276 | 277 | fn подбрить_многострочные_комментарии(&mut self) { 278 | let mut вложенность: usize = 1; 279 | while вложенность > 0 && self.текущий_символ().is_some() { 280 | if self.имеет_приставку(&['/', '*']) { 281 | вложенность += 1; 282 | self.отрезать_символы(2); 283 | } else if self.имеет_приставку(&['*', '/']) { 284 | вложенность -= 1; 285 | self.отрезать_символы(2); 286 | } else { 287 | self.отрезать_символ(); 288 | } 289 | } 290 | } 291 | 292 | fn следующая_лексема(&mut self) -> Результат<Лексема> { 293 | 'подбрить_пробелы_и_комментарии: loop { 294 | self.подбрить_пробелы(); 295 | if self.имеет_приставку(&['/', '/']) { 296 | self.следующая_строка(); 297 | } else if self.имеет_приставку(&['/', '*']) { 298 | self.отрезать_символы(2); 299 | self.подбрить_многострочные_комментарии(); 300 | } else { 301 | break 'подбрить_пробелы_и_комментарии; 302 | } 303 | } 304 | 305 | let лок = self.лок(); 306 | 307 | let сим = if let Some(сим) = self.текущий_символ().cloned() { 308 | сим 309 | } else { 310 | return Ok(Лексема { 311 | вид: ВидЛексемы::Конец, 312 | текст: String::new(), 313 | лок, 314 | }); 315 | }; 316 | 317 | if сим.is_alphabetic() || сим == '_' { 318 | let начало = self.позиция; 319 | while self.символы.get(self.позиция).map(|сим| сим.is_alphanumeric() || *сим == '_').unwrap_or(false) { 320 | self.отрезать_символ(); 321 | } 322 | let текст = self.символы[начало..self.позиция].iter().collect(); 323 | for &(ключ, вид) in КЛЮЧЕВЫЕ_СЛОВА.iter() { 324 | if ключ == текст { 325 | return Ok(Лексема {вид, текст, лок}) 326 | } 327 | } 328 | return Ok(Лексема { 329 | вид: ВидЛексемы::Идент, 330 | текст, 331 | лок, 332 | }) 333 | } 334 | 335 | if self.имеет_приставку(&['1', '6', '%']) { 336 | self.отрезать_символы(3); 337 | let начало = self.позиция; 338 | while self.символы.get(self.позиция).and_then(шестнадцатеричная_цифра).is_some() { 339 | self.отрезать_символ(); 340 | } 341 | let текст = self.символы[начало..self.позиция].iter().collect(); 342 | return Ok(Лексема { 343 | вид: ВидЛексемы::ЦелШестЧисло, 344 | текст, 345 | лок, 346 | }); 347 | } 348 | 349 | if сим.is_numeric() { 350 | let начало = self.позиция; 351 | while self.символы.get(self.позиция).map(|сим| сим.is_numeric()).unwrap_or(false) { 352 | self.отрезать_символ(); 353 | } 354 | // Это условие крайне важно, чтобы разобрать выражение 355 | // "1..10" как "1", "..", "10". 356 | if Some('.') == self.символы.get(self.позиция).cloned() && Some('.') != self.символы.get(self.позиция + 1).cloned() { 357 | self.отрезать_символ(); 358 | while self.символы.get(self.позиция).map(|сим| сим.is_numeric()).unwrap_or(false) { 359 | self.отрезать_символ(); 360 | } 361 | let текст = self.символы[начало..self.позиция].iter().collect(); 362 | return Ok(Лексема { 363 | вид: ВидЛексемы::ВещЧисло, 364 | текст, 365 | лок, 366 | }) 367 | } else { 368 | let текст = self.символы[начало..self.позиция].iter().collect(); 369 | return Ok(Лексема { 370 | вид: ВидЛексемы::ЦелЧисло, 371 | текст, 372 | лок, 373 | }) 374 | } 375 | } 376 | 377 | if сим == '«' { 378 | self.отрезать_символ(); 379 | let mut вложенность: usize = 1; 380 | let mut текст = String::new(); 381 | loop { 382 | if let Some(сим) = self.текущий_символ().cloned() { 383 | match сим { 384 | '«' => { 385 | self.отрезать_символ(); 386 | вложенность += 1; 387 | текст.push(сим); 388 | } 389 | '»' => { 390 | self.отрезать_символ(); 391 | вложенность -= 1; 392 | if вложенность == 0 { 393 | return Ok(Лексема { 394 | вид: ВидЛексемы::Строка, 395 | текст, 396 | лок, 397 | }); 398 | } 399 | текст.push(сим); 400 | } 401 | '\\' => { 402 | self.отрезать_символ(); 403 | match self.текущий_символ().cloned() { 404 | Some('н') => { 405 | self.отрезать_символ(); 406 | текст.push('\n'); 407 | } 408 | Some('т') => { 409 | self.отрезать_символ(); 410 | текст.push('\t'); 411 | } 412 | Some('\\') => { 413 | self.отрезать_символ(); 414 | текст.push('\\'); 415 | } 416 | Some('"') => { 417 | let лок = Лок { 418 | строка: self.строка + 1, 419 | столбец: self.позиция - self.начало_строки + 1, 420 | путь_к_файлу: self.путь_к_файлу.to_path_buf(), 421 | }; 422 | диагностика!(&лок, "ОШИБКА", "Экранировать \"лапки\" внутри «ёлочек» не нужно!"); 423 | return Err(()); 424 | } 425 | Some('»') => { 426 | self.отрезать_символ(); 427 | текст.push('»'); 428 | } 429 | Some('«') => { 430 | self.отрезать_символ(); 431 | текст.push('«'); 432 | } 433 | Some(сим) => { 434 | let лок = Лок { 435 | строка: self.строка + 1, 436 | столбец: self.позиция - self.начало_строки + 1, 437 | путь_к_файлу: self.путь_к_файлу.to_path_buf(), 438 | }; 439 | диагностика!(&лок, "ОШИБКА", "неизвестная поседовательность экранирования начинается с «{сим}»"); 440 | return Err(()); 441 | } 442 | None => { 443 | диагностика!(&лок, "ОШИБКА", "незавершённая строка"); 444 | return Err(()); 445 | } 446 | } 447 | } 448 | _ => { 449 | self.отрезать_символ(); 450 | текст.push(сим) 451 | } 452 | } 453 | } else { 454 | диагностика!(&лок, "ОШИБКА", "незавершённая строка"); 455 | return Err(()); 456 | } 457 | } 458 | } 459 | 460 | if сим == '"' { 461 | self.отрезать_символ(); 462 | let mut текст = String::new(); 463 | loop { 464 | if let Some(сим) = self.текущий_символ().cloned() { 465 | match сим { 466 | '"' => { 467 | self.отрезать_символ(); 468 | return Ok(Лексема { 469 | вид: ВидЛексемы::Строка, 470 | текст, 471 | лок, 472 | }); 473 | } 474 | '\\' => { 475 | self.отрезать_символ(); 476 | match self.текущий_символ().cloned() { 477 | Some('н') => { 478 | self.отрезать_символ(); 479 | текст.push('\n'); 480 | } 481 | Some('т') => { 482 | self.отрезать_символ(); 483 | текст.push('\t'); 484 | } 485 | Some('\\') => { 486 | self.отрезать_символ(); 487 | текст.push('\\'); 488 | } 489 | Some('"') => { 490 | self.отрезать_символ(); 491 | текст.push('\"'); 492 | } 493 | Some('«') | Some('»') => { 494 | let лок = Лок { 495 | строка: self.строка + 1, 496 | столбец: self.позиция - self.начало_строки + 1, 497 | путь_к_файлу: self.путь_к_файлу.to_path_buf(), 498 | }; 499 | диагностика!(&лок, "ОШИБКА", "Экранировать «ёлочки» внутри \"лапок\" не нужно!"); 500 | return Err(()); 501 | } 502 | Some(сим) => { 503 | let лок = Лок { 504 | строка: self.строка + 1, 505 | столбец: self.позиция - self.начало_строки + 1, 506 | путь_к_файлу: self.путь_к_файлу.to_path_buf(), 507 | }; 508 | диагностика!(&лок, "ОШИБКА", "неизвестная поседовательность экранирования начинается с «{сим}»"); 509 | return Err(()); 510 | } 511 | None => { 512 | диагностика!(&лок, "ОШИБКА", "незавершённая строка"); 513 | return Err(()); 514 | } 515 | } 516 | } 517 | _ => { 518 | self.отрезать_символ(); 519 | текст.push(сим) 520 | } 521 | } 522 | } else { 523 | диагностика!(&лок, "ОШИБКА", "незавершённая строка"); 524 | return Err(()); 525 | } 526 | } 527 | } 528 | 529 | for &(приставка, вид) in ПРИСТАВКИ_ПРЕПИНАНИЙ.iter() { 530 | if self.имеет_приставку(приставка) { 531 | self.отрезать_символы(приставка.len()); 532 | let текст = приставка.iter().collect(); 533 | return Ok(Лексема {вид, текст, лок}) 534 | } 535 | } 536 | 537 | self.отрезать_символ(); 538 | диагностика!(&лок, "ОШИБКА", "Неизвестная лексема начинающаяся с «{сим}»"); 539 | Err(()) 540 | } 541 | 542 | pub fn вытащить_лексему(&mut self) -> Результат<Лексема> { 543 | if let Some(лексема) = self.буфер.take() { 544 | лексема 545 | } else { 546 | self.следующая_лексема() 547 | } 548 | } 549 | 550 | pub fn подсмотреть_лексему(&mut self) -> Результат<Лексема> { 551 | if self.буфер.is_none() { 552 | self.буфер = Some(self.следующая_лексема()) 553 | } 554 | self.буфер.clone().unwrap() 555 | } 556 | 557 | pub fn вытащить_лексему_вида(&mut self, ожидаемые_виды: &[ВидЛексемы]) -> Результат<Лексема> { 558 | assert!(ожидаемые_виды.len() > 0); 559 | 560 | let лексема = self.вытащить_лексему()?; 561 | for ожидаемый_вид in ожидаемые_виды { 562 | if лексема.вид == *ожидаемый_вид { 563 | return Ok(лексема) 564 | } 565 | } 566 | 567 | if ожидаемые_виды.len() == 1 { 568 | let ожидаемый_вид = ожидаемые_виды[0]; 569 | диагностика!(&лексема.лок, "ОШИБКА", 570 | "{ожидался} {ожидаемый_вид}, но {повстречался} {действительный_вид}", 571 | ожидался = ГЛАГОЛ_ОЖИДАЛСЯ.отобразить(&ожидаемый_вид.сущ().род), 572 | ожидаемый_вид = ожидаемый_вид.сущ().текст, 573 | повстречался = ГЛАГОЛ_ПОВСТРЕЧАЛСЯ.отобразить(&лексема.вид.сущ().род), 574 | действительный_вид = лексема.вид.сущ().текст); 575 | } else { 576 | let mut список_видов = String::new(); 577 | for (порядок, ожидаемый_вид) in ожидаемые_виды.iter().enumerate() { 578 | let ожидаемый_вид = ожидаемый_вид.сущ().текст; 579 | if порядок == 0 { 580 | write!(&mut список_видов, "{ожидаемый_вид}").unwrap(); 581 | } else { 582 | write!(&mut список_видов, ", либо {ожидаемый_вид}").unwrap(); 583 | } 584 | } 585 | диагностика!(&лексема.лок, "ОШИБКА", 586 | "ожидались {список_видов}, но {повстречался} {действительный_вид}", 587 | повстречался = ГЛАГОЛ_ПОВСТРЕЧАЛСЯ.отобразить(&лексема.вид.сущ().род), 588 | действительный_вид = лексема.вид.сущ().текст); 589 | } 590 | 591 | Err(()) 592 | } 593 | } 594 | -------------------------------------------------------------------------------- /исходники/фазм.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::io::{self, Write}; 3 | use std::path::Path; 4 | use std::process::{Command, Stdio}; 5 | use компилятор::ПП; 6 | use компилятор::ВидИнструкции; 7 | use типизация::*; 8 | use Результат; 9 | 10 | fn сгенерировать_инструкции(файл: &mut impl Write, пп: &ПП, точка_входа_программы: usize) -> Результат<()> { 11 | let mut внешние_символы: Vec<_> = пп.внешние_символы.iter().collect(); 12 | внешние_символы.sort_by_key(|(_, индекс)| *индекс); 13 | // https://stackoverflow.com/questions/18024672/what-registers-are-preserved-through-a-linux-x86-64-function-call 14 | let _ = writeln!(файл, " mov r12, начало_второго_стека"); 15 | let _ = writeln!(файл, " mov r13, начало_второго_стека"); 16 | let _ = writeln!(файл, " call инструкция_{точка_входа_программы}"); 17 | let _ = writeln!(файл, " mov rax, 60"); 18 | let _ = writeln!(файл, " mov rdi, 0"); 19 | let _ = writeln!(файл, " syscall"); 20 | for (индекс, инструкция) in пп.код.iter().enumerate() { 21 | let _ = writeln!(файл, "инструкция_{индекс}: ;;; {путь_к_файлу}:{строка}:{столбец}: {вид_инструкции:?}", 22 | путь_к_файлу = инструкция.лок.путь_к_файлу.display(), 23 | строка = инструкция.лок.строка, 24 | столбец = инструкция.лок.столбец, 25 | вид_инструкции = инструкция.вид); 26 | match &инструкция.вид { 27 | ВидИнструкции::Ноп => {} 28 | ВидИнструкции::Вытолкнуть => { 29 | let _ = writeln!(файл, " pop rax"); 30 | } 31 | ВидИнструкции::Продублировать => { 32 | let _ = writeln!(файл, " pop rax"); 33 | let _ = writeln!(файл, " push rax"); 34 | let _ = writeln!(файл, " push rax"); 35 | } 36 | ВидИнструкции::Натуральное(значение) => { 37 | let _ = writeln!(файл, " mov rax, {значение}"); 38 | let _ = writeln!(файл, " push rax"); 39 | } 40 | ВидИнструкции::Целое(значение) => { 41 | let _ = writeln!(файл, " mov rax, {значение}"); 42 | let _ = writeln!(файл, " push rax"); 43 | } 44 | ВидИнструкции::ГлобальныеДанные(смещение) => { 45 | if *смещение < 0 { 46 | let _ = writeln!(файл, " mov rax, данные{смещение}"); 47 | } else { 48 | let _ = writeln!(файл, " mov rax, данные+{смещение}"); 49 | } 50 | let _ = writeln!(файл, " push rax"); 51 | } 52 | ВидИнструкции::ВыделитьНаСтеке(размер) => { 53 | let _ = writeln!(файл, " sub r12, {размер}"); 54 | } 55 | ВидИнструкции::ОсвободитьСоСтека(размер) => { 56 | let _ = writeln!(файл, " add r12, {размер}"); 57 | } 58 | ВидИнструкции::ВершинаСтека(смещение) => { 59 | let _ = writeln!(файл, " mov rax, r12"); 60 | let _ = writeln!(файл, " add rax, {смещение}"); 61 | let _ = writeln!(файл, " push rax"); 62 | } 63 | ВидИнструкции::СохранитьКадр => { 64 | let _ = writeln!(файл, " mov rax, r13"); 65 | let _ = writeln!(файл, " mov r13, r12"); 66 | let _ = writeln!(файл, " sub r12, 8"); 67 | let _ = writeln!(файл, " mov [r12], rax"); 68 | } 69 | ВидИнструкции::ВосстановитьКадр => { 70 | let _ = writeln!(файл, " mov r13, [r12]"); 71 | let _ = writeln!(файл, " add r12, 8"); 72 | } 73 | ВидИнструкции::Кадр(смещение) => { 74 | let _ = writeln!(файл, " mov rax, r13"); 75 | let _ = writeln!(файл, " add rax, {смещение}"); 76 | let _ = writeln!(файл, " push rax"); 77 | } 78 | ВидИнструкции::АргументНаСтек => { 79 | let _ = writeln!(файл, " pop rax"); 80 | let _ = writeln!(файл, " sub r12, 8"); 81 | let _ = writeln!(файл, " mov [r12], rax"); 82 | } 83 | ВидИнструкции::АргументСоСтека => { 84 | let _ = writeln!(файл, " mov rax, [r12]"); 85 | let _ = writeln!(файл, " push rax"); 86 | let _ = writeln!(файл, " add r12, 8"); 87 | } 88 | ВидИнструкции::Записать8 => { 89 | let _ = writeln!(файл, " pop rsi"); 90 | let _ = writeln!(файл, " pop rax"); 91 | let _ = writeln!(файл, " mov [rsi], al"); 92 | } 93 | ВидИнструкции::Записать16 => { 94 | сделать!(&инструкция.лок, "Кодогенерация инструкции Записать16"); 95 | return Err(()) 96 | } 97 | ВидИнструкции::Записать32 => { 98 | let _ = writeln!(файл, " pop rsi"); 99 | let _ = writeln!(файл, " pop rax"); 100 | let _ = writeln!(файл, " mov [rsi], eax"); 101 | } 102 | ВидИнструкции::Записать64 => { 103 | let _ = writeln!(файл, " pop rsi"); 104 | let _ = writeln!(файл, " pop rax"); 105 | let _ = writeln!(файл, " mov [rsi], rax"); 106 | } 107 | ВидИнструкции::ПрочитатьБезЗнак8 => { 108 | let _ = writeln!(файл, " pop rsi"); 109 | let _ = writeln!(файл, " xor rax, rax"); 110 | let _ = writeln!(файл, " mov al, [rsi]"); 111 | let _ = writeln!(файл, " push rax"); 112 | } 113 | ВидИнструкции::ПрочитатьБезЗнак16 => { 114 | сделать!(&инструкция.лок, "Кодогенерация инструкции ПрочитатьБезЗнак16"); 115 | return Err(()) 116 | } 117 | ВидИнструкции::ПрочитатьБезЗнак32 => { 118 | let _ = writeln!(файл, " pop rsi"); 119 | let _ = writeln!(файл, " xor rax, rax"); 120 | let _ = writeln!(файл, " mov eax, [rsi]"); 121 | let _ = writeln!(файл, " push rax"); 122 | } 123 | ВидИнструкции::ПрочитатьЗнак8 => { 124 | сделать!(&инструкция.лок, "Кодогенерация инструкции ПрочитатьЗнак8"); 125 | return Err(()) 126 | } 127 | ВидИнструкции::ПрочитатьЗнак16 => { 128 | сделать!(&инструкция.лок, "Кодогенерация инструкции ПрочитатьЗнак16"); 129 | return Err(()) 130 | } 131 | ВидИнструкции::ПрочитатьЗнак32 => { 132 | сделать!(&инструкция.лок, "Кодогенерация инструкции ПрочитатьЗнак32"); 133 | return Err(()) 134 | } 135 | ВидИнструкции::Прочитать64 => { 136 | let _ = writeln!(файл, " pop rsi"); 137 | let _ = writeln!(файл, " mov rax, [rsi]"); 138 | let _ = writeln!(файл, " push rax"); 139 | } 140 | ВидИнструкции::СкопироватьПамять => { 141 | let _ = writeln!(файл, " cld"); 142 | let _ = writeln!(файл, " pop rcx"); 143 | let _ = writeln!(файл, " pop rdi"); 144 | let _ = writeln!(файл, " pop rsi"); 145 | let _ = writeln!(файл, " rep movsb"); 146 | } 147 | ВидИнструкции::ПамятьРавно => { 148 | let _ = writeln!(файл, " xor rax, rax"); 149 | let _ = writeln!(файл, " cld"); 150 | let _ = writeln!(файл, " pop rcx"); 151 | let _ = writeln!(файл, " pop rdi"); 152 | let _ = writeln!(файл, " pop rsi"); 153 | let _ = writeln!(файл, " rep cmpsb"); 154 | let _ = writeln!(файл, " setz al"); 155 | let _ = writeln!(файл, " push rax"); 156 | } 157 | ВидИнструкции::НатСложение => { 158 | let _ = writeln!(файл, " pop rbx"); 159 | let _ = writeln!(файл, " pop rax"); 160 | let _ = writeln!(файл, " add rax, rbx"); 161 | let _ = writeln!(файл, " push rax"); 162 | } 163 | ВидИнструкции::НатВычитание => { 164 | let _ = writeln!(файл, " pop rbx"); 165 | let _ = writeln!(файл, " pop rax"); 166 | let _ = writeln!(файл, " sub rax, rbx"); 167 | let _ = writeln!(файл, " push rax"); 168 | } 169 | ВидИнструкции::НатУмножение => { 170 | let _ = writeln!(файл, " pop rbx"); 171 | let _ = writeln!(файл, " pop rax"); 172 | let _ = writeln!(файл, " xor rdx, rdx"); 173 | let _ = writeln!(файл, " mul rbx"); 174 | let _ = writeln!(файл, " push rax"); 175 | } 176 | ВидИнструкции::НатДеление => { 177 | let _ = writeln!(файл, " pop rbx"); 178 | let _ = writeln!(файл, " pop rax"); 179 | let _ = writeln!(файл, " xor rdx, rdx"); 180 | let _ = writeln!(файл, " div rbx"); 181 | let _ = writeln!(файл, " push rax"); 182 | } 183 | ВидИнструкции::НатОстаток => { 184 | let _ = writeln!(файл, " pop rbx"); 185 | let _ = writeln!(файл, " pop rax"); 186 | let _ = writeln!(файл, " xor rdx, rdx"); 187 | let _ = writeln!(файл, " div rbx"); 188 | let _ = writeln!(файл, " push rdx"); 189 | } 190 | ВидИнструкции::НатМеньше => { 191 | let _ = writeln!(файл, " pop rbx"); 192 | let _ = writeln!(файл, " pop rax"); 193 | let _ = writeln!(файл, " xor rcx, rcx"); 194 | let _ = writeln!(файл, " cmp rax, rbx"); 195 | let _ = writeln!(файл, " setb cl"); 196 | let _ = writeln!(файл, " push rcx"); 197 | // СДЕЛАТЬ: можно ли использовать условное 198 | // перемещение для реализации инструкций сравнения? 199 | } 200 | ВидИнструкции::НатМеньшеРавно => { 201 | let _ = writeln!(файл, " pop rbx"); 202 | let _ = writeln!(файл, " pop rax"); 203 | let _ = writeln!(файл, " xor rcx, rcx"); 204 | let _ = writeln!(файл, " cmp rax, rbx"); 205 | let _ = writeln!(файл, " setbe cl"); 206 | let _ = writeln!(файл, " push rcx"); 207 | } 208 | ВидИнструкции::НатБольше => { 209 | let _ = writeln!(файл, " pop rbx"); 210 | let _ = writeln!(файл, " pop rax"); 211 | let _ = writeln!(файл, " xor rcx, rcx"); 212 | let _ = writeln!(файл, " cmp rax, rbx"); 213 | let _ = writeln!(файл, " seta cl"); 214 | let _ = writeln!(файл, " push rcx"); 215 | } 216 | ВидИнструкции::НатБольшеРавно => { 217 | let _ = writeln!(файл, " pop rbx"); 218 | let _ = writeln!(файл, " pop rax"); 219 | let _ = writeln!(файл, " xor rcx, rcx"); 220 | let _ = writeln!(файл, " cmp rax, rbx"); 221 | let _ = writeln!(файл, " setae cl"); 222 | let _ = writeln!(файл, " push rcx"); 223 | } 224 | ВидИнструкции::НатРавно => { 225 | let _ = writeln!(файл, " pop rbx"); 226 | let _ = writeln!(файл, " pop rax"); 227 | let _ = writeln!(файл, " xor rcx, rcx"); 228 | let _ = writeln!(файл, " cmp rax, rbx"); 229 | let _ = writeln!(файл, " setz cl"); 230 | let _ = writeln!(файл, " push rcx"); 231 | } 232 | ВидИнструкции::ЦелМеньше => { 233 | let _ = writeln!(файл, " pop rbx"); 234 | let _ = writeln!(файл, " pop rax"); 235 | let _ = writeln!(файл, " xor rcx, rcx"); 236 | let _ = writeln!(файл, " cmp rax, rbx"); 237 | let _ = writeln!(файл, " setl cl"); 238 | let _ = writeln!(файл, " push rcx"); 239 | } 240 | ВидИнструкции::ЦелМеньшеРавно => { 241 | let _ = writeln!(файл, " pop rbx"); 242 | let _ = writeln!(файл, " pop rax"); 243 | let _ = writeln!(файл, " xor rcx, rcx"); 244 | let _ = writeln!(файл, " cmp rax, rbx"); 245 | let _ = writeln!(файл, " setle cl"); 246 | let _ = writeln!(файл, " push rcx"); 247 | } 248 | ВидИнструкции::ЦелБольше => { 249 | let _ = writeln!(файл, " pop rbx"); 250 | let _ = writeln!(файл, " pop rax"); 251 | let _ = writeln!(файл, " xor rcx, rcx"); 252 | let _ = writeln!(файл, " cmp rax, rbx"); 253 | let _ = writeln!(файл, " setg cl"); 254 | let _ = writeln!(файл, " push rcx"); 255 | } 256 | ВидИнструкции::ЦелБольшеРавно => { 257 | let _ = writeln!(файл, " pop rbx"); 258 | let _ = writeln!(файл, " pop rax"); 259 | let _ = writeln!(файл, " xor rcx, rcx"); 260 | let _ = writeln!(файл, " cmp rax, rbx"); 261 | let _ = writeln!(файл, " setge cl"); 262 | let _ = writeln!(файл, " push rcx"); 263 | } 264 | ВидИнструкции::ЦелУмножение => { 265 | let _ = writeln!(файл, " pop rbx"); 266 | let _ = writeln!(файл, " pop rax"); 267 | let _ = writeln!(файл, " xor rdx, rdx"); 268 | let _ = writeln!(файл, " imul rbx"); 269 | let _ = writeln!(файл, " push rax"); 270 | } 271 | ВидИнструкции::ЦелДеление => { 272 | let _ = writeln!(файл, " pop rbx"); 273 | let _ = writeln!(файл, " pop rax"); 274 | let _ = writeln!(файл, " cqo"); 275 | let _ = writeln!(файл, " idiv rbx"); 276 | let _ = writeln!(файл, " push rax"); 277 | } 278 | ВидИнструкции::ЦелОстаток => { 279 | let _ = writeln!(файл, " pop rbx"); 280 | let _ = writeln!(файл, " pop rax"); 281 | let _ = writeln!(файл, " cqo"); 282 | let _ = writeln!(файл, " idiv rbx"); 283 | let _ = writeln!(файл, " push rdx"); 284 | } 285 | ВидИнструкции::ЦелОтриц => { 286 | let _ = writeln!(файл, " pop rax"); 287 | let _ = writeln!(файл, " neg rax"); 288 | let _ = writeln!(файл, " push rax"); 289 | } 290 | ВидИнструкции::КонвертНат64Вещ32 => { 291 | // СДЕЛАТЬ: конвертация натуральных чисел в вещественные (и обратно) использует знаковую конвертацию. 292 | // 293 | // В общем, ничего плохого в этом нет до тех пор пока натуральные числе 294 | // не слишком большие. 295 | // 296 | // Для больших натуральных чисел нам нужно использовать трюки, которые 297 | // используют компиляторы языка Си: делим значение на два, чтобы убрать 298 | // бит знака, конвертируем споловиненное значение, и умножаем вещественный 299 | // результат обратно на два. С учётом остатков конечно же. 300 | let _ = writeln!(файл, " pop rax"); 301 | let _ = writeln!(файл, " pxor xmm0, xmm0"); 302 | let _ = writeln!(файл, " cvtsi2ss xmm0, rax"); 303 | let _ = writeln!(файл, " movd eax, xmm0"); 304 | let _ = writeln!(файл, " push rax"); 305 | } 306 | ВидИнструкции::КонвертЦел64Вещ32 => { 307 | let _ = writeln!(файл, " pop rax"); 308 | let _ = writeln!(файл, " pxor xmm0, xmm0"); 309 | let _ = writeln!(файл, " cvtsi2ss xmm0, rax"); 310 | let _ = writeln!(файл, " movd eax, xmm0"); 311 | let _ = writeln!(файл, " push rax"); 312 | } 313 | ВидИнструкции::КонвертВещ32Нат64 => { 314 | let _ = writeln!(файл, " pop rax"); 315 | let _ = writeln!(файл, " movd xmm0, eax"); 316 | let _ = writeln!(файл, " cvttss2si rax, xmm0"); 317 | let _ = writeln!(файл, " push rax"); 318 | } 319 | ВидИнструкции::КонвертВещ32Цел64 => { 320 | let _ = writeln!(файл, " pop rax"); 321 | let _ = writeln!(файл, " movd xmm0, eax"); 322 | let _ = writeln!(файл, " cvttss2si rax, xmm0"); 323 | let _ = writeln!(файл, " push rax"); 324 | } 325 | ВидИнструкции::Вещ32Умножение => { 326 | let _ = writeln!(файл, " pop rax"); 327 | let _ = writeln!(файл, " pop rbx"); 328 | let _ = writeln!(файл, " movd xmm0, eax"); 329 | let _ = writeln!(файл, " movd xmm1, ebx"); 330 | let _ = writeln!(файл, " mulss xmm0, xmm1"); 331 | let _ = writeln!(файл, " movd eax, xmm0"); 332 | let _ = writeln!(файл, " push rax"); 333 | } 334 | ВидИнструкции::Вещ32Деление => { 335 | let _ = writeln!(файл, " pop rbx"); 336 | let _ = writeln!(файл, " pop rax"); 337 | let _ = writeln!(файл, " movd xmm0, eax"); 338 | let _ = writeln!(файл, " movd xmm1, ebx"); 339 | let _ = writeln!(файл, " divss xmm0, xmm1"); 340 | let _ = writeln!(файл, " movd eax, xmm0"); 341 | let _ = writeln!(файл, " push rax"); 342 | } 343 | ВидИнструкции::Вещ32Сложение => { 344 | let _ = writeln!(файл, " pop rax"); 345 | let _ = writeln!(файл, " pop rbx"); 346 | let _ = writeln!(файл, " movd xmm0, eax"); 347 | let _ = writeln!(файл, " movd xmm1, ebx"); 348 | let _ = writeln!(файл, " addss xmm0, xmm1"); 349 | let _ = writeln!(файл, " movd eax, xmm0"); 350 | let _ = writeln!(файл, " push rax"); 351 | } 352 | ВидИнструкции::Вещ32Вычитание => { 353 | let _ = writeln!(файл, " pop rbx"); 354 | let _ = writeln!(файл, " pop rax"); 355 | let _ = writeln!(файл, " movd xmm0, eax"); 356 | let _ = writeln!(файл, " movd xmm1, ebx"); 357 | let _ = writeln!(файл, " subss xmm0, xmm1"); 358 | let _ = writeln!(файл, " movd eax, xmm0"); 359 | let _ = writeln!(файл, " push rax"); 360 | } 361 | ВидИнструкции::Вещ32Меньше => { 362 | let _ = writeln!(файл, " pop rbx"); 363 | let _ = writeln!(файл, " pop rax"); 364 | let _ = writeln!(файл, " movd xmm0, eax"); 365 | let _ = writeln!(файл, " movd xmm1, ebx"); 366 | let _ = writeln!(файл, " cmpltss xmm0, xmm1"); 367 | let _ = writeln!(файл, " movd eax, xmm0"); 368 | let _ = writeln!(файл, " push rax"); 369 | } 370 | ВидИнструкции::Вещ32МеньшеРавно => { 371 | let _ = writeln!(файл, " pop rbx"); 372 | let _ = writeln!(файл, " pop rax"); 373 | let _ = writeln!(файл, " movd xmm0, eax"); 374 | let _ = writeln!(файл, " movd xmm1, ebx"); 375 | let _ = writeln!(файл, " cmpless xmm0, xmm1"); 376 | let _ = writeln!(файл, " movd eax, xmm0"); 377 | let _ = writeln!(файл, " push rax"); 378 | } 379 | ВидИнструкции::Вещ32Больше => { 380 | let _ = writeln!(файл, " pop rbx"); 381 | let _ = writeln!(файл, " pop rax"); 382 | let _ = writeln!(файл, " movd xmm0, eax"); 383 | let _ = writeln!(файл, " movd xmm1, ebx"); 384 | let _ = writeln!(файл, " cmpnless xmm0, xmm1"); 385 | let _ = writeln!(файл, " movd eax, xmm0"); 386 | let _ = writeln!(файл, " push rax"); 387 | } 388 | ВидИнструкции::Вещ32БольшеРавно => { 389 | let _ = writeln!(файл, " pop rbx"); 390 | let _ = writeln!(файл, " pop rax"); 391 | let _ = writeln!(файл, " movd xmm0, eax"); 392 | let _ = writeln!(файл, " movd xmm1, ebx"); 393 | let _ = writeln!(файл, " cmpnltss xmm0, xmm1"); 394 | let _ = writeln!(файл, " movd eax, xmm0"); 395 | let _ = writeln!(файл, " push rax"); 396 | } 397 | ВидИнструкции::Вещ32Отриц => { 398 | let _ = writeln!(файл, " mov eax, 0x80000000"); 399 | let _ = writeln!(файл, " pop rbx"); 400 | let _ = writeln!(файл, " movd xmm0, ebx"); 401 | let _ = writeln!(файл, " movd xmm1, eax"); 402 | let _ = writeln!(файл, " pxor xmm0, xmm1"); 403 | let _ = writeln!(файл, " movd eax, xmm0"); 404 | let _ = writeln!(файл, " push rax"); 405 | } 406 | ВидИнструкции::ЛогОтрицание => { 407 | let _ = writeln!(файл, " xor rbx, rbx"); 408 | let _ = writeln!(файл, " pop rax"); 409 | let _ = writeln!(файл, " test rax, rax"); 410 | let _ = writeln!(файл, " setz bl"); 411 | let _ = writeln!(файл, " push rbx"); 412 | } 413 | ВидИнструкции::БитИли => { 414 | let _ = writeln!(файл, " pop rax"); 415 | let _ = writeln!(файл, " pop rbx"); 416 | let _ = writeln!(файл, " or rax, rbx"); 417 | let _ = writeln!(файл, " push rax"); 418 | } 419 | ВидИнструкции::БитИ => { 420 | let _ = writeln!(файл, " pop rax"); 421 | let _ = writeln!(файл, " pop rbx"); 422 | let _ = writeln!(файл, " and rax, rbx"); 423 | let _ = writeln!(файл, " push rax"); 424 | } 425 | ВидИнструкции::БитЛибо => { 426 | let _ = writeln!(файл, " pop rax"); 427 | let _ = writeln!(файл, " pop rbx"); 428 | let _ = writeln!(файл, " xor rax, rbx"); 429 | let _ = writeln!(файл, " push rax"); 430 | } 431 | ВидИнструкции::БитСмещениеВлево => { 432 | let _ = writeln!(файл, " pop rcx"); 433 | let _ = writeln!(файл, " pop rax"); 434 | let _ = writeln!(файл, " shl rax, cl"); 435 | let _ = writeln!(файл, " push rax"); 436 | } 437 | // СДЕЛАТЬ: правое битовое смещение положительных и отрицательных чисел может отличаться 438 | ВидИнструкции::БитСмещениеВправо => { 439 | let _ = writeln!(файл, " pop rcx"); 440 | let _ = writeln!(файл, " pop rax"); 441 | let _ = writeln!(файл, " shr rax, cl"); 442 | let _ = writeln!(файл, " push rax"); 443 | } 444 | ВидИнструкции::ПечатьСтроки => { 445 | let _ = writeln!(файл, " pop rbx"); 446 | let _ = writeln!(файл, " mov rsi, [rbx+{}]", СРЕЗ_АДРЕС_СМЕЩЕНИЕ); 447 | let _ = writeln!(файл, " mov rdx, [rbx+{}]", СРЕЗ_РАЗМЕР_СМЕЩЕНИЕ); 448 | let _ = writeln!(файл, " mov rax, 1 ; SYS_write"); 449 | let _ = writeln!(файл, " mov rdi, 1 ; stdout"); 450 | let _ = writeln!(файл, " syscall"); 451 | } 452 | ВидИнструкции::Ввод => { 453 | let _ = writeln!(файл, " mov rax, 0 ; SYS_read"); 454 | let _ = writeln!(файл, " mov rdi, 0 ; stdin"); 455 | let _ = writeln!(файл, " pop rdx"); 456 | let _ = writeln!(файл, " pop rsi"); 457 | let _ = writeln!(файл, " syscall"); 458 | let _ = writeln!(файл, " push rax"); 459 | } 460 | ВидИнструкции::Возврат => { 461 | let _ = writeln!(файл, " ret"); 462 | } 463 | ВидИнструкции::ВнутреннийВызов(индекс_инструкции_пп_цели) => { 464 | let _ = writeln!(файл, " call инструкция_{индекс_инструкции_пп_цели}"); 465 | } 466 | ВидИнструкции::ВнешнийВызов{индекс, арность, результат} => { 467 | let регистры = &["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; 468 | if *арность > регистры.len() { 469 | сделать!(&инструкция.лок, "Слишком большая арность"); 470 | return Err(()) 471 | } 472 | for регистр in &регистры[0..*арность] { 473 | let _ = writeln!(файл, " pop {регистр}"); 474 | } 475 | let _ = writeln!(файл, " call {имя}", имя = внешние_символы[*индекс].0); 476 | if let Some(результат) = результат { 477 | match результат { 478 | Тип::Нат64 | Тип::Цел64 | Тип::Лог => { 479 | let _ = writeln!(файл, " push rax"); 480 | }, 481 | Тип::Вещ32 => { 482 | let _ = writeln!(файл, " movd eax, xmm0"); 483 | let _ = writeln!(файл, " push rax"); 484 | } 485 | _ => { 486 | сделать!(&инструкция.лок, "Кодогенерация возврата типа «{тип}» из внешних процедур", 487 | тип = результат.текст()); 488 | return Err(()) 489 | } 490 | } 491 | } 492 | } 493 | ВидИнструкции::Прыжок(индекс_инструкции_пп_цели) => { 494 | let _ = writeln!(файл, " jmp инструкция_{индекс_инструкции_пп_цели}"); 495 | } 496 | ВидИнструкции::УсловныйПрыжок(индекс_инструкции_пп_цели) => { 497 | let _ = writeln!(файл, " pop rax"); 498 | let _ = writeln!(файл, " test rax, rax"); 499 | let _ = writeln!(файл, " jnz инструкция_{индекс_инструкции_пп_цели}"); 500 | } 501 | ВидИнструкции::СисВызов{..} => { 502 | сделать!(&инструкция.лок, "Кодогенерация для инструкции «{вид:?}»", вид = инструкция.вид); 503 | return Err(()) 504 | } 505 | } 506 | } 507 | Ok(()) 508 | } 509 | 510 | pub fn сгенерировать_исполняемый_файл(путь_к_исполняемому: &Path, пп: &ПП, точка_входа_программы: usize) -> Результат<()> { 511 | let статический = пп.внешние_символы.len() == 0; 512 | 513 | let путь_к_фазму = путь_к_исполняемому.with_extension("fasm"); 514 | let файл = fs::File::create(&путь_к_фазму).map_err(|ошибка| { 515 | eprintln!("ОШИБКА: не удалось открыть файл «{путь_к_фазму}»: {ошибка}", 516 | путь_к_фазму = путь_к_фазму.display()); 517 | })?; 518 | let mut файл = io::BufWriter::new(файл); 519 | if статический { 520 | let _ = writeln!(&mut файл, "format ELF64 executable"); 521 | let _ = writeln!(&mut файл, "entry _start"); 522 | let _ = writeln!(&mut файл, "_start:"); 523 | } else { 524 | let _ = writeln!(&mut файл, "format ELF64"); 525 | let _ = writeln!(&mut файл, "section \".text\" executable"); 526 | let _ = writeln!(&mut файл, "public _start"); 527 | for (имя, _) in &пп.внешние_символы { 528 | let _ = writeln!(&mut файл, "extrn {имя}"); 529 | } 530 | let _ = writeln!(&mut файл, "_start:"); 531 | } 532 | сгенерировать_инструкции(&mut файл, пп, точка_входа_программы)?; 533 | 534 | if !статический { 535 | let _ = writeln!(&mut файл, "section \".data\" writable"); 536 | } 537 | 538 | let _ = writeln!(&mut файл, "данные:"); 539 | let длинна_строки = 10; 540 | let количество_строк = пп.иниц_данные.len()/10; 541 | let остаток_строки = пп.иниц_данные.len()%длинна_строки; 542 | for строка in 0..количество_строк { 543 | let _ = write!(&mut файл, " db"); 544 | for столбец in 0..длинна_строки { 545 | let индекс = строка*длинна_строки + столбец; 546 | let _ = write!(&mut файл, " {байт:#04X}", байт = пп.иниц_данные[индекс]); 547 | if столбец + 1 < длинна_строки { 548 | let _ = write!(&mut файл, ","); 549 | } 550 | } 551 | let _ = writeln!(&mut файл); 552 | } 553 | if остаток_строки > 0 { 554 | let _ = write!(&mut файл, " db"); 555 | for столбец in 0..остаток_строки { 556 | let индекс = количество_строк*длинна_строки + столбец; 557 | let _ = write!(&mut файл, " {байт:#04X}", байт = пп.иниц_данные[индекс]); 558 | if столбец + 1 < остаток_строки { 559 | let _ = write!(&mut файл, ","); 560 | } 561 | } 562 | let _ = writeln!(&mut файл); 563 | } 564 | let размер_второго_стека = 1_000_000; 565 | let _ = writeln!(&mut файл, " rb {}", пп.размер_неиниц_данных + размер_второго_стека); 566 | let _ = writeln!(&mut файл, "начало_второго_стека:"); 567 | 568 | if !статический { 569 | let _ = writeln!(&mut файл, "section \".note.GNU-stack\""); 570 | } 571 | 572 | drop(файл); 573 | println!("ИНФО: сгенерирован файл «{путь_к_фазму}»", 574 | путь_к_фазму = путь_к_фазму.display()); 575 | 576 | // СДЕЛАТЬ: более умный способ находить бинарник fasm и ld. Возможно имеет смысл держать их прямо в репе. 577 | if статический { 578 | Command::new("fasm") 579 | .arg(&путь_к_фазму) 580 | .arg(&путь_к_исполняемому) 581 | .stdout(Stdio::inherit()) 582 | .spawn() 583 | .map_err(|ошибка| { 584 | eprintln!("ОШИБКА: не получилось запустить дочерний процесс fasm: {ошибка}"); 585 | })? 586 | .wait() 587 | .map_err(|ошибка| { 588 | eprintln!("ОШИБКА: что-то пошло не так пока мы ждали завершения дочернего процесса fasm: {ошибка}"); 589 | })?; 590 | println!("ИНФО: сгенерирован файл «{путь_к_исполняемому}»", 591 | путь_к_исполняемому = путь_к_исполняемому.display()); 592 | } else { 593 | let путь_к_объектнику = путь_к_исполняемому.with_extension("o"); 594 | 595 | Command::new("fasm") 596 | .arg(&путь_к_фазму) 597 | .arg(&путь_к_объектнику) 598 | .stdout(Stdio::inherit()) 599 | .spawn() 600 | .map_err(|ошибка| { 601 | eprintln!("ОШИБКА: не получилось запустить дочерний процесс fasm: {ошибка}"); 602 | })? 603 | .wait() 604 | .map_err(|ошибка| { 605 | eprintln!("ОШИБКА: что-то пошло не так пока мы ждали завершения дочернего процесса fasm: {ошибка}"); 606 | })?; 607 | 608 | println!("ИНФО: сгенерирован файл «{путь_к_объектнику}»", 609 | путь_к_объектнику = путь_к_объектнику.display()); 610 | 611 | let mut кмд = Command::new("ld"); 612 | кмд 613 | .arg("-o").arg(&путь_к_исполняемому) 614 | .arg(путь_к_объектнику) 615 | // СДЕЛАТЬ: расхардкодить -dynamic-linker 616 | .arg("-dynamic-linker").arg("/lib64/ld-linux-x86-64.so.2") 617 | // СДЕЛАТЬ: расхардкодить пусть к линкуемым библиотекам 618 | .arg("-L./модули/"); 619 | let mut библиотеки: Vec<_> = пп.библиотеки.iter().collect(); 620 | библиотеки.sort_by_key(|(_, индекс)| *индекс); 621 | for (имя, _) in &библиотеки { 622 | кмд.arg(format!("-l{имя}")); 623 | } 624 | кмд.stdout(Stdio::inherit()) 625 | .spawn() 626 | .map_err(|ошибка| { 627 | eprintln!("ОШИБКА: не получилось запустить дочерний процесс ld: {ошибка}"); 628 | })? 629 | .wait() 630 | .map_err(|ошибка| { 631 | eprintln!("ОШИБКА: что-то пошло не так пока мы ждали завершения дочернего процесса ld: {ошибка}"); 632 | })?; 633 | 634 | println!("ИНФО: сгенерирован файл «{путь_к_исполняемому}»", 635 | путь_к_исполняемому = путь_к_исполняемому.display()); 636 | } 637 | 638 | #[cfg(all(unix))] { 639 | use std::os::unix::fs::PermissionsExt; 640 | let файл = fs::File::open(&путь_к_исполняемому).map_err(|ошибка| { 641 | eprintln!("ОШИБКА: не получилось открыть файл «{путь_к_исполняемому}»: {ошибка}", 642 | путь_к_исполняемому = путь_к_исполняемому.display()); 643 | })?; 644 | let mut права = файл.metadata().map_err(|ошибка| { 645 | eprintln!("ОШИБКА: не получилось прочитать метаданные файла «{путь_к_исполняемому}»: {ошибка}", 646 | путь_к_исполняемому = путь_к_исполняемому.display()); 647 | })?.permissions(); 648 | права.set_mode(0o755); 649 | файл.set_permissions(права).map_err(|ошибка| { 650 | eprintln!("ОШИБКА: не получилось установить права для файла «{путь_к_исполняемому}»: {ошибка}", 651 | путь_к_исполняемому = путь_к_исполняемому.display()); 652 | })?; 653 | } 654 | 655 | Ok(()) 656 | } 657 | -------------------------------------------------------------------------------- /исходники/интерпретатор.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::io::{Read, Write, BufRead}; 3 | use std::convert::TryInto; 4 | use super::Результат; 5 | use std::mem; 6 | use компилятор::{ПП, ВидИнструкции, Инструкция, Имена}; 7 | use типизация::*; 8 | 9 | // Разметка памяти 10 | // | второй стек | инициализированные данные | неинициализированные данные | куча? | 11 | // ^ ^ 12 | // 0 Начало стека и данных. Стек растет в сторону нуля. 13 | 14 | pub const РАЗМЕР_СЛОВА: usize = mem::size_of::(); 15 | 16 | #[derive(Default)] 17 | pub struct Машина<'ы> { 18 | индекс_инструкции: usize, // аналог rip 19 | кадр: usize, // аналог rbp (для первого стека) 20 | второй_стек: usize, // аналог rsp 21 | кадр_второго_стека: usize, // аналог rbp (для второго стека) 22 | // В каком-то смысле, эти переменные выше являются регистрами 23 | // нашей виртуальной машины, не смотря на то, что машина-то 24 | // стековая. 25 | 26 | pub стек: Vec, 27 | начало_данных: usize, 28 | начало_второго_стека: usize, 29 | pub память: Vec, 30 | инструкции: &'ы [Инструкция], 31 | } 32 | 33 | macro_rules! ошибка_времени_исполнения { 34 | ($машина:expr, $($аргы:tt)*) => {{ 35 | let индекс_инструкции = $машина.индекс_инструкции; 36 | if let Some(инструкция) = $машина.инструкции.get(индекс_инструкции) { 37 | let вид_инструкции = &инструкция.вид; 38 | let ::диагностика::Лок{путь_к_файлу, строка, столбец} = &инструкция.лок; 39 | eprint!("{путь_к_файлу}:{строка}:{столбец}: {вид_инструкции:?}: ", путь_к_файлу = путь_к_файлу.display()); 40 | } 41 | eprint!("ОШИБКА ВРЕМЕНИ ИСПОЛНЕНИЯ: {индекс_инструкции}: "); 42 | eprintln!($($аргы)*); 43 | }}; 44 | } 45 | 46 | impl<'ы> Машина<'ы> { 47 | pub fn новая(пп: &ПП, объём_второго_стека: usize) -> Машина { 48 | let начало_данных = объём_второго_стека; 49 | let второй_стек = объём_второго_стека; 50 | let кадр_второго_стека = объём_второго_стека; 51 | let начало_второго_стека = объём_второго_стека; 52 | let mut машина = Машина { 53 | индекс_инструкции: 0, 54 | кадр: 0, 55 | второй_стек, 56 | кадр_второго_стека, 57 | стек: Vec::new(), 58 | 59 | начало_данных, 60 | начало_второго_стека, 61 | 62 | память: vec![], 63 | инструкции: &пп.код, 64 | }; 65 | 66 | // СДЕЛАТЬ: Ресайз вектора капец какой медленный. Возможно из-за 67 | // инициализации. Надо что-нибудь с этим сделать. 68 | машина.память.resize(машина.память.len() + объём_второго_стека, 0); 69 | машина.память.extend_from_slice(пп.иниц_данные.as_slice()); 70 | машина.память.resize(машина.память.len() + пп.размер_неиниц_данных, 0); 71 | машина 72 | } 73 | 74 | fn протолкнуть_значение_нат(&mut self, значение: usize) -> Результат<()> { 75 | self.стек.push(значение); 76 | Ok(()) 77 | } 78 | 79 | fn вытолкнуть_значение_нат(&mut self) -> Результат { 80 | if let Some(значение) = self.стек.pop() { 81 | Ok(значение) 82 | } else { 83 | ошибка_времени_исполнения!(self, "Опустошение стека"); 84 | Err(()) 85 | } 86 | } 87 | 88 | fn протолкнуть_значение_вещ32(&mut self, значение: f32) -> Результат<()> { 89 | let mut bytes = [0u8; 8]; 90 | bytes[0..4].copy_from_slice(&значение.to_le_bytes()); 91 | self.протолкнуть_значение_нат(usize::from_le_bytes(bytes)) 92 | } 93 | 94 | fn вытолкнуть_значение_вещ32(&mut self) -> Результат { 95 | Ok(f32::from_le_bytes(self.вытолкнуть_значение_нат()?.to_le_bytes()[0..4].try_into().unwrap())) 96 | } 97 | 98 | // СДЕЛАТЬ: вариант функции срез_памяти, который возвращает массив размера известного на этапе компиляции 99 | // Возможно через какие-нибудь дженерики. Такой вариант будет очень удобен для чтения примитивных типов 100 | // из памяти безо всяких этих try_into().unwrap() и прочей лабуды. 101 | pub fn срез_памяти(&mut self, адрес: usize, размер: usize) -> Результат<&mut [u8]> { 102 | let мин = self.второй_стек; 103 | let макс = self.память.len(); 104 | 105 | if адрес < мин { 106 | ошибка_времени_исполнения!(self, "Попытка получить доступ к некорректнному диапазону памяти [{начало}..{конец}). Разрешенный диапазон [{мин}..{макс})", начало = адрес, конец = адрес+размер); 107 | return Err(()) 108 | } 109 | 110 | if let Some(срез) = self.память.get_mut(адрес..адрес+размер) { 111 | Ok(срез) 112 | } else { 113 | ошибка_времени_исполнения!(self, "Попытка получить доступ к некорректнному диапазону памяти [{начало}..{конец}). Разрешенный диапазон [{мин}..{макс})", начало = адрес, конец = адрес+размер); 114 | Err(()) 115 | } 116 | } 117 | 118 | fn количество_элементов_стека(&self) -> usize { 119 | self.стек.len() 120 | } 121 | 122 | fn проверить_арность_аргументов(&self, арность: usize) -> Результат<()> { 123 | let размер_стека = self.количество_элементов_стека(); 124 | if размер_стека < арность { 125 | ошибка_времени_исполнения!(self, "Недостаточно аргументов для инструкции. Требуется как минимум {арность}, но всего в стеке аргументов находится {размер_стека}."); 126 | Err(()) 127 | } else { 128 | Ok(()) 129 | } 130 | } 131 | 132 | fn инструкция(&self) -> Результат<&Инструкция> { 133 | match self.инструкции.get(self.индекс_инструкции) { 134 | Some(инструкция) => Ok(инструкция), 135 | None => { 136 | ошибка_времени_исполнения!(self, "некорректный индекс инструкции"); 137 | Err(()) 138 | } 139 | } 140 | } 141 | 142 | fn выделить_на_втором_стеке(&mut self, размер: usize) -> Результат<()> { 143 | if self.второй_стек < размер { 144 | ошибка_времени_исполнения!(self, "переполнение второго стека"); 145 | return Err(()) 146 | } 147 | self.второй_стек -= размер; 148 | Ok(()) 149 | } 150 | 151 | fn освободить_со_второго_стека(&mut self, размер: usize) -> Результат<()> { 152 | if размер > self.начало_второго_стека - self.второй_стек { 153 | ошибка_времени_исполнения!(self, "опустошение второго стека"); 154 | return Err(()) 155 | } 156 | self.второй_стек += размер; 157 | Ok(()) 158 | } 159 | 160 | fn протолкнуть_на_второй_стек(&mut self, значение: usize) -> Результат<()> { 161 | self.выделить_на_втором_стеке(РАЗМЕР_СЛОВА)?; 162 | self.срез_памяти(self.второй_стек, РАЗМЕР_СЛОВА)?.copy_from_slice(&значение.to_le_bytes()); 163 | Ok(()) 164 | } 165 | 166 | fn вытолкнуть_из_второго_стека(&mut self) -> Результат { 167 | let значение = usize::from_le_bytes(self.срез_памяти(self.второй_стек, РАЗМЕР_СЛОВА)?.try_into().unwrap()); 168 | self.освободить_со_второго_стека(РАЗМЕР_СЛОВА)?; 169 | Ok(значение) 170 | } 171 | 172 | pub fn интерпретировать(&mut self, имена: &Имена, точка_входа: usize, режим_отладки: bool) -> Результат<()> { 173 | self.индекс_инструкции = точка_входа; 174 | 175 | let mut глубина_вызовов = 0; 176 | let mut цель_перешагивания: Option = None; 177 | self.протолкнуть_значение_нат(self.инструкции.len())?; 178 | loop { 179 | let индекс_инструкции = self.индекс_инструкции; 180 | let инструкция = self.инструкция()?; 181 | 182 | if режим_отладки { 183 | if let Some(цель) = цель_перешагивания.clone() { 184 | if глубина_вызовов <= цель { 185 | цель_перешагивания = None; 186 | } 187 | } 188 | 189 | if цель_перешагивания.is_none() { 190 | диагностика!(&инструкция.лок, "ИНСТРУКЦИЯ", "{индекс_инструкции}: {вид_инструкции:?}", вид_инструкции = инструкция.вид); 191 | eprintln!("стек = {стек:?}", стек = self.стек); 192 | eprintln!("кадр = {кадр}", кадр = self.кадр); 193 | eprintln!("второй_стек = {второй_стек}", второй_стек = self.второй_стек); 194 | eprintln!("кадр_второго_стека = {кадр_второго_стека}", кадр_второго_стека = self.кадр_второго_стека); 195 | eprintln!("переменные"); 196 | for (имя, переменная) in имена.переменные.iter() { 197 | let адрес = self.начало_данных + переменная.смещение as usize; 198 | eprintln!(" {имя}: {адрес:#X} = {:?}", &self.память[адрес..адрес+переменная.тип.размер(&имена.структуры)]); 199 | } 200 | loop { 201 | let mut команда = String::new(); 202 | eprint!("> "); 203 | io::stdin().lock().read_line(&mut команда).unwrap(); 204 | let аргы: Vec<&str> = команда.trim().split(' ').filter(|арг| арг.len() > 0).collect(); 205 | match аргы.as_slice() { 206 | ["выход", ..] => { 207 | return Ok(()); 208 | } 209 | ["инст", парам @ ..] => match парам { 210 | [инст] => match инст.parse::() { 211 | Ok(индекс_инструкции) => if let Some(инструкция) = self.инструкции.get(индекс_инструкции) { 212 | диагностика!(&инструкция.лок, "ИНСТРУКЦИЯ", "{индекс_инструкции}: {вид_инструкции:?}", вид_инструкции = инструкция.вид); 213 | } else { 214 | eprintln!("ОШИБКА: нету инструкции под номером {индекс_инструкции}") 215 | }, 216 | Err(_ошибка) => { 217 | eprintln!("ОШИБКА: индекс инструкции не является корректным целым числом"); 218 | }, 219 | }, 220 | _ => { 221 | eprintln!("Пример: инст [индекс_инструкции]"); 222 | eprintln!("ОШИБКА: требуется индекс инструкции"); 223 | } 224 | } 225 | ["перешаг", ..] => { 226 | цель_перешагивания = Some(глубина_вызовов); 227 | break 228 | } 229 | [команда, ..] => { 230 | eprintln!("ОШИБКА: неизвестная команда «{команда}»"); 231 | } 232 | [] => { 233 | break 234 | } 235 | } 236 | } 237 | } 238 | } 239 | 240 | match &инструкция.вид { 241 | ВидИнструкции::Ноп => { 242 | self.индекс_инструкции += 1; 243 | } 244 | ВидИнструкции::Вытолкнуть => { 245 | self.вытолкнуть_значение_нат()?; 246 | self.индекс_инструкции += 1; 247 | } 248 | ВидИнструкции::Продублировать => { 249 | let значение = self.вытолкнуть_значение_нат()?; 250 | self.протолкнуть_значение_нат(значение)?; 251 | self.протолкнуть_значение_нат(значение)?; 252 | self.индекс_инструкции += 1; 253 | } 254 | &ВидИнструкции::ГлобальныеДанные(смещение) => { 255 | self.протолкнуть_значение_нат((self.начало_данных as i32 + смещение) as usize)?; 256 | self.индекс_инструкции += 1; 257 | } 258 | &ВидИнструкции::Натуральное(значение) => { 259 | self.протолкнуть_значение_нат(значение)?; 260 | self.индекс_инструкции += 1; 261 | } 262 | &ВидИнструкции::Целое(значение) => { 263 | self.протолкнуть_значение_нат(значение as usize)?; 264 | self.индекс_инструкции += 1; 265 | } 266 | &ВидИнструкции::ВыделитьНаСтеке(размер) => { 267 | self.выделить_на_втором_стеке(размер as usize)?; 268 | self.индекс_инструкции += 1; 269 | } 270 | &ВидИнструкции::ОсвободитьСоСтека(размер) => { 271 | self.освободить_со_второго_стека(размер as usize)?; 272 | self.индекс_инструкции += 1; 273 | } 274 | &ВидИнструкции::ВершинаСтека(смещение) => { 275 | self.протолкнуть_значение_нат((self.второй_стек as i32 + смещение) as usize)?; 276 | self.индекс_инструкции += 1; 277 | } 278 | ВидИнструкции::СохранитьКадр => { 279 | let старый_кадр = self.кадр_второго_стека; 280 | self.кадр_второго_стека = self.второй_стек; 281 | self.протолкнуть_на_второй_стек(старый_кадр)?; 282 | self.индекс_инструкции += 1; 283 | } 284 | ВидИнструкции::ВосстановитьКадр => { 285 | self.кадр_второго_стека = self.вытолкнуть_из_второго_стека()?; 286 | self.индекс_инструкции += 1; 287 | } 288 | ВидИнструкции::Кадр(смещение) => { 289 | self.протолкнуть_значение_нат((self.кадр_второго_стека as i32 + смещение) as usize)?; 290 | self.индекс_инструкции += 1; 291 | } 292 | ВидИнструкции::АргументНаСтек => { 293 | let значение = self.вытолкнуть_значение_нат()?; 294 | self.протолкнуть_на_второй_стек(значение)?; 295 | self.индекс_инструкции += 1; 296 | } 297 | ВидИнструкции::АргументСоСтека => { 298 | let значение = self.вытолкнуть_из_второго_стека()?; 299 | self.протолкнуть_значение_нат(значение)?; 300 | self.индекс_инструкции += 1; 301 | } 302 | &ВидИнструкции::ВнутреннийВызов(адрекс) => { 303 | глубина_вызовов += 1; 304 | self.протолкнуть_значение_нат(индекс_инструкции + 1)?; 305 | self.индекс_инструкции = адрекс; 306 | } 307 | ВидИнструкции::ВнешнийВызов{..} => { 308 | ошибка_времени_исполнения!(self, "вынешние вызовы не поддерживаются в режиме интерпретации"); 309 | return Err(()) 310 | } 311 | ВидИнструкции::Записать8 => { 312 | self.проверить_арность_аргументов(2)?; 313 | let адрес = self.вытолкнуть_значение_нат()?; 314 | let значение = (self.вытолкнуть_значение_нат()? & 0xFF) as u8; 315 | let тип = Тип::Нат8; 316 | self.срез_памяти(адрес, тип.размер(&имена.структуры))?.copy_from_slice(&значение.to_le_bytes()); 317 | self.индекс_инструкции += 1; 318 | } 319 | ВидИнструкции::Записать16 => { 320 | сделать!(&инструкция.лок, "Интерпретация инструкции Записать16"); 321 | return Err(()); 322 | } 323 | ВидИнструкции::Записать32 => { 324 | self.проверить_арность_аргументов(2)?; 325 | let адрес = self.вытолкнуть_значение_нат()?; 326 | let значение = self.вытолкнуть_значение_нат()? as u32; 327 | self.срез_памяти(адрес, 4)?.copy_from_slice(&значение.to_le_bytes()); 328 | self.индекс_инструкции += 1; 329 | } 330 | ВидИнструкции::Записать64 => { 331 | self.проверить_арность_аргументов(2)?; 332 | let адрес = self.вытолкнуть_значение_нат()?; 333 | let значение = self.вытолкнуть_значение_нат()?; 334 | let тип = Тип::Нат64; 335 | self.срез_памяти(адрес, тип.размер(&имена.структуры))?.copy_from_slice(&значение.to_le_bytes()); 336 | self.индекс_инструкции += 1; 337 | } 338 | ВидИнструкции::ПрочитатьБезЗнак8 => { 339 | self.проверить_арность_аргументов(1)?; 340 | let адрес = self.вытолкнуть_значение_нат()?; 341 | let значение: u8 = u8::from_le_bytes(self.срез_памяти(адрес, 1)?.try_into().unwrap()); 342 | self.протолкнуть_значение_нат(значение as usize)?; 343 | self.индекс_инструкции += 1; 344 | } 345 | ВидИнструкции::ПрочитатьБезЗнак16 => { 346 | сделать!(&инструкция.лок, "Интерпртация инструкции ПрочитатьБезЗнак32"); 347 | return Err(()); 348 | } 349 | ВидИнструкции::ПрочитатьБезЗнак32 => { 350 | self.проверить_арность_аргументов(1)?; 351 | let адрес = self.вытолкнуть_значение_нат()?; 352 | let значение: u32 = u32::from_le_bytes(self.срез_памяти(адрес, 4)?.try_into().unwrap()); 353 | self.протолкнуть_значение_нат(значение as usize)?; 354 | self.индекс_инструкции += 1; 355 | } 356 | ВидИнструкции::ПрочитатьЗнак8 => { 357 | сделать!(&инструкция.лок, "Интерпртация инструкции ПрочитатьЗнак8"); 358 | return Err(()); 359 | } 360 | ВидИнструкции::ПрочитатьЗнак16 => { 361 | сделать!(&инструкция.лок, "Интерпртация инструкции ПрочитатьЗнак8"); 362 | return Err(()); 363 | } 364 | ВидИнструкции::ПрочитатьЗнак32 => { 365 | сделать!(&инструкция.лок, "Интерпртация инструкции ПрочитатьЗнак32"); 366 | return Err(()); 367 | } 368 | ВидИнструкции::Прочитать64 => { 369 | self.проверить_арность_аргументов(1)?; 370 | let адрес = self.вытолкнуть_значение_нат()?; 371 | let тип = Тип::Нат64; 372 | let значение: u64 = u64::from_le_bytes(self.срез_памяти(адрес, тип.размер(&имена.структуры))?.try_into().unwrap()); 373 | self.протолкнуть_значение_нат(значение as usize)?; 374 | self.индекс_инструкции += 1; 375 | } 376 | ВидИнструкции::СкопироватьПамять => { 377 | let размер = self.вытолкнуть_значение_нат()?; 378 | let цель = self.вытолкнуть_значение_нат()?; 379 | let источник = self.вытолкнуть_значение_нат()?; 380 | for индекс in 0..размер { 381 | self.память[цель + индекс] = self.память[источник + индекс]; 382 | } 383 | self.индекс_инструкции += 1; 384 | } 385 | ВидИнструкции::ПамятьРавно => { 386 | let размер = self.вытолкнуть_значение_нат()?; 387 | let цель = self.вытолкнуть_значение_нат()?; 388 | let источник = self.вытолкнуть_значение_нат()?; 389 | let mut равна = true; 390 | for индекс in 0..размер { 391 | if self.память[цель + индекс] != self.память[источник + индекс] { 392 | равна = false; 393 | break; 394 | } 395 | } 396 | if равна { 397 | self.протолкнуть_значение_нат(1)?; 398 | } else { 399 | self.протолкнуть_значение_нат(0)?; 400 | } 401 | self.индекс_инструкции += 1; 402 | } 403 | ВидИнструкции::НатМеньше => { 404 | self.проверить_арность_аргументов(2)?; 405 | let правый = self.вытолкнуть_значение_нат()?; 406 | let левый = self.вытолкнуть_значение_нат()?; 407 | if левый < правый { 408 | self.протолкнуть_значение_нат(1)?; 409 | } else { 410 | self.протолкнуть_значение_нат(0)?; 411 | } 412 | self.индекс_инструкции += 1; 413 | } 414 | ВидИнструкции::НатМеньшеРавно => { 415 | self.проверить_арность_аргументов(2)?; 416 | let правый = self.вытолкнуть_значение_нат()?; 417 | let левый = self.вытолкнуть_значение_нат()?; 418 | if левый <= правый { 419 | self.протолкнуть_значение_нат(1)?; 420 | } else { 421 | self.протолкнуть_значение_нат(0)?; 422 | } 423 | self.индекс_инструкции += 1; 424 | } 425 | ВидИнструкции::НатБольше => { 426 | self.проверить_арность_аргументов(2)?; 427 | let правый = self.вытолкнуть_значение_нат()?; 428 | let левый = self.вытолкнуть_значение_нат()?; 429 | if левый > правый { 430 | self.протолкнуть_значение_нат(1)?; 431 | } else { 432 | self.протолкнуть_значение_нат(0)?; 433 | } 434 | self.индекс_инструкции += 1; 435 | } 436 | ВидИнструкции::НатБольшеРавно => { 437 | self.проверить_арность_аргументов(2)?; 438 | let правый = self.вытолкнуть_значение_нат()?; 439 | let левый = self.вытолкнуть_значение_нат()?; 440 | if левый >= правый { 441 | self.протолкнуть_значение_нат(1)?; 442 | } else { 443 | self.протолкнуть_значение_нат(0)?; 444 | } 445 | self.индекс_инструкции += 1; 446 | } 447 | ВидИнструкции::НатРавно => { 448 | self.проверить_арность_аргументов(2)?; 449 | let правый = self.вытолкнуть_значение_нат()?; 450 | let левый = self.вытолкнуть_значение_нат()?; 451 | if левый == правый { 452 | self.протолкнуть_значение_нат(1)?; 453 | } else { 454 | self.протолкнуть_значение_нат(0)?; 455 | } 456 | self.индекс_инструкции += 1; 457 | } 458 | ВидИнструкции::НатСложение => { 459 | self.проверить_арность_аргументов(2)?; 460 | let правый = self.вытолкнуть_значение_нат()?; 461 | let левый = self.вытолкнуть_значение_нат()?; 462 | let (результат, _насрать) = левый.overflowing_add(правый); 463 | self.протолкнуть_значение_нат(результат)?; 464 | self.индекс_инструкции += 1; 465 | } 466 | ВидИнструкции::НатВычитание => { 467 | self.проверить_арность_аргументов(2)?; 468 | let правый = self.вытолкнуть_значение_нат()?; 469 | let левый = self.вытолкнуть_значение_нат()?; 470 | let (результат, _насрать) = левый.overflowing_sub(правый); 471 | self.протолкнуть_значение_нат(результат)?; 472 | self.индекс_инструкции += 1; 473 | } 474 | ВидИнструкции::НатУмножение => { 475 | self.проверить_арность_аргументов(2)?; 476 | let правый = self.вытолкнуть_значение_нат()?; 477 | let левый = self.вытолкнуть_значение_нат()?; 478 | self.протолкнуть_значение_нат(левый * правый)?; 479 | self.индекс_инструкции += 1; 480 | } 481 | ВидИнструкции::НатДеление => { 482 | self.проверить_арность_аргументов(2)?; 483 | let правый = self.вытолкнуть_значение_нат()?; 484 | let левый = self.вытолкнуть_значение_нат()?; 485 | self.протолкнуть_значение_нат(левый / правый)?; 486 | self.индекс_инструкции += 1; 487 | } 488 | ВидИнструкции::НатОстаток => { 489 | self.проверить_арность_аргументов(2)?; 490 | let правый = self.вытолкнуть_значение_нат()?; 491 | let левый = self.вытолкнуть_значение_нат()?; 492 | self.протолкнуть_значение_нат(левый % правый)?; 493 | self.индекс_инструкции += 1; 494 | } 495 | ВидИнструкции::ЦелМеньше => { 496 | self.проверить_арность_аргументов(2)?; 497 | let правый = self.вытолкнуть_значение_нат()? as i64; 498 | let левый = self.вытолкнуть_значение_нат()? as i64; 499 | if левый < правый { 500 | self.протолкнуть_значение_нат(1)?; 501 | } else { 502 | self.протолкнуть_значение_нат(0)?; 503 | } 504 | self.индекс_инструкции += 1; 505 | } 506 | ВидИнструкции::ЦелМеньшеРавно => { 507 | self.проверить_арность_аргументов(2)?; 508 | let правый = self.вытолкнуть_значение_нат()? as i64; 509 | let левый = self.вытолкнуть_значение_нат()? as i64; 510 | if левый <= правый { 511 | self.протолкнуть_значение_нат(1)?; 512 | } else { 513 | self.протолкнуть_значение_нат(0)?; 514 | } 515 | self.индекс_инструкции += 1; 516 | } 517 | ВидИнструкции::ЦелБольше => { 518 | self.проверить_арность_аргументов(2)?; 519 | let правый = self.вытолкнуть_значение_нат()? as i64; 520 | let левый = self.вытолкнуть_значение_нат()? as i64; 521 | if левый > правый { 522 | self.протолкнуть_значение_нат(1)?; 523 | } else { 524 | self.протолкнуть_значение_нат(0)?; 525 | } 526 | self.индекс_инструкции += 1; 527 | } 528 | ВидИнструкции::ЦелБольшеРавно => { 529 | self.проверить_арность_аргументов(2)?; 530 | let правый = self.вытолкнуть_значение_нат()? as i64; 531 | let левый = self.вытолкнуть_значение_нат()? as i64; 532 | if левый >= правый { 533 | self.протолкнуть_значение_нат(1)?; 534 | } else { 535 | self.протолкнуть_значение_нат(0)?; 536 | } 537 | self.индекс_инструкции += 1; 538 | } 539 | ВидИнструкции::ЦелОтриц => { 540 | self.проверить_арность_аргументов(1)?; 541 | let значение = self.вытолкнуть_значение_нат()? as i64; 542 | self.протолкнуть_значение_нат((-значение) as usize)?; 543 | self.индекс_инструкции += 1; 544 | } 545 | ВидИнструкции::ЦелУмножение => { 546 | self.проверить_арность_аргументов(2)?; 547 | let правый = self.вытолкнуть_значение_нат()? as i64; 548 | let левый = self.вытолкнуть_значение_нат()? as i64; 549 | self.протолкнуть_значение_нат((левый * правый) as usize)?; 550 | self.индекс_инструкции += 1; 551 | } 552 | ВидИнструкции::ЦелДеление => { 553 | self.проверить_арность_аргументов(2)?; 554 | let правый = self.вытолкнуть_значение_нат()? as i64; 555 | let левый = self.вытолкнуть_значение_нат()? as i64; 556 | self.протолкнуть_значение_нат((левый / правый) as usize)?; 557 | self.индекс_инструкции += 1; 558 | } 559 | ВидИнструкции::ЦелОстаток => { 560 | self.проверить_арность_аргументов(2)?; 561 | let правый = self.вытолкнуть_значение_нат()? as i64; 562 | let левый = self.вытолкнуть_значение_нат()? as i64; 563 | self.протолкнуть_значение_нат((левый % правый) as usize)?; 564 | self.индекс_инструкции += 1; 565 | } 566 | ВидИнструкции::КонвертНат64Вещ32 => { 567 | let значение = self.вытолкнуть_значение_нат()?; 568 | self.протолкнуть_значение_вещ32(значение as f32)?; 569 | self.индекс_инструкции += 1; 570 | } 571 | ВидИнструкции::КонвертЦел64Вещ32 => { 572 | let значение = self.вытолкнуть_значение_нат()? as i64; 573 | self.протолкнуть_значение_вещ32(значение as f32)?; 574 | self.индекс_инструкции += 1; 575 | } 576 | ВидИнструкции::КонвертВещ32Нат64 => { 577 | let значение = self.вытолкнуть_значение_вещ32()?; 578 | self.протолкнуть_значение_нат(значение as usize)?; 579 | self.индекс_инструкции += 1; 580 | } 581 | ВидИнструкции::КонвертВещ32Цел64 => { 582 | let значение = self.вытолкнуть_значение_вещ32()?; 583 | self.протолкнуть_значение_нат((значение as i64) as usize)?; 584 | self.индекс_инструкции += 1; 585 | } 586 | ВидИнструкции::Вещ32Умножение => { 587 | self.проверить_арность_аргументов(2)?; 588 | let правый = self.вытолкнуть_значение_вещ32()?; 589 | let левый = self.вытолкнуть_значение_вещ32()?; 590 | self.протолкнуть_значение_вещ32(левый * правый)?; 591 | self.индекс_инструкции += 1; 592 | } 593 | ВидИнструкции::Вещ32Деление => { 594 | self.проверить_арность_аргументов(2)?; 595 | let правый = self.вытолкнуть_значение_вещ32()?; 596 | let левый = self.вытолкнуть_значение_вещ32()?; 597 | self.протолкнуть_значение_вещ32(левый / правый)?; 598 | self.индекс_инструкции += 1; 599 | } 600 | ВидИнструкции::Вещ32Сложение => { 601 | self.проверить_арность_аргументов(2)?; 602 | let правый = self.вытолкнуть_значение_вещ32()?; 603 | let левый = self.вытолкнуть_значение_вещ32()?; 604 | self.протолкнуть_значение_вещ32(левый + правый)?; 605 | self.индекс_инструкции += 1; 606 | } 607 | ВидИнструкции::Вещ32Вычитание => { 608 | self.проверить_арность_аргументов(2)?; 609 | let правый = self.вытолкнуть_значение_вещ32()?; 610 | let левый = self.вытолкнуть_значение_вещ32()?; 611 | self.протолкнуть_значение_вещ32(левый - правый)?; 612 | self.индекс_инструкции += 1; 613 | } 614 | ВидИнструкции::Вещ32Меньше => { 615 | self.проверить_арность_аргументов(2)?; 616 | let правый = self.вытолкнуть_значение_вещ32()?; 617 | let левый = self.вытолкнуть_значение_вещ32()?; 618 | if левый < правый { 619 | self.протолкнуть_значение_нат(1)?; 620 | } else { 621 | self.протолкнуть_значение_нат(0)?; 622 | } 623 | self.индекс_инструкции += 1; 624 | } 625 | ВидИнструкции::Вещ32МеньшеРавно => { 626 | self.проверить_арность_аргументов(2)?; 627 | let правый = self.вытолкнуть_значение_вещ32()?; 628 | let левый = self.вытолкнуть_значение_вещ32()?; 629 | if левый <= правый { 630 | self.протолкнуть_значение_нат(1)?; 631 | } else { 632 | self.протолкнуть_значение_нат(0)?; 633 | } 634 | self.индекс_инструкции += 1; 635 | } 636 | ВидИнструкции::Вещ32Больше => { 637 | self.проверить_арность_аргументов(2)?; 638 | let правый = self.вытолкнуть_значение_вещ32()?; 639 | let левый = self.вытолкнуть_значение_вещ32()?; 640 | if левый > правый { 641 | self.протолкнуть_значение_нат(1)?; 642 | } else { 643 | self.протолкнуть_значение_нат(0)?; 644 | } 645 | self.индекс_инструкции += 1; 646 | } 647 | ВидИнструкции::Вещ32БольшеРавно => { 648 | self.проверить_арность_аргументов(2)?; 649 | let правый = self.вытолкнуть_значение_вещ32()?; 650 | let левый = self.вытолкнуть_значение_вещ32()?; 651 | if левый >= правый { 652 | self.протолкнуть_значение_нат(1)?; 653 | } else { 654 | self.протолкнуть_значение_нат(0)?; 655 | } 656 | self.индекс_инструкции += 1; 657 | } 658 | ВидИнструкции::Вещ32Отриц => { 659 | let значение = self.вытолкнуть_значение_вещ32()?; 660 | self.протолкнуть_значение_вещ32(-значение)?; 661 | self.индекс_инструкции += 1; 662 | } 663 | ВидИнструкции::ЛогОтрицание => { 664 | self.проверить_арность_аргументов(1)?; 665 | let значение = self.вытолкнуть_значение_нат()?; 666 | if значение == 0 { 667 | self.протолкнуть_значение_нат(1)?; 668 | } else { 669 | self.протолкнуть_значение_нат(0)?; 670 | } 671 | self.индекс_инструкции += 1; 672 | } 673 | ВидИнструкции::БитИли => { 674 | let а = self.вытолкнуть_значение_нат()?; 675 | let б = self.вытолкнуть_значение_нат()?; 676 | self.протолкнуть_значение_нат(а | б)?; 677 | self.индекс_инструкции += 1; 678 | } 679 | ВидИнструкции::БитИ => { 680 | let а = self.вытолкнуть_значение_нат()?; 681 | let б = self.вытолкнуть_значение_нат()?; 682 | self.протолкнуть_значение_нат(а & б)?; 683 | self.индекс_инструкции += 1; 684 | } 685 | ВидИнструкции::БитЛибо => { 686 | let а = self.вытолкнуть_значение_нат()?; 687 | let б = self.вытолкнуть_значение_нат()?; 688 | self.протолкнуть_значение_нат(а ^ б)?; 689 | self.индекс_инструкции += 1; 690 | } 691 | ВидИнструкции::БитСмещениеВлево => { 692 | let сдвиг = self.вытолкнуть_значение_нат()?; 693 | let значение = self.вытолкнуть_значение_нат()?; 694 | self.протолкнуть_значение_нат(значение << сдвиг)?; 695 | self.индекс_инструкции += 1; 696 | } 697 | ВидИнструкции::БитСмещениеВправо => { 698 | let сдвиг = self.вытолкнуть_значение_нат()?; 699 | let значение = self.вытолкнуть_значение_нат()?; 700 | self.протолкнуть_значение_нат(значение >> сдвиг)?; 701 | self.индекс_инструкции += 1; 702 | } 703 | ВидИнструкции::Прыжок(индекс) => { 704 | self.индекс_инструкции = *индекс; 705 | } 706 | &ВидИнструкции::УсловныйПрыжок(индекс) => { 707 | self.проверить_арность_аргументов(1)?; 708 | let значение = self.вытолкнуть_значение_нат()?; 709 | if значение == 0 { 710 | self.индекс_инструкции += 1; 711 | } else { 712 | self.индекс_инструкции = индекс; 713 | } 714 | } 715 | ВидИнструкции::ПечатьСтроки => { 716 | self.проверить_арность_аргументов(1)?; 717 | let строка = self.вытолкнуть_значение_нат()?; 718 | let адрес = usize::from_le_bytes( 719 | self.срез_памяти(строка + СРЕЗ_АДРЕС_СМЕЩЕНИЕ, РАЗМЕР_СЛОВА)?.try_into().unwrap() 720 | ); 721 | let размер = usize::from_le_bytes( 722 | self.срез_памяти(строка + СРЕЗ_РАЗМЕР_СМЕЩЕНИЕ, РАЗМЕР_СЛОВА)?.try_into().unwrap() 723 | ); 724 | let _ = io::stdout().write(self.срез_памяти(адрес, размер)?); 725 | let _ = io::stdout().flush(); 726 | self.индекс_инструкции += 1; 727 | } 728 | ВидИнструкции::Ввод => { 729 | self.проверить_арность_аргументов(2)?; 730 | let длинна = self.вытолкнуть_значение_нат()?; 731 | let указатель = self.вытолкнуть_значение_нат()?; 732 | let размер = io::stdin().read(self.срез_памяти(указатель, длинна)?).unwrap(); 733 | self.протолкнуть_значение_нат(размер)?; 734 | self.индекс_инструкции += 1; 735 | } 736 | ВидИнструкции::Возврат => { 737 | // СДЕЛАТЬ: Ввести отдельную инструкцию останова. 738 | // И генерировать точку входа наподобии того, как мы это делаем в эльф. 739 | // Т.е. точка входа 0. Он прыгает в главную, и после вызывает останов. 740 | if глубина_вызовов == 0 { 741 | break; 742 | } 743 | self.индекс_инструкции = self.вытолкнуть_значение_нат()?; 744 | глубина_вызовов -= 1; 745 | }, 746 | ВидИнструкции::СисВызов {..} => { 747 | ошибка_времени_исполнения!(self, "системные вызовы не поддерживаются в режиме интерпретации"); 748 | return Err(()) 749 | } 750 | } 751 | } 752 | Ok(()) 753 | } 754 | } 755 | --------------------------------------------------------------------------------