Неоднозначный вариант и бодрость духа x3

Попытка настроить пример boost Spirit x3 calc для анализа функций, которые могут принимать функции в качестве аргументов. Однако это не компилируется.

namespace client{ namespace ast{
struct ts;
struct fnc;
typedef boost::variant<
ts,
boost::recursive_wrapper<fnc>
> node;
struct ts{
unsigned int id;
};
struct fnc{
std::vector<char> id;
std::vector<node> args;
};
}}
BOOST_FUSION_ADAPT_STRUCT(
client::ast::ts,
(unsigned int, id)
)
BOOST_FUSION_ADAPT_STRUCT(
client::ast::fnc,
(std::vector<char>, id)
(std::vector<client::ast::node>, args)
)
namespace client{
namespace x3 = boost::spirit::x3;
namespace calc_grammar{
using x3::uint_;
using x3::alpha;
using x3::alnum;
using x3::lit;
using x3::char_;
x3::rule<class funct, ast::fnc> const funct("function");
x3::rule<class ts, ast::ts> const ts("timeseries");
x3::rule<class funct_name, std::vector<char>> const funct_name("function_name");
auto const funct_def = funct_name >> lit('(') >> -((ts|funct)%lit(',')) >> lit(')');
auto const ts_def = lit('#') >> uint_ >> lit('#');
auto const funct_name_def = lit('@') >> alpha >> *(alnum|char_('_'));
auto const calc = x3::grammar(
"calc",
funct = funct_def,
ts = ts_def,
funct_name = funct_name_def
);
}
using calc_grammar::calc;
}

ошибка C2665: ‘boost :: detail :: option :: make_initializer_node :: apply :: initializer_node :: initialize’: ни одна из 5 перегрузок не может преобразовать все типы аргументов

Там также примечание для пользователя в варианте .hpp

// NOTE TO USER :
// Compile error here indicates that the given type is not
// unambiguously convertible to one of the variant's types
// (or that no conversion exists).

И все же я не мудрее …

10

Решение

Я заметил этот старый вопрос. Тем временем X3 немного эволюционировал, и я все равно ответил бы сейчас.

Я подозревал, что основная проблема могла быть связана с (отсутствующими) (неявными) конструкторами в элементах варианта.

Во всяком случае, вот живая демонстрация с более легкой грамматикой:

namespace grammar_def {
using namespace x3;

rule<class funct, ast::fnc> const funct("function");

auto const ts        = lexeme [ '#' >> uint_ >> '#' ];
auto const fname     = lexeme [ '@' >> raw [ alpha >> *(alnum | '_') ] ];
auto const expr      = ts|funct;

auto const funct_def = fname >> '(' >> -expr % ',' >> ')';

BOOST_SPIRIT_DEFINE(funct)
}

Я также добавил несколько помощников потокового вывода. Обратите внимание, как я изменил id введите в std::string для простоты (трудно / невозможно перегружать operator<< за vector<char> без вторжения namespace std):

namespace client { namespace ast {
static std::ostream& operator<<(std::ostream& os, ts const& v) {
using namespace boost::fusion;
return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
}

static std::ostream& operator<<(std::ostream& os, fnc const& v) {
using namespace boost::fusion;
return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
}
template<typename T>
static std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) {
os << "("; for (auto& el : v) os << (&el==&v[0]?"":", ") << el; return os << ")";
}
} }

демонстрация

У этого есть больше (дополнительный) слесарное дело, чтобы учесть более богатую информацию отладки:

Жить на Колиру

//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3.hpp>

namespace client { namespace ast {
struct ts;
struct fnc;

//using string = std::vector<char>;
using string = std::string; // for easier printing/debugging

struct ts {
unsigned int id;
ts(unsigned id=0):id(id) {}
};

typedef boost::variant<ts, boost::recursive_wrapper<fnc> > node;

struct fnc {
string id;
std::vector<node> args;
};
} }

BOOST_FUSION_ADAPT_STRUCT(client::ast::ts, id)
BOOST_FUSION_ADAPT_STRUCT(client::ast::fnc, id, args)

//namespace std { static ostream& operator<<(ostream&os, vector<char> const& v) { return os.write(&v[0], v.size()); } }

namespace client { namespace ast {
static std::ostream& operator<<(std::ostream& os, ts const& v) {
using namespace boost::fusion;
return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
}

static std::ostream& operator<<(std::ostream& os, fnc const& v) {
using namespace boost::fusion;
return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
}
template<typename T>
static std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) {
os << "("; for (auto& el : v) os << (&el==&v[0]?"":", ") << el; return os << ")";
}
} }

namespace client {
namespace x3 = boost::spirit::x3;
namespace grammar_def {
using namespace x3;

x3::rule<class funct, ast::fnc> const funct("function");

auto const ts     // = x3::rule<class ts, ast::ts> {"timeseries"}
= lexeme [ '#' >> uint_ >> '#' ];
auto const fname  // = x3::rule<class fname, ast::string> {"function_name"}
= lexeme [ '@' >> raw [ alpha >> *(alnum | '_') ] ];
auto const expr   // = rule<struct expr_, ast::node > {"expr"}
= ts|funct;

auto const funct_def = fname >> '(' >> -expr % ',' >> ')';

BOOST_SPIRIT_DEFINE(funct)
}

auto const& grammar = x3::skip(x3::space) [grammar_def::funct];
}

#include <iostream>

int main() {
std::string const s {
"@pow( #1#, \n""     @trunc(\n""           @pi ()\n""   ) )"};
std::cout << "Parsing '" << s << "'\n";

auto f = s.begin();
client::ast::fnc parsed;

if (parse(f, s.end(), client::grammar, parsed)) {
std::cout << "Parse succeeded: " << parsed << "\n";
} else {
std::cout << "Parse failed\n";
}

if (f != s.end())
std::cout << "Remaining unparsed input: '" << std::string(f, s.end()) << "'\n";
}

Печать:

Parsing '@pow( #1#,
@trunc(
@pi ()
) )'
Parse succeeded: pow(1, trunc(pi()))
6

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector