Файл: jourdain_spravochnik_programmista.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 04.07.2020

Просмотров: 3100

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

В AL возвращается код символа для однобайтных символов ASCII,

иначе ASCII 0 для расширенных кодов, и тогда номер кода - в AH.


;---проверяем наличие символа в буфере

MOV AH,1 ;номер функции

INT 16H ;проверка наличия символа

JZ NO_CHARACTER ;переход если ZF = 1

;---имеется символ - смотрим какой

CMP AL,0 ;это расширенный код?

JE EXTENDED_CODE ;если да, то на другую ветку


Низкий уровень.


Как и в примере высокого уровня просто сравниваем указатели:


;---сравниваем указатели на голову и хвост

MOV AX,0 ;устанавливаем добавочный сегмент

MOV ES,AX ;на начало памяти

MOV AL,ES:[41AH] ;берем один указатель

MOV AH,ES:[41CH] ;берем другой указатель

CMP AH,AL ;сравниваем их

JNE GET_KEYSTROKE ;если неравны, то к процедуре ввода




3.1.3 Ожидать ввод символа и не выводить его на экран.




Обычно вводимые символы выводятся на экран, чтобы было видно,

что напечатано. Но иногда автоматическое эхо на экране нежела-

тельно. Например, выбор пункта меню по нажатию клавиши. Иногда

надо сначала проверить вводимые символы на ошибку перед выводом

на экран. В частности, любая программа, обрабатывающая расширен-

ные коды, должна избегать автоматического эха, так как при этом

первый байт этих кодов (ASCII 0) будет выводиться на экран,

вставляя пробелы между символами.


Высокий уровень.


Функция Бейсика INKEY$ не дает эхо на терминал. Она возвращает

строку длиной 1 байт для символов ASCII и длиной 2 байта для

расширенных кодов. INKEY$ не ожидает нажатия клавиши, до тех пор,

пока она не помещена в цикл, в котором ожидается нажатие клавиши.

Цикл работает, обращаясь к INKEY$, а затем присваивая возвращае-

мую им строку переменной, в данном случае C$. Если клавиша не

была нажата, то INKEY$ возвращает нулевую строку, т.е. строку

длиной ноль символов, которая обозначается двумя знаками кавычек,

между которыми ничего нет (""). До тех пор пока INKEY$ возвращает

"" - цикл повторяется: 100 C$=INKEY$:IF C$="" THEN 100.

В нижеприведенном примере предполагается, что вводимые символы

выбирают одну из возможностей меню и каждый выбор приводит к

выполнению определенной процедуры программы. Выбор может быть

сделан за счет нажатия клавиш A, B, C ... (давая 1-байтные коды

ASCII) или Alt-A, Alt-B, Alt-C ... (давая 2-байтные расширенные

коды). Для их распознавания используется функция LEN, которая

определяет была ли строка длиной в 1 или 2 байта. В случае кодов

ASCII набор операторов IF...THEN сразу начинает проверять какая

клавиша была нажата, отсылая программу на соответствующую проце-

дуру. В случае 2-байтных кодов управление передается отдельной

процедуре. В этой процедуре функция RIGHT$ убирает левый символ,

который просто равен нулю и только отмечает расширенный код.

Затем используется функция ASC для преобразования строки из сим-

вольной формы в числовую. И, наконец, вторая серия операторов

IF...THEN проверяет получившееся число на соответствующие Alt-A,


Alt-B и т.д.


100 C$ = INKEY$:IF C$="" THEN 100 'ожидаем нажатия клавиши

110 IF LEN(C$)=2 THEN 500 'если расш. код - на 500

120 IF C$="a" OR C$="A" THEN GOSUB 1100 'это A?

130 IF C$="b" OR C$="B" THEN GOSUB 1200 'это B?

140 IF C$="c" OR C$="C" THEN GOSUB 1300 'это C?

.

.

500 C$=RIGHT$(C$,1) 'получаем второй байт расш. кода

510 C=ASC(C$) 'преобразуем его в число

520 IF C=30 THEN GOSUB 2100 'это Alt-A?

530 IF C=48 THEN GOSUB 2200 'Alt-B?

