The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Каталог документации / Раздел "Программирование, языки" / Оглавление документа

[ Содержание ] [ Предыдущая ] [ Следующая ]

Глава 2. Действия

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

     Действие - это произвольный оператор C, и поэтому может производить ввод и вывод, вызывать подпрограммы и изменять внешние переменные. Дейстиве обозначается одним или более операторами, заключенными в фигурные скобки "{" и "}". Hапример,

A : '(' B ')'
  { hello( 1, "abc" ); }

    и

XXX : YYY ZZZ
  { printf("a message\n"); flag = 25; }

    являются грамматическими правилами с действиями.

     Операторы действий слегка изменяются, чтобы способствовать простой связим между действиями и парсером. Символ доллара "$" используется как сигнал Yacc-y в этом контексте.

     Чтобы вернуть значение, дейстиве обычно устанавливает псевдопеременную "$$" в некоторое значение. Hапример, действие, которое ничего не делает, а только возвращает значение 1 , это

{ $$ = 1 }

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

A : B C D ;

    то $2 имеет значение, возвращенное C, а $3 - значение, возвращенное D.

     Как более конкретный пример, представим правило

expr : '(' expr ')' ;

    Значение, возвращенное этим правилом - это обычно значение expr в скобках. Это может быть выражено так:

expr : '(' expr ')'
  { $$ = $2 ; }

    По умолчанию значение правила - это значение первого элемента в нем ($1). Таким образом, грамматическое правило вида

A : B ;

    часто не требует явного действия.

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

A : B
  { $$ = 1; }
  C
  { x = $2; y = $3; }
  ;

    устанавливает x в 1, а y - в значение, возвращенное C.

     Действия, которые не завершают правило, в действительности обрабатываются Yaccом с помощью нового нетерминального символа и нового правила, сопоставляющего это имя с пустой строкой. Внутреннее действие - это действие, вызываемое при распознавании этого добавленного правила. Yacc в действительности обращается с вышеприведенным примером, как будто он написан как

$ACT : /* пустое */
  { $$ = 1; }
  ;
A : B $ACT C
  { x = $2; y = $3; }
  ;

    В многих приложениях вывод не производится напрямую действиями; скорее, в памяти генерируется структура, такая как дерево разбора и она преобразуется перед тем, как генерируется вывод. Деревья разбора чрезвычайно просто строить, при заданных функциях построения и обработки желаемой структуры дерева. Hапример, предположим, что существует функция на C node(), написанная так, что вызов

node( L, n1, n2 )

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

expr : expr '+' expr
  { $$ = node( '+', $1, $3 ); }

    Пользователь может определить другие переменные для использования в дейстивях. Объявления и описания могут появляться в секции объявлений, заключенные в символы "%{" и "}%". Эти объявления и определения имеют глобальную область действия, так что они известны операторам действий и лексическому анализатору. Hапример,

%{
int variable = 0;
%}

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

     В этих примерах все значения - целые: обсуждение значений других типов будет в главе 10.

[ Содержание ] [ Предыдущая ] [ Следующая ]



c 1998-2000 SoloTony (Antonio Solo) solotony@mail.ru



Спонсоры:
Слёрм
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2020 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру