为什么规则不适用于使用C ++的Flex?

时间:2017-04-20 01:25:20

标签: c++ macos flex-lexer lexer

我有这段代码,但是使用c ++操作无法正常运行。 我试过了,但我没有得到任何错误,你怎么看?有人知道哪个是错误吗?。

ejem05.l

%x use
%{
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>

using namespace std;

#define MAX_USE_NUM 10
YY_BUFFER_STATE use_stack[MAX_USE_NUM];
int use_stack_ptr = 0;   
%}

%option c++ noyywrap

%%
<INITIAL,use>[0-9]+ {cout<< "Number found: "<< endl;}
use[[:blank:]]+ {BEGIN(use);}
<use>[[:alpha:][:punct:][:digit:]]+ {
    cout << "Nombre de archivo: "<< YYText() << endl;
    if ( use_stack_ptr >= MAX_USE_NUM ) {
        fprintf( stderr, "Too much files" );
        exit(1);
    }
    use_stack[use_stack_ptr++] = YY_CURRENT_BUFFER;
    ifstream in(YYText());
    yyin = &in;
    if (!yyin) {
        cout<< "ERROR file not found" << endl;
        exit(1);
    }
    yy_switch_to_buffer(
    yy_create_buffer( yyin, YY_BUF_SIZE ) );
    BEGIN(0);
}
<<EOF>> {
        if (--use_stack_ptr < 0 ) {
            yyterminate();
        }  else {
            yy_delete_buffer( YY_CURRENT_BUFFER );
            yy_switch_to_buffer(use_stack[use_stack_ptr] );
            }
}
%%

int main(int argc, char** argv) {
    ++argv, --argc; /* skip over program name */
    ifstream in(argv[0]);
    yyFlexLexer* lexer = new yyFlexLexer(&in);
    while(lexer->yylex()!=0) 
        ;
    return 0;
}

我的输入文件是:

entrada.txt

use entrada1.txt
use entrada2.txt

文件内容:

entrada1.txt

45
56

文件内容:

entrada2.txt

34
67
89

我得到了这个结果:

  

Nombre de archivo:entrada1.txt
Nombre de archivo:entrada2.txt

我使用以下命令编译了这个文件:

flex ejem05.l
c++ lex.yy.cc -o ejem05
./ejem05 entrada.txt

不起作用的规则是:

<INITIAL,use>[0-9]+ {cout<< "Number found: "<< endl;}

提前致谢。对不起,我的英语不好。

1 个答案:

答案 0 :(得分:2)

我不知道这是否是您所看到的行为的原因,因为它基本上是未定义的行为,但似乎它与该问题有关。

这些都不适合使用C ++ I / O对象:

{
  // ...
  ifstream in(YYText());    // Point 1
  yyin = &in;               // Point 2
  if (!yyin) {              // Point 3
    cout<< "ERROR file not found" << endl;
    exit(1);
  }
  yy_switch_to_buffer(      // Point 4
    yy_create_buffer( yyin, YY_BUF_SIZE ) );
  BEGIN(0);
}
  1. in具有自动存储持续时间(即它是一个局部变量),因此当范围退出时它将被破坏,这将很快(但不会在传递给{{1之前)见下文。)

  2. yy_create_buffer是一个成员变量,因此它的生命周期是FlexLexer对象的生命周期。 yyin是本地对象的地址(如上所述)。当块退出时,&in变成悬空指针,因为它指向的对象不再存在。任何使用它的尝试都将是Undefined Behavior。 (我怀疑你逃避的原因是yyin实际上并非每次使用,但我不确定。)

  3. 由于yyin刚被设置为实际对象的地址,因此它不能是空指针。所以测试永远不会成功。即使文件未正确打开,也永远不会检测到错误。 C惯用法是检查yyin的返回值,它返回指向fopen的指针,因此可能为NULL。用于检查文件是否正确打开的C ++惯用语是:

    FILE

    依赖于被覆盖的operator!。您也可以调用if (!in) { ,它具有相同的语义。

  4. 最后,您将in.fail()(通过引用)传递给yyinyy_create_buffer函数没有详细记录(我自己很少使用C ++接口的原因之一),但它有理由认为它不接受它作为参数接收的yy_create_buffer的所有权。 。 (std::istream*对象在某种程度上有文档记录;在其构造函数的描述中,文档指出“yyFlexLexer不接受其流参数的所有权。由用户来确保指向的流至少保持活动状态只要yyFlexLexer实例“并且事实证明在这种情况下大致相同的警告适用。这并不奇怪,因为yyFlexLexer成员函数无法复制它传递的yy_create_buffer对象 - - 这些对象不可复制 - 如果没有复制,就无法取得所有权。

    std::istream做的是保留指向yy_create_buffer的{​​{1}}的指针。 (这没有记录,但它在生成的代码中清晰可见。)但是,因为它是std::istream,当rdbuf()被破坏时,它也会处置它的std::fstream。随后尝试使用指向被破坏的in的指针当然是更多的未定义行为,但是如果你非常幸运(或者可能是不幸的话),那么足够的位在指向{的内存中仍然有效。 {1}}报告第一次尝试从中读取文件结束或错误。这肯定会解释你所看到的症状,但这些都是高度投机的。

  5. 结论:如果您打算使用C ++,请按照规则玩游戏。不要创建悬空指针,不要让过期的对象过早地被破坏,并在创建它们之后和使用之前检查rdbuf()对象的有效性。