Опубликован: 23.07.2006 | Уровень: специалист | Доступ: платный
Лекция 7:

Восходящие анализаторы

Пример конфликта перенос-свертка

Итак, имеется следующая входная цепочка: if E1 then if E2 then S1 else S2. Рассмотрим работу анализатора пошагово:

Содержимое стека Необработанная часть входной цепочки Действие
$ if E1 then if E2 then S1 else S2 shift
$if E1 1 then if E2 then S1 else S2 shift
$ if E 1 then if E2 then S1 else S2 shift
$ if E1 then if E2 then S1 else S2 shift
$ if E1 then if E2 then S1 else S2 shift
$ if E1 then if E2 then S1 else S2 shift
$ if E1 then if E2 then S1 else S2 shift
$ if E1 then if E2 then S1 else S2 shift

После последнего шага возникают две альтернативы: либо (а) применить свертку по правилу 1 к последовательности if E2 then S1 на вершине стека, либо (б) перенести символ else на вершину стека. Обе альтернативы легко угадываются из вида правил 1 и 2. Грамматики с правилами такого типа называются грамматиками с "висящим" (dangling) else .

Для подавляющего большинства языков программирования, имеющих условные операторы описанного вида, действие (б) предпочтительно. Общепринятым правилом для данной ситуации является соотнесение каждого else с "ближайшим" then . Это правило может быть формализовано с использованием однозначной грамматики. Идея в том, чтобы установить соответствие между then и else , что эквивалентно требованию, чтобы между then и else могли появиться только оператор, не являющийся условным оператором, или условный оператор с обязательным else ( if expr then stmt else stmt ).

Разрешение конфликта перенос-свертка

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

(1) stmt -> matched_stmt
(2) stmt -> unmatched_stmt
(3) matched_stmt -> if expr then matched_stmt else matched_stmt
(4) matched_stmt -> Other
(5) unmatched_stmt -> if expr then stmt
(6) unmatched_stmt -> if expr then matched_stmt else unmatched_stmt

Новая грамматика порождает тот же язык, что и старая, но вывод цепочки if E1 then if E2 then S1 else S2 теперь не содержит конфликтов.

Альтернативой построению новой грамматики может служить "соглашение", что в случае конфликта перенос-свертка, перенос является предпочтительным действием.

После принятия одной из этих альтернатив вывод может быть продолжен следующим образом:

Stack contents Unprocessed input string Action
$ if E1 then if E2 then S1 else S2 shift
$ if E1 then if E2 then S 1 else S2 reduce [2]
$ if E 1 then S reduce [1]
$

Неоднозначные грамматики. Конфликт перенос-перенос

Второй тип конфликта, который может возникнуть, это так называемый конфликт перенос-перенос ( reduce/reduce ), который возникает, когда на вершине стека анализатора возникает строка терминалов, к которой может быть применена свертка по двум различным правилам.

Пример.Рассмотрим грамматику G 2 ('id', '(', ')', '=' и ',' - терминалы) .

(1) stmt -> id (parameters_list)
(2) stmt -> expr = expr
(3) parameter_list -> parameter_list, parameter
(4) parameter_list -> Parameter
(5) parameter -> Id
(6) expr -> id (expr_list)
(7) expr -> Id
(8) expr_list -> expr_list, expr
(9) expr_list -> Expr

В процессе разбора входной цепочки id (id, id) происходит следующее:

Содержимое стека Необработанная часть Действие
$ id (id, id) shift
$ id (id, id) shift
$ id ( id, id) shift
$ id (id , id) shift

Очевидно, что после выполнения последнего шага необходимо произвести свертку находящегося на вершине стека терминала id . Но какое правило использовать? Если использовать правило (5), то будет получен вызов процедуры, если использовать правило (7), то получится вырезка из массива. Чтобы избежать неоднозначности, в первом правиле можно заменить терминал id на другой терминал, например, procid . Но в этом случае, чтобы вернуть правильный лексический класс, лексический анализатор должен выполнить сложную работу по определению, является ли данный идентификатор обозначением процедуры или массива.

Вероника Стрельская
Вероника Стрельская
Россия
Сергей Покаляев
Сергей Покаляев