А.П.Гармашов, программист
О текстах подпрограмм в кодах для БЕЙСИКа БК 0010
Загрузку программ в машинных кодах при работе с БЕЙСИКом на ПЭВМ БК-0010 обычно выполняют либо командой Бейсик-системы BLOAD, либо помещают тексты машинных кодов в операторы DATA, а оттуда - по нужным адресам. Перевод текста программы в кодах в операторы DATA для Бейсик-программы выполняется вручную.
Приведённая ниже программа предназначена для автоматической генерации операторов DATA из любых программ в кодах. Во время выполнения её исходный текст заменяется строками программы на Бейсике с операторами DATA, содержащими представления кодов в десятичной, восьмеричной или шестнадцатеричной системах счисления. Текст программы генерации теряется.
Для пояснения работы программы сначала рассмотрим особенности интерпретатора ПЭВМ БК-0010 - интерпретатора "компилирующего типа", хранящего во время выполнения программы исходный текст и исполняемый модуль. Исходный текст начинается с адреса &O3052, причём строки программы хранятся без номеров и не всегда в порядке их следования в программе. Сначала расположена наиболее "старая" строка с учётом исправлений текста, а последней - последняя введённая или изменённая строка. В начало строки добавляется символ с кодом 0, если только она не начинается с зарезервированного слова БЕЙСИКа. В этом случае код 0 не добавляется, а слово заменяется внутренним кодом БЕЙСИКа. Например, для оператора DATA код &O100 (символ В конец строки всегда добавляется признак конца строки - символ с кодом &O12. Номера строк хранятся отдельно в виде упорядоченного по возрастанию номеров списка, начиная с адреса &O36754 в направлении уменьшения адресов. Для каждой строки программы выделено три слова. В слове со старшим адресом записан номер строки, затем адрес начала "тела" строки и адрес внутри исполняемого модуля (если программа уже транслировалась), иначе в третье слово записан 0. Отметим, что для Бейсик-системы важна информация в слове по адресу &O2024.
Там хранится текущее значение указателя на конец списка строк (адрес последнего занятого слова в списке). До ввода текста программы это &O36756.
Теперь можно рассмотреть непосредственно текст программы.
5 CLEAR 240 10 ? CHR$(140)+CHR$(140); 20 DATA &O12501, &O11502, &O13703, &O352, &O112223, &O77102, &O10337, &O352, &O207 30 DATA &O11505, &O4737, &O100536, &O207 40 DEF FNC$(X%)=MID$(STR$(X%),2%,LEN(STR$(X%))-2%) 50 DEF USR1=&O400 60 DEF USR2=&O422 70 FOR I%=0 ТО 12 80 READ J% 90 POKE &O400+2%*I%,J% 100 NEXT 110 B$=CHR$(159) 120 ? B$+"ГЕНЕРАТОР USR П/П ДЛЯ БЕЙСИКА" 130 ? "РЕЗУЛЬТАТЫ: "+B$+"1-DEC, 2-ОСТ, 3-HEX ?"; 140 T$=INKEY$ 150 IF T$<"1" OR T$> "3" THEN 140 160 ? T$ 170 ? "ЗАГРУЗКА П/П В КОДАХ" 180 A%=USR2(&O42000) 190 CN%=0 200 РОКЕ &O352,&O3052 210 TB%=&O36754 220 JJ%=&O42000+PEEK(&O266) 230 J%=0 240 IF J% MOD 10%<>0% THEN 300 250 A$=""+"@" 260 CN%=CN%+10% 270 POKE TB%,CN% 280 POKE TB%-2%,PEEK(&O352) 290 TB%=TB%-6% 300 AD%=&O42000+2%*J% 310 R%=PEEK(AD%) 320 IF T$="1" TH B$=""+FNC$(R%) 330 IF R%<0% THEN B$=""+"-"+B$ 340 IF T%="2" THEN IF R%<8% AND R%>=0% THEN B$=""+FNC$(R%) ELSE B$=""+"&O"+OCT$(R%) 350 IF T%="3" THEN IF R% < 10% AND R% >=0% THEN B$=""+FNC$(R%) ELSE B$=""+"&H"+HEX$(R%) 360 A$=""+A$+B$ 370 IF(J%+1%) MOD 10%<>0% AND JJ%-AD%>=0% THEN 420 380 A$=""+A$+CHR$(10%) 390 P$=USR1(A$) 400 A$="" 410 IF JJ%-AD%>=0% THEN 430 ELSE 450 420 A$=""+A$+"," 430 J%=J%+1% 440 GOTO 240 450 POKE &O2024,TB%+2% 460 CLS
Строка 10 - начальная установка экрана. Начало служебной строки после этого всегда имеет адрес &O40000. В строках 20 и 30 - 2 функции в кодах. Они определены в строках 60, 70. Функция USR1 копирует содержимое символьной переменной (параметра), помещая копию с адреса, записанного в &O352. После этого &O352 указывает на первый свободный байт за копией. Функция USR2 вызывает программу монитора чтения с магнитофона. Параметр подпрограммы типа INTEGER указывает на начальный адрес загрузки.
После запроса имени загружаемой программы в кодах в строке 180 указан начальный адрес &O42000 (в качестве буфера используем экран). Переменная CN% - счётчик строк генерируемого текста. Он изменяется через 10. В строке 200 для функции USR1 задаётся начальный адрес, куда будут помещаться строки программы (без номеров). С адреса TB% = &O36754 в сторону уменьшения адресов формируется список вида: номер строки, её адрес, затем пропускаем одно слово, номер следующей строки и т.д. В строках 240-440 в цикле считываются коды из буфера (экрана), формируется строка с оператором DATA и текстом кодов через запятую. Размер исходной программы в кодах читается из &O266.
При формировании строки вместо DATA записывается символ '@', а в конце строки добавляется символ с кодом &O12. В зависимости от выбора основания системы счисления (10,8,16) в строках 310-360 получается текст считанного в строке 310 машинного слова. Определённая в 40 функция FNC$ удаляет пробелы в начале и конце строки символов, получаемых функцией STR$. Но при отрицательном аргументе символ '-' будет потерян. Строка 330 добавляет '-' для этого случая. После накопления десяти команд в DATA либо окончания обработки всего буфера в строках 370-410 готовые строки по USR1 записываются, причём &O352 всегда указывает на следующий свободный байт. В строках 290-300 эта информация заносится в список строк Бейсик- программы. По завершении генерации управление передаётся в строку 450 для записи адреса конца списка строк в &O2024.
Потеря исходного текста программы на этапе выполнения может использоваться и с другими целями, например для занесения на место текста данных или программ в кодах. Возможен и промежуточный вариант между сохранением и потерей исходного текста - частичное его изменение. Так для хранения программы в кодах непосредственно в тексте Бейсик-программы можно разместить коды внутри символьной переменной. Для этого первая строка программы должна быть вида
10 AA$ = "12345..."
В этой строке форматируется символьная переменная, которая будет использована для хранения подпрограммы. Длина переменной - не меньше длины программы в кодах. Этой записи с адреса &O3052 будут соответствовать коды: 0, потом текст AA$ = ", содержимое переменной, " и код 12. Содержимое переменной AA$ записано с адреса &O3060 (имя состоит из двух символов и взято для того, чтобы этот адрес был чётным, т.е. границей слова). С этого адреса можно загружать программу в кодах, например, с помощью USR2, описанной выше, или просто операторами POKE. В результате строка 10 будет содержать необходимую информацию, а функцию пользователя определяем с адреса &O3060. Изображение текста строки на экране имеет своеобразный вид. Теперь эту строку можно использовать в Бейсик-программах. Существенными ограничениями для такого способа размещения программы являются:
- программа в кодах должна быть перемещаемой, иначе её надо будет скопировать по нужным адресам;
- программа не должна содержать код &O12, поскольку он будет принят Бейсик-системой за признак конца строки.
- длина программы ограничена размерами символьной переменной.
Таким образом, несмотря на компактность, этот способ может иметь ограниченное применение в основном для коротких программ. Любопытными могут быть побочные эффекты при отображении на экране текста программы с такой строкой. Например, при размещении кодов из строки 30 в символьной переменной соответствующая строка видна на экране в виде двух символов, а если разместить слово &O112414, то на экране по команде LIST вообще будет только графический курсор.
Программа - генератор текстов операторов DATA, описанная в статье, имеет ограничение: длина программы в кодах (исходные данные для генератора) не должна быть более &O212. Опыт работы показал, что при больших размерах начинаются сбои при формировании переменной A$.
Кроме того, привожу краткое описание ещё одной программы, на этот раз в кодах.
Печать строк при выполнении программы на БЕЙСИКе БК 0010.
Команда LIST БК 0010 не реализована при работе в программном режиме. Предлагается программа в кодах для вывода на экран строк Бейсик-программы во время выполнения. Программа оформляется как функция пользователя USR и может загружаться с любого адреса.
Параметр функции - номер вводимой строки (целое число).
013701 002026 024115 001405 020137 002024 003420 024141 000771 014103 105723 001407 012702 133400 153102 011201 012702 020337 104020 010301 012702 005377 104020 000207