Как исправить ошибку в Bison в этой грамматике LALR?

Я пытаюсь узнать, как правильно исправить ошибку в Bison. Дело в том, что когда ввод верен, все работает до тех пор, пока ввод не будет неправильным. В этом случае он определяет все последующие входные данные как неправильные, даже если они верны. Кто-нибудь знает, как это решить?

%{
    int yyerror(char *s);
    int yylex(void);
   //#define YYDEBUG 1
   #include <stdio.h>
   int linenum = 0;
%}


%token a_TOK b_TOK c_TOK d_TOK e_TOK f_TOK g_TOK h_TOK newline_TOK any_TOK

%%
X: S
    | error newline_TOK { yyerrok; yyclearin; };
S: A B LF X;
A: a_TOK h_TOK | a_TOK b_TOK A c_TOK | a_TOK B c_TOK;
B: C D E;
LF: newline_TOK {
        linenum += 1;
        printf("Correct derivation - line %d!\n", linenum);
    };
C: d_TOK | e_TOK;
D: f_TOK D | f_TOK;
E: B | g_TOK;
%%

int yyerror(char *s)
{
    linenum += 1; 
    printf("Syntax error - line %d\n", linenum);
    return 0;
}

int main(void)
{
#if YYDEBUG
  yydebug = 1;
#endif
    if (!yyparse())
        printf("End of input reached\n");
    return 0;
}

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть три проблемы с вашей текущей грамматикой и восстановлением ошибок:

  • правило X верхнего уровня с выдачей ошибок не является рекурсивным, поэтому после восстановления ошибки единственным допустимым продолжением является конец ввода. Все, кроме EOF, приведет к другой ошибке (которая будет отброшена до следующей новой строки для восстановления, а затем повторится процесс).

  • ваше рекурсивное правило S (косвенно) праворекурсивно, поэтому весь ввод должен быть распознан и помещен в стек, прежде чем S можно будет уменьшить, занимая строки справа налево. Итак, еще раз, восстановление ошибок может произойти только в конце ввода.

  • ваше рекурсивное правило S не имеет базового варианта, поэтому оно никогда не может завершиться без ошибки - ввод без каких-либо ошибок получит синтаксическую ошибку при достижении EOF.

Исправление состоит в том, чтобы сделать ваше правило верхнего уровня леворекурсивным (с базовым регистром) и (пока вы это делаете, хотя это совершенно не обязательно, просто проще) избавиться от правила X. Так что у тебя есть

S : /* epsilon */
  | S A B LF
  | S error newline_TOK { yyerrok; yyclearin; }
  ;

Теперь после устранения ошибки он может анализировать больше A B LF строк.

Вы можете подумать, что S в выдаче ошибки является странным, и на самом деле это не обязательно (можно удалить) без каких-либо изменений в поведении, если только вы не хотите добавить действие к правилу S A B LF, которое потребляет $1 (возможно, чтобы связать все строки анализируются вместе в своего рода список или векторную структуру данных). В этом случае S в выдаче ошибки необходим для передачи ранее проанализированных строк через восстановление ошибок в строки, проанализированные впоследствии.

Другие вопросы по теме