Синтаксическая проблема с Bison и Flex во время компиляции и выполнения

В настоящее время я работаю над проектом, который состоит в анализе содержимого текстового файла, представляющего билет на самолет, с использованием bison и flex. Я создал два файла, ticket.y и ticket.l, для определения правил грамматики и соответствующих регулярных выражений.

Пример файла, который я хочу проанализировать, выглядит следующим образом (ExampleAirplaneTicket.txt):

DOSSIER YBNUKR 
ANTOINE/DESAINT-EXUPERY
22/01/16 OS412  CDG 10:00  VIE 12:00    2:00
22/01/16 OS051  VIE 13:20  NRT +07:25   11:05 
23/01/16 OS8577 NRT 10:00  CHI 09:00    01:45

Вот содержимое моего billet.l (ticket.l) файла:

%{
#include "billet.tab.h"
void yyerror(const char *s);
%}

DIGIT [0-9]
ALPHA [A-Za-z]
SEP [ \t]

%%

"DOSSIER"               { return DOSSIER; }
{ALPHA}{6}              { return CODE_DOSSIER; }
{ALPHA}{3}"/"           { yylval.sval = strdup(yytext); return CODE_AEROPORT; }
{ALPHA}{4}+("/"{ALPHA}+)?("-"{ALPHA}+)?  { yylval.sval = strdup(yytext); return NOM_PRENOM; }
{DIGIT}{2}"/"{DIGIT}{2}"/"{DIGIT}{2} { return DATE; }
{ALPHA}{2}{DIGIT}{2,4}  { return NUM_VOL; }
{ALPHA}{3}              { return CODE_AEROPORT; }
{DIGIT}{2}":"{DIGIT}{2} { yylval.sval = strdup(yytext); return HEURE_OR_DUREE_VOL; }
"+"                     { return PLUS; }
{SEP}+                  { }
\n                      { return NEWLINE; }
.                       { fprintf(stderr, "Caractère non autorisé: '%s'\n", yytext); exit(1); }

%%

А вот содержимое моего billet.y (ticket.y) файла:

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void yyerror(const char *s);
int yylex();
%}

%union {
  char *sval;
}

%token DOSSIER CODE_DOSSIER NEWLINE PLUS
%token <sval> DATE NUM_VOL CODE_AEROPORT HEURE_OR_DUREE_VOL
%token <sval> NOM_PRENOM

%type <sval> nom_prenom
%type <sval> heure_arrivee
%type <sval> heure_avec_plus

%%

billet: DOSSIER CODE_DOSSIER NEWLINE infos_passager NEWLINE vols;

infos_passager: nom_prenom '/' nom_prenom NEWLINE { printf("Infos passager : %s / %s\n", $1, $3); };

vols: vol NEWLINE vols | vol NEWLINE;

vol: DATE NUM_VOL CODE_AEROPORT HEURE_OR_DUREE_VOL CODE_AEROPORT heure_arrivee HEURE_OR_DUREE_VOL { printf("Vol : %s %s %s %s %s %s %s\n", $1, $2, $3, $4, $5, $6, $7); };

heure_arrivee: heure_avec_plus | HEURE_OR_DUREE_VOL;

heure_avec_plus: PLUS HEURE_OR_DUREE_VOL { $$ = $2; };

nom_prenom: NOM_PRENOM;

%%

int main() {
    yyparse();
    return 0;
}

void yyerror(const char *s) {
    fprintf(stderr, "Erreur de syntaxe : %s\n", s);
}

Когда я все компилирую, я не могу проверить свою программу на файле ExampleAirplaneTicket.txt. У меня просто синтаксическая ошибка, и, несмотря на несколько попыток, я не смог решить эти проблемы или даже выяснить, откуда она берется.

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

Я попытался реализовать синтаксический анализатор, используя flex и bison для анализа определенного текстового формата, представляющего информацию об авиабилетах. Я написал файлы .l и .y и внес необходимые коррективы, исходя из предыдущих проблем. Теперь я ожидаю, что программа успешно скомпилируется и проанализирует файл ExampleAirlineTicket.txt без каких-либо синтаксических ошибок или других проблем. За исключением того, что когда я тестирую файл, я просто получаю синтаксическую ошибку, но не знаю, откуда она взялась.

Когда я компилирую billet.l, я получаю это предупреждение (я не думаю, что это проблема):

billet.l:17: warning, the rule can't match
billet.l:20: warning, the rule can't match

Никаких предупреждений ни при компиляции billet.y, ни при компиляции всего с gcc.

Но когда я тестирую текстовый файл, я получаю следующее:

Syntax error

ОБНОВЛЯТЬ :

Я объединил токены HURE и DUREE_VOL в один токен: TIME_OR_FLIGHT_TIME. Мои файлы выше были обновлены.

У меня больше нет предупреждений в строках 17 и 20, но появляется предупреждение в строке 18 при компиляции billet.l.

И все та же синтаксическая ошибка при выполнении текстового файла

Файл заготовки.l :

