我不会因为继承而使事情变得复杂。组合通常就足够了,并且不会混淆 qi 解析器接口。
我绘制了一个关于如何完成版本控制语法的小草图。假设旧语法:
template <typename It, typename Skipper>
struct OldGrammar : qi::grammar<It, Skipper, std::string()>
{
OldGrammar() : OldGrammar::base_type(mainrule)
{
using namespace qi;
rule1 = int_(1); // expect version 1
rule2 = *char_; // hopefully some interesting grammar
mainrule = omit [ "version" > rule1 ] >> rule2;
}
private:
qi::rule<It, Skipper, std::string()> mainrule;
qi::rule<It, Skipper, int()> rule1;
qi::rule<It, Skipper, std::string()> rule2;
};
正如您所看到的,这是相当严格的,要求版本恰好为 1。然而,未来发生了,发明了新版本的语法。现在,我要添加
friend struct NewGrammar<It, Skipper>;
到旧的语法并开始实现新的语法,如果需要的话,新的语法会慷慨地回退到旧的语法:
template <typename It, typename Skipper>
struct NewGrammar : qi::grammar<It, Skipper, std::string()>
{
NewGrammar() : NewGrammar::base_type(mainrule)
{
using namespace qi;
new_rule1 = int_(2); // support version 2 now
new_start = omit [ "version" >> new_rule1 ] >> old.rule2; // note, no expectation point
mainrule = new_start
| old.mainrule; // or fall back to version 1 grammar
}
private:
OldGrammar<It, Skipper> old;
qi::rule<It, Skipper, std::string()> new_start, mainrule;
qi::rule<It, Skipper, int()> new_rule1;
};
(我没有尝试让它与继承一起工作,尽管它很可能也应该工作。)