I want to parse lines as this one:
20191201 170003296,1.102290,1.102470,0
To do so, I have written the following basic yacc/lex grammar/lexer:
grammar.y:
%{
#include <time.h>
#include <stdio.h>
%}
%union {
struct tm datetime; /* DATE TIME VALUES */
double float_number; /* 8 BYTES DOUBLE VALUE */
long integer_number; /* 8 BYTES INTEGER VALUE */
}
%token <datetime> DATETIME
%token <float_number> FLOAT_NUMBER
%token <integer_number> INTEGER_NUMBER
%%
lastbid_lastask: DATETIME ',' FLOAT_NUMBER ',' FLOAT_NUMBER ',' INTEGER_NUMBER '\n' { printf("MATCH %lf %lf %ld\n", $3, $5, $7); }
;
%%
int main(int argc, char *argv[]) {
yyparse();
return 0;
}
lexer.l:
%{
#include <time.h>
#include "grammar.h"
void read_float_number(void);
void read_integer_number(void);
void read_date_YYYYMMDD_HHMMSSmmm(void);
void yyerror(const char* msg);
%}
%%
/* YYYYMMDD HHMMSSmmm DATE */
[12][09][0-9][0-9][0-1][0-9][0-3][0-9][ ][0-2][0-9][0-5][0-9][0-5][0-9][0-9][0-9][0-9] { read_date_YYYYMMDD_HHMMSSmmm(); return DATETIME; }
/* FLOAT NUMBER */
[0-9]+\.[0-9]+ { read_float_number(); return FLOAT_NUMBER; }
/* INTEGER NUMBER */
[0-9]+ { read_integer_number(); return INTEGER_NUMBER; }
/* PASS ',' CHARACTER */
, { return ','; }
/* PASS '\n' CHARACTER */
\n { return '\n'; }
/* PASS UNEXPECTED CHARACTER */
. { return yytext[0]; }
%%
/* READ FLOAT NUMBER */
void read_float_number(void) {
printf("void read_float_number(void)\n");
printf("#%s#\n", yytext);
sscanf(yytext, "%lf", &yylval.float_number);
printf("%lf\n", yylval.float_number);
}
/* READ INTEGER NUMBER */
void read_integer_number(void) {
printf("void read_integer_number(void)\n");
printf("#%s#\n", yytext);
sscanf(yytext, "%ld", &yylval.integer_number);
printf("%ld\n", yylval.integer_number);
}
/* READ YYYYMMDD HHMMSSmmm DATE */
void read_date_YYYYMMDD_HHMMSSmmm(void) {
printf("void read_date_YYYYMMDD_HHMMSSmmm(void)\n");
printf("#%s#\n", yytext);
/* DATETIME STRUCT TM */
struct tm dt;
/* READ VALUES */
sscanf(yytext, "%4d%2d%2d %2d%2d%2d", &dt.tm_year, &dt.tm_mon, &dt.tm_mday, &dt.tm_hour, &dt.tm_min, &dt.tm_sec);
/* NORMALIZE VALUES */
dt.tm_year = dt.tm_year - 1900; /* NORMALIZE YEAR */
dt.tm_mon = dt.tm_mon - 1; /* NORMALIZE MONTH */
dt.tm_isdst = -1; /* NO INFORMATION ABOUT DST */
mktime(&dt); /* NORMALIZE STRUCT TM */
/* PRINT DATE TIME */
char buffer[80];
strftime(buffer, 80, "%c %Z", &dt);
printf("%s\n", buffer);
/* COPY STRUCT TM TO YACC RETURN VALUE */
memcpy(&yylval.datetime, &dt, sizeof(dt));
}
/* YYERROR */
void yyerror(const char* msg) {
fprintf(stderr, "yyerror %s\n", msg);
exit(1);
}
makefile:
CCFLAGS = -std=c89 -c
YFLAGS = -d # Forces generation of y.tab.h
OBJS = lexer.o grammar.o
TARGET = readfile
readfile: $(OBJS)
cc $(OBJS) -std=c89 -ll -o $(TARGET)
grammar.h grammar.o: grammar.y
yacc $(YFLAGS) -ogrammar.c grammar.y
cc $(CCFLAGS) grammar.c
lexer.o: lexer.l grammar.h
lex -olexer.c lexer.l
cc $(CCFLAGS) lexer.c
clean:
rm -f $(OBJS) grammar.[ch] lexer.c
When I test the program I get the following behaviour, first line is correctly parsed but second line causes an yyerror:
% ./readfile
20191201 170003296,1.102290,1.102470,0
void read_date_YYYYMMDD_HHMMSSmmm(void)
#20191201 170003296#
Sun Dec 1 17:00:03 2019 CET
void read_float_number(void)
#1.102290#
1.102290
void read_float_number(void)
#1.102470#
1.102470
void read_integer_number(void)
#0#
0
MATCH 1.102290 1.102470 0
20191201 170004413,1.102320,1.102470,0
void read_date_YYYYMMDD_HHMMSSmmm(void)
#20191201 170004413#
Sun Dec 1 17:00:04 2019 CET
yyerror syntax error
Why does second line fail?
lastbid_lastask
in it... – Antti HaapalaYYACCEPT
(orYYABORT
if you want the parse to fail with a non-zero return code.) – rici