I modified line 15 to change the pattern from {ALPHA}+("/"{ALPHA}+)?("-"{ALPHA}+)? to {ALPHA}{4}+("/"{ALPHA}+)?("-"{ALPHA}+)? in order to assume the name has at least 4 letters.
I also changed the token returned on line 15 from NOM_PRENOM to STRING.

файл заготовки.у:

I added a new token <sval> STRING to the list of tokens.
I modified the nom_prenom rule to accept either STRING or STRING / STRING.

У меня есть новые ошибки для компиляции из billet.y (и больше нет billet.l):

ticket.y: warning: 1 conflict per offset/reduction [-Wconflicts-sr]
ticket.y: note: run with "-Wcounterexamples" option to generate counterexamples of conflicts

И все еще синтаксическая ошибка, когда я запускаю свой текстовый файл ExampleAirplaneTicket.txt

Ваш пост должен включать ошибки, которые вы получаете при компиляции вашей программы и/или при ее запуске.

Rachid K. 10.04.2023 17:22

@РашидК. Я просто добавил это в конец сообщения

Elblocktri 10.04.2023 17:27

Это может помочь добавить %define parse.error verbose в ваш файл bison. Это даст вам лучшее сообщение об ошибке.

Piotr Siupa 10.04.2023 18:16

В строке 18 у вас тот же pb, что и в моем ответе: шаблон строки 15 (NOM_PRENOM) перекрывает шаблон строки 18 (CODE_AEROPORT). Итак, в этом случае вы должны изменить грамматику, добавив правило для описания строки с помощью NOM и PRENOM: ИСПОЛЬЗУЙТЕ простой шаблон STRING и создайте правило, описывающее nom_prenom, которое является либо STRING, либо STRING "/" STRING...

Rachid K. 10.04.2023 19:25

В качестве первой попытки перед изменением грамматики временно измените строку 15 следующим образом: {ALPHA}{4}+(.... чтобы предположить, что имя состоит как минимум из 4 альф, чтобы сделать правило в строке 18 более конкретным ( только 3 альфа)

Rachid K. 10.04.2023 19:31

@РашидК. Спасибо ! Я отредактировал, как вы просили, обновил сообщение и объяснил, что я сделал, а также другие появившиеся ошибки (я не думаю, что они мешают, но у меня все еще есть синтаксическая ошибка)

Elblocktri 10.04.2023 19:48

Вы смешиваете два предложения. Токен STRING будет введен, если вы измените грамматику. На первом этапе просто оставьте свою грамматику такой, какая она есть, но изменив только правило в строке 15.

Rachid K. 10.04.2023 19:52

@РашидК. Простите меня, я все сделал, я обновил пост, поэтому у меня нигде нет предупреждения, но все равно синтаксическая ошибка при выполнении

Elblocktri 10.04.2023 20:07

@Elblocktri: я обновил свой ответ черновиком решения. Ваш pb исходит от лексического анализатора, который не различает все шаблоны (вы пытаетесь сделать в нем слишком много анализа, пусть грамматика сделает свою работу). Предлагаемый ответ необходимо уточнить...

Rachid K. 10.04.2023 21:40

Оно работает! Еще раз большое спасибо, я понял в чем проблема

Elblocktri 10.04.2023 21:48

Кстати, Bison поддерживает классы символов Posix. Например, ваш {DIGIT} — это эквивалент [[:digit:]], {ALPHA} — это [[:alpha:]], а {SEP} — это [[:blank:]]. Вы можете найти больше здесь: regular-expressions.info/posixbrackets.html

Piotr Siupa 11.04.2023 00:01
CSS: FlexBox
CSS: FlexBox
Ранее разработчики использовали макеты с помощью Position и Float. После появления flexbox сценарий полностью изменился.
Введение в отзывчивый дизайн с использованием CSS
Введение в отзывчивый дизайн с использованием CSS
Поскольку число людей, пользующихся интернетом с помощью мобильных устройств, продолжает расти, важно, чтобы веб-сайты адаптировались к различным...
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик Модуль flexbox, также известный как гибкий модуль разметки box, помогает эффективно проектировать и...
1
11
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Следующие предупреждения от flex:

billet.l:17: warning, the rule can't match
billet.l:20: warning, the rule can't match

исходят из того, что правило:

  • NOM_PRENOM охватывает то, что ожидается по правилу CODE_AEROPORT
  • HEURE токен - это тот же шаблон, что и правило DUREE_VOL

Итак, некоторые токены (CODE_AEROPORT и DUREE_VOL) никогда не появятся. Это может быть причиной того, что вы получаете сообщение «Синтаксическая ошибка» по умолчанию.

Примечание. Исходный файл C, сгенерированный bison, показывает, что «Синтаксическая ошибка» сообщается, когда количество зарегистрированных токенов (внутренняя переменная yycount) равно 0:

/*
[...]
     - The only way there can be no lookahead present (in yychar) is if
       this state is a consistent state with a default action.  Thus,
       detecting the absence of a lookahead is sufficient to determine
       that there is no unexpected or expected token to report.  In that
       case, just report a simple "syntax error".
[...]
*/
[...]
  switch (yycount)
    {
# define YYCASE_(N, S)                      \
      case N:                               \
        yyformat = S;                       \
      break
      YYCASE_(0, YY_("syntax error"));
      YYCASE_(1, YY_("syntax error, unexpected %s"));
      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
# undef YYCASE_
    }

Обновлять

Обновление из последних модификаций поста. В вашем лексическом анализаторе есть неясности. Работа по различению входных данных должна выполняться в грамматике. Вот предложение, в котором количество токенов в лексическом анализаторе уменьшено, а правила в грамматике более детализированы.

Вот упрощенный лексический анализатор (billet.l):

%{
#include "billet.tab.h"
void yyerror(const char *s);
%}

DIGIT [0-9]
ALPHA [A-Za-z]
ALPHA2 [-A-Za-z]
SEP [ \t]

%%

"DOSSIER"               { return DOSSIER; }
{ALPHA2}+               { yylval.sval = strdup(yytext); return STRING; }
{DIGIT}+                { yylval.sval = strdup(yytext); return NUM; }
{ALPHA}{2}{DIGIT}{2,4}  { yylval.sval = strdup(yytext); return NUM_VOL; }
"+"                     { return PLUS; }
{SEP}+                  { }
\n                      { return NEWLINE; }
"/"                     { return SLASH; }
":"                     { return COLON; }
.                       { fprintf(stderr, "Caractère non autorisé: '%s'\n", yytext); exit(1); }

%%

И чуть более проработанный синтаксический анализатор (billet.y):

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void yyerror(const char *s);
int yylex();
%}

