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

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

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

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

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

Символ подчеркивания: «_» Пробел: « » Арабские цифры от 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)

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

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

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

Например, в Turbo Pascal используются следующие зарезервиро­ванные слова: and, asm, array, begin, case, const, constructor, destructor, div, do, downto, else, end, file, for и др.

При наборе программы эти слона отображаются на экране белым цветом, напоминая нам, что они являются ключевыми.

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

Типы данных - важнейшее понятие языка, поскольку все объекты языка характеризуются типами, которые в значительной степени определяют операции над ними, а также вид «компьютерного» пред­ставления соответствующих данных. В языке существует ряд стан­дартных типов данных, целый, вещественный, символьный, логический и пр. Для каждого типа есть правила их обозначения. Эти обозначения пишутся вслед за именем.

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

Любой язык программирования имеет целый ряд встроенных функ­ций, т.е. готовых программ, одно обращение к которым по их имени приводит к получению результата, например sin (х), cos(x), log(x) и т.д. Напомним, что функция sqrt (х) обеспечивает нахождение квадратно­го корня из указанного аргумента.

Алгоритм, записанный на языке программирования, называется программой.

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


Любая программа выполняется в результате ее трансляции - пере­вода записи операторов на язык компьютера. Каждый оператор в про­грамме после трансляции будет представлен набором кодов команд. Эти команды выполняются в оперативной памяти компьютера.

Все константы и переменные размещаются в своих ячейках памяти в соответствии с присвоенными им идентификаторами - именами.

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

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

Операторы языка программирования позволяют приступить к на­писанию простейших программ с использованием типовых алгорит­мических конструкций.

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

Ранее вы познакомились с основными алгоритмическими конструк­циями: линейной, разветвляющейся и циклической. Для реализации этих конструкций используются соответствующие операторы языка программирования. Синтаксис (правила) записи операторов в различ­ных языках программирования могут несколько отличаться. В связи с этим можно использовать список правил оформления операторов языка - неотъемлемую часть ПО (системы) языка программирования, представленную в разделе «Помощь». Часто в системе языка програм­мирования автоматически воспроизводится типовой оператор при наборе первых символов оператора, а пользователю требуется его под­править. Рассмотрим основные операторы, реализующие типовые ал­горитмические конструкции.

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

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

Оператор вывода. Этот оператор предназначен для вывода резуль­татов или на экран монитора или на принтер.

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

Оператор условного перехода передает управление только в случае истинности некоторого условия, а в противном случае - просто игно­рируется.

Смысл этого оператора состоит в том, что если условие истинно, то выполняется оператор или группа операторов, следующих за словом THEN, а если условие ложно, то выполняется оператор или группа операторов, следующих за словом ELSE (иначе). Конструкция ELSE здесь заключена в квадратные скобки. По правилам описания форматов это означает ее необязательность. В случае отсут­ствия в формате конструкции ELSE оператор выполняет также дей­ствия: если условие истинно, то выполняется оператор или группа операторов, следующих за словом THEN, а в противном случае - опе­ратор, следующий за оператором IF в программе. Если используется группа операторов, то они разделяются двоеточиями.

Для реализации циклических алгоритмических конструкций ис­пользуется оператор цикла, в языке Basic это «связка» операторов FOR и NEXT. Первый из них является начальным и главным оператором. Он открывает собой тело цикла, т. е. группу операторов, которые будут циклически выполняться фиксированное число раз.

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

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

Формализуем основные конструкции языка программирования 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-выражения и др.).

2. ПОНЯТИЕ ЯЗЫКА ПРОГРАММИРОВАНИЯ. ПОНЯТИЕ ЛЕКСИКИ, СИНТАКСИСА И СЕМАНТИКИ.

3.СПОСОБЫ ФОРМАЛЬНОГО ОПРЕДЕЛЕНИЯ СИНТАКСИСА ЯЗЫКА ПРОГРАММИРОВАНИЯ: МЕТАЯЗЫК, СИНТАКСИЧЕСКИЕ ДИАГРАММЫ.

