Как сделать подпрограмму в программе

В Аде, также как и во всех современных языках программирования, подпрограммы позволяют программисту группировать инструкции в самостоятельные, логически законченные алгоритмические единицы, которые, в последствии, могут быть вызваны и выполнены в любом месте программы. Они являются элементарным базовым средством для повторного использования кода и разделения одной большой задачи на самостоятельные подзадачи меньшего размера (декомпозиция). Использование подпрограмм позволяет уменьшить как общий размер исходных текстов программы, так и общий размер результирующих исполняемых файлов. Таким образом, применение подпрограмм облегчает общее управление проектом и упрощает его сопровождение.

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

Создаем Подпрограмму в VBA

6.1 Общие сведения о подпрограммах

Также как и в Паскале, подпрограммами Ады являются процедуры и функции.

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

формальный параметр Параметр который используется при описании подпрограммы (процедуры или функции).
фактический параметр Объект, который передается в подпрограмму при вызове подпрограммы. В качестве фактического параметра подпрограммы может быть передано целое выражение, при этом режимом передачи параметра не может быть режим «out».

Каждый формальный параметр подпрограммы имеет имя, тип и режим передачи.

Подпрограммы могут содержать локальные описания типов, подтипов, переменных, констант, других подпрограмм и пакетов.

Подпрограмма Ады, как правило, состоит из двух частей: спецификации и тела. Спецификация описывает интерфейс обращения к подпрограмме, другими словами — «что» обеспечивает подпрограмма. Тело подпрограммы описывает детали реализации алгоритма работы подпрограммы, то есть, «как» подпрограмма устроена.

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

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

Уроки по С++. Урок 13. Подпрограммы. Функции. Прототип функции.

Необходимо заметить, что спецификации подпрограмм, как правило, помещаются в спецификации пакетов, а тела подпрограмм — в тела пакетов.

Кроме того, подпрограмма может быть самостоятельным независимым программным модулем. В этом случае, спецификация и тело подпрограммы помещаются в разные файлы (в файл спецификации и в файл тела, соответственно). Следует также заметить, что помещать спецификацию в отдельный файл, когда подпрограмма не является самостоятельной единицей компиляции не обязательно. В этом случае, спецификация подпрограммы может отсутствовать.

6.1.1 Процедуры

procedure имя_процедуры [ (формальные_параметры) ] ;
procedure имя_процедуры [ (формальные_параметры) ] is
begin
end [ имя_процедуры ];
procedure Demo(X: Integer; Y: Float) is begin null; — пустая инструкция end Demo;
Demo(4, 5.0);

6.1.2 Функции

function имя_функции [ (формальные_параметры) ] return тип_возвращаемого_значения ;
function имя_функции [ (формальные_параметры) ] return тип_возвращаемого_значения is
begin
end [ имя функции ];

6.1.3 Локальные переменные

Как уже говорилось, подпрограммы (и процедуры, и функции) могут содержать локальные переменные. Такие переменные доступны только внутри подпрограммы и не видимы извне этой подпрограммы. Время жизни (время существования) таких переменных определяется временем жизни (временем выполнения) подпрограммы.

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

6.1.4 Локальные подпрограммы

with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Ive_Got_A_Procedure is X : Integer := 6; Y : Integer := 5; procedure Display_Values (Number : Integer) is begin Put (Number); New_Line; end Display_Values; begin Display_Values (X); Display_Values (Y); end Ive_Got_A_Procedure;

6.1.5 Раздельная компиляция

with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Ive_Got_A_Procedure is X : Integer := 6; Y : Integer := 5; procedure Display_Values(Number : Integer) is separate; begin Display_Values(X); Display_Values(Y); end Ive_Got_A_Procedure;
separate(Ive_Got_A_Procedure) — примечание! нет завершайщего символа — точки с запятой procedure Display_Values(Number : Integer) is begin Put(Number); New_Line; end Display_Values;

6.1.6 Подпрограммы как библиотечные модули

    Примечание:
    В системе компилятора GNAT существует соглашение согласно которому файлы спецификаций имеют расширение ads (ADa Specification), а файлы тел имеют расширение adb (ADa Body).

procedure Display_Values(Number : Integer);
with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Display_Values(Number : Integer) is begin Put(Number); New_Line; end Display_Values;
with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; with Display_Values; procedure Ive_Got_A_Procedure is X : Integer := 6; Y : Integer := 5; begin Display_Values(X); Display_Values(Y); end Ive_Got_A_Procedure;

