Модульное программирование
Содержание
Введение 3
1 Постановка задачи 5
2 Модульное программирование 6
3 Описание программы 11
Заключение 16
Список литературы 17
Приложение А 18
Приложение Б 19
Введение
Структурное программирование — методология программирования, базирующаяся на системном подходе к анализу, проектированию и реализации программного обеспечения. Эта методология зародилась вначале 70-х гг. и оказалась настолько жизнеспособной, что и до сих пор является основной в большом количестве проектов. Ее основу составляет концепция модульного программирования.
Концепцию модульного программирования можно сформулировать в виде нескольких понятий и положений. Основа концепции модульного программирования — модуль, который является продуктом процесса разбиения большой задачи на ряд более мелких функционально самостоятельных подзадач. Этот процесс называется функциональной декомпозицией задачи. Каждый модуль в функциональной декомпозиции представляет собой «черный ящик» с одним входом и одним выходом. Модули связаны между собой только входными и выходными данными.
Модульный подход позволяет безболезненно производить модернизацию программы в процессе ее эксплуатации и облегчает ее сопровождение. Дополнительно модульный подход позволяет разрабатывать части программ одного проекта на разных языках программирования, после чего с помощью компоновочных средств объединять их в единый загрузочный модуль.
Основная цель модульного подхода — простота и ясность реализуемых решений.
В данной курсовой работе предполагается разработать алгоритм решения задачи, в которой необходимо, с использованием двух модулей, написать программу конкатенации двух строк.
Для достижения поставленной цели необходимо решить следующие задачи:
- определить метод решения задачи
- определить подходящие для использования в работе средства ассемблирования и команды транслятора
- разработать алгоритм решения задачи
- реализовать разработанный алгоритм в виде программы
1 Постановка задачи
Используя
два модуля, необходимо написать
программу конкатенации двух строк, одна
из которых, должна располагаться в главном
модуле, а другая во вспомогательном.
2 Модульное программирование
Приступая к разработке программного продукта, следует помнить, что он является большой системой, поэтому должны приниматься меры по ее упрощению. Одним из основополагающих принципов упрощения является принцип “разделяй и властвуй”, который получил научное название декомпозиция. При разработке программного продукта этот принцип реализуют путем разработки большой программы по частям, которые называют программными модулями, а сам такой метод разработки программ называют модульным программированием. В теории под модулем понимается следующее.
Модуль
– это замкнутая программа, которую
можно вызвать из другого модуля
и самостоятельно откомпилировать.
Другое определение: программный модуль
– это любой фрагмент описания
процесса, оформляемый как
Модуль – это программа, обладающая тремя основными атрибутами:
- Он выполняет одну или несколько функций;
- Модуль реализует некоторую логику (алгоритм);
- Используется в одном или нескольких контекстах.
При этом функция – это то, что делает модуль, а не то, как он это делает. А вот логика характеризует, как модуль выполняет свои функции. Контекст описывает конкретное применение.
Принципы модульного программирования позволяют получать программные комплексы минимальной сложности. Эти принципы следующие:
а) усиление внутренних связей в каждом модуле (иначе принцип называется повышением прочности модуля);
б) ослабление взаимосвязи между модулями (иначе этот принцип называется ослаблением сцепления модулей).
Если рассматривать программу как набор предложений, связанных между собой некоторыми отношениями (как по выполняемым функциям, так и по обрабатываемым данным), то применение принципов модульного программирования означает, что необходимо распределить предложения программы по отдельным модулям так, чтобы предложения внутри каждого модуля были тесно связаны, а связь между любыми двумя модулями была минимальной.
Стиль программирования – это способ построения программ, концептуальной основой которых являются соответствующая система понятий, стиль мышления и подход к решению задач.
Модульный стиль программирования заключается в том, что алгоритм любой исходной задачи представляется как композиция алгоритмов простых подзадач, последовательно выделенных из исходной задачи. Каждая подзадача может быть реализована с помощью функций и процедур или с помощью модулей. Поскольку в этом случае каждая подзадача имеет структуру, аналогичную структуре исходной основной программы, то можно продолжить детализацию каждой из подпрограмм (принцип декомпозиции).
Однако на практике при реализации больших проектов процедуры и функции оказываются недостаточно удобным средством по следующим причинам:
- большой объем текста программы затрудняет ее понимание;
- всякий раз после изменения программы ее необходимо перекомпилировать, затрачивая определенное время.
Поэтому
структурные элементы подзадач, полученные
в процессе декомпозиции исходной задачи,
часто реализуются в виде программных
модулей, расширяющих понятие
При проектировании программы формируется иерархия модулей. Главный модуль передает подготовленные параметры и управление модулю, который сам может передавать управление и параметры другим модулям, последние после выполнения в них программного кода возвращают управление назад, вызвавшему его модулю. Подобная структура независимых модулей позволяет легко модифицировать программу исходной задачи путем замены старых модулей на новые, добавления и удаления ненужных модулей.
В нашей программе мы будем использовать два модуля - один основной модуль (loc) и один вспомогательный (loc1). В основе связки этих двух модулей лежат две директивы TASM: EXTRN и PUBLIC. Директива EXTRN предназначена для объявления некоторого имени внешним по отношению к основному модулю. Это имя во вспомогательном модуле должно быть объявлено в директиве PUBLIC. Директива PUBLIC предназначена для объявления некоторого имени, определенного в этом модуле и видимого в других модулях. Синтаксис этих директив следующий:
EXTERN имя: тип имя: тип
PUBLIC имя,..., имя
Здесь имя — идентификатор, определенный в другом модуле. В качестве идентификатора могут выступать:
- имена переменных, определенных директивами типа DB, DW и т. д.;
- имена процедур;
- имена констант, определенных операторами = и EQU.
В нашем случае в качестве идентификатора выступают имена процедур.
Аргумент тип определяет тип идентификатора. Указание типа необходимо для того, чтобы транслятор правильно сформировал соответствующую машинную команду. Действительные адреса вычисляются на этапе редактирования, когда будут разрешаться внешние ссылки. Возможные значения типа определяются допустимыми типами объектов для этих директив:
- если имя — это имя переменной, то тип может принимать значения BYTE, WORD, DWORD, PWORD, FWORD, QWORD и TBYTE;
- если имя — это имя процедуры, то тип может принимать значения NEAR или FAR;
- если имя — это имя константы, то тип должен быть ABS.
Следовательно, тип идентификатора в нашем случае может принимать значения NEAR или FAR.
Но не менее важно организовать информационный обмен между модулями. Рассмотрим основные способы организации такой связи.
Информационный обмен между модулями (процедурами) предполагает обмен данными. В этой связи важно понимать значение терминов аргумент, переменная, константа.
Аргумент — это ссылка на некоторые данные, которые требуются для выполнения возложенных на модуль функций и размещенных вне этого модуля. По аналогии с макрокомандами выделяют формальные и фактические аргументы. Исходя из этого, формальный аргумент можно рассматривать не как непосредственные данные или их адрес, а как «тару» для действительных данных, которые будут положены в нее с помощью фактического аргумента. Формальный аргумент можно рассматривать как элемент интерфейса модуля (конкретный вывод «скарта»), а фактический аргумент — это то, что фактически передается на место формального аргумента.
Переменная — это нечто, размещенное в регистре или ячейке памяти, что может в дальнейшем подвергаться изменению.
Константа — информационный объект простого типа, значение которого никогда не изменяется.
Таким образом, если некоторые данные в модуле могут подвергаться изменению, то это переменные. Если переменная находится за пределами модуля (процедуры) и должна быть как-то передана в него, то для модуля она является формальным аргументом. Значение переменной передается в модуль для замещения соответствующего параметра при помощи фактического аргумента.
Если входные данные для модуля (аргументы) — переменные, то один и тот же модуль можно использовать многократно для разных наборов значений этих переменных. При программировании на языке высокого уровня программист ограничен в выборе способов передачи аргументов теми рамками, которые для него оставляет компилятор. В языке ассемблера практически нет никаких ограничений на этот счет, и, фактически, решение проблемы передачи аргументов предоставлено программисту.
На практике используются следующие варианты передачи аргументов в модуль (процедуру):
- через регистры
- через общую область памяти;
- через стек;
Для разработки алгоритма решения данной задачи мы будем использовать вариант передачи аргументов в модуль через стек.
3 Описание программы
Основным модулем мы будем называть тот, который получает управление после запуска программы. В основном модуле происходит вызов двух процедур COPY(процедура копирования двух строк в буфер) и PRINT(процедура вывода полученной строки кодом) с помощью межсегментной команды CALL. Команда CALL в основном модуле должна "знать", что процедуры COPY и PRINT существуют вне данного сегмента (иначе ассемблер выдаст сообщение о том, что идентификаторы COPY и PRINT не определены).
…
CALL COPY
…
CALL PRINT
…
С помощью директивы EXTRN можно указать ассемблеру, что ссылка на процедуры COPY и PRINT имеет атрибут FAR, т.е. они определены в другом ассемблерном модуле, вспомогательном.
EXTRN COPY:FAR
EXTRN PRINT:FAR
Процедуры COPY и PRINT содержат директиву PUBLIC, которая указывает ассемблеру и компоновщику, что вспомогательный модуль должен "знать" адрес процедур COPY и PRINT.
PUBLIC COPY, PRINT
…
Во вспомогательном модуле будут находиться процедуры COPY(процедура копирования двух строк в буфер) и PRINT(процедура вывода полученной строки кодом), которые получают параметры через стек. Передача аргументов через стек при вызове процедур используется наиболее часто. Суть этого способа заключается в том, что вызывающая процедура самостоятельно заносит в стек передаваемые данные, после чего обращается к вызываемой процедуре. При передаче управления процедуре процессор автоматически записывает на вершину стека два (для процедур типа near) или четыре (для процедур типа far) байта. Эти байты являются адресом возврата в вызывающую программу. Если перед передачей управления процедуре командой CALL в стек были записаны переданные процедуре данные или указатели на них, то они окажутся под адресом возврата. Для произвольного доступа к данным в стеке архитектура процессора имеет специальный регистр ЕВР\ВР (Base Point — указатель базы). Так же как и для регистра ESP\SP, обращение к ЕВР\ВР автоматически предполагает работу с сегментом стека. Перед использованием этого регистра для доступа к данным стека содержимое стека необходимо правильно инициализировать, что предполагает формирование в нем адреса, который бы указывал непосредственно на переданные данные. Для этого в начало процедуры рекомендуется включить дополнительный фрагмент кода. Он имеет свое название — пролог процедуры.
COPY PROC
;начало пролога
PUSH ВР
MOV BP,SP
;конец пролога
Код пролога состоит всего из двух команд. Первая команда push bp сохраняет содержимое ВР в стеке с тем, чтобы исключить порчу находящегося в нем значения в вызываемой процедуре. Вторая команда пролога mov bp,sp настраивает ВР на вершину стека. После этого можно не волноваться о том, что содержимое SP перестанет быть актуальным, и осуществлять прямой доступ к содержимому стека. Что обычно и делается. Для процедур типа far эти значения необходимо скорректировать еще на 2, так как при вызове процедуры дальнего типа в стек записывается полный адрес — содержимое CS и IP.
Конец процедуры также должен быть оформлен особым образом, обеспечивая корректный возврат из процедуры. Фрагмент кода, выполняющего такие действия, имеет свое название — эпилог процедуры. Код эпилога должен восстановить контекст программы в точке вызова процедуры из вызывающей программы. При этом, в частности, нужно откорректировать содержимое стека, убрав из него ставшие ненужными аргументы, передававшиеся в процедуру. Это можно сделать несколькими способами:
- можно использовать последовательность из п команд pop xx. Лучше всего это делать в вызывающей программе сразу после возврата управления из процедуры.
- можно откорректировать регистр указателя стека SP на величину 2 • п, например, командой add sp,NN, где NN = 2 • п, а п — количество аргументов. Это также лучше делать после возврата управления вызывающей процедуре.
- можно использовать машинную команду RET n в качестве последней исполняемой команды в процедуре. Здесь n — количество байтов, на которое нужно увеличить содержимое регистра ESP\SP после того, как со стека будут сняты составляющие адреса возврата. Видно, что этот способ аналогичен предыдущему, но выполняется процессором автоматически.
В нашем случае выход из процедуры осуществляется командой RETF, возвращающей стек в исходное состояние.
;выход с освобождением стека
RETF 16
Кроме того, в процедуре COPY мы определим локальную переменную [ВР-2], типа WORD и будем ее использовать. Сначала обнулим нашу локальную переменную.
MOV WORD PTR [ВР-2],0
Затем поместим в неё первую строку STOKA1 и загрузим в буфер. После мы поместим в неё вторую строку STROKA2 и только в процедуре PRINT загрузим её в буфер.
Вызов и работа процедур будет весьма напоминать то, как это делается в языках высокого уровня.
В последнем шаге, мы оттранслируем оба модуля loc и loc1. Результаты трансляции приведены в соответствии с Рисунком 1 и Рисунком 2.
Рисунок
1 - Основной модуль
Рисунок 2 - Вспомогательный модуль
В результате на диске образуются два объектных модуля: loc .OBJ и loc1.OBJ . Теперь дело за редактором связей. В командной строке укажем: LINKloc+loc1. После этого отвечаем на вопросы как обычно. При просьбе указать имя МАР-файла, указываем loc (впрочем, имя не имеет никакого значения). В результате компоновки образуется загрузочный модуль loc.exe и loc.map, а также происходит вывод на экран полученной строки, результаты вывода данной строки приведены на Рисунке 3.
Рисунок 3 – Результат вывода на экран полученной строки
В
этом файле содержатся сведения о
сегментах (начальный и конечный
адрес, длина, имя, класс), скомпонованных
в один модуль в том порядке, как они
помещены в него (начиная с младших адресов).
Обращаем Ваше внимание, что вначале идут
сегменты модуля loc, а затем сегменты модуля
loc1. Именно так, как мы указали модули в
командной строке. Если бы в командной
строке было LINKloc1+loc, то порядок сегментов
был бы обратный. При этом сначала запустился
бы модуль loc1, что привело бы к катастрофе.
Итак, главный модуль должен быть первым,
порядок остальных модулей уже не так
важен.
Заключение
Нам
удалось разработать алгоритм решения
задачи, использующей два модуля, для
написания программы
Особенностью данной задачи является то, что данные передаются в модулю через стек. Этот метод передачи данных практичен и удобен в применении.
Алгоритм
решения данной задачи разработан и
оформлен в виде программы и представлен
в приложении данной работы.
Список литературы
- Пирогов В.Ю., ASSEMBLER. Учебный курс.- М.: Издатель Молгачева С.В., Издательство Нолидж, 2001. - 848 с., ил.
- Юров В. И., Assembler. Учебник для вузов. 2-е изд. — СПб.: Питер, 2003. —637 с.: ил.
- http://www.studcode.ru/archiv/
razrabotka-struktury/ - http://thelib.ru/books/abel_
piter/assembler_i_ programmirovanie_dlya_ibm_pc- read.html
Приложение А
Листинг 1. Основной модуль
EXTRN COPY:FAR
EXTRN print:FAR
STE SEGMENT STACK
DB 100 DUP(0)
STE ENDS
DATA SEGMENT
STROKA1 DB "GRAND",0
STROKA2 DB "MOTHER",0
BUFER DB 100 DUP(?)
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STE
BEGIN
MOV AX,DATA
MOV DS,AX
PUSH DS
LEA AX,BUFER
PUSH AX
PUSH DS
LEA AX,STROKA1
PUSH AX
PUSH DS
LEA AX,STROKA2
PUSH AX
CALL COPY
MOV AX,03
INT 10H
PUSH DS
LEA AX,BUFER
PUSH AX
CALL PRINT
MOV AX,4C00H
INT 21H
CODE ENDS
END
BEGIN
Приложение Б
Листинг 2. Вспомогательный модуль
PUBLIC COPY, PRINT
COD SEGMENT
ASSUME CS:COD
COPY PROC
PUSH ВР
MOV BP,SP
SUB SP,2
MOV WORD PTR [ВР-2],0
LDS SI,[ВР+10]
LDS DI,[ВР+14]
LO1:
MOV AL,DS:[SI]
CMP AL,0
JZ ZER1
MOV DS:[DI],AL
INC DI
INC SI
INC WORD PTR [ВР-2]
JMP SHORT L01
ZER1:
LDS SI,[BP+6]
L02:
MOV AL,DS:[SI]
CMP AL,0
JZ ZER2
MOV DS:[DI],AL
INC DI
INC SI
INC WORD PTR [ВР-2]
JMP SHORT LO2
ZER2:
MOV BYTE PTR DS:[DI],0
MOV AX,[ВР-2]
ADD SP,2
POP ВР
RETF 16
COPY ENDP
PRINT PROC
PUSH ВР
MOV ВР,SP
LDS SI,[BP+б]
LO3:
MOV DL,DS: [SI]
CMP DL,0
JZ ZER3
MOV AH, 2
INT 21H
INC SI
JMP SHORT L03
ZER3:
POP BP
RETF 4
PRINT ENDP
COD ENDS
END

- Модульное программирование. Интеллектуальная собственность
- Модульное программирование на примере сортировки последовательностей
- Модульно обучение на уроках спецтехнологии
- Модульно-рейтингове навчання в школі
- Модульные учебные программы и принципы их построения
- Модульный подход в обучающем консультировании
- Модульный принцип организации производства: достоинства и недостатки
- Модульная технология на уроках информатики в школе
- Модульная технология обучения
- Модульное обучение
- Модульное обучение в школе
- Модульное программирование
- Модульное программирование
- Модульное программирование