# Стеки виртуальной машины Во время работы, виртуальная машина FZLang полагается на три стека: данных, окружений и вызовов. Каждый стек инициализируется как массив из 256 значений, а затем зануляется. Основное свойство, присущее всем трём стекам - последнее значение является верхом стека и сниматься в первую очередь должно оно, декрементируя указатель на вершину стека. ## Стек данных Стек данных представляет из себя массив из 256 элементов типа `fzl_value_t`. Структура `fzl_value_t` - это контейнер для хранения значений, используемых во время работы программы. ```c 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`. ```c 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` и дающий ему имя: ```c typedef struct { char *name; fzl_value_t value; } fzl_vm_env_entry_t; ``` Объект же представляет из себя массив полей, хранимых в этом объекте. Количество элементов определется при аллокации объекта (опкод `FZL_OPCODE_ALLOC_OBJECT N`, подробнее - в [описании опкодов](./opcodes.md)). ```c 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`.