Общие правила синтаксиса языков программирования. Структура языков программирования

Форма Бэкуса-Наура (БНФ)

Форма Бэкуса-Наура (БНФ) была впервые применена при описании Алгола-60. БНФ совпадает по сути с нотацией КС-грамматик, отличаясь лишь обозначениями. Предусмотрены следующие метасимволы:

<> - служат для выделения нетерминалов - понятий языка. | - «или». Разделяет альтернативные правые части правил. - «есть по определению». Заменяет стрелку, используемую при записи продукций КС-грамматик.

Терминальные символы записываются как есть, никаких специальных способов их выделения не предусмотрено. Вот пример определений на БНФ, взятый из спецификации Алгола-60 - «Модифицированного сообщения»:

<простое арифметическое выражение> ::= <терм> 1 Окак операции типа сложения> <терм> | <простое арифметическое выражение> <знак операции типа сложения> <терм> <знак операции типа сложения> ::= + | -

Как видим, для выражения повторений используется рекурсия, причем повсеместно - левая. БНФ использована Н. Виртом при описании языка Паскаль. Хотя в нотацию были добавлены метаскобки {и}, обозначающие повторение, применены они лишь в отдельных случаях, в то время как, например, грамматика выражений леворекурсивна.

Синтаксические диаграммы

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

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

Таким образом, синтаксические диаграммы могут служить не только для порождения, но и для распознавания автоматных языков. Диаграммы стали популярны после выхода книги К. Йенсен и Н. Вирта «Паскаль». Они использованы в первой ее части - «Руководстве» - компактном учебнике языка. На рис. 3.1 показана одна из имеющихся там диаграмм.

Расширенная форма Бэкуса-Наура

Как уже говорилось, отсутствие в нотации формальных грамматик (и БНФ) средств явного задания повторений создает ряд трудностей. Во-первых, определения оказываются сложными для понимания, недостаточно наглядными из-за обилия рекурсий. Во-вторых, возникают проблемы с тем, что грамматики, дающие подходя- щие семантические деревья, оказываются леворекурсивными. При описании Модулы-2 и Оберона Н. Вирт использовал расширенную Бэкуса-Наура форму (РБНФ). Главные модификации касаются введения скобок { и} для повторений, а [ и ] - для обозначения необязательного вхождения цепочек терминалов и нетерминалов в правые части правил. Соглашения относительно обозначений терминалов и нетерминалов также изменены, что не столь принципиально. В дальнейшем мы будем пользоваться именно РБНФ. Вот как она определяется в спецификации Оберона-2: Варианты разделяются знаком |. Квадратные скобки [ и ] означают необязательность записанного внутри них выражения, а фигурные скобки { и } означают его повторение (возможно, 0 раз). Нетерминальные символы начинаются с заглавной буквы (например, Оператор). Терминальные символы или начинаются малой буквой (например, идент), или записываются целиком заглавными буквами (например, begin), или заключаются в кавычки (например, ":="). К этому следует добавить, что в роли знака «есть по определению» в РБНФ используется «=», а каждое правило заканчивается точкой. Вот так может быть определен синтаксис идентификатора (имени) с помощью РБНФ:

Имя = Буква { Буква | Цифра }.

Являясь метаязыком, РБНФ должна быть пригодна для описания языков, имеющих практический интерес. В том числе с помощью РБНФ может быть определен и синтаксис самой РБНФ:

Синтаксис = { Правило }. Правило = Имя "=" Выражение Выражение = Вариант { "I" Вариант }. Вариант - Элемент { Элемент }. Элемент = Имя | Цепочка | "{" Выражение "}" | "[" Выражение "]" | "{" Выражение "}". Цепочка = """ { символ) """ | """{ символ } """.

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

Описания синтаксиса языков семейства Си

Си (англ. C) - стандартизированный процедурный язык программирования, разработанный в начале 1970-х годов сотрудниками Bell Labs Кеном Томпсоном и Денисом Ритчи как развитие языка Би. Си был создан для использования в операционной системе UNIX. С тех пор он был портирован на многие другие операционные системы и стал одним из самых используемых языков программирования. Си ценят за его эффективность; он является самым популярным языком для создания системного программного обеспечения. Его также часто используют для создания прикладных программ. Несмотря на то, что Си не разрабатывался для новичков, он активно используется для обучения программированию. В дальнейшем синтаксис языка Си стал основой для многих других языков. Для языка Си характерны лаконичность, современный набор конструкций управления потоком выполнения, структур данных и обширный набор операций.

В знаменитой книге Б. Кернигана и Д. Ритчи описание синтаксиса языка Си дано в нотации, которая эквивалентна БНФ, но использует другие соглашения об обозначениях терминалов и нетерминалов, альтернативных правых частей правил, необязательных конструкций. Нетерминалы записываются курсивом, терминалы - прямым шрифтом. Альтернативные части правил выписываются в столбик по одному в строке или помечаются словами «one of» (один из). Необязательные части сопровождаются подстрочным индексом «opt (от optional) - необязательный; «необ» - в некоторых русских пере- водах). Левая часть правила записывается отдельной строкой с отступом влево. Вот пример определений конструкций языка Си:

Составной оператор {список описанийopt список операторовopt } список операторов оператор оператор список операторов

Как видим, из-за отсутствия явного способа выражения повторений, определе- ния изобилуют рекурсией. Аналогичная нотация с минимальными изменениями использована для описа- ния синтаксиса языков-потомков Си: Си++, Ява, Си#. Вот выдержка из стандарта ЕСМА-334 на язык Си#:

Block: {Statement-listopt} statement-list: statement statement-list statement

Специального названия эта нотация, судя по всему, не имеет. И представляется, как минимум, странной. Она неудобна не только для чтения, но и для обработки на компьютере. Ее использование при описании новых языков трудно объяснить чем-либо, кроме дурно понятой необходимости следовать традициям.

Особенности языка Си

  1. Имеет простую языковую базу, из которой вынесены в библиотеки многие существенные возможности, вроде математических функций или функций управления файлами;
  2. Имеет ориентацию на процедурное программирование, обеспечивающую удобство применения структурного стиля программирования;
  3. Имеет систему типов, предохраняющую от бессмысленных операций;
  4. Использование препроцессора для, например, определения макросов и включения файлов с исходным кодом;
  5. Имеет непосредственный доступ к памяти компьютера через использование указателей;
  6. Имеет минимальное число ключевых слов;
  7. Передача параметров в функцию по значению, а не по ссылке (при этом передача по ссылке выполняется с помощью указателей);
  8. Указатели на функции и статические переменные;
  9. Имеет области действия имён;
  10. Записи - определяемые пользователем собирательные типы данных (структуры), которыми можно манипулировать как одним целым;

Пример программы "Hello world " на Си

main() { printf("Hello, World!\n"); } #include int main() { printf("Hello, World!\n"); return 0; }

Описания синтаксиса языка Ада

Ада(Ada) - язык программирования, созданный в 1979-1980 годах в результате проекта, предпринятого Министерством обороны США с целью разработать единый язык программирования для встраиваемых систем (то есть систем управления автоматизированными комплексами, работающими в реальном времени). Имелись в виду, прежде всего, бортовые системы управления военными объектами (кораблями, самолётами, танками, ракетами, снарядами и т. п.). Перед разработчиками не стояло задачи создать универсальный язык, поэтому решения, принятые авторами Ады, нужно воспринимать в контексте особенностей выбранной предметной области. Язык назван в честь Ады Лавлэйс.Исследования, выполненные в начале и середине 1970-х годов, показали, что если Пентагон будет использовать единый язык программирования для решения всех своих задач вместо примерно 450 языков и их диалектов, то появится возможность получить огромную экономию средств (около 24 млрд долл. за период с 1983-го по 1999 год).Язык Ада основан на идеях структурного программирования и обеспечивает поддержку разработки сложных многомодульных программ, высокую степень машино-независимости и переносимости.При проектировании языка в первую очередь внимание акцентировалось на надежности и эффективности - язык создавался специально для разработки больших программных комплексов реального времени для встроенных систем, к которым предъявляются высокие требования надежности.

Особенности

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

Осбенности синтаксиса

  1. Программы модульные, механизм контроля импорта-экспорта описаний между модулями включает две разные директивы: одну для подключения другого модуля (with), другую - для импорта его описаний (use). Также существует возможность переименовать модуль при импорте (rename) - этот вариант позволяет использовать для обозначения пакета более удобные программисту идентификаторы.
  2. Пакеты (один из типов модулей) могут содержать заголовок и личную часть - то, что содержится в ней, не экспортируется и другим модулям недоступно.
  3. Поддерживается механизм обобщённых (настраиваемых) модулей: пакетов, процедур и функций, позволяющих описывать обобщённые алгоритмы обработки данных без указания конкретного типа.
  4. Развитая система типов, как встроенных, так и порождаемых программистом. Есть множество способов создания новых типов, язык поддерживает два разных понятия: «подтип» и «производный тип». Переменные типа и подтипа совместимы, переменные типа и его производного типа - нет.
  5. Развитые средства обращения к процедурам и функциям: поддерживаются входные и выходные параметры, передача фактических параметров в произвольном порядке с указанием имён формальных, параметры со значениями по умолчанию.
  6. Поддерживается переопределение процедур, функций и операторов - создание нескольких вариантов процедуры, функции или оператора с одним и тем же именем, но различными сигнатурами (типами и количеством параметров).
  7. Встроенные в язык конструкции поддержки параллельного программирования: поддерживаются понятия «задача» (параллельно выполняемый фрагмент программы), «вход задачи» (средство синхронизации и коммуникации параллельно выполняющихся задач), поддерживается механизм «рандеву» (протокол взаимодействия параллельно выполняемых задач через вход одной из них), имеется оператор выбора SELECT для организации условного межпотокового взаимодействия (выбора параллельной задачи, с которой следует взаимодействовать, в зависимости от готовности к рандеву и некоторых других условий).

Контекстно-свободные грамматики языков Aда-83 и Ада-95 определены с помощью варианта БНФ, в который добавлены обозначения повторений и необязательных частей. Названия нетерминалов записываются обычным шрифтом с использованием знака подчеркивания, если название составное, а зарезервированные слова - жирным шрифтом. Поскольку ни квадратные, ни фигурные скобки в Аде не используются, как не используется и знак «|» (все это метасимволы), никакого специального обозначения для терминалов не предусмотрено. Определение синтаксиса оператора if, взятое из стандарта Ада-95, выглядит так:

If_statement::= if condition then sequence_of_statements {elsif condition then sequence_of_statements} end if;

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

Для удовлетворения требованиям надёжности язык построен таким образом, чтобы как можно большее количество ошибок обнаруживалось на этапе компиляции. Кроме того, одним из требований при разработке языка была максимально лёгкая читаемость текстов программ, даже в ущерб лёгкости написания. Результатом такого подхода стал несколько «тяжеловесный» синтаксис и множество ограничений, отсутствующих в наиболее распространённых промышленных языках (С и C++) и часто воспринимаемых профессиональными программистами как избыточные, например, та же строгая типизация. Это привело к формированию представления об Аде как о сложном, малопонятном и неудобном в использовании языке.

Пример программы "Hellow world" на Аде

with Ada.Text_IO; procedure Hello is use Ada.Text_IO; begin Put_Line("Hello, world!"); end Hello;

Определение синтаксиса Кобола и ПЛ/1

Кобол (COBOL, COmmon Business Oriented Language ), язык программирования третьего поколения (первая версия в 1959), предназначенный, в первую очередь, для разработки бизнес-приложений.Разработчиком первого единого стандарта Кобола являлась Грейс Хоппер (бабушка Кобола). К 1997 году активно использовалось около 240 миллиардов строк кода на Коболе. Около 90 % финансовых транзакций в мире обрабатывается кодом на Коболе, и 75 % коммерческой обработки данных написано на Коболе. Общая стоимость используемого в настоящее время коболовского кода оценивается в 2 триллиона долларов США. До сих пор ежегодно пишутся миллиарды новых строк кода на Коболе.

Своеобразная система обозначений, являющаяся примером ранних нотаций, была применена при описании языков Кобол и ПЛ/1. Вот пример - определение формата глагола MOVE в Коболе:


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

Особенности языка Кобол

  1. Грамоздкость, многословность
  2. Хооршие, современные средства для работы со структурами данных и файлами, что обеспечило ему долгую жизнь в бизнес-приложениях(по крайней мере, в США).
  3. Обеспечивает наглядную и достаточно компактную запись алгоритмов в форме, независимой от конкретных машин, предназначенных для решения задач.
  4. Содержит большое колличество команд,которые представляют собой сложные комплексы типовых подпрограмм, обеспечивающих решение планово-экономических задач.

Пример программы "Hello world " на Коболе

IDENTIFICATION DIVISION. PROGRAM-ID. HELLO-WORLD. * ENVIRONMENT DIVISION. * DATA DIVISION. * PROCEDURE DIVISION. PARA-1. DISPLAY "Hello, world.". * EXIT PROGRAM.

ПЛ/1 -(PL/I, Programming Language I - «Язык программирования номер один») - разработанный в 1964 году язык программирования, созданный для научных, инженерных и бизнес-ориентированных вычислений. Он содержит такой широкий набор синтаксических конструкций и встроенных функций, что, вероятно, не существует ни одного компилятора, поддерживающего все возможности языка ПЛ/1. ПЛ/1 поддерживает рекурсию и структурное программирование, и его основная область применения - обработка данных

Основные свойства ПЛ/1

  1. Свободный синтаксис
  2. Ключевые слова и идентификаторы нечувствительны к регистру
  3. По умолчанию (в классических мэйнфреймовских версиях - всегда) передача параметров по ссылке
  4. Поддержка сложных структур с объединениями (в терминологии языка Паскаль - записи с вариантами)
  5. Чрезвычайно развитая система встроенных типов данных, при этом возможность неявных преобразований между большинством из них
  6. Несколько видов динамического выделения памяти
  7. Очень обобщенные операторы со многими вариантами синтаксиса
  8. Строго определённая семантика управляющих конструкций
  9. Операции с массивами
  10. Развитый механизм исключительных состояний
  11. Поддержка на уровне языка мультизадачности и асинхронного ввода-вывода
  12. Поддержка на уровне языка сложных методов доступа для ввода-вывода
  13. Очень развитый препроцессор, фактически сам являющийся подмножеством ПЛ/1

