В настоящее время я работаю над проектом, который состоит в анализе содержимого текстового файла, представляющего билет на самолет, с использованием 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
@РашидК. Я просто добавил это в конец сообщения
Это может помочь добавить %define parse.error verbose
в ваш файл bison. Это даст вам лучшее сообщение об ошибке.
В строке 18 у вас тот же pb, что и в моем ответе: шаблон строки 15 (NOM_PRENOM) перекрывает шаблон строки 18 (CODE_AEROPORT). Итак, в этом случае вы должны изменить грамматику, добавив правило для описания строки с помощью NOM и PRENOM: ИСПОЛЬЗУЙТЕ простой шаблон STRING и создайте правило, описывающее nom_prenom, которое является либо STRING, либо STRING "/" STRING...
В качестве первой попытки перед изменением грамматики временно измените строку 15 следующим образом: {ALPHA}{4}+(.... чтобы предположить, что имя состоит как минимум из 4 альф, чтобы сделать правило в строке 18 более конкретным ( только 3 альфа)
@РашидК. Спасибо ! Я отредактировал, как вы просили, обновил сообщение и объяснил, что я сделал, а также другие появившиеся ошибки (я не думаю, что они мешают, но у меня все еще есть синтаксическая ошибка)
Вы смешиваете два предложения. Токен STRING будет введен, если вы измените грамматику. На первом этапе просто оставьте свою грамматику такой, какая она есть, но изменив только правило в строке 15.
@РашидК. Простите меня, я все сделал, я обновил пост, поэтому у меня нигде нет предупреждения, но все равно синтаксическая ошибка при выполнении
@Elblocktri: я обновил свой ответ черновиком решения. Ваш pb исходит от лексического анализатора, который не различает все шаблоны (вы пытаетесь сделать в нем слишком много анализа, пусть грамматика сделает свою работу). Предлагаемый ответ необходимо уточнить...
Оно работает! Еще раз большое спасибо, я понял в чем проблема
Кстати, Bison поддерживает классы символов Posix. Например, ваш {DIGIT}
— это эквивалент [[:digit:]]
, {ALPHA}
— это [[:alpha:]]
, а {SEP}
— это [[:blank:]]
. Вы можете найти больше здесь: regular-expressions.info/posixbrackets.html
Следующие предупреждения от 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, я до сих пор не понимаю, откуда она... И у меня все еще есть синтаксическая ошибка во время выполнения
Если по каким-то причинам вы не можете различить два токена с помощью шаблона, используйте один и тот же токен для обоих. Это синтаксический анализатор, который сможет определить, ожидается ли токен во входном потоке или нет. Например, используйте HEURE_OR_DUREE_VOL для одного и того же шаблона вместо двух отдельных HEURE и DUREE_VOL, поскольку они имеют один и тот же шаблон. И затем это будет использоваться в грамматике.
Я изменил, как вы предложили, у меня все еще есть то же предупреждение в строке 18 и синтаксическая ошибка при выполнении...
Вы должны обновить свой пост с некоторой темой «обновления», чтобы показать, что вы делаете...
Я изменил файлы в основном посте!
Ваш пост должен включать ошибки, которые вы получаете при компиляции вашей программы и/или при ее запуске.