从stdin到文件的Flex / Bison EOF传播
我有一个扫描仪,解析器和一个main,我通过它创建一个可执行文件
bison -d parser.y; flex scanner.l; gcc main.c parer.tab.c lex.yy.c
当我运行./a.out
它会按照我想要的方式执行操作:如果Ctrl+D
则会检测到EOF
,并且main
可以相应地执行操作。 这意味着:如果yyin
是stdin
那么点击Return
结束该行的解析,主循环等待下一个输入行。 按Ctrl+D
结束主循环中的break
解析输入并退出。 如果输入来自一个文件,e,g, testFile
该文件可以包含1个要解析的表达式,直到EOF。 在文件场景中,新行应该像空格和制表符一样被吃掉。 当输入来自stdin
时,所有这些应该像解释器一样,当输入来自文件时,它应该像脚本评估器一样。 这种测试文件的示例内容是: test\n
。 这里未检测到EOF。 我很难理解为什么会这样。 换句话说,我想在这里扩展问题,以便另外使用输入文件
parser.y:
%{ #include #include #include /* 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; } }
scanner.l:
%{ #include #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 %% <> { return TEOF; } [ \t] { } [\n] { if (yyin == stdin) return 0; } [a-zA-Z][a-zA-Z0-9]* { return TWORD; } . { return TJUNK; } %%
main.c中:
#include #include #include #include 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 %i", result); } fprintf(fOut, "\n\n done \n "); exit(EXIT_SUCCESS); }
我试图根据这里或这里提出的建议重写解析,没有太大的成功。 当从文件中读取输入时,主要知道EOF的正确方法是什么?
更新:一个建议是该问题可能是由于return 0;
在\n
。 作为一个快速测试,我只返回0如果yyin == stin
./a.out testFile
但是调用./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;
如果有人能给我一个更优雅的解决方案,我仍然会很感激。 这可能是制作干净版本的好方法。
如链接中所述, flex
具有用于识别输入文件或流的结尾的语法(例如,来自字符串的输入)。
实际上, flex
实际上有这样的规则在任何时候都在运行。 默认情况下,规则调用yywrap
。 你把它关了(用%noyywrap
)。 那没关系,除了……
遇到“EOF令牌”时的默认操作是返回0。
bison(和byacc)生成的解析器需要查看此零令牌。 请参阅带有flex和bison的END OF FILE标记的 答案 (仅在没有它的情况下有效) 。
您的词法分析器在遇到换行符时返回0
令牌。 这会造成各种麻烦。 毫无疑问,这会导致您从文件中读取时所观察到的内容。
编辑:好的,不管怎样,应用更新,让我们考虑你的语法。
请记住,野牛添加了一个寻找零令牌的特殊产品。 让我们用$
代表(通常是人们,或者有时是$end
)。 所以你的整个语法(没有动作和“错误”被删除,因为它也很特殊)是:
$all : input $; input: word | eof | /* empty */; word: TWORD; eof: TEOF;
这意味着你的语法接受的唯一句子是:
TWORD $
要么:
TEOF $
要么:
$
因此,当您调用yyparse()
, yyparse()
内的循环将从词法分析器中预读一个标记,并在标记为零值文件结尾$
接受(并返回)结果。 如果不是,则令牌需要是TWORD
或TEOF
(其他任何内容都会导致调用yyerror()
并尝试重新同步)。 如果令牌是两个有效令牌之一, yyparse()
将再次调用词法分析器以validation下一个令牌是零值的文件结束$
令牌。
如果所有这些都成功, yyparse()
将返回成功。
重新添加操作,您应该看到printf
输出,并根据用于识别(最多一个)令牌的减少规则获取存储在parseValue
的值。