Почему мой бизон / флекс не работает как положено? - PullRequest
0 голосов
/ 07 апреля 2019

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

Кроме того, если я изменю порядок строк, строки не будут преобразованы, поэтому будет работать только одна конкретная строка.

Это мой входной файл:

input.txt

B0102 Bobi 2017/01/16 V8 1, massage 12.50
J1841 Jeco 20.2 2017/01/17 V8 2, Tosse 2, tosquia 22.50
B2232 Bobi 2017/01/17 Tosse 1, Leptospirose 1, bath 30.00, massage 12.50
B1841 Jeco 21.4 2017/01/18 Leptospirose 1, Giardiase 2

И вот что я должен получить:

выход

Bobi (B0102) paid 2 services/vaccines 22.50
Jeco (J1841) paid 3 services/vaccines 62.50
Bobi (B2232) paid 4 services/vaccines 62.50
Jeco (B1841) paid 2 services/vaccines 30.00

Если я изменю порядок строк во входном файле, даже первая строка не преобразуется. Однако, если порядок такой, как я показал выше, это мой вывод:

Bobi (B0102) paid 2 services/vaccines 22.50
syntax error

Это мой код:

file.y

%{
    #include "file.h"
    #include <stdio.h>
    int yylex();
    int counter = 0;
    int vaccineCost = 10;
%}

%union{
    char* code;
    char* name;
    float value;
    int quantity;
};

%token COMMA WEIGHT DATE SERVICE VACCINE
%token CODE
%token NAME
%token VALUE
%token QUANTITY

%type <name> NAME
%type <code> CODE
%type <value> VALUE
%type <quantity> QUANTITY
%type <value> services


%start begining

%%

begining: /*empty*/
    | animal
    ;

animal: CODE NAME WEIGHT DATE services {printf("%s (%s) paid %d services/vaccines %.2f\n", $2, $1, counter, $5); counter = 0;}
    | CODE NAME DATE services {printf("%s (%s) paid %d services/vaccines %.2f\n", $2, $1, counter, $4); counter = 0;}
    ;

services: services COMMA SERVICE VALUE {$$ = $1 + $4; counter++;}
    | services COMMA VACCINE QUANTITY{$$ = $1 + $4*vaccineCost;counter++;}
    | SERVICE VALUE{$$ = $2;counter++;}
    | VACCINE VALUE 
{$$ = $2*vaccineCost;counter++;}
    ;

%%

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

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

file.flex

%option noyywrap

%{
    #include "file.h"
    #include "file.tab.h"
    #include <stdio.h>
    #include <string.h>
%}

/*Patterns*/
YEAR 20[0-9]{2}
MONTH 0[1-9]|1[0-2]
DAY 0[1-9]|[1-2][0-9]|3[0-1]

%%
,                                   {return COMMA,;}
[A-Z][0-9]{4}            {yylval.code = strdup(yytext); return CODE;}       
[A-Z][a-z]*          {yylval.name = strdup(yytext); return NAME;}
[0-9]+[.][0-9]                             {return WEIGHT;}
{YEAR}"/"{MONTH}"/"{DAY}                           {return DATE;}
(banho|massagem|tosquia)                    {return SERVICE;}
[0-9]+\.[0-9]{2}              {yylval.value = atof(yytext);return VALUE;}
(V8|V10|Anti-Rabatica|Giardiase|Tosse|Leptospirose)          {return VACCINE;}
[1-9]           {yylval.quantity = atoi(yytext);return QUANTITY;}
\n  
.       
<<EOF>> return 0;

%%

И вот команды, которые я выполняю:

bison -d file.y
flex -o file.c file.flex
gcc file.tab.c file.c -o exec -lfl
./exec < Input.txt

Может кто-нибудь указать мне правильное направление или сказать, что не так с моим кодом?

Спасибо, и если мое объяснение было недостаточно хорошим, я сделаю все возможное, чтобы объяснить его лучше !!

1 Ответ

2 голосов
/ 07 апреля 2019

Есть как минимум две разные проблемы, которые вызывают эти симптомы.

  1. Ваша грамматика верхнего уровня принимает не более одного animal:

    inicio: /*vazio*/
        | animal
    

    Таким образом, ввод, содержащий более одной строки, не будет разрешен. Вам нужен верхний уровень, который принимает любое количество animal с. (Кстати, современные версии зубров позволяют писать %empty как правую часть пустого производства, вместо того, чтобы (не) использовать комментарий.

  2. Порядок правил вашего сканера означает, что большинство слов, которые вы хотите распознать как VACINA, будут распознаваться как NOME. Напомним, что когда два шаблона совпадают с одним и тем же токеном, первый в файле wlll победит. Итак, с этими правилами:

    [A-Z][a-z]*          {yylval.nome = strdup(yytext); return NOME;}
    (V8|V10|Anti-Rabatica|Giardiase|Tosse|Leptospirose)          {return VACINA;}
    

    Токены типа Tosse, которые могут соответствовать любому правилу, будут соответствовать первому правилу. Только V8 и Anti-Rabatical, которые [A-Z][a-z]* не совпадают, перейдут ко второму правилу. Таким образом, ваша первая строка ввода не вызывает эту проблему, но все остальные вызывают.

Вам, вероятно, следует синтаксически обрабатывать символы новой строки, если только вы не разрешите разделять записи лечения на несколько строк. И помните, что многие (f) версии lex не допускают пустых действий, как в ваших последних двух правилах flex. Это может вызвать лексические ошибки.

И, наконец,

<<EOF>> return 0;

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

...