540 IF C=46 THEN GOSUB 2300 'Alt-C?



Отметим, что в строке 120 (и последующих) можно также использо-

вать числовые значения кодов ASCII:


120 IF C=97 OR C=65 THEN GOSUB 1100


Конечно надо сначала преобразовать C$ в форму целого числа, как

это сделано в строке 510. В программах, в которых требуется длин-

ная цепочка таких операторов, можно сэкономить место, изменяя C

таким образом, чтобы она всегда соответствовала либо верхнему,

либо нижнему регистру. Сначала нужно только проверить, что код

ASCII C$ находится в правильном диапазоне. Затем установить,

меньше ли этот код 91, тогда мы имеем дело с символом верхнего

регистра. Если это так, то надо для перевода в нижний регистр

добавить 32. В противном случае, оставить все как есть. После

этого будет достаточно более короткого оператора, такого как IF

C=97 THEN ... Вот код этой процедуры:


500 C=ASC(C$) 'получаем ASCII код символа

510 IF NOT ((C>64 AND C<91)OR(C>96 AND C<123)) THEN ...

520 IF C<91 THEN C=C+32 'приводим все к нижнему регистру

530 IF C=97 THEN ... '... начинаем проверку значений


Средний уровень.


Функции 7 и 8 прерывания 21H ожидают ввода символа, если буфер

клавиатуры пуст, а когда он появляется, то не выводится на экран.

При этом функция 8 определяет Ctrl-Break (и инициирует процедуру

обработки Ctrl-Break[3.2.8]), а функция 7 не реагирует на него. В

обоих случаях символ возвращается в AL. Когда AL содержит ASCII

0, то получен расширенный код. Повторите прерывание и в AL поя-

вится второй байт расширенного кода.


;---получаем введенный символ

MOV AH,7 ;номер функции

INT 21H ;ожидаем ввод символа

CMP AL,0 ;проверка на расширенный код

JE EXTENDED_CODE ;если да, то на особую процедуру

. ;иначе, код символа в AL


;---процедура обработки расширенных кодов

EXTENDED_CODE: INT 21H ;берем второй байт кода

CMP AL,75 ;проверяем на "стрелку-влево"

JNE C_R ;если нет, то след. проверка

JMP CURSOR_LEFT;если да, то на процедуру

C_R: CMP AL,77 ;сравниваем дальше и т.д.


BIOS обеспечивает процедуру, которая предоставляет те же воз-

можности, что и функции MS DOS. Поместите 0 в AH и вызовите пре-

рывание 16H. Функция ожидает ввода символа и возвращает его в AL.

В этом случае и расширенные коды обрабатываются за одно прерыва-

ние. Если в AL содержится 0, то в AH будет содержаться номер

расширенного кода. При это не обрабатывается Ctrl-Break.



;---ждем нажатия клавиши

MOV AH,0 ;номер функции ожидания ввода

INT 16H ;получаем введенный код

CMP AL,0 ;проверка на расширенный код

JE EXTENDED_CODE ;если да, то на спец. процедуру

. ;иначе символ в AL


;---процедура обработки расширенного кода


EXTENDED_CODE: CMP AH,75 ;берем расширенный код из AH

;и т.д.




3.1.4 Ожидание нажатия клавиши и эхо на экран.




При вводе данных и текста, эхо вводимых символов обычно вы-

дается на экран. При этом такие символы как возврат каретки или

забой переводятся в соответствующие перемещения курсора, а не

изображаются как ASCII символы для этих кодов. Выдача эха проис-

ходит в той позиции, где предварительно был установлен курсор и

текст автоматически переносится на следующую строку при достиже-

нии конца текущей. Перенос на следующую строку не требует спе-

циального кода, поскольку символы помещаются в следующую позицию

буферной памяти дисплея, которая представляет из себя одну длин-

ную строку, включающую все 25 строк дисплея.


Высокий уровень.


В Бейсике надо перехватить введенный символ с помощью операто-

ра INKEY$, как показано в [3.1.3]. Затем его надо вывести на

экран, прежде чем получать таким же способом следующий. Для выво-

да можно использовать либо оператор PRINT, либо оператором POKE

