анализатор наддува lex-> qi: Получение «недокументированного» механизм on_success для работы

редактировать : Я вырвал лексер, так как он не интегрируется с Ци и просто запутывает грамматику (см. Вот).


on_success не очень хорошо задокументировано, и я пытаюсь подключить его к парсеру. Примеры, касающиеся on_success разобраться с парсерами, только построенными на qi т.е. нет lex,

Вот как я пытаюсь представить конструкцию:

using namespace qi::labels;
qi::on_success(event_entry_,std::cout << _val << _1);

Но это не скомпилируется. Я боюсь проблемы быть lex, Может ли кто-нибудь сказать мне, что я делаю неправильно, и, во-вторых, сказать мне, что все заполнители доступны, там напечатайте и что они представляют (так как они не задокументированы).

Полный файл выглядит следующим образом:

#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/home/phoenix/bind/bind_member_variable.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/none.hpp>
#include <boost/cstdint.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <exception>
#include <vector>

namespace lex = boost::spirit::lex;
namespace px = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;template <typename Lexer>
struct tokens : lex::lexer<Lexer>
{
tokens()
: left_curly("\"{\""),
right_curly("\"}\""),
left_paren("\"(\""),
right_paren("\")\""),
colon(":"),
scolon(";"),
namespace_("(?i:namespace)"),
event("(?i:event)"),
optional("(?i:optional)"),
required("(?i:required)"),
repeated("(?i:repeated)"),
t_int_4("(?i:int4)"),
t_int_8("(?i:int8)"),
t_string("(?i:string)"),
ordinal("\\d+"),
identifier("\\w+")

{
using boost::spirit::lex::_val;

this->self
=
left_curly    [ std::cout << px::val("lpar") << std::endl]
| right_curly   [ std::cout << px::val("rpar") << std::endl]
| left_paren
| right_paren
| colon               [ std::cout << px::val("colon") << std::endl]
| scolon
| namespace_          [ std::cout << px::val("kw namesapce") << std::endl]
| event               [ std::cout << px::val("kw event") << std::endl]
| optional            [ std::cout << px::val("optional ")  << "-->" << _val << "<--" << std::endl]
| required            [ std::cout << px::val("required") << std::endl]
| repeated
| t_int_4
| t_int_8
| t_string
| ordinal             [ std::cout << px::val("val ordinal (") << _val << ")" << std::endl]
| identifier          [std::cout << px::val("val identifier(") << _val << ")" << std::endl];this->self("WS") =   lex::token_def<>("[ \\t\\n]+");
}lex::token_def<lex::omit> left_curly, right_curly, colon, scolon,repeated, left_paren, right_paren;
lex::token_def<lex::omit> namespace_, event, optional, required,t_int_4, t_int_8, t_string;
lex::token_def<boost::uint32_t> ordinal;
lex::token_def<> identifier;
};

enum event_entry_qualifier
{
ENTRY_OPTIONAL,
ENTRY_REQUIRED,
ENTRY_REPEATED
};

enum entry_type
{
RBL_INT4,
RBL_INT8,
RBL_STRING,
RBL_EVENT
};

struct oid
{
boost::uint32_t   ordinal;
std::string       name;
};

BOOST_FUSION_ADAPT_STRUCT
(
oid,
(boost::uint32_t, ordinal)
(std::string, name)
)

struct type_descriptor
{
entry_type  type_id;
std::string referenced_event;
};

BOOST_FUSION_ADAPT_STRUCT
(
type_descriptor,
(entry_type, type_id)
(std::string, referenced_event)
)

struct event_entry
{
event_entry_qualifier  qualifier;
oid                   identifier;
type_descriptor       descriptor;
};

BOOST_FUSION_ADAPT_STRUCT
(
event_entry,
(event_entry_qualifier, qualifier)
(oid, identifier)
(type_descriptor, descriptor)
)

struct event_descriptor
{
oid                       identifier;
std::vector<event_entry>  event_entries;
};

BOOST_FUSION_ADAPT_STRUCT
(
event_descriptor,
(oid, identifier)
(std::vector<event_entry>, event_entries)
)

