Параметры–значения и параметры–переменные.




Структура программ в D Pascal

 

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

 

Программы CF Pascal состоят из заголовка, объявления переменных, объявления процедур и тела программы. D Pascal богаче чем CF Pascal и содержит дополнительные возможности как внешние файлы, константы, типы и функции, и это отражает его структура программы. В D Pascal <заголовок программы> и <блок> могут содержать больше элементов, чем в CF Pascal. Синтаксис D Pascal следующий:

 

<программа>::= <заголовок программы>; <блок>.

<заголовок программы>::= PROGRAM <идентификатор> (<список идентификаторов>);

<список идентификаторов>::= <список идентификаторов>, <идентификатор> |

<блок>::= <раздел объявления констант><раздел объявления типов>

<раздел объявления переменных>

<раздел объявления процедур и функций><оператор BEGIN>

<раздел объявления переменных>::= VAR <объявления переменных>; |

<объявления переменных>::= <объявления переменных>, <объявление переменной>

| <объявление переменной>

<объявление переменной>::= <список идентификаторов>: <обозначение типа>

 

Порядок этих частей очень жесткий, но он легко запоминается из требования Паскаля объявлять идентификаторы до использования. Идентификаторы констант, которые объявляются в разделе объявлений констант и могут быть использованы в объявлении диапазонов в разделе объявления типов, объявляются перед типами. Аналогично, объявления переменных должны появиться до использования переменных в процедурах, а процедуры должны быть объявлены до того как они могут быть вызваны в операторе BEGIN.

 

Внешние файлы.

 

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

 

Файлы могут иметь время жизни, как и другие переменные в Паскале, которое определяется временем выполнения программы или временем жизни соответствующего блока, но они могут также продолжать существовать за пределами выполнения программы. Если файловая переменная появляется в заголовке программы, (с INPUT и OUTPUT), файл называется внешним. Содержимое внешнего файла может читаться и записываться Паскаль-программой, но файл может существовать до начала выполнения программы и оставаться после завершения выполнения. Например, в программе

 

PROGRAM FileProcess(INPUT, OUTPUT, ExtFile);

VAR

IntFile, ExtFile: TEXT;

BEGIN

END.

Содержимое файла ExtFile может существовать до выполнения FileProcess и оставаться после выполнения, а содержимое IntFile должно быть создано в FileProcess и будет уничтожено при завершении выполнения. Каждая Паскаль-машина имеет различные способы связывания внешних файлов с именами в файловой системе. Часто идентификатор задает используемое имя, но это может быть и не так из-за ограничений за пределами Паскаль-машины.

 

Внешние файлы могут иметь три разных варианта использования: ввод – предоставление данных программе извне, вывод – сохранение данных, подготовленных данной программой другим программам и изменение – предоставление данных программе для изменения с целью дальнейшего использования.

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

PROGRAM Register(INPUT, OUTPUT, Students);

{добавляет имена в INPUT в Students и сообщает

о дублировании имен в OUTPUT}

VAR

Students, Temp1, Temp2: TEXT;

BEGIN {Register}

{Копировать INPUT в Temp1}

{сортировать имена в Temp1}

{соединить Temp1 и Students в Temp2 –

если имя существует в обоих файлах,

послать в OUTPUT и не дублировать в Temp2}

{копировать Temp2 в Students}

END. {Register}

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

Внешние файлы D Pascal обеспечивают возможность создания, не просто одиночных программ, а программных систем, где программы обмениваются информацией через внешние файлы. Например, другая программа может распечатывать файл Students, скажем, как в следующем разделе проекта:

PROGRAM PrintRegistered(INPUT, OUTPUT, Students);

{печатает имена в Students в OUTPUT}

VAR

Students: TEXT;

BEGIN {PrintRegistered}

{Копировать и форматировать имена из Students в OUTPUT}

END. {PrintRegistered}

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

 

Константы.

 

С помощью именования константных значений программист может изменять эти значения для всей программы без необходимости искать их править в коде.

 

