- Lektsia - бесплатные рефераты, доклады, курсовые работы, контрольные и дипломы для студентов - https://lektsia.info -

Расширенные директивы описания процедур



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


ИМЯ proc [[МОДИФИКАТОР_ЯЗЫКА] ЯЗЫК] [РАССТОЯНИЕ]
[arg СПИСОК_АРГУМЕНТОВ]
[local СПИСОК_АРГУМЕНТОВ]
...
[ИМЯ] endp

Приведем синтаксис определения передаваемых процедуре ар­гументов:

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
arg A:word, B:word:4, C:byte =ArgSize
local X:dword, Y:word:2 =LocSize
...

Здесь A определяется, как [BP+4], B – [BP+6], C – [BP+14], а ArgSize – 20. X – [BP-2], Y – [BP-6], а LocSize – 8.

Область действия имен

Если для аргументов и локальных переменных, а также меток операторов в подпрограмме, не заданы имена с предшествующим префиксом локального идентификатора, все аргументы, заданные в заголовке процедуры, определены ли они с помощью директивы arg или local и метки имеют глобальную область действия.

Идентификаторы с локальной областью действия разрешает ди­ректива locals (не путать с директивой local).

Например:

locals __
TST1 proc
arg __A: word, __B: word, __C: byte
local __X: word, __Y: dword
...

В этом примере директива locals __ определяет двойной символ подчеркивания как префикс локальных имен. Это означает, что все имена, начинающиеся с данной пары символов, будут счи­таться локальными в пределах подпрограммы.

Итоги

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


locals __

...
Func proc near
arg __p1: word, __p2: word, ... = __ArgSize
local __v1: byte, __v2: word, ... = __LocSize
;Действие: ...
;Входные параметры: ...
;Выходные параметры: ...
;Возвращает: ...
;Обращение: ...
;Замечания:
; регистры не модифицирует
; стек чистит от параметров

push BP ;+ BP - указатель
mov BP, SP ;- кадра стека
sub SP, __LocSize ;выделение памяти для лок. переменных
push SI, DI ;сохранение регистров
...
mov SI, __p1 ;доступ к параметру
...
mov __v2, SI ;доступ к локальной переменной
...
pop DI, SI ;восстановление регистров
mov SP, BP ;чистка стека от лок. переменных
pop BP ;восстановление BP
ret __ArgSize ;возврат и чистка стека от параметров
Func endp

ПРИМЕР ВЫПОЛНЕНИЯ РАБОТЫ

Разработать подпрограмму, которая удаляет, начиная с задан­ной позиции строки, указанное число символов. Разработать про­грамму, которая вводит с клавиатуры строку, вводит позицию и длину удаляемой части строки и удаляет эту часть.

Текст программы:


locals __

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?


Лабораторная работа

ÈÑÏÎËÜÇÎÂÀÍÈÅ ÏÎÄÏÐÎÃÐÀÌÌ ÍÀ ßÇÛÊÅ ÀÑÑÅÌÁËÅÐÀ  ÏÐÎÃÐÀÌÌÀÕ ÍÀ ßÇÛÊÀÕ C È PASCAL

ЦЕЛЬ РАБОТЫ

Цель настоящей работы – выработка навыков подготовки раз­ноязыковых программ в операционной системе MS-DOS.

ОСНОВНЫЕ СВЕДЕНИЯ

Введение

Каждый язык программирования обладает своими достоинст­вами и недостатками. Поэтому при разработке больших проектов может возникнуть необходимость написания отдельных частей программы на различных языках программирования, например:

· вся программа на каком-либо языке высокого уровня (ЯВУ), а для доступа к нестандартной аппаратуре или нестандартного доступа к стандартной требуется написание подпрограмм на языке ассемблера;

· в программе на ЯВУ необходимо повысить эффективность вы­полнения какого-либо фрагмента и для этого переписать его на языке ассемблера;

· необходимо использовать библиотеку подпрограмм, написан­ную на языке, отличном от языка разрабатываемой про­граммы.

Вся конкретная информация и примеры рассмотрены для сис­темы программирования (СП) Borland C++ Version 3.1 и Borland Pascal Version 6.0 фирмы Borland International, Inc. и ориентиро­ваны на программирования в DOS.

ТерминЫ и сокращения

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

Процедура – подпрограмма, не возвращающая значения (см. процедуры Паскаля).

Функция – подпрограмма, возвращающая значение (см. функ­ции Паскаля или Си).

Параметр – фрагмент данных, передаваемый подпрограмме, и возможно, изменяемый ею. Внешние (глобальные) данные пара­метрами не являются.

Формальный параметр – обозначение (идентификатор) пара­метра в подпрограмме.

Фактический параметр – выражение или идентификатор пе­ременной, подставляемый при обращении (вызове) подпрограммы.

Прототип подпрограммы – описание заголовка подпрограммы с описанием формальных параметров.

Основной язык – язык, на котором написана вызывающая про­грамма, язык подпрограммы – язык, на котором написана подпро­грамма.

Сокращения:

СП – система программирования

ЯП – язык программирования

ЯВУ – язык программирования высокого уровня

ИМ – исходный модуль

ОМ – объектный модуль

Соглашения о связях

Вообще говоря, для каждого транслятора с языка высокого уровня существует свое собственное соглашение о связях между подпрограммами. То есть соглашение о том, в какие машинные команды и конструкции языка ассемблера транслируются опера­торы языка высокого уровня, служащие для описания и вызова подпрограмм.

Понятие «соглашение о связях» включает следующие аспекты: преобразование имен подпрограмм и переменных, передача и воз­врат управления, передача и возврат данных, преобразование дан­ных при передаче и возврате, трансляция и компоновка подпро­грамм в единую программу.

Преобразование имен

Под термином «преобразование имен» понимаются правила формирования имен транслятором при создании объектного мо­дуля. Необходимо учитывать, по меньшей мере, следующие мо­менты:

· допустимое количество символов в имени в программе на ЯП и в ОМ;

· различаются ли прописные и строчные буквы в программе на ЯП и в ОМ;

· не добавляет ли что-нибудь транслятор от себя к именам в ОМ.

Длина внешнего имени (т.е. имени «видимого» компоновщи­ком) зависит от конкретной СП, как правило, это 32 символа.

В языке C в именах различаются прописные и строчные буквы, в языке Pascal, напротив, не различаются. Как правило, трансля­торы с этих языков поступают соответствующим образом при формировании имен в ОМ. В частности, Pascal-трансляторы преобразуют строчные буквы в прописные.

С-трансляторы, как правило, включают символ подчеркивания в начало каждого имени в ОМ.