如何使flex使用包含文本的文件(.txt / .c / etc。)作为输入

时间:2018-12-27 14:27:52

标签: c compiler-construction flex-lexer c99

我是flex的新手,我在编程方面的经验还很少。我需要使用flex创建一个扫描器,该扫描器最终将输出令牌流。目前,我只需要启动并运行绝对的基础知识。我希望编译后的输出文件“ a.exe”能够从单个文件中的文本而不是用户输入中运行。输出也应该是文件。作业要求程序能够像在cmd / PS窗口中那样运行: 。\ a.exe inputfile.txt outputfile.txt 输入和输出文件是按此顺序添加的任何文件名。 就目前情况而言,我的程序创建了我指定的输出文件,但未写入任何内容。尝试阅读Flex手册时,我感到非常困惑,因为我对计算机科学总体上还是很陌生。 目前,我只想获取一个可执行文件,该文件将遵循rules部分并正确输出。这就是说,我一般只是在计算输入文件中的字符,然后尝试将它们显示到输出文件中。我还试图帮助班上的其他人有个开始的地方(因为在这一事件中没有一个人被正式授课过),所以我花一些时间尝试以通用方式(带有安装和使用说明)创建该文件,以便我可以给他们一个地方来开始实际制作扫描仪的工作。

我从http://gnuwin32.sourceforge.net/packages.html安装了Flex 2.5.4a。安装后,我编辑了路径以包含bin文件。

我使用命令“ flex tokenout.l”和“ gcc lex.yy.c”构建文件,然后生成一个a.exe文件。在创建输出文件后,该文件似乎一点用都没有。

代码:

int num_lines = 0;
int num_chars = 0;
FILE *yyin;
FILE *yyout;

%%
\n  ++num_lines; ++num_chars;
.   ++num_chars;
%%

int yywrap(void) {
    return 0;
}
int main(int argc, char *argv[])
{
    yyin = fopen(argv[1],"r");
    yyout = fopen(argv[2],"w");
    yyparse();
    yylex();
    fprintf(yyout,"# of lines = %d, # of chars = %d\n", num_lines, num_chars);
    fclose(yyin);
    fclose(yyout);
    return 0;
}

结果应为指定为第二个参数的文件的“行数=实际行数,字符数=实际字符数”行。

当前已创建第二个自变量指定的文件,但仍为空白。

3 个答案:

答案 0 :(得分:1)

Lex(flex)在到达其输入流的末尾(在yywrap中时调用(或更准确地说,生成调用yyin的代码)。此功能的作用是:

  1. 如果需要/适当,请关闭输入文件。
  2. 如果有下一个文件,请切换到下一个输入文件。
  3. 如果flex应该结束,则返回非零值(最好是1),如果现在yyin重新打开到下一个文件,则返回0。

或者,如the manual所述:

  

扫描仪从YY_INPUT接收到文件结尾指示后,便会检查“ yywrap()”功能。如果“ yywrap()”返回false(零),则认为函数已经执行并设置yyin指向另一个输入文件,然后继续扫描。如果返回true(非零),则扫描程序终止,并向其调用方返回0。请注意,无论哪种情况,启动条件均保持不变;它不会恢复为INITIAL

     

如果您不提供自己的'yywrap()'版本,则必须使用'%option noyywrap'(在这种情况下,扫描仪的行为就像'yywrap()'返回了1 ),否则您必须链接“ -lfl”以获得该例程的默认版本,该版本始终返回1。

(现代flex具有<<EOF>>规则,通常这是处理堆叠输入文件的更好方法,因为文件之间的转换几乎总是会强制标记边界。)

答案 1 :(得分:1)

yyin = fopen(argv[1],"r");
yyout = fopen(argv[2],"w");
yyparse();
yylex();
  

目前,我的程序创建了我指定的输出文件,但是没有写入任何内容。

您很困惑,因为您不知道程序在做什么,也不知道程序在做什么,因为它没有告诉您。您需要的是反馈。特别是,您需要检查错误。

例如,如果第一个打开(3)失败怎么办?如果 yyparse 失败或不返回怎么办? (不会。)检查错误,并让程序告诉您正在发生的事情。

#include <err.h>
if( argc < 3 ) {
    errx(EXIT_FAILURE, "syntax: foo in out");
}
if( (yyin = fopen(argv[1],"r")) == NULL ) {
    err(EXIT_FAILURE, "could not read '%s'", argv[1]);
}
if (yyout = fopen(argv[2],"w")) == NULL ) {
    err(EXIT_FAILURE, "could not write '%s'", argv[2]);
}

printf("starting yyparse\n");
if( 0 != yyparse() ) {
    errx(EXIT_FAILURE, "parse error");
}
printf("starting yylex\n");
if( 0 != yylex() )  {
    errx(EXIT_FAILURE, "lex error");
}

以上内容可确保使用足够的参数启动程序,确保两个文件均成功打开,并检查错误分析和词法检查。不过,这只是一个例子。正如John Bollinger advised一样,您不需要yyparse,因为您没有使用野牛,并且yyout仅控制flex ECHO语句使用的文件。您可以使用自己的全局FILE *句柄,并在flex操作中对其使用 fprintf (3)。

我想您会发现,您永远不会在屏幕上看到“开始yylex”,因为yyparse永远不会返回,因为-如果它是在某个地方生成的,它不会返回,因为它正在调用 yylex < / strong>,它从不返回任何内容。

我将删除这些行,并使用以下命令设置flex调试

  yy_flex_debug = 1;

在调用yylex之前。我认为您会发现它更有意义。

答案 2 :(得分:0)

您似乎是从改编an example program from the Flex manual开始的。很好,但是也许您的第一步应该是使确切的示例程序正常工作。之后,一次执行一次。例如,下一步可能是使它使用第一个参数作为输入文件的名称(并且没有其他更改)。

关于您介绍的部分程序,我看到了两个语义问题:

  1. 当将flex与bison(或yacc)一起使用时,调用yyparse()的是生成的解析器(通过yylex()访问),通常它将重复执行直到输入为累。在这种情况下,主程序直接调用lexer是没有用的。

  2. yyout是flex将ECHO语句的输出定向到的文件,仅此而已。它对您不是特别有用,我暂时将其忽略。