Пример программы "Hello world" на ПЛ/1

Test: procedure options(main); declare My_String char(20) varying initialize("Hello, world!"); put skip list(My_String); end Test;

Алфавит языка

Первоначальный алфавит ПЛ/1 включал 60 символов:

$ @ # A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 = + - * / () , . " % ; : ¬ & | > < _ ? пробел

Была предусмотрена возможность работы и с более ограниченным 48-символьным алфавитом, в который не входили:

@ # ; : ¬ & | > < _ ? -

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

Литература

  1. Свердлов С.З. Языки программирования и методы трансляции: Учебное пособие. - СПб.: Питер, 2007. - 638 с.: ил.

программный синтаксис комбинаторный логика

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

Формализуем основные конструкции языка программирования SML посредством форм Бэкуса-Наура или БНФ (история их создания изложена во вступительной лекции).

Неформально определим синтаксис (языка программирования или математической теории) как форму конструкций (программы или теории) и способов их комбинирования. Более точное определение синтаксиса будет сформулировано далее в ходе лекции.

Определим понятие синтаксиса более строго.

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

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

Основной задачей синтаксиса является определение формы и вида допустимых языковых конструкций. Эту задачу можно решить путем перечисления описаний всех языковых конструкций. Одним из механизмов такого описания является уже упомянутая нами нотация БНФ

Мы будем рассматривать параллельно БНФ-формализации синтаксиса ламбда-исчисления и языка программирования SML. В последнем случае мы ограничимся базовым набором конструкций языка, подчеркнув такие существенные возможности, как кортежи (tuples) и let-выражения.

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

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

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

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

Рассмотрим синтаксис языка программирования SML в сравнении с синтаксисом ламбда-исчисления.

Для большей наглядности и сопоставимости формализаций синтаксиса обоих языков (языка формальной математической теории и языка программирования) будем использовать единую нотацию, а именно, БНФ.

Прежде всего, необходимо договориться об обозначениях.

Рассмотрим традиционные обозначения БНФ и поясним смысл каждого из них.

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

Определяющий символ "::=" отделяет определяемую конструкцию от составляющих ее ранее определенных базовых конструкций.

Определяемая конструкция записывается слева от "::=" в угловых скобках "<" и ">".

Альтернативы (возможные варианты) конструкций перечисляются по вертикали.

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

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

<выражение> ::= <константа> | <переменная> |

(<выражение> <выражение>) |

л <переменная> . <выражение>

Поясним смысл приведенных обозначений.

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

  • 1. константы;
  • 2. переменной;
  • 3. двух выражений, заключенных в круглые скобки, т.е. знакомой нам операции аппликации ламбда-выражений;
  • 4. символа л, за которым следует переменная, точка и выражение, т.е. знакомой нам операции абстракции.

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

Для иллюстрации перечисленных выше тезисов рассмотрим важнейшие синтаксические категории языка программирования SML.

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

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

Комментарием назовем произвольный поясняющий текст к программе, который, согласно синтаксису языка SML, положено заключать в ограничители вида "(*" и "*)".

В частности, рассмотрим структуру основных синтаксически допустимых типов выражений языка.

<выражение> ::= <идентификатор> | <литерал> |

<выражение> <выражение> |

<выражение> <идентификатор> <выражение>

Как видно из БНФ-формализации, синтаксически корректным выражением в языке программирования SML считается:

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

Продолжим обсуждение выражений.

В дополнение к перечисленным альтернативам, синтаксически допустимыми выражениями языка программирования SML, также являются:

if <выражение> then <выражение>

else <выражение> |

(<выражение> ... <выражение>) |

let <описание> in <выражение> end |

  • 1. три выражения, соединенные зарезервированными словами if ("если"), then ("тогда") и else ("в противном случае"), называемые условным выражением и фактически представляющие собой предикатную функцию, которая реализует выполнение второго выражения в случае истинности первого и выполнение третьего в противном случае;
  • 2. конечную последовательность выражений, заключенную в круглые скобки (или так называемый кортеж) и применяемую для структуризации данных;
  • 3. описание и выражение, соединенные зарезервированными словами let ("положим"), in ("в") и end ("конец"), которые определяют операцию подстановки описания в выражение с учетом всевозможных вхождений в него указанного фрагмента описания;
  • 4. выражение, заключенное в круглые скобки (как мы уже знаем, в ламбда-исчислении и комбинаторной логике эту операцию можно производить без ограничений) и используемое для явного указания приоритета операции.

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

Перейдем к рассмотрению структуры синтаксически допустимых видов описаний объектов языка.

Приведем соответствующую формализацию в терминах БНФ.

<описание> ::=

val < идентификатор > = < выражение > |

fun < идентификатор > < идентификатор > =

< выражение > |

local < описание > in <описание> end

Синтаксически допустимыми описаниями языка программирования SML, как следует из представленной БНФ, являются:

  • 1. идентификатор и выражение, соединенные зарезервированными словами val и "=", которые обозначают связывание идентификатора (переменной, константы или другого синтаксически допустимого объекта языка программирования) с тем или иным выражением;
  • 2. три идентификатора и выражение, соединенные зарезервированными словами fun и "=", которые обозначают связывание функции (обозначенной первым идентификатором) с параметром (обозначенным вторым идентификатором) с выражением, определяющим порядок вычисления значения;
  • 3. два описания, соединенные зарезервированными словами local, in и end, которые обозначают локальное определение первого описания в контексте второго.

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

Перейдем к рассмотрению структуры синтаксически допустимых описаний типов объектов языка.

Приведем соответствующую формализацию в терминах БНФ.

<тип> ::= int | bool |

<тип> * ... * <тип> |

<тип> -> <тип>

Как следует из представленной БНФ, синтаксически допустимыми типами языка программирования SML являются:

  • 1. целочисленные величины, обозначаемые зарезервированным словом int;
  • 2. логические значения, обозначаемые зарезервированным словом bool;
  • 3. кортежи - упорядоченные n-ки элементов определенных типов;
  • 4. функции - упорядоченные n-ки элементов определенных типов, соединенных зарезервированными символами "->".

Рассмотрим следующий пример, иллюстрирующий приписывание типов в языке SML. Константа типа кортеж вида (0,false,1,true) имеет тип (int*bool*int*bool).

Заметим, что варианты типов (1) и (2) являются элементарными, тогда как (3) и (4) представляют собой производные типы с явно указанной (или выводимой) структурой, откуда и происходит название "структурированный тип".

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

Рассмотрим подробнее синтаксические особенности основных видов литералов.

Приведем соответствующую формализацию в терминах БНФ.

<литерал> ::= <литерал целого типа> |

<литерал строкового типа> |

<литерал вещественного типа>

Как следует из представленной БНФ, синтаксически допустимыми типами литералов в языке программирования SML являются следующие:

  • 1. целочисленные литералы, имеющие тип int и лежащие в диапазоне от -230 до +230 (последнее обстоятельство связано с особенностями машинного представления данных);
  • 2. строковые литералы, имеющие тип string и представляющие собой алфавитно-цифровые последовательности символов в коде формата ASCII;
  • 3. вещественные литералы, имеющие базовый тип real, обобщенную форму вида M x 10E, где M - мантисса в диапазоне от -1 до +1, а E - порядок в соответствующем диапазоне.

Заметим, что значение (т.е. семантика) литералов в полной мере определяется их лексическим (а, значит, и синтаксическим) представлением.

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

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

<выражение> <выражение>

Как следует из представленной БНФ, синтаксически допустимая конструкция языка программирования SML, описывающая операцию аппликации, весьма точно соответствует описанию операции аппликации в ламбда-исчислении.

Проиллюстрируем аппликацию функции к аргументу в языке программирования SML следующим примером.

Рассмотрим функцию succ, которая задается определением

fun succ n = n+1;

и осуществляет прибавление единицы к (целочисленному) аргументу.

Для рассматриваемой функции succ синтаксически корректная аппликация может иметь вид succ 2 и вычисляться в ходе выполнения программы в значение 3.

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

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

Приведем соответствующую формализацию в терминах БНФ:

if <выражение> then <выражение> else <выражение>;

Как видно из БНФ-формализации, синтаксически корректное условное выражение состоит из трех подвыражений, соединенных зарезервированными словами if, then и else, уже упоминавшихся нами в ходе лекции.

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

Заметим также, что функции сравнения встроены в язык SML и имеют вид: "=" (равно), "<" (меньше), ">" (больше), "<=" (меньше или равно), ">=" (больше или равно), "<>" (не равно). Результатом вычисления любой из этих функций является логическое значение.

Проиллюстрируем синтаксис условного выражения следующим примером на языке SML:

if n>=10 then 1 else 0;

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

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

Рассмотрим структуру синтаксически допустимых конструкций, известных под названием let-выражений.

Приведем соответствующую формализацию в терминах БНФ:

let <описание> in <выражение> end;

Как видно из БНФ-формализации, синтаксически корректное let-выражение состоит из описания и выражения, соединенных зарезервированными словами let, in и end.

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

