Опубликован: 23.07.2006 | Доступ: свободный | Студентов: 2215 / 889 | Оценка: 4.28 / 4.17 | Длительность: 21:37:00
Специальности: Системный архитектор
Лекция 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 . Но в этом случае, чтобы вернуть правильный лексический класс, лексический анализатор должен выполнить сложную работу по определению, является ли данный идентификатор обозначением процедуры или массива.