Анализировать условие достижения конца потока (конца файла) и ошибки ввода-вывода;

Получать и устанавливать указатель текущей позиции в потоке;

Управлять буферизацией потока и размером буфера.

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

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

Поток можно открыть в текстовом или двоичном режиме. В соответствии с этим различают файлы текстовые и двоичные.

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

читается числовая информация, то происходит преобразование прочитанной последовательности символов в двоичное целое или число с плавающей точкой в соответствии со спецификацией формата; при форматном выводе числовой информации происходит преобразование из внутреннего представления числа в последовательность символов, изображающих число. Последовательность символов, хранящаяся в текстовом файле, может быть разбита на строки. При записи в текстовый поток символа новой строки ‘\n’ он заменяется последовательностью символов CR (“возврат каретки”) и LR (“перевод строки”). При

чтении из текстового файла последовательность символов CR и LR преобразуется в один символ новой строки ‘\n’.

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

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

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

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

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

на новую текущую позицию в соответствии с числом прочитанных байтов).

Этот процесс продолжается пока не исчерпана форматная строка или не достигнут конец файла или не произошла ошибка. В первом случае функция возвращает количество объектов, получивших значение при вводе, при достижении конца файла – возвращает константу EOF, в случае ошибки – значение –1.

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

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

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

13. ПОНЯТИЕ ПРОГРАММЫ. СТРУКТУРА ПРОГРАММЫ.

Простая программа – это программа с управляющей структурой, обладающей следующими особенностями:

1) имеется только один вход и один выход,

2) через каждый узел программы проходит путь от входа к выходу структуры.

Логически программы можно разбить на 2 блока:

1. величины с которыми работаем

2. действия производимые над величинами (в соответствии с алгоритмом решения задачи).

Программа в си состоит из подпрограмм. Из них путем механического объединения формируется текст программы, но всегда существует основная подпрограмма. Синтаксис подпрограммы: 1. Заголовок void main ()

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

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

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

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

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

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

14. ЯЗЫКОВЫЕ СРЕДСТВА ВЫЧИСЛЕНИЙ НАД ДАННЫМИ: ВЫРАЖЕНИЕ, ОПЕРАТОР ПРИСВАИВАНИЯ. СИНТАКСИС И СИМАНТИКА ВЫРАЖЕНИЯ И ОПРЕТОРА ПРИСВАИВАНИЯ.

ВЫРАЖЕНИЕ – множество взаимосвязанных операций над переменными и константами и скобок «()», в котором результат одной операции является операндом другой.

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

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

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

Оператор присваивания

В простейшем случае общий вид оператора: V = E;

Здесь V – имя переменной, а E – выражение. В операторе присваивания используется операция присваивания = .

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

12. СОВМЕСТИМОСТЬ ТИПОВ. ПРЕОБРАЗОВАНИЕ ТИПОВ.

В выражениях в качестве операндов могут присутствовать переменные и константы разных типов (здесь и далее мы ограничимся пока только известными нам базовыми типами данных). Результат каждой операции также имеет свой определенный тип, который зависит от типов операндов. Если в бинарных операциях типы данных обоих операндов совпадают, то результат будет иметь тот же самый тип. Если нет, то транслятор должен включить в код программы неявные операции, которые преобразуют тип операндов, то есть выполнить ПРИВЕДЕНИЕ ТИПОВ. Преобразование типов может включать в себя следующие действия:

Увеличение или уменьшение разрядности машинного слова , то есть “усечение” или “растягивание” целой переменной;

Преобразование целой переменной в переменную с плавающей точкой и наоборот;

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

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

double x,d; // double x,d; int n;

d = x - (int)x; // n = x; d = x - d;

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

1) все операнды типа float преобразуются к типу double;

2) если один операнд имеет тип long double, то второй операнд преобразуется к типу long double;

3) если один операнд имеет тип double, то второй операнд преобразуется к типу double;

4) если один операнд имеет тип unsigned long, то второй операнд преобразуется к типу unsigned long;

