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

Любой язык программирования состоит из трех частей:

● Алфавит.

● Синтаксис.

● Семантика

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

  1. Алфавит языка Си

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

1. Латинские строчные и прописные буквы: a, b, …, z и A, B, …, Z

2. Цифры: 0, 1, …, 9

3. Символ подчеркивания: _

4. Пробел (код 32)

5. Специальные символы: +, -, * и др.

6. Составные символы, воспринимаемые как один символ: <=, >= и др.

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

  1. Понятие о типе

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

● Тип определяет множество значений, которые может принимать данное.

● Тип определяет перечень операций, которые можно применять к данным.

● Каждое значение может относиться только к одному типу.

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

  1. Система типов языка Си Система типов языка Си

В соответствии с одной из систем классификации все типы языка Си делят на следующие четыре категории:

void ,

● скалярные,

● агрегатные.

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

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

Следует отметить, что void является зарезервированным словом. Оно используется для следующих целей:

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

● Зарезервированное слово void в языке используется для указания на то обстоятельство, что функция не имеет параметров.

В качестве примера применения типа void может служить объявление библиотечной функции clrscr(), которая не имеет возвращаемого значения и не принимает параметров:

void clrscr(void );

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

В стандарте языка С99 к скалярным типам относятся следующие виды типов:

● арифметические,

● логический,

● указатели,

● перечисления.

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

Арифметические типы составляют большую группу типов. В ней можно выделить три части:

● вещественные,

● комплексные.

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

Каждая из оставшихся разновидностей арифметических типов включает в себя достаточно большое количество отдельных типов. К числу основных (базовых) арифметических типов относят следующие типы. Для целочисленных типов базовыми типами считаются типы char иint , а для вещественных типов –float иdouble . Обращает на себя внимание тот факт, что символьный тип (типchar ) в языке Си рассматривается как разновидность целочисленного типа. Это обстоятельство можно рассматривать как проявление ослабленной типизации, которое присуще языку Си.

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

signed (знаковый),

unsigned (беззнаковый),

long (длинный),

short (короткий).

С учетом модификаторов можно написать 17 разновидностей арифметических типов.

Основным целочисленным типом в языке Си является тип int . Это аппаратно-зависимый тип. Размер, который занимает данное, относящееся к этому типу, зависит от размера машинного слова конкретной среды программирования.

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

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

● массивы,

● структуры,

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

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

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

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

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

· «::=» - читается как «может быть заменено на»,

· «|» - читается как «или».

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

Пример БНФ

Правила построения конструкции <Целое>, записанные в

БНФ, могут выглядеть следующим образом:

<Целое> ::= <3нак> <Целое без знака> | <Целое без знака>

<Целое без знака> ::= <Целое без знака> <Цифра> | <Цифра>

<Цифра> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

<3нак> ::= + | -

Для отображения того, что конструкция <Целое без знака> может включать неограниченное количество цифр, использовано правило с левосторонней рекурсией. Многократное применение этого правила позволяет построить целое число с любым количеством цифр.

Синтаксические диаграммы отображают правила построения конструкций в более наглядной форме. На такой диаграмме символы алфавита изображают блоками в овальных рамках, названия конструкций – в прямоугольных, а правила построения конструкций - в виде линий со стрелками на концах. При этом, если линия входит в блок, то в описываемую конструкцию должен входить соответствующий символ. Разветвление линии означает, что при построении конструкции возможны варианты. На рис. 2.1 представлена синтаксическая диаграмма, иллюстрирующая первые два правила описания конструкции <Целое>. Из диаграммы видно, что целое число может быть записано со знаком или без и включать произвольное количество цифр.



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

Алфавит языка программирования Borland Pascal 7.0 включает:

1. строчные, прописные буквы латинского алфавита (a..z, A..Z) и знак подчеркивания (_), который также во многих случаях считается буквой (строчные и прописные буквы не различаются);

2. цифры (0...9);

3. специальные знаки, состоящие из одного и двух символов:

. ,+ - * / = : < > { } () ^ @ $ #<> <= >= := (* *)

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

Из символов алфавита в соответствии с правилами синтаксиса строят различные конструкции. Простейшей из них является конструкция <Идентификатор>.

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

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

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

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

