Процедуры и функции TMT Pascal
Процедуры - это последовательность команд. Процедуры являются отдельными
блоками кода. Функции - это процедуры, которые возвращают
значение. Кроме этого процедуры ни чем не отличаются от
функций.
Процедуры - блоки кода, которые вызываются из одного или более мест
вашей программы. Процедуры делают исходный текст более читаемым и
уменьшают размер исполняемой программы, потому что повторяющиеся блоки
кода заменяются запросом к процедуре. И процедуры и функции принимают
параметры. Параметры позволяют вызывающей программе связываться с
процедурой.
Параметры могут проходить как значение или как ссылка или как константа.
Если параметры проходят как значение, то используется только
значение параметра и
процедура не имеет доступа к фактической переменной. Можно
изменять значение параметра. Это будет иметь эффект только внутри тела
процедуры и не будет изменять фактическую переменную.
Если параметры проходят ссылкой (параметры
Var), то
проходит адрес местоположения памяти, содержащего значение, таким
образом делая возможным изменить переменную.
Если проходит константа (параметры
Const),
то проходит адрес местоположения памяти, содержащего значение, но
компилятор не позволяет изменять постоянный параметр и не позволяет
проходить ему как фактическому параметру переменной для другой
процедуры или функции.
Описание Процедур и Функций
Предварительное объявление процедур
Внешние процедуры
Процедура обработки прерываний
Процедурная величина
Использование операторов в качестве процедур
Описание Процедур и Функций
Процедуры и функции имеют следующую форму:
procedure Идентификатор [(СписокПараметров)];
или
function Идентификатор [(СписокПараметров)] : ВозвращаемыйТип;
ВозвращаемыйТип - это тип возвращаемого функцией значения.
СписокПараметров определяется как:
Параметр [;Параметр]
где Параметр - это:
[var] Идентификатор [,Идентификатор] [: ИмяТипа]
или
[const] Идентификатор [,Идентификатор] [: ИмяТипа]
var определяет переменный параметр.
const определяет
постоянные параметры. Параметры
var и
const проходят
ссылкой, в отличие от прошедших значением.
Тело процедуры или функции имеет следующую форму:
[Описание]
begin
Оператор [;Оператор]
end;
Типы, метки, константы и переменные, объявленные в разделе
Описаниe
перед ключевым словом
begin - это локальные переменные. Место
для этих переменных выделяется только тогда, когда вызывается
процедура. Подобно всем описаниям переменных их данные не определены
пока они не инициализированы. Процедуры и функции TMT Pascal могут
вызываться рекурсивно.
Все идентификаторы должны быть объявлены перед ссылкой на них. То же
самое правило относится к процедурам и функциям.
Предварительное объявление процедур
Слово
Forward используется, чтобы определить процедуру до ее
полного описания.
Forward сообщает TMT Паскалю, что
описание появится далее в программе. Предварительное описание
процедуры имеет следующую форму:
ИмяПроцедуры; forward;
Внешние процедуры
Слово
External используется, чтобы определить процедуру,
которая связана с внешним объектом.
Пример:
;----------------- [vga.asm] ----------------
IDEAL
P386
MODEL FLAT,PASCAL
CODESEG
GLOBAL SETVIDEOMODE: PROC
PROC SETVIDEOMODE USES EAX, MODE: WORD
MOV AX, [MODE]
INT 10H
RET
ENDP SETVIDEOMODE
GLOBAL CLEARVGA: PROC
PROC CLEARVGA USES ECX, COLOR: BYTE
MOV EDI, 0A0000H
MOV AL, [COLOR]
MOV AH, AL
MOV ECX, EAX
SHL EAX, 16
MOV AX, CX
MOV ECX, 64000/4
CLD
REP STOSD
RET
ENDP CLEARVGA
END
;--------------------------------------------
///////////////// [Test.pas] ////////////////
program Test;
{$ifndef __DOS__}
Эта программа должна компилироваться только для MSDOS
{$endif}
uses CRT;
{$l vga} // подключение файла vga.obj
procedure SetVideoMode(Mode: Word); external;
procedure ClearVGA(Color: Byte); external;
begin
SetVideoMode($13); // установка режима VGA/MCGA 320x200
ClearVGA(10); // заполнение экрана зеленым цветом
ReadKey; // ожидание нажатия клавиши
ClearVGA(15); // заполнение экрана белым цветом
ReadKey; // ожидание нажатия клавиши
ClearVGA(0); // заполнение экрана черным цветом
ReadKey; // ожидание нажатия клавиши
SetVideoMode($03); // установка текстового режима VGA 80x25
end.
/////////////////////////////////////////////
См. также: Динамически подключаемые библиотеки (DLL)
Процедура обработки прерываний
В TMT Паскале пункт
Interrupt определяет процедуру, которая
должна использоваться как программа обработки прерываний.
Параметры процедуры обработки прерываний - регистры ЦЕНТРАЛЬНОГО
ПРОЦЕССОРА. Порядок регистров ЦЕНТРАЛЬНОГО ПРОЦЕССОРА:
EFLAGS, CS,
EIP, EAX, EBX, ECX, EDX, ESI, EDI, DS, ES, EBP. Если этим
регистровым переменным присвоить новое значение, то после завершения
прерывания новые значения будут записаны в фактические регистры
ЦЕНТРАЛЬНОГО ПРОЦЕССОРА.
Описание:
procedure IntProc(used registers); interrupt;
В качестве примера приведем простой метод работы с обработчиками
прерываний.
program Timer1;
uses Dos, Crt;
var
Int1CSave: FarPointer;
Time: LongInt;
// TimerHandler
procedure TimerHandler; Interrupt;
var
StoreX, StoreY: Word;
begin
Inc(time);
StoreX:= WhereX;
StoreY:= WhereY;
GotoXY(1,1);
Write(time);
GotoXY(StoreX, StoreY);
Port[$20] := $20;
end;
begin
ClrScr;
Time := 0;
GetIntVec($1C, Int1CSave);
SetIntVec($1C, @TimerHandler);
Writeln;
Writeln('Type something and press "ENTER" to exit');
Readln;
SetIntVec($1C, Int1CSave);
end.
Важно! При использовании
Intr()
и MS DOS() имейте в виду, что программы обработки прерывания DOS
могут иметь дело только с адресами в пределах 1 мегабайта памяти.
Процедурная величина
TMT Паскаль имеет понятие процедурной величины. Это дает возможность
использовать процедуру или функцию в программе как обычный простой
объектный тип, такой как перечисляемый тип или тип поддиапазона.
Можно объявлять переменную процедурного типа, присваивать ей значение,
и вызывать тело процедуры.
Процедурная величина, осуществленная в TMT Паскале занимает 8 байтов
памяти и состоит из двух частей: точка входа к процедуре и ссылка к
локальному окружению процедуры (известная как основа процедуры). Формат
процедурного значения следующий:
0 +-----------------------+
¦ Точка входа ¦
4 +-----------------------¦
¦ Локальное окружение ¦
8 +-----------------------+
Первая часть необходима для вызова процедуры. Вторая часть
используется, чтобы обратиться к процедурным переменным.
Такой формат процедурной величины несовместим с форматом Borland
Pascal, который имеет только точку входа.
Кроме того, структура границы стека и параметр, пропускающий
соглашения, отличаются от принятых в Borland Pascal.
Таким образом, подход, используемый в TVision и CLassLib для записи
итераций не может использоваться. Однако мы предлагаем этот правильный
и надежный (и более стандартный) путь:
type list = object
next: ^list;
procedure for_all (procedure body (var v));
end;
procedure list.for_all;
var p: ^list;
begin
p := @self;
repeat
body (p);
p := p^.next;
end;
end;
...
type int_list = object (list)
value: integer;
function first_positive: ^int_list;
end;
function int_list.first_positive;
label OK;
var res: ^int_list;
procedure do_item (var v);
begin
if int_list (v).value > 0 then
begin
res := @v;
goto OK;
end
end;
begin
res := nil;
for_all (do_item);
OK:
first_positive := res;
end;
...
Процедурная величина из метода объекта может быть получена при выборе
этого метода из некоторого значения объекта (не от типа). Параметры
этой процедурной величины должны соответствовать параметрам метода.
Обращение такой процедурной величины - обращение соответствующего
метода объекта. Ссылка к объекту передается через основу процедурной
величины.
Вы можете использовать только глобальные процедурные величины для
инициализации типизированной константы.
Процедурные величины могут использоваться только в том окружении, где
они были сформированы и находятся. Таким образом,
- для локальных процедур - до выхода из блока, в котором они описаны;
- для методов - до тех пор, пока существует основной объект.
Использование операторов в качестве процедур
В TMT Pascal Вы можете использовать любой оператор как тело процедуры,
кроме оператора присваивания и вызова процедуры.
Переменная RESULT в теле таких функций обозначает переменную, которая
содержит возвращаемое значение. RESULT - это тип возвращаемой функции
и может использоваться как переменная без каих-либо ограничений.
С TMT Pascal Вы можете вводить тело процедуры непосредственно как
параметр процедуры. Процедура или заголовок функции (если не указан)
принимает параметр процедурного типа. Если заголовок процедуры
определен, имя процедуры пропускается.
Пример:
function Integral(function f(a: Real):Real; low, high, step: Real): Real;
begin ... end;
...
Writeln(integral (
function(x: Real): Real; begin Result := sqrt(x) end, 0, 10, 0.1));
Writeln(integral(begin Result := sqrt(a) end, 0, 10, 0.1));
Writeln(integral(
function; // необходимо ключевое слово function
var x: Real; // для локального описания
begin x := sqrt(a); Result := x end, 0, 10, 0.1)
);
Writeln(integral(
declare; // другой путь
var x: Real; // для описания локальной переменной
begin
x := sqrt(a);
Result := x
end, 0, 10, 0.1)
);
TMT Pascal допускает выход из локальной процедуры к той, которая
содержит эту процедуру. Эта особенность имеется в стандарте ANSI Pascal,
но отсутствует в Borland Pascal. Вместе с процедурными значениями,
это очень полезно для обработки ошибки:
program Test;
var
on_eof: procedure;
function read_char: char;
var c: char;
begin
if Eof (Input) then on_eof;
Read(c);
Read_char := c;
end;
procedure MyProc;
label eof_reached;
procedure go_eof;
begin
goto eof_reached;
end;
begin
on_eof := go_eof;
while True do Write (read_char);
Eof_reached:
writeln ('*** EOF ***');
on_eof := nil;
end;
begin
MyProc;
end.
Ограничение. Операторы
Break и
Continue не могут
использоваться для выхода из процедуры. Используйте
Goto вместо них.
Пример:
{ неправильный пример }
for i := 1 to 10 do
Writeln (
integral( // из предыдущего примера
if a < 0
then break // неправильно
else result := sqrt (a),
i, i + 1, 0.01)
);
{ правильный пример }
declare
label L;
begin
for i := 1 to 10 do Writeln (
integral(
if a < 0
then goto L // правильно
else result := sqrt (a), i, i + 1, 0.01)
);
Функции могут возвращать любые значения любого типа, включая
структуры и массивы.