gpt4 book ai didi

c++ - 从 boost::spirit 解析器中检索 AST

转载 作者:可可西里 更新时间:2023-11-01 17:52:24 26 4
gpt4 key购买 nike

在我阅读 tutorials 之后在 boost::spirit ,我非常喜欢它,因为解析器组合器语法。制作解析器非常简单。

不幸的是,教程在从解析器中获取复杂数据结构的问题上并没有那么准确。我正在尝试前往 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 规则中获取信息的方式有关,但我不确定。

有人能帮忙吗?

最佳答案

您正在尝试使用 Boost Phoenix 占位符调用 ast::binary_op 的构造函数。它们混合不好。您需要使用 lazy callast::binary_op 构造函数。这是在 Phoenix 中使用 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(文字),因此没有属性。

我还注意到 varnamenumber 规则中缺少一对括号:

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

灵气增幅很厉害,但也很难调试。当我开始使用它时,我发现了这些Boost Spirit Applications非常有用。

我不是 Boost Spirit 专家,希望这会有所帮助。

关于c++ - 从 boost::spirit 解析器中检索 AST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8460817/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com