Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么会出现这种情况+;lex basic解析器不处理控件+;D/EOF?_C_Yacc_Lex_C89 - Fatal编程技术网

为什么会出现这种情况+;lex basic解析器不处理控件+;D/EOF?

为什么会出现这种情况+;lex basic解析器不处理控件+;D/EOF?,c,yacc,lex,c89,C,Yacc,Lex,C89,我有一个yacc/lex程序来处理这类行(在本例中,它只处理一种格式,但其思想是它显然会处理更多格式): lex词法分析器(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(co

我有一个yacc/lex程序来处理这类行(在本例中,它只处理一种格式,但其思想是它显然会处理更多格式):

lex词法分析器(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));


}
%{

#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

%%

input:                          /* empty */
                        | input lastbid_lastask

lastbid_lastask:        DATETIME ',' FLOAT_NUMBER ',' FLOAT_NUMBER ',' INTEGER_NUMBER '\n'      { printf("MATCH %lf %lf %ld\n", $3, $5, $7); }
                        ;

%%

extern FILE *yyin;

int main(int argc, char *argv[]) {

        while(!feof(yyin)) {
                yyparse();
        }
        return 0;

}
% cat 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
现在我编译了程序,没有错误,但当我尝试执行它时,我得到以下结果:

% cat test.csv | ./readfile
Segmentation fault (core dumped)
% cat test.csv | ./readfile
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
void read_date_YYYYMMDD_HHMMSSmmm(void)
#20191201 170004413#
Sun Dec  1 17:00:04 2019 CET
void read_float_number(void)
#1.102320#
1.102320
void read_float_number(void)
#1.102470#
1.102470
void read_integer_number(void)
#0#
0
...
现在,如果我替换:

while(!feof(yyin)) 
与:

然后我得到这个:

% cat test.csv | ./readfile
Segmentation fault (core dumped)
% cat test.csv | ./readfile
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
void read_date_YYYYMMDD_HHMMSSmmm(void)
#20191201 170004413#
Sun Dec  1 17:00:04 2019 CET
void read_float_number(void)
#1.102320#
1.102320
void read_float_number(void)
#1.102470#
1.102470
void read_integer_number(void)
#0#
0
...
所以它是可行的,但程序不会以EOF结束。 虽然我知道核心转储可能意味着很多事情,但我可以做些什么来进一步定位问题并获得正常行为?

不要在循环中调用
yyparse()
。它将解析整个输入并返回;当它返回时,您知道整个输入已被解析(或遇到语法错误)。不需要进行任何EOF测试

(有一些单独的情况需要打破这一规则,其中大多数都与扫描仪返回输入结束指示符有关,而不是在输入结束时,或者解析器使用
yyapt/YYABORT
有序地提前终止解析。换句话说,如果您有需要打破这一规则的情况,你已经知道你必须这么做。)

while(!feof(file)){…}
有一个完整的解释为什么它几乎总是一个bug。(摘要:EOF标志是在读取检测到EOF之后设置的,因此在执行读取之前没有设置EOF的事实证明了什么。
while(!feof(file))
idiom很好地保证了在文件末尾您将得到一个意外的EOF——这在“但我刚刚检查了EOF…”的意义上是意外的

不过,我不认为FAQ涵盖了这个特定的问题,这是针对使用(f)lex的程序的。当(f)lex扫描器到达文件末尾时,它会将
yyin
设置为NULL。然后,如果
yywrap
告诉它没有更多的输入,
yylex
返回0,这告诉它的调用者(
yyparse
)到达文件结尾。然后
yyparse
完成解析并返回。如果然后循环,
yyin
为NULL,
feof(NULL)
为未定义的行为。这就是程序出错的原因

当您删除
feof
测试(但仍然循环)时,您重新输入
yyparse
,但这次
yyin
设置为
NULL
。flex扫描仪认为这意味着“使用默认输入”,即
stdin
。如果
yyin
以前是某个输入文件,这意味着
yyparse
的新调用将尝试从终端获取其输入,这可能不是您所期望的。另一方面,如果是
stdin
达到EOF,那么您将处于一个硬循环中,不断地接收g来自
stdin
的新EOF信号不在循环中调用
yyparse()
。它将解析整个输入并返回;当它返回时,您知道整个输入已被解析(或遇到语法错误)。应该不需要任何EOF测试

(有一些单独的情况需要打破这一规则,其中大多数都与扫描仪返回输入结束指示符有关,而不是在输入结束时,或者解析器使用
yyapt/YYABORT
有序地提前终止解析。换句话说,如果您有需要打破这一规则的情况,你已经知道你必须这么做。)

while(!feof(file)){…}
有一个完整的解释为什么它几乎总是一个bug。(摘要:EOF标志是在读取检测到EOF之后设置的,因此在执行读取之前没有设置EOF的事实证明了什么。
while(!feof(file))
idiom很好地保证了在文件末尾您将得到一个意外的EOF——这在“但我刚刚检查了EOF…”的意义上是意外的

不过,我不认为FAQ涵盖了这个特定的问题,这是针对使用(f)lex的程序的。当(f)lex扫描器到达文件末尾时,它会将
yyin
设置为NULL。然后,如果
yywrap
告诉它没有更多的输入,
yylex
返回0,这告诉它的调用者(
yyparse
)到达文件结尾。然后
yyparse
完成解析并返回。如果然后循环,
yyin
为NULL,
feof(NULL)
为未定义的行为。这就是程序出错的原因


当您删除
feof
测试(但仍然循环)时,您重新输入
yyparse
,但这次
yyin
设置为
NULL
。flex扫描仪认为这意味着“使用默认输入”,即
stdin
。如果
yyin
以前是某个输入文件,这意味着
yyparse
的新调用将尝试从终端获取其输入,这可能不是您所期望的。另一方面,如果是
stdin
达到EOF,那么您将处于一个硬循环中,不断地接收g来自
stdin的新EOF信号

为什么要调用
yyparse()
是否在循环中?我的理解是,您只需调用它一次,它就会解析整个输入,并在达到EOF时返回。移除循环可以处理CONTROL+D。这不是一个借口,只是一个信息性的旁注,循环和yyin文件的用法包含在“Lex和Yacc”的第一个示例中O'ReillySee的书为什么打电话给
yyparse()
是否在循环中?我的理解是,您只需调用它一次,它就会解析整个输入,并在达到EOF时返回。移除循环可以处理CONTROL+D。这不是一个借口,只是一个信息性的旁注,循环和yyin文件的用法包含在“Lex和Yacc”的第一个示例中O'ReillySee的书出于某种原因(可能是一种特殊情况),使用
,而(!feof(yyin))
包含在O'Reilly的Lex和Yacc书中。删除它并添加语法规则