Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

metoda_2013

.pdf
Скачиваний:
54
Добавлен:
03.05.2015
Размер:
6.36 Mб
Скачать

ТЕОРИЯ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ И МЕТОДЫ ТРАНСЛЯЦИИ

 

А2 удалить два элемента «1» в

=

 

стек

"1"

 

 

 

 

 

+

А1 поместить «+» в стек

 

 

 

 

 

 

b

А1 поместить в стек «b»

 

 

 

 

 

 

 

А3 удалить из стека три элемента;

1 +

b

 

"2" в стек

=" 2"

 

 

 

 

 

)

 

 

 

 

 

 

 

*

А1 «*» в стек

 

 

 

 

 

 

 

 

(

 

 

 

 

 

 

 

с

А1 поместить в стек « с»

 

 

 

 

 

 

+

А1 поместить в стек « +»

 

 

 

 

 

 

d

А1 поместить в стек «d»

 

 

 

 

 

 

А3 удалить из стека три элемента;

c + d ="

 

."3" в стек

3"

 

 

 

 

 

)

 

 

 

 

 

 

 

 

А3 удалить из стека три элемента;

"2"

*"

 

."4" в стек

3" = "4"

 

 

 

 

 

А4 удалить из стека элемент

 

 

 

 

 

 

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

Работа с таблицей символов

 

 

Поскольку синтаксический

анализатор

обычно

использует контекстно-свободную

грамматику,

необходимо

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

270

ТЕОРИЯ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ И МЕТОДЫ ТРАНСЛЯЦИИ

Определяющая и прикладная реализация

Когда описывается идентификатор, например int a

Мы говорим, что имеется определяющая реализация «а». Однако «а» может встречаться и в другом контексте:

а:=4 или a+b или read(a),

здесь будут прикладные реализации «а» . При обработке :

определяющей реализации идентификатора компилятор помещает объект в таблицу символов,

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

Блочная структура программы

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

begin int a;

end; begin char a

. . .

end;

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

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

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

Примером Т - грамматики может служить следующая грамматика:

271

ТЕОРИЯ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ И МЕТОДЫ ТРАНСЛЯЦИИ

Г: Vтвх = {a,b,c}, Vтвых = {x,y,z}, Va = { I,A}

R = {<I> -> a<I>x<A>, <I> -> z,

<A> -> <A><C>, <A> -> by

}.

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

С использованием таких обозначений правила грамматики ГТ4.1 имеют вид:

R = {<I>->a<I>{x}<A>, <I>->{z}, <A>-><A>c, <A>->b{y}

}.

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

<I> ==> a<I>{x}<A> ==> a{z}{x}<A> ==> a{z}{x]b{y}

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

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

Входная и выходная грамматики заданной транслирующей граммагики.

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

272

ТЕОРИЯ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ И МЕТОДЫ ТРАНСЛЯЦИИ

 

Определение. Если из правил транслирующей грамматики

ГТ

удалить выходные символы, то получим

входную грамматику

ГТвх для заданной грамматики.

Если из правил заданной

транслирующей

грамматики удалить

входные символы,

то

получим выходную грамматику ГТвых

заданной транслирующей

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

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

Определение. Если из цепочки символов a , полученной путем вывода в заданной Т -грамматике , исключим все выходные символы, то получим цепочку a1, которую назовем входной цепочкой. Если же из цепочки a исключим все символы входного алфавита, то в результате получим цепочку a2, которую назовем выходной цепочкой, порождаемой Т - грамматикой . Цепочки a1 и a2 образуют пару, выводимую в заданной Т - грамматике.

Построение транслирующей грамматики по СУ - схеме.

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

Последнее определение позволяет нам сделать вывод, что один и тот же перевод может быть задан как с помощью СУ - схемы, так и с помощью Т - грамматики. Эти два способа задания являются равноправными и, более того, они допускают преобразование друг в друга.

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

Утверждение. Для каждой простой СУ-схемы Т можно построить транслирующую грамматику ГТ такую, что переводы, порождаемые СУ - схемой и Т - грамматикой, совпадают.

C(T) = C(ГТ)

Чтобы показать справедливость этого утверждения, опишем способ построения Т - грамматики по заданной СУ - схеме. Допустим, что задана СУ - схема

Т = {Vтвх, Vтвых,Va,Q,I}

273

