Dopo aver letto il tutorials su boost::spirit, mi è piaciuto molto a causa della sintassi del combinatore parser. Fare un parser è così facile.Recupero AST da boost :: parser spirito
Sfortunatamente, le esercitazioni non erano così precise sull'ottenere dal parser una struttura dati complessa. Sto cercando di arrivare allo Kaleidoscope AST.
In ogni caso, qui essere il mio codice 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
ho omesso le BOOST_FUSION_ADAPT_STRUCT
parti, ma ci sono.
E questa mia espressione 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
Il problema che ho è che sembra avere un problema con il conseguente ast::expression
. La compilazione genera più di 200 righe di errori di modello complessi. Sospetto che sia qualcosa con il modo in cui ho cercato di ottenere le informazioni dalla regola binop
, ma non ne sono sicuro.
Qualcuno può aiutare?
Grazie al fatto che 'construct <>' ha veramente tolto molti errori. Ora mi rimane solo uno: 'parser.hpp: 38: 81: errore: il valore di 'boost :: spirit :: _ 1' non è utilizzabile in un'espressione costante' e 'nota:' boost :: spirit :: _1 'non è stato dichiarato' constexpr''. Qualsiasi aiuto? – Lanbo
Ok, ho sbagliato a scrivere la tua soluzione. Grazie! – Lanbo
Quel link di Spirit Applications ha alcune ottime fonti di esempio, grazie! – rvalue