И.А. Волкова, И.Г. Головин, Л.Е. Карпов - Системы программирования (1119414), страница 9
Текст из файла (страница 9)
Компилятор обязан сообщить об ошибке, если в программепредписано выполнить некоторую операцию с несовместимым с нейоперандом, например, произвести сложение указателей.2. Проверки управления. Передача управления за пределы синтаксическихконструкций должна производиться только в разрешенные места программы.Например, в языках Си и Си++ оператор выхода из цикла break можетвстречаться только внутри операторов цикла или перебора. Любое другое егоупотребление должно приводить к сообщению об ошибке.3.
Проверки единственности. В определенных ситуациях объект можетупотребляться только один раз. Например, во многих языкахпрограммирования, где есть оператор перебора, все метки в конструкцияхописания альтернатив case одного оператора должны быть уникальными,элементы в перечислениях enum также не должны повторяться.4. Проверки, связанные с именами. Иногда одно и то же имя должноиспользоваться дважды или большее число раз. Компилятор долженпроверять, что во всех местах использовано одинаковое имя. Например, вязыке Ада процедура блок или цикл может иметь имя, которое должнонаходиться и в начале, и в конце синтаксической конструкции.К типичным для многих языков контекстным условиям относятся такиесемантические ограничения:••••••каждое имя, используемое в программе, должно быть описано, причемтолько один раз;в операторе присваивания типы переменной и выражения должны совпадать(либо относиться к некоторым семантически близким типам);в условном операторе и в операторе цикла в качестве условия возможнотолько логическое выражение;операнды операций отношения должны быть целочисленными (либо иметькакие-либо другие, но точно известные типы);тип выражения и совместимость типов операндов в выраженииопределяются по фиксированным для данного языка правилам; старшинствоопераций обычно задано синтаксическими правилами;каждая метка, на которую есть ссылка или переход, должна один разприсутствовать в программе (несколько вхождений одной метки легкопроверяются во время анализа синтаксиса);34•••единственность описаний идентификаторов рассматривается с учетомблочной структуры программы;при вызове функции число фактических параметров и их типы должнысоответствовать числу и типам формальных параметров;обычно в языке накладываются ограничения на типы операндов каждойоперации, определенной в этом языке; на типы левой и правой частей воператоре присваивания; на тип параметра цикла; на тип условия воператорах цикла и условном операторе и т.
п.Конкретный состав подобных требований жестко связан с семантикойкомпилируемогоязыка.Например,требованиеобязательногоописанияидентификаторов в некоторых языках отсутствует. Некоторые языки допускаютавтоматическое преобразование типов несогласованных операндов выражений. Иногдав вызовах процедур и функций допускается указывать не все фактические параметры,остальные параметры получают значения по умолчанию.Семантический анализатор должен фиксировать все случаи нарушениясемантических соглашений и условий, найденные им в программе, и выдаватьсообщения о семантических ошибках в программе.3.3.2.2. Дополнение внутреннего представленияМногие языки запрещают смешивать в выражениях операнды даже “близких”типов, например, использовать рядом операнды вещественных и целочисленных типов,знаковых и беззнаковых типов и т. д.
Однако большинство реальных языковпрограммирования допускает некоторые вольности при записи выражений, гарантируя,что в компиляторах будут предприняты меры по согласованию типов. Абсолютноаналогичная работа выполняется при обработке операций обращения к функциям ипроцедурам с параметрами.Задача семантического анализатора состоит в поиске всех мест, где нужновыполнить подобные преобразования типов и вставить во внутреннее представлениеявные команды преобразования. Иногда эти преобразования тривиальны и состоят изодной-двух команд, а иногда они выполняются встроенными библиотечнымифункциями.Преобразования типов могут производиться не только по отношению к простымарифметическим данным.
Во многих языках существуют данные, позволяющиессылаться на другие данные – указатели и ссылки. Иногда операция доступа к даннымпо указателю приводит к введению в программу целой серии команд по настройкевнутренних регистров, выделению фрагментов данных, размеры которых не кратныцелому числу машинных слов или байтов и т. д.Все это означает, что действия, выполняемые при семантическом анализекомпилируемой программы, существенным образом влияют на порождаемыекомпилятором объектные программы.3.3.2.3.
Проверка правил программированияМногие современные компиляторы не только проверяют ограничения итребования, выставляемые семантикой языка, но также выполняют дополнительныепроверки, способствуя выработке “правильного” стиля программирования. Во многихязыках программирования действуют правила хорошего программирования.35••••••Каждая переменная или описанная константа программы должна бытьиспользована в программе хотя бы один раз.Каждая переменная программы должна получить значение до своего первогоиспользования (например, до использования в правой части оператораприсваивания).Результат вычисления функции должен быть определен при любом ходе еевыполнения (например, независимо от выбора исполняемых ветвей вусловных операторах).В программе не должно быть невыполняемых в принципе операторов.Каждый оператор программы должен иметь потенциальную возможностьвыполниться хотя бы один раз.Условные операторы (всех разновидностей) должны предусматриватьвозможность хода выполнения программы по любой из своих ветвей.Операторы цикла должны предусматривать возможность завершения цикла.3.3.2.4.
Разнесение имен по пространствам именованияРаспределение использованных в программе идентификаторов по пространствамименования есть одна из важных задач этапа семантического анализа. Требованияразличных языков программирования, предъявляемые к именам используемых впрограммах объектов, распространяются на имена объектов, относящиеся к однимпространствам именования и видимости.
С одной стороны это означает, что объектынельзя использовать вне тех блоков, где они описаны и видны, с другой стороны, этоослабляет требования уникальности имен, поскольку объектам, относящимся к разнымблокам, можно давать одинаковые имена, не внося при этом путаницы в программу.На этапе лексического анализа разрешить все эти проблемы абсолютноневозможно – там уникальность имен определяется только их записью какпоследовательности букв, цифр и других разрешенных символов.
На более позднихстадиях компиляции одинаково записываемые имена необходимо заменять на новыеуникальные в пределах всей программы. В частности,••••имена локальных объектов блоков дополняются именами блоков (функций,процедур), в которых они описаны,имена внутренних (в терминах языка Си++ – статических) переменных ифункций модулей программы дополняются именами самих этих модулей,имена процедур и функций, принадлежащих классам в объектноориентированных языках (Си++) или вложенных в другие процедуры ифункции в процедурных языках дополняются именами этих классов илипроцедур,имена методов в описаниях классов дополняются именами, строящимися взависимости от числа и типов их формальных параметров, это же относитсяи к именам перегруженных функций Си++.Особой заботой компиляторов являются имена внешних (глобальных) объектов,которые остаются видимыми в объектной программе и могут обрабатываться другимикомпонентами систем программирования, например, редакторами связей.
Для такихимен в конкретных системах программирования могут существовать собственныесоглашения именования. Такие имена должны быть уникальными на уровне библиотек,в которые они могут попадать после завершения компиляции.363.3.3. Внутреннее представление программДополнительную сложность задаче компиляции придает тот факт, что из-засерьезных различий между входным и выходным языками провести непосредственноепреобразование из одного языка в другой не всегда представляется возможным. Дажесинтаксический анализ исходного текста приходится делать поэтапно, разбивая его налексическую и собственно синтаксическую часть.
Это позволяет использовать накаждом этапе свои грамматические правила разбора, существенно упрощая реализациюраспознавателей, применяемых на этих этапах. Именно поэтому часто в компиляторахна некоторых стадиях обработки программ возникает некоторое промежуточноевнутреннее представление компилируемой программы, которое лишь на завершающейстадии преобразуется в представление программы на выходном языке компилятора.К основным свойствам языков внутреннего представления программ можноотнести такие:•••языки внутреннего представления позволяют фиксировать синтаксическуюструктуру исходной программы;текст на языках внутреннего представления можно автоматическигенерировать во время синтаксического анализа;конструкции языков внутреннего представления относительно простотранслируются в объектный код, либо достаточно эффективноинтерпретируются.Легче всего синтаксическому анализатору организовать внутреннее (а для себя –выходное) представление в виде дерева синтаксического разбора.