Программа на Borland Pascal состоит из трех частей: заголовка, раздела описаний и раздела операторов.

  • Заголовок программы не является обязательным, он состоит из служебного слова program и идентификатора - имени программы.
  • Раздел описаний содержит описания всех используемых программой ресурсов (полей данных, подпрограмм и т.д.).
  • Раздел операторов заключается в, так называемые, операторные скобки begin ...end и заканчивается точкой. Между операторными скобками записывают управляющие операторы программы, которые разделяют специальным знаком – точкой с запятой «;». Если точка с запятой стоит перед end , то считается, что после точки с запятой стоит «пустой» оператор.
  • В тексте программы возможны комментарии, которые помещают в фигурные скобки.

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

Program example; {заголовок программы}

{раздел описаний}

Uses crt;

Var a,b:integer; {объявление переменных}

{раздел операторов}

Write ("Введите два натуральных числа:"); {запрашиваем ввод данных}

Readln(a,b); {вводим значения}

while a<>b do {цикл-пока а<>b}

if a>b then a:=a-b {если a>b, тогда a:=a-b}

else b:=b-a; {иначе b:=b-a}

Writeln(‘Hauбoльшuй общий делитель равен ’,a); {выводим результат}

End. {конец программы}

Программа названа «example». Раздел описаний в данном случае включает только описание переменных (см. параграф 2.3). Раздел операторов содержит операторы ввода исходных данных, вычислений и вывода результатов. Начнем рассмотрение особенностей программирования на языке Borland Pascal с проблемы описания данных.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Множество информации или «смыслов», характеризующее план содержания данного языка;

    Множество « текстов », т.е. последовательностей физических сигналов, которые характеризуют план выражения данного языка;

    Отображение, определенное на множестве текстов и ставящее в соответствие каждому элементу этого множества некоторые элементы множества смыслов, а также обратное отображение.

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

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

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

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

Т А – множество текстов языка А ,

Т В – множество текстов языка В ,

S – множество смыслов языков А и В (для простоты считаем, что смысловые множества языков совпадают),

f А – функция, отображающая Т А в S ,

f B – функция, отображающая S в Т В .

    Семантический (смысловой) перевод:

f А : Т А S f B : S Т В

Пусть имеется некоторый текст t Т А , тогда:

    f А (t ) = s S

    f B (s ) t’ Т В .

Итак, переводом текста t Т А является текст t Т В .

    Формальный перевод.

Этот способ заключается в явном задании алгоритма вычисления функции, являющейся суперпозицией функций f А и f B . Обозначим эту суперпозицию через I AB .

I AB = f B (f А (t )).

3.2. Нормальные формы Бекуса

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

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

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

Классы объектов, которые используются в формах Бекуса:

    Цепочка основных символов языка.

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

    Металингвистическая связка :: = . Она соединяет левую и правую части формулы.

Каждый вариант представляет собой цепочку, состоящую из металингвистических переменных и основных символов. Для того, чтобы построить определяемую формулой конструкцию, нужно выбрать некоторый вариант построения из правой части формулы и, используя соответствующие формулы, подставить вместо каждой металингвистической переменной некоторые цепочки основных символов. Варианты правой части формулы разделяются металингвистической связкой |, имеющей значение «или». Металингвистическая переменная обозначается словами, заключенными в угловые скобки < >, которые поясняют смысл описываемой конструкции.

Числа определяются в языке при помощи следующих правил:

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

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

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

    <порядок> :: = e <целое>

    <правильная дробь> ::= .<целое без знака>

    <целое> ::= <целое без знака> | + <целое без знака> | – <целое без знака>

    <целое без знака> :: = <цифра> | <целое без знака> <цифра>

    <цифра> :: = 0|1|2|3|4|5|6|7|8|9

Пример 7: Вывод по формулам числа 1.5 e -2

<число>, <число без знака>, <десятичное число> <порядок>, <целое без знака> <правильная дробь> <порядок>, <цифра> <правильная дробь> <порядок>, 1 <правильная дробь> <порядок >, 1. <целое без знака> <порядок>, 1. <цифра> <порядок>, 1. 5 <порядок>, 1. 5e<целое>, 1. 5 e- <целое без знака>, 1. 5e- <цифра> , 1. 5 e-2 .

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



Copyright © 2024 Браузеры. Антивирусы. Безопасность. Windows. Игры. Видеокарты.