прямо поместить символ в видеобуфер, используя отображение в

память, как показано в [4.3.1] (буфер начинается с сегмента памя-

ти &HB000 для монохромного адаптера и с &HB800 - для цветного

адаптера). При использовании PRINT не забудьте поставить в конце

двоеточие, иначе будет автоматически добавлен код возврата карет-

ки. Ниже приведены примеры использования обоих методов. При этом

не проводится никакого анализа на управляющие символы. Вводимые

символы формируются в виде строки данных в переменной KEYSTROKE$.


100 ' метод использующий PRINT

110 LOCATE 10,40 'установка курсора в позицию 10,40

120 KEYSTROKE$="" 'очистка переменной

130 C$=INKEY$:IF C$="" THEN 130 'ожидание ввода символа

140 KEYSTROKE$=KEYSTROKE$ + C$ 'запись его в переменную

150 PRINT C$; 'печать символа

160 GOTO 130 'прием следующего символа


100 ' метод использующий POKE

110 DEF SEG = &HB000 'установка сегмента на видеобуфер

120 POINTER = 1678 'указатель на позицию 10,40

130 KEYSTROKE$="" 'очистка переменной

140 C$=INKEY$:IF C$="" THEN 140 'ожидание ввода символа

150 KEYSTROKE$=KEYSTROKE$ + C$ 'запись его в переменную

160 POKE POINTER,ASC(C$) 'помещение символа в видеобуфер

170 POINTER=POINTER + 2 'сдвиг указателя на следующий символ

180 GOTO 140 'прием следующего символа


Средний уровень.


Функция 1 прерывания 21H ожидает ввода символа, если буфер

клавиатуры пуст, а затем выводит его на экран в текущую позицию

курсора. Обрабатывается Ctrl-Break, поэтому может выполняться

процедура обработки Ctrl-Break [3.2.8]. Введенный символ возвра-

щается в AL. При вводе расширенного кода AL содержит ASCII 0. Для

получения в AL второго байта расширенного кода надо повторить

прерывание.



;---получение введенного символа

MOV AH,1 ;номер функции

INT 21H ;ожидаем нажатия клавиши

CMP AL,0 ;расширенный код?

JE EXTENDED_CODE ;если да, то на спец. процедуру

. ;иначе символ находится в AL


;---процедура обработки расширенных кодов


INT 21H ;получаем в AL номер кода

CMP AL,77 ;проверка на "курсор-вправо"

JNE C_R ;если нет, проверка следующего

JMP CURSOR_RIGHT ;если да, то на процедуру

C_R: CMP AL,75 ;... и т.д.


Эта функция полностью игнорирует клавишу <ESC>. Клавиша табу-

ляции интерпретируется нормально. Клавиша забой сдвигает курсор

на одну позицию влево, но символ, находящийся в этой позиции не

стирается. Клавиша <Enter> вызывает перемещение курсора в первую

позицию текущей строки (нет автоматического перевода строки).




3.1.5 Прием символа без ожидания.




Некоторые программы, работающие в реальном времени не могут

останавливаться и ждать нажатия клавиши; они принимают символ из

буфера клавиатуры только в те моменты, когда это удобно для прог-

раммы. Например, бездействие процессора во время ожидания ввода с

клавиатуры остановило бы все действия на экране в игровой прог-

рамме. Напомним, что легко проверить пуст или нет буфер клавиату-

ры, используя методы, описанные в [3.1.2].


Высокий уровень.


Надо просто использовать INKEY$, не помещая его в цикл:


100 C$=INKEY$ 'получение символа

110 IF C$ <> "" THEN...'если символ введен, то ...

120 ... 'иначе нет символа в буфере


Средний уровень.


Функция 6 прерывания 21H - это единственный способ получить

введенный символ без ожидания. Эта функция не дает эха на экран и

не распознает Ctrl-Break. Перед вызовом прерывания в DL должно

быть помещено 0FFH. В противном случае функция 6 служит совершен-

но противоположной цели - печатает в текущей позиции курсора

символ, находящийся в DL. Флаг нуля устанавливается в 1, если

буфер клавиатуры пуст. Если символ принят, то он помещается в AL.

