===== Основные понятия ===== FIXME == Структура программы == Общая структура программы на языке Паскаль задана жёстко и выглядит так: Program <правильное имя>; // Предложение, содержащее **заголовок программы**. // Данное предложение может отсутствовать, поскольку в // используемой нами системе Free Pascal // и большинстве (во всех?) современных версий Паскаля // никакой роли не играет. // Оно оставлено для совместимости с другими версиями // языка, которые его требуют. // Например: Program ChoiseSort3v; // Предложения заканчивается точкой с запятой Uses <список подключаемых библиотек>; // **Раздел импорта**, // который всегда состоит из одного предложения! // Данное предложение может отсутствовать, если вы не // используете никаких дополнительных библиотек. // Например: Uses CRT, OGLgraph; // Список разделяется запятыми, // предложения заканчивается точкой с запятой <Раздел описаний> // Раздел глобальных описаний может состоять из нескольких // подразделов, порядок следования которых - свободный, // но все они должны быть здесь - перед кодом. // // Этот раздел содержит описание всего, что // не задано изначально, // не импортируется из библиотек, // не является локальным объектом внутри процедуры. // А именно - именованные константы, пользовательские типы, // переменные и наконец - имена меток. // // В принципе, этот раздел тоже может отсутствовать. Begin // Обязательные операторные скобки Begin-end <Раздел кода> // Операторы, составляющие "главную процедуру" // Чисто теоретически, их тоже может не быть! // Тогда программа честно ничего не делает. // Но "скобки" должны быть. End. // Программа кончается точкой Текст в **угловых скобках** (символы < и >) требует замены "по смыслу". Не путайте с **операциями** < и >! Ещё раз обратите внимание на жёсткий порядок следования частей программы на этом уровне детализации её структуры. Все части идут именно в этом порядке и не повторяются. Но некоторые могут отсутствовать совсем. == Раздел описаний == Раздел описаний может состоять из нескольких подразделов, разбитых по категориям описываемых объектов - типов, переменных, меток и констант. Отдельными подразделами считаются каждая функция или процедура. const // Начался раздел констант n = 10; // Описание (именованной) константы var // Начался раздел глобальных переменных, // значит - закончился раздел констант i, j : integer; // 1-е описание переменных r, q : real; // 2-е описание переменных k, m : integer; // 3-е описание переменных - снова integer. // Имеем право. Begin // Обязательный раздел кода ... End. // Конец всему (в этой программе)! Объекты программы могут быть связаны описанием. const n = 10; // Константа n определяет длину массива type Arr10 = array[1 .. n] of integer; // Используя n, описываем целый тип массивов var A,B : Arr10; // Используем описание типа Arr10 для описания переменных A, B Запомните правило - **если что-то, описываемое вами, ссылается на что-то другое, то это другое должно быть описано заранее**. Например, если вы используете константу для описания массива (как в примере), то она должна быть описана выше по коду. Из этого правила есть единственное исключение, связанное с использованием указателей. Учтите, что библиотечные объекты, т.е. объекты системные или описанные в библиотеках, подключённых с помощью //uses//, описывать не надо и на них можно ссылаться из любого места. Но, как мы узнаем позже, их имена можно "перекрыть"! Ниже приведён неправильный код, где ничего не описывается заблаговременно. var A,B : Arr10; // А что это? type Arr10 = array[1 .. n] of integer; // И сколько же это будет? const n = 10; В раздел описаний может входить несколько "однотипных" подразделов описаний. var i, j : integer; // Описали часть переменных const n = 10; // Спохватились и описали константу n var A,B : array[1 .. n] of integer; // "Дописали" ещё часть переменных === Полный пример === Подразделы могут следовать в любом порядке и повторяться. В примере приводится "канонический" порядок следования подразделов - именованные константы, типы, переменные. За ними часто следуют описания одной или нескольких процедур и функций, которых в примере нет. Затем порядок может повториться. Это делается, чтобы разбить все объекты, используемые в программе "по смыслу" - типы, определённые пользователем, процедуры, работающие с этими типами и вспомогательные объекты - константы и служебные переменные. Метки описываются там, где это удобно. ... // Здесь могли бы быть заголовок и раздел импорта const // Начался 1-й раздел констант Pi = 4.0; // Описание (именованной) константы // Внимание - мы перекрыли системное определение Пи! var // Начался 1-й раздел глобальных переменных, // значит - закончился раздел констант i, j : integer; // 1-е описание переменных r, q : real; // 2-е описание переменных k, m : integer; // 3-е описание переменных - снова integer. Имеем право. const // Начался 2-й раздел констант n = 10; // Описание (именованной) константы type // Начался раздел типов A10 = array[1..n] of integer; // Это тип, определённый пользователем. // Обратите внимание - мы использовали // ранее описанную константу var // Начался раздел переменных, закончился раздел типов A,B : A10; // 4-е описание переменных пользовательского типа A10 ... // Что-то ещё, возможно - ничего // Где-то здесь кончается раздел переменных label // Раздел меток нужен редко 1, endOfAll; // список объявленных меток // Теперь это "законные" метки ... // Что-то ещё, возможно - ничего Begin // Обязательный раздел кода ... End. // Конец всему (в этой программе)! == Примеры программ нелепых, но синтаксически грамотных == Данная программа содержит только раздел кода, но он - пуст, так что программа самым честным образом ничего не делает. Ибо и не должна. Begin // Если убрать этот комментарий, то получится // минимальная правильная программа на Паскале // Впрочем, для Паскаля его и нет. End. Данная программа действительно работает (стирает с экрана следы работы предыдущих программ), но не содержит ни одного описания. Её реальный аналог есть, например, в операционной системе ДОС. Uses CRT; // без CRT не будет работать clrscr ("clearscreen") Begin clrscr; // команда очищает экран от результатов предыдущих вводов/выводов End. В данной программе есть все разделы (кроме описания функций), но она не выполняет никаких полезных действий. Program Prog; // К бессмысленному предложению Program - бесполезное, но правильное имя // Всё есть и никто ничего не делает. Uses CRT, Graph; // Собираемся работать и с текстом, и с графикой, но так и не собирёмся Const // Раздел констант n = 5; // В данном случае n - не переменная, а другое обозначение 5. m : integer = 6; // Один из ужасов Паскаля. Это - статическая переменная! // Без понимания, что к чему, лучше не использовать, // но это - настоящая переменная Var // Раздел переменных i:integer; // Запасная переменная - нам не потребуется Label // Раздел меток. BeeginProgram, // У меток описывать нечего, но они должны EndProgram; // быть перечислены. Type S100 = string[100]; Procedure Proc(x:integer); // Данная процедура принимает параметр x // после чего всегда печатает: // "Опять - 25. Не мешайте работать!" Const S2 = '. Не мешайте работать!'; Var S1 : S100; Begin: x := n; // Для данной процедуры значения параметров не важны S1 := 'Опять - '; writeln(S1, x, S2 ); End; Begin BeginProgram: // Метка ничего не делает, но место указывает ; // Отсюда собираемся работать goto EndProgram; // Хватит УЖЕ работать, пошли домой Proc(n); // Здесь мы к счастью никогда не побываем, goto BeginProgram; // иначе - никогда не выберемся EndProgram: // Место у выхода ; // Перекур после честной работы End. // Теперь - совсем всё В данной программе есть все разделы (кроме описания функций), но она не выполняет никаких полезных действий. ===== Ввод/вывод ===== var x, y, z: integer; a, b, c: real; var x: integer; a: real; begin read(x); {Сохранит введенное с клавиатуры в переменную x} readln(a); {Сохранит введенное с клавиатуры в переменную a и добавит перевод строки} end. При вводе данных, они должны соответствовать "принимающим" переменным, т.е. нельзя ввести бессмысленные в языке Pascal значения, значения в формате другого типа (например, ввести значения 1.34 и даже 2.0 в целочисленную переменную) или выходящие за пределы диапазона значений, разрешённого для переменных указанного типа. Заметьте, что в строковую переменную можно занести и "Мама мыла раму", и "2.0". var x: integer; a: real; begin x := 2; write(x); {Выведет на экран значение переменной x} write('x= ', x); writeln(x); {Выведет на экран значение переменной x и перейдет на следующую строку} writeln('x= ', x); a := 0.15; writeln(a); writeln(a * x); writeln(a * x:4:1); end. Допустимо сразу выводить на экран значения выражений любой сложности без сохранения их в переменной. Частными случаями выражений являются вызовы функций, переменные и константы. begin write(0.3); write( 0.15 * 2.0 ); writeln( sin(3.14) ); end. Одним оператором (командой) ввода/вывода можно вводить/выводить значения нескольких аргументов, в том числе - разнотипных. begin writeln("Полученное значение ", 0.3); // Обратите внимание на пробелы writeln( 100.0:5:2, '(км/ч)'); // writeln( 200.0:5:2, '(км/ч)'); writeln( 300.0:5:2, '(км/ч)'); writeln( sin(3.14*1/2):8:4, sin(3.14*1/4):8:4, sin(3.14*1/8):8:4 ); end. == Распространённые ошибки == Недопустимо следующее : const x=0.3; var y : integer; A : array[1..9] of integer; F : text; begin read (0.3); // чтение "в никуда" - нет переменной, которая примет введённое значение. read (x); // тоже самое, но константа указана по имени readln (0.15 * y); // тоже самое, но вместо константы - целое выражение readln (A); // составной тип данных можно заполнять только по-элементно readln (F); // "неудачное" чтение из файла F - и файл F не открыт, и не указана // переменная-приёмник. Считать же саму файловую переменную F - нельзя! end. var A : array[1..9] of integer; F : text; begin writeln (x, 0.15 * y, 0.3); // Вывод - будет, но все выводимые значения сольются в нечто нечитаемое writeln (A); // составной тип данных можно выводить только по-элементно writeln (F); // "неудачнае" запись в файл F - и файл F не открыт, и не указано, // что выводить. Выводить таким образом у файл F - нельзя! end.