Flex C++ - #ifdef inside flex 块

Flex C++ - #ifdef inside flex block

我想在预处理器中定义常量,它仅在定义时启动匹配某些模式。是否有可能这样做,或者有其他方法如何处理这个问题? 即在 C:

中删除单行注释的简化版本
%{
#define COMMENT
%}

%%
#ifdef COMMENT
[\/][\/].*$ ;
#endif

[1-9][0-9]* printf("It's a number, and it works with and without defining COMMENT");
%%

这个(非常合理的)请求没有很好的解决方案,但有一些可能性。

(F)lex 开始条件

Flex start conditions 使定义一些可选模式变得相当简单,但它们组合得不好。如果您只有一个控制变量,此解决方案将最有效,因为您需要为每个可能的控制变量组合定义一个单独的开始条件。

例如:

%s NO_COMMENTS
%%

<NO_COMMENTS>"//".*     ; /* Ignore comments in `NO_COMMENTS mode. */

%s声明意味着所有未标记的规则也适用于N_COMMENTS状态;您通常会在示例中看到 %x(“独占”),但这会迫使您明确标记几乎所有规则。

一旦您以这种方式修改了语法,您就可以 select 适当的规则集 在 运行-time 通过设置词法分析器的状态BEGIN(INITIAL)BEGIN(NO_COMMENTS)。 (BEGIN 宏仅在 flex 生成的文件中定义,因此您需要导出执行这两个操作之一的函数。)

将 cpp 用作实用程序。

flex 中没有预处理器功能。您可以使用 C 预处理器在将 flex 文件传递​​给 flex 之前对其进行预处理,但是您必须非常小心地处理您的输入文件:

  1. C 预处理器期望其输入是一系列有效的 C 预处理器标记。由于非常不同的引用规则,许多常见的 flex 模式将不符合这个假设。 (举个简单的例子,识别 C 注释的常见模式包括字符 class [^/*],C 预处理器会将其解释为包含 C 注释的开头。)

  2. flex 输入文件可能有许多行是有效的 #include 指令。没有办法避免这些指令被扩展(除了从文件中删除它们)。一旦扩展并合并到源代码中,头文件就不再包含保护,因此您必须告诉 flex 不要从它自己的模板中插入任何 #include 文件。我相信这是可能的,但它会有点脆弱。

  3. C 预处理器可能会扩展看起来像宏调用的内容。

  4. C 预处理器可能不会保留线性空白,从而改变 flex 扫描器定义的含义。

m4 和其他预处理器

使用m4作为预处理器会更安全,但这当然意味着学习m4。 (你不需要安装它,因为 flex 已经依赖于它。所以如果你有 flex 你也有 m4。)你仍然需要非常小心引用序列。 M4 允许您自定义这些序列,因此它比 cpp 更易于管理。但是不要复制将 [[ 定义为引号定界符的常见习语;它在正则表达式中很常见。

此外,m4 不会插入 #line 指令,任何重要的使用都会改变输入行的数量,使错误消息更难解释。 (更不用说调试的挑战了。)在这个非常简单的情况下,您可能可以避免这个问题,但问题会再次出现。

您也可以编写自己的简单预处理器,但您仍然需要解决上述问题。