Константные значения могут быть заданы именами с использованием объявлений, как следующие:

CONST

LastCh = ‘#’;

FieldWidth = 4;

Max = 9999;

Min = -Max;

Name = ‘Blaise Pascal’;

Поскольку константный идентификатор, представленный объявлением константы, именует значение, он имеет тот же тип и может появляться везде, где могут встречаться значения этого типа. В следующем примере, использующем приведенное выше объявление констант, Min и Max используются для объявления диапазона, LastCh сравнивается с символьным значением, FieldWidth управляет размером поля в котором распечатываются значения типа SmallInt, Name используется в операторе Write.

TYPE

SmallInt = Min.. Max;

VAR

Value: SmallInt;

Ch: CHAR;

BEGIN

...

WHILE Ch <> LastCh

DO

...

READ(Value);

WRITELN(Value:FieldWidth);

WRITELN(Name);

...

END

Синтаксис для раздела объявлений констант представлен ниже.

 

<раздел объявлений констант>::= CONST <объявления констант> |

<объявления констант>::= <объявления констант> <объявление константы> |

<объявление константы>

<объявление константы>::= <идентификатор> = <константа>;

<константа>::= <знак> <беззнаковое число> | <беззнаковое число>

| <знак> <идентификатор константы> | <идентификатор константы>

| <строка символов>

<идентификатор константы>::= <идентификатор>

 

Контекстное правило, которое сопровождает данные синтаксические правила утверждает, что только <идентификаторы> которые появляются в <объявлении констант> являются <константными идентификаторами>. Эти специальные идентификаторы не могут быть использованы как если бы они были переменными, потому что их значения фиксированы. Например, константный идентификатор не может появляться в левой части оператора присваивания или как фактический параметр, соответствующий формальному VAR параметру.

Константные идентификаторы помогаю документировать программы и облегчают последующие изменения программ. Объявление константы LastCh с фиксированным значением # и использование LastCh вместо литерала ‘#’ улучшает программу. Рассмотрим следующий фрагмент:

CONST

LastCh = ‘#’;

VAR

Ch: CHAR;

BEGIN

WHILE Ch <> LastCh

DO

...

