Лекции.Орг


Поиск:




Категории:

Астрономия
Биология
География
Другие языки
Интернет
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Механика
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Транспорт
Физика
Философия
Финансы
Химия
Экология
Экономика
Электроника

 

 

 

 


Этапы семантического анализа




 

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

· проверку соблюдения во входной программе семантических соглашений вход­ного языка;

· дополнение внутреннего представления программы в компиляторе операто­рами и действиями, неявно предусмотренными семантикой входного языка;

· проверку элементарных семантических (смысловых) норм языков програм­мирования, напрямую не связанных с входным языком.

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

Примерами таких соглашений являются следующие требования:

· каждая метка, на которую есть ссылка, должна один раз присутствовать в про­грамме;

· каждый идентификатор должен быть описан один раз, и ни один идентифи­катор не может быть описан более одного раза (с учетом блочной структуры описаний);

· все операнды в выражениях и операциях должны иметь типы, допустимые для данного выражения или операции;

· типы переменных в выражениях должны быть согласованы между собой;

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

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

Например, если мы возьмем оператор языка Pascal, имеющий вид: а:= b+с; то с точки зрения синтаксического разбора это будет абсолютно правильный оператор. Однако мы не можем сказать, является ли этот оператор правильным с точки зрения входного языка (Pascal), пока не проверим семантические требо­вания для всех входящих в него лексических элементов. Такими элементами здесь являются идентификаторы а, b и с. Не зная, что они собой представляют, мы не можем не только окончательно утверждать правильность приведенного выше оператора, но и понять его смысл. Фактически необходимо знать описание этих идентификаторов.

В том случае, если хотя бы один из них не описан, имеет место явная ошибка. Если это числовые переменные и константы, то мы имеем дело с оператором сложения, если же это строковые переменные и константы – с оператором кон­катенации строк. Кроме того, идентификатор а, например, ни в коем случае не может быть константой – иначе нарушена семантика оператора присваивания. Также невозможно, чтобы одни из идентификаторов были числами, а другие – строками, или, скажем, идентификаторами массивов или структур – такое соче­тание аргументов для операции сложения недопустимо. И это только некоторая часть соглашений, которые должен проверить компилятор с точки зрения семан­тики входного языка (в данном примере – Pascal).

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

Если какое-либо из семантических требований входного языка не выполняется, то компилятор выдает сообщение об ошибке и процесс компиляции на этом, как правило, прекращается.

Дополнение внутреннего представления программы операторами и действиями, предусмотренными семантикой входного языка, неявно связано с преобразова­нием типов операндов в выражениях и при передаче параметров в процедуры и функции. Если вернуться к рассмотренному выше элементарному оператору языка Pascal: а:= b+с; то можно отметить, что здесь выполняются две операции: одна операция сложе­ния (или конкатенации, в зависимости от типов операндов) и одна операция присвоения результата. Соответствующим образом должен быть порожден и код результирующей программы.

Однако не все так очевидно просто. Допустим, что где-то перед рассмотренным оператором мы имеем описание его операндов в виде:

 

var

a: real;

b: integer;

с: double;

 

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

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

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

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

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

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

Примерами таких соглашений являются следующие требования:

· каждая переменная или константа должна хотя бы один раз использоваться в программе;

· каждая переменная должна быть определена до ее первого использования при любом ходе выполнения программы (первому использованию перемен­ной должно всегда предшествовать присвоение ей какого-либо значения);

· результат функции должен быть определен при любом ходе ее выполнения;

· каждый оператор в исходной программе должен иметь возможность хотя бы один раз выполниться;

· операторы условия и выбора должны предусматривать возможность хода вы­полнения программы по каждой из своих ветвей;

· операторы цикла должны предусматривать возможность завершения цикла.

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

Необязательность соглашений такого типа – еще одна из особенностей при их обработке в семантическом анализаторе: их несоблюдение не может трак­товаться как ошибка. Даже если компилятор полностью уверен в своей “право­те”, тот факт, что какое-то из указанных соглашений не соблюдается, не должен приводить к прекращению компиляции входной программы. Обычно факт обна­ружения несоблюдения такого рода соглашений трактуется компилятором как “предупреждение” (warning). Компилятор выдает пользователю сообщение об обнаружении несоблюдения одного из требований, не прерывая сам процесс ком­пиляции, т. е. он просто обращает внимание пользователя на то или иное место в исходной программе. То, как реагировать на “предупреждение” (вносить изменения в исходный код или проигнорировать этот факт), – это уже забота и ответственность разработчика программы.

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

 





Поделиться с друзьями:


Дата добавления: 2016-11-18; Мы поможем в написании ваших работ!; просмотров: 825 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Слабые люди всю жизнь стараются быть не хуже других. Сильным во что бы то ни стало нужно стать лучше всех. © Борис Акунин
==> читать все изречения...

2195 - | 2119 -


© 2015-2024 lektsii.org - Контакты - Последнее добавление

Ген: 0.01 с.