Искра-226/Файловая система: различия между версиями

Материал из Emuverse
(new info)
мНет описания правки
 
(не показаны 2 промежуточные версии этого же участника)
Строка 1: Строка 1:
{{emuverse}}
{{emuverse}}


'''Формат файлов BASIC 02''' — способ хранения программ на дисках [[Искра-226]]. Файловая система унаследована от [[Wang 2200]], представление программы — оригинальное и с Wang несовместимо.
'''Файловая система Искры 226''' — способ хранения файлов на дисках [[Искра-226]]. Унаследована от [[Wang 2200]] и совпадает с ней побайтово; содержимое файлов — оригинальное и с Wang несовместимо.


Программа может храниться в двух видах: '''текстовом''' (плоский текст в [[КОИ-8]]) и '''токенизированном'''. Оба вида имеют одинаковую внешнюю структуру и различаются одним байтом в заголовочном секторе.
Статья описывает файловую систему, указатель каталога и текстовое представление программ. Отдельно вынесены:


== Общее устройство ==
* [[Искра-226/Кодирование BASIC-файлов]] — токенизированная запись программы;
На диске располагаются физические сектора размером 128 байт 77 дорожек, 26 секторов на дорожке, одна сторона. Физические сектора попарно объединены в логические размером 256 байт со сквозной нумерацией. Далее везде будут подразумеваться логические сектора.
* [[Искра-226/Файлы данных BASIC 02]] записи, значения и способы доступа;
* [[Искра-226/Графический буфер BASIC 02]] — формат рисунка.


Файлу выделяется непрерывный диапазон секторов, границы которого записаны в «Указателе каталога». Раскладка внутри диапазона:
== Диск ==
 
Физический сектор — 128 байт; 77 дорожек по 26 секторов, одна сторона. Физические сектора попарно объединены в логические по 256 байт со сквозной нумерацией. Далее везде подразумеваются логические сектора. Полный объём тома — 1001 сектор, 256 256 байт.
 
Типы файлов:
 
* '''ПФ''' — программный файл: программа на Бейсике в текстовом либо оттранслированном виде;
* '''ФД''' — файл данных.
 
Файлу выделяется непрерывный диапазон секторов, границы записаны в указателе каталога.


{| class="wikitable"
{| class="wikitable"
Строка 17: Строка 27:
| следующие N || поток содержимого
| следующие N || поток содержимого
|-
|-
| … || резерв, заполнен нулями
| … || резерв, нули
|-
|-
| последний выделенный || control record
| последний выделенный || концевая запись
|}
|}


Таким образом, любой файл занимает на диске как минимум на 512 байт больше, чем размер его полезных данных.
Размер файла на диске не меняется, поэтому при перезаписи более коротким содержимым '''хвост не затирается''': там остаются фрагменты предыдущих версий, иногда в другом представлении. Обработку следует прекращать на первой встреченной концевой записи.
 
Размер файла на диске уменьшать нельзя, поэтому при перезаписи файла более коротким содержимым '''старые данные в хвосте не затираются'''. Там могут остаться читаемые фрагменты предыдущих версий файла, иногда в другом представлении. Их нельзя принимать за часть текущего файла, поэтому необходимо завершать обработку файла при нахождении первой control record.
 
Искра-226 поддерживает работу с двумя типами файлов: ПФ — «Программные файлы» и ФД — «Файлы данных». Программные файлы всегда содержат программу на Бейсике, в текстовом или упакованном токенизированном виде. Файлы данных, соответственно, данные, доступные из программ пользователя.
 
В соответствии с документацией, Искра-226 поддерживает прямой доступ программ к секторам диска, при этом к записанным таким образом дискам всё нижеизложенное может быть неприменимо, так как форматом хранения полностью управляет программа пользователя по своему усмотрению.


Также, в наличии имеется несколько системных дисков, на которых содержатся различные версии интерпретатора Бейсика, с которых производится начальная загрузка компьютера. Эти диски имеют свой формат и здесь не рассматриваются.
Диски прямого доступа (запись по абсолютным адресам секторов) указателя каталога не имеют; формат содержимого таких дисков задаёт программа пользователя. Загрузочные диски с интерпретатором имеют собственный формат: нулевой сектор начинается сигнатурой <code>06 90 09 90 07 90</code>, за ней 18 знаков имени и даты версии.


== Указатель каталога ==
== Указатель каталога ==
Начиная с 0 сектора на диске располагается «Указатель каталога».


Первые 16 байт содержат служебную информацию в следующем составе:
Начинается с сектора 0. Первые 16 байт нулевого сектора — параметры диска:


{| class="wikitable"
{| class="wikitable"
! Смещение !! Размер !! Значение
! Смещение !! Размер !! Значение
|-
|-
| 0-1 || 2 || размер Указателя каталога в секторах, 16 бит big-endian
| 0–1 || 2 || размер указателя каталога в секторах (<code>LS</code>), старший байт первым
|-
|-
| 2-3 || 2 || номер последнего использованного сектора, 16 бит big-endian
| 2–3 || 2 || текущий конец каталога — первый свободный сектор
|-
|-
| 4–5 || 2 || размер тома (обычно 1000), 16 бит big-endian
| 4–5 || 2 || конец области каталога
|-
|-
| 6–15 || 10 || нули
| 6–15 || 10 || нули
|}
|}


После служебной информации идут 16-байтовые записи каталога, описывающие файлы. По непонятной причине записи каталога не сгруппированы в начале указателя, а распределены по всем его секторам. Неиспользованные записи заполнены нулями. Следовательно, для чтения указателя каталога необходимо пройти все его сектора, игнорируя нулевые строки.
Размер указателя задаётся при создании каталога оператором <code>SCRATCH DISK</code> параметром <code>LS=</code>, по умолчанию 24, допустимо 1…255; в дальнейшем не меняется. В нулевом секторе помещается 15 записей, в остальных 16. Неиспользованные записи заполнены нулями.
 
Записи '''не сгруппированы''' в начале указателя и не упорядочены по секторам файлов: номер сектора, в который попадает запись, вычисляется хешированием имени. Для чтения каталога надо пройти все его секторы, пропуская нулевые записи.
 
=== Хеш имени файла ===
 
Номер сектора указателя вычисляется по «старому» хешу Wang 2200:
 
имя дополнить пробелами до восьми байт
tmp = 0
для каждого байта имени:  tmp = tmp XOR байт
tmp = 3 × tmp
tmp = (tmp mod 256) + (tmp div 256)
сектор = tmp mod LS
 
Свёртка выполняется исключающим ИЛИ, не сложением. «Новый» хеш Wang, введённый в MVP OS 2.5, на Искре не применяется.
 
Хеш '''вырождается при <code>LS</code>, кратном трём''': после умножения на 3 и складывания половинок результат всегда кратен трём, поэтому занятыми оказываются только каждый третий сектор указателя. При <code>LS = 24</code> все записи попадают в секторы 0, 12, 15 и 18.
 
Запись кладётся в первый свободный слот своего сектора, слоты заполняются подряд от начала. Правило переполнения сектора неизвестно.
 
Освобождение слота выполняется '''обнулением первых восьми байт''' записи; имя при этом остаётся на диске. Оператор <code>SCRATCH</code> запись не обнуляет, а помечает.


== Запись каталога ==
== Запись каталога ==


16 байт, побайтово совпадает с Wang 2200.
16 байт, совпадает с Wang 2200.


{| class="wikitable"
{| class="wikitable"
! Смещение !! Размер !! Значение
! Смещение !! Размер !! Значение
|-
|-
| 0 || 1 || статус: <code>10</code> — активна, <code>11</code> — удалена (scratched), <code>00</code> свободна
| 0 || 1 || статус, битовое поле; '''бит 0''' файл вычеркнут
|-
|-
| 1 || 1 || тип файла: <code>80</code> — программа, <code>00</code> — данные
| 1 || 1 || тип файла: <code>80</code> — программа, <code>00</code> — данные
Строка 71: Строка 95:
|}
|}


Байт типа '''не различает''' текстовое и токенизированное представление: у обоих <code>80</code>.
Наблюдаемые значения статуса: <code>10</code> — активна, <code>11</code> и <code>21</code> — вычеркнута, <code>00</code> — свободна. Сравнивать статус на точное равенство нельзя, значим только бит 0. Бит 5 (значение <code>21</code>) предположительно помечает переименование.
 
Байт типа '''не различает''' текстовое и оттранслированное представление программы: у обоих <code>80</code>.


Указатель каталога всегда начинается с нулевого сектора диска; за ним идёт область каталога. Число секторов указателя задаётся при создании каталога оператором <code>SCRATCH DISK</code> параметром <code>LS=</code>, по умолчанию равно 24 и в дальнейшем не меняется; допустимы значения от 1 до 255. В нулевом секторе помещается до 15 записей, в остальных — до 16: первые 16 байт нулевого сектора занимает блок параметров диска.  
Оператор <code>LIST DC</code> выводит типы как <code>P</code> (программный), <code>D</code> (данные), <code>SP</code> и <code>SD</code> (вычеркнутые), что соответствует сочетанию байта статуса и байта типа.<ref name="balasanyan" />


Оператор <code>LIST DC</code> выводит типы файлов как <code>P</code> (программный), <code>D</code> (файл данных), <code>SP</code> и <code>SD</code> (вычеркнутые из каталога программный и файл данных соответственно), что соответствует сочетанию байта статуса и байта типа в записи.<ref name="balasanyan" />
Тип «данные» ничего не говорит о внутреннем устройстве файла: он может содержать как логические записи, так и сырые блоки, записанные оператором <code>DATA SAVE BA</code>.


=== Пример ===
=== Пример ===
Строка 82: Строка 108:
  └───┘ └───┘ └───┘      └─────────────────────┘
  └───┘ └───┘ └───┘      └─────────────────────┘
Активная запись, программа, секторы 49…63, имя <code>DIG DEM</code>.
Активная запись, программа, секторы 49…63, имя <code>DIG DEM</code>.
== Размещение файлов ==
* Файлы лежат подряд в порядке создания, диапазоны секторов не пересекаются.
* Место вычеркнутого файла заново не занимается: <code>SCRATCH</code> только помечает запись.
* Первый файл начинается с сектора <code>LS</code>, сразу за указателем.
* Поле «текущий конец» равно последнему занятому сектору плюс единица, но обрезается по концу области каталога; при разборе границу надёжнее брать по записям каталога.


== Заголовочный сектор ==
== Заголовочный сектор ==
Строка 92: Строка 125:
| 1–8 || имя файла, дополнено пробелами
| 1–8 || имя файла, дополнено пробелами
|-
|-
| 9 || признак формата записи, см. ниже
| 9 || признак формата записи
|-
|-
| 10–255 || нули
| 10–255 || нули
|}
|}


Байт 9 — единственный признак, по которому различаются два представления программы. В исследованном наборе наблюдались значения <code>20</code> (текстовое), <code>21</code> (токенизированное) и <code>25</code> (токенизированное и защищённое).
Байт 9 (в справочнике<ref name="vtoraya" /> назван «признак защиты») — битовое поле, единственный признак, различающий два представления программы: '''бит 0''' — программа оттранслирована (параметр <code>T</code> оператора <code>SAVE DC</code>), '''бит 2''' — защищена (параметр <code>P</code>); оба вместе соответствуют параметру <code>G</code>.
 
=== Связь с параметрами оператора SAVE DC ===
 
Документация<ref name="balasanyan" /> описывает три параметра специальных форматов записи программы:
 
{| class="wikitable"
! Параметр !! Действие
|-
| <code>T</code> || программа записывается в оттранслированной форме — во внутреннем формате машины, что сокращает занимаемое место и время загрузки
|-
| <code>P</code> || программа защищается от просмотра и записи; после загрузки возможно только выполнение, режим сохраняется до оператора <code>CLEAR</code>
|-
| <code>G</code> || оттранслированная и защищённая форма одновременно
|}
 
Отсюда следует, что '''текстовое представление — это режим по умолчанию''', а токенизированное включается явным указанием параметра <code>T</code>. Термин «оттранслированная форма» в документации обозначает именно токенизированную запись.
 
Документированные значения байта 9 (в источнике он назван «признак защиты»):<ref name="vtoraya" />


{| class="wikitable"
{| class="wikitable"
Строка 129: Строка 144:
|}
|}


Таким образом байт 9 — битовое поле: '''бит 0''' — программа оттранслирована (параметр <code>T</code>), '''бит 2''' — программа защищена (параметр <code>P</code>); сочетание обоих соответствует параметру <code>G</code>. Значения <code>22</code> и <code>23</code> не используются.
Значения <code>22</code> и <code>23</code> не используются. Текстовое представление — режим по умолчанию, оттранслированное включается явным параметром <code>T</code>.


Значения <code>20</code>, <code>21</code> и <code>25</code> наблюдались на дисковых образах (<code>25</code> — у файла <code>STAT05</code>, защищённого и оттранслированного одновременно), <code>24</code> взято из документации.
Защищённая программа после загрузки может только выполняться; режим снимается оператором <code>CLEAR</code>.


== Секторы потока ==
== Секторы потока ==


Первые два байта каждого сектора потока — служебные, в содержимое не входят.
Первые два байта каждого сектора программного потока — служебные, в содержимое не входят. У секторов файла данных служебный заголовок занимает '''один''' байт.


'''Байт 0''' — позиция сектора:
'''Байт 0''' — позиция сектора:


{| class="wikitable"
{| class="wikitable"
! Значение !! Смысл
! Код !! Смысл
|-
|-
| <code>02</code> || первый сектор потока
| <code>02</code> || первый сектор потока
|-
|-
| <code>8F</code> || промежуточный
| <code>03</code> || последний сектор потока
|-
| <code>1C</code> || концевая запись
|-
| <code>8B</code> || запись целиком в одном секторе (только файлы данных)
|-
|-
| <code>03</code> || последний
| <code>8F</code> || промежуточный сектор
|}
|}


В токенизированных программах все секторы потока наблюдались с маркером <code>02</code>; позиционная разметка <code>02</code>/<code>8F</code>/<code>03</code> подтверждена на текстовых файлах и на потоке значений переменных. Причина различия не установлена.
В оттранслированных программах все секторы потока идут с маркером <code>02</code>. Позиционная разметка <code>02</code>/<code>8F</code>/<code>03</code> наблюдается в текстовых файлах и в потоках данных.
 
'''Байт 1''' — только у программных секторов. Во всех исследованных потоках программы он равен <code>80</code>.


{{Внимание|У секторов данных служебный заголовок занимает '''один''' байт, а не два. То, что во всех наблюдавшихся секторах данных на позиции 1 стоял <code>00</code>, объясняется не разметкой потока, а тем, что это первый байт двухбайтового идентификатора значения, и <code>00</code> в нём означает числовой тип. Для сектора, начинающегося со строкового значения, значение будет другим. Использовать байт 1 как признак «программа или данные» нельзя; надёжный признак — байт 9 заголовочного сектора и байт типа в записи каталога.}}
'''Байт 1''' программных секторов равен <code>80</code>. Как признак «программа или данные» он непригоден: у секторов данных на позиции 1 стоит первый байт идентификатора значения. Надёжные признаки — байт 9 заголовочного сектора и байт типа записи каталога.


Двухбайтовая длина служебного заголовка программных секторов подтверждается арифметикой: длины записей строк сходятся только при пропуске двух байтов на каждой пересекаемой границе сектора.
== Концевая запись ==
 
В токенизированном файле сначала идут секторы программы, за ними могут следовать секторы значений переменных с собственной нумерацией.
 
Маркер <code>03</code> имеет содержательный смысл: документация<ref name="balasanyan" /> описывает файл как область, в которой между последней записью данных и последним сектором файла остаются неиспользованные секторы, а концевая запись помечает сектор, откуда можно продолжать запись. Таким образом <code>03</code> — не просто «последний по счёту сектор», а граница записанной области, и всё, что лежит за ней до конца выделенного диапазона, к текущему содержимому файла не относится.
 
== Control record ==
 
Лежит в '''последнем выделенном''' секторе, а не сразу за содержимым.


  1C <длина: 2 байта, старший первым>
  1C <длина: 2 байта, старший первым>


Остаток сектора — нули. Маркер <code>1C</code> соответствует по роли байту <code>20</code> в Wang. Второй источник<ref name="vtoraya" /> описывает эту структуру как признак конца файла <code>1C</code>, за которым во втором и третьем байтах сектора записано число реально занятых секторов, а остальные байты нулевые; последний сектор файла данных устроен так же, как последний сектор программного файла.
Остаток сектора — нули. Соответствует по роли байту <code>20</code> в Wang.
 
Документация<ref name="balasanyan" /> отдельно указывает, что последний сектор файла отводится под служебную информацию, а концевая запись занимает ещё один сектор, поэтому при создании файла его размер следует заказывать на два сектора больше, чем требуется собственно под данные.


Счётчик соответствует графе «Использовано», которую показывает оператор <code>LIST DC</code>. Согласно документации<ref name="balasanyan" /> он '''не поддерживается системой автоматически''': значение заносит прикладная программа оператором <code>DATA SAVE DC END</code>, записывающим односекторную концевую запись в текущий сектор из таблицы устройств. Если признак конца данных не записан, в графе «Использовано» всегда стоит 00001; если записан — число реально использованных секторов.
Счётчик равен '''собственной позиции записи от начала файла''', считая с единицы, то есть числу занятых секторов вместе с заголовком. Он же — графа «Использовано» в выдаче <code>LIST DC</code>.


Там, где значение выставлено, оно равно '''заголовок + секторы содержимого + сам control record''', то есть совпадает с правилом Wang:
* У программных файлов концевую запись пишет сам оператор <code>SAVE DC</code>; она есть всегда.
* У файлов данных её пишет прикладная программа оператором <code>DATA SAVE DC END</code>. Если признак конца не записан, в графе «Использовано» стоит 00001.
* Оператор <code>DATA SAVE DC OPEN</code> пишет в '''последний''' сектор файла запись <code>1C 00 01</code> — единственный случай, когда счётчик не равен позиции.


{| class="wikitable"
Запись лежит не обязательно в последнем выделенном секторе: если файлу дали запас или его положили на место вычеркнутого файла большего размера, за ней остаётся нулевой хвост.
! Файл !! Секторов содержимого !! Счётчик !! Ожидаемо
|-
| <code>ФС</code> || 5 || 7 || 1+5+1 = 7
|-
| <code>ДЕМ6</code> || 16 || 18 || 1+16+1 = 18
|}


{{Внимание|Счётчик не является инвариантом файловой системы и при разборе ненадёжен. У <code>#СТАТИСТ</code> он равен 48 при 46 секторах содержимого — значение, по-видимому, осталось от предыдущей, более длинной версии программы, остатки которой лежат в резерве того же файла. У <code>DIG DEM</code> счётчик равен 6 при 5 секторах содержимого, то есть на единицу меньше ожидаемого; возможная причина в том, что там последней операцией была запись потока данных, а не программы. Границы файла следует брать из каталога, а конец данных определять по структуре записей.}}
Счётчик не инвариант файловой системы и при разборе ненадёжен: у файлов, записанных не операторами <code>DATA SAVE DC</code>, он произволен. Границы файла следует брать из каталога.


== Текстовое представление ==
== Текстовое представление ==


Программа хранится плоским текстом. Кодировка — КОИ-8 (ГОСТ 19768-74): прописная кириллица в 0xE0–0xFF, строчная в 0xC0–0xDF. Номера строк записаны обычными ASCII-цифрами.
Программа хранится плоским текстом. Кодировка — [[КОИ-8]] (ГОСТ 19768-74): прописная кириллица в <code>E0</code>–<code>FF</code>, строчная в <code>C0</code>–<code>DF</code>. Номера строк записаны обычными цифрами.


* Разделитель строк — байт '''<code>85</code>'''.
* Разделитель строк — байт '''<code>85</code>'''.
Строка 193: Строка 196:
* Байт <code>24</code> (<code>$</code>) отображается на экране Искры как <code>¤</code>.
* Байт <code>24</code> (<code>$</code>) отображается на экране Искры как <code>¤</code>.


Выбор <code>85</code> возможен именно потому, что кириллица занимает только верхнюю четверть кодовой таблицы и диапазон 0x80–0x9F остаётся свободным. К самой кодировке КОИ-8 это соглашение отношения не имеет и за пределами Искры не встречается.
Байт <code>85</code> свободен потому, что диапазон <code>80</code>–<code>9F</code> в КОИ-8 не занят. Тем же байтом машина разделяет строки в символьном буфере операторов <code>SAVE</code> и <code>LOAD</code> и выдаёт нажатие клавиши CR/LF.


Разбор: склеить содержимое секторов, отбрасывая по два служебных байта, разбить по <code>85</code>, отбросить нули.
Разбор: склеить содержимое секторов, отбрасывая по два служебных байта, разбить по <code>85</code>, отбросить нули.
Строка 203: Строка 206:
Заголовок сектора, затем <code>5 REM ПЕТРЕНКО …</code>, разделитель, <code>8 PRINT …</code>.
Заголовок сектора, затем <code>5 REM ПЕТРЕНКО …</code>, разделитель, <code>8 PRINT …</code>.


== Токенизированное представление ==
== Виды дисков ==
 
=== Сборка потока ===
 
Склеить содержимое секторов с байтом 1 равным <code>80</code>, отбрасывая по два служебных байта у каждого. Далее смещения даны от начала полученного потока.
 
=== Пролог и таблицы ===
 
Поток начинается с трёх 16-битных длин, '''старший байт первым''', за которыми следуют три таблицы:
 
{| class="wikitable"
! Смещение !! Размер !! Значение
|-
| 0 || 2 || L1 — длина таблицы 1 в байтах, запись 8 байт
|-
| 2 || 2 || L2 — длина таблицы 2 в байтах, запись 4 байта
|-
| 4 || 2 || L3 — длина таблицы 3 в байтах, запись 4 байта
|-
| 6 || L1 || таблица 1
|-
| 6+L1 || L2 || таблица 2
|-
| 6+L1+L2 || L3 || таблица 3
|}
 
'''Программа начинается по смещению <code>6 + L1 + L2 + L3</code>.'''
 
Проверено на четырёх файлах:
 
{| class="wikitable"
! Файл !! L1 !! L2 !! L3 !! Старт !! Первая строка
|-
| <code>DIG DEM</code> || 24 || 20 || 0 || 50 || <code>0 GOTO 10</code>
|-
| <code>#СТАТИСТ</code> || 216 || 488 || 108 || 818 || <code>999 REM  КОНЕЦ</code>
|-
| <code>ДЕМ6</code> || 392 || 256 || 0 || 654 || <code>10 REM "ДЕМ6". ГОРОСКОП</code>
|-
| <code>EDITOR</code> || 448 || 800 || 0 || 1254 || <code>10 % EDITOR.  ВЕРСИЯ 4.1</code>
|}
 
Формула даёт точную границу, эвристический поиск начала программы не требуется. На расширенном наборе из 51 токенизированного файла она также не даёт сбоев: разбор каждого файла доходит до конца потока без рассинхронизации.
 
==== Таблица 1 ====
 
'''Таблица 1 описывает переменные, которым нужен дескриптор размера''' — массивы и символьные переменные с явно заданной длиной. Оператор объявления при этом не важен: в таблицу попадают как переменные из <code>DIM</code>, так и из <code>COM</code> (аналог <code>DIM</code> для переменных, общих для нескольких программ). Числовые скаляры и символьные переменные с длиной по умолчанию в таблице 1 не описываются.
 
В файле <code>М1.Х</code> записей 13 при 10 переменных в <code>DIM</code>; лишние три — <code>C(14)</code>, <code>G(14)</code> и <code>N0¤21</code>, объявленные в <code>COM</code>.
 
Запись — 8 байт:
 
{| class="wikitable"
! Смещение !! Размер !! Значение
|-
| 0–1 || 2 || адрес переменной в памяти, младший байт первым
|-
| 2–3 || 2 || тип: <code>00 08</code> — символьная, <code>2D 08</code> — числовая или целая
|-
| 4–5 || 2 || для массивов — число элементов, младший байт первым
|-
| 6–7 || 2 || размерный код, младший байт первым
|}
 
Размерный код равен '''<code>2 × размер элемента</code>''', а его младший бит означает, что длина была задана явно. Для числовых переменных код 16 (размер элемента 8 байт), для целых 4 (2 байта), для символьных <code>2 × длина + 1</code>: длина 8 → 17, 64 → 129, 128 → 257, 253 → 507.
 
Символьная переменная, объявленная без указания длины, получает длину по умолчанию 16 и '''чётный''' код 32. В <code>STAT01A</code> так объявлены <code>B6¤(400)</code> и <code>B7¤(10)</code>, у обоих код 32, тогда как у всех переменных с явной длиной в том же файле код нечётный и точен. Поэтому нечётность кода нельзя использовать как признак символьного типа — для этого служат байты 2–3.
 
===== Двумерные массивы =====
 
У двумерного массива вторая размерность записывается в байты 2–3, на место признака типа, а первая остаётся в поле числа элементов. Размерности '''не перемножаются''', поэтому оператор <code>DIM</code> восстанавливается точно.
 
Правило проверено на десяти массивах в четырёх файлах, включая <code>A(5,6)</code> из <code>STAT03</code> с двумя разными малыми размерностями. В <code>М1.Х</code> пять массивов вида <code>(2,99)</code> дают в байтах 2–3 значение 99, а в поле числа элементов 2; контрольный <code>R(2,2)</code> с равными размерностями даёт 2 и 2. Размер выделяемой памяти считается по общей формуле с перемножением размерностей: у <code>P(2,99)</code> разность адресов равна 1590 = 2 × 99 × 8 + 6, у <code>R(2,2)</code> — 38 = 2 × 2 × 8 + 6.
 
Пример записи <code>Q(7,8)</code> из <code>STAT01A</code>:
 
00 00  08 00  07 00  10 00
 
Байты 2–3 равны 8 (вторая размерность), байты 4–5 равны 7 (первая), размерный код 16 — числовая. Опознание надёжно: соседние записи таблицы содержат 13 и 8 элементов, а в тексте <code>DIM</code> вокруг <code>Q(7,8)</code> стоят <code>A(13)</code> и <code>E(8)</code>.
 
Практическое правило: '''старший байт поля 2–3 равен <code>08</code> — массив одномерный''', иначе поле 2–3 целиком занято второй размерностью. Значения <code>08 2D</code> и <code>08 00</code> не могут быть размерностью, так как означали бы 2093 и 2048 элементов по второму измерению.
 
Вопрос «как при двумерности кодируется тип переменной» снимается: тип хранится не в таблице 1, а во флаге записи таблиц 2 и 3 (см. ниже), поэтому байты 2–3 таблицы 1 свободны под размерность. Символьные двумерные массивы в наборе есть — пятнадцать записей, у которых флаг помечает символьный тип, а старший байт поля 2–3 равен <code>0C</code>.
 
{{Внимание|1=Исключение — '''неявно объявленные массивы'''. У переменной, к которой обратились с индексом без предварительного <code>DIM</code>, число элементов всегда равно 10 (размерность массива по умолчанию), а в байтах 2–3 стоят значения <code>01 27</code> или <code>07 59</code>, размерностями не являющиеся: в исследованном наборе они встречаются девять и семь раз соответственно и только при десяти элементах, в неродственных программах. Их природа не установлена. Такие массивы следует выводить как одномерные <code>(10)</code>. Настоящий двумерный массив <code>(10,10)</code> в наборе тоже есть — в <code>STATIST</code>, там байты 2–3 равны <code>00 0A</code>.}}
 
===== Порядок записей обратен порядку объявления =====
 
Память под переменные выделяется '''сверху вниз''', от верхней границы, а записи в таблице отсортированы по возрастанию адреса. Поэтому '''первая переменная в <code>DIM</code> оказывается последней записью таблицы''', и сопоставлять их нужно с конца.
 
Проверено на файле <code>EDITOR</code>: 7 операторов <code>DIM</code> объявляют 50 переменных, L1 = 448 = 56 записей. При обратном сопоставлении разность адресов соседних записей совпадает с ожидаемым размером переменной '''у 44 из 50''' точно, а оставшиеся 6 расходятся ровно на 1 байт — это нечётные длины (<code>A¤1</code>, <code>K¤253</code>, <code>G¤19</code>), округляемые вверх до чётной.
 
{{Внимание|1='''Адреса в таблице 1 могут быть нулевыми.''' В файле <code>STAT05</code> все 11 записей имеют адрес <code>0000</code>, поэтому любое правило, опирающееся на разность адресов соседних записей, там неприменимо. Разборщику следует проверять адреса на ненулевое значение перед использованием.
 
Остальные поля при этом заполнены и корректны: обратный порядок относительно <code>DIM</code> сохраняется, размерный код точен для всех строковых переменных, у массива <code>K(9)</code> число элементов равно 9.}}
 
Размер выделяемой памяти:
 
* скалярная символьная переменная — объявленная длина, округлённая вверх до чётной;
* массив — <code>N × размер элемента + 6</code>, где 6 байт занимает дескриптор.
 
Формула для массивов проверена на 20 массивах <code>EDITOR</code> без единого расхождения: <code>V¤(20)64</code> → 1286, <code>S¤(48)64</code> → 3078, <code>P%(300)</code> → 606, <code>X(2)</code> → 22.
 
===== Таблица отражает состояние на момент сохранения =====
 
Число записей может превышать число переменных в <code>DIM</code>. В <code>STAT01A</code> записей 26 при 23 объявленных переменных, и три лишние стоят в области самых низких адресов, то есть выделены последними.
 
Число элементов у лишних записей соответствует не тексту программы, а значению, которое переменная получила при выполнении: в <code>STAT01A</code> у всех трёх лишних записей это 300, тогда как в <code>DIM</code> объявлено 200. Программа содержит оператор <code>MAT REDIM</code>, переопределяющий размерности во время работы, поэтому таблица описывает состояние памяти на момент сохранения, а не исходный текст.
 
Косвенное подтверждение: в токенах <code>DIM</code> файла <code>STAT01A</code> переменные <code>X</code>, <code>Y</code> и <code>G¤</code> получили индексы <code>40</code>, <code>41</code>, <code>42</code>, тогда как все остальные — обычные значения подряд.
 
Причина этого выяснена на файле <code>STAT03</code>, сохранённом в обоих представлениях. Выросший массив получает не только новый дескриптор в таблице 1, но и '''новый индекс переменной''', причём интерпретатор правит операнд в самом операторе <code>DIM</code>, оставляя код и <code>MAT REDIM</code> работать со старым индексом. Оператор
 
20 DIM X(100),G¤(100)5,Q(5,100),D(6),E(5),A(5,6)
 
кодируется как
 
46 06 19 1A 1B 03 04 05
 
— первые три переменные записаны индексами <code>19</code>, <code>1A</code>, <code>1B</code>, тогда как <code>MAT REDIM</code> в строке 200 обращается к ним же как <code>E0 00</code>, <code>E0 01</code>, <code>E0 02</code>. В таблицах 2 и 3 бит 0 флага установлен и у <code>19</code>, <code>1A</code>, <code>1B</code>, и у <code>00</code>, <code>01</code>, <code>02</code>: первым соответствуют дескрипторы с 300 элементами (размер после переопределения), вторым — исходные, со 100.
 
{{Внимание|1=Из этого следует, что операторы <code>DIM</code> в оттранслированном файле нельзя использовать как источник соответствия «индекс — дескриптор»: там могут стоять «теневые» индексы. Надёжный источник — бит 0 флага записей таблиц 2 и 3.}}
 
Дополнительный дескриптор создаётся '''только тогда, когда массив вырастает за пределы исходного выделения'''. Если новый размер не превышает объявленного в <code>DIM</code>, память переиспользуется на месте и запись в таблице остаётся одна.
 
Наиболее наглядно это видно в <code>STAT03</code>, где <code>MAT REDIM</code> переопределяет шесть массивов, а лишних записей три:
 
{| class="wikitable"
! Массив !! Объявлено !! После переопределения !! Дескриптор
|-
| <code>X(100)</code> || 100 || 300 || добавлен
|-
| <code>G¤(100)5</code> || 100 || 300 || добавлен
|-
| <code>Q(5,100)</code> || 100 || 300 || добавлен
|-
| <code>D(6)</code> || 6 || не больше 6 || нет
|-
| <code>E(5)</code> || 5 || не больше 5 || нет
|-
| <code>A(5,6)</code> || 5, 6 || не больше 5 и 6 || нет
|}
 
Правило согласуется и с остальными файлами: в <code>STAT01A</code> из одиннадцати переопределяемых массивов выросли три, в <code>STAT00</code> из четырёх — два, и столько же лишних записей в каждом случае.
 
Если программа не выполнялась после загрузки, оператор <code>MAT REDIM</code> не отрабатывает и лишних записей нет вовсе: в <code>STAT08</code> записей ровно шесть при шести переменных в <code>DIM</code>.
 
В <code>EDITOR</code> шесть записей таблицы 1 не соответствуют ни одному <code>DIM</code>. По флагам таблицы 2 они принадлежат переменным с индексами <code>39</code>, <code>54</code>, <code>64</code>, <code>90</code>, <code>92</code>, <code>93</code>, причём у всех шести число элементов равно 10 — размерности массива по умолчанию. Это '''неявно объявленные массивы''': переменная, к которой обратились с индексом без предварительного <code>DIM</code>, получает десять элементов и полноценный дескриптор. Три из шести — целые (<code>%</code>), размерный код 4, три — действительные, код 16.
 
==== Таблицы 2 и 3 ====
 
Таблицы 2 и 3 образуют '''один непрерывный массив дескрипторов переменных'''. Формат записей в обеих одинаков, граница между ними определяется только счётчиками пролога; число записей — <code>L2 / 4</code> и <code>L3 / 4</code>, поскольку длины в прологе даны в байтах, а запись занимает 4 байта, а не 8.
 
{| class="wikitable"
! Смещение !! Размер !! Значение
|-
| 0–1 || 2 || адрес переменной в памяти, младший байт первым; <code>0000</code>, если память не выделена
|-
| 2 || 1 || флаг типа
|-
| 3 || 1 || назначение не установлено
|}
 
===== Порядок записей =====
 
Записи описывают '''все''' переменные программы, а не только скалярные, и идут в порядке '''убывания индекса переменной'''. Если обозначить
 
N = L2 / 4 + L3 / 4
 
то запись, описывающая переменную с индексом ''i'', находится на позиции <code>N − 1 − i</code>, если считать позиции подряд: сначала записи таблицы 2, затем записи таблицы 3.
 
Отсюда следует, что '''<code>N</code> — это общее число переменных программы''', то есть наибольший использованный индекс плюс единица. Таблица 3 приходится на самые младшие индексы — именно те, которые занимает оператор <code>COM</code>: он всегда выполняется первым и получает индексы с нуля.
 
Правило проверено на всех файлах исследованного набора, разбор которых не срывается на бинарных полезных нагрузках операторов <code>ASMB</code> и <code>$GIO</code>: для 28 файлов совпадение точное.
 
===== Флаг типа =====


{| class="wikitable"
{| class="wikitable"
! Бит !! Значение
! Вид !! Признак
|-
|-
| 5 (<code>0x20</code>) || символьная переменная
| с каталогом || байты 0–1 нулевого сектора — разумный <code>LS</code>, дальше 16-байтовые записи
|-
|-
| 4 (<code>0x10</code>) || числовая переменная (действительная)
| загрузочный || сектор 0 начинается с <code>06 90 09 90 07 90</code>
|-
|-
| ни 5, ни 4 || '''целая переменная''' (суффикс <code>%</code>)
| пакет ассемблера || сектор 0 начинается с <code>7E E1 F3 ED E2</code> (<code>~АСМБ</code>)
|-
|-
| 0 (<code>0x01</code>) || у переменной есть дескриптор в таблице 1 — то есть это массив либо символьная переменная с явно заданной длиной
| прямого доступа || каталога нет, есть заголовочные секторы <code>01 &lt;имя&gt; &lt;признак&gt;</code>
|-
|-
| 7, 3 || назначение не установлено
| пустой || нули
|}
|}
Признак целого типа установлен на файле <code>VICT</code>, единственном в наборе, где есть и целые переменные, и обе копии программы. Ровно три записи таблицы 2 имеют <code>флаг &amp; 0x30 = 0</code> — те, что соответствуют индексам <code>23</code>, <code>28</code> и <code>33</code>. В текстовом листинге ровно три целых переменных, и их индексы совпадают: <code>E%</code> — строка 98 (<code>E%=0</code> → <code>36 04 23 D9 E8 00</code>), <code>E7%</code> — строка 1010, <code>E3%</code> — строка 5070. У всех троих адрес равен <code>0000</code>: целым скалярам в общей области скаляров место не отводится.
Признак символьного типа согласуется с прежним наблюдением: в <code>М1.Х</code> у <code>N¤</code> и <code>N1¤</code> флаг <code>A8</code>, а адреса этих переменных отстоят от соседних на 16 байт — длина символьной переменной по умолчанию.
===== Связь с таблицей 1 =====
Число записей с установленным битом 0 флага '''в точности равно <code>L1 / 8</code>''' во всех файлах набора. Более того, соответствие оказывается порядковым: ''k''-я по счёту такая запись (в порядке файла) описывает ту же переменную, что и ''k''-я запись таблицы 1.
k = 0
для pos = 0 … N−1:
    если флаг[pos] и 1:
        дескриптор_переменной(N − 1 − pos) = запись таблицы 1 номер k
        k = k + 1
Это даёт '''точное соответствие «индекс переменной → запись таблицы 1» без разбора операторов <code>DIM</code> и <code>COM</code>'''. Прежний способ — сопоставление по порядку объявления — ошибочен по двум причинам:
* оператор <code>COM</code> объявляет и обычные скаляры, у которых записи в таблице 1 нет: в <code>М1.Х</code> из тринадцати объявленных переменных дескриптор имеют только три (<code>C(14)</code>, <code>G(14)</code>, <code>N0¤21</code>);
* после <code>MAT REDIM</code> в операнде <code>DIM</code> могут стоять «теневые» индексы (см. ниже).
Три записи таблицы 3 в <code>М1.Х</code> с низкими значениями поля 0–1 (<code>0014</code>, <code>000D</code>, <code>0005</code>) — это как раз те три переменные <code>COM</code>, которые описаны в таблице 1. У всех переменных с дескриптором таблицы 1 поле 0–1 содержит не адрес, а небольшое число, растущее примерно на восемь с каждой такой переменной (в <code>М1.Х</code> — 5, 13, 20, 29, 38, 46, 54, 62, 70, 78, 85, 93, 101). Назначение этого поля не установлено.
===== Практическое следствие =====
Хотя имена переменных в оттранслированном файле не сохраняются, для '''каждой''' переменной восстанавливаются:
* тип — действительная, целая (<code>%</code>) или символьная (<code>¤</code>);
* массив это или скаляр;
* размерности массива и длина элемента.
Разборщику не нужны ни эвристики «массив или скаляр» по разностям адресов (в защищённых файлах адреса нулевые), ни разбор операторов <code>DIM</code>.
=== Индексы переменных и их имена ===
Переменные адресуются в коде однобайтовым индексом. Индексы назначаются '''в порядке первого появления переменной в тексте программы''', а не по алфавиту и не по типу.
Операторы <code>COM</code> и <code>DIM</code> делят единое пространство индексов: в <code>М1.Х</code> оператор <code>COM</code> занимает индексы <code>00</code>–<code>0C</code>, а следующий за ним <code>DIM</code> продолжает с <code>0D</code>.
Для переменных, объявленных в <code>DIM</code>, это даёт прямое соответствие: операторы <code>DIM</code> перечисляют свои переменные подряд, в том же порядке, в каком они записаны в исходном тексте. В <code>EDITOR</code> семь операторов <code>DIM</code> занимают индексы <code>01</code>–<code>32</code> непрерывно; индекс <code>00</code> достался переменной <code>R2%</code>, встретившейся раньше — в строке 30, до первого <code>DIM</code>. В <code>ДЕМ6</code>, где до <code>DIM</code> переменных не было, нумерация начинается с <code>00</code>.
{{Внимание|1='''Имена переменных в оттранслированном файле не сохраняются.''' Таблицы содержат дескрипторы памяти — адрес, тип, размер, — но не имена.
Проверка на <code>EDITOR</code>, где программа сохранена одновременно в текстовом и оттранслированном виде: сопоставление 866 общих строк дало однозначное имя для 146 индексов из 160, и ни одно поле таблиц с этими именами не коррелирует. В таблице 1 поле по смещению 4–5 совпадает у <code>Y¤4</code> и <code>Z¤253</code> (72), у <code>D¤8</code> и <code>Q5¤40</code> (204); в таблице 2 последний байт записи совпадает у заведомо разных переменных (<code>D%</code> и <code>I%</code>, <code>J%</code> и <code>E</code>).
Это согласуется с назначением параметра <code>T</code>: при выполнении имена не нужны, всё адресуется по индексу, а отказ от их хранения и даёт заявленную экономию места. Практическое следствие — '''читаемый листинг из оттранслированного файла восстановить нельзя'''. Восстанавливается структура программы, но переменные остаются безымянными, если не сохранилась текстовая версия того же исходника.
Не хранится только само имя. Тип переменной — действительная, целая или символьная — и её размерности восстанавливаются полностью по таблицам 2, 3 и 1, поэтому в листинге можно выводить корректные суффиксы <code>%</code> и <code>¤</code> и корректные размерности массивов.}}
=== Записи строк ===
Программа — последовательность записей, разделённых байтом '''<code>FE</code>'''. Перед первой записью разделителя нет.
&lt;номер строки: 2 байта BCD&gt; &lt;len: 1 байт&gt; &lt;тело&gt;
<code>len</code> считается '''включая сам байт len''' и до следующего <code>FE</code>. Следующий разделитель находится по адресу <code>адрес(len) + len</code>.
В отличие от текстового представления, записи '''пересекают''' границу сектора; два служебных байта нового сектора в длину не входят.
==== Выравнивание в конце сектора ====
Если очередная запись не помещается в остаток сектора, остаток заполняется нулями, а запись начинается с первого байта следующего сектора. Такие нули стоят '''после''' разделителя <code>FE</code> и в длину записи не входят.
Точное правило формулируется через границы секторов, а не через длину заголовка. Поток рассматривается как последовательность 254-байтовых кусков — по одному на сектор, '''без обрезки хвостовых нулей'''. После разделителя <code>FE</code>, стоящего по смещению ''q'':
b = (⌊q / 254⌋ + 1) × 254
если b > q и все байты потока с q по b−1 нулевые, то q = b
То есть переход к следующему сектору выполняется только тогда, когда весь остаток текущего куска нулевой.
С этим правилом разбор всех 51 токенизированного файла исследованного набора проходит без единой рассинхронизации, а <code>EDITOR</code> даёт ровно 1422 записи строк — столько же, сколько строк в его текстовой версии. Эвристика «пропустить до трёх нулей после <code>FE</code>» этого не обеспечивает: длина выравнивания доходит до шести байт.
{{Внимание|1=Строка с номером 0 кодируется байтами <code>00 00 &lt;len&gt;</code> — такая строка есть в файле <code>DIG DEM</code> (<code>0 GOTO 10</code>). Разборщик, безусловно пропускающий пару нулей перед номером строки, разрушает разбор подобных файлов. Нули следует пропускать только по правилу выше.}}
=== Операторы ===
Тело записи — последовательность операторов:
&lt;токен глагола: 1 байт&gt; &lt;len: 1 байт&gt; &lt;операнды: len байт&gt;
Здесь <code>len</code> — длина только операндов, сам байт len не считается. <code>len = 00</code> означает оператор без операндов, например голый <code>PRINT</code>.
Наличие явной длины у каждого оператора позволяет разрезать программу на операторы, ещё не зная значений токенов. Эта особенность вынужденная: в отличие от Wang, где многословные команды собираются из нескольких токенов вперемешку с обычным ASCII и границы видны по самому потоку, у Искры весь текст программы переведён в токены и поток непрозрачен.
==== Пример разбора ====
Строка 2000 файла <code>#СТАТИСТ</code>, длина 0x54 = 84:
20 00 54
23 01 23                          GOSUB ' 35
4C 39 E3 1F «БУДЕТЕ …» DD 00 DD E3 12 «-[1] ИЛИ ДВУМЯ [2]» DD
                                  PRINT "…";F¤;"…";
41 01 5C                          INPUT F%
36 03 5D D9 0E                    N7=N3
24 06 0E D7 11 D3 20 01          IF N3&lt;N6THEN2001
36 03 5D D9 11                    N7=N6
Сумма: 3 + 59 + 3 + 5 + 8 + 5 = 83, плюс байт длины = 84.
== Таблица токенов ==
=== Глаголы ===
Основной массив значений восстановлен из прошивки интерпретатора (алфавитный список ключевых слов по смещению 0x1840 и 51-байтовый массив перестановки по 0x19B6). Отмеченные записи проверены или исправлены сопоставлением токенизированной и текстовой версий одной программы.
{| class="wikitable"
! Токен !! Оператор !! Примечание
|-
| <code>1E</code> || IF END THEN || выведено из данных; операнд — 2 байта BCD, номер строки
|-
| <code>21</code> || GOTO || подтверждено
|-
| <code>22</code> || GOSUB || подтверждено
|-
| <code>23</code> || GOSUB' || в прошивочной таблице пропуск; значение выведено из данных
|-
| <code>24</code> || IF || подтверждено
|-
| <code>25</code> || KEYIN || подтверждено
|-
| <code>26</code> || ON || подтверждено
|-
| <code>27</code> || DEFFN' || подтверждено
|-
| <code>28</code> || PRINTUSING || в опубликованной таблице ошибочно указан GOSUB'; исправлено по данным
|-
| <code>29</code> || DATA || подтверждено
|-
| <code>2A</code> || SAVE ||
|-
| <code>2B</code> || RENUMBER ||
|-
| <code>2C</code> || CLEAR ||
|-
| <code>2D</code> || LOAD ||
|-
| <code>2E</code> || LIST ||
|-
| <code>2F</code> || RUN || подтверждено
|-
| <code>30</code> || RETURN CLEAR || подтверждено
|-
| <code>34</code> || ON ERROR || подтверждено
|-
| <code>35</code> || LET ||
|-
| <code>36</code> || ''(присваивание без ключевого слова)'' || подтверждено
|-
| <code>3A</code> || DEFFN' с текстовым определением || выведено из данных
|-
| <code>3F</code> || <code>%</code> (краткая форма REM) || подтверждено
|-
| <code>40</code> || $GIO ||
|-
| <code>41</code> || INPUT || подтверждено
|-
| <code>42</code> || STOP || подтверждено
|-
| <code>43</code> || AND( || подтверждено
|-
| <code>44</code> || READ || подтверждено
|-
| <code>45</code> || BOOL ||
|-
| <code>46</code> || DIM || подтверждено
|-
| <code>47</code> || CONVERT || подтверждено
|-
| <code>48</code> || PACK( || подтверждено
|-
| <code>4A</code> || ADD ||
|-
| <code>4B</code> || BIN( ||
|-
| <code>4C</code> || PRINT || подтверждено
|-
| <code>4D</code> || ROTATE || подтверждено
|-
| <code>4E</code> || COM || подтверждено
|-
| <code>50</code> || HEXPRINT ||
|-
| <code>51</code> || RESTORE || подтверждено
|-
| <code>52</code> || NEXT || подтверждено
|-
| <code>53</code> || REWIND ||
|-
| <code>54</code> || SELECT || подтверждено
|-
| <code>55</code> || BACKSPACE ||
|-
| <code>56</code> || REM || подтверждено
|-
| <code>57</code> || FOR || подтверждено
|-
| <code>58</code> || SKIP ||
|-
| <code>59</code> || END ||
|-
| <code>5A</code> || DEFFN ||
|-
| <code>5C</code> || RES ||
|-
| <code>5D</code> || UNPACK( || подтверждено
|-
| <code>5E</code> || RETURN || подтверждено
|-
| <code>5F</code> || TRACE ||
|-
| <code>61</code> || OR( ||
|-
| <code>62</code> || XOR( ||
|-
| <code>63</code> || ''(операция над символьными переменными, имя не установлено)'' || выведено из данных
|-
| <code>64</code> || INIT || подтверждено
|-
| <code>66</code> || DATA LOAD BT || подтверждено
|-
| <code>68</code> || DATA SAVE BT || подтверждено
|-
| <code>6D</code> || COPY ||
|-
| <code>6E</code> || DATA SAVE BA || подтверждено
|-
| <code>70</code> || DATA LOAD BA || подтверждено
|-
| <code>71</code> || DATA LOAD DA || подтверждено
|-
| <code>74</code> || DATA LOAD DC || выведено из данных
|-
| <code>75</code> || DATA LOAD DC OPEN T || выведено из данных
|-
| <code>76</code> || DATA SAVE DC || подтверждено
|-
| <code>77</code> || DATA SAVE DC CLOSE || подтверждено
|-
| <code>78</code> || DATA SAVE DC OPEN T || подтверждено
|-
| <code>79</code> || DBACKSPACE ||
|-
| <code>7A</code> || DSKIP ||
|-
| <code>7B</code> || LIMITS || подтверждено
|-
| <code>7C</code> || LIST DC || подтверждено
|-
| <code>7D</code> || LOAD DC || выведено из данных
|-
| <code>7E</code> || MOVE ||
|-
| <code>80</code> || SAVE DC || выведено из данных
|-
| <code>81</code> || SCRATCH ||
|-
| <code>82</code> || SCRATCH DISK || подтверждено
|-
| <code>83</code> || VERIFY ||
|}
Пометка «подтверждено» означает сверку с текстовым листингом той же программы. Основная часть подтверждений получена на файле <code>EDITOR</code> автоматическим сопоставлением 866 общих строк: в строках, где число операторов в обоих представлениях совпало, первый глагол каждого оператора сверялся с первым словом соответствующего оператора текста. Так подтверждены 34 значения, включая <code>21</code> = GOTO (147 совпадений), <code>4C</code> = PRINT (212), <code>24</code> = IF (266).
Отдельно стоит краткая форма комментария <code>%</code> (токен <code>3F</code>): она встречается в <code>EDITOR</code> 122 раза против 7 у полного <code>REM</code> (токен <code>56</code>), и её операнд записывается сырым текстом без префикса <code>E3</code> — так же, как у <code>REM</code>.
Значения назначены не по алфавиту, а тематическими группами с запасом внутри каждой: управление ходом выполнения в 0x21–0x2F, ввод-вывод около 0x41–0x4C, дисковые операции в 0x74–0x83. Составные дисковые команды получают '''один''' токен на всю фразу, тогда как в Wang та же команда собирается из нескольких (<code>DATA</code> + <code>LOAD</code> + <code>DC</code>).
Документация<ref name="balasanyan" /> описывает также операторы <code>DATA SAVE DC END</code>, <code>DATA SAVE DC CLOSE</code> и <code>DATA LOAD DC OPEN</code>. Все три найдены: <code>DATA LOAD DC OPEN</code> — токен <code>75</code>, <code>DATA SAVE DC CLOSE</code> — отдельный токен <code>77</code>, а <code>DATA SAVE DC END</code> оказался не отдельным глаголом, а обычным <code>DATA SAVE DC</code> (<code>76</code>) с единственным операндом <code>D7</code> — ключевым словом <code>END</code>.
=== Операнды дисковых операторов ===
Первый байт операндов дискового оператора — '''код устройства или режима''', а не ссылка на переменную:
{| class="wikitable"
! Байт !! Значение
|-
| <code>00</code> || <code>F</code> — первый дисковод
|-
| <code>01</code> || <code>R</code> — второй дисковод
|-
| <code>02</code> || <code>T</code> — обращение по номеру файла (<code>#n</code>)
|}
Правило проверено на <code>LIST DC F</code> → <code>7C 01 00</code>, <code>LIST DC R</code> → <code>7C 01 01</code>, <code>LOAD DC F/1C,"М2"</code> → <code>7D 08 00 DC DE 1C DE E3 02 ED 32</code>, <code>SCRATCH R"VIC"</code> → <code>81 05 01 E3 03 56 49 43</code>, <code>SCRATCH T#D,F1¤</code> → <code>81 05 02 DB 22 DE 4C</code>, <code>DATA SAVE DC OPEN T(700)A¤</code> → <code>78 07 02 EB E7 07 00 D0 09</code>.
Ключевые слова конца и начала файла кодируются токенами, у которых в позиции операции другое значение:
79 01 D6              DBACKSPACE BEG
7A 01 D7              DSKIP END
76 01 D7              DATA SAVE DC END
79 04 DB E8 01 DE D6  DBACKSPACE #1,BEG
Тот же <code>D6</code> в операторах <code>DATA SAVE DC</code> и <code>SAVE DC</code> печатается как <code>¤</code>, а <code>D2</code> (обычно <code>STEP</code>) — как параметр <code>T</code>:
76 07 D6 DB E8 02 DE E0 12                  DATA SAVE DC ¤#2,W()
80 0E 01 D6 D2 EB E3 03 «VIC» D0 E3 03 «VIC»  SAVE DC R¤T("VIC")"VIC"
Оператор <code>SCRATCH DISK</code> использует ключевые слова <code>LS</code> и <code>END</code>:
82 0B 01 06 D9 E8 05 DE D7 D9 E7 10 00      SCRATCH DISK RLS=5,END=1000
82 0B 00 06 D9 E8 05 DE D7 D9 E7 10 00      SCRATCH DISK FLS=5,END=1000
Здесь <code>01</code>/<code>00</code> — дисковод, <code>06</code> — ключевое слово <code>LS</code>, <code>D9</code> — знак равенства, <code>D7</code> — <code>END</code>.
=== Списки переменных и списки выражений ===
Список '''принимающих''' переменных пишется '''без разделителей''' — соседние ссылки на переменные и есть список:
41 02 0A 0B                                INPUT T0,N0
74 03 05 0C 0D                              DATA LOAD DC A1¤,E1,E2
7B 08 02 DB 22 DE 4C 4D 4E 36 4F            LIMITS T#D,F1¤,O,A,Q,R
46 04 00 01 02 03                          DIM X(300),Y(300),N(2),G¤(300)5
Список '''выражений''' разделяется <code>DE</code>:
76 06 D6 05 DE 0A DE 0B                    DATA SAVE DC ¤A1¤,T0,N0
28 0B E7 04 70 DE 0F DE 10 DE 00 10 D0      PRINTUSING 470,I,D,X(D)
Запятая между приглашением и переменной в операторе <code>INPUT</code> не кодируется:
41 14 E3 11 «СТЕПЕНЬ  СВОБОДЫ » 00          INPUT "СТЕПЕНЬ  СВОБОДЫ ",K
Номер строки-образа в <code>PRINTUSING</code> — обычная константа <code>E7</code>, а диапазоны строк в <code>SAVE</code>, <code>LOAD</code> и <code>SAVE DC</code> записываются '''сырым двухбайтовым BCD''' без токена:
80 … 90 00 DE 90 90                        SAVE DC …"*ASMBBAS" 9000,9090
2A 0A DD 10 52 15 DE 52 15 DE 52 25        SAVE Z¤5215,5215,5225
У оператора <code>BIN(</code> закрывающая скобка и знак равенства не кодируются, как у <code>PACK(</code> и <code>UNPACK(</code>:
4B 02 22 3B                                BIN(A¤)=J%
=== Двухбайтовые глаголы ===
Матричные и графические операторы кодируются двумя байтами: префиксом <code>06</code> и подкодом. Длина операторной части следует за подкодом на обычном месте:
06 &lt;подкод&gt; &lt;len&gt; &lt;операнды&gt;
Разборщик, ожидающий однобайтовый глагол, на таких строках теряет синхронизацию.
{| class="wikitable"
! Подкод !! Оператор !! Достоверность
|-
| <code>00</code> || <code>PLOT</code> (?) || выведено из данных, см. ниже
|-
| <code>01</code> || MAT (присваивание) || подтверждено
|-
| <code>02</code> || MAT REDIM || подтверждено
|-
| <code>03</code> || MAT READ || по контексту: <code>RESTORE 1,X:06 03 02 E0 24</code>
|-
| <code>04</code> || MAT INPUT || по контексту: приглашение <code>PRINT</code>, затем <code>06 04 02 E0 32</code>
|-
| <code>06</code> || MAT COPY || подтверждено
|-
| <code>0A</code> || MAT SEARCH || подтверждено
|-
| <code>0C</code> || <code>¤TRAN(</code> || подтверждено
|-
| <code>0F</code> || <code>¤OPEN</code> || подтверждено
|-
| <code>13</code> || DOT || сопоставление идиом двух программ
|-
| <code>14</code> || DDRAW || сопоставление идиом двух программ
|-
| <code>15</code> || DRAW || подтверждено
|-
| <code>19</code> || NPLOT || подтверждено
|-
| <code>1C</code> || ''(массив и четыре числа; вероятно <code>FRAME</code>)'' || выведено из данных
|-
| <code>1E</code> || LABEL || подтверждено
|-
| <code>1F</code> || <code>¤COPY</code> || подтверждено
|-
| <code>22</code> || <code>¤LET</code> || подтверждено
|-
| <code>23</code> || WINDOW || подтверждено
|-
| <code>24</code> || LINPUT || подтверждено
|-
| <code>25</code> || ASMB || подтверждено
|-
| <code>26</code> || REPLACE || подтверждено
|}
Операторы <code>DOT</code> и <code>DDRAW</code> опознаны совпадением идиомы в двух программах. Текстовый листинг <code>FAN01</code>:
1540 T3=1:FOR T=2TOT4:NPLOT B6¤(),(M6+M8*(T-T3)),P7+3:DDRAW B6¤(),0,-3:NEXT T
1560 …:DOT B6¤(),R8,R9:DDRAW B6¤(),R6,R7:NEXT T
Токены <code>M4</code> в тех же конструкциях (рисование засечки на оси и отрезка по приращениям):
06 19 … : 06 14 09 E0 10 DE E8 00 DE E9 E8 03      NPLOT …:DDRAW A(),0,-3
06 13 06 E0 10 DE 2A DE 2B : 06 14 06 E0 10 DE 2C DE 1C
==== Подкод 00 ====
Операнды состоят из групп, ограниченных <code>D7</code> … <code>D4</code> (то есть <code>&lt;</code> … <code>&gt;</code>) и разделённых <code>DE</code>; внутри группы до трёх элементов, тоже через <code>DE</code>. Третий элемент (перо) может отсутствовать, быть выражением, строковым литералом или одним из токенов <code>E5</code>/<code>E6</code>:
06 00 09 D7 E8 00 DE E8 10 DE E6 D4                    &lt;0,16,…&gt;
06 00 … D7 E8 56 DE E7 02 55 DE D4 DE D7 DE 2E E9 E7 02 25 DE E6 D4 …
Такой синтаксис соответствует оператору <code>PLOT</code> системы Wang 2200, где аргументы записываются в угловых скобках. В указателе операторов книги<ref name="balasanyan" /> <code>PLOT</code> присутствует только как имя устройства вывода, поэтому имя оператора считается вероятным, но не доказанным.
Примеры из <code>STAT00</code> и <code>STAT01A</code>:
06 02 19 E0 00 EB 09 D0 DE E0 01 EB 08 D0 DE …  MAT REDIM X(…),Y(…),…
06 01 04 E0 07 D9 EF                            MAT S0=ZER
06 19 08 E0 12 DE 26 DE E7 02 50                NPLOT B6¤(),C1,250
06 1F 06 DC DE 14 DE E0 12                      ¤COPY /14,B6¤()
В матричном присваивании <code>EF</code> в позиции операнда означает <code>ZER</code>.
В операторе <code>MAT REDIM</code> размерности массива, в отличие от обращения к элементу, заключаются в '''явную''' открывающую скобку <code>EB</code>, а между собой разделяются <code>DE</code>. Длина элемента символьного массива указывается после закрывающей скобки:
E0 02 EB 0E DE 0D D0        Q(M1,N)  — двумерный
E0 05 EB 0E DE 0F D0        A(M1,M2)
E0 01 EB 0D D0 E8 05        G¤(N)5    — длина элемента после скобки
==== Пропущенные параметры ====
Пропущенный параметр не кодируется ничем: между разделителями <code>DE</code> просто нет операнда. Оператор <code>LABEL B6¤(),,,B3¤(1)</code> с тремя пропущенными параметрами даёт три подряд идущих <code>DE</code>:
06 1E 09 E0 12 DE DE DE 11 E8 01 D0
=== Операнды ===
{| class="wikitable"
! Токен !! Значение !! Достоверность
|-
| <code>00</code>–<code>C9</code> || ссылка на переменную по индексу || подтверждено
|-
| <code>CA</code> || FROM (в <code>PACK</code>/<code>UNPACK</code>) || подтверждено
|-
| <code>CB</code> || ALL (в <code>RETURN CLEAR ALL</code>) || подтверждено
|-
| <code>CC</code> || GOSUB в составе <code>ON … GOSUB</code> || подтверждено
|-
| <code>CD</code> || GOTO в составе <code>ON … GOTO</code> || подтверждено
|-
| <code>D0</code> || <code>)</code> || вероятно
|-
| <code>D1</code> || TO || подтверждено
|-
| <code>D2</code> || STEP; параметр <code>T</code> в <code>SAVE DC</code> || подтверждено
|-
| <code>D3</code> || THEN, далее 2 байта BCD — номер строки || подтверждено
|-
| <code>D4</code> || <code>&gt;</code> || подтверждено
|-
| <code>D5</code> || <code>&lt;&gt;</code> в позиции операции, <code>AT(</code> в позиции операнда || подтверждено
|-
| <code>D6</code> || <code>&lt;=</code> в позиции операции; <code>BEG</code> или <code>¤</code> в позиции операнда || подтверждено
|-
| <code>D7</code> || <code>&lt;</code> в позиции операции; <code>END</code> в позиции операнда || подтверждено
|-
| <code>D8</code> || <code>&gt;=</code> в позиции операции, <code>ROUND(</code> в позиции операнда || подтверждено
|-
| <code>D9</code> || <code>=</code> || подтверждено
|-
| <code>DB</code> || <code>#</code> || подтверждено
|-
| <code>DC</code> || <code>/</code> || вероятно
|-
| <code>DD</code> || <code>;</code> || подтверждено
|-
| <code>DE</code> || <code>,</code> || подтверждено
|-
| <code>DF</code> || <code>*</code> в позиции операции, <code>TAB(</code> в позиции операнда || подтверждено
|-
| <code>E0</code> || <code>^</code> в позиции операции, ссылка на массив целиком в позиции операнда || подтверждено
|-
| <code>E1</code> || функция <code>STR</code> || подтверждено
|-
| <code>E2</code> || шестнадцатеричный литерал <code>HEX(…)</code>: <code>E2 &lt;len&gt; &lt;len байт&gt;</code> || подтверждено
|-
| <code>E3</code> || строковый литерал: <code>E3 &lt;len&gt; &lt;len байт КОИ-8&gt;</code> || подтверждено
|-
| <code>E5</code> || число с фиксированной точкой, см. ниже || подтверждено
|-
| <code>E6</code> || число с порядком, см. ниже || подтверждено
|-
| <code>E7</code> || числовая константа: <code>E7 &lt;2 байта BCD&gt;</code>, диапазон 0–9999 || подтверждено
|-
| <code>E8</code> || числовая константа: <code>E8 &lt;байт BCD&gt;</code>, диапазон 0–99 || подтверждено
|-
| <code>E9</code> || <code>-</code>, бинарный или унарный || подтверждено
|-
| <code>EA</code> || <code>+</code> || вероятно
|-
| <code>EB</code> || <code>(</code> || вероятно
|-
| <code>EC</code>, <code>ED</code>, <code>EE</code>, <code>EF</code> || <code>POS(</code>, <code>LEN(</code>, <code>NUM(</code>, <code>VAL(</code> — без закрывающей скобки || подтверждено
|-
| <code>F0</code> || математическая функция, имя не установлено || выведено из данных
|-
| <code>F1</code> || <code>#PI</code> — константа π || подтверждено
|-
| <code>F2</code> || <code>ABS(</code> || подтверждено
|-
| <code>F3</code> || <code>INT(</code> || подтверждено
|-
| <code>F4</code> || <code>RND(</code> || подтверждено
|-
| <code>F5</code> || <code>SGN(</code> || подтверждено
|-
| <code>F6</code> || <code>SQR(</code> || подтверждено
|-
| <code>F7</code> || <code>LOG(</code> || подтверждено
|-
| <code>F8</code> || <code>EXP(</code> || подтверждено
|-
| <code>F9</code>, <code>FA</code>, <code>FB</code>, <code>FC</code> || математические функции, имена не установлены || выведено из данных
|-
| <code>FD</code> || <code>ARCTAN(</code> || вероятно
|-
| <code>FE</code> || разделитель записей строк || подтверждено
|}
=== Математические функции ===
Книга<ref name="balasanyan" /> (разд. 4.7) перечисляет пятнадцать функций: <code>SIN</code>, <code>COS</code>, <code>TAN</code>, <code>ARCSIN</code>, <code>ARCCOS</code>, <code>ARCTAN</code>, <code>RND</code>, <code>ABS</code>, <code>INT</code>, <code>SGN</code>, <code>LOG</code>, <code>EXP</code>, <code>SQR</code>, <code>ROUND</code>, <code>#PI</code>. Все они, кроме пяти тригонометрических, размещены по токенам:
* <code>F1</code> = <code>#PI</code>. В <code>STAT04</code> выражение <code>SQR(2*#PI)</code> кодируется как <code>F6 E8 02 DF F1 D0</code>; сверено с текстовой копией той же программы.
* <code>F4</code> = <code>RND(</code>. В <code>UDAW</code>: <code>E8 50 DF F4 E8 01 D0 EA E8 15</code> — <code>50*RND(1)+15</code>, а в соседней строке <code>10*RND(1)&lt;9.68</code>.
* <code>F5</code> = <code>SGN(</code>. В <code>EDITOR</code> строка 6717: <code>4E D9 F5 65 E9 04 34 D0 D0</code> = <code>B%=SGN(B-P%(I))</code>; сверено с текстовой копией.
* <code>D8</code> = <code>ROUND(</code> в позиции операнда, см. ниже.
* <code>FD</code> — вероятно <code>ARCTAN(</code>: в <code>M3</code> и <code>P3</code> её единственный аргумент всегда отношение (<code>FD 25 DC 26 D0</code>).
На пять оставшихся имён (<code>SIN</code>, <code>COS</code>, <code>TAN</code>, <code>ARCSIN</code>, <code>ARCCOS</code>) приходится ровно пять свободных токенов — <code>F0</code>, <code>F9</code>, <code>FA</code>, <code>FB</code>, <code>FC</code>, — но программ, сохранённых одновременно в обоих представлениях и использующих тригонометрию, в исследованном наборе нет, поэтому распределение имён по токенам не установлено.
=== Двузначность токенов старшей половины ===
Часть токенов диапазона <code>D0</code>–<code>EF</code> читается по-разному в зависимости от того, ожидается ли на их месте знак операции или очередной операнд. Интерпретатор различает их по состоянию разбора, отдельного признака в файле нет.
{| class="wikitable"
! Токен !! В позиции операции !! В позиции операнда
|-
| <code>D2</code> || STEP || параметр <code>T</code> оператора <code>SAVE DC</code>
|-
| <code>D5</code> || <code>&lt;&gt;</code> || <code>AT(</code>
|-
| <code>D6</code> || <code>&lt;=</code> || <code>BEG</code>; <code>¤</code> после <code>DATA SAVE DC</code> и <code>SAVE DC</code>
|-
| <code>D7</code> || <code>&lt;</code> || <code>END</code>
|-
| <code>D8</code> || <code>&gt;=</code> || <code>ROUND(</code>
|-
| <code>DF</code> || <code>*</code> || <code>TAB(</code>
|-
| <code>E0</code> || <code>^</code> || ссылка на массив целиком
|-
| <code>E9</code> || <code>-</code> бинарный || <code>-</code> унарный
|}
Двузначность <code>D8</code> подтверждена тремя независимыми строками с текстовой сверкой:
2F D9 D8 EF 11 DE DB DC 17 DE E8 01 D0    Y=ROUND(VAL(Y2¤,2)/K7,1)
D8 E5 14 21 17 DF 64 E8 07 D0 DE E8 00 D0  ROUND(2.117*P(7),0)
B1 D9 D8 B1 DC 9A DE E8 00 D0              Q5=ROUND(Q5/P4,0)
В операторе <code>MAT SEARCH</code> знак сравнения стоит '''в позиции операнда''' — сразу после запятой, отделяющей искомое значение:
06 0A 08 E0 20 DE D4 22 D1 E0 1E          MAT SEARCH L4¤(),&gt;A¤TON4¤()
06 0A 0F E1 0D E8 01 DE 45 D0 DE D9 E3 01 20 D1 E0 20  MAT SEARCH STR(Q¤,1,M%),=" "TOL4¤()
{{Внимание|1=Ссылками на переменные являются значения '''<code>00</code>–<code>C9</code>''', а не <code>00</code>–<code>BF</code>: первый токен — <code>CA</code> (<code>FROM</code>). Индексы <code>C0</code>–<code>C9</code> реально встречаются в крупных программах (в <code>EDITOR</code> 200 переменных), например <code>C1 D9 9C</code> — присваивание переменной с индексом <code>C1</code>. Разборщик с границей <code>C0</code> портит листинг таких программ.}}
Ссылка на массив целиком записывается как <code>E0</code> и порядковый номер переменной в <code>DIM</code>: <code>74 02 E0 09</code> соответствует <code>DATA LOAD DC G¤()</code>, а <code>E0 09 D1 E0 00</code> — <code>G¤()TOX()</code>.
Каждое прочтение подтверждено не менее чем двумя независимыми строками <code>STAT05</code>: <code>TAB(17)</code> кодируется как <code>DF E8 17 D0</code>, а <code>.5*LOG(</code> — как <code>E5 01 50 DF F7</code>; <code>K(1)&lt;&gt;1</code> и <code>PRINT AT(9,10)</code> оба дают <code>D5</code>; <code>K0*(-1)</code> даёт <code>DF EB E9 E8 01 D0</code>, где <code>E9</code> стоит в позиции операнда.
Разборщик с одним фиксированным значением на токен на таких строках даёт неверный листинг, поэтому таблицу операндов нужно применять с учётом позиции.
=== Оператор SELECT ===
Первый байт операндов — код группы устройств, записи разделяются <code>DE</code>. Ширина строки, если она задана, записывается после <code>EB</code> как '''двоичное 16-битное число, старший байт первым''' (не BCD).
{| class="wikitable"
! Код !! Группа !! Пример
|-
| <code>00</code> || файл <code>#n</code>: номер, адрес и, необязательно, дисковод || <code>00 01 18</code> = <code>#118</code>; <code>00 01 18 00</code> = <code>#118F</code>
|-
| <code>01</code> || без параметров; вероятно режим тригонометрии (<code>SELECT D</code>/<code>R</code>) || <code>54 01 01</code>
|-
| <code>05</code> || <code>P</code> — пауза после каждой выводимой строки || <code>05 01</code> = <code>SELECT P1</code>; <code>05</code> = <code>SELECT P</code>
|-
| <code>06</code> || устройство, вероятно <code>LIST</code> || <code>06 0C</code>
|-
| <code>07</code> || <code>PRINT</code> || <code>07 0C EB 00 82</code> = <code>SELECT PRINT0C(130)</code>
|-
| <code>08</code> || вероятно <code>PLOT</code> || <code>08 10 DE …</code> (адрес 10 — блок отображения графической информации)
|-
| <code>0A</code> || <code>DISK</code> || <code>0A 18 01</code> = <code>SELECT DISK18R</code>
|-
| <code>0C</code> || устройство, вероятно <code>CO</code> || <code>0C 05 EB 00 50</code>
|}
Опознание кодов <code>01</code>, <code>06</code>, <code>08</code> и <code>0C</code> косвенное. В книге<ref name="balasanyan" /> перечислены группы <code>CI</code>, <code>CO</code>, <code>PRINT</code>, <code>LIST</code>, <code>TAPE</code>, <code>PLOT</code>, <code>DISK</code>, <code>#n</code> и <code>P</code>; строка 300 файла <code>GC121</code> выполняет <code>0C 05(80), 07 05(80), 06 05</code> — типичный возврат <code>CO</code>, <code>PRINT</code> и <code>LIST</code> на экран.
В записях группы <code>00</code> дисковод указывается не всегда: <code>SELECT #118</code> даёт трёхбайтовую запись, <code>SELECT #118F</code> — четырёхбайтовую. Разборщик, всегда читающий четыре байта, съедает разделитель следующей записи.
=== Числовые константы ===
Целые константы кодируются двумя токенами в зависимости от величины: <code>E8</code> — один байт BCD (0–99), <code>E7</code> — два байта BCD (0–9999).
Для дробных чисел служат токены <code>E5</code> и <code>E6</code>. За токеном следует байт-описатель, затем цифры числа в BCD по две на байт; если цифр нечётное число, последняя тетрада заполняется нулём. В описателе '''старшая тетрада — количество цифр до запятой, младшая — общее количество цифр'''.
{| class="wikitable"
! Запись !! Байты !! Описатель !! Цифры
|-
| <code>.5</code> || <code>E5 01 50</code> || 0 / 1 || 5
|-
| <code>.08</code> || <code>E5 02 08</code> || 0 / 2 || 08
|-
| <code>2.5</code> || <code>E5 12 25</code> || 1 / 2 || 25
|-
| <code>.196854</code> || <code>E5 06 19 68 54</code> || 0 / 6 || 196854
|-
| <code>.000344</code> || <code>E5 06 00 03 44</code> || 0 / 6 || 000344
|}
Токен <code>E6</code> устроен так же, но после цифр мантиссы идёт дополнительный байт порядка: <code>1E6</code> кодируется как <code>E6 11 10 06</code> — одна цифра мантиссы, одна цифра до запятой, порядок 6.
Токен <code>E5</code> служит и для '''целых чисел больше 9999''' — всего, что не помещается в <code>E7</code>. Дробной части при этом нет, обе тетрады описателя равны:
{| class="wikitable"
! Запись !! Байты !! Описатель !! Цифры
|-
| <code>51840</code> || <code>E5 55 51 84 00</code> || 5 / 5 || 51840
|-
| <code>248830</code> || <code>E5 66 24 88 30</code> || 6 / 6 || 248830
|-
| <code>2488320</code> || <code>E5 77 24 88 32 00</code> || 7 / 7 || 2488320
|-
| <code>2.718281828</code> || <code>E5 1A 27 18 28 18 28</code> || 1 / 10 || 2718281828
|}
Длина хвоста токена — <code>1 + ⌈''младшая тетрада'' / 2⌉</code> байт для <code>E5</code> и на один байт больше для <code>E6</code>. Разборщик, не потребляющий эти байты, теряет синхронизацию до конца оператора; в исследованном наборе <code>E5</code> встречается в 407 операторах, <code>E6</code> — в 210.
Номер метки в <code>GOSUB'</code> хранится '''двоичным''', а не в BCD. То же относится к первому байту операндов оператора <code>DEFFN'</code>.
=== Цепочка операторов DATA ===
Два последних байта операндов каждого оператора <code>DATA</code> — '''указатель на следующий оператор <code>DATA</code>, младший байт первым'''. У последнего оператора <code>DATA</code> в программе он равен <code>00 00</code>. По этой цепочке работают операторы <code>READ</code> и <code>RESTORE</code>.
{| class="wikitable"
! Файл !! Значения указателей
|-
| <code>DIG DEM</code> || 03C0, 03E7, 040E, 0435, 045C, …, 0594, 0000
|-
| <code>M0</code> || 0443, 046A, 0491, 04B8, …, 0617, 0000
|-
| <code>VICT</code> || 0A97, 0ABE, 0AE5, 0B0C, …, 0C6B, 0000
|}
Шаг постоянен, когда постоянна длина операторов, но значения — адреса в памяти интерпретатора, а не смещения в потоке файла, поэтому пересчёт по потоку сходится не всегда.
{{Внимание|1=Эти два байта нельзя разбирать как токены. Именно они выглядели как «неопознанные токены» в конце строк <code>DATA</code>: <code>C0 14</code>, <code>C9 04</code>, <code>FA 0E</code>, <code>CF 0B</code>, <code>E4 2C</code>, <code>F9 2C</code>.}}
=== Подпрограммы с параметрами ===
Аргументы <code>GOSUB'</code> следуют сразу за байтом метки и разделяются токеном <code>DE</code>; скобки не кодируются. Вызов <code>GOSUB ' 5(1,1,N-2)</code> даёт:
23 0B 05 E8 01 DE E8 01 DE 0D E9 E8 02
Объявление <code>DEFFN'</code> содержит метку, четыре нулевых байта и индексы формальных параметров. Нули, по-видимому, отведены под адрес возврата, заполняемый при выполнении. Объявление <code>DEFFN ' 5(N1,D1,D2)</code> даёт:
27 08 05 00 00 00 00 12 20 21
Оператор <code>ON … GOTO</code> кодируется как индекс переменной, токен <code>CD</code> и номера строк по два байта BCD подряд без разделителей.
=== Индексация массивов ===
У обращения к элементу массива '''нет открывающей скобки''': ссылка на переменную сама открывает список индексов, а <code>D0</code> его закрывает.
01 32 D0        →  01(32)
2A 03 E8 01 D0 D0  →  2A(03,1)
Токен <code>EB</code> используется только как группирующая скобка в выражениях:
EB 34 E9 33 E9 E8 01 D0  →  (34*33*1)
Разборщик, ожидающий <code>EB</code> перед индексом массива, рассинхронизируется.
== Поток значений переменных ==
Секторы, следующие за программой в токенизированном файле, содержат значения переменных, записанные в том же формате, что и обычные файлы данных. Структура описана в документации<ref name="balasanyan" />.
Служебная информация в секторе двух видов:
* '''идентификатор сектора''' — 1 байт в начале сектора, значение <code>02</code> (признак данных);<ref name="vtoraya" /> под данные остаются 255 байт;
* '''идентификатор значения''' — 2 байта перед каждым значением, содержат тип (числовое или символьное) и длину.
Размеры значений:
{| class="wikitable"
! Тип !! Значение !! Со служебными байтами !! Значений в секторе
|-
| целое || 2 байта || 4 байта || 63
|-
| действительное || 8 байт || 10 байт || 25
|-
| символьное || длина значения || длина + 2 || —
|}
Значение, не помещающееся в секторе целиком, переносится в следующий сектор полностью. Элементы массивов записываются построчно.
=== Пример ===
В файле <code>DIG DEM</code> сектор данных начинается с идентификатора сектора <code>02</code>, за которым идут 25 записей по 10 байт:
00 08 &lt;8 байт значения&gt;
Идентификатор <code>00 08</code> означает числовое значение длиной 8 байт. Двадцать пятая запись заканчивается на пятом байте от конца сектора, оставшиеся 5 байт не используются: 1 + 25 × 10 + 5 = 256. Расчёт сходится точно и подтверждает однобайтовую длину идентификатора сектора.
== Алгоритм разбора ==
# Прочитать запись каталога: первый и последний сектор, тип должен быть <code>80</code>.
# Прочитать первый сектор: проверить байт 0 = <code>01</code>, взять имя, прочитать байт 9.
# Если байт 9 = <code>20</code>: склеить содержимое секторов, разбить по <code>85</code>, отбросить нули, перекодировать КОИ-8. Готово.
# Если байт 9 = <code>21</code>: собрать поток из секторов с байтом 1 = <code>80</code>, беря с каждого ровно 254 байта '''без обрезки хвостовых нулей'''; прочитать L1, L2, L3; перейти к смещению <code>6 + L1 + L2 + L3</code>.
# Построить таблицу переменных: <code>N = L2/4 + L3/4</code>; для каждой позиции ''pos'' индекс равен <code>N − 1 − pos</code>, тип берётся из флага; записи с установленным битом 0 флага по порядку сопоставляются записям таблицы 1.
# Для каждой записи строки: номер строки из двух байтов BCD, длина из третьего, тело до следующего <code>FE</code>. Если по отсчитанной длине не оказалось <code>FE</code> — поток рассинхронизирован, разбор остановить.
# После <code>FE</code>: если весь остаток текущего 254-байтового куска нулевой, перейти к началу следующего куска.
# Тело разрезать на операторы по схеме <code>&lt;глагол&gt;&lt;len&gt;&lt;операнды&gt;</code>, учитывая двухбайтовые глаголы с префиксом <code>06</code>.
# Перед разбором операндов учесть особые формы: у <code>DATA</code> два последних байта — указатель цепочки, у дисковых операторов первый байт — код <code>F</code>/<code>R</code>/<code>T</code>, у <code>GOSUB'</code> и <code>DEFFN'</code> первый байт — двоичная метка, у <code>SELECT</code> и <code>SCRATCH DISK</code> — собственный формат.
Обработку файла следует прекращать на '''первом''' встреченном секторе с маркером <code>1C</code>, а не доходить до конца выделенного диапазона: за control record могут лежать остатки предыдущей, более длинной версии файла.
Число записей в таблицах 2 и 3 равно <code>L2 / 4</code> и <code>L3 / 4</code> — запись в них вдвое короче, чем в таблице 1.
Байт длины в каждой записи и в каждом операторе даёт бесплатную проверку целостности на каждом шаге. Дополнительная проверка — совпадение числа записей таблиц 2 и 3 с установленным битом 0 флага и числа записей таблицы 1 (<code>L1 / 8</code>).


== Отличия от Wang 2200 ==
== Отличия от Wang 2200 ==
Строка 1133: Строка 229:
| Запись каталога || 16 байт || совпадает побайтово
| Запись каталога || 16 байт || совпадает побайтово
|-
|-
| Маркер control record || <code>20</code> || <code>1C</code>
| Хеш имени || «старый» и «новый» || только «старый»
|-
| Маркер концевой записи || <code>20</code> || <code>1C</code>
|-
|-
| Маркер заголовка || <code>40</code> (<code>50</code> для защищённых) || <code>01</code>
| Маркер заголовка || <code>40</code> (<code>50</code> для защищённых) || <code>01</code>
Строка 1139: Строка 237:
| Маркеры секторов || битовое поле в старшей тетраде || отдельные значения <code>02</code>/<code>8F</code>/<code>03</code>
| Маркеры секторов || битовое поле в старшей тетраде || отдельные значения <code>02</code>/<code>8F</code>/<code>03</code>
|-
|-
| Конец строки в программе || <code>0D 00 00</code> || <code>FE</code> как разделитель
| Представление программы || ключевые слова в токенах, остальное ASCII || несовместимо, см. [[Оттранслированное представление BASIC 02]]
|-
| Конец блока || <code>FD</code> (EOB) / <code>FE</code> (EOD) || не используется
|-
| Диапазон токенов || 0x80–0xFB, 124 значения || глаголы 0x1E–0x83, операнды 0xCA–0xFE, индексы переменных 0x00–0xC9
|-
| Текст в программе || ключевые слова в токенах, остальное обычный ASCII || всё в токенах, ASCII только внутри строковых литералов
|-
| Переменные || имена в открытом виде || индексы в таблицу, имена не хранятся
|-
| Длина оператора || отсутствует || обязательный байт после каждого глагола
|}
|}


Таблицы токенов не имеют между собой ничего общего: систематического сдвига нет, совпадений по отдельным байтам нет. Инструментарий Wang для детокенизации переиспользовать нельзя. Совпадает только уровень файловой системы.
Совпадает только уровень файловой системы. Инструментарий Wang для разбора самих программ непригоден.
 
Вероятная причина расхождения — кодировка. В Wang верхняя половина таблицы свободна и отдана под ключевые слова; у Искры она занята кириллицей, поэтому глаголы перенесены вниз, а от литерального ASCII в потоке отказались полностью.
 
== Не установлено ==
 
# Полная таблица токенов: часть значений в диапазонах 0x31–0x33, 0x37–0x39, 0x3B–0x3E, 0x49, 0x4F, 0x5B, 0x60, 0x65, 0x67, 0x69–0x6C, 0x72, 0x73, 0x7F не занята в известной таблице.
# Имя оператора у глаголов <code>37</code> и <code>63</code>, у подкода <code>06 00</code> (вероятно <code>PLOT</code>) и <code>06 1C</code> (вероятно <code>FRAME</code>).
# Распределение имён <code>SIN</code>, <code>COS</code>, <code>TAN</code>, <code>ARCSIN</code>, <code>ARCCOS</code> по свободным токенам <code>F0</code>, <code>F9</code>, <code>FA</code>, <code>FB</code>, <code>FC</code>: программ с тригонометрией, сохранённых сразу в обоих представлениях, в наборе нет.
# Смысл поля по смещению 4–5 записи таблицы 1 у скалярных символьных переменных: у массивов там число элементов, у скаляров значения образуют ряд с шагом около 6 в порядке объявления независимо от длин, что указывает скорее на указатель, чем на характеристику самой переменной.
# Смысл байта 3 записей таблиц 2 и 3, а также битов 7 и 3 флага.
# Смысл поля 0–1 записей таблиц 2 и 3 у переменных, имеющих дескриптор в таблице 1: это не адрес, а небольшое число, растущее примерно на восемь.
# Что кодирует токен <code>DB</code> как второй аргумент функции <code>VAL</code>: во всём наборе встречается только <code>VAL(x,2)</code>.
# Однобайтовый операнд у <code>AND(</code>, <code>OR(</code>, <code>XOR(</code>: <code>43 03 15 DE F0</code> = <code>AND(A¤,F0)</code>, <code>61 06 00 E8 01 D0 DE FF</code> = <code>OR(A¤(1),FF)</code>. Похоже на шестнадцатеричную маску без <code>HEX()</code>, но правило, по которому она отличается от ссылки на переменную, неизвестно.
# Причина различия разметки секторов между токенизированными и текстовыми потоками: в текстовых файлах наблюдается позиционная схема <code>02</code>/<code>8F</code>/<code>03</code>, в токенизированных все секторы программы идут с маркером <code>02</code>.
# Токены операторов, встречающихся в указателе книги, но не найденных в наборе: <code>DATA SAVE DA END</code>, <code>MOVE END</code>, <code>COM CLEAR</code>, <code>CLEAR N/P/V</code>, <code>LIST V</code>, <code>LIST *</code>, <code>LIST %</code>, <code>LIST ¤</code>.


== Примечания ==
== Примечания ==


<references>
<references>
<ref name="balasanyan">Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987. — 264 с.: ил. — разделы 5.1, 5.2, 11.5, 18.1, 18.4, 18.7.</ref>
<ref name="balasanyan">Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987. — 264 с.: ил.</ref>
<ref name="vtoraya">Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение: справочное руководство. — Киев, 1988. — структура программного файла и файла данных, значения признака защиты.</ref>
<ref name="vtoraya">Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение: справочное руководство. — Киев, 1988.</ref>
</references>
</references>


== Источники ==
== Источники ==


* Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987. — 264 с.: ил.
* Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987.
* Реконструкция по образам дисков: файлы <code>TRANSFER</code>, <code>ФС</code> (текстовые), <code>DIG DEM</code>, <code>#СТАТИСТ</code>, <code>ДЕМ6</code> (токенизированные), <code>EDITOR</code> (сохранён в обоих представлениях — 182 сектора, 1422 строки; основной материал для проверки структуры таблиц и таблицы токенов), <code>STAT05</code> (защищённый и оттранслированный, с расчётами с плавающей точкой; материал для разбора формата констант и двузначности токенов), <code>STAT01A</code> (защищённый и оттранслированный; единственный образец с двумерным массивом), <code>STAT00</code> (защищённый и оттранслированный, сокращённая версия той же программы; материал для разбора двухбайтовых глаголов), <code>М1.Х</code> (сохранён в обоих представлениях; единственный образец с оператором <code>COM</code> и непустой таблицей 3, а также с шестью двумерными массивами), <code>STAT03</code> и <code>STAT08</code> (защищённые и оттранслированные; материал для разбора условий появления дополнительных дескрипторов при <code>MAT REDIM</code>, а <code>STAT08</code> — единственный оттранслированный файл с заполненными адресами в таблице 1).
* Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение. — Киев, 1988.
 
* [http://www.wang2200.org/disk_org.html Wang 2200 Disk Organization] — файловая система и хеш имени для сопоставления.
Дамп <code>STAT01A</code> снят с удалённого файла, поэтому его целостность не гарантирована; выводы по нему опираются только на таблицу 1 и операторы <code>DIM</code>, взаимно согласованные по всем 23 объявленным переменным.
* Реконструкция по 42 образам дисков: 303 записи каталога, 94 файла программ.
 
Расшифрованный листинг <code>EDITOR</code> получен ранней версией инструментария и содержит дефект: в нём полностью отсутствует символ <code>&lt;</code> (ноль вхождений при сотне вхождений <code>&gt;</code>), из-за чего строки вида <code>IF N¤"????"THEN202</code> выглядят без знака сравнения, хотя в токенах он есть (<code>D5</code>). Для сверки предпочтительны листинги <code>STAT0x</code>, <code>VICT</code> и <code>M1</code>.
 
При сверке представлений следует учитывать, что текстовая и оттранслированная копии одной программы на диске могут относиться к разным её версиям. В <code>STAT05</code> текстовый листинг строки 240 содержит вызов <code>ABS</code>, отсутствующий в оттранслированной копии, что подтверждается длиной оператора. У <code>EDITOR</code> расхождения версий заметны по номерам строк в <code>THEN</code>.
* Расширенный набор (2026): 51 оттранслированный файл и 28 текстовых листингов, в том числе 12 пар «текст + токены»: <code>EDITOR</code>, <code>M1</code>, <code>VICT</code>, <code>STAT00</code>, <code>STAT001</code>, <code>STAT01</code>, <code>STAT02</code>, <code>STAT03</code>, <code>STAT04</code>, <code>STAT05</code>, <code>STAT08</code>, <code>STAT09</code>. Ключевые для этой статьи: <code>STAT04</code> (константы, <code>#PI</code>), <code>STAT09</code> (полный набор дисковых операторов), <code>VICT</code> (единственная пара с целыми переменными), <code>M1</code> (оператор <code>COM</code>), <code>STAT03</code> (поведение <code>MAT REDIM</code>), <code>M4</code> и <code>FAN01</code> (графические операторы <code>DOT</code> и <code>DDRAW</code>), <code>S1</code>, <code>S2</code>, <code>GC121</code> (<code>IF END THEN</code>), <code>UDAW</code> (<code>RND</code>).
* Таблица глаголов — из прошивки интерпретатора, по материалам проекта [https://github.com/elaranovikova/iskra226 elaranovikova/iskra226].
* Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение: справочное руководство. — Киев, 1988.
* Структура файловой системы Wang для сопоставления — [http://www.wang2200.org/disk_org.html Wang 2200 Disk Organization].


[[Категория:Искра-226]]
[[Категория:Искра-226]]

Текущая версия от 18:38, 26 августа 2026

Этот документ создан для Emuverse и распространяется на условиях лицензии CC-BY-SA-3.0.

Файловая система Искры 226 — способ хранения файлов на дисках Искра-226. Унаследована от Wang 2200 и совпадает с ней побайтово; содержимое файлов — оригинальное и с Wang несовместимо.

Статья описывает файловую систему, указатель каталога и текстовое представление программ. Отдельно вынесены:

Диск

Физический сектор — 128 байт; 77 дорожек по 26 секторов, одна сторона. Физические сектора попарно объединены в логические по 256 байт со сквозной нумерацией. Далее везде подразумеваются логические сектора. Полный объём тома — 1001 сектор, 256 256 байт.

Типы файлов:

  • ПФ — программный файл: программа на Бейсике в текстовом либо оттранслированном виде;
  • ФД — файл данных.

Файлу выделяется непрерывный диапазон секторов, границы записаны в указателе каталога.

Сектор Содержимое
первый заголовок файла
следующие N поток содержимого
резерв, нули
последний выделенный концевая запись

Размер файла на диске не меняется, поэтому при перезаписи более коротким содержимым хвост не затирается: там остаются фрагменты предыдущих версий, иногда в другом представлении. Обработку следует прекращать на первой встреченной концевой записи.

Диски прямого доступа (запись по абсолютным адресам секторов) указателя каталога не имеют; формат содержимого таких дисков задаёт программа пользователя. Загрузочные диски с интерпретатором имеют собственный формат: нулевой сектор начинается сигнатурой 06 90 09 90 07 90, за ней 18 знаков имени и даты версии.

Указатель каталога

Начинается с сектора 0. Первые 16 байт нулевого сектора — параметры диска:

Смещение Размер Значение
0–1 2 размер указателя каталога в секторах (LS), старший байт первым
2–3 2 текущий конец каталога — первый свободный сектор
4–5 2 конец области каталога
6–15 10 нули

Размер указателя задаётся при создании каталога оператором SCRATCH DISK параметром LS=, по умолчанию 24, допустимо 1…255; в дальнейшем не меняется. В нулевом секторе помещается 15 записей, в остальных 16. Неиспользованные записи заполнены нулями.

Записи не сгруппированы в начале указателя и не упорядочены по секторам файлов: номер сектора, в который попадает запись, вычисляется хешированием имени. Для чтения каталога надо пройти все его секторы, пропуская нулевые записи.

Хеш имени файла

Номер сектора указателя вычисляется по «старому» хешу Wang 2200:

имя дополнить пробелами до восьми байт
tmp = 0
для каждого байта имени:  tmp = tmp XOR байт
tmp = 3 × tmp
tmp = (tmp mod 256) + (tmp div 256)
сектор = tmp mod LS

Свёртка выполняется исключающим ИЛИ, не сложением. «Новый» хеш Wang, введённый в MVP OS 2.5, на Искре не применяется.

Хеш вырождается при LS, кратном трём: после умножения на 3 и складывания половинок результат всегда кратен трём, поэтому занятыми оказываются только каждый третий сектор указателя. При LS = 24 все записи попадают в секторы 0, 12, 15 и 18.

Запись кладётся в первый свободный слот своего сектора, слоты заполняются подряд от начала. Правило переполнения сектора неизвестно.

Освобождение слота выполняется обнулением первых восьми байт записи; имя при этом остаётся на диске. Оператор SCRATCH запись не обнуляет, а помечает.

Запись каталога

16 байт, совпадает с Wang 2200.

Смещение Размер Значение
0 1 статус, битовое поле; бит 0 — файл вычеркнут
1 1 тип файла: 80 — программа, 00 — данные
2–3 2 первый сектор файла, старший байт первым
4–5 2 последний сектор файла, старший байт первым
6–7 2 не используются
8–15 8 имя файла, дополнено пробелами справа

Наблюдаемые значения статуса: 10 — активна, 11 и 21 — вычеркнута, 00 — свободна. Сравнивать статус на точное равенство нельзя, значим только бит 0. Бит 5 (значение 21) предположительно помечает переименование.

Байт типа не различает текстовое и оттранслированное представление программы: у обоих 80.

Оператор LIST DC выводит типы как P (программный), D (данные), SP и SD (вычеркнутые), что соответствует сочетанию байта статуса и байта типа.[1]

Тип «данные» ничего не говорит о внутреннем устройстве файла: он может содержать как логические записи, так и сырые блоки, записанные оператором DATA SAVE BA.

Пример

 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
10 80 00 31 00 3F 00 00 44 49 47 20 44 45 4D 20
└───┘ └───┘ └───┘       └─────────────────────┘

Активная запись, программа, секторы 49…63, имя DIG DEM.

Размещение файлов

  • Файлы лежат подряд в порядке создания, диапазоны секторов не пересекаются.
  • Место вычеркнутого файла заново не занимается: SCRATCH только помечает запись.
  • Первый файл начинается с сектора LS, сразу за указателем.
  • Поле «текущий конец» равно последнему занятому сектору плюс единица, но обрезается по концу области каталога; при разборе границу надёжнее брать по записям каталога.

Заголовочный сектор

Смещение Значение
0 01
1–8 имя файла, дополнено пробелами
9 признак формата записи
10–255 нули

Байт 9 (в справочнике[2] назван «признак защиты») — битовое поле, единственный признак, различающий два представления программы: бит 0 — программа оттранслирована (параметр T оператора SAVE DC), бит 2 — защищена (параметр P); оба вместе соответствуют параметру G.

Значение Символ Защита Представление
20 пробел нет текстовое
21 ! нет оттранслированное
24 ¤ есть текстовое
25 % есть оттранслированное

Значения 22 и 23 не используются. Текстовое представление — режим по умолчанию, оттранслированное включается явным параметром T.

Защищённая программа после загрузки может только выполняться; режим снимается оператором CLEAR.

Секторы потока

Первые два байта каждого сектора программного потока — служебные, в содержимое не входят. У секторов файла данных служебный заголовок занимает один байт.

Байт 0 — позиция сектора:

Код Смысл
02 первый сектор потока
03 последний сектор потока
1C концевая запись
8B запись целиком в одном секторе (только файлы данных)
8F промежуточный сектор

В оттранслированных программах все секторы потока идут с маркером 02. Позиционная разметка 02/8F/03 наблюдается в текстовых файлах и в потоках данных.

Байт 1 программных секторов равен 80. Как признак «программа или данные» он непригоден: у секторов данных на позиции 1 стоит первый байт идентификатора значения. Надёжные признаки — байт 9 заголовочного сектора и байт типа записи каталога.

Концевая запись

1C <длина: 2 байта, старший первым>

Остаток сектора — нули. Соответствует по роли байту 20 в Wang.

Счётчик равен собственной позиции записи от начала файла, считая с единицы, то есть числу занятых секторов вместе с заголовком. Он же — графа «Использовано» в выдаче LIST DC.

  • У программных файлов концевую запись пишет сам оператор SAVE DC; она есть всегда.
  • У файлов данных её пишет прикладная программа оператором DATA SAVE DC END. Если признак конца не записан, в графе «Использовано» стоит 00001.
  • Оператор DATA SAVE DC OPEN пишет в последний сектор файла запись 1C 00 01 — единственный случай, когда счётчик не равен позиции.

Запись лежит не обязательно в последнем выделенном секторе: если файлу дали запас или его положили на место вычеркнутого файла большего размера, за ней остаётся нулевой хвост.

Счётчик — не инвариант файловой системы и при разборе ненадёжен: у файлов, записанных не операторами DATA SAVE DC, он произволен. Границы файла следует брать из каталога.

Текстовое представление

Программа хранится плоским текстом. Кодировка — КОИ-8 (ГОСТ 19768-74): прописная кириллица в E0FF, строчная в C0DF. Номера строк записаны обычными цифрами.

  • Разделитель строк — байт 85.
  • Строка не пересекает границу сектора; хвост сектора заполняется нулями.
  • Байт 24 ($) отображается на экране Искры как ¤.

Байт 85 свободен потому, что диапазон 809F в КОИ-8 не занят. Тем же байтом машина разделяет строки в символьном буфере операторов SAVE и LOAD и выдаёт нажатие клавиши CR/LF.

Разбор: склеить содержимое секторов, отбрасывая по два служебных байта, разбить по 85, отбросить нули.

Пример

02 80 35 20 52 45 4D 20 F0 E5 F4 F2 E5 EE EB EF … 85 38 20 50 52 49 4E 54 …

Заголовок сектора, затем 5 REM ПЕТРЕНКО …, разделитель, 8 PRINT ….

Виды дисков

Вид Признак
с каталогом байты 0–1 нулевого сектора — разумный LS, дальше 16-байтовые записи
загрузочный сектор 0 начинается с 06 90 09 90 07 90
пакет ассемблера сектор 0 начинается с 7E E1 F3 ED E2 (~АСМБ)
прямого доступа каталога нет, есть заголовочные секторы 01 <имя> <признак>
пустой нули

Отличия от Wang 2200

Wang 2200 Искра-226
Запись каталога 16 байт совпадает побайтово
Хеш имени «старый» и «новый» только «старый»
Маркер концевой записи 20 1C
Маркер заголовка 40 (50 для защищённых) 01
Маркеры секторов битовое поле в старшей тетраде отдельные значения 02/8F/03
Представление программы ключевые слова в токенах, остальное ASCII несовместимо, см. Оттранслированное представление BASIC 02

Совпадает только уровень файловой системы. Инструментарий Wang для разбора самих программ непригоден.

Примечания

  1. Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987. — 264 с.: ил.
  2. Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение: справочное руководство. — Киев, 1988.

Источники

  • Баласанян В. Э., Богдюкевич С. В., Шахвердов В. А. Программирование на микроЭВМ «Искра 226». — М.: Финансы и статистика, 1987.
  • Аладьев В. З. и др. Персональный компьютер «Искра-226». Архитектура и программное обеспечение. — Киев, 1988.
  • Wang 2200 Disk Organization — файловая система и хеш имени для сопоставления.
  • Реконструкция по 42 образам дисков: 303 записи каталога, 94 файла программ.