gpt4 book ai didi

c - Flex/Bison EOF 从标准输入与文件传播

转载 作者:行者123 更新时间:2023-12-02 02:58:54 25 4
gpt4 key购买 nike

我有一个扫描仪、解析器和一个主程序,我通过它创建一个可执行文件

bison -d parser.y;柔性扫描仪.l; gcc main.c parer.tab.c lex.yy.c

当我运行 ./a.out 时,它会执行我想要的操作:如果按下 Ctrl+D ,则会检测到 EOF 并且 main 可以采取相应的行动。这意味着:如果yyinstdin,那么点击Return就会结束该行的解析,并且主循环等待下一个输入行。按 Ctrl+D 在主循环中使用 break 结束解析输入并退出。如果输入来自文件,例如 testFile,则该文件可以包含 1 个要解析的表达式,直到 EOF。在文件场景中,新行应该像空格和制表符一样被吃掉。当输入来自 stdin 时,所有这些都应该像解释器一样运行;当输入来自文件时,所有这些都应该像脚本评估器一样运行。此类测试文件的示例内容为:test\n。这里没有检测到 EOF。我很难理解为什么会出现这种情况。换句话说,我想要问题的扩展 here额外处理输入文件

解析器.y:

%{
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

/* stuff from flex that bison needs to know about: */
int yylex();
int yyparse();
FILE *yyin;

static int parseValue;

void yyerror(const char *s);
%}

%token TWORD
%token TEOF
%token TJUNK

%start input

%%
input: word { printf("W"); parseValue = 1; }
| eof { printf("eof"); parseValue = -11;}
| /* empty */ { printf("_"); parseValue = -1; }
| error { printf("E"); parseValue = -2; }
;

eof: TEOF
;

word: TWORD
;
%%

void yyerror(const char *s) {
printf("nope...");
}

int getWord( FILE *file) {
int err;

if (file) {
yyin = file;
} else /* error */ {
printf("file not valid");
return -3;
}

err = yyparse();
if (!err) {
return parseValue;
} else /* error */ {
printf("parse error");
return -4;
}
}

扫描仪.l:

%{
#include <stdio.h>
#include "parser.tab.h"
#define YYSTYPE int

int yylex();
%}

/* avoid: implicit declaration of function ‘fileno’ */
/*%option always-interactive*/

%option noyywrap
/* to avoid warning: ‘yyunput’ defined but not used */
%option nounput
/* to avoid warning: ‘input’ defined but not used */
%option noinput

%%
<<EOF>> { return TEOF; }
[ \t] { }
[\n] { if (yyin == stdin) return 0; }
[a-zA-Z][a-zA-Z0-9]* { return TWORD; }
. { return TJUNK; }
%%

main.c:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>

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

int result = 0;
FILE *fOut = stdout, *fIn = stdin;

/* skip over program name */
++argv, --argc;
if ( argc > 0 ) {
fIn = fopen( argv[0], "r" );
}

while (true) {
fprintf(fOut, "\nTEST : ", result);

result = getWord(fIn);

if (result == -11) {
printf(" %i ", result); printf("--> EOF");
break;
}
if (result < 0) {
printf(" %i ", result); printf("--> <0");
/*continue;*/
break;
}

fprintf(fOut, " => %i", result);
}

fprintf(fOut, "\n\n done \n ");
exit(EXIT_SUCCESS);
}

我尝试根据建议重写解析 herehere ,但没有取得太大成功。从文件读取输入时, main 知道 EOF 的正确方法是什么?

更新:一种建议是,该问题可能是由于 \n 上的 return 0; 造成的。作为一个快速测试,如果 yyin == stin 我只返回 0,但调用 ./a.out testFile 仍然无法捕获 EOF更新2:我通过使用 yywrap 使其工作。我摆脱了所有 TEOF 的东西。扫描仪有一个部分:

extern int eof;

最后:

int yywrap() {
eof = 1;
return 1;
}

在解析器中有一个:

int eof = 0;

文件中的更下方:

err = yyparse();
if (err != 0) return -4;
else if (eof) return -11;
else return parseValue;

如果有人可以向我展示一个更优雅的解决方案,我仍然会很感激。 This可能是制作干净版本的好方法。

最佳答案

如链接中所述,flex 具有用于识别输入文件或流的末尾(例如,来自字符串的输入)的语法。

事实上,flex 始终有效地运行着这样的规则。默认情况下,该规则调用yywrap。您将其关闭(使用 %noyywrap)。没关系,除了...

遇到“EOF token”时的默认操作是返回 0。

由 bison(和 byacc)生成的解析器需要看到这个零标记。请参阅this answerEND OF FILE token with flex and bison (only works without it) .

您的词法分析器在遇到换行符时返回 0 标记。那会带来各种麻烦。毫无疑问,这会导致您在从文件中读取数据时所观察到的情况。

<小时/>

编辑:好的,解决了这个问题并应用了更新,让我们考虑一下您的语法。

请记住,bison 添加了一个特殊的产生式来寻找零标记。让我们用 $ 来表示(正如人们通常所做的那样,或者有时是 $end)。因此,您的整个语法(没有任何操作,并且删除了“错误”,因为它也很特殊)是:

$all : input $;

input: word | eof | /* empty */;

word: TWORD;

eof: TEOF;

这意味着您的语法仅接受的句子是:

TWORD $

或者:

TEOF $

或者:

$

因此,当您调用 yyparse() 时,yyparse() 内部的循环将从词法分析器中提前读取一个标记,并接受(并返回)结果(如果token 是零值的文件结尾$。如果不是,则 token 必须是 TWORDTEOF 之一(任何其他值都会导致调用 yyerror() 并尝试重新同步)。如果 token 是两个有效 token 之一,yyparse() 将再次调用词法分析器以验证下一个 token 是否是零值文件结尾$ token 。

如果所有这些都成功,yyparse() 将返回成功。

重新添加操作,您应该看到 printf 输出,并根据用于识别(最多一) token 。

关于c - Flex/Bison EOF 从标准输入与文件传播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20458469/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com