[英]Retrieving AST from boost::spirit parser
After I've read the tutorials on boost::spirit , I quite liked it because of the parser combinator syntax. 在我阅读了关于boost :: spirit的教程之后,由于解析器组合器语法,我非常喜欢它。 Making a parser is so easy.
制作解析器非常简单。
Unfortunately, the tutorials were not as exact on the matter of getting a complex data structure out of the parser. 遗憾的是,在从解析器中获取复杂数据结构的问题上,教程并不那么精确。 I am trying to get to the Kaleidoscope AST .
我正试图进入Kaleidoscope AST 。
Anyway, here be my AST code: 无论如何,这是我的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
I've omitted the BOOST_FUSION_ADAPT_STRUCT
parts, but they are there. 我省略了
BOOST_FUSION_ADAPT_STRUCT
部分,但它们在那里。
And this my expression parser: 这是我的表达式解析器:
#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
The problem I have is that it seems to have a problem with the resulting ast::expression
. 我遇到的问题是它似乎与生成的
ast::expression
有问题。 The compiled throws out more than 200 lines of complex template errors. 编译时抛出超过200行复杂模板错误。 I suspect it is something with the way I tried to get the information out of the
binop
rule, but I am not sure. 我怀疑这是我尝试从
binop
规则中获取信息的方式,但我不确定。
Can anyone help? 有人可以帮忙吗?
You are trying to call ast::binary_op
's constructor using Boost Phoenix placeholders. 您正在尝试使用Boost Phoenix占位符调用
ast::binary_op
的构造函数。 They don't mix well. 它们混合不好。 You need to use a lazy call to the
ast::binary_op
constructor. 你需要使用对
ast::binary_op
构造函数的惰性调用 。 This is provided in Phoenix by using construct
: 这是在凤凰城使用
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)] ;
Also, I think you only need the _1
and _2
placeholders, as the '+'
, '-'
,... are converted to qi::lit
(litteral) thus having no attribute. 另外,我认为你只需要
_1
和_2
占位符,因为'+'
, '-'
,...被转换为qi::lit
(litteral)因此没有属性。
I also noted a couple of missing parenthesis in varname
and number
rules : 我还注意到
varname
和number
规则中有两个缺少的括号:
qi::rule<Iterator, std::string(), ascii::space_type> varname;
// ^^
qi::rule<Iterator, double(), ascii::space_type> number;
// ^^
Boost Spirit Qi is very powerful, but also very hard to debug. Boost Spirit Qi非常强大,但也很难调试。 When I started to use it, I found these Boost Spirit Applications very useful.
当我开始使用它时,我发现这些Boost Spirit应用程序非常有用。
I hope this will be helpful, as I'm not a Boost Spirit expert. 我希望这会有所帮助,因为我不是一个提升精神专家。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.