Fehlerhafte Verwendung von spirit::phoenix closures.



  • Ich habe vor ein paar XML Parser und allgemeine Hilfsklassen für das Arbeiten mit XML Dokumenten zu schreiben. Folgender Code ist nach ein paar Stunden herumspielen mit Spirit und Phoenix enstanden.
    Die Struktur chset_it ist ein chset Wrapper der als Ergebnis den Iterator statt dem Zeichen an die Semantische Aktion weitergibt ( so machen es fast alle parser von spirit ).
    Die Behandlung von char und wchar_t erscheint mir noch etwas unsauber .. daran tüftle ich noch rum.
    Das zentrale Problem ist die Closure der Regel R in tag::parse. Ich verwende sie um die Position des ersten und letzten Zeichen des Namens zu kopieren, und um sie dem Charaktersequenz Parser (ja sollte eigentlich Stringparser sein) am Ende des Tags zu übergeben. Damit könnte man die rekursiven Regeln von spirit verwenden um die XML Syntax in einen Ausdruck zu packen.
    Leider bekomme ich hier nur einen Speicherzugriffsfehler in den closures.

    #include <iostream>
    #include <boost/spirit.hpp>
    #include <boost/spirit/utility/chset_operators.hpp>
    using namespace boost::spirit;
    using namespace std;
    
    template <typename CharT=char>
    struct xml_parser
    {
    	struct chset_it : public parser<chset_it>
    	{
    		const chset<CharT>  tester;
    		typedef chset_it self_t;
    
    		chset_it ( const chset<CharT> & t) : tester(t) {}
    
    		template <typename ScannerT>
            struct result {
                typedef typename match_result<
                    ScannerT,
                    typename ScannerT::iterator_t
                >::type type;
            };
    
    		template <typename ScannerT>
    		typename parser_result<self_t, ScannerT>::type
    		parse(ScannerT const& scan) const
    		{
                      typedef typename ScannerT::iterator_t iterator_t;
    			if(!scan.at_end())
    			{
    				if ( tester.test(*scan) )
    				{
    					iterator_t save(scan.first);
    					++scan;
    
    					return scan.create_match(1, save, save, scan.first);
    				}
    			}
    			return scan.no_match();
    		}
    	};
    
    	struct char_sets
    	{
    		chset<CharT> NameStartChar;
    		chset<CharT> NameChar; 
    		chset<CharT> Char;
    
    		char_sets() 
    			: NameStartChar(":A-Z_a-z"), NameChar("-.0-9"), Char(" -~")
    		{
    			NameChar |= NameStartChar | chlit<CharT>(0xB7);
    			Char = Char | chlit<CharT>(0x09) | chlit<CharT>(0x0A) | 
    				chlit<CharT>(0x0D) | chlit<CharT>(0x85) | 
    				range<CharT>(0xA0, 0xFF);
    		}
    	};
    
    	static char_sets global_char_set;
    
    	struct tag : public parser<tag>
    	{	
    		typedef tag self_t;
    
    		template <class IteratorT>
    		struct tagname_closure : public closure< tagname_closure<IteratorT>, IteratorT, IteratorT>
    		{
    			typename closure<tagname_closure<IteratorT>,IteratorT,IteratorT>::member1 begin;
    			typename closure<tagname_closure<IteratorT>,IteratorT,IteratorT>::member2 end;
    		};
    
    		template <typename ScannerT>
    		typename parser_result<self_t, ScannerT>::type
    		parse(ScannerT const& scan) const
    		{
    			if(!scan.at_end())
    			{
    				typedef typename ScannerT::iterator_t iterator_t;
    				iterator_t saved = scan.first;
    				typedef typename tagname_closure<iterator_t>::context_t clos_context_t;
    				chset_it NameStartChar_p(global_char_set.NameStartChar);
    				chset_it NameChar_p(global_char_set.NameChar);
    
    				rule<ScannerT,  clos_context_t> R =
    					chlit<CharT>('<')
    					>>  NameStartChar_p[R.begin = phoenix::arg1] 
    					>> 	+( NameChar_p[R.end = phoenix::arg1] )
    					 >> (
    						  ( chlit<CharT>('>') 
    							>> chlit<CharT>('<') 
    							>> chlit<CharT>('/') 
    							>> f_chseq_p( R.begin, R.end)
    							>> chlit<CharT>('>') 
    						  ) 
    						  | 
    						  ( chlit<CharT>('/') 
    							>> chlit<CharT>('>')
    						  )
    						);
    
    				if ( R.parse(scan) )
    				{
    					return scan.create_match(2, nil_t(), saved, scan.first);
    				}
    			}
    			return scan.no_match();
    		}
    
    	};
    
    	struct parser : public grammar<parser>
    	{
    		template <class ScannerT>
    		struct definition 
    		{
    			definition(const parser &self)
    			{
    				document = *xmltag_p;
    			}
    			tag xmltag_p;
    			rule<ScannerT> document;
    
    			rule<ScannerT> const &	start() const { return document;}
    		};
    	};
    };
    template <class CharT>
    typename xml_parser<CharT>::char_sets xml_parser<CharT>::global_char_set;
    
    xml_parser<wchar_t>::char_sets::char_sets() : NameStartChar(L":A-Z_a-z"), NameChar(L"-.0-9"), Char(L" -~")
    {
    	NameStartChar = NameStartChar | range<wchar_t>(0x00C0, 0x02FF) |
    		range<wchar_t>(0x0370, 0x037D) | range<wchar_t>(0x037F, 0x1FFF) |
    		range<wchar_t>(0x200C, 0x200D) | range<wchar_t>(0x2070, 0x218F) |
    		range<wchar_t>(0x2C00, 0x2FEF) | range<wchar_t>(0x3001, 0xD7FF) |
    		range<wchar_t>(0xF900, 0xEFFFF);
    
    	NameChar |= NameStartChar | chlit<wchar_t>(0xB7) | 
    		range<wchar_t>(0x0300, 0x036F) | range<wchar_t>(0x203F, 0x2040); 
    
    	Char = Char | chlit<wchar_t>(0x09) | chlit<wchar_t>(0x0A) | 
    		chlit<wchar_t>(0x0D) | chlit<wchar_t>(0x85) | 
    		range<wchar_t>(0xA0, 0xFF);
    };
    
    int main ()
    {
    	xml_parser<char>::parser xml;
    	char str[] = " <asd /> ";
    	parse_info<> info = parse(str, xml, space_p);
    	if(info.full)
    		cout << "No error " << endl;
    	else 
    		cout << " Error : " << info.stop << endl;
    
    	xml_parser<wchar_t>::parser xml2;
    	wchar_t str2[] = L" <asd > </asd>";
    	parse_info<> info2 = parse(str, xml2, space_p);
    
    	if(info2.full)
    		cout << "No error " << endl;
    	else 
    		cout << " Error : " << info2.stop << endl;
    
    }
    

    Ich nehme an dass ich wohl mal wieder einen Weg gefunden habe Closures falsch zu verwenden ..

    EDIT1: Formatierung


Anmelden zum Antworten