LR(k)-грамматики — различия между версиями
Margarita (обсуждение | вклад) (→Алгоритм) |
Margarita (обсуждение | вклад) |
||
| Строка 2: | Строка 2: | ||
== LR(k)-грамматика == | == LR(k)-грамматика == | ||
| + | === Определение === | ||
| + | |||
{{Определение | {{Определение | ||
|id=def_augmented_grammar) | |id=def_augmented_grammar) | ||
| Строка 10: | Строка 12: | ||
|id=def_LR_K | |id=def_LR_K | ||
|definition= | |definition= | ||
| − | Пусть <tex>\Gamma' =\langle \Sigma', N', S', P' \rangle</tex> {{---}} пополненная грамматика для КС-грамматики <tex>\Gamma</tex>. Грамматика <tex>\Gamma</tex> | + | Пусть <tex>\Gamma' =\langle \Sigma', N', S', P' \rangle</tex> {{---}} пополненная грамматика для КС-грамматики <tex>\Gamma</tex>. Грамматика <tex>\Gamma</tex> является '''LR(k)-грамматикой''', если для любых двух [[Контекстно-свободные_грамматики,_вывод,_лево-_и_правосторонний_вывод,_дерево_разбора#Лево-_и_правосторонний_вывод_слова|правосторонних выводов]]: |
* <tex>S' \Rightarrow^* \beta A t z \Rightarrow \beta \alpha t z \Rightarrow^* w, </tex> если <tex>|t|=k</tex> или <tex>|t|<k, |z|=0 (z = \varepsilon)</tex> | * <tex>S' \Rightarrow^* \beta A t z \Rightarrow \beta \alpha t z \Rightarrow^* w, </tex> если <tex>|t|=k</tex> или <tex>|t|<k, |z|=0 (z = \varepsilon)</tex> | ||
* <tex>S' \Rightarrow^* \gamma B t z' \Rightarrow \gamma \xi t z' \Rightarrow^* w', </tex> если <tex>|t|=k</tex> или <tex>|t|<k, |z'|=0 (z' = \varepsilon)</tex> | * <tex>S' \Rightarrow^* \gamma B t z' \Rightarrow \gamma \xi t z' \Rightarrow^* w', </tex> если <tex>|t|=k</tex> или <tex>|t|<k, |z'|=0 (z' = \varepsilon)</tex> | ||
| Строка 25: | Строка 27: | ||
* не более <tex>k</tex> символов цепочки (англ. ''k-token lookahead'') используются для принятия решения. | * не более <tex>k</tex> символов цепочки (англ. ''k-token lookahead'') используются для принятия решения. | ||
| − | ====Замечание о | + | ====Замечание о пополненной грамматике==== |
Использование в определении LR(k)-грамматики пополненной грамматики существенно для однозначного определения конца анализа. Действительно, если грамматика использует <tex>S</tex> в правых частях правил, то свертка основы в <tex>S</tex> не может служить сигналом приема входной цепочки. Свертка же в <tex>S'</tex> в пополненной грамматике служит таким сигналом, поскольку <tex>S'</tex> нигде, кроме начальной сентенциальной формы, не встречается. | Использование в определении LR(k)-грамматики пополненной грамматики существенно для однозначного определения конца анализа. Действительно, если грамматика использует <tex>S</tex> в правых частях правил, то свертка основы в <tex>S</tex> не может служить сигналом приема входной цепочки. Свертка же в <tex>S'</tex> в пополненной грамматике служит таким сигналом, поскольку <tex>S'</tex> нигде, кроме начальной сентенциальной формы, не встречается. | ||
| − | Существенность использования пополненной грамматики в определении LR(k)-грамматик продемонстрируем на следующем конкретном примере. Пусть | + | Существенность использования пополненной грамматики в определении LR(k)-грамматик продемонстрируем на следующем конкретном примере. Пусть пополненная грамматика имеет следующие правила: |
<tex> | <tex> | ||
| Строка 58: | Строка 60: | ||
Управляющая программа одинакова для всех LR-анализаторов, а таблица и автомат изменяются от одного анализатора к другому. | Управляющая программа одинакова для всех LR-анализаторов, а таблица и автомат изменяются от одного анализатора к другому. | ||
| − | Для запоминания строки запись в стек имеет вид: <tex>s_0X_1s_1X_2...X_ms_m</tex>, где <tex>s_m</tex> {{---}} вершина стека. Каждый <tex>X_i</tex> {{---}} символ грамматики(терминал или нетерминал), а <tex>s_i</tex> {{---}} состояние автомата. Каждое состояние суммирует информацию, cодержащуюся в стеке перед ним. <tex>s_0</tex> {{---}} | + | Для запоминания строки запись в стек имеет вид: <tex>s_0X_1s_1X_2...X_ms_m</tex>, где <tex>s_m</tex> {{---}} вершина стека. Каждый <tex>X_i</tex> {{---}} символ грамматики(терминал или нетерминал), а <tex>s_i</tex> {{---}} состояние автомата. Каждое состояние суммирует информацию, cодержащуюся в стеке перед ним. <tex>s_0</tex> {{---}} стартовое состояние автомата. |
| − | Обращение к таблице происходит | + | Обращение к таблице происходит следующим образом <tex>\mathtt{T[state, token]}</tex>, где |
*<tex>\mathtt{state}</tex> {{---}} состояние автомата, | *<tex>\mathtt{state}</tex> {{---}} состояние автомата, | ||
*<tex>\mathtt{token}</tex> {{---}} входной символ; | *<tex>\mathtt{token}</tex> {{---}} входной символ; | ||
| Строка 83: | Строка 85: | ||
=== Алгоритм === | === Алгоритм === | ||
# Программа читает символ из входной цепочки. | # Программа читает символ из входной цепочки. | ||
| − | # Обращается к | + | # Обращается к управляющей таблице. |
# Совершает соответствующее действие. | # Совершает соответствующее действие. | ||
# Возвращается к первому пункту, пока входная цепочка не закончится. | # Возвращается к первому пункту, пока входная цепочка не закончится. | ||
| Строка 91: | Строка 93: | ||
<font size=2> | <font size=2> | ||
'''Result''' algorithmLR(w: '''string''') | '''Result''' algorithmLR(w: '''string''') | ||
| − | curToken {{---}} указатель на | + | curToken {{---}} указатель на первый символ в строке w |
'''while''' haveToken() | '''while''' haveToken() | ||
curState = top() | curState = top() | ||
Версия 18:19, 30 августа 2015
Восходящий разбор (англ. Bottom-up parsing) предназначен для построения дерево разбора. Мы можем представить себе этот процесс как "свертку" исходной строки к правилу грамматики. Каждый шаг свертки заключается в сопоставлении некоторой подстроки и правой части какого-то правила грамматики, затем происходит замена этой подстроки на нетерминал, являющийся левой частью правила. Восходящий разбор менее интуитивный, чем нисходящий, но зато позволяет разбирать большее множество грамматик.
Содержание
LR(k)-грамматика
Определение
| Определение: |
| Пусть — контекстно-свободная грамматика. Пополненной грамматикой (англ. augmented grammar), полученной из , назовем грамматику , где |
| Определение: |
Пусть — пополненная грамматика для КС-грамматики . Грамматика является LR(k)-грамматикой, если для любых двух правосторонних выводов:
верно, что , следует, что и |
Говоря неформально, мы делаем правостороннюю свёртку нашей строки в стартовый нетерминал. Если по не более чем символам неразобранной строки мы можем однозначно определить, во что сворачивается хвост выведенного правила, то грамматика будет LR(k).
LR(k) означает, что
- входная цепочка обрабатывается слева направо (англ. left-to-right parse);
- выполняется правый вывод (англ. rightmost derivation);
- не более символов цепочки (англ. k-token lookahead) используются для принятия решения.
Замечание о пополненной грамматике
Использование в определении LR(k)-грамматики пополненной грамматики существенно для однозначного определения конца анализа. Действительно, если грамматика использует в правых частях правил, то свертка основы в не может служить сигналом приема входной цепочки. Свертка же в в пополненной грамматике служит таким сигналом, поскольку нигде, кроме начальной сентенциальной формы, не встречается.
Существенность использования пополненной грамматики в определении LR(k)-грамматик продемонстрируем на следующем конкретном примере. Пусть пополненная грамматика имеет следующие правила:
Если игнорировать -е правило, то, не заглядывая в правый контекст основы , можно сказать, что она должна сворачиваться в . Аналогично основа безусловно должна сворачиваться в . Создается впечатление, что данная грамматика без -го правила есть LR(0)-грамматика. С учетом же -го правила, после свертки в , просматривая символов, нельзя определить, делать ли свертку в , следовательно это не LR(0)-грамматика. Получили противоречие.
TODO тут надо либо дать более формальное объяснение, либо объяснить почему k не должно меняться от пополнения грамматики.
LR-разборщик
Принцип переноса-свёртки
При LR(k)-анализе применяется метод перенос-свертка (англ. shift-reduce). Суть метода сводится к следующему:
- Программа анализатора читает последовательно символы входной строки до тех пор, пока не накопится цепочка, совпадающая с правой частью какого-нибудь из правил. Рассмотренные символы переносим в стек (операция перенос).
- Далее все символы совпадающей цепочки извлекаются из стека и на их место помещается нетерминал, находящийся в левой части этого правила (операция свертка).
Структура
Метод перенос-свертка использует следующие компоненты:
- Входная строка
- Стек (для запоминания рассмотренных символов)
- Управляющая таблица (для определения, какое действие применить - перенос или свертку)
- Автомат (для запоминания информации о текущем состоянии стека)
Управляющая программа анализатора
Управляющая программа одинакова для всех LR-анализаторов, а таблица и автомат изменяются от одного анализатора к другому.
Для запоминания строки запись в стек имеет вид: , где — вершина стека. Каждый — символ грамматики(терминал или нетерминал), а — состояние автомата. Каждое состояние суммирует информацию, cодержащуюся в стеке перед ним. — стартовое состояние автомата.
Обращение к таблице происходит следующим образом , где
- — состояние автомата,
- — входной символ;
В таблице информация имеет следующий вид:
struct Cell
enum:
Shift
Reduce
Accept // допуск
Error // ошибка
struct Shift
state: int // переход в стостояние state
struct Reduce
rule: int // свертка по правилу rule
Рузультатом работы управляющей программы будет:
struct Result
enum:
Accept // допуск
Error // ошибка
Алгоритм
- Программа читает символ из входной цепочки.
- Обращается к управляющей таблице.
- Совершает соответствующее действие.
- Возвращается к первому пункту, пока входная цепочка не закончится.
|
Result algorithmLR(w: string)
curToken — указатель на первый символ в строке w
while haveToken()
curState = top()
if [curState, curToken] == Shift s
push(curToken)
push(s)
nextToken()
else if [curState, curToken] == Reduce A
for j = 1 to
pop()
pop()
s = top()
push(A)
push(goto [s, A])
Вывод правила (A )
else if [curState, curToken] == Accept
return Accept
else
return Error
|
Функция получает состояние и символ грамматики и выдает состояние. Функция , строящаяся по грамматике , есть функция переходов детерминированного магазинного автомата, который распознает язык, порождаемый грамматикой .
См. также
Источники информации
- Альфред Ахо, Рави Сети, Джеффри Ульман. Компиляторы. Принципы, технологии, инструменты. Издательство Вильямс, 2003. Стр. 301 - 326.
- Терехов Ан.А., Вояковская Н., Булычев Д., Москаль А. - Разработка компиляторов на платформе .NET - Восходящие анализаторы
- Б.К.Мартыненко. Языки и трансляции. Стр. 198 - 223