template <typename Iterator, typename Lexer>
struct grammar : qi::grammar<Iterator,event_descriptor(), qi::in_state_skipper<Lexer> >
{
template <typename TokenDef>
grammar(TokenDef const& tok)
: grammar::base_type(event_descriptor_)
{
using qi::_val;
//start = event;
event_descriptor_ = tok.event >> oid_ >> tok.left_curly >> *(event_entry_) >> tok.right_curly;

event_entry_ = event_qualifier >> oid_ >> type_descriptor_ >> tok.scolon;

event_qualifier = tok.optional [ _val = ENTRY_OPTIONAL]
| tok.required [ _val = ENTRY_REQUIRED]
| tok.repeated [ _val = ENTRY_REPEATED];

oid_  = tok.ordinal
>> tok.colon
>> tok.identifier;

type_descriptor_
= (( atomic_type >> qi::attr(""))
| ( event_type >> tok.left_paren >> tok.identifier >> tok.right_paren));

atomic_type = tok.t_int_4         [ _val = RBL_INT4]
| tok.t_int_8             [ _val = RBL_INT8]
| tok.t_string            [ _val = RBL_STRING];

event_type = tok.event            [_val = RBL_EVENT];

using namespace qi::labels;
qi::on_success(event_entry_,std::cout << _val << _1);
}

qi::rule<Iterator> start;
qi::rule<Iterator, event_descriptor(), qi::in_state_skipper<Lexer> > event_descriptor_;
qi::rule<Iterator, event_entry(), qi::in_state_skipper<Lexer> > event_entry_;
qi::rule<Iterator, event_entry_qualifier()> event_qualifier;
qi::rule<Iterator, entry_type()> atomic_type;
qi::rule<Iterator, entry_type()> event_type;
qi::rule<Iterator, type_descriptor(),qi::in_state_skipper<Lexer> > type_descriptor_;
qi::rule<Iterator, oid()> oid_;};

std::string test = " EVENT 1:sihan { OPTIONAL 123:hassan int4; OPTIONAL 123:hassan int4; } ";

int main()
{
typedef lex::lexertl::token<std::string::iterator, boost::mpl::vector<boost::uint32_t, std::string> > token_type;
typedef lex::lexertl::actor_lexer<token_type> lexer_type;
typedef tokens<lexer_type>::iterator_type iterator_type;

tokens<lexer_type> token_lexer;
grammar<iterator_type,tokens<lexer_type>::lexer_def> grammar(token_lexer);

std::string::iterator it = test.begin();
iterator_type first = token_lexer.begin(it, test.end());
iterator_type last = token_lexer.end();

bool r;

r = qi::phrase_parse(first, last, grammar, qi::in_state("WS")[token_lexer.self]);

if(r)
;
else
{
std::cout << "parsing failed" << std::endl;
}
}

5

Решение

Глядя на заголовочные файлы, я думаю, что значение заполнителей:

_1 = Iterator position when the rule was tried.
_2 = Iterator to the end of the input.
_3 = Iterator position right after the rule has been successfully matched.

(Так как я не уверен, что строки выше понятны, вот небольшой пример с вашими данными)

                                 rule being tried
