LR(k)-грамматики — различия между версиями
Margarita (обсуждение | вклад)  (→Алгоритм)  | 
				Margarita (обсуждение | вклад)   (→Алгоритм)  | 
				||
| Строка 94: | Строка 94: | ||
       '''while''' haveToken()  |        '''while''' haveToken()  | ||
           curState = top()  |            curState = top()  | ||
| − |            '''if''' <tex>T</tex>[curState, curToken] == Shift s    | + |            '''if''' <tex>\mathtt{T}</tex>[curState, curToken] == Shift s    | 
               push(curToken)  |                push(curToken)  | ||
               push(s)  |                push(s)  | ||
               nextToken()  |                nextToken()  | ||
| − |            '''else if''' <tex>T</tex>[curState, curToken] == Reduce A <tex> \to \beta</tex>    | + |            '''else if''' <tex>\mathtt{T}</tex>[curState, curToken] == Reduce A <tex> \to \beta</tex>    | 
               '''for''' j = 1 '''to''' <tex>|\beta |</tex>     |                '''for''' j = 1 '''to''' <tex>|\beta |</tex>     | ||
                   pop()  |                    pop()  | ||
| Строка 106: | Строка 106: | ||
               push(goto [s, A])    |                push(goto [s, A])    | ||
               Вывод правила (A <tex> \to \beta</tex>)  |                Вывод правила (A <tex> \to \beta</tex>)  | ||
| − |            '''else''' '''if''' <tex>T</tex>[curState, curToken] == Accept    | + |            '''else''' '''if''' <tex>\mathtt{T}</tex>[curState, curToken] == Accept    | 
               '''return''' Accept  |                '''return''' Accept  | ||
           '''else'''    |            '''else'''    | ||
Версия 15:27, 29 августа 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