0

我正在研究在 Linux 平台上使用 C++ 的元编程语言解析器。现在,我需要为解析器实现选项/长选项以提供一些附加功能。基本上,如果用户传入一些附加选项,解析器需要在解析文本文件时存储统计信息。

我可以想到两种方法来实现它。一种方法是用户全局存储用户输入的选项。另一种方法是创建一个单例类来存储选项。所以我想知道是否有其他方法可以实现它。最好/最推荐的实施方式是什么?提前致谢。

问候,

K·海因

4

2 回答 2

2

globals 和 singleton 都会使解析器的单元测试变得很痛苦。要对解析器在不同选项下的行为方式进行单元测试,您的测试需要修改全局变量。这种方法至少存在两个问题: 全局变量和您的类之间没有明确的关联。除了检查实现之外,读者无法判断您的类中使用了哪些全局变量以及它们如何影响行为。这样的全局变量不能是 const (因为它们是在 main 中设置的)。因此,您失去了沟通和强制执行的能力,即一旦创建解析器,选项的值就无法更改。

经典的单例甚至比全局更糟糕,因为它使您无法替换实现并且通常完全阻碍测试。

一个不错的方法是注入一个 const 对象,该对象将选项存储到解析器构造函数。但是不要把命令行解析逻辑放在这个对象中,否则你将无法方便地在测试中使用该对象。

于 2012-09-30T07:29:47.057 回答
1

要扩展 Jan 的答案,您将拥有如下功能:

bool my_parser(const parser_options &options);

parser_options类型可以是简单的结构,例如:

struct parser_options
{
    FILE *source_file;
    bool warnings_as_errors;
    std::shared_ptr<error_handler> eh;
    ...
};

error_handler可以这样定义:

struct error_handler
{
    virtual void error(int code, const char *message) = 0;
    virtual void warning(int code, const char *message) = 0;
    virtual ~error_handler() {}
};

然后该程序将执行以下操作:

int main(int argc, const char *argv)
{
    parser_options options;
    // process argc/argv options here, adding them to options, e.g.:
    //     case WARN_AS_ERROR: options.warnings_as_errors = true; break;
    return my_parser(options, &error) ? ERROR_SUCCESS : ERROR_FAILURE;
}

my_parser这允许您编写直接调用的测试,parser_options独立于命令行处理进行设置,并允许error_handler指定不同的(例如,以机器可读的形式格式化信息)。

注意:这并不是一个完美的解析器设计,它只是一个如何设计这样的东西的例子。

注意:如果应用程序可以配置为控制流水线(例如无优化、打印内部 AST、内部表示、汇编代码、预处理器输出),此设计对于测试并不是严格必要的。但是,该设计更加灵活,因为它允许不同的程序使用它而无需直接调用命令行程序(GUI 应用程序/IDE、静态分析工具等)。

于 2012-09-30T10:23:25.573 回答