flex/bison 中的多个解析器:包含失败

Multiple parsers in flex/bison : include fails

我正在尝试使用多个解析器构建程序。我已将不同解析器的 flex / bison 文件放在不同的文件夹中以避免冲突。

为了能够使用它们,我使用了不同的前缀。但是,我的程序不会从头开始构建,扫描器 类 产生错误:

#pragma once

#if ! defined(yyFlexLexerOnce)
#define yyFlexLexer spFlexLexer
#include <FlexLexer.h>
#undef yyFlexLexer
#endif

#include "split_pattern_parser.h"

namespace SP {

class SP_Scanner : public spFlexLexer {
...
}

我收到这个错误:

error: expected class-name before ‘{’ token
 class SP_Scanner : public spFlexLexer {

我设法通过多次删除 #if ! defined(yyFlexLexerOnce) 条件来编译,并在出现此错误时重新放置它:

src/actions/actions_scanner.h:4:21: error: redefinition of ‘class actFlexLexer’
#define yyFlexLexer actFlexLexer
                 ^
actions_lexer.cpp:32:25: error: previous definition of ‘class actFlexLexer’

(actions 只是另一个词法分析器)

即使这对我来说不是什么大问题(我可以继续做我的项目),但当我不得不交出我的项目时,问题就大了:解释这个过程并不整洁构建代码。

在此先感谢您的帮助

你不应该和 yyFlexLexerOnce 开玩笑。这是 Flex 的内部实现。

您需要声明您使用的每个 FlexLexer 类型,最好只声明一次。您还需要精确地声明一次 FlexLexer 本身。 yyFlexLexerOnce 宏是将 flex 扫描仪的 C++ 接口放在一起的人选择使这成为可能的方式。 (多个头文件本来是我的选择,但我相信他们有他们的理由。)

所以忘记曾经见过 yyFlexLexerOnce,然后按照手册告诉你的方式去做:

#define yyFlexLexer spFlexLexer
#include "FlexLexer.h"
#undef yyFlexLexer

// This will not normally be in the same header file, but it could be.

#define yyFlexLexer actFlexLexer
#include "FlexLexer.h"
#undef yyFlexLexer

FlexLexer.h 有两个重要问题。

第一个,如上图所示,它被设计成 #included 不止一次,所以它没有头球后卫。这意味着您必须确保它永远不会包含在 yyFlexLexer 的相同预处理器定义中两次。一个好的习惯用法可能是创建一个小包装器:

/*** File: sp_scanner.h ***/

#pragma once
#define yyFlexLexer spFlexLexer
#include "FlexLexer.h"
#undef yyFlexLexer

但这会遇到第二个问题:yyFlexLexer 在生成的扫描器实现文件中自动 #included,具有 yyFlexLexer 的适当 #define。因此,您 不得 #include 它(甚至是间接地)在您的 .l 扫描器定义文件中的任何插入代码中。

这在您有实施扫描器所需的其他声明的并不少见的情况下会造成麻烦。诱惑是将这些声明放在 sp_lexer.h 头文件中(如上所述),但这不会起作用,因为您不能 #include "sp_lexer.h" 在扫描仪定义文件中。相反,您需要创建另一个头文件,并从 scanner.l 文件和 sp_lexer.h 文件中 #include 它。

具体来说,假设您正在使用 yyclass 选项在派生的 class 中插入扫描器实现方法。显然,您需要在生成的扫描器之前声明这个派生的class,并且您还需要在生成的扫描器的任何消费者中声明这个派生的class。所以你最终会得到这样的结果:

/*** File: sp_scanner_internal.h ***/
#pragma once
namespace sp {
  class Scanner : public spFlexLexer {
    /* ... */
  };
}

/*** File: sp_scanner.h ***/
#pragma once
#define yyFlexLexer spFlexLexer
#include "FlexLexer.h"
#undef yyFlexLexer
#include "sp_scanner_internal.h"

/*** File: sp_scanner.l ***/
%option prefix="sp"
%option outfile="sp_scanner.cpp"
%option yyclass="sp::Scanner"

%{
  #include "sp_scanner_internal.h"
  #include "sp_parser.h"
%}

我从您的示例文件中删除了 %option header-file,因为该头文件不应在 C++ 项目中使用。见 Flex manual:

The --header-file option is not compatible with the --c++ option, since the C++ scanner provides its own header in yyFlexLexer.h.

我也删除了 #include <iostream>,因为它包含在 FlexLexer.h 中,但是如果您愿意保留它当然没有问题。