_________________________________
´                                 `
[EVENT][1][:][sihan][{][OPTIONAL][123][:][hassan][int4][;][OPTIONAL][321][:][hassan2][int4][;][}]
_1                                 _3                                 _2

Как GManNickG упоминает в комментариях, это итераторы лексера, и вы не можете легко получить доступ к исходной строке с ними. conjure2 example сочетает в себе использование лексера и on_error/on_success, Для этого он использует особый вид токена, position_token, Этот токен всегда имеет доступ к паре итераторов исходной строки, связанной с ним (обычный токен теряет эту информацию при использовании lex::omit). position_token имеет несколько интересных методов. matched() возвращает iterator_range<OriginalIterator>, а также begin() а также end() вернуть соответствующие итераторы.

В приведенном ниже коде я решил создать phoenix::function это берет два итератора лексера (вызванный с _1 и _3) и возвращает строку, которая покрывает расстояние между ними (используя std::string(begin_iter->begin(), end_iter->begin())).

Одна проблема, которую я обнаружил, заключалась в том, что тот факт, что пробел был в другом состоянии, приводил к тому, что итераторы position_token вернулись были недействительными. То, что я сделал, чтобы решить эту проблему, поместил все в то же состояние, а затем просто использовать lex::_pass = lex::pass_flags::pass_ignore с пробелами.

Последняя (незначительная) проблема заключается в том, что если вы хотите использовать std::cout << _val вам нужно определить operator<< для типов, которые вас интересуют.

PS: я всегда использую BOOST_SPIRIT_USE_PHOENIX_V3, и это требует, чтобы каждый включенный дух / феникс происходил из boost/spirit/include/..., Если по какой-либо причине вам нужно / нужно использовать V2, вам нужно изменить функцию phoenix ::. Я также не способен использовать старый стиль для цикла, поэтому, если вы не можете использовать c ++ 11, вам придется изменить определение оператора<< для дескриптора события.


#define BOOST_SPIRIT_USE_PHOENIX_V3
// #define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_bind.hpp> //CHANGED
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/lex_lexertl_position_token.hpp> //ADDED
#include <boost/none.hpp>
#include <boost/cstdint.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <exception>
#include <vector>

namespace lex = boost::spirit::lex;
namespace px = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;template <typename Lexer>
struct tokens : lex::lexer<Lexer>
{
tokens()
: left_curly("\"{\""),
right_curly("\"}\""),
left_paren("\"(\""),
right_paren("\")\""),
colon(":"),
scolon(";"),
namespace_("(?i:namespace)"),
event("(?i:event)"),
optional("(?i:optional)"),
required("(?i:required)"),
repeated("(?i:repeated)"),
t_int_4("(?i:int4)"),
t_int_8("(?i:int8)"),
t_string("(?i:string)"),
ordinal("\\d+"),
identifier("\\w+")

{
using boost::spirit::lex::_val;

this->self
=
left_curly    //[ std::cout << px::val("lpar") << std::endl]
| right_curly   //[ std::cout << px::val("rpar") << std::endl]
| left_paren
| right_paren
| colon               //[ std::cout << px::val("colon") << std::endl]
| scolon
| namespace_         // [ std::cout << px::val("kw namesapce") << std::endl]
| event              // [ std::cout << px::val("kw event") << std::endl]
| optional            //[ std::cout << px::val("optional ")  << "-->" << _val << "<--" << std::endl]
| required            //[ std::cout << px::val("required") << std::endl]
| repeated
| t_int_4
| t_int_8
| t_string
| ordinal             //[ std::cout << px::val("val ordinal (") << _val << ")" << std::endl]
| identifier          //[std::cout << px::val("val identifier(") << _val << ")" << std::endl]
| lex::token_def<>("[ \\t\\n]+")   [lex::_pass = lex::pass_flags::pass_ignore] //CHANGED
;
}lex::token_def<lex::omit> left_curly, right_curly, left_paren, right_paren, colon, scolon;
lex::token_def<lex::omit> namespace_, event, optional, required, repeated, t_int_4, t_int_8, t_string;
lex::token_def<boost::uint32_t> ordinal;
lex::token_def<> identifier;
};

enum event_entry_qualifier
{
ENTRY_OPTIONAL,
ENTRY_REQUIRED,
ENTRY_REPEATED
};

enum entry_type
{
RBL_INT4,
RBL_INT8,
RBL_STRING,
RBL_EVENT
};

struct oid
{
boost::uint32_t   ordinal;
std::string       name;
};

BOOST_FUSION_ADAPT_STRUCT
(
oid,
(boost::uint32_t, ordinal)
(std::string, name)
)

std::ostream& operator<<(std::ostream& os, const oid& val) //ADDED
{
return os << val.ordinal << "-" << val.name;
}

struct type_descriptor
{
entry_type  type_id;
std::string referenced_event;
};

BOOST_FUSION_ADAPT_STRUCT
(
type_descriptor,
(entry_type, type_id)
(std::string, referenced_event)
)

std::ostream& operator<<(std::ostream& os, const type_descriptor& val)  //ADDED
{
return os << val.type_id << "-" << val.referenced_event;
}

struct event_entry
{
event_entry_qualifier  qualifier;
oid                   identifier;
type_descriptor       descriptor;
};BOOST_FUSION_ADAPT_STRUCT
(
event_entry,
(event_entry_qualifier, qualifier)
(oid, identifier)
(type_descriptor, descriptor)
)

std::ostream& operator<<(std::ostream& os, const event_entry& val)  //ADDED
{
return os << val.qualifier << "-" << val.identifier << "-" << val.descriptor;
}

struct event_descriptor
{
oid                       identifier;
std::vector<event_entry>  event_entries;
};BOOST_FUSION_ADAPT_STRUCT
(
event_descriptor,
(oid, identifier)
(std::vector<event_entry>, event_entries)
)

std::ostream& operator<<(std::ostream& os, const event_descriptor& val)  //ADDED
{
os << val.identifier << "[";
for(const auto& entry: val.event_entries)   //C++11
os << entry;
os << "]";
return os;
}

struct build_string_impl        //ADDED
{
template <typename Sig>
struct result;
template <typename This, typename Iter1, typename Iter2>
struct result<This(Iter1,Iter2)>
{
typedef std::string type;
};

template <typename Iter1, typename Iter2>
std::string operator()(Iter1 begin, Iter2 end) const
{
return std::string(begin->begin(),end->begin());
}
};

px::function<build_string_impl> build_string;

template <typename Iterator, typename Lexer>
struct grammar : qi::grammar<Iterator,event_descriptor() >
{
template <typename TokenDef>
grammar(TokenDef const& tok)
: grammar::base_type(event_descriptor_)
{
using qi::_val;
//start = event;
event_descriptor_ = tok.event >> oid_ >> tok.left_curly >> *(event_entry_) >> tok.right_curly;

event_entry_ = event_qualifier >> oid_ >> type_descriptor_ >> tok.scolon;

event_qualifier = tok.optional [ _val = ENTRY_OPTIONAL]
| tok.required [ _val = ENTRY_REQUIRED]
| tok.repeated [ _val = ENTRY_REPEATED];

oid_  = tok.ordinal
>> tok.colon
>> tok.identifier;

type_descriptor_
= (( atomic_type >> qi::attr(""))
| ( event_type >> tok.left_paren >> tok.identifier >> tok.right_paren));

atomic_type = tok.t_int_4         [ _val = RBL_INT4]
| tok.t_int_8             [ _val = RBL_INT8]
| tok.t_string            [ _val = RBL_STRING];

event_type = tok.event            [_val = RBL_EVENT];

using namespace qi::labels;
qi::on_success(event_entry_,std::cout << _val << " " << build_string(_1,_3) << std::endl); //CHANGED
// BOOST_SPIRIT_DEBUG_NODES( (event_descriptor_)(event_entry_)(event_qualifier)(oid_)(type_descriptor_)(atomic_type)(event_type) );

}

qi::rule<Iterator> start;
qi::rule<Iterator, event_descriptor()> event_descriptor_;
qi::rule<Iterator, event_entry()> event_entry_;
qi::rule<Iterator, event_entry_qualifier()> event_qualifier;
qi::rule<Iterator, entry_type()> atomic_type;
qi::rule<Iterator, entry_type()> event_type;
qi::rule<Iterator, type_descriptor()> type_descriptor_;
qi::rule<Iterator, oid()> oid_;};

std::string test = " EVENT 1:sihan { OPTIONAL 123:hassan int4; OPTIONAL 321:hassan2 int4; } ";

int main()
{
typedef lex::lexertl::position_token<std::string::iterator, boost::mpl::vector<boost::uint32_t, std::string> > token_type; //CHANGED
typedef lex::lexertl::actor_lexer<token_type> lexer_type;
typedef tokens<lexer_type>::iterator_type iterator_type;

tokens<lexer_type> token_lexer;
grammar<iterator_type,tokens<lexer_type>::lexer_def> grammar(token_lexer);

std::string::iterator it = test.begin();
iterator_type first = token_lexer.begin(it, test.end());
iterator_type last = token_lexer.end();

bool r;

r = qi::parse(first, last, grammar); //CHANGED

if(r)
;
else
{
std::cout << "parsing failed" << std::endl;
}
}
4

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

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

По вопросам рекламы [email protected]