5) если один операнд имеет тип long, то второй операнд преобразуется к типу long;

6) если один операнд имеет тип unsigned int, то второй операнд преобразуется к типу unsigned int;

7) все операнды типа char преобразуются к типу int;

8) все операнды типа unsigned char преобразуются к типу unsigned int;

9) иначе оба операнда имеют тип int.

Тип значения выражения имеет тип результата последней выполняемой операции в этом выражении

15. ЯЗЫКОВЫЕ СРЕДСТВА УПРАВЛЕНИЯ ВЫЧИСЛЕНИЯМИ: ВЕТВЛЕНИЯ, ЦИКЛЫ (ПОНЯТИЕ, НАЗНАЧЕНИЕ, СТРУКТУРНАЯ СХЕМА, ВИДЫ).

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

Таким образом, в самом общем виде структурная схема цикла содержит три части:

Действия по подготовке цикла к первому исполнению;

Действия, являющиеся основным содержанием данного вычислительного процесса – тело цикла;

Действия, отслеживающие повторение тела цикла – проверка условия продолжения или условия окончания повторений.

Блок-схема алгоритма вычисления значения полинома n–й степени для заданного значения x:
Для итерационных методов характерны стереотипные вычисления, связанные с переходом от одного приближения к следующему. Это позволяет записывать соответствующие этим методам алгоритмы в виде циклических, причем число повторений этих стереотипных вычислений (итераций) заранее, как правило, неизвестно и зависит от начального приближения и допустимой погрешности. Характерным условием окончания цикла является некоторое отношение, связывающее разность последовательных приближений и допустимую погрешность.

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

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

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

В 1960-х гг. X. Барендрегтом (Hendrik Barendregt) был детально описан синтаксис лямбда-исчисления - математической формализации, поддерживающей языки функционального программирования. Примерно в то же время Дж. Бэкусом (John Backus) были созданы основы формализации синтаксиса языков программирования посредством специального математического языка. Позднее П. Науром (Peter Naur) этот язык (а с точки зрения целевого языка программирования - метаязык) был доработан, в результате чего возникла математическая нотация, известная и сегодня под названием «форм Бэкуса - Наура» (БНФ).

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

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

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

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

Мы будем рассматривать параллельно БНФ-формализации синтаксиса лямбда-исчисления и языка программирования F#. В последнем случае ограничимся базовым набором конструкций языка, подчеркнув такие существенные возможности, как кортежи (tuples), а также так называемые let-выражения. Для формирования правильного понимания роли и места синтаксиса в исследовании языков программирования рассмотрим обобщенную схему трансляции исходного текста программы (написанной, например, на языке программирования F#) в машинный код. В ходе трансляции программы, прежде всего, выполняется так называемая процедура лексического анализа, которая включает в себя выделение в тексте программы элементарных конструкций языка, или, иначе, лексем (в частности, имен переменных или идентификаторов, специальных или ключевых слов, значений констант, переменных и др.). По завершении лексического анализа выполняется так называемая процедура синтаксического разбора текста программы, которая представляет собой проверку корректности синтаксиса текста, написанного на языке программирования. Эта процедура, возможно, включает выполнение проверки корректности типизации в той или иной форме.

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

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

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

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

() | к .

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

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

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

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

Для иллюстрации перечисленных выше тезисов рассмотрим важнейшие синтаксические категории языка программирования F#. Под выражением будем понимать обозначение конструкции языка, которой может быть присвоено значение (константы, переменной, функции и т.д.). Описанием будем в дальнейшем называть запись, связывающую выражение языка программирования с именем, обозначающим его в программе (идентификатором). Под термином «зарезервированное» (или, иначе, «служебное») слово будем иметь в виду конструкцию языка, однозначно интерпретируемую в качестве инструкции языка программирования (например, «if», «then», «let»). Напомним, что в данной нотации цитирование производится без кавычек или других символов-ограничителей. Комментарием назовем произвольный поясняющий текст к программе, который, согласно синтаксису языка F# положено заключать в ограничители вида «(*» и «*)», а «//» - комментарий до конца строки.

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

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

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