Проиллюстрируем синтаксис let-выражений примерами из языка программирования SML.

Рассмотрим следующие let-выражения:

let val n=2 in n+1 end;

let k=9876*8765 in (k-1, k, k+1) end;

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

В ходе лекции неоднократно упоминалось понятие кортежа.

Рассмотрим подробнее этот весьма важный (в особенности при реализации функций) вид синтаксических конструкций языка программирования SML.

Приведем формализацию синтаксически допустимого представления кортежа в терминах БНФ:

(<выражение>, ..., <выражение>)

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

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

Проиллюстрируем синтаксис конструкции кортежа примерами из языка программирования SML:

Пример 1: (1, 2*1, 2*2*1)

Пример 2: (1, true, 0, false)

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

Полученный в ходе лекции опыт рассмотрения основных видов синтаксических конструкций языка программирования SML позволяет перейти к формальному синтаксису таких фундаментальных языковых конструкций как описания переменных и функций.

Рассмотрим формализации синтаксически корректных описаний переменных и функций в терминах БНФ:

<описание> ::=

val <идентификатор> = <выражение>

<описание> ::=

fun <идентификатор> <идентификатор> =

<выражение>

Первое определение представляет собой описание переменной, второе - функции. При этом оба определения имеют сходную структуру.

Проиллюстрируем формальные описания переменных и функций следующими примерами:

Пример 1. val x=2;

Пример 2. fun fact n =

if n<2 then 1

else n * fact (n - 1);

Пример 3. fun f (x,y) = x*x + y*y;

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

Заметим в заключение, что именно при реализации последней функции используются кортежи (поскольку синтаксис SML в "чистом" виде, как следует из БНФ, допускает применение только одноместных функций).

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

  • · синтаксис языков функционального программирования достаточно близок к синтаксису формальных теорий, на которых они основаны (в частности, это справедливо для ламбда-исчисления и языка SML);
  • · БНФ являются актуальной и адекватной формализацией синтаксиса языка;
  • · язык программирования SML, в отличие от ранних языков функционального программирования, имеет ряд расширенных конструкций (кортежи, let-выражения и др.).

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

Алфавит. Синтаксис и семантика:

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

Строчные и прописные латинские буквы:

Символ подчеркивания: «_» Пробел: « » Арабские цифры от 0 до 9:

Перечень знаков операций:

Последовательность ограничителей:

Спецификаторы:

Служебные слова:

Элементарные конструкции языка Паскаль: имена, числа, строки . Именами (или идентификаторами) называются элементы языка - метки, константы, переменные, типы, процедуры, модули, функции, объекты. Имя (идентификатор) в среде Турбо Паскаль включает в себя цифры, буквы латинского алфавита, символ подчеркивания. Отсутствует различие между прописными и строчными буквами (PROGRAM, Program и program - означает одно и то же).

На первом месте в идентификаторе не может стоять цифра (т.е. 1program - не правильно, program3 иprogram2file - такие идентификаторы допускаются). Символ «_» может находиться в любой позиции (т.е. _program,program_, program_file - допустимые идентификаторы). Идентификатор может иметь неопределенную длину, однако только первые 63 символа в нем значимые. Служебные (зарезервированные) слова не могут выступать в качестве имен.

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

В исходном коде программы комментарии заключают или в фигурные скобки»{ … }», или в скобки вида «(* … *)». Комментарии могут занимать неопределенное число строк. В языке Паскаль числа чаще представляются в десятичной системе счисления (целые и действительные). Положительный знак числа не учитывается, поэтому может быть опущен. Целые числа представляются в форме без десятичной точки:

395 -67 7808 +126

А действительные представляются в форме с десятичной точкой:

597.2 1.79 -5.526 8.0004

При случае допускается возможность записи числа с использованием десятичного порядка (обозначается E):

3E09 = 3*10^9 -5.34E6 = -5.34*10^6 29.3E-29 = 29.3*10^(-29)

синтаксис (языка программирования или математической теории) как форму конструкций (программы или теории) и способов их комбинирования. Более точное определение синтаксиса будет сформулировано далее в ходе лекции.

Определим понятие синтаксиса более строго.

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

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

Основной задачей синтаксиса является определение формы и вида допустимых языковых конструкций. Эту задачу можно решить путем перечисления описаний всех языковых конструкций. Одним из механизмов такого описания является уже упомянутая нами нотация БНФ

Мы будем рассматривать параллельно БНФ -формализации синтаксиса ламбда-исчисления и языка программирования SML . В последнем случае мы ограничимся базовым набором конструкций языка, подчеркнув такие существенные возможности, как кортежи ( tuples ) и let-выражения .

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

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

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

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

