Вам не нужны наборы FIRST и FOLLOW.Вы должны вычислить их, чтобы получить таблицу разбора.Это таблица {<non-terminal, token> -> <action, rule>}
, если LL (k) (что означает просмотр non-terminal
в стеке и token
на входе, который action
взять и, если применимо, который rule
применить), илитаблица {<state, token> -> <action, state>}
if (C | LA |) LR (k) (что означает данные state
в стеке и token
на входе, которые action
взять и перейти к которым state
.
После того, как вы получите эту таблицу, вам больше не нужны FIRST и FOLLOWS.
Если вы пишете семантический анализатор, вы должны предположить, что анализатор работает правильно. Обработка ошибок на уровне фраз(что означает обработку ошибок синтаксического анализа), полностью ортогональна семантическому анализу.
Это означает, что в случае ошибки синтаксического анализа обработчик ошибок на уровне фразы (PLEH) попытается исправить ошибку., анализ останавливается. Если это возможно, семантический анализатор не должен знать, была ли ошибка, которая была исправлена, или не было никакой ошибки вообще!
Вы можете взглянуть на myбиблиотека компиляторов для примеров.
Об обработке ошибок на уровне фразы, вам снова не нужно ПЕРВЫЙ и СЛЕДУЙТЕ.Давайте поговорим о LL (k) сейчас (просто потому, что о LR (k) я пока особо не задумывался).После того, как вы построите грамматическую таблицу, у вас будет много записей, как я сказал так:
<non-terminal, token> -> <action, rule>
Теперь, когда вы анализируете, вы берете все, что находится в стеке, если это был терминал, то вы должнысопоставьте это с входом.Если он не совпадает, обработчик ошибок на уровне фразы включается:
Роль первая: обрабатывать недостающие терминалы - просто сгенерируйте поддельный терминал того типа, который вам нужен в вашем лексере, и получитепопытка синтаксического анализаВы можете делать и другие вещи (например, проверить заранее во вводе, если у вас есть нужный токен, отбросьте один токен из лексера)
Если то, что вы получите, не является терминалом (T
)вместо этого вы должны взглянуть на свой лексер, взять lookahead
и посмотреть на свой стол.Если запись <T, lookahead>
существовала, значит, вы готовы.Следуйте за действием и нажмите / сложите из стека.Если, однако, такой записи не было, опять-таки запускается обработчик ошибок на уровне фразы:
Роль вторая: обрабатывать неожиданные терминалы - вы можете сделать много вещей, чтобы пройти это.То, что вы делаете, зависит от того, что такое T
и lookahead
, и от вашего экспертного знания грамматики.
Примеры того, что вы можете сделать:
- Fail!Вы ничего не можете сделать
- Игнорировать этот терминал.Это означает, что вы помещаете
lookahead
в стек (после повторного нажатия T
) и продолжаете анализатор.Сначала парсер совпадет с lookahead
, выбросит его и продолжит.Пример: если у вас есть такое выражение: *1+2/0.5
, вы можете сбросить неожиданное *
таким образом. - Измените
lookahead
на что-то приемлемое, нажмите T
назад и повторите попытку.Например, выражение вроде этого: 5id = 10;
может быть недопустимым, потому что вы не принимаете идентификаторы, которые начинаются с цифр.Вы можете заменить его на _5id
, например, чтобы продолжить