Получение AST из парсера boost::spirit

После того, как я прочитал учебники по boost::spirit, они мне очень понравились из-за синтаксиса комбинатора парсеров. Создавать парсер так просто.

К сожалению, учебники были не так точны в вопросе получения сложной структуры данных из парсера. Я пытаюсь добраться до Kaleidoscope AST.

В любом случае, вот мой код AST:

#ifndef __AST_HPP__
#define __AST_HPP__

#include 
#include 
#include 
#include 
#include 
#include 

namespace ast {

struct add;
struct sub;
struct mul;
struct div;
struct func_call;
template struct binary_op;

typedef boost::variant>, boost::recursive_wrapper>,
        boost::recursive_wrapper>, boost::recursive_wrapper<
                binary_op
>, boost::recursive_wrapper> expression; template struct binary_op { expression left; expression right; binary_op(const expression & lhs, const expression & rhs) : left(lhs), right(rhs) { } }; struct func_call { std::string callee; std::vector args; func_call(const std::string func, const std::vector &args) : callee(func), args(args) { } }; struct prototype { std::string name; std::vector args; prototype(const std::string &name, const std::vector &args) : name(name), args(args) { } }; struct function { prototype proto; expression body; function(const prototype &proto, const expression &body) : body(body), proto(proto) { } }; } #endif

Я опустил части BOOST_FUSION_ADAPT_STRUCT, но они там есть.

А это мой парсер выражений:

#ifndef __PARSER_HPP__
#define __PARSER_HPP__

#include 
#include 
#include 
#include 

#include "ast.hpp"

namespace parser {

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;

template
struct expression: qi::grammar {
    expression() :
        expression::base_type(expr) {
        using qi::lit;
        using qi::lexeme;
        using ascii::char_;
        using ascii::string;
        using ascii::alnum;
        using ascii::alpha;
        using qi::double_;
        using namespace qi::labels;

        using phoenix::at_c;
        using phoenix::push_back;

        number %= lexeme[double_];
        varname %= lexeme[alpha >> *(alnum | '_')];

        binop
                = (expr >> '+' >> expr)[_val = ast::binary_op(_1, _3)]
                        | (expr >> '-' >> expr)[_val
                                = ast::binary_op(_1, _3)]
                        | (expr >> '*' >> expr)[_val
                                = ast::binary_op(_1, _3)]
                        | (expr >> '/' >> expr)[_val
                                = ast::binary_op(_1, _3)];

        expr %= number | varname | binop;
    }

    qi::rule expr;
    qi::rule binop;
    qi::rule varname;
    qi::rule number;
};

}

#endif

Проблема у меня в том, что у него, похоже, проблема с результирующим ast::expression. Скомпилированное выражение выбрасывает более 200 строк ошибок сложного шаблона. Я подозреваю, что это что-то с тем, как я пытался получить информацию из правила binop, но я не уверен.

Кто-нибудь может помочь?

8
задан Lanbo 10 December 2011 в 23:41
поделиться