WRITELN(‘Инвентарный #:’)

END

Если мы решили заканчивать входную последовательность другим символом, (например $), нам необходимо всего лишь изменить только объявление соответствующей константы:

CONST

LastCh = ‘$’;

Поиск и замена # на $ по всему телу программы одновременно и утомительно и чревато внесением ошибок. Например, мы по ошибке можем заменить # на $ в последнем операторе WRITE.

 

Типы

 

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

 

Хотя типы данных описывают наборы значений и операции, которые могут быть к ним применимы, объявления типов Паскаля описывают только представление значений. Новые типы объявленные в <разделе объявлений типов> блока связыванием идентификатора (имени нового типа) с описанием его значений (например, списком констант перечислимого типа или границами диапазона). Несколько примеров новых типов представлены ниже:

TYPE

CType = CHAR;

Ct = CType;

Month = (NoMonth, Jan, Feb, Mar, Apr, May, Jun,

Jul, Aug, Sep, Oct, Nov, Dec);

Summer = Jun.. Aug;

DayNum = 1.. 31;

Letter = ‘A’.. ‘Z’;

Идентификаторы как Letter могут встречаться везде, где встречаются в объявлениях списках формальных параметров. Идентификаторы типов – это удобное сокращение – именуя список констант, идентификаторы как Month могут легко повторяться в программе без опасности, что объявление тип может быть задано некорректно.

Синтаксис объявления типа приведен ниже:

 

<раздел объявлений типов>::= TYPE <объявления типов> |

<объявления типов>::= <объявления типов> <объявление типа>

| <объявление типа>

<объявление типа>::= <идентификатор> = <обозначение типа>;

<обозначение типа>::= <идентификатор типа> | <новый тип>

<новый тип>::= <новый порядковый тип>

<новый порядковый тип>::= <перечислимый тип> | <тип диапазон>

 

Одно из наиболее важных направлений использования идентификаторов типов – списки формальных параметров.

 

<список формальных параметров>::= (<формальные параметры>) |

<формальные параметры>::= <формальные параметры>; <формальный параметр>

| <формальный параметр>

<формальный параметр>::= <параметр переменная>

<параметр переменная>::= VAR <список идентификаторов>: <идентификатор типа>

 

Каждый формальный параметр должен быть объявлен с идентификатором типа.

Таким образом, ни один из формальных параметров не в следующем заголовке процедуры не объявлен корректно:

PROCEDURE Proc

(VAR Mo: (NoMonth, Jan, Feb, Mar, Apr, May

b Jun, Jul, Aug, Sep, Oct, Nov, Dec);

VAR Day: 1..31;

VAR Finitial, Linitial: ‘A’.. ‘Z’);

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

TYPE

Month = (NoMonth, Jan, Feb, Mar, Apr, May, Jun,

Jul, Aug, Sep, Oct, Nov, Dec);

DayNum = 1..31;

Letter = ‘A’.. ‘Z’;

PROCEDURE Proc (VAR Mo: Month; VAR Day: DayNum;

VAR Finitial, Linitial: Letter);

Способность объявления новых типов поднимает вопрос эквивалентности типов: когда два типа являются одним и тем же? Многие операции в программе зависят от операндов, имеющих соответствие типов и Паскаль имеет три степени совместимости типов для обработки различных ситуаций: одинаковый, совместимый для присваивания, и совместимый.

Контекстные правила, регулирующие согласование типов, следующие:

1. Фактические параметры должны иметь одинаковые типы, что и соответствующие формальные параметры.

2. Тип переменной в левой части присваивания должен быть совместим для присваивания с типом выражения в правой части.

3. Операнды операций сравнения должны иметь совместимые типы.

В Паскале два типа являются одинаковыми, если они были определены как эквивалентные в объявлениях типов. Переменные имеют одинаковый тип если они объявлены с идентификаторами типов, которые являются одинаковыми, или одинаковый тип объявлен вместе с объявлением переменной. Например, рассмотрим объявления:

TYPE

T1 = INTEGER;

T2 = T1;

SmallInt = 0.. 9;

Age = 0.. 9;

VAR

W: SmallInt;

X: 0..9;

Y, Z: 0.. 9;

Типы INTEGER, T1 и T2 в примере выше являются одинаковыми. SmallInt и Age не являются одинаковыми. Y и Z имеют одинаковый тип, но технически X имеет различный тип.

В следующем фрагменте программы на Паскале, используя выше приведенные объявления, только W может быть передано P, поскольку это единственная переменная тот же типа что и Parm.

PROCEDURE P (VAR Parm: SmallInt);

...

P(W); {допустимо – Parm и W имеют одинаковый тип SmallInt}

P(X); {недопустимо – Parm и X имеют разные типы}

P(Y); {недопустимо – Parm и Y имеют разные типы}

...

Два типа, T1 и T2, совместимы если справедливо следующее:

· T1 и T2 имеют одинаковый тип.

· T1 является диапазоном T2 или T2 является диапазоном T1 или оба типа являются диапазонами одного владеющего типа.

В примере выше, тип X совместим с Y, потому что оба являются диапазонами INTEGER. Переменные Letter и Digit в следующем примере имеют совместимые типы, потому что оба типа определяют диапазон одного владеющего типа CHAR.

VAR

Letter: ‘A’.. ‘Z’;

Digit: ‘0’.. ’9’;

BEGIN

...

IF (Digit <= ‘0’) OR (Digit = Letter)

...

END

Таким образом, Digit может быть сравнена с константой ‘0’ типа CHAR и с Letter.

Значение типа T2 совместимо для присваивания с типом T1. если выполняется одно из следующих условий:

· T1 и T2 имеют одинаковый тип (но не файловый тип)

· T1 и T2 совместимые порядковые типы и значение типа T2 лежит в интервале возможных значений T1.

 

В следующем примере только первые два оператора присваивания допустимы.

 

TYPE

SmallInt = 0.. 99;

SmallerInt = 0.. 9;

VAR

X: SmallInt;

Y: SmallerInt;

BEGIN

X:= 0; {Тип X (SmallInt) совместим с типом 0 (INTEGER)

и 0 лежит в интервале возможных значений типа

SmallInt}

Y:= X; {Тип Y (SmallerInt) совместим с типом X

(SmallInt) и значение X (0) лежит в интервале

возможных значений типа SmallerInt}

Y:= X - 1; {Тип Y (SmallInt) совместим с типом 0 (INTEGER)

и 0 лежит в интервале возможных значений типа

SmallInt}

END

 

Параметры–значения и параметры–переменные.

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

 

Существует две разновидности формальных параметров в D Pascal: параметры-переменные и параметры-значения. В объявлении процедуры параметры-переменные выглядят как объявления переменных. Они начинаются ключевым словом VAR, за которым следует список идентификаторов, разделенных запятыми, которые являются именами формальных параметров, двоеточие и идентификатор, определяющий тип параметра. Параметры-значения определяются как параметры-переменные, за исключением того, что ключевое слово VAR пропускается. В следующем примере VarParm – формальный параметр-переменная типа T, а ValParm – формальный параметр-значение типа T.

 

PROCEDURE P (VAR VarParm: T; ValPrm: T);

 

Синтаксические правила, описывающие параметры:

 

<формальный параметр>::= <параметр-переменная> | <параметр-значение>

<параметр-переменная>::= VAR <список идентификаторов>: <идентификатор типа>

<параметр-значение>::= <список идентификаторов>: <идентификатор типа>

 

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

 

Часто параметры используются только для передачи значений. Значение в вызывающий код через эти параметры не возвращается. Такие исключительно входные параметры, должны быть объявлены как формальные параметры-значения для различения их с формальными параметрами-переменными, которые используются как выходные или входные-выходные параметры. Когда фактический параметр связан с формальным параметром-значением, значение фактического параметра присваивается формальному параметру, но ссылка не устанавливается. Таким образом, любые присваивания значений формальному параметру в блоке процедуры изменяют его значение, но не значение фактического параметра.

 

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

 

Разница между параметрами-переменными и значениями видна в программе VarVsValue.

 

PROGRAM VarVsValue(OUTPUT);

VAR

A, B: INTEGER;

PROCEDURE Bump (VAR VarF: INTEGER; ValF: INTEGER);

BEGIN {Bump}

VarF:= VarF + 1;

ValF:= ValF + 1;

WRITELN(VarF, ValF)

END; {Bump}

BEGIN {VarVsValue}

A:= 0;

B:= 0;

Bump(A, B);

WRITELN(A, B)

END. {VarVsValue}

Выполнение:

OUTPUT: 1 1

1 0

Bump добавляет 1 к каждому формальному параметру, так что оба ValF и VarF имеют значение 1 в конце процедуры. Однако, изменения сделанные с формальными параметрами в Bumpпоявляются только в фактическом параметре, который связан с формальным параметром-переменной и не происходят в фактическом параметре, который был связан со значением формального параметра-значения. А имеет значение 1 в конце блока программы, а B сохранило свое значение, которое она имела до выполнения процедуры.

Значение вызова процедуры параметрами-переменными представлено в главе 9 может быть расширено для работы с параметрами-значениями. Формальные параметры-значения добавляются и удаляются из состояния выполнения аналогично локальным переменным процедуры. После того как формальный параметр-значение добавлен в состояние выполнения, новая переменная связывается с текущим значением фактического параметра.

В объявлении:

PROCEDURE P (Y: Typ);

T;

Тело T добавляется в состояние выполнения как значение идентификатора P. Тогда значение процедурного оператора

P(E)

будет

P(E)(s) = VAR Y: Typ ◦ Y:= E ◦ s(P) ◦ VAR Y: TypT

Если бы здесь были параметры-переменные или конфликт имен локальных и глобальных идентификаторов, они должны были бы модифицированы в s(P) как описано в разделах 9.1.4 и 9.2.5 соответственно.

Это определение может быть использовано для вычисления значения вызова Bump в VarVsValue. Начальное состояние будет:

{OUTPUT·<††, ††, W>}

Далее значение функции программы будет

VAR A, B: INTEGER ◦

BEGIN A:= 0; B:= 0’; Bump (A, B);WRITELN(A, B) END ◦

VAR A, B: INTEGERT ◦. ({OUTPUT·<††, ††, W>}) =

VAR A, B: INTEGER ◦

BEGIN A:= 0; B:= 0’; Bump (A, B);WRITELN(A, B) END ◦

VAR A, B: INTEGERT ◦. ({OUTPUT·<††, ††, W>, A·?, B·?}) =

Bump (A, B);WRITELN(A, B) ◦ VAR A, B: INTEGERT

. ({OUTPUT·<††, ††, W>, A·0, B·0})

Процедурный оператор расширяется до серии композиций функций, которые применяют функцию, соответствующую объявлению ValF, присваиванию значения B ValF, тела Bump, где вхождения A заменяются на VarF и транспозицию объявления ValF.

 

Функции.

 

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

 

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

FUNCTION Max2(P1, P2: INTEGER): INTEGER;

{(P1 > P2 --> Max2:= P1) | (P2 >= P1 --> Max2:= P2)}

BEGIN {Max2}

IF P1 > P2

THEN

Max2:= P1 {возвращаем P1 как значение Max2}

ELSE

Max2:= P2 {возвращаем P2 как значение Max2}

END; {Max2}

Синтаксические правила для объявления функции представлены ниже:

<раздел объявления функций/процедур>::= <объявления функций/процедур> |

<объявления функций/процедур>::= <объявление функции/процедуры>

| <объявления функций/процедур> <объявление функции/процедуры>

<объявление функции/процедуры>::= <заголовок>; <блок>;

<заголовок>::= PROCEDURE <идентификатор> <список формальных параметров>

| FUNCTION <идентификатор> <список формальных параметров>: <тип результата>

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

FUNCTION Max3(P1, P2, P3: INTEGER): INTEGER;

{Max3 присваивается наибольшее значение из P1, P2, P3}

VAR

T: INTEGER;

BEGIN {Max3}

T:= Max2(P2, P3);

Max3:= Max2(P1, T);

END; {Max3}

Когда Max2 вызывается первый раз, она возвращает наибольшее из P2, P3, которое присваивается T. Далее T используется как фактический параметр во втором вызове Max2. Поскольку вызовы функций могут появляться везде, где появляются выражения, а параметры Max2 являются параметрами-значениями, Max3 может быть переписана так, что первый вызов Max2 будет параметром в ее втором вызове.

FUNCTION Max3(P1, P2, P3: INTEGER): INTEGER;

{Max3 присваивается наибольшее значение из P1, P2, P3}

BEGIN {Max3}

Max3:= Max2(P1, Max2(P2, P3));

END; {Max3}

Выражение в операторе присваивания будет вычислено сначала вызовом Max2 для получения максимума P2, P3 и далее вызовом Max2 с P1 и результатом предыдущего вызова.

 

Следующие синтаксические правила включают вызовы функций в синтаксис выражений добавлением и к <множителю>.

 

<множитель>::= <переменная> | <вызов функции>

|<беззнаковая константа> | (выражение) | NOT <множитель>

<вызов функции>::= <идентификатор функции> <список фактических параметров>

<идентификатор функции>::= <идентификатор>

<список фактических параметров>::= (<список фактических параметров>) |

<список фактических параметров>::= <список фактических параметров>,

<фактический параметр> | <фактический параметр>

<фактический параметр>::= <выражение>

 

Заметим, что <список фактических параметров> может быть пустым – функция может не иметь параметров.



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-04-12 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: