Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Информатика

.pdf
Скачиваний:
94
Добавлен:
11.05.2015
Размер:
1.73 Mб
Скачать

231

int 21h” (функция 2) – вывод символа. Перед применением вызова программа помещает в регистр DL код выводимого символа. В программе данный системный вызов используется для перевода строки, что исключает наложение на экране строк, принадлежащих родительской и дочерней программам.

int 21h” (функция 0Ah) – ввод с клавиатуры символьной строки. В качестве последнего символа строки вводится символ 0Dh (возврат каретки). (Этот символ помещается в водимую строку драйвером клавиатуры при нажатии клавиши <Enter>.) Перед применением вызова программа помещает в регистры DS и DX соответственно адрес-сегмент и адрес-смещение для младшего байта буфера, в который должна быть введена строка. Данный буфер имеет три поля:

1)младший байт содержит максимальное число вводимых символов. Запись этого числа выполняет сама программа;

2)второй байт содержит число фактически введенных символов. Запись в этот байт выполняет DOS;

3)остальные байты буфера содержат введенную строку, заканчивающуюся кодом 0Dh.

Первый исполнительный оператор jmp «перепрыгивает» через данные программы на ее фрагмент, выполняющий возврат в систему «лишней» памяти. Вспомним, что для com-программы DOS выделяет всю ОП, оставшуюся после загрузки самой ОС. Так как наша программа использует лишь небольшую часть этой памяти, то она желает сообщить об этом системе. Простейший вариант этого – оставить за программой те 64 К, в которые первоначально загружается com-программа. Но наша программа делает больше: она создает свой новый стек, разместив его сразу за своим кодом, а от всей остальной памяти отказывается.

Само освобождение памяти выполняет ранее рассмотренный системный вызов “int 21h” (функция 4Ah). При этом количество запрашиваемых параграфов памяти определяется в результате целочисленного деления длины

232

программы (константа Lprog), увеличенной на 15 (0Fh), на длину одного параграфа – 16.

После того, как память освобождена, программа выводит на экран просьбу ввести имя загружаемого файла. Если искомый файл находится в текущем каталоге, то достаточно ввести имя файла и расширение имени (com или exe). Иначе – следует ввести имя-путь файла. Если файл находится на другом логическом диске, то имя-путь должно предваряться именем этого диска,

например: c:\distant\pr1.com .

Введенное имя файла передается на вход системного вызова “int 21h” (функция 4Bh, подфункция 0). Этому предшествует небольшая корректировка имени: в последний байт (с кодом 0Dh) записывается число 0.

Интересно отметить, что данная программа может запускать сама себя. В результате создается новый экземпляр программы, обладающий всеми ее свойствами. Н а б е р и т е текст программы и проверьте практически это и другие свойства данного простейшего интерпретатора команд.

18.3.Многопрограммный редактор

18.3.1.Структура многопрограммного редактора

Переделаем разработанный в разделе 16 редактор так, чтобы он состоял не из одной, а из нескольких программ. В результате должна получиться программная система, структура которой приведена на рис.64. На этом рисунке программы изображены в виде параллелограммов. Подобное изображение программ используется для того, чтобы подчеркнуть возможную независимость (параллельность) выполнения программ. При этом выполнение каждой программы представляет собой отдельный программный процесс, изображаемый в виде параллелограмма. Несмотря на то, что подобная параллельность реализуется лишь в мультипрограммных ОС, к которым DOS

233

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

Dispatcher

 

 

 

 

 

 

 

 

 

 

Init_sector

Write_sect

 

N_sector

. . .

Рис. 64. Структура многопрограммного редактора

Небольшие прямоугольники внутри процессов на рис.64 обозначают точки входа в процесс. Точка входа – место в алгоритме процесса (программы), находясь в котором процесс “простаивает”, ожидая инициирующего (запускающего) воздействия со стороны других процессов.

Как видно из рис.64, главной программой многопрограммного редактора является Dispatcher. Но в отличие от однопрограммного варианта, она инициирует не свои внутренние процедуры, а отдельные программы, каждая из которых инициируется при нажатии пользователем своей функциональной клавиши. Прежде чем инициировать соответствующую программу, диспетчер должен загрузить в ОП загрузочный модуль программы. И загрузка и инициирование программы выполняются диспетчером с помощью рассмотренного ранее системного вызова EXEC.

Стрелки на рис.64 обозначают управляющие (инициирующие) воздействия. Такое воздействие поступает на точку входа инициируемой программы. Одновременно иницирующая программа сама оказывается в одной из точек своих входов. Например, диспетчер после запуска любой своей дочерней программы сразу же оказывается в той своей точке входа, которой

234

соответствует оператор исходной программы, расположенный сразу же после вызова EXEC.

18.3.2. Программы

Применение вызова EXEC для запуска различных программ редактора отличается лишь именами com-файлов, содержащих загрузочные модули этих программ. Для того чтобы осуществлять поиск этих имен, в программе диспетчера удобно использовать измененную таблицу переходов, содержащую вместо имен процедур имена дочерних файлов. При этом в соответствии с требованиями вызова EXEC каждое имя файла должно заканчиваться нулевым байтом.

Одновременно с запуском дочерней программы программа Dispatcher передает ей на вход данные, предназначенные для обработки в запускаемой программе. В качестве таких данных используется совокупность глобальных переменных, примером которых является Sector. Несмотря на то, что эти глобальные переменные использовались нами и ранее для информационной взаимосвязи между модулями программы, механизм их передачи теперь будет другой. Дело в том, что в отличие от процедур, входящих в состав одной программы, программы не имеют общих областей (разделов) памяти. Поэтому передаваемые данные включаются или в состав «наследуемых» данных – в состав PSP и блока окружения, или передающая программа передает с помощью PSP адрес области ОП, которая содержит входные данные.

Второй из этих подходов и будет использоваться нами в многопрограммном редакторе с тем отличием, что каждая из взаимодействующих программ имеет дело со своим набором глобальных переменных. Сразу же после своего инициирования дочерняя программа копирует в свою собственную память набор глобальных переменных, принадлежащий программе Dispatcher. И, наоборот, перед своим завершением дочерняя программа выполняет обратное копирование глобальных переменных из своей области памяти в область

235

памяти диспетчера. Такое копирование глобальных переменных приводит к повышенным затратам памяти (каждая программа имеет свой экземпляр глобальных переменных), но повышает надежность всей программной системы, так как сбой в работе одной из программ не приведет к нарушению правильности главной совокупности глобальных переменных.

Для выполнения самой операции копирования удобно использовать рассмотренный нами ранее оператор movsb с префиксом rep. Напомним, что перед применением данного оператора следует сбросить флаг DF (оператором cld) и записать в регистр CX число переписываемых байтов. Что касается начальных адресов области-источника и области-приемника, то каждый из них задается не одним, а двумя регистрами:

(DS:SI) – адрес области-источника;

(ES:DI) – адрес области-приемника.

Вспомним, что ранее для передачи адресов нами использовались лишь регистры SI и DI. Такое отличие от прежнего применения оператора movsb обусловлено тем, что области памяти, участвующие в копировании, находятся теперь не в одном, а в различных сегментах памяти. Поэтому регистры DS и ES используются для передачи адресов этих сегментов.

Естественно, что при инициировании дочерней программы диспетчер должен передать ей начальный адрес своей области, содержащей глобальные переменные, в виде пары двухбайтовых чисел – (DS, SI). Для передачи этих двух чисел может быть использовано, например, поле PSP, предназначенное для устаревших блоков управления файлами и расположенное по относительному адресу 5ch. Допустим, что первым в это поле записывается требуемое содержимое DS, а затем SI.

Ниже приводится сокращенная запись модифицированной программы Dispatcher, предназначенной для многопрограммного редактора:

org 100h

236

;

;Координирует выполнение модулей редактора

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Dispatcher:

cr

equ

0dh

 

lf

equ

0ah

 

 

jmp

Begin

; Переход через данные

;Глобальные переменные

Sector

times

256 db 0

; Буфер для редактируемого сектора

Address

dw

0

; Адрес-смещение сектора

N

db

0

; Номер сектора в сегменте памяти

Lognum

db

0

; Логический номер открытого файла

Lf

dw

0

; Длина файла в секторах

Lsec

dw

0

; Фактическая длина сектора

Prf

db

0

; Признак редактирования файла

;Другие данные программы

. . . . . . . .

 

Blocpar

times

6

db

0

; Первые 6 байт блока параметров

Param

times

8

db

0

; Последние 8 байт блока параметров

; Освобождение лишней памяти

Begin:

. . . . . . . .

;Вопрос о желании редактировать файл

. . . . . . . .

;Запрос имени файла

. . . . . . . .

;Открытие файла

. . . . . . . .

;Определение длины файла

237

. . . . . . . .

;Сообщение о длине файла

. . . . . . . .

;Прежний диспетчер

. . . . . . . .

