Пример настоящей программы для компьютера на языке Лого 16 > Последовательность работы программиста на компьютере 17 > Основные приемы программирования 18 Глава. 2 Устройство и работа компьютера 21

Вид материалаДокументы

Содержание


Глава .3Строгости Паскаля
3.1.Структура программы
BEGIN WriteLn(1993); WriteLn(1994) END.
CONST k = 10; VAR
PROGRAM и в простейшем случае имени программы. Пример программы: PROGRAM
3.2.Структура процедур и функций
Hard входят процедура a1
3.4.Совместимость типов
VAR a: Byte; b: Word
VAR a: Integer; b: Word
3.5.Форматы вывода данных
Real всегда изображаются в неудобочитаемом экспоненциальном виде. Например, после выполнения фрагмента r:=465.28073; WriteLn(r)
3.6.Переполнение ячеек памяти
3.7.Дерево типов
3.8.Синтаксисические диаграммы Паскаля
Подобный материал:
1   ...   13   14   15   16   17   18   19   20   ...   25

Глава .3Строгости Паскаля


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

3.1.Структура программы


Самая маленькая программа на Паскале имеет такой вид:

BEGIN END.

Она, естественно, ничего не делает. Если мы хотим заставить программу что-то делать, то все операторы, приказывающие выполнять нужные нам действия, мы должны записать между BEGIN и END. Например:

BEGIN WriteLn(1993); WriteLn(1994) END.

Обычно программа содержит переменные, константы, обращения к подпрограммам и прочие элементы. Все они должны быть описаны выше BEGIN. Например:

CONST k = 10;

VAR a : Real;

BEGIN

a:=5;

WriteLn(a+k)

END.

Таким образом, программа на Паскале состоит из двух и только двух разделов:

  1. выше BEGIN расположен раздел описаний,
  2. ниже BEGIN расположен раздел выполняемых операторов.

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


Приведем полный список служебных слов, после которых задаются описания:
  • Переменные описываются после служебного слова VAR
  • Метки описываются после служебного слова LABEL
  • Константы описываются после служебного слова CONST
  • Процедуры описываются после служебного слова PROCEDURE
  • Функции описываются после служебного слова FUNCTION
  • Новые типы, определяемые программистом,

описываются после служебного слова TYPE

Если программа на Паскале использует модули, то они должны быть перечислены выше раздела описаний после служебного слова USES.

И наконец, программа может иметь заголовок, который состоит из служебного слова PROGRAM и в простейшем случае имени программы.

Пример программы:

PROGRAM Divan;

USES Crt,Graph;

Label met1,met2;

Const k = 100;

S = 'Хорошо!';

TYPE Kniga = array [1..k] of String;

Tablitsa = array [0..20,1..10] of Integer;

Minuta = 0..60;

VAR x,y : Real;

Uspevaemost : Tablitsa;

PROCEDURE Torpeda......

FUNCTION Invers......

begin

.......

end.

3.2.Структура процедур и функций


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

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

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

Приведу пример записи программы с вложенными подпрограммами:

PROGRAM Hard;

Uses ...

Label ...

Const ...

Type ...

Var ...

Procedure a1;

Const ...

Var ...

Procedure a11;

Label ...

Type ...

Var ...

begin

...

end;

Function f11

Var ...

begin

...

end;

begin

...

end;

Function f2;

Procedure a21;

begin

...

end;

begin

...

end;

begin

...

end.

Здесь в программу Hard входят процедура a1 и функция f2. В процедуру a1 вложены процедура a11 и функция f11. В функцию f2 вложена процедура a21.

Из f2 видна a1, но не видны a11 и f11. Точно так же из a21 видны a1 и f2, но не видны a11 и f11. Это значит, что в теле процедуры a21может содержаться вызов a1и f2, но не может содержаться вызов a11и f11.

3.3.Выражения


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

a := b+1 - здесь выражение - b+1

if c-6>f then … - здесь выражение - c-6>f

WriteLn (a+5) - здесь выражение - a+5


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