6.2 Режимы передачи параметров

    «in»
    «in out»
    «out»
    access

    по-умолчанию, для передачи параметров подпрограммы, всегда устанавливается режим — «in» .

6.2.1 Режим «in»

with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Demo(X : in Integer; Y : in Integer) is begin X := 5; — недопустимо, in параметр доступен только по чтению Put(Y); Get(Y); — также недопустимо end Demo;

6.2.2 Режим «in out»

procedure Demo(X : in out Integer; Y : in Integer) is Z : constant Integer := X; begin X := Y * Z; — это допустимо! end Demo;

6.2.3 Режим «out»

procedure Demo(X : out Integer; Y : in Integer) is — при входе в подпрограмму X не инициализирован. begin X := Y; end Demo;

Читайте также:
Чему будет равно значение с в результате выполнения фрагмента программы

6.2.4 Режим access

. . . function Demo_Access(A : access Integer) return Integer is begin return A.all; end Demo_Access; . . . type Integer_Access is access Integer; Integer_Access_Var : Integer_Access := new Integer'(1); Aliased_Integer_Var : aliased Integer; . . . X : Integer := Demo_Access(Integer_Access_Var); Y : Integer := Demo_Access(Aliased_Integer_Var’Access); Z : Integer := Demo_Access(new Integer); . . .

6.3 Сопоставление формальных и фактических параметров

6.3.1 Позиционное сопоставление

procedure Demo(X : Integer; Y : Integer); — спецификация процедуры . . . Demo(1, 2);

6.3.2 Именованное сопоставление

procedure Demo(X : Integer; Y : Integer); — спецификация процедуры . . . Demo(X => 5, Y => 3 * 45); — именованное сопоставление — формальных и фактических — параметров при вызове
Demo(X => 5, Y => 3 * 45);

Demo(Y => 3 * 45, — при именованом сопоставлении X => 5); — порядок следования параметров — не имеет значения

6.3.3 Смешивание позиционного и именованного сопоставления

procedure Square(Result : out Integer; Number : in Integer) is begin Result := Number * Number; end Square;

Square(X, 4); Square(X, Number => 4); Square(Result => X, Number => 4); Square(Number => 4, Result => x); Square(Number => 4, X); — недопустимо, поскольку позиционно-ассоциируемый — параметр следует за параметром, ассоциируемым — по имени

6.4 Указание значения параметра по-умолчанию

with Ada.Text_IO; use Ada.Text_IO; procedure Print_Lines(No_Of_Lines: Integer := 1) is begin for Count in 1 .. No_Of_Lines loop New_Line; end loop; end Print_Lines;
Print_Lines; — это печатает одну строку Print_Lines(6); — переопределяет значение параметра — установленное по-умолчанию

with Ada.Text_IO; use Ada.Text_IO; procedure Write_Lines(Letter : in Char := ‘*’; No_Of_Lines : in Integer := 1) is begin for I in 1 .. No_Of_Lines loop for I in 1 .. 80 loop Put(Letter); end loop; New_Line; end loop; end Write_Lines;
Write_Lines; — для параметров Letter и No_Of_Lines — используются значения устанавливаемые — по-умолчанию Write_Lines(‘-‘); — значение по-умолчанию — для No_Of_Lines Write_Lines(no_of_lines => 5); — значение по-умолчанию — для Letter Write_Lines(‘-‘, 5) — оба параметра определены

6.5 Совмещение (overloading)

Поиск новых имен для подпрограмм, которые выполняют одинаковые действия, но с переменными разных типов, всегда является большой проблемой при разработке программного обеспечения. Хорошим примером для иллюстрации такой проблемы является процедура Insert.

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

6.5.1 Совмещение подпрограмм (subprogram overloading)

procedure Insert(Item : Integer); — две процедуры с одинаковыми именами, procedure Insert(Item : Float); — но имеющие разный «профиль»

6.5.2 Совмещение знаков операций (operator overloading)

procedure Add_Demo is type Vector is array (Positive range <>) of Integer; A : Vector(1..5); B : Vector(1..5); C : Vector(1..5); function «+»(Left, Right : Vector) return Vector is Result : Vector(Left’First..Left’Last); Offset : constant Natural := Right’First — 1; begin if Left’Length /= Right’Length then raise Program_Error; — исключение, — рассматриваются позже end if; for I in Left’Range loop Result(I) := Left(I) + Right(I — Offset); end loop; return Result; end «+»; begin A := (1, 2, 3, 4, 5); B := (1, 2, 3, 4, 5); C := A + B; end Add_Demo;

6.5.3 Спецификатор «use type»

use type имя_типа

Источник: www.ada-ru.org

10) Excel VBA: вызов подпрограммы

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

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

В этом уроке вы узнаете

  • Зачем использовать подпрограммы
  • Правила именования подпрограмм и функций
  • Синтаксис подпрограммы VBA
  • Как вызвать подпрограмму в VBA

Зачем использовать подпрограммы

  • Разбейте код на небольшой управляемый код : средняя компьютерная программа имеет тысячи и тысячи строк исходного кода. Это вводит сложность. Подпрограммы помогают решить эту проблему, разбивая программу на небольшие управляемые куски кода.
  • Повторное использование кода . Допустим, у вас есть программа, которая нуждается в доступе к базе данных, почти все окна в программе должны будут взаимодействовать с базой данных. Вместо того, чтобы писать отдельный код для этих окон, вы можете создать функцию, которая обрабатывает все взаимодействия с базой данных. Затем вы можете вызвать его из любого окна.
  • Подпрограммы и функции самодокументируются . Допустим, у вас есть функция CalculateLoanInterest и другая, которая сообщает connectToDatabase. Просто взглянув на название подпрограммы / функции, программист сможет сказать, что делает программа.

Правила именования подпрограмм и функций

Чтобы использовать подпрограммы и функции, есть набор правил, которым нужно следовать.

  • Имя подпрограммы или функции не может содержать пробел
  • Имя подпрограммы или функции должно начинаться с буквы или символа подчеркивания. Не может начинаться с цифры или специального символа
  • Имя подпрограммы или функции не может быть ключевым словом. Ключевое слово – это слово, которое имеет особое значение в VBA. Такие слова, как Private, Sub, Function, End и т. Д., Являются примерами ключевых слов. Компилятор использует их для конкретных задач.

Синтаксис подпрограммы VBA

Вам нужно будет включить вкладку «Разработчик» в Excel, чтобы следовать этому примеру. Если вы не знаете, как включить вкладку «Разработчик», прочтите руководство по VBA Operators.

ЗДЕСЬ в синтаксисе,

Private Sub mySubRoutine(ByVal arg1 As String, ByVal arg2 As String) ‘do something End Sub

Код

действие

  • “Private Sub mySubRoutine (…)”
  • Здесь ключевое слово «Sub» используется для объявления подпрограммы с именем «mySubRoutine» и запуска тела подпрограммы.
  • Ключевое слово Private используется для указания области действия подпрограммы.
  • «ByVal arg1 As String, ByVal arg2 As String»:
  • Он объявляет два параметра строкового типа данных имя arg1 и arg2
  • “End Sub”
  • «End Sub» используется для завершения тела подпрограммы

Следующая подпрограмма принимает имя и фамилию и отображает их в окне сообщения.

Теперь мы собираемся запрограммировать и выполнить эту подпроцедуру. Давай посмотрим это.

Как вызвать подпрограмму в VBA

  1. Разработайте пользовательский интерфейс и установите свойства для пользовательских элементов управления.
  2. Добавить подпрограмму
  3. Напишите код события click для командной кнопки, которая вызывает подпрограмму
  4. Протестируйте приложение

Шаг 1) Пользовательский интерфейс

Дизайн пользовательского интерфейса, как показано на рисунке ниже

Функции VBA и подпрограмма

Установите следующие свойства. Свойства, которые мы устанавливаем

S / N контроль Имущество Ценность
1 CommandButton1 имя btnDisplayFullName
2 титр Полное имя подпрограммы

Ваш интерфейс должен выглядеть следующим образом

Функции VBA и подпрограмма

Шаг 2) Добавьте подпрограмму

  1. Нажмите Alt + F11, чтобы открыть окно кода
  2. Добавьте следующую подпрограмму
Читайте также:
Программа предназначена для создания полиграфической продукции это

Private Sub displayFullName(ByVal firstName As String, ByVal lastName As String) MsgBox firstName » “” » используется для объединения двух переменных и добавления пустого пространства между ними.

