Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Шпоры по тяпу.docx
Скачиваний:
8
Добавлен:
01.04.2025
Размер:
808 Кб
Скачать
☆

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

Одним из средств автоматизированного построения трансляторов является генератор компиляторов Yacc.

Yacc строит синтаксический анализатор, работающий на основе метода “сдвиг - приведение”.

Этот генератор работает с атрибутными грамматиками. Атрибутные грамматики характеризуются тем, что с каждым грамматическим символом связывается множество атрибутов.

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

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

Исходный текст для Yacc, основой которого являются продукции и семантические правила, пишется в текстовом редактор и сохраняется в файле с расширением y. Работа программы yacc.exe, в качестве параметра которой выступает исходный файл с расширением y, строит транслятор. Yacc строит транслятор на основе кода, содержащегося в файле Yyparse.cod. Если исходный текст содержит ошибки, то при генерации транслятора будет создан файл ошибок с расширением lst.

Полученный в результате работы yacc модуль присоединяется к проекту Delphi, который содержит текст основной программы. Для корректной работы с этим проектом, он должен использовать библиотеку Yacclib.pas.

Транслятор строится Yacc в виде функции yyparse, которая вызывается из основной программы.

При генерации транслятора Yacc включает код лексического анализатора, построенного Lex.

Исходный текст для yacc состоит из трех частей: определения, продукции и вспомогательные процедуры. Части разделяются символами %%.

В части определений можно указать код, который должен быть перенесен в текст результирующего транслятора без изменения. Для этого он помещается между символами %{ и %}. В качестве такого кода могут выступать заголовок модуля или объявления типов, используемые затем для описания атрибутов терминалов и нетерминалов.

В результирующем коде будет объявлена переменная yyLval. Эта переменная всегда автоматически определяется YACC в тексте синтаксического анализатора и используется для хранения атрибутов терминалов, которые должны быть переданы из лексического анализатора в синтаксический. Тип этой переменной YYSType

Часть определений включает следующие разделы.

1 Задание стартового символа.

%start символ

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

2 Определение атрибутов терминалов грамматики.

%token <тип атрибута> терминал

При наличии такого определения в исходном тексте, в модуле, содержащем транслятор, декларируется константа указанного типа с именем, соответствующим терминалу. Эти константы используются в исходном файле Lex без дополнительных объявлений. В качестве типа может быть использован любой стандартный тип Pascal или декларированный ранее.

3 Задание ассоциативности операций.

%left символ – лево ассоциативная операция

%right символ – право ассоциативная операция

%noassoc символ – неассоциативная операция

Приоритет операции определяется ее положением при определении. Чем ниже задана операция при определении, тем выше ее приоритет.

4 Задание типов атрибутов нетерминалов

%type <тип атрибута> нетерминал.

Вторая часть Yacc-программы содержит продукции и связанные с ними семантические правила. Левая часть продукции отделяется от правой символом “:”.

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

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

нетерминал : продукция 1 {семантическое правило 1}

| продукция 2 {семантическое правило 2}

…

| продукция n {семантическое правило n}

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

Если мы используем неоднозначную грамматику, то LALR-алгоритм будет генерировать конфликты действий синтаксического анализа. Yacc может автоматически решать конфликты исходы из правил: 1) Конфликт свертка/свертка разрешает выбором продукции, находящейся первой в спецификации Yacc. 2) конфликт перенос/свертка разрешается в пользу переноса. Это правило корректно разрешает конфликт, возникающий из-за неоднозначности появления else. Эти правила по умолчанию не всегда представляют именно то,что требуется создателю компилятора, Yacc обеспечивает общий механизм для разрешения конфликтов перенос/свертка. В частьности объявлений терминалам можно назначить приоритеты и ассоциативность. Можно обеспечить неассоциативность оператора (операторы не могут быть скомбинированы). Yacc разрешает конфликты перенос/свертка назначением приоритета и ассоциативности каждой продукции, участвующей в конфликте. Если необходимо осуществить выбор между переносом входного символа a и сверкой в соответствии с продукцией A-> α, то Yacc выполняет свертку, если приоритет продукции выше приоритета a, или если приоритеты одинаковы, и ассоциативность продукции – левая. В противном случае перенос