Арифметические выражения (то есть имеющие значением число):
  • 0
  • 2+5
  • Sqrt(b+1) - Sqr(a[4,i]+r) + 1
  • a[4,i] + vovka.ves
  • ((w+b)/19)*(2/(w+1)+5)


Строковые выражения (то есть имеющие значением строку символов):
  • ‘Весна’
  • Copy(s,a,b)
  • Copy(s,a,b)+ ‘Весна’


Логические выражения (то есть имеющие значением true или false):
  • a>0
  • (a+c)/(d+8)<=b+1
  • c>’Ю’
  • stroka=‘Весна’
  • Copy(s,a,b)+ ‘Весна’ <> s1
  • a in b


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

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

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

3.4.Совместимость типов


Часто при запуске программы Паскаль выдает сообщение Type mismatch (несовместимость типов) и на этом основании отказывается выполнять программу. Так произойдет, например, при выполнении ошибочного фрагмента VAR y: Integer BEGIN y:=3/8: …., так как результат деления получается вещественный, а переменная y описана, как Integer. Нам нужно знать о том, какие типы совместимы, а какие нет.

Тип выражения с операндами разных типов. Что будет, если в одном выражении участвуют величины разных типов? Какого типа будет результат выражения? Например, какого типа будет сумма a+b в следующем фрагменте:

VAR a: Byte; b: Word;

BEGIN .... a+b ... ?

Вот ответ - Если осуществляется операция над двумя величинами разных типов, то перед выполнением операции они преобразуются к общему типу и только затем операция выполняется. Общий тип определяется так:
  • Если диапазон одного из типов входит в диапазон другого, то общим типом становится тип с большим диапазоном. В приведенном выше примере значение переменной a будет преобразовано к типу Word и полученная сумма также будет иметь этот тип.
  • Если диапазоны типов пересекаются, то общим типом становится ближайший тип, “охватывающий” оба типа.

В примере

VAR a: Integer; b: Word;

BEGIN .... a+b ...

значения a и b перед суммированием преобразуются к типу LongInt.
  • Если один из типов вещественный, а другой целочисленный, то общий тип - всегда вещественный.

Когда в выражение входит несколько операндов (например, a+b*c) то указанные правила применяются последовательно, пока не будет вычислено все выражение (сначала определяется тип произведения b*c и произведение вычисляется, затем исходя из получившегося типа определяется тип суммы и сумма вычисляется).

Требования к типам в операторе присваивания. Чтобы Паскаль мог выполнить оператор присваивания, тип переменной в левой части (тип 1) и тип выражения в правой части (тип 2) должны друг другу соответствовать по определенным правилам:
  • эти типы должны быть одинаковы
  • или, если эти типы не одинаковы, то диапазон типа 1 должен включать в себя диапазон типа 2, например:

Тип 1 Тип 2

(sun, mon, tue, wen) (sun, mon, tue)

String Char
  • или тип 1 - вещественный, тип 2 – целочисленный


Требования к совместимости типов формальных и фактических параметров процедур и функций. Эти требования зависят от того, о каких параметрах идет речь – о параметрах-переменных или параметрах-значениях. В первом случае требование простое – типы должны быть эквивалентны. Во втором случае действуют требования к типам в операторе присваивания, где тип 1 – формальный параметр, тип 2 – фактический.

3.5.Форматы вывода данных


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

c:='Ф'; s:='хорошо'; i:=18; WriteLn(c,s,i)

мы увидим в строке экрана

Ф

х

о

р

о

ш

о

1

8



















Мы можем приказать Паскалю отводить под каждое данное столько позиций в строке, сколько нам нужно: WriteLn(c:3,s:8,i:4)

Вот что мы увидим в строке экрана:







Ф







х

о

р

о

ш

о







1

8





































Здесь под c отведено поле в три позиции (с 1 по 3), начиная с левого края экрана. Под s отведено поле в 8 позиций (с 4 по 11). Под i отведено поле в 4 позиции (с 12 по 15). Информацией заполняется правая часть поля, а левая часть может остаться пустой.

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

r:=465.28073; WriteLn(r)

