diff --git a/тесты/kvs_full_test.csv b/тесты/kvs_full_test.csv index aeedab1..841443a 100644 --- a/тесты/kvs_full_test.csv +++ b/тесты/kvs_full_test.csv @@ -22,4 +22,5 @@ 1;тест_адресации_р15;Проверка косвенной адресации через R15 (ASCII код первого символа аргумента) 1;двоеточие_в_строке;Проверка обработки строк с двоеточием внутри 1;тест_адресации_р12;Проверка косвенной адресации через R12 (ASCII код первого символа аргумента) -1;вызов_функции;Проверка вызова функций и возврата: сложение 10+20=30 через код возврата \ No newline at end of file +1;вызов_функции;Проверка вызова функций и возврата: сложение 10+20=30 через код возврата +1;остаток_от_деления;Проверка деления и получения остатка: 42 % 10 = 2 (проверка через код возврата) \ No newline at end of file diff --git a/тесты/остаток_от_деления/остаток_от_деления.py b/тесты/остаток_от_деления/остаток_от_деления.py new file mode 100644 index 0000000..d6b51db --- /dev/null +++ b/тесты/остаток_от_деления/остаток_от_деления.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Тест для проверки операции деления и получения остатка +Запускает скомпилированную программу и проверяет код возврата +Ожидаемый результат: 42 % 10 = 2 +""" + +import subprocess +import sys +import os +from pathlib import Path + +# Определяем пути +SCRIPT_DIR = Path(__file__).parent.absolute() +PROJECT_ROOT = SCRIPT_DIR.parent.parent +SOURCE_REL = SCRIPT_DIR / "остаток_от_деления.квс" + +def clean(): + """Очищает артефакты сборки""" + files = [ + "остаток_от_деления.elf", + "остаток_от_деления.csv", + "остаток_от_деления.аст", + "остаток_от_деления.токены", + "остаток_от_деления.константа", + "остаток_от_деления_pass4.log" + ] + for f in files: + f_path = SCRIPT_DIR / f + if f_path.exists(): + f_path.unlink() + print(f"DEBUG: Удалён {f}", file=sys.stderr) + +def build() -> bool: + """ + Собирает тестовую программу с помощью КВС + + Returns: + bool: True если сборка успешна, иначе False + """ + print(f"DEBUG: Сборка {SOURCE_REL}", file=sys.stderr) + os.chdir(PROJECT_ROOT) + + build = subprocess.run( + ["python3", "квс_сборка.py", str(SOURCE_REL)], + capture_output=True, + text=True + ) + + if build.returncode != 0: + print(f"❌ Ошибка сборки: {build.returncode}", file=sys.stderr) + print(build.stderr, file=sys.stderr) + return False + + print("DEBUG: Сборка успешна", file=sys.stderr) + return True + +def test_division_remainder() -> bool: + """ + Запускает скомпилированную программу и проверяет код возврата + 42 % 10 = 2 + + Returns: + bool: True если код возврата = 2, иначе False + """ + print("DEBUG: Запуск ELF, ожидается код возврата 2", file=sys.stderr) + os.chdir(SCRIPT_DIR) + + elf_path = SCRIPT_DIR / "остаток_от_деления.elf" + if not elf_path.exists(): + print("❌ ELF файл не найден", file=sys.stderr) + return False + + # Запускаем программу без аргументов + run = subprocess.run( + [str(elf_path)], + capture_output=True, + text=True + ) + + expected_code = 2 # 42 % 10 = 2 + + if run.returncode != expected_code: + print(f"❌ Код возврата: ожидался {expected_code}, получен {run.returncode}", file=sys.stderr) + if run.stderr: + print(f" stderr: {run.stderr}", file=sys.stderr) + if run.stdout: + print(f" stdout: {run.stdout}", file=sys.stderr) + return False + + print(f"DEBUG: Тест пройден (код {run.returncode})", file=sys.stderr) + return True + +def main(): + """Главная функция теста""" + print("DEBUG: Начало теста остаток_от_деления", file=sys.stderr) + + # Собираем программу + if not build(): + clean() + sys.exit(1) + + # Запускаем тест + if not test_division_remainder(): + clean() + sys.exit(1) + + # Очищаем артефакты + clean() + + print("✅ Все тесты пройдены!", file=sys.stderr) + sys.exit(0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/тесты/остаток_от_деления/остаток_от_деления.квс b/тесты/остаток_от_деления/остаток_от_деления.квс new file mode 100644 index 0000000..7d86e52 --- /dev/null +++ b/тесты/остаток_от_деления/остаток_от_деления.квс @@ -0,0 +1,35 @@ +;./тесты/остаток_от_деления/остаток_от_деления.elf +;echo $? # должен быть 2 + +;для вывода чисел в терминал нужно преобразование в строку +;а для этого нужен остаток от деления (но тут надо бы больше случаев отработать) + +; ============================================================ +; остаток_от_деления.квс - тест операции деления и остатка +; Проверяем: 42 / 10 = 4 остаток 2 +; ============================================================ + +.текст +.глобал _start + +_start: + ; Подготовка делимого: RDX:RAX = 0:42 + переместить_имм раикс, 42 ; делимое = 42 + переместить_имм рдикс, 0 ; обнуляем RDX (старшая часть 128-битного делимого) + + ; Делитель в регистр + переместить_имм рбикс, 10 ; делитель = 10 + + ; Выполняем деление: RDX:RAX / RBX + ; После деления: RAX = частное (4), RDX = остаток (2) + разделить рбикс + + ; Перемещаем остаток в RDI для кода возврата + переместить рдиай, рдикс ; остаток из RDX в RDI + + ; Системный вызов exit + переместить_имм раикс, 60 ; номер syscall exit = 60 + вызов_системы + +.данные +тестовая_переменная: .байт 0 diff --git a/тесты/сложение/сложение.квс b/тесты/сложение/сложение.квс index 3a87319..9e9ab45 100644 --- a/тесты/сложение/сложение.квс +++ b/тесты/сложение/сложение.квс @@ -1,4 +1,3 @@ -; Файл: черновик/черновик.квс ; Тест операции сложения (прибавить) ; Результат должен быть 42 diff --git a/тесты/черновик/черновик.квс b/тесты/черновик/черновик.квс index 10d313c..d8861fc 100644 --- a/тесты/черновик/черновик.квс +++ b/тесты/черновик/черновик.квс @@ -1,30 +1,148 @@ +; ============================================================ +; вывод_числа.квс — исправленный синтаксис деления +; ============================================================ + .текст .глобал _start _start: - ; Вызов функции с двумя аргументами - переместить_имм рдиай, 10 ; первый аргумент = 10 - переместить_имм рсиай, 20 ; второй аргумент = 20 - вызвать сложить_два_числа + переместить_имм раикс, -12345 + вызвать вывести_число - ; Результат в RAX — используем как код возврата - переместить рдиай, раикс ; первый аргумент sys_exit = результат - переместить_имм раикс, 60 ; sys_exit + ; Вывод перевода строки + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, новая_строка + переместить_имм рдикс, 1 + вызов_системы + + ; Завершение + переместить_имм раикс, 60 + переместить_имм рдиай, 0 вызов_системы -сложить_два_числа: - ; Пролог +вывести_число: втолкнуть рбипи переместить рбипи, рсипи - ; Тело функции: сложить аргументы - прибавить рдиай, рсиай ; RDI += RSI - переместить раикс, рдиай ; результат в RAX + втолкнуть рбикс + втолкнуть рсикс + втолкнуть рдикс + втолкнуть р8 + втолкнуть р9 + втолкнуть р10 + втолкнуть р11 + + ; ---- Проверка на отрицательное ---- + проверить раикс, раикс + переход_если_больше_или_равно _положительное + + втолкнуть раикс + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + переместить_имм рсиай, минус_символ + переместить_имм рдикс, 1 + вызов_системы + вытолкнуть раикс + отрицать раикс + +_положительное: + ; ---- Сохраняем число в R8 ---- + переместить р8, раикс + переместить_имм р9, 0 + + ; ---- Устанавливаем R10 на КОНЕЦ буфера (буфер + 19) ---- + переместить_имм р10, буфер + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + увеличить р10 + + ; Записываем нуль-терминатор + переместить_имм [р10], 0 + + ; ---- Особый случай: число = 0 ---- + проверить р8, р8 + переход_если_равно _ноль_особый_случай + +_цикл_деления: + проверить р8, р8 + переход_если_равно _вывод_числа + + ; ---- ДЕЛЕНИЕ (исправленный синтаксис) ---- + переместить_имм рдиай, 0 ; RDX = 0 + переместить раикс, р8 ; RAX = R8 + переместить_имм рсиай, 10 ; RSI = 10 + разделить рдиай, раикс, рсиай ; ← ИСПРАВЛЕНО! + + ; ---- Сохраняем результат ---- + переместить р8, раикс ; R8 = частное + прибавить рдиай, '0' ; RDX = цифра + '0' + уменьшить р10 ; двигаем указатель влево + сохранить [р10], дил ; сохраняем байт + увеличить р9 ; счётчик цифр++ + переход _цикл_деления + +_ноль_особый_случай: + ; Если число = 0, записываем '0' в начало буфера + переместить_имм [буфер], '0' + переместить_имм р10, буфер + переместить_имм р9, 1 + переход _вывод_числа + +_вывод_числа: + переместить рсиай, р10 + переместить рдикс, р9 + вызвать вывести_строку + + вытолкнуть р11 + вытолкнуть р10 + вытолкнуть р9 + вытолкнуть р8 + вытолкнуть рдикс + вытолкнуть рсикс + вытолкнуть рбикс + + переместить рсипи, рбипи + вытолкнуть рбипи + вернуться + +вывести_строку: + втолкнуть рбипи + переместить рбипи, рсипи + + втолкнуть раикс + втолкнуть рдиай + + переместить_имм раикс, 1 + переместить_имм рдиай, 1 + вызов_системы + + вытолкнуть рдиай + вытолкнуть раикс - ; Эпилог переместить рсипи, рбипи вытолкнуть рбипи вернуться .данные -тестовая_переменная: .байт 0 \ No newline at end of file + минус_символ: .байт '-' + новая_строка: .байт 10 + +.бнд + буфер: .резб 20 \ No newline at end of file