%union {
  char *sval;
}

%token DOSSIER CODE_DOSSIER NEWLINE PLUS SLASH COLON
%token <sval> DATE NUM_VOL STRING NUM
%token <sval> NOM_PRENOM

%type <sval> duree_vol
%type <sval> heure
%type <sval> airport
%type <sval> nom_prenom
%type <sval> date
%type <sval> heure_arrivee
%type <sval> heure_avec_plus
%define parse.error verbose
%%

liste : billet liste | billet

billet: DOSSIER STRING NEWLINE infos_passager NEWLINE vols;

infos_passager: nom_prenom { printf("Infos passager : %s\n", $1); free($1); };

vols: vol NEWLINE vols | vol NEWLINE;

vol: date NUM_VOL airport heure airport heure_arrivee duree_vol { printf("Vol : %s %s %s %s %s %s %s\n", $1, $2, $3, $4, $5, $6, $7); free($1); free($2); free($3); free($4); free($5); free($6); free($7); };

duree_vol : heure 

heure : NUM COLON NUM { char str[20]; snprintf(str, sizeof(str), "%s:%s", $1, $3); $$ = strdup(str); free($1); free($3); }

airport : STRING

date: NUM SLASH NUM SLASH NUM { char str[20]; snprintf(str, sizeof(str), "%s/%s/%s", $1, $3, $5); $$ = strdup(str); free($1); free($3); free($5); }

heure_arrivee: heure_avec_plus | heure;

heure_avec_plus: PLUS heure { $$ = $2; };

nom_prenom: STRING | STRING SLASH STRING { char str[120]; snprintf(str, sizeof(str), "%s/%s", $1, $3); $$ = strdup(str); free($1); free($3); };

%%

int main() {
    yyparse();
    return 0;
}

void yyerror(const char *s) {
    fprintf(stderr, "Erreur de syntaxe : %s\n", s);
}

Построил это:

$ flex billet.l
$ bison -d billet.y
$ gcc billet.tab.c lex.yy.c -lfl

И запустите его с чем-то вроде:

$ ./a.out < input.txt
Infos passager : ANTOINE/DESAINT-EXUPERY
Vol : 22/01/16 OS412 CDG 10:00 VIE 12:00 2:00
Vol : 22/01/16 OS051 VIE 13:20 NRT 07:25 11:05
Vol : 23/01/16 OS8577 NRT 10:00 CHI 09:00 01:45

Я изменил, что мог, у меня новая строка предупреждения 18, я до сих пор не понимаю, откуда она... И у меня все еще есть синтаксическая ошибка во время выполнения

Elblocktri 10.04.2023 18:45

Если по каким-то причинам вы не можете различить два токена с помощью шаблона, используйте один и тот же токен для обоих. Это синтаксический анализатор, который сможет определить, ожидается ли токен во входном потоке или нет. Например, используйте HEURE_OR_DUREE_VOL для одного и того же шаблона вместо двух отдельных HEURE и DUREE_VOL, поскольку они имеют один и тот же шаблон. И затем это будет использоваться в грамматике.

Rachid K. 10.04.2023 18:51

Я изменил, как вы предложили, у меня все еще есть то же предупреждение в строке 18 и синтаксическая ошибка при выполнении...

Elblocktri 10.04.2023 18:58

Вы должны обновить свой пост с некоторой темой «обновления», чтобы показать, что вы делаете...

Rachid K. 10.04.2023 19:06

Я изменил файлы в основном посте!

Elblocktri 10.04.2023 19:13

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