Код ASCII 0 индицирует расширенный код и для получения номера

кода прерывание должно быть повторено.


MOV AH,6 ;номер функции DOS

MOV DL,0FFH ;запрос ввода с клавиатуры

INT 21H ;получение символа

JZ NO_CHAR ;переход если нет символа

CMP AL,0 ;проверка на расширенный код

JE EXTENDED_CODE ;если да, то на спец. процедуру

... ;иначе в AL код ASCII


EXTENDED_CODE: INT 21H ;получаем номер расширенного кода

... ;номер кода в AL




3.1.6 Получение строки символов.




И Бейсик и MS DOS предоставляют процедуры для приема строки

символов. Они автоматически повторяют процедуры ввода одного

символа, описанные в предыдущих разделах, ожидая ввода возврата

каретки, сигнализирующего окончание строки. Конечно должна быть

отведена память, достаточная для приема всех символов строки, и

должна записываться длина каждой строки для того, чтобы отделить

одну строку от другой. Это делается с помощью дескрипторов стро-

ки, которые состоят из одного или более байтов, содержащих адрес

и/или длину строки. В Бейсике первые два байта дескриптора строки

содержат адрес строки, а сами дескрипторы хранятся в массиве

отдельно от строк. Длина строки хранится в третьем байте 3-байт-


ного дескриптора. С другой стороны, DOS хранит длину строки прямо

в начале самой строки и для программы достаточно знать положение

строки в памяти.


Высокий уровень.


Бейсик может принимать с и без автоматического эха на экране.

Более просто делается ввод с эхом, так как он выполняется

встроенной функцией ввода строки INPUT. INPUT автоматически соби-

рает вводимые символы, выводя их на экран по мере получения. При

нажатии клавиши <Enter> ввод завершается и значение строки прис-

ваивается указанной переменной (посылаемый клавишей <Enter> код

ASCII 13 не добавляется к строке). INPUT допускает возможность

редактирования строки, предоставляемую DOS, поэтому опечатки

могут быть исправлены перед вводом строки. INPUT принимает числа

в ввиде строки и автоматически преобразует их в числовую форму,

если для ввода будет указано имя числовой переменной. Наконец,

INPUT может выдавать на экран строку, запрашивающую пользователя

о требуемой информации. Такая строка может быть длиной до 254

символов. Если ее длина больше, то лишние символы игнорируются.

Основная форма этого оператора INPUT "запрос", имя_переменной.

Полное описание этого опертора см. в руководстве по Бейсику.


110 INPUT "Enter your name: ",NAME$ 'принимает имя как строку

120 INPUT "Enter your age: ",AGE% 'принимает возраст как число


Оператор INPUT неадекватен, когда в вводимой строке могут

встречаться расширенные коды, такие как коды управления курсором

в полноэкранном текстовом редакторе. В этом случае требуется

использовать функцию INKEY$ для приема каждого символа, затем

проверять ввод на расширенные коды, выделять символы управления

курсором, такие как возврат каретки, и только после этого выво-

дить на экран те символы, которые следует выводить. При этом

управляющие символы также включаются по одному в конец строковой

переменной. Текстовые файлы представляют собой набор таких стро-

ковых переменных. В пункте [3.1.8] Вы найдете процедуру ввода с

клавиатуры, в которой функция INKEY$ испоьзуется указанным обра-

зом.



Средний уровень.


Функция 0AH прерывания 21H позволяет вводить строку длиной до

254 символов, выдавая эхо на терминал. Эта процедура продолжает

ввод поступающих символов до тех пор, пока не нажата клавиша

возврат каретки. DS:DX указывает на адрес памяти, куда должна

быть помещена строка. При входе первый байт в этой позиции должен

содержать число байтов, отводимых для этой строки. После того как

строка введена, второй байт даст число реально введенных симво-

лов. Сама строка начинается с третьего байта.

Надо отвести достаточно памяти для строки нужной длины плюс

два байта для дескриптора строки и один добавочный байт для возв-

рата каретки. Когда Вы устанавливаете максимальную длину строки в

первом байте, то не забудьте добавить 1 для возврата каретки. Код

возврата каретки - ASCII 13 - вводится как последний символ стро-