Рассмотрим синтаксис языка программирования SML в сравнении с синтаксисом ламбда-исчисления .

Для большей наглядности и сопоставимости формализаций синтаксиса обоих языков (языка формальной математической теории и языка программирования) будем использовать единую нотацию, а именно, БНФ .

Прежде всего, необходимо договориться об обозначениях.

Рассмотрим традиционные обозначения БНФ и поясним смысл каждого из них.

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

Определяющий символ "::=" отделяет определяемую конструкцию от составляющих ее ранее определенных базовых конструкций.

Определяемая конструкция записывается слева от "::=" в угловых скобках "<" и ">" .

Альтернативы (возможные варианты) конструкций перечисляются по вертикали.

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

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

Поясним смысл приведенных обозначений.

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

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

Рис. 1.12. Структуры языка программирования высокого уровня

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

Язык программирования имеет три основные составляющие: алфавит, синтаксис и семантику.

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

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

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

Для описания синтаксиса языка программирования тоже нужен какой-то язык. В этом случае речь идет о метаязыке («надъязыке»). Метаязык – язык, используемый для описания других языков. Наиболее распространенными метаязыками являются металингвистические формулы Бекуса-Наура (язык БНФ) и синтаксические диаграммы. В дальнейшем мы чаще всего будем использовать язык синтаксических диаграмм. Он более нагляден, легче воспринимается. В некоторых случаях для удобства мы будем обращаться к отдельным элементам языка БНФ.

В БНФ всякое синтаксическое понятие описывается в виде формулы, состоящей из правой и левой части, соединенных знаком::=, смысл которого эквивалентен словам «по определению есть». Слева от знака::= записывается имя определяемого понятия (метапеременная), которое заключается в угловые скобки < >, а в правой части записывается формула или диаграмма, определяющая все множество значений, которые может принимать метапеременная.

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

В такой последовательности, очевидно, конечным определяемым понятием должно быть понятие программы.

В записях метаформул приняты определенные соглашения. Например, формула БНФ, определяющая понятие «двоичная цифра», выглядит следующим образом:

<двоичная цифра>::=0|1.

Значок | эквивалентен слову «или». Это определение можно представить на языке синтаксических диаграмм (рис. 1.13).

Рис. 1.13. Понятие «двоичная цифра» на языке синтаксических диаграмм

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

Понятие «двоичный код» как непустую последовательность двоичных цифр БНФ описывает так:

<двоичный код> ::= <двоичная цифра> | <двоичный код> <двоичная цифра>.

Определение, в котором некоторое понятие определяется само через себя, называется рекурсивным. Рекурсивные определения характерны для БНФ.

Синтаксическая диаграмма двоичного кода представлена на рис. 1.14.

Рис. 1.14. Синтаксическая диаграмма двоичного кода

Возвратная стрелка обозначает возможность многократного повторения. Очевидно, что диаграмма более наглядна, чем БНФ.

Синтаксические определения языка программирования состоят из имени, определяемого в настоящий момент и не определенного где-либо выше термина, за которым следует двоеточие (:). Альтернативы обычно следуют за этим в отдельных строках, но могут также помещаться и в одной строке, в таком случае им предшествует фраза «одно из».

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

Например, лексемы языка C++ образуются из последовательности операций, выполняемых с программой компилятором и препроцессором языка.

Программа на языке C++ – последовательность ACSII-символов, представляющих собой ее исходный код, создаваемый при работе в текстовом редакторе.

Базовая программная единица в языке C++ представляет собой файл. Обычно такой файл соответствует файлу ОС, находящемуся в оперативной памяти или на диске и имеющему созданное по правилам ОС имя и расширение.С или.СРР.

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

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

Комментарии – текстовые части, предназначенные для аннотирования программы. Комментарии перед лексическим анализом исключаются из исходного текста программы.

