Э. Таненбаум - Архитектура компьютера (1127755), страница 206
Текст из файла (страница 206)
Один из способов адаптировать программу к таблицам диспетчеризации— изменить ее таким образом, чтобы из вводимых символов формировалось осмысленное сообщение. К примеру, все символы, кроме восьмеричных цифр, могут составить сообщение об ошибке. Буферизованный и произвольный доступ к файлам зующал буферизованный Листинг В.в. Программа, и произвольный доступ к ф 771пс1и1е ".
Лпузсз1пг.п" Ьптп12 = 612 .БЕСТ ТЕХТ 'пТЬЧТМ . МОЧ ВР,5Р МОЧ 01,11пе1п РО5Н ВЕТСНАВ 1 5Ч5 СМРВ АС Цп' ОС 97 ОЕ 11 5Т058 ОМР 1Ь 1 РОБИ 0 Р05Н 11пе1п Р05Н ОРЕИ 5ч5 СМР АХ,О ОЕ 91 МОЧ ( П 10еп).АХ МОЧ 51,11пп~-2 МОЧ ВХ,О САС Т 11ЬЧТ СМР СХ.О ОСЕ ЗТ 2; МОЧВ АС Цп' ВЕРИЕ 5СА58 ОИЕ 1Ь 1ИС (соилы МОЧ АХ,ВХ реали айлу ! 2 ' 3 ! 5 ' 6 ! В ! 9 ! 10 ! 12 13 15 ! 16 17 18 19 ' 20 ! 21 ! 22 ! 23 ! 24 ! 26 ! 26 ! 27 ! 28 ! 29 ! 30 Программа 10ГВВцйз, представленная в листинге В.8, являет собой пример произвольного файлового ввода-вывода. Она допускает, что файл состоит из произвольного числа символьных строк, каждая из которых потенциально может отличаться по длине от других. Сначала зта программа считывает файл и формирует таблицу, в которой запись и отра7кает положение начала строки и в файле.
Впоследствии можно запросить конкретную символьную строку, отыскать запись для нее в таблице и считать с помощью системных вызовов 1зееИ и геаф Имя файла при стандартном вводе указывается в первой вводимой строке. Программа состоит из нескольких относительно независимых кодовых фрагментов, которые можно адаптировать для иных целей. 810 Приложение В, Программирование на языке ассемблера 8 7: 508 АХ,СХ ХСНВ 5!.И 5ТО5 ХСНВ 51,01 СМР СХ.О ЗИЕ 2Ь ЗМР 1Ь МОХ 5Р.ВР Р05Н 1!пеап Р05Н еггвеаа Р05Н Р81НТЕ 5У5 Р05Н ЕХ1Т Р05Н ЕХ1Т 515 САСС оеапии СМР АХ,О ЗСЕ ВТ МОХ ВХ.!сиг1!и) СМР ВХ.О ЗСЕ 77 СМР ВХ,!соиле) 35 77 5НС ВХ.1 МОХ АХ.1!пп-2!ВХ) МОХ СХ.17пп!ВХ) Р05Н 0 Р05Н О Р05Н АХ Р05Н (Т!1Оеа) Р05Н 05ЕЕК 575 508 СХ,АХ Р05Н СХ Р05Н Ьиг Р05Н ! П10еа) Р05Н ВЕАО ба АОО 5Р.4 Р05Н 1 Р05Н Нй!ТЕ 5У5 АОО 5Р, 14 ЗМР ЗЬ Р05Н асапегг Р05Н РК1НТЕ 575 АОО 5Р,4 ЗМР ЗЬ Р05Н О Р05Н ЕХ!Т 575 Та))ьпс Р05Н Ьпса!а Р05Н Ьпг Р05Н !П 10еа) Р05Н ВЕАО 515 АОО 5Р.В ! 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 Примеры 81 1 ! 90 ! 91 ! 92 ! 93 МОИ СХ.АХ ЯОО ВХ,СХ МОЧ 01.ЬЬТ НЕТ В первых пяти строках кода определяются номера системных вызовов и размер буфера, а указатель базы, как обычно, настраивается на вершину стека.
В строках 6 — 13 из стандартного ввода считывается имя файла, а затем оно сохраняется в символьной строке с меткой 11пе1п. Если имя файла не закрыто новой строкой, выводится сообщение об ошибке, а процесс заканчивается с ненулевым состоянием. Все эти действия отражены в строках 38 — 45. Обратите внимание, что адрес имени файла помещается в стек в строке 39, адрес сообщения об ошибке — в строке 40.
Само сообщение об ошибке (представленное в строке 113) представляет собой запрос на строку Фз в формате РК1ИТГ. Здесь же выполняется вставка содержимого строки 11петп. В случае успешного копирования имени файла его открытие производится в строках 14 — 20. Если вызов ореп завершается с ошибкой, возвращаемое значение становится отрицательным, и для отображения сообщения об ошибке производится переход к метке 9 в строке 28. Если вызов проходит успешно, возвращаемым значением является дескриптор файла, который сохраняется в переменной 1114ез. Этот дескриптор понадобится при последующем выполнении вызовов гезу и Таверн.
9егппи: МОХ 01.1~па!п РОБН 6ЕТСНАИ 1: 575 СМРВ АС Цп' 30 9Ь 3Е 17 5Т058 ЗМР 1Ь 1 НОЕВ Я1Е ' Р05Н спг11п РОБН пиигиа Р05Н 1апе~п РОБН 55СЯИГ 5У5 АОО 5Р, 10 ИЕТ .5ЕСТ .ОАТЯ еггееаа. .А5С12 "Ореп Ха Та11ешп" ппегес; .Я5С12 "ЖЬ" асапегг: .А5С12 "Туре а паеЬегдп" АС!682 .5ЕСТ 855 1~па~0: .5РАСЕ 80 7110еа: .5РАСЕ2 17пп: .БРАСЕ 8192 спг1ап: .5РАСЕ4 Ьпт. .5РАСЕ Ьита'.~~-2 соппг: .5РАСЕ2 ' 94 ! 95 ' 96 ' 97 ! 98 ! 99 ! 100 ! 101 ! 102 ! 103 ! 104 105 106 107 108 ! 109 110 ! 111 ! 112 ! 113 ! 114 ! 115 ! П6 ! 117 ! 118 119 ! 120 ! 121 ! 122 ! 123 ! 124 812 Приложение В. Программирование на языке ассемблера Далее файл считывается блоками по 512 байт, каждый из которых сохраняется в буфере Ьь б На самом деле под буфер выделяется на два байта больше необходимого объема (512 байт), но сделано это лишь для того, чтобы показать способ размещения символической константы и целого числа в одном выражении (строка 123).
Аналогичным образом, в строке 21 в регистр 51 загружается адрес следующего элемента массива 11пп, в результате на дне массива остается машинное слово с нулевым значением. Регистр ВХ получает адрес файла первого непрочитанного символа файла, а значит, в строке 22 перед первым наполнением буфера он инициализируется нулем. За наполнение буфера отвечает подпрограмма Т111Ьпг, размещенная в строках 83-93. После введения в стек аргументов геаб делается запрос нз системный вызов, который помещает число фактически считанных символов в регистр АХ. Это число копируется в СХ, и впоследствии по значению этого регистра можно будет узнать число оставшихся в буфере символов.
Положение в файле первого непрочитанного символа хранится в регистре ВХ, и в строке 91 значение СХ прибавляется к значению ВХ. В строке 92 дно буфера помещается в 01; таким образом, осуществляется подготовка к просмотру буфера на предмет следующего символа новой строки. После возврата из 1111ЬиТ в строке 24 проводится проверка того, были ли какие-либо символы фактически считаны. При отрицательном ответе происходит переход нз цикла чтения с буферизацией ко второй части программы в строке 25. После этого начинается просмотр буфера. Символ Хп загружается в регистр АС в строке 26, а уже в следующей строке это значение просматривается в цикле ВЕР 5СА5В и сравнивается с буферизованными символами.
Выход из цикла может произойти в двух случаях: когда в регистре СХ оказывается нулевое значение или когда просматриваемый символ оказывается символом новой строки. При установленном нулевом флаге последним просмотренным символом оказывается 1п, а положения в файле текущего символа (расположенного после перевода строки) сохраняется в массиве 11пп. Далее происходит приращение счетчика, а положение в файле определяется по значению ВХ и числу символов, оставшихся в СХ (строки 29 — 31 кода).
В строках 32 — 34 выполняется сохранение, но так как для команды 5Т05 целевым адресом является не регистр 51, а регистр 01, перед и после вызова команды 5ТО5 эти регистры меняются местами. В строках 35 — 37 производится проверка оставшихся в буфере данных, после чего в зависимости от значения СХ выполняется переход. По достижении конца файла в нашем распорюкении оказывается полный список положений в файле начальных элементов строк.
Так как массив 11пп начинается с нулевого слова, нам известно, что первая строка начинается с адреса О, следующая строка находится в положении 11пп + 2, и т. д. Размер строки п можно вычислить путем вычитания начального адреса строки и из начального адреса строки и + 1. В оставшейся части программы считывается номер символьной строки, эта строка передается в буфер, после чего она выводится при помощи вызова нг1те. Все необходимые для выполнения этих операций данные имеются в массиве 11пп, где каждая п-ная запись содержит начальное положение строки п в файле. Если номер запрошенной символьной строки равен нулю или выходит за пределы допустимого диапазона, программа завершается путем перехода к метке 7.
Эта часть программы начинается с вызова подпрограммы ВеСпив (строка 46 кода). Она считывает символьную строку из стандартного ввода и сохраняет Вопросы и задания 81 3 в буфере 11пе1п (строки 95 — 103 кода). Далее подготавливается вызов 55САМГ. Принимая во внимание обратный порядок следования аргументов, в стек сначала помещается адрес буфера сог11п, где можно разместить целочисленное значение, затем адрес форматной строки для целочисленного представления пиатяс, и, наконец, адрес буфера 11пе1п, в котором содержится число в десятичном представлении.
Если это возможно, системная подпрограмма 55САМГ помещает двоичное значение в сиг11п. В случае ошибки она возвращает нулевое значение АХ. Проверка возвращаемого значения проводится в строке 48; при ошибке программа генерирует сообщение об ошибке посредством метки 8. Если подпрограмма Ве1пиа возвращает действительное целочисленное значение в сиг11п, оно сначала копируется в ВХ. Далее это значение проверяется на предмет принадлежности к допустимому диапазону (строки 49-53 кода). Если обнаруживается, что номер строки выходит за пределы этого диапазона, происходит выход (ЕХ1Т). Далее необходимо определить конечное положение данной строки в файле и число считываемых файлов; с этой целью значение ВХ умножается на 2 посредством сдвига влево (5НС).
В строке 55 положение текущей символьной строки в файле копируется в регистр АХ. Затем положение следующей символьной строки помещается в регистр СХ, и на его основе вычисляется число байтов в текущей строке. Для произвольного чтения данных из файла применяется вызов 1зееК; он устанавливает смещение к байту, который предполагается прочесть в следующую очередь. Подпрограмма 1зееК выполняется относительно начала файла, и в этой связи в строке 57 в стек помещается нулевой аргумент.
Следующим аргументом является смещение в файле. По определению этот аргумент является длинным (32-разрядным) целым, поэтому сначала в стек вводится нулевое слово, а затем — значение АХ (строки 58 и 59 кода); таким образом формируется 32-разрядное целочисленное значение. Далее в строке 62 в стек отправляются дескриптор файла и код С5ЕЕК, а также выполняется вызов. Возвращаемое значение С5ЕЕК определяет текущее положение в файле, а найти его можно в комбинации регистров ОХ: АХ. Если число умещается в рамки машинного слова (а размер файла не превышает 65 536 байт, по-другому быть и не может), адрес помещается в АХ; следовательно, если вычесть ацачение этого регистра нз СХ (строка 63), мы получим число байтов, которые необходимо прочесть для помещения строки в буфер.
Все остальное очень просто. В строках 64 — 68 строка считывается из файла, а затем при помощи дескриптора 1 файла в строках 70 — 72 она записывается в файл стандартного вывода. Следует иметь в виду, что после частичной очистки стека, которая выполняется в строке 69, значения счетчика и буфера в нем остаются. наконец, в строке 73, указатель стека сбрасывается полностью, после чего осуществляются обратный переход к метке 3 и очередной вызов десяка. Вопросы и задания 1. Каковы значения регистров АН и АС после выполнения команды МОЧ АХ, 702? 2.