Шаг 3) Вызов подпрограммы из события нажатия кнопки.

  • Щелкните правой кнопкой мыши на кнопке, как показано на рисунке ниже. Выберите Просмотр кода.
  • Откроется редактор кода

Функции VBA и подпрограмма

Добавьте следующий код в редакторе кода для события click кнопки btnDisplayFullName.

Private Sub btnDisplayFullName_Click() displayFullName «John», «Doe» End Sub

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

Функции VBA и подпрограмма

Сохраните изменения и закройте окно кода.

Шаг 4) Тестирование кода

На панели инструментов разработчика установите режим «выключен». Как показано ниже.

Функции VBA и подпрограмма

Шаг 5) Нажмите на командную кнопку «Полное имя подпрограммы».

Вы получите следующие результаты

Функции VBA и подпрограмма

Резюме:

  • Подпрограмма – это фрагмент кода, который выполняет определенную задачу. Подпрограмма не возвращает значение после выполнения
  • Подпрограммы предлагают повторное использование кода
  • Подпрограммы помогают разбить большие куски кода на небольшой управляемый код.

Источник: coderlessons.com

Использование подпрограмм

Общая идея использования подпрограмм очевидна: если в программе требуется многократно выполнять один и тот же фрагмент, его можно оформить в виде подпрограммы и вызвать по мере необходимости. Если подпрограмма не требует для своего выполнения никаких параметров и не должна возвращать в основную программу результат своей работы, то дело ограничивается оформлением текста подпрограммы в виде процедуры, завершающейся командой ret, и вызовом этой процедуры с помощью команды call. Как уже отмечалось ранее, подпрограмма может и не образовывать процедуру, а быть просто частью основной программы. Важно только, чтобы у нее была входная метка, и чтобы она завершалась командой ret.
В следующем примере подпрограмма delay используется для включения в основной текст программы программных задержек фиксированной величины.

Пример 3-8. Вызов подпрограммы без параметров

code segment

assume cs:code,ds:data

delay proc ;Процедура-подпрограмма push CX ;Сохраним СХ основной программы mov CX,2000 ;Счетчик внешнего цикла del1: push CX ;Сохраним его mov CX,0 ;Счетчик внутреннего цикла del2: loop del2 ;Внутренний цикл (64К шагов) pop CX ;Восстановим внешний счетчик loop del1 ;Внешний цикл (2000 шагов) pop CX ; Восстановим СХ программы ret ;Возврат в подпрограмму delay endp main proc mov AX,data ;Настроим DS mov DX,AX ;на сегмент данных mov AH,09h ;Функция вывода на экран mov DX,offset npl1 ;Адрес первой строки mov CX,3 ;Будем выводить строки в цикле cntrl1: int 21h ;Вызов DOS cal1 delay ;Вызов подпрограммы задержки add DX,msg_len ;Прибавим к смещению длину строки loop cntrl ;Цикл вызовов DOS mov AX,4C00h ;Завершение программы int 21h main endp code ends data segment msg1 db «Процесс стартовал»,13,10,’$’ msg_len=$-msg1 msg2 db «Процесс идет»,13,10,’$’ msg3 db «Процесс завершается»,13,10,’$’ data ends stk segment stack dw 128 dup(‘) stk ends end main

В тексте программы сначала описана процедура-подпрограмма, затем основная программа. Как уже отмечалось, порядок их описания роли не играет; важно только, чтобы в завершающей директиве окончания трансляции end был указан в качестве точки входа адрес основной программы (main в нашем примере).
Подпрограмма реализует задержку с помощью вложенных циклов с командой loop, использующей в качестве счетчика шагов регистр СХ. В основной программе этот регистр используется для организации цикла вывода трех строк. Поэтому первое, что должна сделать подпрограмма — это сохранить содержимое регистра СХ, для чего естественно использовать стек. Перед завершающей командой ret регистр СХ должен быть восстановлен. Фрагмент, реализующий задержку, был описан ранее, в разделе 3.2.
Основная программа выводит на экран с помощью функции 09h три строки текста. Для упрощения программы, а также чтобы продемонстрировать некоторые приемы программирования, вывод строк реализован в цикле. Строки сделаны одной длины, и модификация смещения к очередной строке выполняется прибавлением к содержимому регистра DX длины строки.

Полезно обратить внимание на организацию цикла в основной программе. В цикл, помимо команды вызова подпрограммы задержки и предложения, модифицирующего регистр DX, включена лишь команда int 21h. Регистр АН с номером функции заново не настраивается.

