flex读取EOF两次

时间:2013-09-12 01:56:50

标签: parsing syntax-error bison flex-lexer eof

在下面这个非常简单的例子中,我想用一个a的语言阅读,并确保没有剩下的字符。

文件: example.y

%{
#include <stdio.h>
#include <ctype.h>
int yylex(void);
int yyerror(char *s);
%}

%token A
%token END
%token JUNK

%% /* Grammar Rules */
accept: A END { printf("language accepted!\n"); }
;
%%

文件: example.in

%{
#include "ex.tab.h"
#define YY_NO_INPUT
%}
%option nounput
%%
a printf("A found\n"); return A;
<<EOF>> { printf("EOF found\n"); return END; }
. { printf("JUNK found\n"); return JUNK; }
%%

使用以下测试输入文件编译和运行此程序的结果:

a

产生以下输出:

A found

EOF found
language accepted!
EOF found
Error: syntax error

因为EOF被读了两次,我认为这就是为什么程序不接受我的输入语言。我的问题是,为什么EOF被阅读两次以及如何阻止?

此外,在没有EOF规则的情况下执行上述操作会导致输入

abbbb

打印“接受”消息,但由于输入过多而立即失败。我想要的只是传递或失败,这就是为什么我试图使用EOF来验证我会得到一个结果。

3 个答案:

答案 0 :(得分:1)

野牛(以及我所知道的除柠檬以外的所有yacc衍生物)除非后面跟着EOF标记,否则不会减少开始产量。实际上,它将语法修改为以下内容:

$accept: accept $end;
accept: A END {...}

您的END令牌与内置$end令牌不同。因此野牛会愉快地减少accept规则(因此触发你的printf,你的代码中的消息似乎与输出中的消息不同,这表明它们来自你的代码的不同版本)但它不会减少自己的$accept规则,从而报告语法错误。

flex准备不止一次匹配<<EOF>>的情况肯定如此。只要你要求更多代币,我相信它会继续这样做,但我可能是错的;当然,它会匹配两次。但那不是你的问题。你的问题是,你试图强迫野牛去做它会做的事情,除非你已经让它无法做到这一点。

简而言之,让flex为EOF返回0,这是它想要做的,并且信任bison只接受由EOF终止的输入。这将使您的代码更简单。

(棘手的部分实际上是识别一个没有输入结尾的句子;例如,如果你将一种语言嵌入到另一种语言中 - 例如,HTML中的javascript或CSS。在这种情况下,你必须玩一些游戏,我相信这就是为什么柠檬不插入通常的增强启动规则。)

答案 1 :(得分:1)

我能够使用以下解决方案在带有flex的EOF中进行扫描并将其传递给Bison,而不会再次与EOF匹配。

Make bison reduce to start symbol only if EOF is found

该解决方案涉及使用start condition来读取下一个EOF而不实际读取EOF。一旦“初始”EOF被触发(END可以被发送到Bison),那么EOF就会被读入并自然地完成flex / bison解析。至少这是我对它的理解。

的Flex

%x REALLYEND                                              <--- declare start condition
%option noinput nounput
%%
"END"                   { return END; }
.                       { return TOK; }
<INITIAL><<EOF>>        { BEGIN(REALLYEND); return EOP; } <---- trigger start condition
<REALLYEND><<EOF>>      { return 0; }                     <---- trigger EOF
%%

野牛

%%
prog : END EOP { printf ("ok\n"); }; <-- can use EOP just like END in my example
%%

答案 2 :(得分:0)

答案是3折

1)在大多数情况下,您应该允许您的野牛解析器处理EOF。这可能是最简单的方法。但这并不总是可行的。

2)处理<<EOF>>内置的flex规则有some special requirements(手册的强制性链接)。

3)关于这一点的注释1.如果你第一次发现你的语法似乎需要某种类型的文件令牌结束就可以了(c的某些变体需要这样)但它被认为是坏的表单(某些编辑器具有在文件末尾添加可能导致冲突的换行符的设置)。