boost::spirit 算术公式解析器无法编译

Posted

技术标签:

【中文标题】boost::spirit 算术公式解析器无法编译【英文标题】:boost::spirit arithmetic formulas parser fails to compile 【发布时间】:2015-10-30 10:34:12 【问题描述】:

我正在尝试为填充抽象语法树的算术表达式编写一个精神解析器。如果我不尝试填充 AST,解析器将编译,但在当前版本中失败(出现一个 24K 错误)。我正在使用带有 -std=c++11 的 clang++ 3.5.0,并在 Ubuntu 14.4 上运行。

#include <string>
#include <vector>
#include <utility>

#include <boost/spirit/include/qi.hpp>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/include/adapted.hpp>

#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>

using std::string;
using std::vector;
using std::pair;

using boost::spirit::qi::grammar;
using boost::spirit::qi::space_type;
using boost::spirit::qi::rule;

struct Term; // forward dec
typedef boost::recursive_wrapper<Term> RWTerm;
typedef pair<char, RWTerm> OpAndRWTerm;
typedef pair<RWTerm, vector<OpAndRWTerm> > Expr;
typedef boost::variant<Expr, double> Factor;
typedef pair<char, Factor> OpAndFactor;
struct Term : public pair<Factor, vector<OpAndFactor> >;

template<typename It>
struct formula_parser : grammar<It, Expr(), space_type> 
  formula_parser() : formula_parser::base_type(expr_rule) 
    using boost::spirit::qi::double_;
    using boost::spirit::ascii::char_;

    factor_rule %= double_ | parenthesis_rule;
    parenthesis_rule %= '(' >> expr_rule >> ')';
    op_and_factor_rule %= char_("/*") >> factor_rule;
    term_rule %= factor_rule >> *op_and_factor_rule;
    op_and_term_rule %= char_("+-") >> term_rule;
    expr_rule %= term_rule >> *op_and_term_rule;
  
  rule<It, OpAndRWTerm(), space_type> op_and_term_rule;
  rule<It, Expr(), space_type> expr_rule;
  rule<It, OpAndFactor(), space_type> op_and_factor_rule;
  rule<It, RWTerm(), space_type> term_rule;
  rule<It, Expr(), space_type> parenthesis_rule;
  rule<It, Factor(), space_type> factor_rule;
;

int main() 
  formula_parser<string::const_iterator> grammar;

我从错误消息中了解到,fusion 在规则 term_rule 中混淆了 Types Factor 和 RWTerm。

我做错了什么?

【问题讨论】:

【参考方案1】:

如果我改变两件事,它会为我编译:

    由于Term 继承自std::pairTerm 是一个 类型。出于这个原因,您需要将BOOST_FUSION_ADAPT_STRUCT 应用到Term,无论是否已经在&lt;boost/fusion/adapted/std_pair.hpp&gt; 中为std::pair 完成了此操作:

    BOOST_FUSION_ADAPT_STRUCT(
        Term,
        (Factor, first)
        (std::vector<OpAndFactor>, second)
    )
    

    或者,您可以将Term 设为具有两个成员的独立结构,然后在其上应用BOOST_FUSION_ADAPT_STRUCT

    struct Term  Factor f; std::vector<OpAndFactor>  o;;
    
    BOOST_FUSION_ADAPT_STRUCT(
        Term,
        (Factor, f)
        (std::vector<OpAndFactor>, o)
    )
    

    顺便说一句:你必须在这里完全限定std::vector,因为下面的will not compile:

    using std::vector;
    BOOST_FUSION_ADAPT_STRUCT(
        Term,
        (Factor, f)
        (vector<OpAndFactor>, o)
    )
    

    声明term_rule时使用Term而不是RWTerm

    rule<It, Term(), space_type> term_rule;
    

完整代码:

#include <string>
#include <vector>
#include <utility>

#include <boost/spirit/include/qi.hpp>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/include/adapted.hpp>

#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>

using boost::spirit::qi::grammar;
using boost::spirit::qi::space_type;
using boost::spirit::qi::rule;

struct Term; // forward dec
typedef boost::recursive_wrapper<Term> RWTerm;
typedef std::pair<char, RWTerm> OpAndRWTerm;
typedef std::pair<RWTerm, std::vector<OpAndRWTerm> > Expr;
typedef boost::variant<Expr, double> Factor;
typedef std::pair<char, Factor> OpAndFactor;
struct Term : public std::pair<Factor, std::vector<OpAndFactor> >;

BOOST_FUSION_ADAPT_STRUCT(
    Term,
    (Factor, first)
    (std::vector<OpAndFactor>, second)
)


template<typename It>
struct formula_parser : grammar<It, Expr(), space_type> 
  formula_parser() : formula_parser::base_type(expr_rule) 
    using boost::spirit::qi::double_;
    using boost::spirit::ascii::char_;

    factor_rule %= double_ | parenthesis_rule;
    parenthesis_rule %= '(' >> expr_rule >> ')';
    op_and_factor_rule %= char_("/*") >> factor_rule;
    term_rule %= factor_rule >> *op_and_factor_rule;
    op_and_term_rule %= char_("+-") >> term_rule;
    expr_rule %= term_rule >> *op_and_term_rule;
  
  rule<It, OpAndRWTerm(), space_type> op_and_term_rule;
  rule<It, Expr(), space_type> expr_rule;
  rule<It, OpAndFactor(), space_type> op_and_factor_rule;
  rule<It, Term(), space_type> term_rule;
  rule<It, Expr(), space_type> parenthesis_rule;
  rule<It, Factor(), space_type> factor_rule;
;

int main() 
  formula_parser<std::string::const_iterator> grammar;

live example

【讨论】:

谢谢 - 它有效!使用从 pair 继承有什么问题? @DavidLehavi 我用解释更新了答案 感谢您提供的详细信息(只有在将您的代码与我之前的尝试进行比较后,我才意识到必须完全限定向量) 最近的boost也可以只是BOOST_FUSION_ADAPT_STRUCT(Term, first, second):further cleanups @sehe我在changelog of 1.58找到了:"推导出成员类型的新ADAPT_STRUCT、ADAPT_ADT、ADAPT_ASSOC_(#9516)"

以上是关于boost::spirit 算术公式解析器无法编译的主要内容,如果未能解决你的问题,请参考以下文章

防止 Boost Spirit Symbol 解析器过早接受关键字

Boost::Spirit 表达式解析器,带有定义的函数

为啥 nvcc 无法使用 boost::spirit 编译 CUDA 文件?

C ++中嵌入式友好的命令解析器

Boost Spirit x3 -- 使用其他解析器参数化解析器

无法使用 Boost Spirit X3 解析空的 C++ 结构