мы увидим на экране




4

.

6

5

2

8

0

7

3

0

0

0

0

2

3

1

E

+

0

0

0

2
















что означает 4.65280730000231 * 102 или, что то же самое, 465.280730000231. Обратите внимание на откуда-то взявшиеся цифры 231. Их появление связано с неточностью представления вещественных чисел в компьютере.

Еще один пример: r:=0.000000308; WriteLn(r)




3

.

0

8

0

0

0

0

0

0

0

0

0

0

7

9

E

-

0

0

0

7
















что означает 3.08000000000079 * 10-7 или, что то же самое, 0.000000308000000000079 .

Еще пример: r:= -0.000003; WriteLn(r)

-

2

.

9

9

9

9

9

9

9

9

9

9

9

9

5

3

E

-

0

0

0

6
















что означает -2.99999999999953 * 10-6 или, что то же самое, -0.00000299999999999953, а это практически равно -0.000003.

Как избавиться от экспоненциального вида? Формат :9:3 прикажет Паскалю изобразить число типа Real в привычном для нас виде, отведя под него 9 позиций в строке, из них 3 позиции под дробную часть числа. Пример:

r:=465.28073; WriteLn(r:9:3)







4

6

5

.

2

8

1























































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

Еще пример: r:=465.28073; WriteLn(r:10:0)






















4

6

5




















































Еще пример: r:= -465.28073; WriteLn(r:10)

-

4

.

7

E

+

0

0

0

2




















































Это у нас получился вывод в "укороченном" экспоненциальном формате.

3.6.Переполнение ячеек памяти


После выполнения программы

VAR i:Byte;

BEGIN i:=250; WriteLn(i); i:=i+10; WriteLn(i) END.

мы увидим на экране числа 250 и 4. А почему не 250 и 260? Потому что тип Byte представляет только числа от 0 до 255. Если в процессе выполнения программы значение переменной вышло за диапазон своего типа, Паскаль не замечает ошибки, а в соответствующей ячейке оказывается ерунда. Это касается всех типов. Впрочем, ценой некоторой потери скорости Паскаль можно легко настроить на проверку выхода за диапазон (см. приложение).

3.7.Дерево типов


Паскаль предоставляет солидные возможности для конструирования новых типов. Так, если мы пишем VAR a : array[1..10] of array [2..5] of set of Byte, то имеем в виду, что переменная a является массивом array[1..10], который сконструирован из массивов array [2..5], каждый из которых сконструирован из элементов, являющихся множествами set, каждое из которых сконструировано из элементов типа Byte.

Схема, приводимая ниже, демонстрирует, какие типы из каких можно конструировать. Например, файлы можно конструировать из строк, а записи из массивов. А вот множества из вещественных чисел конструировать нельзя.





3.8.Синтаксисические диаграммы Паскаля


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

Есть два самых распространенных способа записи синтаксиса. С одним из них я вас познакомил в 1.2, другой использует так называемые синтаксические диаграммы. Здесь я буду использовать второй метод плюс еще третий - обычный словесный (когда понятность будет достаточным возмещением за нестрогость).

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




Пользоваться синтаксической диаграммой нужно так. Заходите в диаграмму по стрелке. Оказавшись внутри «домика», записывайте на лист бумаги в строчку то, что там указано. Предположим, в нашем случае вы зашли в «букву». Значит, записывайте любую букву, например, N. Затем продолжайте путешествие строго по стрелкам. Оказавшись на развилке, поворачивайте в любую сторону, разрешенную стрелками. Снова оказавшись в «домике», приписывайте справа в строчку то, что там указано. Пусть, например, следующий ваш домик «цифра». Вы должны приписать справа к букве любую цифру, например, 8. Получится N8. И так далее. Когда надоест, добирайтесь до выходной стрелки. Вы гарантированно получите правильное имя.

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

Также во избежание затемнения смысла подробностями диаграммы будут не везде до конца конкретны. Например, в диаграмме имени я писал “буква”, а надо было – “латинская буква”.








































Опережающее описание процедуры или функции см. в 6.6









































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