Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Расширенные директивы описания процедур
Возможен следующий синтаксис описания процедуры:
Приведем синтаксис определения передаваемых процедуре аргументов: arg АРГУМЕНТ [, АРГУМЕНТ ]... [ =ИМЯ ] При определении локальных переменных процедуры используется следующий синтаксис: local АРГУМЕНТ [, АРГУМЕНТ ]... [ =ИМЯ ] Отдельные аргументы имеют следующий синтаксис: ИМЯ_АРГУМЕНТА [[ СЧЕТЧИК_1 ]] [: ТИП [: СЧЕТЧИК_2 ]] Здесь ТИП – это тип данных аргумента – byte, word, dword и т.п. СЧЕТЧИК_2 задает, сколько элементов данного типа определяет аргумент. Например, в определении аргумента: arg TMP: dword: 4 определяется аргумент с именем TMP, состоящий из 4 двойных слов. По умолчанию СЧЕТЧИК_2 имеет значение 1 (кроме аргументов типа byte. Так как вы не можете занести в стек байтовое значение, для аргументов типа byte значение счетчика по умолчанию равно 2, что обеспечивает для них в стеке размер в слово. Например: arg REALBYTE: byte: 1 СЧЕТЧИК_1 представляет собой число элементов массива. Если поле СЧЕТЧИК_1 не задано, то по умолчанию оно равно 1. Если список аргументов завершается символом равенства (=) и идентификатором, то ассемблер будет приравнивать этот идентификатор к общему размеру блока аргументов (в байтах). Если вы не используете автоматическое использование соглашений языков высокого уровня в ассемблере, то можете использовать данное значение в конце процедуры в качестве аргумента инструкции ret. Аргументы и переменные определяются в процедуре как операнды в памяти относительно BP. Передаваемые аргументы, определенные с помощью директивы arg, имеют положительное смещение относительно BP. Локальные переменные, определенные с помощью директивы local, имеют отрицательное смещение от BP. Например: FUNC1 proc NEAR Здесь A определяется, как [BP+4], B – [BP+6], C – [BP+14], а ArgSize – 20. X – [BP-2], Y – [BP-6], а LocSize – 8. Область действия имен Если для аргументов и локальных переменных, а также меток операторов в подпрограмме, не заданы имена с предшествующим префиксом локального идентификатора, все аргументы, заданные в заголовке процедуры, определены ли они с помощью директивы arg или local и метки имеют глобальную область действия. Идентификаторы с локальной областью действия разрешает директива locals (не путать с директивой local). Например: locals __ В этом примере директива locals __ определяет двойной символ подчеркивания как префикс локальных имен. Это означает, что все имена, начинающиеся с данной пары символов, будут считаться локальными в пределах подпрограммы. Итоги Соединив все, что было сказано в предыдущих параграфах, можно предложить следующий шаблон подпрограммы:
... push BP; + BP - указатель ПРИМЕР ВЫПОЛНЕНИЯ РАБОТЫ Разработать подпрограмму, которая удаляет, начиная с заданной позиции строки, указанное число символов. Разработать программу, которая вводит с клавиатуры строку, вводит позицию и длину удаляемой части строки и удаляет эту часть. Текст программы:
model small stack 100h dataseg MESS1 db 0dh, 0ah, 0dh, 0ah, " Введите строку: ", 0dh, 0ah, " $" MESS2 db 0dh, 0ah, " Введите позицию: $" MESS3 db 0dh, 0ah, " Введите число удаляемых символов: $" MESS4 db 0dh, 0ah, 0dh, 0ah, " Строка после удаления: ", 0dh, 0ah, " $" S_BUFLEN db 80; Макс. длина строки S_FACTLEN db? ; Длина фактически введенной строки S_INPBUF db 80 dup (? ); Введенная строка N_BUFLEN db 3; Макс. длина числа при вводе N_FACTLEN db? ; Фактическая длина N_INPBUF db 3 dup (? ); Строка представления числа POSDEL dw? ; Позиция, начиная с которой удаляем LENDEL dw? ; Сколько символов удалить
codeseg startupcode ; Ввод строки MLOOP: lea DX, MESS1 mov AH, 09h int 21h; Приглашение к вводу строки lea DX, S_BUFLEN mov AH, 0Ah int 21h; Ввод строки mov BL, S_FACTLEN cmp BL, 0; Строка пустая? jne LLL0; Нет - продолжать jmp QUIT; Закончить работу LLL0: mov BH, 0; Дополнить длину до слова add BX, 2; и получить адрес позиции add BX, DX; сразу после конца строки mov byte ptr[BX], 0; Записать признак конца строки ; Ввод позиции удаления LLL1: lea DX, MESS2; Приглашение mov AH, 09h; к вводу
int 21h; позиции удаления lea DX, N_BUFLEN mov AH, 0Ah int 21h; Ввод строки числа lea BX, N_INPBUF; Адрес строки представления числа mov CL, N_FACTLEN; Длина этой строки call VAL; Перевод в целое число jc LLL1; Ошибка? - повторить ввод cmp AL, 0; Ноль? je LLL1; Повторить ввод cmp AL, S_FACTLEN; Превышает длину строки? jg LLL1; Повторить ввод mov POSDEL, AX; Запомнить позицию удаления ; Ввод длины удаляемой части LLL2: lea DX, MESS3; Приглашение mov AH, 09h; к вводу int 21h; числа удаляемых lea DX, N_BUFLEN mov AH, 0Ah int 21h; Ввод строки числа удаляемых lea BX, N_INPBUF; Адрес строки представления числа mov CL, N_FACTLEN; Длина этой строки call VAL; Перевод в целое число jc LLL2; Ошибка? - повторить ввод mov LENDEL, AX; Запомнить число удаляемых add AX, POSDEL; Подсчитать, не выходит ли dec AX; удаляемая часть cmp AL, S_FACTLEN; за конец строки? jg LLL2; Если да - повторить ввод ; Занесение параметров в стек и вызов п/п удаления lea AX, S_INPBUF push AX; 1-й параметр - адрес строки push POSDEL; 2-й параметр - позиция удаления push LENDEL; 3-й параметр - число удаляемых call DELSUBS; Вызов подпрограммы ; Вывод результата lea DX, MESS4 mov AH, 09h int 21h; Заголовок вывода lea BX, S_INPBUF mov CX, 80 LLL3: cmp byte ptr [BX], 0; Цикл поиска конца строки и выход je LLL4; - когда конец строки найден inc BX; Сдвиг по строке loop LLL3 LLL4: mov byte ptr [BX], '$'; Заменить признак конца строки lea DX, S_INPBUF mov AH, 09h int 21h; Вывод результата
jmp MLOOP; На повторение работы
QUIT: exitcode 0
; Действие: ; функция вычисляет целое число по его строковому представлению. ; Результат не может быть больше 255. ; Для неверно введенных чисел устанавливает флаг переноса ; Параметры: ; BX - адрес строки - предстваления числа ; CX - длина этой строки ; Возвращает: ; CF - установлен, если в строке не цифры, AX - не определен ; сброшен, строка нормальная, AX - число ; AX - преобразованное число, если сброшен VAL proc near push DX; Сохранить все изменяемые регистры, ; кроме AX, в котором результат mov CH, 0; Расширяем длину до слова mov AX, 0; Начальное значение результата mov DL, 10; Основание системы счисления __1: imul DL; Умножить на основание jc __2; Переполнение байта? mov DH, [BX]; Очередная цифра sub DH, '0'; Получить значение цифры jl __2; Это была не цифра! cmp DH, 9 jg __2; Это опять же была не цифра! add AL, DH; + значение цифры к результату jc __2; Переполнение байта? inc BX; Сдвиг по строке loop __1; Цикл по строке jmp __3; Нормальное число __2: stc; Было переполн. - устанавливаем CF __3: pop DX; Восстановить все, что сохраняли ret VAL endp
; Подпрограмма удаления подстроки DELSUBS proc near arg __Ldel: word, __Pdel: word, __StrAdr: word = __ArgSize ; Params struc; Структура стека после сохранения BP ; SaveBP dw? ; Сохраненное значение BP ; SaveIP dw? ; Адрес возврата ; LDel dw? ; 3-й параметр - число удаляемых ; PDel dw? ; 2-й параметр - позиция удаления ; StrAdr dw? ; 1-й параметр - адрес строки ; Params ends push BP; Сохранить BP mov BP, SP; Теперь BP адресует стек ПОСЛЕ сохр.BP, ; но ДО сохранения остальных регистров push ES AX SI DI CX; Сохранить все изменяемые регистры
mov AX, DS; ES будет указывать на mov ES, AX; сегмент данных mov DI, __StrAdr; Вычислить в DI адрес, add DI, __PDel; куда надо dec DI; пересылать символы mov SI, DI; А в SI - адрес, add SI, __LDel; откуда их пересылать cld; Продвигаться от начала строки к концу __REPEAT: movsb cmp byte ptr [SI-1], 0 jne __REPEAT pop CX DI SI AX ES; Восстановить все, что сохраняли pop BP ret __ArgSize; Убрать из стека 3 параметра-слова DELSUBS endp
end ВАРИАНТЫ ЗАДАНИЙ В приведенных ниже вариантах заданий используется стандартное представление строк ASCII с кодом 0 в качестве ограничителя конца строки. Способ передачи параметров выбирается программистом произвольно. Рекомендуется зациклить программу по вводу, а признаком окончания работы считать ввод пустой строки. 1. Разработать подпрограмму, которая определяет, содержится ли одна заданная строка в другой заданной строке, и если да, то, начиная с какой позиции. Разработать программу, которая вводит с клавиатуры две строки и сообщает, содержится ли одна из них в другой и сколько раз. 2. Разработать подпрограмму, которая подсчитывает, сколько раз заданный символ встречается в строке. Разработать программу, которая вводит с клавиатуры строку, вводит число N и выдает список символов, которые встречаются в строке не менее чем N раз. 3. Разработать две подпрограммы, одна из которых соединяет две строки в одну, а другая обрезает строку до заданной длины (или дополняет пробелами, если длина строки меньше заданной). Разработать программу, которая вводит с клавиатуры число N, затем вводит несколько строк (конец ввода – пустая строка) и формирует новую строку, состоящую из первых N символов каждой введенной строки. 4. Разработать две подпрограммы, одна из которых сравнивает две строки по лексикографическому порядку, а другая обменивает значения двух строк. Разработать программу, которая вводит с клавиатуры несколько строк (конец ввода – пустая строка) и сортирует их в лексикографическом порядке. 5. Разработать подпрограмму, которая разбивает заданную строку на две части: первое слово строки (до первого пробела) и остаток строки (пробелы после первого слова отбрасываются). Разработать программу, которая вводит с клавиатуры строку и выводит каждое слово с новой строки. 6. Разработать подпрограмму, которая переставляет символы заданной строки в обратном порядке. Разработать программу, которая вводит с клавиатуры строку и переставляет в обратном порядке символы в каждом слове (слова разделяются пробелами). 7. Разработать подпрограмму, которая вставляет подстроку в строку, начиная с заданной позиции. Разработать программу, которая вводит с клавиатуры исходную строку, вводит подстроку и позицию вставки, вставляет подстроку в строку. 8. Разработать две подпрограммы, одна из которых преобразует любую заданную букву в заглавную (в том числе для русских букв), а другая - преобразует букву в строчную. Разработать программу, которая вводит с клавиатуры строку и заменяет первые буквы всех слов на заглавные, а остальные буквы - на строчные. КОНТРОЛЬНЫЕ ВОПРОСЫ 1. Что такое «ближние» и «дальние» подпрограммы? 2. Как определяется, «ближний» или «дальний» вариант команды call использован в программе? 3. Какие еще способы передачи параметров можно предложить, кроме двух, описанных в данной работе? 4. Может ли массив быть параметром процедуры? 5. Нельзя ли адресовать параметры в стеке через регистр SP, не используя BP? 6. Что и как нужно изменить в программе из примера, если используется версия ассемблера, не поддерживающая понятие структуры? 7. Изменить описание подпрограммы из примера с использованием упрощенных директив описания подпрограмм. 8. Что означает операнд команды ret? 9. Какой последовательностью команд можно было бы заменить команду ret 6?
ЦЕЛЬ РАБОТЫ Цель настоящей работы – выработка навыков подготовки разноязыковых программ в операционной системе MS-DOS. ОСНОВНЫЕ СВЕДЕНИЯ Введение Каждый язык программирования обладает своими достоинствами и недостатками. Поэтому при разработке больших проектов может возникнуть необходимость написания отдельных частей программы на различных языках программирования, например: · вся программа на каком-либо языке высокого уровня (ЯВУ), а для доступа к нестандартной аппаратуре или нестандартного доступа к стандартной требуется написание подпрограмм на языке ассемблера; · в программе на ЯВУ необходимо повысить эффективность выполнения какого-либо фрагмента и для этого переписать его на языке ассемблера; · необходимо использовать библиотеку подпрограмм, написанную на языке, отличном от языка разрабатываемой программы. Вся конкретная информация и примеры рассмотрены для системы программирования (СП) Borland C++ Version 3.1 и Borland Pascal Version 6.0 фирмы Borland International, Inc. и ориентированы на программирования в DOS. ТерминЫ и сокращения Подпрограмма – фрагмент программы, оформленный таким образом, что к нему можно обращаться (вызывать) из других фрагментов программы и возвращаться в точку вызова. При вызове подпрограммы ей можно передавать параметры и она может возвращать значение. Процедура – подпрограмма, не возвращающая значения (см. процедуры Паскаля). Функция – подпрограмма, возвращающая значение (см. функции Паскаля или Си). Параметр – фрагмент данных, передаваемый подпрограмме, и возможно, изменяемый ею. Внешние (глобальные) данные параметрами не являются. Формальный параметр – обозначение (идентификатор) параметра в подпрограмме. Фактический параметр – выражение или идентификатор переменной, подставляемый при обращении (вызове) подпрограммы. Прототип подпрограммы – описание заголовка подпрограммы с описанием формальных параметров. Основной язык – язык, на котором написана вызывающая программа, язык подпрограммы – язык, на котором написана подпрограмма. Сокращения: СП – система программирования ЯП – язык программирования ЯВУ – язык программирования высокого уровня ИМ – исходный модуль ОМ – объектный модуль Соглашения о связях Вообще говоря, для каждого транслятора с языка высокого уровня существует свое собственное соглашение о связях между подпрограммами. То есть соглашение о том, в какие машинные команды и конструкции языка ассемблера транслируются операторы языка высокого уровня, служащие для описания и вызова подпрограмм. Понятие «соглашение о связях» включает следующие аспекты: преобразование имен подпрограмм и переменных, передача и возврат управления, передача и возврат данных, преобразование данных при передаче и возврате, трансляция и компоновка подпрограмм в единую программу. Преобразование имен Под термином «преобразование имен» понимаются правила формирования имен транслятором при создании объектного модуля. Необходимо учитывать, по меньшей мере, следующие моменты: · допустимое количество символов в имени в программе на ЯП и в ОМ; · различаются ли прописные и строчные буквы в программе на ЯП и в ОМ; · не добавляет ли что-нибудь транслятор от себя к именам в ОМ. Длина внешнего имени (т.е. имени «видимого» компоновщиком) зависит от конкретной СП, как правило, это 32 символа. В языке C в именах различаются прописные и строчные буквы, в языке Pascal, напротив, не различаются. Как правило, трансляторы с этих языков поступают соответствующим образом при формировании имен в ОМ. В частности, Pascal-трансляторы преобразуют строчные буквы в прописные. С-трансляторы, как правило, включают символ подчеркивания в начало каждого имени в ОМ. Популярное:
|
Последнее изменение этой страницы: 2016-03-25; Просмотров: 1059; Нарушение авторского права страницы