Это и не нужно, так как DOS, выполняя затребованную операцию, первым делом сохраняет все регистры программы, а перед возвратом в программу их восстанавливает. Поэтому, вызывая функции DOS (или BIOS) можно не заботиться о сохранении регистров — их содержимое система на разрушает. Надо только иметь в виду, что многие функции DOS и BIOS после своего завершения возвращают в программу некоторую информацию (число реально введенных символов, доступный объем памяти, номер видеорежима и т.п.) Обычно эта информация возвращается в регистре АХ, однако могут использоваться и другие регистры или их сочетания. Поэтому, обращаясь в программе к системным функциям, необходимо ознакомиться с их описанием и, в частности, посмотреть, какие регистры они могут использовать для возвращаемых значений.
Запустив программу, можно убедиться в том, что строки текста появляются на экране через заметные промежутки времени.
В примере 3-8 подпрограмма не требовала параметров. Чаще, однако, подпрограмма должна принимать один или несколько параметров и возвращать результат. В этом случае необходимо организовать взаимодействие основной программы и подпрограммы.

Никаких специальных средств языка для этого не существует; передачу параметров в подпрограмму и из нее программист организует по своему усмотрению. Для передачи параметров как в одну, так и в другую сторону можно использовать регистры общего назначения, ячейки памяти или стек. Например, нетрудно преобразовать подпрограмму delay из примера 3-8 так, чтобы ей можно было передавать величину требуемой задержки. Пусть эта величина (в числе шагов внешнего цикла) передается в регистре SI.

Пример 3-8а. Подпрограмма задержки с одним параметром, передаваемом в регистре SI

delay proc ;Процедура- подпрограмма

push CX ;Сохраним СХ основной программы

mov CX,SI ;Счетчик внешнего цикла del1: push CX ;Сохраним его mov CX,0 ;Счетчик внутреннего цикла del2: loop del2 ;Внутренний цикл (64К шагов) pop CX ;Восстановим внешний счетчик loop del1 ;Внешний цикл (2000 шагов) pop CX ;Восстановим СХ программы ret ;Возврат в программу

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

Читайте также:
Doc какой программой открыть

Пример 3-8б. Подпрограмма задержки с преобразованием параметра, передаваемого в регистре SI

delay proc ;Процедура-подпрограмма

push AX ;Сохраним все

push BX ;используемые push CX ;в программе push DX ;регистры mov AX,SI ;первый сомножитель в AX mov BX,600 ;второй экспериментально ;подобранный сомножитель mul BX ;Произведение в DX:AX mov CX,AX ;Нам оно нужно в CX del1: push CX ;Сохраним его mov CX,0 ;Счетчик внутреннего цикла del2: loop del2 ;внутренний цикл (64К шагов) pop CX ;Восстановим внешний счетчик loop del1 ;Внешний цикл ( 2000 шагов) pop DX ;Восстановим pop CX ;все сохраненные pop BX ; в начале подпрограммы pop AX ;регистры ret ;Возврат в программу

Эксперименты показали, что для получения правильной задержки значение параметра, обозначающее число секунд, следует умножать на 600. Поскольку при умножении в системе команд МП 86 первый сомножитель должен находиться в регистре АХ, а второй не может быть непосредственным значением и тоже, следовательно, должен быть помещен в один из регистров, и, к тому же, произведение занимает два регистра DX:AX, приходится сохранять при входе в подпрограмму не один регистр, как в предыдущем примере, а 4. Передаваемый в SI параметр переносится в АХ, в ВХ загружается второй сомножитель, а из полученного с помощью команды mul произведения используется младшая часть, находящаяся в АХ. Таким образом, для данного варианта подпрограммы значение задержки не должно превышать 109 с (109 х 600 = 65500, что почти совпадает с максимально возможным значением 65535).
Следует обратить внимание на опасность, подстерегающую нас при выполнении операции умножения. Пусть значение передаваемого параметра составляет всего 5. При умножении на 600 получится число 3000, которое безусловно помещается в регистре АХ. Однако операция умножения 16-разрядных операндов