В дополнение к перечисленным на предыдущем слайде альтернативам синтаксически допустимыми выражениями языка программирования F#, как следует из БНФ

if then else | (...) |

также являются:

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

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

let = | let «^последовательность неременных> =

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

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

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

Sbytel intl6 | uint 16| uint32| int64| uint64|

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

  • 1) целочисленные величины;
  • 2) числа с «плавающей» запятой;
  • 3) логические значения;
  • 4) отсутствие значения;
  • 5) кортежи - упорядоченные п -ки элементов определенных типов;
  • 6) функции - упорядоченные и-ки элементов определенных типов, соединенных зарезервированными символами -к

Рассмотрим следующий пример, иллюстрирующий приписывание типов в языке F#. Константа типа кортеж вида (0, false, 1, true) имеет тип (int*bool*int*bool). Заметим, что варианты типов (1)-(4) являются элементарными, тогда как (5) и (6) представляют собой производные типы с явно указанной (или выводимой) структурой, откуда и происходит название «структурированный тип».

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

Рассмотрим подробнее синтаксические особенности основных видов литералов. Приведем соответствующую формализацию в терминах БНФ:

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

  • 1) целочисленные литералы, имеющие типы int, sbyte, byte, inti б, uintlG, int32, uint, uint32, int64, uint64, bigint;
  • 2) строковые литералы, имеющие типы Char, byte, byte, string;
  • 3) вещественные литералы, имеющие типы decimal, float; double, single, float32.

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

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

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

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

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

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

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

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

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

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

if п>=10 then 1 else О

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

Рассмотрим структуру синтаксически допустимых конструкций, известных под названием let-выражений. Приведем соответствующую формализацию в терминах БНФ:

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

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

Проиллюстрируем синтаксис let-выражений примерами из языка программирования F#. Рассмотрим следующие let-выражения:

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

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

(лх. х+1) 2. Второе выражение позволяет свести многократное вычисление громоздкой операции (умножения) к однократному.

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

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

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

  • (1, 2*1, 2*2*1)
  • (1, true, 0, false)

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

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

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

::= fun -> ::= let =

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

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

let гес fact n=if n -> x*x+y*y;

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

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

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

Контрольные вопросы

Вариант 1 : в чем состоит основное назначение синтаксиса?

  • а) формализация вида и формы конструкций языка (+);
  • б) формализация значения конструкций языка;
  • в) формализация абстрактной машины для реализации языка.

Вариант 2: какова последовательность синтаксического разбора программы?

  • а) лексический, синтаксический, семантический анализ (+);
  • б) синтаксический, лексический, семантический анализ;
  • в) семантический, лексический, синтаксический анализ.

Вариант 3: что из перечисленного является формализацией синтаксиса?

  • а) форма Бэкуса - Наура (+);
  • б) лямбда-исчисление;
  • в) комбинаторная логика.

Вариант 1 : какой из объектов не имеет обозначения в формах Бэкуса - Наура?

  • а) определяемая конструкция;
  • б) альтернативные конструкции;
  • в) цитирование (+).

Вариант 2: что понимается под синтаксисом?

  • а) совокупность элементов языка;
  • б) описание формы языка (+);
  • в) модель реализации языка.

Вариант 3: какие объекты может содержать выражение языка F#?

  • а) идентификатор, литерал, выражение (+);
  • б) функция, идентификатор, литерал;
  • в) условие, литерал, выражение.

Вариант 1: каков наиболее полный перечень синтаксических категорий языка F#?

  • а) выражение, описание, служебное слово, комментарий (+);
  • б) константа, функция, переменная, значение;
  • в) идентификатор, константа, функция, переменная.

Вариант 2: какие ключевые слова используются для описания в языке F#?

  • а) val, fun, let;
  • б) val, if, local;
  • в) let, fun (+).

Вариант 3: на какие категории подразделяются типы F#?

  • а) структурированные и неструктурированные (+);
  • б) литералы и функции;
  • в) переменные и константы.