Files
2026-10-19 17:24:40 +03:00

4.1 KiB

Стеки виртуальной машины

Во время работы, виртуальная машина FZLang полагается на три стека: данных, окружений и вызовов. Каждый стек инициализируется как массив из 256 значений, а затем зануляется. Основное свойство, присущее всем трём стекам - последнее значение является верхом стека и сниматься в первую очередь должно оно, декрементируя указатель на вершину стека.

Стек данных

Стек данных представляет из себя массив из 256 элементов типа fzl_value_t. Структура fzl_value_t - это контейнер для хранения значений, используемых во время работы программы.

typedef struct
{
  fzl_type_t type;

  union
  {
    void *obj;

    struct
    {
      const char *value;
      size_t length;
    } s;

    char c;
    bool b;

    int8_t i8;
    uint8_t u8;

    int16_t i16;
    uint16_t u16;

    int32_t i32;
    uint32_t u32;

    int64_t i64;
    uint64_t u64;

    intptr_t i;
    uintptr_t u;
  } as;
} fzl_value_t;

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

Стек окружений

Чтобы определять лексическое окружение, в котором на данный момент производятся вычисления и выполняются команды, используется стек окружений. Стек окружений - это массив из 256 элементов типа fzl_vm_env_t.

typedef struct
{
  size_t size;
  size_t remainder;

  fzl_vm_env_entry_t *table;

  fzl_vm_object_t **owned_objects;
  size_t owned_objects_remainder;
  size_t owned_objects_count;
} fzl_vm_env_t;

Каждый элемент стека хранит таблицу локальных имён fzl_vm_env_entry_t, а также объекты, которые принадлежат текущему окружению. Локальное имя - это контейнер, оборачивающий fzl_value_t и дающий ему имя:

typedef struct
{
  char *name;
  fzl_value_t value;
} fzl_vm_env_entry_t;

Объект же представляет из себя массив полей, хранимых в этом объекте. Количество элементов определется при аллокации объекта (опкод FZL_OPCODE_ALLOC_OBJECT N, подробнее - в описании опкодов).

typedef struct
{
  fzl_value_t *values;
  size_t values_count;
} fzl_vm_object_t;

Создание окружения или выход из него происходит при опкодах FZL_OPCODE_MK_ENVTABLE и FZL_OPCODE_RM_ENVTABLE соответственно. При этом, если компилятор видит возвращаемое из функции значение типа FZL_TYPE_OBJECT, то перед опкодами FZL_OPCODE_RET и FZL_OPCODE_RM_ENVTABLE он вставляет FZL_OPCODE_ESCAPE_OBJECT, которое позволяет переместить владение объектом в родительское окружение.

Стек возврата

Стек возврата хранит адреса инструкций при входе в функцию (через опкод FZL_OPCODE_CALL). Опкод FZL_OPCODE_RET снимает адрес со стека вызовов и прыгает на снятый адрес.

Сам по себе стек представляет из себя 256 элементов типа size_t.