int 20h

;

;Интерпретатор команд

;- - - - - - - - - - - - - - - - -

;Входы: DL – скан-код, соответствующий команде

;Чтение: Table – таблица переходов

;

 

 

 

 

Command:

 

 

 

 

 

push

ax

 

 

 

push

bx

 

 

 

mov

bx,Table

; ВХÅадрес таблицы

.M1:

cmp

byte[bx], 0ffh

; Конец таблицы?

 

je

.Exit

; Да, кода нет в таблице

 

cmp

dl,[bx]

; Это вход в таблицу?

 

je

.Dispatch

; Да, выполнить команду

 

add

bx,18

; Нет, переход к

 

clc

 

;

следующему

 

jmp

.M2

;

элементу таблицы

;Обработчик команды выполняет запуск соответствующей

;

дочерней программы

 

 

.Dispatch:

 

 

 

 

 

inc

bx

 

; В BX адрес имени файла

 

mov

dx, bx

 

; DX Å BX

 

mov

[Param], ds

; Адрес-сегмент передаваемых данных

 

mov

[Param+2], Sector

; Адрес-смещение данных

238

 

 

 

 

mov

bx, Blocpar

 

 

mov

ax, 4b00h

 

 

int

21h

; Запуск программы

;

 

 

 

.Exit:

stc

 

; CF Å 1

.M2:

jnc

.M1

; Повторение для нового элемента таблицы

 

pop

bx

 

 

pop

ax

 

 

ret

 

 

;Таблица переходов содержит скан-коды управляющих клавиш и

;имена программ, выполняющих соответствующие команды

Table

db

3bh

; <F1>

 

db

‘Init_sector.com’, 0, 0

 

db

3ch

; <F2>

 

db

‘Write_sector.com’, 0

 

db

3dh

; <F3>

 

db

‘Next_sector.com’, 0, 0

 

db

3eh

; <F4>

 

db

‘Edit_sector.com’, 0, 0

 

db

3fh

; <F5>

 

db

‘Prev_sector.com’, 0, 0

 

db

40h

; <F6>

 

db

‘N_sector.com’, 0, 0, 0, 0, 0

 

db

0ffh

; Конец таблицы

 

%include

‘Video_io.asm’

 

%include

‘Cursor_io.asm’

 

%include

‘Kbd_io.asm’

В приведенной выше программе глобальные переменные программы собраны вместе в единый блок, начинающийся с метки Sector. Напомним, что

239

глобальные переменные образуют ту информацию, которой модули программной системы обмениваются между собой. Начальные адрес-сегмент и адрес-смещение этого блока записываются в поле Param, содержимое которого копируется в PSP дочерней программы во время выполнения системного вызова EXEC.

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

Video_io.asm, Cursor.asm и Kbd_io.asm. Эти файлы подсоединялись к программе и раньше, но через файл Disp_sec.asm, который теперь в главной программе не нужен.

Дочерние программы удобнее реализовать в виде com-программ. Это удобство заключается в том, что все сегментные регистры содержат одно и то же, указывая на начало сегмента памяти, выделенного программе. Что касается исходных текстов дочерних программ, то они мало отличаются от текстов соответствующих процедур. Эти отличия находятся лишь в начале и в конце программ. Причем во всех дочерних программах отличия одинаковы:

;Программа выполняет одну из команд пользователя

;-------------------------------------------------------------------

 

absolute

5ch

; Следующий байт имеет адрес-смещение 5ch

Param

resb

4

 

; Поле входных параметров

;

 

 

 

 

 

segment

code

; Виртуальный сегмент кода

 

org

100h

 

 

 

jmp

Begin

 

; Переход через данные

;Глобальные переменные (экземпляр программы)

Sector

times 256 db 0

; Буфер для редактируемого сектора

240

Address

dw

0

N

db

0

Lognum

db

0

Lf

dw

0

Lsec

dw

0

Prf

db

0

;Другие данные программы

;Адрес-смещение сектора

;Номер сектора в сегменте памяти

;Логический номер открытого файла

;Длина файла в секторах

;Фактическая длина сектора

;Признак редактирования файла

. . . . . . . .

Begin:

mov cx, 265 cld

mov ds, [Param] mov si, [Param+2] mov di, Sector

rep movsb

. . . . . . . .

mov

cx, 265

cld

 

mov

si, Sector

mov

es, [Param]

mov

di, [Param+2]

rep movsb

 

;Подсоединение файлов операторами %include

. . . . . . . .

18.4. Лабораторная работа 16

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