2015-10-30 1 views
1

Я пытаюсь написать синтаксический анализатор для арифметического выражения, который заполняет абстрактное синтаксическое дерево. Парсер компилируется, если я не пытаюсь заполнить AST, но сбой (с одной ошибкой 24K) в текущей версии. Я использую clang ++ 3.5.0 с -std = C++ 11 и работает на Ubuntu 14.4.boost: парсер синтаксических парных спиритов не скомпилирован

#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; 
} 

То, что я понял из сообщения об ошибке, что слияние смешивает типы Factor и RWTerm в правиле term_rule.

что я делаю неправильно?

ответ

3

Он компилирует для меня, если я изменить две вещи:

  1. Так как Term наследует от std::pair, Term является новый типа. По этой причине вам необходимо обратиться BOOST_FUSION_ADAPT_STRUCT к Term, независимо от того, это было сделано для std::pair в <boost/fusion/adapted/std_pair.hpp>:

    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) 
    ) 
    
  2. Использование Term вместо RWTerm при объявлении term_rule:

    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

+0

Спасибо, это работает! что не так с использованием наследования от пары? –

+1

@DavidLehavi Я обновил ответ с объяснением –

+0

спасибо за подробности (только после сравнения кода с моими предыдущими попытками я понял, что нужно полностью квалифицировать вектор) –