我正在尝试使用多个解析器构建程序。我已将不同解析器的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’
(行动只是另一个词法分析者)
即使对我来说这不是一个大问题(我可以继续处理我的项目),但是当我必须分发我的项目时它会变得非常棘手:要解释这个程序来构建它并不是一件好事。代码。
提前感谢您的帮助
答案 0 :(得分:2)
你不应该和yyFlexLexerOnce
一起愚弄。这是Flex实施的内部。
您需要声明您使用的各种FlexLexer
,理想情况下恰好一次。您还需要准确地声明FlexLexer
本身一次。 yyFlexLexerOnce
宏是将弹性扫描仪的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
有两个重要问题。
如上所示,第一个是它被设计为#include
d不止一次,所以它没有标题保护。这意味着您必须确保它在yyFlexLexer
的相同预处理器定义中永远不会包含两次。一个好习惯可能是创造一个小包装:
/*** File: sp_scanner.h ***/
#pragma once
#define yyFlexLexer spFlexLexer
#include "FlexLexer.h"
#undef yyFlexLexer
但是这会遇到第二个问题:yyFlexLexer
在生成的扫描程序实施文件中自动为#include
d,并且#define
为yyFlexLexer
。因此, #include
扫描程序定义文件中的任何插入代码中的 .l
(甚至间接地)都不能 sp_lexer.h
。
这会在非常罕见的情况下产生烦恼,在这种情况下,您需要执行扫描程序所需的其他声明。诱惑是将这些声明放在#incldue "sp_lexer.h"
头文件中(如上所述),但这不会起作用,因为您不能在扫描仪定义文件中#include
。相反,您需要创建另一个头文件,并scanner.l
文件和sp_lexer.h
文件中的yyclass
。
具体地说,假设您使用/*** 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"
%}
选项在派生类中插入scanner实现方法。显然,您需要在生成的扫描程序之前声明此派生类,并且还要在生成的扫描程序的任何使用者中声明此派生类。所以你最终会得到这样的东西:
%option header-file
我从示例文件中删除了--header-file
,因为该头文件不应该在C ++项目中使用。请参阅Flex manual:
--c++
选项与yyFlexLexer.h
选项不兼容,因为C ++扫描程序在#include <iostream>
中提供了自己的标头。
我也删除了FlexLexer.h
,因为它包含在sprintf
中,但当然如果您愿意保留它也不是问题。