【问题标题】:why is the rule not working on Flex using C++?为什么该规则不适用于使用 C++ 的 Flex?
【发布时间】:2017-09-16 10:43:35
【问题描述】:

我有此代码,但使用 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

我得到了这个结果:

档案名称:entrada1.txt
档案名称:entrada2.txt

我已经使用这些命令编译了这个文件:

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

无效的规则是:

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

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

【问题讨论】:

    标签: c++ macos flex-lexer lexer


    【解决方案1】:

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

    这些都不适合使用 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 对象的生命周期。 &amp;in 是本地对象的地址(如上所述)。当块退出时,yyin 成为一个悬空指针,因为它指向的对象不再存在。任何使用它的尝试都将是未定义的行为。 (我怀疑你逃脱的原因是 yyin 实际上并不是每个人都使用过,但我不确定。)

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

      if (!in) {
      

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

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

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

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

    【讨论】:

    • ifstream in(YYText());被破坏,因此从不读取 entrada1.txt 中的内容。
    • 非常感谢。这正是我在代码中的问题。 ^^
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 2021-03-31
    • 2019-04-23
    相关资源
    最近更新 更多