1

在下面这个极其简单的例子中,我想用一个单一的语言阅读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 来验证我会得到一个结果。

4

3 回答 3

3

我能够使用以下解决方案使用 flex 扫描 EOF 并将其传递给 Bison,而不会再次遇到匹配 EOF。

仅当找到 EOF 时才使野牛减少到开始符号

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

柔性

%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
%%
于 2013-09-12T05:45:58.990 回答
1

野牛(以及我知道的所有 yacc 衍生物,除了柠檬)不会减少开始生产,除非它后面跟着一个 EOF 令牌。实际上,它将语法修改为如下所示:

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

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

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

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

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

于 2013-09-12T04:37:19.867 回答
0

答案是3折

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

2) 处理<<EOF>>内置的 flex 规则有一些特殊要求(必须链接到手册)。

3)关于第 1 点的注释。如果您首先发现您的语法似乎需要某种类型的文件结束标记是可以的(c 的某些变体需要这个)但它被认为是错误的形式(一些编辑器具有在文件末尾添加换行符的设置,这可能会导致冲突)。

于 2013-10-22T06:08:29.550 回答