代码之家  ›  专栏  ›  技术社区  ›  matli

灵活放置预定义宏

  •  0
  • matli  · 技术社区  · 7 年前

    我有以下灵活来源:

    %{
    #if !defined(__linux__) && !defined(__unix__)
    /* Maybe on windows */
    #endif
    int num_chars = 0;                                                                                                                                                                                                   
    %}
    
    %%
    .       ++num_chars;                                                                                                                                                                                                 
    %%
    int main()
    {
      yylex();                                                                                                                                                                                                             
      printf("%d chars\n", num_chars);                                                                                                                                                                                     
      return 0;                                                                                                                                                                                                            
    }
    
    int yywrap()
    {
      return 1;                                                                                                                                                                                                            
    }
    

    我通过命令生成一个C文件 flex flextest.l 并用编译结果 gcc -o fltest lex.yy.c

    令我惊讶的是,我得到了以下输出:

    flextest.l:2:37: error: operator "defined" requires an identifier
      #if !defined(__linux__) && !defined(__unix__)
    

    在进一步检查之后,问题似乎是flex实际上已经替换了 __unix__ 使用空字符串,如所示:

    $ grep __linux_ lex.yy.c
    #if !defined(__linux__) && !defined()
    

    为什么会发生这种情况,有没有可能避免这种情况?

    1 回复  |  直到 7 年前
        1
  •  1
  •   rici    7 年前

    实际上 m4 (当前版本使用的宏处理器 flex )哪个在扩大 __unix__ 到空字符串。 m4的GNU实现将某些符号定义为空宏,以便使用 ifdef

    当然,这是一个弹性的缺陷。flex不应允许从扫描仪定义文件复制的用户内容中展开宏 m4,而flex的当前版本正确地安排了要引用的扫描仪描述文件中包含的文本,以便它将通过 m4 unmodified,即使它碰巧包含一个可以集成的字符串rpreted by m4 as a macro expansion.

    flex的v2.5.39和v2.6.1中肯定存在这个bug。我没有测试所有以前的版本,但我认为它是在flex修改为使用 m4时引入的,根据新闻文件,它是v2.5.30版。

    这个特别的引用问题在2.6.2版中得到了修复,但是当前版本的flex(2.6.4)包含了各种其他的错误修复,所以我建议您升级到最新版本。


    如果您真的需要一个可以同时使用Buggy和最新版本的Flex的版本,那么您可以使用以下两种黑客中的一种:

    1. 找到其他方法来编写 uuunix_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu一种可能性是:

      #define C(x,y) x##y
      #define UNIX_ C(__un,ix__)
      #if !defined(__linux__) && !UNIX_
      

      那个黑客不适合 defined ,因为 defined(UNIX_) 测试是否 UNIX_ 是定义的,而不是它扩展到的内容是否被定义。但通常内置符号,如 uuunix_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu #if 指令将未定义d的任何标识符视为0,这意味着您通常可以不使用 x 而不是 defined(x) . (但是,如果 #define x 0 实际上,它不是一个完美的替代品。)

    2. 与许多M4应用程序一样,flex将M4的引号重新定义为 [[ ]] . BuggyFlex和修正后的版本都用一个相当复杂的序列来替换这些引号,该序列有效地引用了引号。但是,错误版本没有引用用户定义的文本,因此宏替换将在用户文本中执行。(如前所述,这就是为什么 Unix>变成空字符串的原因。

      在不引用用户定义文本的flex版本中,可以调用定义引号的M4宏。然后,可以使用这些新的引号引用 if 行,以防止宏替换 unix_uuuuuuuuuuuux>。但是,必须恢复引用定义,否则将完全破坏文件其余部分的宏处理。这有点棘手,因为它不可能写入 [. 。(flex将用不同的字符串替换它。)

      下面的内容似乎起到了作用。注意,宏调用放在C注释中。changequote宏将展开为空字符串(如果展开)。但是在2.6.2版以后的flex版本中,用户提供的文本被引用,因此changequote宏将不会被扩展。将它们放在注释中会从C编译器中隐藏它们。

      %{
      /*m4_changequote(<<,>>)<<*/
      #if !defined(__linux__) && !defined(__unix__)
      /*>>m4_changequote(<<[>><<[>>,<<]>><<]>>)*/
      
      /* Maybe on windows */
      #endif
      

      (更改引号的M4宏是 changequote 但flex调用 -P 标记更改内置项,如 changeQuote to m4_changequote . 在第二个changeQuote调用中,这两个调用 [ 哪个组成了 [[ sign are individually quoted with the temporary << 引号,它将它们隐藏在flex中的代码中,而flex则修改了 [. 的用法。

      我不知道这个黑客有多可靠,但它在我在我的机器上玩过的flex版本上起作用,包括2.5.4(pre-m4)2.5.39(Buggy)、2.6.1(Buggy)、2.6.2(稍微调试过)和2.6.4(更多调试过)。

    推荐文章