всегда, независимо от конкретной величины произведения, помещает его в пару регистров DX:AX, и, следовательно, при небольшой величине произведения регистр DX будет обнуляться. Поэтому, хотя мы и не используем старшую часть произведения и фактически ее может и не быть, сохранение и последующее восстановление регистра DX является обязательным.
Передача параметров в подпрограмму через регистры общего назначения или даже через сегментные регистры вполне возможна, однако на практике для передачи параметров чаще всего используют стек, хотя бы потому, что регистров немного, а в стек можно поместить любое число параметров. При этом применяется своеобразная методика работы со стеком не с помощью команд push и pop, а с помощью команд mov с косвенной адресацией через регистр ВР, который архитектурно предназначен именно для адресации к стеку. Преобразуем пример 3-8а так, чтобы единственный в этом примере параметр (условная величина задержки) передавался в подпрограмму не через регистр SI, а через стек. Вызов подпрограммы delay в этом случае должен выполняться следующим образом:

push 2000 ;Проталкиваем в стек значение параметра

call delay ;Вызываем подпрограмму delay

Текст подпрограммы подвергнется значительным изменениям:

Пример 3-8в. Передача параметра через стек

delay proc ;Процедура-подпрограмма

push CX ;Сохраним СХ основной программы

push BP ;Сохраним BP mov BP,SP ;Настроим BP на текущую вершину стека mov CX, [BP+6] ;Скопируем из стека параметр del1: push CX ;Сохраним его mov CX,0 ;Счетчик внутреннего цикла del2 loop del2 ;Внутренний цикл(64К шагов) pop CX ;Восстановим внешний счетчик loop del1 ;Внешний цикл pop BP ;Восстановим BP pop CX ;и СХ программы ret 2 ;Возврат и снятие со стека ;ненужного уже параметра

Команда call, передавая управление подпрограмме, сохраняет в стеке адрес возврата в основную программу. Подпрограмма сохраняет в стеке еще два 16-разрядных регистра. В результате стек оказывается в состоянии, изображенном на рис. 3.9.
После сохранения в стеке исходного содержимого регистра ВР (в основной программе нашего примера этот регистр не используется, однако в общем случае это может быть и не так), в регистр ВР копируется содержимое указателя стека, после чего в ВР оказывается смещение вершины стека. Далее командой mov в регистр СХ заносится содержимое ячейки стека, на 6 байтов ниже текущей вершины. В этом месте стека как раз находится передаваемый в подпрограмму параметр, как это показано в левом столбце рис. 3.8. Конкретную величину смещения относительно вершины стека надо для каждой подпрограммы определять индивидуально,

Рис. 3.8. Состояние стека в подпрограмме после сохранения регистров.

исходя из того, сколько слов сохранено ею в стеке к этому моменту. Напомним, что при использовании косвенной адресации с регистром ВР в качестве базового, по умолчанию адресуется стек, что в данном случае и требуется.
Параметр, полученный таким образом, используется далее в подпрограмме точно так же, как и в примере 3-8а.
Выполнив возложенную на нее задачу, подпрограмма восстанавливает сохраненные ранее регистры и осуществляет возврат в основную программу с помощью команды ret, в качестве аргумента которой указывается число байтов, занимаемых в стеке отправленными туда перед вызовом подпрограммы параметрами. В нашем случае единственный параметр занимает 2 байт. Если здесь использовать обычную команду ret без аргумента, то после возврата в основную программу параметр останется в стеке, и его надо будет оттуда извлекать (между прочим, не очень понятно, куда именно, ведь все регистры у нас могут быть заняты). Команда же с аргументом, осуществив возврат в вызывающую программу, увеличивает содержимое указателя стека на значение ее аргумента, тем самым осуществляя логическое снятие параметра. Физически этот параметр, как, впрочем, и все остальные данные, помещенные в стек, остается в стеке и будет затерт при дальнейших обращениях к стеку.
Разумеется, в стек можно было поместить не один, а сколько угодно параметров. Тогда для их чтения надо было использовать несколько команд mov со значениями смещения ВР+6, ВР+8, BP+0Ah и т.д.
Рассмотренная методика может быть использована и при дальних вызовах подпрограмм, но в этом случае необходимо учитывать, что дальняя команда call сохраняет в стеке не одно, а два слова, что повлияет на величину рассчитываемого смещения относительно вершины стека.

Fore kc .ru
Рефераты, дипломы, курсовые, выпускные и квалификационные работы, диссертации, учебники, учебные пособия, лекции, методические пособия и рекомендации, программы и курсы обучения, публикации из профильных изданий

Источник: www.i-assembler.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru