[an error occurred while processing this directive]
Раздел I 4.1
Создание модуля команд
Рассмотрев все основные модули "Системы расширения возможностей интерпретатора "Бейсик", мы подошли к настоящему разделу, посвященному проблеме создания модуля команд, состоящего из отдельных процедур и функций.
Создание собственных модулей команд по-существу и является основной задачей программиста, разрабатывающего новые драйверы на основе "Системы".
Прежде всего следует уяснить, что любая команда - это всего лишь обычная подпрограмма на машинном языке, выполняющая какие-либо действия, определяющие ее конкретное предназначение.
Для примера рассмотрим подпрограмму LINE, строящую горизонтальную линию на текстовом экране из псевдографических символов "-".
*-------------------* * Подпрограмма LINE * *-------------------* вход: X -длина линии (0-255) COUT3 EQU ¤FC0E подпрограмма среды "Монитор" LINE CPX #0 BEQ END LINE1 JSR COUT3 DEX BNE LINE1 END RTS
Подпрограмма LINE является простейшей подпрограммой на языке Ассемблера. Она строит горизонтальную линию из символов "-", количество которых должно быть установлено в регистре X, пользуясь подпрограммой системы "Монитор" COUT3 (¤FC0E).
Ничего не стоит превратить эту подпрограмму в процедуру, доступную интурпретатору "Системы".
Для организации команды требуется знать формат "Поля команды" (особого заголовка, стоящего перед исполняемой подпрограммой команды и служащего для ее идентификации модулем интерпретации команд INTPRALL.ASM и связи команд в модули).
Общий формат поля команды:
DFB ATRIBUT DW NEXTCOM DFB MIN,MAX ASC "NAME comentary" DFB 0
-1-й байт - атрибут команды в битах (ATRIBUT)
Номер бита:!Значение: -----------+------------------------------------------------ 7 !"1"-функция,"0"-процедура 6 !"1"-нестандартная интерпретация параметров, !"0"-обычная 5 !"1"-команда запрещена в режиме диалога, !"0"-разрешена 4 !"1"-результат функции-строка,"0"-число !(значим только для функций). 3-0 !резерв (в интерпретаторе INTPRALL.ASM не исполь- !зуются)
-2-3-й байты - ссылка на следующую команду (фактически должны содержать адрес начала поля следующей команды). Если данная команда последняя в списке, то ссылки нет (нулевые байты 2-3).
-4-5-й байты - соответственно минимальное и максимальное количество входных параметров (MIN,MAX). Минимальное их кол-во, естественно, 0, максимальное 20 (для INTPRET.ASM - 32).
-NAME (имя команды). Имя команды должно быть записано заглавными буквами и не содержать пробелов. Длина имени не более 15 символов.
-comentary (коментарий). После имени команды может следовать коментарий - произвольный текст длиной до 230 символов, отделенный от имени команды NAME пробелом.
Предпочтительно указание в коментарии формата параметров команды и их типов.
-0 (нулевой байт) - признак конца Поля команды. (если коментария нет, то он следует сразу за именем команды).
*Примечание:
В более ранней версии интерпретатора команд INTPRET.ASM (в отличие от описываемого INTPRALL.ASM) формат поля команды несколько отличался. Поля команд под INTPRET.ASM не содержали байта ATRIBUT (все команды считались процедурами).
Итак, теперь снабдим нашу подпрограмму LINE необходимым заголовком команды:
*-------------------* * Процедура "LINE" * *-------------------* LINE DFB :00000000 DW NEXTCOM DFB 0,1 ASC "LINE X" DFB 0
Атрибут команды LINE указывает, что это процедура (7-й бит "0") с обычной интерпретацией параметров (6-й бит "0") и разрешена в диалоге (5-й бит "0").
Минимальное кол-во параметров - 0, максимальное - 1 (числовой, т.к. интурпретация обычная).
Теперь осталось связать нашу процедуру с ее полем и передать ей параметры из буфера параметров (их накапливает INTPRALL.ASM в BUF1 и BUF11; см. Раздел I 3.1.3)
*-------------------* * Процедура "LINE" * *-------------------* LINE DFB :00000000 DW NEXTCOM DFB 0,1 ASC "LINE X" DFB 0 LIST1 LDX BUF1 BEQ END LIST2 JSR COUT3 DEX BNE LIST2 END RTS
У подпрограммы LINE всего лишь один параметр, следовательно он хранится в BUF1 (младший байт).
Однако параметр может быть не задан вовсе (минимальное кол-во параметров 0), следовательно, требуется это проверить:
*-------------------* * Процедура "LINE" * *-------------------* LINE DFB :00000000 DW NEXTCOM DFB 0,1 ASC "LINE X" DFB 0 LINE1 LDX XBUF1 BNE LINE2 LDX #¤FF BNE LINE3 LINE2 LDX BUF1 BEQ END LINE3 JSR COUT3 DEX BNE LINE3 END RTS
Теперь процедура LINE строит линию из 255 символов, если параметров не задано (кол-во их хранится в XBUF1) или строит линию из того кол-ва знаков "-", которое передается параметрам X (берется из BUF1).
Однако следует вспомнить, что ширина экрана АЦР32 - 32 символа, а АЦР64 - 64 символа. Кроме того, необходимо проверить, чтобы старший байт параметра X был равен 0.
*-------------------* * Процедура "LINE" * *-------------------* LINE DFB :00000000 DW NEXTCOM DFB 0,1 ASC "LINE X" DFB 0 LINE1 JSR CH.PARM LDX XBUF1 BNE LINE3 BIT COLOR BMI LINE2 LDA LINE32 BNE LINE4 LINE2 LDX LINE64 BNE LINE4 LINE3 LDX BUF1 LINE4 JSR CHLINE BCS LINERR LINE5 JSR COUT3 DEX BNE LINE5 RTS CHLINE BIT COLOR BMI CHLINE1 CPX LINE32 RTS CHLINE1 CPX LINE64 RTS LINE32 DFB 32 LINE64 DFB 64 LINERR JMP BASERR ; выдать "Ошибочное значение"
Теперь мы получили законченную, универсальную процедуру. В первой строке мы обращаемся к подпрограмме CH.PARM модуля ALLSUBRS.ASM (она проверяет, чтобы параметры имели значение не более 255; см.Раздел I 3.1.4). Еще мы дополнили нашу процедуру проверкой режима (он проверяется по состоянию COLOR; в АЦР64 COLOR ≥ ¤80) относительно которого выбирается максимальная длина линии (LINE32 или LINE64) и осуществляется проверка допустимого максимального значения параметра.
Как видите, создание процедуры под "Систему" не такое уж сложное дело. Автор постепенно написал всю процедуру вместе с данным описанием всего за 15 минут.
Конечно, эта процедура была написана только ради примера и не претендует на самое красивое решение. Более сложные команды должны создаваться после тщательного обдумывания и желательно, так, чтобы они максимально охватывали сферу своего применения. Их следует стараться писать максимально рационально, так как планируется многократное их использование в разных драйверах.
Теперь следует сказать несколько слов об особенностях создания функций.
Для примера рассмотрим функцию DEFSLOT библиотеки фирмы Friends' Software:
*-------------------* * Функция "DEFSLOT" * *-------------------* ; функция определяет устройство, установленное ; в разъем S (тип контроллера) DEFSLOT DFB :10000000 DW NEXTCOM DFB 1,1 ASC "DEFSLOT (S)" DFB 0 JSR CH.PARH LDA BUF1 параметр S BEQ DSERR не может быть равен 0 CMP #1 BEQ DSERR в 1й слоте генплата CMP #7 не может быть больше 6 BCS DSERR (у АГАТа 6 слот!) ORA #¤C0 STA RNDN занести в RNDN LDA #¤0C STA RNDL занести в RNDL LDY #0 LDA (RNDL),Y считать байт, по адресу ¤CS0C TAY поместить в регистр Y LDA #0 в аккумуляторе 0 RTS DSERR JMP BASERR46 выдать ошибку "Ошибочное значение"
Функция DEFSLOT (7-й бит "1") возвращает константу-число (4-й бит "0"), определяющее тип контроллера, установленный в разъем с номером S (обязательный параметр).
DEFSLOT может возвращать следующие константы:
¤10 - ячейка памяти ¤4B - ячейка принтера ¤BD - контроллер дисковода FD55 (ЕС 5323.01) ¤F0 - контроллер дисковода ЕС 5088 ¤EA - контроллер "сети".
Результат своей работы функция возвращает в регистрах:
X,Y,A. В данном случае возвращаемое число не выходит из диапазона 0-FF. Поэтому A=0, Y - содержит константу. Регистр X - значим только для функций, результат которых - строка.
В общем случае функция должна вернуть:
регистр X - длина текста (для числовых функций не используется)
A,Y - адрес хранения текста (для строк) A - старший байт |Возвращаемый текст должен быть в Y - младший |обратном коде (EOR #¤80) - число (для функций с числовым параметром): A - старший байт Y - младший.
В создании команд, требующих строковые параметры имеется еще одна тонкость. Дело в том, что стандартные интерпретаторы INTPRET.ASM или INTPRALL.ASM могут передавать командам только числовые параметры. Если Вам требуется передать хотя бы один строковый параметр команде, Вам придется воспользоваться так называемой "нестандартной интерпретацией параметров", которая разрешается для команды, если бит 6 ее атрибута установлен в "1".
Рассмотрим строковую функцию ZSTR¤, которая превращает переданную ей строку в строку, состоящую из заглавных символов:
*---------------* * Функция ZSTR¤ * *---------------* DFB :11110000 DW NEXTCOM DFB 0,0 ASC "ZSTR¤ (A¤)" DFB 0 ZSTR1 SEC JSR INPAR TXA PHA LDY #0 ZSTR2 LDA (¤5E),Y ORA #¤80 STA ¤200,Y INY DEX BNE ZSTR2 JSR GETC1 CMP #¤29 закрывающая скобка BNE ZSTRERR JSR GETCHR BEQ ZSTR3 конец строки CMP #¤3A или двоеточие BNE ZSTRERR ZSTR3 PLA TAX LDA #¤02 LDY #0 RTS ZSTRERR JMP BASERR12 ; Универсальная подпрограмма INPAR ; "Считать параметры" ; by Serkov S.V. 13.08.95 ;-------------------------------------- ; вход: а) C=0 требуется число ; б) C=1 требуется строка ; выход а) C=0 ; Y,A - число (младший/старший) ; б) C=1 ; Y,A - адрес ; X - длина строки INPAR PHP JSR ¤DD62 PLP BCC NPUR SPUR JSR ¤E5BC TAX LDA ¤5F LDY ¤5E BIT ¤11 BPL PARERR SEC RTS NPUR BIT ¤11 BMI PARERR JSR ¤E712 CLC LDA ¤51 LDY ¤50 RTS PARERR JMP BASERR (синтаксическая ошибка)
Интерпретатор INTPRALL.ASM не берет никаких параметров для команд с нестандартной интерпретацией и, пропустив последнюю кавычку имени команды, сразу переходит к ее исполнению (для процедур). Для фукций еще пропускается открывающая скобка "(". В нашем примере функция ZSTR¤(A¤) самостоятельно интерпретирует свой аргумент A¤ через универсальную подпрограмму INPAR (INPAR может работать как с числовыми, так и со строковыми параметрами). По окончанию работы функции (делает все символы заглавными, ORA #¤80, в регистре X возвращается ее длина, а в Y,A - адрес новой строки. Интерпретатор сам присвоит результат заданной переменной (если пользователь запишет:)
&B¤=ZSTR¤"(A¤)
Функция ZSTR¤ при интерпретации аргумента также проверяет налачие после аргумента A¤ закрывающей скобки (во внутреннем представлении Бейсика константа ¤29) и следующего за ней признака конца строки (0) или двоеточия (¤3A) отделяющего функцию от следующей команды Бейсика.
Для их интерпретации ZSTR¤ использует обращение к системным подпрограммам GETC1 и GETCHR.
Их значение следующее:
GETC1 - взять символ, на который указывает указатель текущего символа интерпретатора Бейсик (¤B8-¤B9).
GETCHR - пропустить текущий символ и взять следующий, обратившись к GETC1.
Для интерпретации могут оказаться полезными следующие знаки во внутреннем представлении Бейсика:
¤22 - кавычки ¤28 - открывающая скобка ¤29 - закрывающая скобка ¤3A - двоеточие ¤D0 - знак равенства ¤2C - запятая.
Теперь вернемся к подпрограмме INPAR. INPAR пользуется универсальной подпрограммой Бейсика READPAR (¤DD62).
Эта подпрограмма способна считывать любые параметры, представленные в переменными и выражениями в формате языка Бейсик, начиная от первого символа параметра, до первого символа к нему не относящегося. При этом, если выражение записано неверно, Бейсик может диагностировать различные типы ошибок.
Вообще подпрограмму INPAR Вы можете разобрать самостоятельно, к тому же, она снабжена необходимым кол-вом комментариев.
Автор рекомендует использовать указанную подпрограмму в своих модулях команд. (Подпрограмма создавалась для нового интерпретатора команд INTBASIC.ASM, выход которого планируется к 01.10.95).
Теперь, после стольких примеров, я думаю, что Вас не затруднит создание любой команды. Стоит сказать еще несколько слов об организации ошибок в командах и их обработке.
Для организации ошибок формата интерпретатора "Бейсик" (коды ошибок и их диагностика см. Раздел III.6 ) следует загрузить код соответствующей ошибки в регистр X и произвести переход на точку BASERR, определенную в модуле INTPRALL.ASM.
Например:
LDX #130 выдать ошибку "Строка длинна" JMP BASERR
для ошибок, обработка которых осуществляется модулем INTPRALL.ASM можно сразу делать JMP на их точки входа
Для диагностики ошибок ДОС (коды см. Раздел III.6) и ошибок с собственными диагностиками следует пользоваться услугами модуля универсальной обработки ошибок ERRORMOD.ASM (см. Раздел I 3.2.2).
.ст Раздел I:4.2
[an error occurred while processing this directive]