【发布时间】:2016-01-11 14:21:00
【问题描述】:
我用 bison 编写了一个 verilog 解析器,并使用 boost::variant 来存储每个规则的每个变体的所有差异情况。我用一个小例子,BNF 表达式规则来展示我的数据结构:
expression :
primary
| expression + expression
primary :
(expression)
| number
存储它的数据结构是:
typedef boost::variant<
std::shared_ptr<exp1>,
std::shared_ptr<exp2>,
> expression
typedef boost::variant<
std::shared_ptr<prim1>,
std::shared_ptr<prim2>,
> primary
exp1/2 和 prim1/2 类用于存储表达式和初级中的两种不同情况:
class exp1 : public BaseClass {
public :
std::shared_ptr<primary> mem1;
exp1(std::shared_ptr<primary> i1):
mem1(i1)
{}
}
为简单起见,我只显示exp1,而exp2和prim1/2类似。 在野牛文件中,规则及其动作是这样写的:
expression :
primary {
$$= std::make_shared<expression>(std::make_shared<exp1>($1));
}
这样的解决方案会导致两个问题:
1 编译速度非常慢,使用 g++ 4.8.4 几乎需要 1 分钟
2 运行时间不是很快
我有一个类似的用ocaml和ocamlyacc编写的解析器,它支持非常优雅的变体规范,1秒编译,运行速度与上面提到的g++版本非常相似。
我使用 boost::variant 的方式有什么问题吗?
==============
我将所有变体更改为带有接受 shared_ptrs 的构造函数的类:
class ComponentBase {
};
Class VariantBase{
};
class prim1;
class prim2;
class exp1;
class exp2;
class expression : public VariantBase {
expression (shared_ptr<ComponentBase> i1):
VariantBase(i1) {}
}
class primary : public VariantBase {
primary (shared_ptr<ComponentBase> i1):
VariantBase(i1) {}
}
然后编译没有任何改进。看来yacc生成的代码是慢的根源。
有什么建议吗?
【问题讨论】:
-
我认为语法树比这更复杂。真的,1 分钟太长了?
-
至于运行时,您必须检查 bison 提供的 cpp 文件。如果源代码难以优化,或者您关闭了优化,您的运行时间将会受到影响。
-
实际上bison源文件包含3700~行、200~规则和500~组件。对于完整的verilog 2005 语言来说,它是一个大的。但是我有一个类似的用ocaml语言编写的,它的编译时间只有3秒。
标签: c++ c++11 boost boost-variant