Традиционный комментарий языка С представляет собой любую последовательность символов, помещаемую после пары символов /*. Признаком конца комментария служит первая пара символов */, встретившаяся после исходной пары /*.

Компилятор языка C++ распознает лексемы шести классов: ключевые слова, идентификаторы, константы, строковые литералы, операции и знаки пунктуации (также называемые разделителями). Формальное описание лексемы имеет следующий вид:

– ключевое слово;

– идентификатор;

– константа;

– строковый литерал;

– операция;

– знак пунктуации.

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

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

Формальное определение идентификатора имеет следующий вид:

– не-цифра;

– идентификатор не-цифра;

– идентификатор цифра.

Не-цифра: одно из

abcdefghijklmnopqrstuvwxyz_ ;

ABCDEFGHIJKLMNOPQRSTUVWXYZ;

цифра: одно из

Идентификатор – произвольное имя любой длины, присваиваемое классам, объектам, функциям, переменным, определяемым пользователем типам данных и т.д. Идентификаторы могут содержать буквы от А до Z и от а до z, символ подчеркивания (_) и цифры от 0 до 9. Существуют только два ограничения:

– первый символ должен являться буквой или символом подчеркивания;

– уникальность и контекст идентификаторов.

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

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

– константа-с-плавающей-точкой;

– целочисленная-константа;

– перечислимая-константа;

– символьная-константа.

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

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

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

Тип используется:

– для определения требуемого количества памяти при ее исходном распределении;

– для интерпретации битовых кодов, находимых в объектах при последующих к ним обращениях;

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

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

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

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

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

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

– функция;

– прототип функции;

Контекст зависит от того, как и где объявлены идентификаторы.

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

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

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

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

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

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

Видимость идентификатора – область исходного кода программы, из которого допустим нормальный доступ к связанному с идентификатором объекту.

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

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

Загрузочный модуль (выполняемая программа) создается из полученных в результате раздельной компиляции объектных модулей с автоматическим поиском и присоединением библиотечных подпрограмм и процедур. Компоновка – это процесс, который позволяет правильно связать каждое вхождение идентификатора с одним конкретным объектом или функцией. Все идентификаторы имеют один из трех атрибутов компоновки, тесно связанных с их контекстом: внешняя компоновка, внутренняя компоновка или отсутствие компоновки. Эти атрибуты определяются местоположением и форматом объявлений, а также явным (или неявным по умолчанию) использованием спецификатора класса памяти.

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

Идентификаторы с типом компоновки отсутствие представляют уникальные элементы программы.

Правила внешней и внутренней компоновки:

– любой идентификатор объекта или файла, имеющий файловый контекст, будет иметь внутренний тип компоновки, если его объявление содержит спецификатор класса памяти static ;

– если объявление идентификатора объекта или функции содержит спецификатор класса памяти extern , то идентификатор имеет тот же тип компоновки, что и видимое объявление идентификатора с файловым контекстом. Если такого видимого объявления не имеется, то идентификатор будет иметь внешний тип компоновки;

– если функция объявлена без спецификатора класса памяти, то ее тип компоновки определяется, как если бы был использован спецификатор класса памяти extern ;

– если идентификатор объекта с файловым контекстом объявлен без спецификатора класса памяти, то идентификатор имеет внешний тип компоновки.

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

Различают объявления определения (их обычно просто называют объявлениями) и объявления ссылки (иногда называемыми неопределяющими объявлениями). Объявление определения, как и следует из названия, выполняет две функции: объявления и определения. Неопределяющие объявления требуют наличия где-либо далее в программе определений. Объявление ссылки просто вводит в программу одно или более имен идентификаторов. Определение фактически распределяет объекту память и связывает идентификатор с этим объектом.

В число объектов, которые могут быть объявлены, входят:

– переменные;

– функции;

– классы и компоненты классов;

– компоненты структур;

– компоненты объединений;

– массивы прочих типов;

– перечислимые константы;

– метки операторов.

Спецификатор типа с одним или более модификатором используется для задания типа объявляемого идентификатора.

Типы делятся на фундаментальные и производные. К фундаментальным типам относятся: void, char, int, float, double, short, long, signed, а также некоторые варианты unsigned. Производные типы включают в себя указатели и ссылки на другие типы, массивы других типов, типы функций, типы классов, структуры и объединения. Объект класса может, например, содержать некоторое число объектов различных типов вместе с функцией манипуляции этими объектами, плюс механизм контроля доступа и наследования от других классов.

Фундаментальные спецификаторы типа создаются из следующих ключевых слов:

char, int, signed, double, long, unsigned, float, short.

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

Простые объявления идентификаторов переменных имеют следующий шаблон:

тип данных перем1 <=иниц1>, перем2 <=иниц2>,...;

где перем1, перем2, ... – это произвольная последовательность отдельных идентификаторов. Каждая из переменных объявляется с указанным типом данных.

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

«Указатель на объект типа type» содержит (то есть указывает) адрес объекта с типом type. Поскольку указатель сам по себе является объектом, то можно установить указатель на указатель. В число прочих объектов, на которые обычно устанавливается указатель, входят массивы, структуры и классы. Размер указателей объектов зависит обычно от модели памяти, размера и расположения сегментов данных.

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

Указатель функции имеет тип «указатель функции, возвращающей тип type», где type есть тип возвращаемых функцией данных.

Объявление указателя всегда должно устанавливать его на некоторый конкретный тип, даже если этот тип void (что фактически означает указатель на любой тип). Однако уже после объявления указатель обычно может быть переназначен на объект другого типа. Указатель со значением null – это адрес, гарантированно отличный от любого допустимого указателя, используемого в программе. Присвоение указателю целой константы 0 определяет его значение null.