我有一个扫描器、解析器和一个主程序,通过以下方式创建可执行文件:
在解析器中有一个:
如果有更加优雅的解决方案,我仍然会很感激。 这个 链接可能是制作干净版本的好方法。
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
结束输入解析并退出。如果输入来自文件,例如testFile
,那么该文件可以包含1个表达式直到EOF
结束。在文件情况下,新行应被视为空格和制表符。所有这些内容都应该像从stdin
输入时的解释器一样运行,并且像从文件输入时的脚本评估器一样运行。这样一个测试文件的示例内容可能是:test\n
。在这里,EOF
未被检测到。我有困惑为什么会这样。换句话说,我想要一个问题这里的扩展版,以便能够处理输入文件
parser.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;
}
}
scanner.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);
}
我尝试根据这里或者这里的建议重写解析器,但是并没有太大的成功。当从文件读取输入时,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;
如果有更加优雅的解决方案,我仍然会很感激。 这个 链接可能是制作干净版本的好方法。
return 0
和'\n'
,但文件解析仍然无法正常工作;它仍在循环中。不确定如何继续。 - oopsyyparse()
内循环,直到词法分析器返回0
来表示输入结束。我记得已经有一段时间了,但是据我回忆,flex实际上会在返回TEOF
标记(一次)后返回0
。(有一些宏可以中止解析或提前接受,但您没有使用它们...) - torekyywrap()
函数使其正常工作了。如果您有更好的想法,我仍然欢迎您的评论。 - oopsyyparse()
在从标准输入读取每个换行符时返回已完成的解析(可能不成功),而在从文件读取时仅在达到“真正的EOF”时才返回。 - torek