c++ - 为什么 Flex/Lex 会将 C++ 代码的变量重置为其初始值?

标签 c++ bison flex-lexer

我试图通过 C++ 使用 Flex 和 Bison 创建简单的编译器,但我不明白为什么当 Flex 到达文件末尾时它会将 C++ 文件中声明的变量重置为其初始值。

lex.l 文件中:

%{
    #include "HelperCode.h"     
    // ... etc
%}
%option c++
%option noyywrap
%option yylineno
%%

[\n]    { dosomething();}

// ...etc
%%

HelperCode.h文件:

namespace
{
    int counter  = 0;

    //rest of code

    void dosomething()
    {
        counter++;
        cout << counter << " ";
        // here it will print the correct values based on input
        // ex: 1 2 3 4 5
    }

    void afterfinish()
    {
        cout << endl << counter;
        // but here it will print '0', like if the counter reset to 0 
    }
}

yacc.y 文件中:

// ... etc
// ...
void main(void)
{
    Parser* p = new Parser();
    p->parse();

    afterfinish(); 
}

最佳答案

问题几乎可以肯定是您将 namespace { ... } 放入头文件中。

包含此内容的每个 C++ 翻译单元都会获得头文件原始文本的拷贝,因此具有命名空间声明的拷贝。由于命名空间是匿名的,因此每个拷贝都是独立的;每个包含此的翻译单元都有自己的计数器,以及dosomethingafterfinish

这与 C 语言中将一些静态定义放入 header 中的情况非常相似,如下所示:

static int counter = 0;
static void dosomething(void) { printf("%d\n", ++counter); }
static void afterfinish(void) { printf("%d\n", counter); }

#include-s 这个 header 的每个 C 单元都有自己的计数器,以及一对自己的私有(private)函数 dosomethingafterfinish 对其进行操作。

词法分析器模块在它自己的计数器上运行,而包含 main 的模块中的 afterfinish它的自己的计数器上运行,它仍然是零。

如果你想要一个由你的模块共享的命名空间,只需给它一个名字。

// header file HelperCode.h
namespace parser_stuff {
  // We no longer *define* the counter in the header, just declare it.
  extern int counter;

  // And we use inline on functions defined in the header, otherwise
  // they will now be multiply defined!
  inline void dosomething()
  {
     counter++;
     // ... etc
  }

  // non-inline function
  void afterfinish();
}


// In one .cpp file somewhere, perhaps HelperCode.cpp
#include "HelperCode.h"

namespace parser_stuff {
  int counter = 0; // One program-wide definition of parser_stuff::counter.

  void afterfinish()
  {
    // ....
  }
}

当然,我们现在要做的

%{
    #include "HelperCode.h"     
    // ... etc
%}
%option c++
%option noyywrap
%option yylineno
%%

[\n]    { parser_stuff::dosomething();}

// ...etc
%%

否则:

%{
    #include "HelperCode.h"     
    // ... etc

    // one of these: bring in a specific identifier, or whole namespace:
    using parser_stuff::dosomething;
    using namespace parser_stuff;
%}
%option c++
%option noyywrap
%option yylineno
%%

[\n]    { dosomething();}

// ...etc
%%

在引用 afterfinish 的主模块中也类似。

关于c++ - 为什么 Flex/Lex 会将 C++ 代码的变量重置为其初始值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34444719/

相关文章:

c - 如何释放 Bison 的内存?

c - Flex 和 Bison 代码 - 总是有语法错误

C++ 指针作用域问题

c - 如何在 yacc 中使用 yylval 和 union

c - Bison 意外 token

c - C代码优化-防止多文件打开

c - 为什么 Bison 只打印输入?

c++ - 为什么这个无锁堆栈类中的 'deleting' 节点会导致竞争条件?

c++ - 有没有办法根据参数使用 'new XXXX'?

C++ : Initializing base class constant static variable with different value in derived class?