Глава 2
Элементы
языков программирования
2.1. Синтаксис
Как и у обычных языков, у языков программирования есть синтаксис:
Синтаксис языка (программирования) — это набор правил, которые определяют, какие последовательности символов считаются допустимыми выражениями (программами) в языке.
Синтаксис задается с помощью формальной нотации.
Самая распространенная формальная нотация синтаксиса — это расширенная форма Бекуса — Наура (РБНФ). В РБНФ мы начинаем с объекта самого верхнего уровня, с программы, и применяем правила декомпозиции объектов, пока не достигнем уровня отдельного символа. Например, в языке С синтаксис условного оператора (if-оператора) задается правилом:
if-onepamop :: = if (выражение) оператор [else оператор]
Имена, выделенные курсивом, представляют синтаксические категории, а имена и символы, выделенные полужирным шрифтом, представляют фактические символы, которые должны появиться в программе. Каждое правило содержит символ «:: =», означающий «представляет собой». Прочие символы используются для краткости записи:
[ ] Не обязательный {} Ноль или более повторений | Или
Таким образом, else-оператор в if-операторе не является обязательным. Использование фигурных скобок можно продемонстрировать на (упрощенном) правиле для объявления списка переменных:
Объявление-переменной ::= спецификатор-типа идентификатор {, идентификатор};
Это читается так: объявление переменной представляет собой спецификатор типа, за которым следует идентификатор (имя переменной) и необязательная последовательность идентификаторов, предваряемых запятыми, в конце ставится точка с запятой.
Правила синтаксиса легче изучить, если они заданы в виде диаграмм (рис. 2.1). Круги или овалы обозначают фактические символы, а прямоугольники — синтаксические категории, которые имеют собственные диаграммы.
.
Последовательность символов, получаемых при последовательном прохождении пути на диаграммах, является (синтаксически) правильной программой.
Хотя многие программисты страстно привязаны к синтаксису определенного языка, этот аспект языка, пожалуй, наименее важен. Любой разумный синтаксис легко изучить; кроме того, синтаксические ошибки обнаруживаются компилятором и редко вызывают проблемы с работающей программой. Мы ограничимся тем, что отметим несколько возможных синтаксических ловушек, которые могут вызвать ошибки во время выполнения программы:
Будьте внимательны с ограничениями на длину идентификаторов. Если значимы только первые 10 символов, то current_winner и current _width будут представлять один и тот же идентификатор.
Многие языки не чувствительны к регистру, то есть СЧЕТ и счет пред-ставляют одно и то же имя. Язык С чувствителен к регистру, поэтому эти имена представляют два разных идентификатора. При разработке чувствительных к регистру языков полезно задать четкие соглашения по использованию каждого регистра, чтобы случайные опечатки не приводили к ошибкам. Например, по одному из соглашений языка С в программе все записывается на нижнем регистре за исключением определенных имен констант, которые задаются на верхнем регистре.
Существуют две формы комментариев: комментарии в языках Fortran, Ada и C++ начинаются с символа (С, - -, и //, соответственно) и распространяются до конца строки, в то время как а языках С и Pascal комментарии имеют как начальный, так и конечный символы: /* ... */ в.С и (* ... *) иди {...} в Pascal. Вторая форма удобна для «закомментаривания» неис-пользуемого кода (который, взможнo, был вставлен для тестированя), но при этом существует опасность пропустить конечный символ, в результате чего будет пропущена последовательность операторов:
с |
а = b + с; Оператор будет пропущен
/*...*/ Здесь конец комментария
Остерегайтесь похожих, но разных символов. Если вы когда-либо изучали математику, то вас должно удивить, что знакомый символ «=» используется в языках С и Fortran как оператор присваивания, в то время как новые символы «==» в С и «.eq.» в Fortran используются в качестве операции сравнения на равенство. Стремление написать:
с |
является настолько общим, что многие компиляторы выдадут предупреждение, хотя оператор имеет допустимое значение.
В качестве исторического прецедента напомним известную проблему с синтаксисом языка Fortran. Большинство языков требует, чтобы слова в программе отделялись одним или несколькими пробелами (или другими пробельными символами типа табуляции), однако в языке Fortran пробельные символы игнорируются. Рассмотрим следующий оператор, который определяет «цикл до метки 10 при изменении индекса i от 1 до 100»:
Fortan |
do 10 i = 1,100
Если запятая случайно заменена точкой, то этот оператор становится на самом деле.оператором присваивания, присваивая 1.100 переменной, имя которой образуется соединением всех символов перед знаком «=»:
Fortan |
do10i = l.TOO
Говорят, эта ошибка заставила ракету взорваться до запуска в космос!
Yandex.RTB R-A-252273-3
- Глава 1
- 1.2. Процедурные языки
- 1.3. Языки, ориентированные на данные
- 1.4. Объектно-ориентированные языки
- 1.5. Непроцедурные языки
- 1.6. Стандартизация
- 1.7. Архитектура компьютера
- 1.8. Вычислимость
- 1.9. Упражнения
- Глава 2
- 2.2. Семантика
- 2.3. Данные
- 2.4. Оператор присваивания
- 2.5. Контроль соответствия типов
- 2.7. Подпрограммы
- 2.8. Модули
- 2.9. Упражнения
- Глава 3
- 3.1. Редактор
- 3.2. Компилятор
- 3.3. Библиотекарь
- 3.4. Компоновщик
- 3.5. Загрузчик
- 3.6. Отладчик
- 3.7. Профилировщик
- 3.8. Средства тестирования
- 3.9. Средства конфигурирования
- 3.10. Интерпретаторы
- 3.11. Упражнения
- Глава 4
- 4.1. Целочисленные типы
- I: Integer; -- Целое со знаком в языке Ada
- 4.2. Типы перечисления
- 4.3. Символьный тип
- 4.4. Булев тип
- 4.5. Подтипы
- 4.6. Производные типы
- 4.7. Выражения
- 4.8. Операторы присваивания
- 4.9. Упражнения
- Глава 5
- 5.1. Записи
- 5.2. Массивы
- 5.3. Массивы и контроль соответствия типов
- Подтипы массивов в языке Ada
- 5.5. Строковый тип
- 5.6. Многомерные массивы
- 5.7. Реализация массивов
- 5.8. Спецификация представления
- 5.9. Упражнения
- Глава 6
- 6.1. Операторы switch и case
- 6.2. Условные операторы
- 6.3. Операторы цикла
- 6.4. Цикл for
- 6.5. «Часовые»
- 6.6. Инварианты
- 6.7. Операторы goto
- 6.8. Упражнения
- Глава 7
- 7.1. Подпрограммы: процедуры и функции
- 7.2. Параметры
- 7.3. Передача параметров подпрограмме
- 7.4. Блочная структура
- 7.5. Рекурсия
- 7.6. Стековая архитектура
- 7.7. Еще о стековой архитектуре
- 7.8. Реализация на процессоре Intel 8086
- 7.9. Упражнения
- Глава 8
- 8.1 . Указательные типы
- 8.2. Структуры данных
- 8.3. Распределение памяти
- 8.4. Алгоритмы распределения динамической памяти
- 8.5. Упражнения
- Глава 9
- 9.1. Представление вещественных чисел
- 9.2. Языковая поддержка вещественных чисел
- 9.3. Три смертных греха
- Вещественные типы в языке Ada
- 9.5. Упражнения
- Глава 10
- 10.1. Преобразование типов
- 10.2. Перегрузка
- 10.3. Родовые (настраиваемые) сегменты
- 10.4. Вариантные записи
- 10.5. Динамическая диспетчеризация
- 10.6. Упражнения
- Глава 11
- 11.1. Требования обработки исключительных ситуаций
- 11.2. Исключения в pl/I
- 11.3. Исключения в Ada
- 11.5. Обработка ошибок в языке Eiffei
- 11.6. Упражнения
- Глава 12
- 12.1. Что такое параллелизм?
- 12.2. Общая память
- 12.3. Проблема взаимных исключений
- 12.4. Мониторы и защищенные переменные
- 12.5. Передача сообщений
- 12.6. Язык параллельного программирования оссаm
- 12.7. Рандеву в языке Ada
- 12.9. Упражнения
- Глава 13
- 13.1. Раздельная компиляция
- 13.2. Почему необходимы модули?
- 13.3. Пакеты в языке Ada
- 13.4. Абстрактные типы данных в языке Ada
- 13.6. Упражнения
- Глава 14
- 14.1. Объектно-ориентированное проектирование
- В каждом объекте должно скрываться одно важное проектное решение.
- 14.3. Наследование
- 14.5. Объектно-ориентированное программирование на языке Ada 95
- Динамический полиморфизм в языке Ada 95 имеет место, когда фактический параметр относится к cw-типу, а формальный параметр относится к конкретному типу.
- 14.6. Упражнения
- Глава 15
- 1. Структурированные классы.
- 15.1. Структурированные классы
- 5.2. Доступ к приватным компонентам
- 15.3. Данные класса
- 15.4. Язык программирования Eiffel
- Если свойство унаследовано от класса предка более чем одним путем, оно используется совместно; в противном случае свойства реплицируются.
- 15.5. Проектные соображения
- 15.6. Методы динамического полиморфизма
- 15.7. Упражнения
- 5Непроцедурные
- Глава 16
- 16.1. Почему именно функциональное программирование?
- 16.2. Функции
- 16.3. Составные типы
- 16.4. Функции более высокого порядка
- 16.5. Ленивые и жадные вычисления
- 16.6. Исключения
- 16.7. Среда
- 16.8. Упражнения
- Глава 17
- 17.2. Унификация
- 17.4. Более сложные понятия логического программирования
- 17.5. Упражнения
- Глава 18
- 18.1. Модель Java
- 18.2. Язык Java
- 18.3. Семантика ссылки
- 18.4. Полиморфные структуры данных
- 18.5. Инкапсуляция
- 18.6. Параллелизм
- 18.7. Библиотеки Java
- 8.8. Упражнения