В.Ш. Кауфман - Языки программирования - концепции и принципы (1990) (1160787), страница 33
Текст из файла (страница 33)
форматирования текста (горизонтальная табуляция, вертикальная табуляция,
возврат каретки, перевод строки, перевод страницы).
Среди графических символов выделено основное множество (прописные
латинские буквы, цифры, пробел и специальные символы # & ' ( ) * + , - . : ;
< = > _ | ).
Кроме того, в алфавит входят строчные латинские буквы и дополнительные
символы ( ! $ % ? @ [ \ ] ' ` { } ^ ).
Правила, позволяющие обозначить произвольную программу с помощью только
основного множества, таковы. Во-первых, в качестве обязательных элементов
программы (ключевые слова, ограничители и разделители) используются только
символы из основного множества. Во-вторых, строчные и прописные буквы
эквивалентны всюду, кроме строк и символьных констант. (Так что и
идентификаторы можно представлять в основном множестве). А строки
обозначаются с помощью символа & так, что "явное" изображение строки
эквивалентно "косвенному", использующему название нужной подстроки.
Например, если ASCII.DOLLAR - это название строки "$", то обозначение "А $
C" эквивалентно "А" & ASCII.DOLLAR & "C".
Подобные названия для всех дополнительных символов и строчных латинских
букв предопределены в языке Ада. Это и позволяет записать любую программу с
помощью одного только основного множества. (Еще пример: "АвС" эквивалентно
"A" & ASCII.LC_B & "C"; здесь LC служит сокращением от английского
LOWER_CASE_LETTER - строчные буквы).
7.8. Лексемы
Понятие эталонного текста как последовательности символов (литер)
позволяет абстрагироваться от особенностей устройств ввода-вывода. Однако
символ - слишком мелкая единица с точки зрения тех сущностей, которые
необходимо обозначать в ЯП. Их намного больше, чем элементов в алфавите.
Удобно, когда эти сущности имеют индивидуальные обозначения, подобные словам
естественного языка, а текст оказывается последовательностью таких "слов",
называемых лексемами. Мы пришли к еще одному (промежуточному) уровню
абстракции - уровню лексем. (Можно считать, что этот уровень удовлетворяет
потребность в рациональной микроструктуре текста - приближает размеры
"неделимого" знака к размеру "неделимого" денотата).
Когда этот уровень абстракции выделен явно, и при письме, и при чтении
можно оперировать достаточно крупными единицами (лексемами), абстрагируясь
(когда это нужно) от конкретного способа представления лексем символами
алфавита. Становится проще манипулировать с текстом, увеличивается
надежность, растет скорость создания и восприятия текста.
Между тем в ЯП уровень лексем выделяется далеко не всегда. Неудачная
идея игнорировать пробелы как естественные разделители возникла на заре
развития ЯП (сравните Фортран и Алгол-60), по-видимому как отрицательная
реакция на необходимость "считать пробелы" в первых позиционных автокодах. В
результате была временно утеряна отлично зарекомендовавшая себя традиция
естественных языков - выделять слова пробелами. В Алголе-60 к тому же
игнорируются все управляющие символы, а в Фортране - переход на новую строку
внутри оператора. В естественных языках подобные особенности текста обычно
используются как разделители слов. В последние годы идея явного выделения
уровня лексем становится общепризнанной и при конструировании ЯП.
Интересно отметить, что "возвращение пробела" как значащего символа
связано и пониманием "ключевых слов" просто как зарезервированных слов (а не
"иероглифов", как в Алголе), ничем другим от остальных слов-лексем не
отличающихся. Но тогда естественно запретить сокращать ключевые слова (иначе
их можно спутать теперь уже не только с другими ключевыми словами, но и с
идентификаторами). Это в целом полезное ограничение, так как способствует
надежности программирования, помогая чтению за счет некоторой дисциплины
письма (что вполне в духе индустриального программирования). Кстати, не
очевидно, что напечатать слово procedure труднее, чем `proc', с учетом
переключения внимания на спецзнаки. К тому же современные системы подготовки
текстов позволяют легко вводить словари сокращений (так что и чтения не
затрудняют, и печатать удобно).
7.9. Лексемы в Аде
Лексемы в Аде аналогичны словам естественного языка. Они делятся на
шесть классов: ограничители (знаки препинания), идентификаторы (среди
которых - зарезервированные ключевые слова), числа, обозначения символов,
строки и примечания. В некоторых случаях, когда невозможно иначе однозначно
выделить лексему, требуется явный разделитель между смежными лексемами. В
качестве разделителя выступает или пробел, или управляющий символ, или конец
строчки. Пробел, естественно, не действует как разделитель в строках,
примечаниях и в обозначении пробела (` '). Управляющие символы (кроме,
возможно, горизонтальной табуляции, эквивалентной нескольким пробелам)
всегда служат разделителями лексем. Между лексемами (а также до первой и
после последней лексемы) текста, допустимо несколько разделителей. Заметим,
что каждая лексема должна располагаться на одной строке (ведь конец строки -
разделитель).
Со списком ключевых слов Ады мы познакомились по ходу изложения. Многие
из них стали фактически стандартными для многих ЯП (procedure, begin, do и
т.д.). Сокращать ключывые слова недопустимо.
Ниже следует описание классов лексем.
Ограничитель. Это одиночный символ
& ' ( ) * + , - . / : ; < = >
и пара символов
=> .. ** := /= >= <= << >> <>
При этом символ может играть роль ограничителя только тогда, когда он
не входит в более длинную лексему (парный ограничитель, примечание, строку).
Идентификатор. Отличается от алгольного или паскалевского
идентификатора только тем, что внутри него допускается одиночное
подчеркивание. Прописные и строчные буквы считаются эквивалентными.
Идентификаторы считаются различными, если отличаются хотя бы одним символом
(в том числе и подчеркиванием), например 'A', '*', ''', ' ' и т.п.
Строка. Это последовательность графических символов, взятая в двойные
кавычки. Внутри строки двойная кавычка изображается повторением двойной
кавычки (""), например "Message of the day".
Примечание. Начинается двумя минусами и заканчивается концом строки.
д) Число.
Примеры целых чисел:
65_536 , 10.000
2#1111_1111# , 16#FF# , 016#0FF#
-- целые константы, равные 255
16#E#E1 , 2#1110_0000#
-- это 222
Примеры вещественных чисел:
16#F.FF#E+2 , 2#1.1111_1111_111#E11
-- 4095.0
(Пробелы внутри не допускаются - ведь они разделители).
8. Исключения
8.1. Основная абстракция
Представим себе заводского технолога, планирующего последовательность
операций по изготовлению, например, блока цилиндров двигателя внутреннего
сгорания. Аналогия с программированием очевидна. Соответствующая
технологическая карта (программа) предусматривает отливку заготовки,
фрезеровку поверхностей и расточку отверстий. Каждый из этапов довольно
подробно расписывается в технологической карте. Однако все предусматриваемые
технологом подробности касаются создания именно блока цилиндров. В
технологической карте, конечно, не сказано, что должен делать фрезеровщик,
если выйдет из строя фреза, если возникнет пожар, землетрясение, нападение
противника. Если бы технолог был вынужден планировать поведение исполнителя
в любых ситуациях, то он никогда не закончил бы работу над такими
"технологическими картами".
В сущности, специализация в человеческой деятельности основана на
способности выделить небольшой класс ситуаций, считающихся существенными для
этого вида деятельности, а от всех остальных абстрагироваться, считать
чрезвычайными, необычными, исключительными, требующими переключения в другой
режим, в другую сферу деятельности.
Примерам нет числа. Кулинарный рецепт не описывает поведения хозяйки,
если в процессе приготовления блюда зазвонит телефон; физические модели
применимы при определенных ограничениях и ничего не говорят о том, что будет
при нарушении этих ограничений (например, из законов Ньютона нельзя узнать о
поведении объектов при релятивистских скоростях).
Вместе с тем важно понимать, что теми аспектами планируемой
деятельности, от которых приходится абстрагироваться, ни в коем случае
нельзя пренебрегать. При реальном возникновении чрезвычайных обстоятельств
именно они и становятся определяющими. Так что в жизнеспособной системе, а
тем более системе, претендующей на повышенную надежность, совершенно
необходим аппарат, обеспечивающий адекватную реакцию системы на чрезвычайные
ситуации. К счастью, технолог обычно вправе рассчитывать на интеллект,
жизненный опыт и общую квалификацию исполнителя-человека.
Программист, вынужденный создавать программу для автомата, по
необходимости попадает в положение заводского технолога, которого заставляют
писать инструкции по гражданской обороне или поведению во время пожара. Ведь
надежная программа должна вести себя разумно в любых ситуациях. Как выйти из
положения, нам уже нетрудно догадаться - снова абстракция (и затем
конкретизация). Нужно иметь возможность, занимаясь содержательной функцией
программы, отвлекаться от проблемы чрезвычайных обстоятельств, а занимаясь
чрезвычайными обстоятельствами, в значительной степени отвлекаться от
содержательной функции программы. Вместе с тем на подходящем этапе
программирования и исполнения программы нужно, конечно, иметь возможность
учесть все тонкости конкретных обстоятельств.
Таким образом мы приходим к одной из важнейших абстракций
программирования - абстракции от чрезвычайных обстоятельств, от особых
(исключительных) ситуаций. Будем называть их для краткости просто
"исключениями", а соответсвующую абстракцию - абстракцией от исключений.
Проще говоря, речь идет об аппарате, поддерживающем систематическое
разделение нормальной и ненормальной работы, причем не только программы, но
в некотором смысле и программиста.
8.2. Определяющие требования
Требования к аппарату исключений в ЯП легко выводятся из самых общих
соображений (и тем не менее нигде не сформулированы). Представим их в виде
трех принципов, непосредственно следующих из назначения исключений в
условиях систематического, надежного и эффективного программирования.
Принцип полноты исключений: на любое исключение должна быть
предусмотрена вполне определенная реакция исполнителя.
Формулировка не претендует на строгость. Конечно, имеется в виду
"любое" исключение не из реального мира, а из "мира" исполнителя (трудно
предусмотреть реакцию компьютера, например, на любую попытку его поломать).
Но зато действительно имеется в виду любое исключение из этого "мира", что
немедленно приводит еще к одному важному понятию, которому до сих пор мы не
имели случая уделить достойного внимания.
Дело в том, что предусматривать определенную реакцию на любое
исключение в каждой программе во всех отношениях неразумно. Читатель легко
поймет, почему. Поэтому наиболее общие правила такого реагирования на
исключения должны быть предусмотрены априори, еще до начала
программирования, т.е. авторами ЯП. Другими словами, существенная часть
реакции на исключения должна предусматриваться "априорными правилами
поведения исполнителя", а не собственно программой.
К сожалению, этот принцип в полной мере воплотить не удается по многим
причинам (в частности, из-за невозможности абсолютно точно определить ЯП или
безошибочно программировать). Однако он полезен в качестве ориентира для
авторов ЯП и программистов.
Об априорных правилах поведения исполнителя.
Планировать поведение исполнителя означает, в частности, согласовывать
его модель мира с моделью решаемой задачи. Чем лучше эти модели согласованы
априори, тем проще планировать поведение, проще достичь взаимопонимания. В
сущности, изученные нами абстракции включают в ЯП именно для того, чтобы
приблизить мир исполнителя к миру решаемых задач. Однако до сих пор у нас не
было случая обратить внимание на то, что "мир исполнителя" не следует
ограничивать операциями и данными (возможно, весьма мощными и
разнообразными).
Сколь мощной ни была бы операция, ее нужно явно указать в программе.
Между тем одна из самых общих технологических потребностей, потребность
писать надежные программы, только что привела нас к абстракции новой
категории, к абстракции от конкретной программы или понятию об априорных
правилах поведения исполнителя (т.е. правилах поведения, предопределенных в
ЯП и не обязательно связанных непосредственно с какими-либо указаниями в
программе).
Именно априорные правила поведения, а не специфические данные и
операции, характеризуют современные развитые ЯП. С этой точки зрения удобно