为什么规则不适用于使用 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 = ∈
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 = ∈ // 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);
}
in
具有自动存储持续时间(即它是一个局部变量),所以它会在退出范围时被破坏,这将很快(但不会在它通过之前到 yy_create_buffer
。见下文。)
yyin
是一个成员变量,所以它的生命周期就是FlexLexer对象的生命周期。 &in
是本地对象的地址(如上所述)。当块退出时,yyin
变成一个悬空指针,因为它指向的对象不再存在。任何使用它的尝试都将是未定义的行为。 (我怀疑你逃避这个的原因是 yyin
实际上并不是每个人都用过,但我不确定。)
由于yyin
刚刚被设置为一个实际对象的地址,它不可能是一个空指针。所以测试永远不会成功。即使文件未正确打开,也永远不会检测到错误。 C 习惯用法是检查 fopen
的 return 值,其中 return 是指向 FILE
的指针,因此可能为 NULL。检查文件是否正确打开的 C++ 习惯用法是:
if (!in) {
依赖于被覆盖的operator!
。您也可以调用具有相同语义的 in.fail()
。
最后,您将 yyin
(通过引用)传递给 yy_create_buffer
。 yy_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::istream
的 rdbuf()
的指针。 (这没有记录,但它在生成的代码中清晰可见。)但是,因为它是一个 std::fstream
,当 in
被破坏时,它也会处理它的 rdbuf()
。随后尝试使用指向被破坏的 rdbuf
的指针当然是更多的未定义行为,但如果你非常非常幸运(或者可能不幸),足够的位在内存中仍然有效指向 rdbuf
报告文件结尾或第一次尝试读取时出错。这肯定可以解释您所看到的症状,但这都是高度推测性的。
底线:如果你打算使用 C++,请按规则玩游戏。不要创建悬挂指针,不要让应该保留的对象过早销毁,并在创建对象之后和使用它们之前检查 std::fstream
对象的有效性。
我有这段代码,但使用 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 = ∈
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 = ∈ // 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);
}
in
具有自动存储持续时间(即它是一个局部变量),所以它会在退出范围时被破坏,这将很快(但不会在它通过之前到yy_create_buffer
。见下文。)yyin
是一个成员变量,所以它的生命周期就是FlexLexer对象的生命周期。&in
是本地对象的地址(如上所述)。当块退出时,yyin
变成一个悬空指针,因为它指向的对象不再存在。任何使用它的尝试都将是未定义的行为。 (我怀疑你逃避这个的原因是yyin
实际上并不是每个人都用过,但我不确定。)由于
yyin
刚刚被设置为一个实际对象的地址,它不可能是一个空指针。所以测试永远不会成功。即使文件未正确打开,也永远不会检测到错误。 C 习惯用法是检查fopen
的 return 值,其中 return 是指向FILE
的指针,因此可能为 NULL。检查文件是否正确打开的 C++ 习惯用法是:if (!in) {
依赖于被覆盖的
operator!
。您也可以调用具有相同语义的in.fail()
。最后,您将
yyin
(通过引用)传递给yy_create_buffer
。yy_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::istream
的rdbuf()
的指针。 (这没有记录,但它在生成的代码中清晰可见。)但是,因为它是一个std::fstream
,当in
被破坏时,它也会处理它的rdbuf()
。随后尝试使用指向被破坏的rdbuf
的指针当然是更多的未定义行为,但如果你非常非常幸运(或者可能不幸),足够的位在内存中仍然有效指向rdbuf
报告文件结尾或第一次尝试读取时出错。这肯定可以解释您所看到的症状,但这都是高度推测性的。
底线:如果你打算使用 C++,请按规则玩游戏。不要创建悬挂指针,不要让应该保留的对象过早销毁,并在创建对象之后和使用它们之前检查 std::fstream
对象的有效性。