# Введение

Этот документ описывает формат файлов с интерпретируемым кодом системы
программирования Рефал-5λ.

# Обзор

При описании интерпретируемого кода будем использовать следующие обозначения
для типов данных:

* `BYTE` — байт, смысл поля зависит от контекста,
* `CHAR` — байт, в котором обычно хранится некоторый печатный символ, кодировку
  используемых символов этот документ не определяет,
* `WORD` — слово из четырёх байт, порядок байт little endian,
* `тип * длина` — последовательность элементов типа `тип` длиной `длина`
  (`длина` — имя некоторого поля данных в структуре),
* `struct новыйтип { имя: тип; имя: тип; … }` — определяет новый тип `новыйтип`
  как последовательность полей указанного типа,
* `ASCIIZ` — последовательность `CHAR`’ов переменной длины, в которой последний
  и только последний символ имеет код 0,
* `тип1 :: тип2` — определяет `тип1` как синоним типа `тип2`.

Интерпретируемый код есть последовательность _блоков_ данных следующего вида:

    struct BLOCK {
      type: BYTE;
      datalen: WORD;
      data: BYTE * datalen;
    }

Файл содержит корректный интерпретируемый код, если первый блок кода имеет тип
`START` и начинается со смещения, кратного 4096.

# Блоки
В заголовках блоков будет указано символическое имя блока и его тип (значение
поля `BLOCK::type`), разделённые знаком `=`. Например, `START=1` означает, что
блок `START` имеет код типа 1.

## Блок START=1

Поле `BLOCK::data` представляет собой строку `CHAR*8` с текстом `RASLCODE`,
поле `BLOCK::datalen`, таким образом, имеет длину 8. Таким образом, блок
представляет собой константную последовательность `"\x01\x08\0\0\0RASLCODE"`.

С этого блока всегда начинается последовательность блоков, при этом внутри
последовательности он может встречаться неограниченное количество раз. Это
позволяет механически конкатенировать две последовательности интерпретируемого
кода и получать новую корректную последовательность.

## Блок CONST_TABLE=2

Блок переменной длины, поле `BLOCK::data` описывается следующей структурой:

    struct CONST_TABLE {
      cookie1: WORD;
      cookie2: WORD;
      external_count: WORD;
      ident_count: WORD;
      number_count: WORD;
      string_count: WORD;
      rasl_length: WORD;
      external_size: WORD;
      ident_size: WORD;
      string_size: WORD;
      externals: FUNCNAME * external_count;
      idents: ASCIIZ * ident_count;
      numbers: WORD * number_count;
      strings: STRING * string_count;
      rasl: RASL_COMMAND * rasl_length;
    }

    struct FUNCNAME {
      type: CHAR;
      name: ASCIIZ;
    }

    struct STRING {
      len: WORD;
      str: CHAR * len;
    }

    struct RASL_COMMAND {
      cmd: BYTE;
      val1: BYTE;
      val2: BYTE;
      bracket: BYTE;
    }

`CONST_TABLE` должно предшествовать любому определению функции (см. далее
детали).

`CONST_TABLE::cookie1`, `CONST_TABLE::cookie2` — устанавливают признаки области
видимости для локальных функций в списке `externals` и для всех последующих
определений функций.

`CONST_TABLE::*_count`, `CONST_TABLE::rasl_len` — определяют количество
соответствующих записей. `CONST_TABLE::*_size` определяют размер в байтах для
полей `CONST_TABLE::externals`, `CONST_TABLE::idents` и `CONST_TABLE::strings`
соответственно. Служат для упрощения распределения памяти.

`CONST_TABLE::externals` — таблица внешних ссылок, используется последующими
блоками `REFAL_FUNCTION`.

Имя функции `FUNCNAME` содержит поле `FUNCNAME::type`, которое может быть либо
`'*'` — функция внешней компоновки, для неё cookie1 = cookie2 = 0, либо `'#'` —
локальная функция с cookie, указанными в `CONST_TABLE`. Поскольку структура
`FUNCNAME` состоит из `CHAR`’а, за которым следует `ASCIIZ`, всю структуру
можно считать как `ASCIIZ` с особым первым символом.

