C++-struct mit spirit parsen
-
Hiho,
ich muss verschiedene DLLs zur Laufzeit ansprechen und daher Headerdateien auf structs parsen und die Struktur ermitteln. Die structs sind relativ einfach gehalten. Enthalten nur Variablen, wobei diese aber auch wieder structs sein können.
Nun wollte ich das ganze mit spirit V2 machen, bin aber mit Grammatiken und der Lexer-Sache noch nicht wirklich vertraut. Ich wollte die structs mit eine Lexer aus dem string der Headerdatei herauslösen und dann das Token an einen qi-Parser übergeben als prinzipielle Vorgehensweise
Folgenden Code habe ich schon, welcher allerdings noch Compile-Fehler wirft:
Lexer:
template <typename Lexer> struct struct_tokens : lex::lexer<Lexer> { struct_tokens() : structContent("struct" //Schlüsselwort "[ \\n\\t]+" //Leerzeichen, usw. "[a-zA-z0-9_]+" //Name der struct "[ \\n\\t]*" //Leerzeichen, usw. "\\{" //öffnende Klammer "[^\\}]*" //alle Zeichen in der struct "\\}" //schließende Klammer "[ \\n\\t]*" //Leerzeichen, usw. ";" //abschließende Semikolon ) { using boost::spirit::lex::_start; using boost::spirit::lex::_end; using boost::phoenix::ref; this->self.add (structContent) ; } lex::token_def<> structContent; };Die regex für die struct entspricht nicht 100% den C++-Regeln, die Headerdateien sind aber selbst auch autogeneriert, von daher sollte die Regel für meinen Fall ausreichen.
Grammatik:
// template <typename Iterator> struct struct_skip_grammar : qi::grammar<Iterator> { template <typename TokenDef> struct_skip_grammar(TokenDef const& tok) : struct_skip_grammar::base_type(start) { using qi::lit; start = *(lit('\n') | lit('\t') | lit(' ')); } qi::rule<Iterator> start; }; // template <typename Iterator> struct struct_grammar : qi::grammar<Iterator> { template <typename TokenDef> struct_grammar(TokenDef const& tok) : struct_grammar::base_type(start) { using phoenix::ref; using phoenix::size; using qi::_1; using qi::lit; using ascii::char_; start = lit("struct") >> +char_("a-zA-z0-9_")[ref(name) += _1] ; } std::string name; qi::rule<Iterator> start; //qi::rule<Iterator,struct_skip_grammar<Iterator> > start; };int _tmain(int argc, _TCHAR* argv[]) { typedef lex::lexertl::token< char const*, boost::mpl::vector<std::string> > token_type; typedef lex::lexertl::lexer<token_type> lexer_type; typedef struct_tokens<lexer_type>::iterator_type iterator_type; // now we use the types defined above to create the lexer and grammar // object instances needed to invoke the parsing process struct_tokens<lexer_type> word_count; // Our lexer struct_grammar<iterator_type> g (word_count); // Our parser // read in the file int memory std::string str = "struct \n{\nint name;\n};"; char const* first = str.c_str(); char const* last = &first[str.size()]; bool r = lex::tokenize_and_parse(first, last, word_count, g);Die Regel ist noch nicht vollständig. Ich wollte zuerst testweise den Namen der struct rauslösen, allerdings wirft der Code schon folgenden Fehler:
d:\quellcode\boost\boost_1_43_0\boost\range\iterator.hpp(63) : error C2039: 'type': Ist kein Element von 'boost::mpl::eval_if_c<C,F1,F2>'
1> with
1> [
1> C=true,
1> F1=boost::range_const_iterator<char>,
1> F2=boost::range_mutable_iterator<const char>
1> ]
1> d:\quellcode\boost\boost_1_43_0\boost\range\iterator_range_core.hpp(55): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "boost::range_iterator<C>".
1> with
1> [
1> C=const char
1> ]
1> d:\quellcode\boost\boost_1_43_0\boost\range\iterator_range_core.hpp(167): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "IteratorT boost::iterator_range_detail::iterator_range_impl<IteratorT>::adl_begin<const Range>(ForwardRange &)".
1> with
1> [
1> IteratorT=const char *,
1> Range=char,
1> ForwardRange=char
1> ]
1> d:\quellcode\boost\boost_1_43_0\boost\variant\variant.hpp(1297): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "boost::iterator_range<IteratorT>::iterator_range<const T>(const Range &)".
1> with
1> [
1> IteratorT=const char *,
1> T=char,
1> Range=char
1> ]
1> d:\quellcode\boost\boost_1_43_0\boost\variant\variant.hpp(1366): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "void boost::variant<T0_>::convert_construct<const T>(T &,int,boost::mpl::false_)".usw. geht noch viel weiter
Inkludiert habe ich alle Headerdateien. Der += Operator für den std::string ist auch definiert (ein Minimalbsp wo ich einfach nur char's in einen std:string per += ranhänge, funktioniert auch). Was ist an meinem Code falsch?
Und falls jemand Vorschläge hat, wie man die prinzipielle Herangehensweise verbessern kann: ich habe ein offenes Ohr^^
Bei der Fassugn wird ja noch einiges Doppelt bearbeitet. Der lexer testet den Aufbau, der Parser testet dann wieder einige Sachen doppelt usw.MfG Pellaeon
-
[a-zA-z]ist keine gültige Range.
-
stimmt das war ein Tippfehler beim Rumtesten. Löst aber leider mein Problem nicht. Kompiliert trotzdem nicht, auch wenn ich die Range vollständig wegnehme.
edit:. wenn ich die Regel mit double aufbaue, dann kompiliert es. Warum klappt das mit dem char_ nicht oO
-
*push*