boost::spirit und Unicode, 2. Spirit Rule-Frage



  • Hiho,

    ich versuche gerade spirit mit wchar_t zu nutzen, aber irgendwie will das einfach nicht funktionieren. Selbst einfachste Beispiele nicht

    bs::rule<> stringNumber =+ bs::range<wchar_t>(L'0',L'9');
    if (bs::parse(line.c_str(),stringNumber).full)
    {
    	//...
    

    line ist ein std::wstring.
    Ich benutze das VS2005 SP1. Folgende Fehlermeldung kommt:

    d:\quellcode\boost\boost_1_39_0\boost\spirit\home\classic\core\non_terminal\impl\rule.ipp(192) : error C2664: 'boost::spirit::classic::impl::abstract_parser<ScannerT,AttrT>::do_parse_virtual': Konvertierung des Parameters 1 von 'const boost::spirit::classic::scanner<IteratorT,PoliciesT>' in 'const boost::spirit::classic::scanner<> &' nicht möglich

    Hat jemand eine Ahnung, woran das liegt? Sollte doch eigentlich funktionieren,.

    MfG Pellaeon



  • bei deiner Fehlermeldung stehen bestimmt noch die eingesetzten Templateparameter mit drin. (beim VS im Output-Tab schauen, nicht in der Fehlerübersicht)

    Ich kann jetzt nach einem kurzen Blick in die Doku nur raten: rule<> benutzt den default-scanner, dessen erster template-parameter (der Iterator) ist ein char const*. Und der dürfte sich mit dem wchar beißen. Deine Fehlermeldung dürfte noch etwas enthalten was darauf hindeutet (IteratorT = char const*)



  • Hiho,

    jo ich hatte das wchar immer an der falschen Stelle versucht zu nutzen. So geht es:

    typedef bs::scanner<const wchar_t*> wscanner; 
    typedef bs::rule<wscanner> wrule;
    typedef bs::chlit<wchar_t> wchar_p;
    
    wrule vec = L'(' >> bs::int_p >> L',' >> bs::int_p >> L',' >> bs::int_p >> L')';
    wrule myRule = *vec;
    
    if (bs::parse(vectors.c_str(),myRule,bs::space_p).full)
    

    Ich hätte aber mal noch eine Frage an die Spirit-Profis. Das ist für mich Neuland, habe jetzt erst angefangen mir die Tuts anzuschauen. Ich will gern folgendes parsen: "(x1,y1,z1) (x2,y2,z2)" usw, also Vektoren. Am liebsten wäre es mir, wenn die Zahlen gleich als String rauskommen, aber erstmal als Zahl wäre auch ok. Mit dem Code drüber funktioniert das nur, wenn keine Leerzeichen dazwischen sind, obwohl ich space_p gesetzt habe. Das versteh ich nicht so recht. Laut Tut müsste er doch jetzt Leerzeichen auslasse?

    MfG Pellaeon



  • Pellaeon schrieb:

    Am liebsten wäre es mir, wenn die Zahlen gleich als String rauskommen, aber erstmal als Zahl wäre auch ok.

    Ich bin mir nicht 100%i sicher, meine aber folgendes gelesen zu haben:
    Die Zahlenparser haben für ihre semantic actions zwei verschiedene Schnittstellen: eine gibt direkt die geparste Zahl zurück, die andere übergibt (wie alle anderen Parser auch) ein Itratorenpaar (Anfang und Ende der geparsten Sequenz). Damit kannst du den gewünschten String dann initialisieren.



  • In spirit2 ist das komplett anders gelöst, da musst du nur den richtigen Namespace angeben.



  • Hiho,

    erstmal danke für die Antworten.
    Also die Zahlen als String rausbekommen, funktioniert super mit dem push_back_a. Das einzige, was noch nicht klappt, ist das space_p als Skip Parser. Der macht irgendwie nix. Deswegen muss ich momentan noch immner per Hand in den Regel die Leerzeichen mit aufnehmen.

    @phlox81 : ist das Spirit 2 final? Weil in der Boost Doku wird man immer zur Classic-Variante gelenkt. Und da ich da die Dok und Tuts benutze, bin ich nich bei der "alten" Version.

    MfG Pellaeon



  • Pellaeon schrieb:

    ist das Spirit 2 final?

    Was verstehst du unter final? Spirit2 wird sicherlich noch weiterentwickelt.

    Weil in der Boost Doku wird man immer zur Classic-Variante gelenkt. Und da ich da die Dok und Tuts benutze, bin ich nich bei der "alten" Version.

    Phlox hat ja hier neulich schon den Link zur Spirit2 Doku geliefert.



  • Ich hoffe du hast bei der rule noch den wide_phrase_scanner_t angegeben. Der sorgt dafür, dass die rule mit dem space_p Skipper klarkommt.

    Also in etwa so:

    typedef bs::scanner<const wchar_t*, wide_phrase_scanner_t> wscanner;
    typedef bs::rule<wscanner> wrule;
    typedef bs::chlit<wchar_t> wchar_p;
    
    wrule vec = L'(' >> bs::int_p >> L',' >> bs::int_p >> L',' >> bs::int_p >> L')';
    wrule myRule = *vec;
    
    if (bs::parse(vectors.c_str(),myRule,bs::space_p).full)
    

    Ansonsten solltest du, wie im FAQ erwähnt, die rule<> nicht benutzen um Parser zu speichern. Grammatiken haben das Problem nicht, Iterator- oder Scannertyp im voraus kennen zu müssen. Außerdem kannst du in Grammatiken ganz leicht Optimierungen einbauen (z.B. subrule, subgrammar) ohne das öffentliche Interface zu verändern.



  • Hiho,

    es lag an dem wide_phrase_scanner_t. Das funktioniert, bringt aber beim Kompilieren eine hässliceh Warnung:

    warning C4584: 'boost::spirit::classic::scanner<IteratorT,PoliciesT>': Basisklasse 'boost::spirit::classic::scanner_base' ist bereits eine Basisklasse von 'boost::spirit::classic::scanner<IteratorT,PoliciesT>'
    1> with
    1> [
    1> IteratorT=const wchar_t *,
    1> PoliciesT=boost::spirit::classic::wide_phrase_scanner_t
    1> ]
    1> and
    1> [
    1> IteratorT=const wchar_t *,
    1> PoliciesT=boost::spirit::classic::scanner_policies_t
    1> ]
    1> d:\quellcode\boost\boost_1_39_0\boost\spirit\home\classic\core\scanner\scanner.hpp(205): Siehe Deklaration von 'boost::spirit::classic::scanner_base'
    1> d:\quellcode\boost\boost_1_39_0\boost\type_traits\is_base_and_derived.hpp(225): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "boost::spirit::classic::scanner<IteratorT,PoliciesT>".
    1> with
    1> [
    1> IteratorT=const wchar_t *,
    1> PoliciesT=boost::spirit::classic::wide_phrase_scanner_t
    1> ]
    1> d:\quellcode\boost\boost_1_39_0\boost\type_traits\is_base_and_derived.hpp(235): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "boost::detail::is_base_and_derived_impl<B,D>".
    1> with
    1> [
    1> B=boost::spirit::classic::parser_context_base,
    1> D=wscanner
    1> ]
    1> d:\quellcode\boost\boost_1_39_0\boost\mpl\if.hpp(63): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "boost::is_base_and_derived<Base,Derived>".
    1> with
    1> [
    1> Base=boost::spirit::classic::parser_context_base,
    1> Derived=wscanner
    1> ]
    1> d:\quellcode\boost\boost_1_39_0\boost\spirit\home\classic\core\non_terminal\impl\rule.ipp(64): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "boost::mpl::if_<T1,T2,T3>".
    1> with
    1> [
    1> T1=boost::is_base_and_derivedboost::spirit::classic::parser\_context_base,wscanner,
    1> T2=wscanner,
    1> T3=boost::spirit::classic::parser_context<>
    1> ]
    1> d:\quellcode\boost\boost_1_39_0\boost\spirit\home\classic\core\non_terminal\impl\rule.ipp(71): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "boost::spirit::classic::impl::get_param<BaseT,DefaultT,T0,T1,T2>".
    1> with
    1> [
    1> BaseT=boost::spirit::classic::parser_context_base,
    1> DefaultT=boost::spirit::classic::parser_context<>,
    1> T0=wscanner,
    1> T1=boost::spirit::classic::nil_t,
    1> T2=boost::spirit::classic::nil_t
    1> ]
    1> d:\quellcode\boost\boost_1_39_0\boost\spirit\home\classic\core\non_terminal\impl\rule.ipp(146): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "boost::spirit::classic::impl::get_context<T0,T1,T2>".
    1> with
    1> [
    1> T0=wscanner,
    1> T1=boost::spirit::classic::nil_t,
    1> T2=boost::spirit::classic::nil_t
    1> ]
    1> d:\quellcode\boost\boost_1_39_0\boost\spirit\home\classic\core\non_terminal\rule.hpp(110): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "boost::spirit::classic::impl::rule_base<DerivedT,EmbedT,T0,T1,T2>".
    1> with
    1> [
    1> DerivedT=boost::spirit::classic::rule<wscanner>,
    1> EmbedT=const boost::spirit::classic::rule<wscanner> &,
    1> T0=wscanner,
    1> T1=boost::spirit::classic::nil_t,
    1> T2=boost::spirit::classic::nil_t
    1> ]
    1> d:\quellcode\spcedit\spcedit\stddata.cpp(360): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "boost::spirit::classic::rule<T0>".
    1> with
    1> [
    1> T0=wscanner
    1> ]

    Der dazugehörige Code ist:

    typedef bs::scanner<const wchar_t*,bs::wide_phrase_scanner_t> wscanner;	
    typedef bs::rule<wscanner> wrule;
    
    std::vector<std::wstring> v;
    wrule components = bs::real_p >> bs::real_p >> bs::real_p;
    wrule vec = L'(' >> components[bs::push_back_a(v)] >> L')';	
    wrule myRule = *vec;
    
    if (bs::parse(vectors.c_str(),myRule,bs::space_p).full)
    ...
    

    Wenn ich die Grammatik wie in der Doku mache:

    struct VectorGrammar : public bs::grammar<VectorGrammar>
    {
    	template <typename ScannerT>
    	struct definition
    	{		
    		definition(VectorGrammar const& self)
    		{
    			bs::rule<ScannerT> components = bs::real_p >> bs::real_p >> bs::real_p;
    			bs::rule<ScannerT> vec = L'(' >> components[bs::push_back_a(v)] >> L')';	
    			r = +vec;
    		}
    
    		bs::rule<ScannerT>  r;            
    		bs::rule<ScannerT> const& start() const { return r; }
    
    		std::vector<CStdData::StringType> v;
    	};
    };
    
    VectorGrammar vec;    //  Our parser
    bs::parse_info<const wchar_t*> info = bs::parse(vectors.c_str(), vec,bs::space_p);
    

    kompiliert das zwar, bringt aber einen Adress-Lesefehler zur Laufzeit. Auch hier ist der String wieder ein wstring.


Anmelden zum Antworten