`CONST_TABLE::numbers`, `CONST_TABLE::idents`, `CONST_TABLE::strings` — таблицы
соответственно целочисленных констант, идентификаторов и строковых констант,
используемых в блоках `REFAL_FUNCTION`.

Строки `STRING` могут содержать внутри себя символы с кодом 0, поэтому
использовать `ASCIIZ` нельзя.

`CONST_TABLE::rasl` — кусок байт-кода, используемый функциями, определёнными
при помощи `REFAL_FUNCTION` (см. далее как).

## Блок REFAL_FUNCTION=3

    struct REFAL_FUNCTION {
      name: FUNCNAME;
      offset: WORD;
    }

В корректном файле с интерпретируемым кодом блок `REFAL_FUNCTION` не может
появляться раньше, чем блок `CONST_TABLE`.

Блок описывает регулярную функцию на Рефале, скомпилированную в RASL. При его
чтении создаётся соответствующий дескриптор функции, указатели на таблицы
констант берутся из последней записи `CONST_TABLE`, предшествующей блоку.
Если функция — локальная, то значения cookie также берутся из последней
записи `CONST_TABLE`. Поле `REFAL_FUNCTION::offset` определяет смещение
начала интерпретируемого кода в поле `CONST_TABLE::rasl`.

## Блоки NATIVE_FUNCTION=4, EMPTY_FUNCTION=5, SWAP=6

    NATIVE_FUNCTION :: FUNCNAME
    EMPTY_FUNCTION :: FUNCNAME
    SWAP :: FUNCNAME

Любому из этих блоков в корректном файле с интерпретируемым кодом должен
предшествовать хотя бы один блок `CONST_TABLE`. Если объявляемая функция
является локальной, то значения cookie берутся из самой последней записи
`CONST_TABLE`, предшествующей блоку.

`NATIVE_FUNCTION` описывает функцию, реализованную в машинном коде, код которой
находится в текущем исполнимом модуле.

`EMPTY_FUNCTION` описывает пустую функцию.

`SWAP` описывает функцию-статический ящик.

## Блок REFERENCE=7

    REFERENCE :: ASCIIZ

Блок `REFERENCE` содержит имя другого скомпилированного модуля, от которого
зависит настоящий модуль.

## Блоки CONDITION_RASL=8, CONDITION_NATIVE=9

    CONDITION_RASL :: FUNCNAME
    CONDITION_NATIVE :: FUNCNAME

Любому из этих блоков в корректном файле с интерпретируемым кодом должен
предшествовать хотя бы один блок `CONST_TABLE`. Если объявляемая функция
является локальной, то значения cookie берутся из самой последней записи
`CONST_TABLE`, предшествующей блоку.

`CONDITION_RASL` описывает вспомогательную функцию реализации условия
для интерпретируемого кода.

`CONDITION_NATIVE` описывает вспомогательную функцию реализации условия
для кода прямой кодогенерации.

## Блок INCORPORATED=10

    INCORPORATED :: ASCIIZ

Блок `INCORPORATED` содержит псевдоним для текущего модуля.

## Блок UNIT_NAME=11

    UNIT_NAME :: ASCIIZ

Блок `UNIT_NAME` содержит имя исходного файла для некоторой единицы трансляции.
Ему должен предшествовать хотя бы один `CONST_TABLE`. Собственно, это имя
и помещается в соответствующую таблицу констант.

## Блок METATABLE=12

    struct METATABLE {
      name: FUNCNAME;
      count: WORD;
      items: METATABLE_PAIR * count;
    }

    struct METATABLE_PAIR {
      ident_id: WORD;
      func_id: WORD;
    }

Ей должен предшествовать хотя бы один `CONST_TABLE`.

* `ident_id` — номер идентификатора в таблице `CONST_TABLE::idents`,
* `func_id` — номер функции в таблице `CONST_TABLE::externals`.
