// 2025-2026 Богданович Давид Когут Прихожденко (кдб.дійсність.укр)

/* Компілювач Мавки */

взяти визначення мавка;
взяти визначення мавка/розбирач;

простір мавка {
  простір компілювач {
    структура ПомилкаКомпілювання {
      позиція_в_тексті: природне;
      рядок: природне;
      стовпець: природне;
      повідомлення: кд; // має звільнити той хто оброляє помилку
    }

    структура Константи {
      розмір: п32;
      дані: *Значення;
    }

    структура Вказівки {
      розмір: п32;
      дані: *п8;
    }

    структура Повтор {
      початок: п32;
      позиції_вказівок_виходу: Накопичувач<п32>;
    }

    структура Код {
      константи: Константи;
      вказівки: Вказівки;
      шлях: *ПредметДаних;
      місцезнаходження_вказівок: МісцезнаходженняВказівок;
      повтори: Накопичувач<Повтор>;
    }

    внутрішня дія перевірити_чи_кд_рівні(а: кд, б: кд) -> логічне {
      якщо а.розмір != б.розмір {
        вернути ні;
      }

      змінна п: природне = 0;

      поки п < а.розмір {
        якщо а.дані[п] != б.дані[п] {
          вернути ні;
        }

        п += 1;
      }

      вернути так;
    }

    внутрішня дія перевірити_чи_починається_на(значення: кд, починається_на: кд, п: *природне) -> логічне {
      змінна пп: природне = 0;

      поки пп < починається_на.розмір {
        змінна ппп = п::вміст + пп;

        якщо ппп >= значення.розмір {
          вернути ні;
        }

        якщо значення.дані[ппп] != починається_на.дані[пп] {
          вернути ні;
        }

        пп += 1;
      }

      п::вміст = п::вміст + пп - 1;

      вернути так;
    }

    внутрішня дія створити_код(М: *Машина, шлях: *ПредметДаних) -> *Код {
      змінна код = виділити<Код>(М, 1);

      код.константи = Константи { 0, пусто };
      код.вказівки = Вказівки { 0, пусто };
      код.шлях = шлях;
      код.місцезнаходження_вказівок = МісцезнаходженняВказівок { 0, пусто };
      код.повтори = зробити_накопичувач<Повтор>(М, 0);

      вернути код;
    }

    внутрішня дія покласти_константу(М: *Машина, код: *Код, значення: Значення) -> п32 {
      код.константи.дані = перевиділити<Значення>(М, код.константи.дані, природне(код.константи.розмір + 1));
      код.константи.дані[код.константи.розмір] = значення;
      код.константи.розмір += 1;
      вернути код.константи.розмір - 1;
    }

    внутрішня дія покласти_константу_числа(М: *Машина, код: *Код, значення: р64) -> п32 {
      змінна п: п32 = 0;

      поки п < код.константи.розмір {
        змінна константа = код.константи.дані[п];

        якщо константа.вид == ЗЧисло {
          якщо константа.дані як р64 == значення {
            вернути п;
          }
        }

        п += 1;
      }

      вернути покласти_константу(М, код, ЧИСЛО(значення));
    }

    внутрішня дія покласти_константу_тексту(М: *Машина, код: *Код, значення: кд) -> п32 {
      змінна п: п32 = 0;

      поки п < код.константи.розмір {
        змінна константа = код.константи.дані[п];

        якщо константа.вид == ЗПредмет {
          змінна предмет_тексту = константа.дані як *Предмет як *ПредметТексту;

          якщо предмет_тексту.клас == М.клас_Текст {
            якщо перевірити_чи_кд_рівні(предмет_тексту.значення, значення) {
              вернути п;
            }
          }
        }

        п += 1;
      }

      змінна предмет_тексту = створити_текст(М, значення);

      вернути покласти_константу(М, код, ПРЕДМЕТ(предмет_тексту));
    }

    внутрішня дія покласти_константу_коду(М: *Машина, код: *Код, значення: адреса) -> п32 {
      змінна значення_як_код = значення як *Код;
      змінна константи = створити_послідовність_без_копіювання(М, природне(значення_як_код.константи.розмір), значення_як_код.константи.дані);
      змінна вказівки = створити_дані_без_копіювання(М, природне(значення_як_код.вказівки.розмір), значення_як_код.вказівки.дані);
      змінна предмет_коду = мавка::створити_код(М, константи, вказівки, значення_як_код.шлях, значення_як_код.місцезнаходження_вказівок);

      вернути покласти_константу(М, код, ПРЕДМЕТ(предмет_коду));
    }

    внутрішня дія покласти_вказівку(М: *Машина, код: *Код, рядок: п32, вид: п8) -> п32 {
      код.вказівки.дані = перевиділити<п8>(М, код.вказівки.дані, природне(код.вказівки.розмір + 1));

      змінна позиція_вказівки = код.вказівки.розмір;
      код.вказівки.дані[код.вказівки.розмір] = вид;
      код.вказівки.розмір += 1;

      покласти_місцезнаходження_вказівки(М, код.місцезнаходження_вказівок::адреса, рядок, позиція_вказівки);

      вернути позиція_вказівки;
    }

    внутрішня дія покласти_вказівку_з_аргументом(М: *Машина, код: *Код, рядок: п32, вид: п8, аргумент: п32) -> п32 {
      код.вказівки.дані = перевиділити<п8>(М, код.вказівки.дані, природне((код.вказівки.розмір + 1) + 4));

      змінна позиція_вказівки = код.вказівки.розмір;
      код.вказівки.дані[код.вказівки.розмір] = вид;
      код.вказівки.розмір += 1;

      змінна аргумент_байти = аргумент::адреса як *п8;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_байти[0];
      код.вказівки.розмір += 1;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_байти[1];
      код.вказівки.розмір += 1;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_байти[2];
      код.вказівки.розмір += 1;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_байти[3];
      код.вказівки.розмір += 1;

      покласти_місцезнаходження_вказівки(М, код.місцезнаходження_вказівок::адреса, рядок, позиція_вказівки);

      вернути позиція_вказівки;
    }

    внутрішня дія покласти_вказівку_з_двома_аргументами(М: *Машина, код: *Код, рядок: п32, вид: п8, аргумент1: п32, аргумент2: п32) -> п32 {
      код.вказівки.дані = перевиділити<п8>(М, код.вказівки.дані, природне((код.вказівки.розмір + 1) + 8));

      змінна позиція_вказівки = код.вказівки.розмір;
      код.вказівки.дані[код.вказівки.розмір] = вид;
      код.вказівки.розмір += 1;

      змінна аргумент_1_байти = аргумент1::адреса як *п8;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_1_байти[0];
      код.вказівки.розмір += 1;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_1_байти[1];
      код.вказівки.розмір += 1;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_1_байти[2];
      код.вказівки.розмір += 1;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_1_байти[3];
      код.вказівки.розмір += 1;

      змінна аргумент_2_байти = аргумент2::адреса як *п8;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_2_байти[0];
      код.вказівки.розмір += 1;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_2_байти[1];
      код.вказівки.розмір += 1;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_2_байти[2];
      код.вказівки.розмір += 1;
      код.вказівки.дані[код.вказівки.розмір] = аргумент_2_байти[3];
      код.вказівки.розмір += 1;

      покласти_місцезнаходження_вказівки(М, код.місцезнаходження_вказівок::адреса, рядок, позиція_вказівки);

      вернути позиція_вказівки;
    }

    внутрішня дія змінити_аргумент_вказівки(М: *Машина, код: *Код, позиція_виду_вказівки: п32, позиція_аргумента_вказівки: п32, новий_аргумент: п32) {
      змінна позиція_аргумента_як_байти = позиція_виду_вказівки + 1 + (позиція_аргумента_вказівки * 4);
      змінна новий_аргумент_як_байти = новий_аргумент::адреса як *п8;

      код.вказівки.дані[позиція_аргумента_як_байти + 0] = новий_аргумент_як_байти[0];
      код.вказівки.дані[позиція_аргумента_як_байти + 1] = новий_аргумент_як_байти[1];
      код.вказівки.дані[позиція_аргумента_як_байти + 2] = новий_аргумент_як_байти[2];
      код.вказівки.дані[позиція_аргумента_як_байти + 3] = новий_аргумент_як_байти[3];
    }

    внутрішня дія отримати_розмір_вказівок(М: *Машина, код: *Код) -> п32 {
      вернути код.вказівки.розмір;
    }

    внутрішня дія отримати_шлях_коду(М: *Машина, код: *Код) -> *ПредметДаних {
      вернути код.шлях;
    }

    внутрішня дія покласти_повтор(М: *Машина, код: *Код, позиція_початку: п32) -> *Повтор {
      код.повтори.покласти(М, Повтор { позиція_початку, зробити_накопичувач<п32>(М, 0) });

      вернути код.повтори.дані[код.повтори.розмір - 1]::адреса;
    }

    внутрішня дія обробити_позиції_вказівок_виходу_з_повтору(М: *Машина, код: *Код, повтор: *Повтор, позиція_виходу: п32) {
      змінна п: п32 = 0;

      поки п < п32(повтор.позиції_вказівок_виходу.розмір) {
        змінити_аргумент_вказівки(М, код, повтор.позиції_вказівок_виходу.дані[п], 0, позиція_виходу);

        п += 1;
      }
    }

    внутрішня дія видалити_останній_повтор(М: *Машина, код: *Код) {
      змінна повтор = код.повтори.дані[код.повтори.розмір - 1];
      звільнити(М, повтор.позиції_вказівок_виходу.дані);
      код.повтори.розмір -= 1;
    }

    внутрішня дія отримати_останній_повтор_з_коду(М: *Машина, код: *Код) -> *Повтор {
      якщо код.повтори.розмір == 0 {
        вернути пусто;
      }

      вернути код.повтори.дані[код.повтори.розмір - 1]::адреса;
    }

    внутрішня дія додати_позицію_перезапису_вказівки_стрибнути_для_виходу_з_повтору(М: *Машина, повтор: *Повтор, позиція: п32) {
      повтор.позиції_вказівок_виходу.покласти(М, позиція);
    }

    дія перекласти(
      М: *Машина,
      шлях: *ПредметДаних,
      сирий_текст: кд,
      знаки: розбирач::Знаки,
      здійснимі: розбирач::Сполуки,
      вихід_коду: **Код,
      вихід_помилки: *ПомилкаКомпілювання
    ) -> логічне;
  }

  дія перекласти_в_код(
    М: *Машина,
    шлях: *ПредметДаних,
    сирий_текст: кд,
    знаки: розбирач::Знаки,
    здійснимі: розбирач::Сполуки,
    вихід_коду: **ПредметКоду,
    вихід_помилки: *компілювач::ПомилкаКомпілювання
  ) -> логічне;
}