ТЕОРИЯ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ И МЕТОДЫ ТРАНСЛЯЦИИ

и требуется построить Т - грамматику Г~ = {V'твх,V'твых,V'a,R,I}.

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

Vтвх = Vтвх', Vтвых = Vтвх', Va = Va'.

Рассмотрим преобразование правила из множества Q СУ - схемы A->a ,b , где цепочки

a = xоAох1А1...xnAn и b = yоAоу1A1...уnAn,

и поставим в соответствие этому правилу правило грамматики в виде:

А -> xоуоAох1у1A1...xnynAn.

Это можно сделать всегда, поскольку СУ - схема - простая и в каждом ее правиле используются одни и те же нетерминалы в одном и том же порядке. Рассмотренное построение обеспечивает включение во входную цепочку выходных символов цепочки, порождаемой СУ-схемой. Следовательно, каждый шаг вывода в Т - грамматике будет добавлять к выводимой цепочке те же символы, что и СУ - схема добавляет к выходной цепочке.

Применение описанных положений рассмотрим на примере построения Т - грамматики по СУ - схеме Т4.4.

Используя фигурные скобки для представления выходных символов и выполняя пре-образование, получаем грамматику

R = {<A> -> x{x}, <A> -> (<B>),

<B> -> <A><C>, <C> -> +<A>{+}<C>, <C> -> $

}.

Перевод цепочки ((x+x)+x) с применением правил построенной грамматики может быть получен с помощью следующего вывода:

<A> ==> <A><C> ==> (<B>)<C> ==> (<A><C>)<C> ==> ((<B>)<C>)<C> ==> ((<A><C>)<C>)<C> ==> ((x{x}<C>)<C> ==> ((x{x}+<A>{+}<C>)<C>)<C> ==>

((x{x}+x{x}{+}<C>)<C>)<C> ==>((x{x}+x{x}{+})<C>)<C> ==> ((x{x}+x{x}{+})+<A>{+}<C>)<C> ==> ((x{x}+x{x}{+})+x{x}{+}<C>)<C> ==> ((x{x}+x{x}{+})+x{x}{+})<C> ==> ((x{x}+x{x}{+})+x{x}{+}).

Исключая из полученной цепочки вначале выходные, а затем входные символы, получаем выводимую пару

((x+x)+x,{x}{x}{+}{x}{+}),

которая совпадает с результатом вывода в заданной СУ - схеме.

274

ТЕОРИЯ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ И МЕТОДЫ ТРАНСЛЯЦИИ

13. Атрибутивные грамматики. Синтезируемый и наследуемый атрибуты.

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

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

2.Все атрибуты нетерминальных символов и символов действия делятся на наследуемые и синтезируемые.

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

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

задается начальное значение каждого наследуемого атрибута начального символа

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

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

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

атрибута как функции некоторых других атрибутов этого символа действия.

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

275

ТЕОРИЯ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ И МЕТОДЫ ТРАНСЛЯЦИИ

Пример синтезирующего атрибута.

Предположим существует лексический блока, задающий входное множество {(,),+,*,c} , c-const для синтаксического блока допускающего выражения

7

Значение выходного символа {ОТВЕТ} должно быть числом. Требуемое отношение между значениями входных лексем и значением выходного ОТВЕТ можно выразить словами "ОТВЕТ - это числовое значение входного выражения". Найдем математическое выражение этой фразы. Рассмотрим конкретную входную цепочку: (С3 + С9) * (С2 + С41), где значения входных лексем, выданных лексическим блоком, указаны индексами. Этой входной цепочке должна соответствовать выходная цепочка ОТВЕТ516. Построим дерево вывода, соответствующее данной входной цепочке.

Каждый нетерминал этого дерева <E>, <T>, <P> помечен значением соответствующего подвыражения, а выходной символ

– требуемым выходным значением.

Чтобы определить, как расставлять значения на дереве вывода, получаемом по данной грамматике, вначале определим, как получить значение любой нетерминальной вершины, если даны значения ее прямых потомков. С этой целью сопоставим каждому правилу грамматики для <E>, <T> и <P> правило вычисления значения вершины, соответствующей нетерминалу

276

q {ОТВЕТr}

ТЕОРИЯ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ И МЕТОДЫ ТРАНСЛЯЦИИ

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

Например, правило вычисления значений для продукции E

левой части равно сумме значения нетерминала <E> в правой части и значения нетерминала <E>. Чтобы применить это правило к левому, заключенному в скобки вхождению <E>, в дереве вывода примера, значение <E> в правой части равно 3, а значение <T> равно 9. Отсюда следует, что значение <E> в левой части равно 12 и можно приписать значение 12 соответствующей вершине дерева.

значение <E> равно значению <T>. Правило для продукции <T> равно произведению значения <T> в правой части и значения <P>.

состоит в том, что значение <P> равно значению с.

правилом, что значение символа ОТВЕТ равно значению <E>. Для того, чтобы выразить приведенные выше правила

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

Тогда продукции и соответствующие им правила можно записать так:

1.

2.

E p

<E>q + <T>r

3.

Ep

q

4.

Tp

q * <P>r

5.

Tp

q

6.

Pp

q)

7.

Pp

q

277

ТЕОРИЯ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ И МЕТОДЫ ТРАНСЛЯЦИИ

Использование имен переменных локально для каждой продукции, и, если одна и та же буква p встречается в двух разных продукциях, это не имеет значения.

Приведенные выше продукции вместе с соответствующими правилами вычисления значений являются примерами “атрибутных правил”, и взятые вместе с начальным нетерминалом <S> образуют “атрибутную грамматику”. Значения вышеприведенных правил называются “атрибутами”.

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

Пример наследуемого атрибута.

Рассмотрим следующую грамматику:

1.<описание>::=type id <список переменных>

2.<список переменных>::=, id <список переменных>

3.<список переменных>::=e /пустое правило/

Предположим, что существует лексический блок, задающий три лексемы id ТИП, где лексема id обозначает идентификатор и ее значение является указателем на соответствующий этому идентификатору элемент таблицы имен. ТИП – лексема со значением, определяющим, какой из типов, ВЕЩЕСТВЕННЫЙ,

278

ТЕОРИЯ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ И МЕТОДЫ ТРАНСЛЯЦИИ

ЦЕЛЫЙ или ЛОГИЧЕСКИЙ, должен быть поставлен в соответствии идентификаторам из данного списка.

При обработке описания каждой переменной синтаксический блок вызывает процедуру УСТАНОВИТЬ_ТИП, которая помещает один из типов ВЕЩЕСТВЕННЫЙ, ЦЕЛЫЙ или ЛОГИЧЕСКИЙ в надлежащее поле таблицы символов. Вызов процедуры УСТАНОВИТЬ_ТИП лучше всего осуществлять сразу после того как, идентификатор поступил на блок синтаксического анализатора. Это можно описать следующей грамматикой, использующей символ действия:

1.<описание>::=type id {УСТАHОВИТЬ_ТИП} <список переменных>

2.<список переменных>::=, id {УСТАHОВИТЬ_ТИП} <список переменных>

3.<список переменных>::=e /пустое правило/

Пусть процедура УСТАНОВИТЬ_ТИП имеет два аргумента: это идентификатор (или его адрес) и тип. Тогда вызов процедуры УСТАHОВИТЬ_ТИП можно записать УСТАНОВИТЬ_ТИП (id, type). Введем в вышеприведенную грамматику атрибуты и правила их вычисления, чтобы в последовательностях актов входные символы были представлены вместе с их значениями, играющими роль атрибутов, а вхождения символов действия {УСТАНОВИТЬ_ТИП} имели по два атрибута, представляющих аргументы соответствующего вызова процедуры УСТАНОВИТЬ_ТИП. Тогда вхождения УСТАНОВИТЬ_ТИП будут

иметь такой вид: {УСТАНОВИТЬ_ТИП}id, type.

Рассмотрим, как УСТАНОВИТЬ_ТИП получает свои атрибуты. В правиле 1 это делается просто, так как атрибуты можно получить используя входные символы type и id, входящие в это правило. В правиле 2 type не доступен, его нужно передать используя атрибуты нетерминала. Поэтому нетерминал <список переменных> должен иметь атрибут, который будет представлять тип.

Таким образом, грамматика перепишется :

1.<описание>::=typet idp {УСТАHОВИТЬ_ТИП}p1, t1 <список переменных> t2

2.<список переменных> t ::=, id p {УСТАHОВИТЬ_ТИП}p1, t1 <список переменных> t2

3.<список переменных> t ::=e /пустое правило/

279

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]