Дизайн компилятора - анализатор снизу вверх
Разбор снизу вверх начинается с листовых узлов дерева и работает вверх, пока не достигнет корневого узла. Здесь мы начинаем с предложения, а затем применяем правила производства в обратном порядке, чтобы достичь начального символа. На приведенном ниже изображении показаны доступные парсеры снизу вверх.

Shift-Reduce Parsing
Разбор Shift-Reduce использует два уникальных шага для анализа снизу вверх. Эти шаги известны как шаг сдвига и шаг понижения.
Шаг сдвига: шаг сдвига относится к продвижению входного указателя к следующему входному символу, который называется смещенным символом. Этот символ помещается в стек. Смещенный символ обрабатывается как один узел дерева разбора.
Шаг сокращения : когда анализатор находит полное правило грамматики (RHS) и заменяет его на (LHS), это называется сокращением шага. Это происходит, когда вершина стека содержит дескриптор. Чтобы уменьшить, функция POP выполняется в стеке, который выскакивает из дескриптора и заменяет его нетерминальным символом LHS.
LR Parser
Парсер LR - это нерекурсивный парсер снизу вверх. Он использует широкий класс контекстно-свободной грамматики, что делает его наиболее эффективным методом синтаксического анализа. Парсеры LR также известны как парсеры LR (k), где L обозначает сканирование входного потока слева направо; R обозначает построение крайнего правого вывода в обратном направлении, а k обозначает количество символов с предварительным ожиданием для принятия решений.
Существует три широко используемых алгоритма для создания LR-парсера:
- SLR (1) - простой анализатор LR:
- Работает на наименьшем классе грамматики
- Несколько штатов, следовательно, очень маленькая таблица
- Простая и быстрая конструкция
- LR (1) - LR Parser:
- Работы по комплектации грамматики LR (1)
- Создает большую таблицу и большое количество состояний
- Медленное строительство
- LALR (1) - синтаксический анализатор LR:
- Работает на промежуточном размере грамматики
- Количество состояний такое же, как в SLR (1)
Алгоритм синтаксического анализа LR
Здесь мы опишем скелетный алгоритм парсера LR:
token = next_token() repeat forever s = top of stack if action[s, token] = “shift si” then PUSH token PUSH si token = next_token() else if action[s, token] = “reduce A::= β“ then POP 2 * |β| symbols s = top of stack PUSH A PUSH goto[s,A] else if action[s, token] = “accept” then return else error()
LL vs. LR
LL | LR |
---|---|
Делает самый левый вывод. | Делает самый правый вывод в обратном порядке. |
Начинается с корневого нетерминала в стеке. | Заканчивается корневым нетерминалом в стеке. |
Заканчивается, когда стек пуст. | Начинается с пустого стека. |
Использует стек для обозначения того, что еще ожидается. | Использует стек для обозначения того, что уже увидено. |
Строит дерево разбора сверху вниз. | Строит дерево разбора снизу вверх. |
Непрерывно выталкивает нетерминал из стека и выталкивает соответствующую правую часть. | Пытается распознать правую часть стека, вытолкнуть его и вытолкнуть соответствующий нетерминал. |
Расширяет нетерминалы. | Уменьшает нетерминалы. |
Читает терминалы, когда он выталкивает один из стека. | Читает терминалы, пока он толкает их в стек. |
Предварительный порядок обхода дерева разбора. | Последовательный обход дерева разбора. |