2011-12-10 53 views
8

在我读boost::spirit上的tutorials之后,我非常喜欢它,因为解析器组合语法。制作解析器非常简单。从boost :: spirit parser获取AST

不幸的是,这些教程并没有从解析器中获得复杂的数据结构。我正在尝试去Kaleidoscope AST

总之,这里是我的AST代码:

#ifndef __AST_HPP__ 
#define __AST_HPP__ 

#include <boost/fusion/include/adapt_struct.hpp> 
#include <boost/variant/recursive_variant.hpp> 
#include <boost/lexical_cast.hpp> 
#include <boost/variant/apply_visitor.hpp> 
#include <string> 
#include <vector> 

namespace ast { 

struct add; 
struct sub; 
struct mul; 
struct div; 
struct func_call; 
template<typename OpTag> struct binary_op; 

typedef boost::variant<double, std::string, boost::recursive_wrapper<binary_op< 
     add>>, boost::recursive_wrapper<binary_op<sub>>, 
     boost::recursive_wrapper<binary_op<mul>>, boost::recursive_wrapper< 
       binary_op<div>>, boost::recursive_wrapper<func_call>> 
     expression; 

template<typename OpTag> 
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<expression> args; 

    func_call(const std::string func, const std::vector<expression> &args) : 
     callee(func), args(args) { 
    } 
}; 

struct prototype { 
    std::string name; 
    std::vector<std::string> args; 

    prototype(const std::string &name, const std::vector<std::string> &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 <boost/config/warning_disable.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 

#include "ast.hpp" 

namespace parser { 

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

template<typename Iterator> 
struct expression: qi::grammar<Iterator, ast::expression(), ascii::space_type> { 
    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<ast::add>(_1, _3)] 
         | (expr >> '-' >> expr)[_val 
           = ast::binary_op<ast::sub>(_1, _3)] 
         | (expr >> '*' >> expr)[_val 
           = ast::binary_op<ast::mul>(_1, _3)] 
         | (expr >> '/' >> expr)[_val 
           = ast::binary_op<ast::div>(_1, _3)]; 

     expr %= number | varname | binop; 
    } 

    qi::rule<Iterator, ast::expression(), ascii::space_type> expr; 
    qi::rule<Iterator, ast::expression(), ascii::space_type> binop; 
    qi::rule<Iterator, std::string, ascii::space_type> varname; 
    qi::rule<Iterator, double, ascii::space_type> number; 
}; 

} 

#endif 

我的问题是,它似乎与所产生的ast::expression有问题。编译过程会抛出200多行复杂的模板错误。我怀疑这是与我试图从binop规则中获取信息的方式有关,但我不确定。

任何人都可以帮忙吗?

回答

7

您正在尝试使用Boost Phoenix占位符调用ast::binary_op的构造函数。他们混合不好。您需要使用lazy call构造函数ast::binary_op。这是在凤凰城提供使用construct

binop = (expr >> '+' >> expr) [_val = construct< ast::binary_op<ast::add> >(_1, _2)] 
     | (expr >> '-' >> expr) [_val = construct< ast::binary_op<ast::sub> >(_1, _2)] 
     | (expr >> '*' >> expr) [_val = construct< ast::binary_op<ast::mul> >(_1, _2)] 
     | (expr >> '/' >> expr) [_val = construct< ast::binary_op<ast::div> >(_1, _2)] ; 

另外,我觉得你只需要_1_2占位符,作为'+''-',...转换为qi::lit(litteral),因此具有无属性。

我还注意到varnamenumber规则一对夫妇失踪括号:

qi::rule<Iterator, std::string(), ascii::space_type> varname; 
//       ^^   
qi::rule<Iterator, double(), ascii::space_type> number; 
//      ^^ 

升压精神齐是很强大,但也很难调试。当我开始使用它时,我发现这些Boost Spirit Applications非常有用。

我希望这会有所帮助,因为我不是一个促进精神专家。

+0

感谢'construct <>'真的带走了很多错误。现在我只剩下一个:'parser.hpp:38:81:error:'boost :: spirit :: _ 1'的值在常量表达式中是不可用的,'note:'boost :: spirit :: _1'没有被宣布为'constexpr'。任何帮助? – Lanbo

+0

好的废品,我写了一个错误写下你的解决方案。谢谢! – Lanbo

+0

That Spirit Applications链接列出了一些很好的示例源,谢谢! – rvalue