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

why is the rule not working on Flex using C++?

我有这段代码,但使用 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;}

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

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

None 这是 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 具有自动存储持续时间(即它是一个局部变量),所以它会在退出范围时被破坏,这将很快(但不会在它通过之前到 yy_create_buffer。见下文。)

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

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

    if (!in) {
    

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

  4. 最后,您将 yyin(通过引用)传递给 yy_create_bufferyy_create_buffer 函数没有很好的文档记录(这是我自己很少使用 C++ 接口的原因之一),但按理说它不拥有作为参数接收的 std::istream* 的所有权. (yyFlexLexer 对象有一些文档;在其构造函数的描述中,文档指出 "yyFlexLexer does not take ownership of its stream arguments. It’s up to the user to ensure the streams pointed to remain alive at least as long as the yyFlexLexer instance" 并且结果表明,大致相同的警告适用于这种情况。这并不奇怪,因为没有办法yy_create_buffer 成员函数可以复制传递给它的 std::istream 对象——这些对象是不可复制的——如果不复制,就无法取得所有权。

    yy_create_buffer 所做的是保留指向 std::istreamrdbuf() 的指针。 (这没有记录,但它在生成的代码中清晰可见。)但是,因为它是一个 std::fstream,当 in 被破坏时,它也会处理它的 rdbuf()。随后尝试使用指向被破坏的 rdbuf 的指针当然是更多的未定义行为,但如果你非常非常幸运(或者可能不幸),足够的位在内存中仍然有效指向 rdbuf 报告文件结尾或第一次尝试读取时出错。这肯定可以解释您所看到的症状,但这都是高度推测性的。

底线:如果你打算使用 C++,请按规则玩游戏。不要创建悬挂指针,不要让应该保留的对象过早销毁,并在创建对象之后和使用它们之前检查 std::fstream 对象的有效性。