From: stephan b. <sg...@us...> - 2004-12-28 04:24:27
|
Update of /cvsroot/pclasses/pclasses2/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16737/test Modified Files: s11nTest.cpp Log Message: Switched back to expat serializers, because it's the only one working at the moment. Index: s11nTest.cpp =================================================================== RCS file: /cvsroot/pclasses/pclasses2/test/s11nTest.cpp,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- s11nTest.cpp 26 Dec 2004 14:44:46 -0000 1.5 +++ s11nTest.cpp 28 Dec 2004 04:24:17 -0000 1.6 @@ -1,10 +1,12 @@ #include <pclasses/s11n/s11n_debuggering_macros.h> #include <pclasses/s11n/SIO.h> +#include <pclasses/s11n/io/data_node_format.h> #include <pclasses/s11n/pods_streamable.h> #include <pclasses/s11n/list.h> #include <pclasses/s11n/map.h> #include <pclasses/Util/LexT.h> +#include <pclasses/Util/StringTool.h> #include <memory> // auto_ptr #include <cassert> #include <list> @@ -22,7 +24,7 @@ // me to do :: on the map here: typedef std::map<std::string,::P::Util::LexT> TestMapType; -#define USE_FAT_PROXIES 1 +#define USE_FAT_PROXIES 0 #if ! USE_FAT_PROXIES // install a custom proxy, which doesn't produce as fat // output as the default one for maps: @@ -35,14 +37,18 @@ # define PS11N_TYPE_NAME "TestListType" # define PS11N_SERIALIZE_FUNCTOR ::P::s11n::list::streamable_list_serializable_proxy # include <pclasses/s11n/reg_serializable_traits.h> +# define PS11N_TYPE TestListType2 +# define PS11N_TYPE_NAME "TestListType2" +# define PS11N_SERIALIZE_FUNCTOR ::P::s11n::list::streamable_list_serializable_proxy +# include <pclasses/s11n/reg_serializable_traits.h> #endif // ! USE_FAT_PROXIES #define SERIALIZE(Node,SType,SObj) serialize< SType >( Node, SObj ) #define DESERIALIZE(Node,SType) deserialize< SType >( Node ) +// #define SERIALIZER_CLASS_NAME "parens" #define SERIALIZER_CLASS_NAME "expat" -// #define SERIALIZER_CLASS_NAME "expat" bool test_load( const std::string & fn ) { @@ -61,6 +67,266 @@ return false; } + +struct rd_parse_error : public std::runtime_error +{ + rd_parse_error( const std::string & what ) : std::runtime_error(what) + {} +}; + +/** + rd_parser is an experimental recursive-depth parser intended + to aid in the parsing of s11n-related grammars. + + My first RD parsing code... +*/ +template <typename NodeType> +class rd_parser : public ::P::s11n::io::data_node_tree_builder<NodeType> +{ // ^^^ should probably use containment, instead of subclassing, + // but i'm way too tired to write the extra API wrappers right now... +public: + typedef NodeType node_type; + typedef rd_parser<NodeType> this_type; + + typedef int state_type; + /** + Handler func: + + istream = input source + + this_type = object to update as source is parsed + + state_type = the state number which triggered the call to this + function. This is to allow one function to handle multiple + states. + */ + typedef state_type (*rd_parse_function)( std::istream &, this_type &, state_type state ); + typedef std::map<state_type, rd_parse_function > handler_map; + + rd_parser() throw() : m_is(0) + { + } + + + explicit rd_parser( std::istream & is ) throw() : m_is(&is) + { + } + + virtual ~rd_parser() throw() + { + } + + /** + Maps the given state to the given handler function. + */ + void mapHandler( state_type state, rd_parse_function f ) throw() + { + this->handlers()[state] = f; + } + + /** + Returns the handler for the given state, or 0 if none has + been mapped. + */ + rd_parse_function handler( state_type state ) const throw() + { + typename handler_map::const_iterator it = this->handlers().find( st ), + et = this->handlers().end(); + return (et == it) ? 0 : (*it).second; + } + + /** + Sets this object's input stream and calls the protected + parse_impl() function. + */ + state_type parse( std::istream & is, state_type startState ) throw(rd_parse_error) + { + this->m_is = &is; + return this->parse_impl( this->m_is, startState ); + } + + /** + Sets this object's input stream and calls the protected + parse_impl() function. + */ + state_type parse( state_type startState ) throw(rd_parse_error) + { + return this->parse_impl( startState ); + } + + std::istream & istream() throw(rd_parse_error) + { + if( ! this->m_is ) + { + throw rd_parse_error( "istream(): No input string has been set!" ); + } + return *this->m_is; + } + + void istream( std::istream & is ) + { + this->m_is = &is; + } + +protected: + + /** + Subclasses may override this to kick off the parsing process. + The default implementation loops through mapped handlers until: + + a) not handler is found for a given state, in which case it throws + an rd_parse_error. + + b) a handler returns <= 0, in which case it returns that + number. + + Return values from handlers should be: + + >0 == next state to go to. + + 0 == parsing completed successfuly. + + <0 == error. + + Interpretation of the numbers is client-dependent. + + If this object has no associated input stream, an + rd_parse_error is thrown. + */ + virtual state_type parse_impl( state_type startState ) throw(rd_parse_error) + { + std::istream & is = this->istream(); + state_type st = startState; + state_type ret = 0; + typename handler_map::iterator it = this->handlers().find( st ), + et = this->handlers().end(); + do + { + if( et == it ) + { + P::Util::LexT lex((state_type)st); + throw rd_parse_error(std::string("Unmapped state: ")+lex.str()); + } + ret = ((*it).second)( is, *this, st ); + st = ret; + if( 0 >= ret ) break; + it = this->handlers().find( ret ); + } + while( 1 ); + return ret; + } + + + handler_map & handlers() throw() + { + return this->m_map; + } + const handler_map & handlers() const throw() + { + return this->m_map; + } + + +private: + std::istream & istr() { return *(this->m_is); } + std::istream * m_is; + handler_map m_map; +}; + +std::istream & read_property( std::istream & in, std::string & key, std::string & val ) +{ + unsigned char c; + bool escaped = false; + std::string bK; + std::string bV; + enum State { + InitialState = -1, ReadName = 0, ReadSep = 1, ReadVal = 2 + }; + State state = InitialState; // 0 == read name, 1 == find seperator, 2 == read property + while( in.good() ) + { + c = in.get(); + if( 0 == c ) break; + if( ! in.good() ) break; + if( !escaped && ('\n' == c) ) + { + continue; + } + switch( state ) + { + case InitialState: + if( std::isspace( c ) ) + { + continue; + } + state = ReadName; + bK += c; + continue; + case ReadName: + if( std::isspace( c ) ) + { + state = ReadSep; + continue; + } + bK += c; + continue; + case ReadSep: + if( std::isspace( c ) ) + { + continue; + } + bV += c; + state = ReadVal; + continue; + case ReadVal: + if( (!escaped) && ('\\' == c) ) + { // next char will be considered escaped + escaped = true; + bV += c; + continue; + } + if ( (!escaped) && (')' == c) ) + { + // found a non-escaped paren to close us. + break; + } + escaped = false; + bV += c; + continue; + default: + in.setstate(std::ios::failbit); + break; + } + break; + } + key = bK; + val = bV; + + return in; +} + +int parens_parser() +{ + typedef std::auto_ptr<SerializerInterface> SAP; + std::string serclass = "parens"; + SAP ser = SAP( ::P::Plugin::pluginManager<SerializerInterface>().create( serclass ) ); + assert( ser.get() && "Could not load serializer :(" ); + CERR << "Loaded serializer '"<<serclass<<"'. :)\n"; + + std::string prop = "key.subkey value (part of the property) value \\value\\ final_value\nline 2.\n... line 3."; + CERR << "Pre-translated = ["<<prop<<"]\n"; + ::P::StringTool::translateEntities( prop, ser->entity_translations() ); + CERR << "Translated = ["<<prop<<"]\n"; + std::istringstream pstream(prop); + std::string pkey = "", pval = ""; + read_property( pstream, pkey, pval ); + ::P::StringTool::translateEntities( pval, ser->entity_translations(), true ); + CERR << "Parsed out: key=["<<pkey<<"], val=["<<pval<<"]\n"; + + + return 0; +} + /// i wish i could make this a P::App... int main( int argc, char ** argv ) { @@ -68,6 +334,11 @@ CERR << "P::s11n tests...\n"; + if( 0 ) + { + return parens_parser(); + } + if( 2 == argc ) { return test_load( argv[1] ) ? 0 : 1; |