为什么我的 bison/flex 没有按预期工作?
Why is my bison/flex not working as intended?
我有这个家庭作业,我必须将一些输入转换为特定的输出。我遇到的问题是我只能将第一行转换成我需要的输出,其他行 return 一个 "syntax error" 错误。
此外,如果我更改行顺序,则不会转换任何行,因此只有一个特定行有效。
这是我的输入文件:
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", , , counter, ); counter = 0;}
| CODE NAME DATE services {printf("%s (%s) paid %d services/vaccines %.2f\n", , , counter, ); counter = 0;}
;
services: services COMMA SERVICE VALUE {$$ = + ; counter++;}
| services COMMA VACCINE QUANTITY{$$ = + *vaccineCost;counter++;}
| SERVICE VALUE{$$ = ;counter++;}
| VACCINE VALUE
{$$ = *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
任何人都可以指出我正确的方向或告诉我我的代码有什么问题吗?
谢谢,如果我的解释不够好,我会尽力解释得更好!!
至少有两个不同的问题导致了这些症状。
你的顶级语法最多只接受一个 animal
:
inicio: /*vazio*/
| animal
因此不允许包含多行的输入。您需要一个接受任意数量的 animal
的顶级。 (顺便说一下,现代 bison 版本允许您将 %empty
写为空产生式的右侧,而不必(误)使用注释。
您的扫描器规则的顺序意味着您想要识别为 VACINA
的大多数单词将被识别为 NOME
。回想一下,当两个模式匹配同一个标记时,文件中的第一个将获胜。所以根据这些规则:
[A-Z][a-z]* {yylval.nome = strdup(yytext); return NOME;}
(V8|V10|Anti-Rabatica|Giardiase|Tosse|Leptospirose) {return VACINA;}
像 Tosse
这样可以匹配任一规则的标记将被假定为匹配第一条规则。只有 [A-Z][a-z]*
不匹配的 V8 和 Anti-Rabatical 会落入第二条规则。所以你的第一个输入行不会触发这个问题,但所有其他的都会。
您可能应该在句法上处理换行符,除非您允许将处理记录拆分为多行。请注意,许多 (f)lex 版本不允许空操作,就像您的最后两个 flex 规则一样。这可能会导致词法错误。
最后
<<EOF>> return 0;
不需要。这就是扫描器默认处理 end-of-fike 的方式。 <<EOF>>
规则通常是扭曲的或多余的,只有在明确需要时才应使用(并且非常小心)。
我有这个家庭作业,我必须将一些输入转换为特定的输出。我遇到的问题是我只能将第一行转换成我需要的输出,其他行 return 一个 "syntax error" 错误。
此外,如果我更改行顺序,则不会转换任何行,因此只有一个特定行有效。
这是我的输入文件:
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", , , counter, ); counter = 0;}
| CODE NAME DATE services {printf("%s (%s) paid %d services/vaccines %.2f\n", , , counter, ); counter = 0;}
;
services: services COMMA SERVICE VALUE {$$ = + ; counter++;}
| services COMMA VACCINE QUANTITY{$$ = + *vaccineCost;counter++;}
| SERVICE VALUE{$$ = ;counter++;}
| VACCINE VALUE
{$$ = *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
任何人都可以指出我正确的方向或告诉我我的代码有什么问题吗?
谢谢,如果我的解释不够好,我会尽力解释得更好!!
至少有两个不同的问题导致了这些症状。
你的顶级语法最多只接受一个
animal
:inicio: /*vazio*/ | animal
因此不允许包含多行的输入。您需要一个接受任意数量的
animal
的顶级。 (顺便说一下,现代 bison 版本允许您将%empty
写为空产生式的右侧,而不必(误)使用注释。您的扫描器规则的顺序意味着您想要识别为
VACINA
的大多数单词将被识别为NOME
。回想一下,当两个模式匹配同一个标记时,文件中的第一个将获胜。所以根据这些规则:[A-Z][a-z]* {yylval.nome = strdup(yytext); return NOME;} (V8|V10|Anti-Rabatica|Giardiase|Tosse|Leptospirose) {return VACINA;}
像
Tosse
这样可以匹配任一规则的标记将被假定为匹配第一条规则。只有[A-Z][a-z]*
不匹配的 V8 和 Anti-Rabatical 会落入第二条规则。所以你的第一个输入行不会触发这个问题,但所有其他的都会。
您可能应该在句法上处理换行符,除非您允许将处理记录拆分为多行。请注意,许多 (f)lex 版本不允许空操作,就像您的最后两个 flex 规则一样。这可能会导致词法错误。
最后
<<EOF>> return 0;
不需要。这就是扫描器默认处理 end-of-fike 的方式。 <<EOF>>
规则通常是扭曲的或多余的,只有在明确需要时才应使用(并且非常小心)。