Операционная система UNIX. Руководство программиста

     

СТАРШИНСТВО ОПЕРАЦИЙ


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

expr : expr OP expr

или

expr : UNARY expr

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

Приоритеты и ассоциативности связываются с лексемами в секции определений. Это делается в группе строк, начинающихся с ключевых слов yacc'а %left, %right или %nonassoc, за которыми следуют списки лексем. Считается, что все лексемы в одной строке имеют одни и те же приоритет и ассоциативность; строки указываются в порядке возрастания приоритета. Так, строки

%left '+' '-' %left '*' '/'

задают приоритет и ассоциативность четырех арифметических операций. '+' и '-' левоассоциативны и имеют меньший приоритет, чем также левоассоциативные '*' и '/'. Для описания правоассоциативных операций используется ключевое слово %right, а для описания операций, подобных операции .LT. в Фортране, которые не являются ассоциативными, - ключевое слово %nonassoc. Например, выражение

A .LT. B .LT. C

некорректно в Фортране; поэтому такую операцию следует описать в yacc при помощи ключевого слова %nonassoc. Действие названных ключевых слов иллюстрирует спецификация


%right '=' %left '+' '-' %left '*' '/'

%%



expr : expr '=' expr | expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | NAME ;

Ее можно использовать, чтобы входную цепочку

a = b = c * d - e - f * g

структурировать следующим образом:

a = (b = (((c * d) - e) - (f * g)))

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

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

%left '+' '-' %left '*' '/'

%%

expr : expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | '-' expr %prec '*' | NAME ;

можно использовать, чтобы установить унарному минусу тот же приоритет, что и у умножения.

Лексему, описанную при помощи конструкций %left, %right или %nonassoc, можно (но не обязательно) описать и при помощи %token.

Приоритеты и ассоциативность yacc использует для того, чтобы разрешить конфликты разбора. Они задают следующие методы разрешения неоднозначностей:


  • Приоритеты и ассоциативность приписываются тем лексемам и литералам, для которых они заданы явно.


  • Грамматическому правилу сопоставляются приоритет и ассоциативность последней лексемы или литерала в теле правила. В случае использования конструкции %prec это сопоставление переопределяется. Некоторым правилам приоритет и ассоциативность могут не сопоставляться.


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




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


Конфликты, разрешенные при помощи приведенного метода, не учитываются при подсчете сообщаемого yacc'ом числа конфликтов перенос-свертка и свертка-свертка. Это означает, что ошибки в спецификации приоритетов могут замаскировать ошибки во входной грамматике. Хорошо было бы воздерживаться от задания приоритетов или использовать их весьма осторожно, пока не приобретен определенный опыт. Чтобы убедиться, что получен именно тот алгоритм разбора, который требуется, следует изучить содержимое файла y.output.




Содержание раздела