Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 [ 72 ] 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225

а = 1 + (n - 1) mod г. Предусмотрите специальный вход для случая г = 1. Перечислите характеристики новой подпрограммы, взяв за образец (4).

5. [21] Предположим, вмашине MIX нет регистра J. Прид>майте способ связи подпрограмм, не использующий регистр J. Проиллюстрируйте свое изобретение на примере, написав подпрограмму НАХ100, фактически эквивалентную (1). Сформулируйте характеристики этой подпрограммы аналогично тому, как это сделано в (4). (Придерживайтесь принятых для MIX соглашений о самомодифицирующемся коде.)

► 6. [26] Предположим, в MIX нет оператора MOVE. Напищите подпрограмму с именем MOVE, такую, чтобы ее последовательность вызова "JMP MOVE; NOP А, 1(F)" давала такой же эффект, как и "MOVE А, 1(F)", если бы последнее было допустимо. Единственные отличия должны заключаться в воздействии на регистр J и в том, что время выполнения подпрограммы несколько увеличится.

► 7. [20] Почему к самомодифицирующемуся коду сейчас относятся неодобрительно?

1.4.2. Сопрограммы

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

Чтобы понять, что представляет собой сопрограмма, давайте посмотрим на подпрограммы с другой стороны. В предыдущем разделе мы придерживались той точки зрения, что подпрограмма - это некая аппаратная реализация, которая используется для сокращения количества строк в программе. Это, конечно, правильно, но возможна и другая точка зрения. Можно рассматривать главную программу и подпрограмму как группу программ, причем каждый член группы должен выполнять определенную работу. Главная программа в процессе своей работы активизирует подпрограмму, последняя выполняет собственную функцию, а затем активизирует главную программу. Мы можем выйти за узкие рамки своих представлений и вообразить, что с точки зрения подпрограммы, когда она осуществляет выход, именно она вызывает главную программу. Главная программа продолжает выполнять свои обязанности, а затем "выходит" в подпрограмму. Подпрограмма работает, а затем снова вызывает главную программу.

Эта несколько надуманная философия на самом деле полностью отражает ситуацию с сопрограммами, для которых невозможно определить, где главная программа, а где подпрограмма. Предположим, имеются сопрограммы АиВ. Программируя А, можно считать, что В - это подпрограмма; в свою очередь, программируя В, как подпрограмму можно рассматривать уже А. Таки.м образом, в сопрограмме А команда "JMP В" используется для активизации сопрограммы В. В сопрограмме В команда "JMP А" применяется для того, чтобы снова активизировать сопрограмму А. Каждый раз при активизации сопрограмма возобновляет выполнение своей программы с той точки, в которой действие было приостановлено в прошлый раз.

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



в MIX подобная связь между сопрограммами А и В осуществляется путем включения в программу следующих четырех команд.

А 9TJ ВХ В STJ АХ

АХ JMP А1 ВХ JMP В1

Для передачи управления любой из сопрограмм требуется четыре машинных такта. Первоначально АХ и ВХ установлены на переход к начальным точкам каждой сопрограммы, А1 и В1. Предположим, сначала запускается сопрограмма А; она начинает выполняться с команды, которая находится в ячейке А1. Когда сопрограмма А выполняет, скажем, команду "JMP В" из ячейки А2, команда из ячейки В сохраняет в АХ содержимое rJ, скажем, команду "JMP А2+1". Команда йЗ ВХ переносит нас в ячейку В1, и вслед за этим начинает выполняться сопрограмма В. В конце концов она доходит до команды "JMP А", которая находится, скажем, в ячейке В2. Мы сохраняем содержимое rJ в ВХ и переходим к ячейке А2+1, продолжая вьшолнять сопрограмму А до тех пор, пока управление снова не перейдет к В, которая сохраняет содержимое регистра J в АХ, переходит к В2+1 и т. д.

Главное различие между связями "программа-подпрограмма" и "сопрограмма- сопрограмма", как видно из предыдущего примера, состоит в том, что подпро-гра.мма всегда начинается с самого начала (как правило, это фиксированная точка), а главная программа или сопрограмма всегда начинается с места, следующего за той точкой, в которой ее выполнение было прекращено в прошлый раз.

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

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

A2B5E3426FG0ZYW3210PQ89R. (2)



Эта последовательность выбивается на перфокартах; пустые колонки, встречающиеся на перфокартах, игйорируются. Входные данные интерпретируются следующим образом, слева направо: если следующий символ - цифра О, 1, ..., 9 (обозначим ее через п), то он указывает на (п -I- 1) повторение следующего символа независимо от того, является ли он цифрой. Нецифровой символ обозначает сам себя. Выходные данные нашей программы должны представлять собой последовательность, полученную указанным образом и разделенную на группы по три символа. Последовательность заканчивается с появлением точки; в последней группе может быть менее трех сн.мволов. Например, последовательность (2) должна быть преобразована нашей программой в следующие группы символов:

ABB BEE ЕЕЕ Е44 446 66F GZY W22 220 OPQ 999 999 999 R. (3)

Обратите внимание, что 3426F означает не 3427 повторений буквы F, а четыре четверки и три шестерки, за которыми следует буква F. Если входная последовательность имеет вид 1., то на выходе будет просто ., а не .., поскольку первая же точка заканчивает вывод. Наша программа должна выбить выходные данные на перфокартах - по шестнадцать групп на каждой карте, за исключением, возможно, последней

Для вьшолнения такого преобразования напишем две сопрограммы и одну подпрограмму. Подпрограмма с имене.м NEXTCHAR предназначена для нахождения непустых символов (т. е не пробелов) во входных данных и помещения каждого последующего такого символа в регистр А.

01 * ПОДПРОГРАММА ВВОДА СИМВОЛОВ

02 READER EQU 16 Номер устройства чтения перфокарт

03 INPUT ORIG *+16 Место для входных карт

04 NEXTCHAR STJ 9F Вход в подпрограмму

05 JXNZ 3F Первоначально гХ = О

06 1Н J6N 2F Первоначально г1б = О

07 IN INPUT (READER) Читать следующую карту

08 JBUS * (READER) Ожидать заверщения

09 ENN6 16 Пусть г1б указывает на следующее слово.

10 2Н LDX INPUT+16,6 Взять следующее слово из ввода.

11 INC6 1 Продвинуть указатель

12 ЗН ENTA О

13 SLAX 1 Следующий символ -+ гА

14 9Н JANZ * Пропустить пробелы

15 JMP NEXTCHAR+1

Эта подпрограмма имеет следующие характеристики. Последовательность вызова: JMP NEXTCHAR.

Состояние при входе: гХ = количество символов, которые еще будут исполь-

зованы; г16 указывает на следующее слово или г16 = 0. указывая, что нужно читать новую карту.

Состояние при выходе: гА = следующий непустой символ ввода; гХ и г16 настроены для следующего входа в NEXTCHAR.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 [ 72 ] 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225