ERAV: Entity Relation Attribute Value:
|
00001 // ERAV.h (C) 2010 adolfo@di-mare.com 00002 00003 #ifndef ERAV_h 00004 #define ERAV_h // Aboid multiple inclusion 00005 00006 #include <map> // these are all the #includes used in the implementation 00007 #include <list> 00008 #include <string> 00009 00010 #include <cctype> // isalpha() && isdigit() && tolower() 00011 #include <cstdlib> // atoi() 00012 #include <cstring> // memcmp() && size_t 00013 00014 /// [E]ntity [R]elation [A]ttribute [V]alue 00015 namespace ERAV { class WORD; class WORD_tuple; class tuple; class parser; } 00016 00017 #if 0 00018 "erav2xml( L ==> XML )" "xml2erav( XML ==> L )" 00019 #endif 00020 00021 // <?xml []...[] ?> <erav> XML </erav> 00022 void erav2xml_enclose( std::string& XML ); 00023 00024 // L<tuple> ==> XML ((append)) 00025 #define NOT_const // L is NOT const: L gets reordered 00026 void erav2xml( NOT_const std::list<ERAV::tuple>& L, std::string& XML ); 00027 00028 // L<tuple> ==> XML ((append)) 00029 void erav2xml( const std::list<ERAV::WORD_tuple>& L , std::string& XML ); 00030 00031 // L<word> ==> W<word> ((append)) || L<string> ==> S<string> ((append)) 00032 void erav2xml( const std::list<ERAV::WORD_tuple>& L , ERAV::WORD& W ); 00033 00034 // W<word> ==> XML ((append)) 00035 void erav2xml( const ERAV::WORD& W , std::string& XML , bool isWORD=true ); 00036 00037 // S<string> ==> XML ((append)) 00038 inline 00039 void erav2xml( const ERAV::WORD& S , std::string& XML , const std::string& ); 00040 00041 // XML ==> [ L<tuple> && W<word> && S<string> ] ((append)) 00042 inline void xml2erav( // throws ERAV::exception on error 00043 const std::string& XML , 00044 std::list<ERAV::tuple>& L , // append to current value 00045 ERAV::WORD& W , // append to current value 00046 ERAV::WORD& S // append to current value 00047 ); 00048 00049 // [ L<tuple> && W<word> && S<string> ] ==> XML ((append)) 00050 inline void erav2xml( 00051 std::list<ERAV::tuple>& L , // reordered 00052 const ERAV::WORD& W , 00053 const ERAV::WORD& S , 00054 std::string& XML // append to current value 00055 ) { 00056 erav2xml( L , XML ); 00057 erav2xml( W , XML ); 00058 erav2xml( S , XML, std::string() ); 00059 // erav2xml_enclose( XML ); 00060 } 00061 00062 inline void erav_clear( 00063 std::list<ERAV::tuple>& L , 00064 ERAV::WORD& W , 00065 ERAV::WORD& S 00066 ); 00067 00068 namespace ERAV { 00069 // Load L from FROM skippind duplicates. 00070 void merge_into( std::list<ERAV::tuple>& L, std::list<ERAV::tuple>& FROM ); 00071 00072 class tuple { // tuples in the ERAV data base 00073 public: 00074 int ID_ENT; // NOT NULL, -- <K+++> <E> Entity 00075 struct _rel_ { // -- <R> Relation 00076 short ID; // NOT NULL, -- <+K++> 00077 short SUB; // NOT NULL, -- <++K+> 00078 char TYPE; // NOT NULL, 00079 } REL; 00080 int ATTRIB; // NOT NULL, -- <+++K> <A> Attribute 00081 struct _val_ { // NOT NULL, <V> Value 00082 #if 0 00083 union { 00084 int INT; // (int) or reference into "WORD" 00085 double FLOAT; 00086 // long TIME; // 2.1474.83.64.7 == 2^31-1 00087 long DATE; // 1492-12-31 00088 long HOUR; // 12:25:37.000 00089 }; // 21.47.48.3647 == 2^31-1 00090 #endif 00091 std::string BLOB; // binary large object 00092 } VAL; 00093 // CONSTRAINT [ERAV_KEY] UNIQUE ( ID_ENT,REL_ID,REL_SUB,ATTRIB )}; 00094 }; 00095 00096 /// (l<r)==>(-1) (l==r)==>((0)) (l>r)==>(+1). 00097 int tplcmp( const ERAV::tuple& l, const ERAV::tuple& r ); 00098 /// (l<r) ???. 00099 bool isLess( const ERAV::tuple& l, const ERAV::tuple& r ); 00100 // { return ( tplcmp(l,r)<0 ); } 00101 #define USE_isLess 00102 #undef USE_isLess 00103 00104 /// (l<r) ???. 00105 inline bool operator<( const ERAV::tuple& l, const ERAV::tuple& r ) { 00106 #ifdef USE_isLess 00107 return ( isLess(l,r) ); 00108 #else 00109 return ( tplcmp(l,r)<0 ); 00110 #endif 00111 } 00112 00113 /// (l==r) ???. 00114 inline bool operator==( const ERAV::tuple& l, const ERAV::tuple& r ) { 00115 #ifdef USE_isLess 00116 return ( !isLess(l,r) && !isLess(r,l) ); 00117 #else 00118 return ( tplcmp(l,r)==0 ); 00119 #endif 00120 } 00121 00122 const int LANG_LEN=2; // "es" "en" etc... 00123 00124 class WORD_tuple { // referenced by VAL_INT in ERAV_tuple 00125 public: 00126 int ID_WORD; 00127 std::string DESCR; 00128 char LANG[LANG_LEN]; 00129 }; 00130 00131 /// \c map<> ( WORD && STRING ). 00132 class WORD { // WORD[25] == [ ("es","Juan"),("en","John"),... ] 00133 friend void ::erav2xml( const ERAV::WORD& W , std::string& XML , bool ); 00134 private: 00135 typedef std::list< std::pair< std::string , std::string > > DESCR; 00136 typedef std::map< int , DESCR > MAP; 00137 private: 00138 MAP m_WORD; 00139 public: 00140 std::string lookUp( int n , const std::string& lang ) const; 00141 bool update( int n , const std::string& lang , const std::string& descr ); 00142 void erase( int n ); 00143 void toList( std::list<ERAV::WORD_tuple>& L ) const; 00144 bool empty() const { return m_WORD.empty(); } 00145 void clear() { m_WORD.clear(); } 00146 private: 00147 static DESCR::iterator lFind( DESCR& L, const std::string& lang ); 00148 static DESCR::const_iterator lFind( const DESCR& L, const std::string& lang ) 00149 { return lFind( *const_cast<DESCR*>(&L), lang ); } 00150 }; 00151 00152 struct attrib { // valid XML attributes for ERAV records 00153 static const char eREL_TYPE = 'e'; //<entity> && <record> 00154 enum { ATTRIB=0, FIRST=ATTRIB, 00155 DESCR, 00156 ID_ENT, REL_ID, REL_SUB, REL_TYPE, 00157 VAL, ID_WORD, ID_STRING, LANG, 00158 LAST=LANG, NONE 00159 };}; // namespace attrib { } 00160 00161 struct tag { // valid XML tags for ERAV records 00162 enum { attrib=attrib::ATTRIB, first=attrib, 00163 descr=attrib::DESCR, 00164 head, erav, entity, record, word, string, 00165 last=string, none=attrib::NONE 00166 };}; // namespace tag { } 00167 00168 class token { 00169 public: // "<?" "?>" "</" "/>" '..' ".." 00170 enum { ZERO=0, LTQ=512, QGT, LTS, SGT, ID, STRING }; // token numbers 00171 private: 00172 friend class parser; 00173 token() : m_token(0), m_line(), m_lexeme() { } 00174 public: 00175 // token( char ch ) : m_token(ch), m_lexeme() { m_lexeme = ch; }; 00176 token( int num ) : m_token(num), m_line(), m_lexeme() { }; 00177 void set( int number, const char* yytext, int yyleng, int yyline ) { 00178 m_token = number; m_lexeme.assign(yytext, yyleng); m_line = yyline; 00179 setTagAttrib(); 00180 } 00181 int getTag() const { return m_tag_attrib; } 00182 int getAttrib() const { return m_tag_attrib; } 00183 // operator int() const { return m_token; } // avoid ambiguity problems 00184 int num() const { return m_token; } // return token number 00185 const std::string & lexeme() const { return m_lexeme; } 00186 static const char* name(int tk); // token´s name 00187 bool operator==( int tk ) const { return this->m_token == tk; } 00188 private: 00189 void setTagAttrib(); // set m_tag_attrib 00190 int m_token; // ZERO, LTQ ... STRING 00191 int m_line; 00192 int m_tag_attrib; // record tag && attrib code 00193 std::string m_lexeme; 00194 }; 00195 00196 class context { 00197 friend class parser; 00198 private: 00199 context() {} 00200 ~context() { if (prev!=0) { delete prev; } } // recursive delete all 00201 private: 00202 context * prev; 00203 int REL_ID; 00204 }; 00205 00206 // scanner 00207 int yylex( char const** cursor, char const** yytext, int* yyleng, int* yyline ); 00208 00209 class parser { 00210 public: 00211 parser( const char* XML, std::list<ERAV::tuple> & L, 00212 ERAV::WORD & W, ERAV::WORD & S 00213 ) : token1(), token2(), 00214 deleteXML(false), 00215 m_context(0), m_context_old(0), m_nest_id(0), 00216 m_str_val() 00217 { real_set(XML,L,W,S, false); } 00218 parser( const std::string& XML, std::list<ERAV::tuple> & L, 00219 ERAV::WORD & W, ERAV::WORD & S 00220 ) : token1(), token2(), 00221 deleteXML(false), 00222 m_context(0), m_context_old(0), m_nest_id(0), 00223 m_str_val() 00224 { real_set(XML.c_str(),L,W,S,true); } // makeCopy=true 00225 void set( const char* XML, std::list<ERAV::tuple> & L, 00226 ERAV::WORD & W, ERAV::WORD & S ) 00227 { real_set(XML,L,W,S, false); } 00228 void set( const std::string& XML, std::list<ERAV::tuple> & L, 00229 ERAV::WORD & W, ERAV::WORD & S ) 00230 { real_set(XML.c_str(), L,W,S,true); } 00231 ~parser(); 00232 void parse(); 00233 private: 00234 void real_set( const char* XML, std::list<ERAV::tuple> & L, 00235 ERAV::WORD & W, ERAV::WORD & S, bool makeCopy ); 00236 void match( int num ); 00237 void error( const char* msg ) /* abort(); */; 00238 friend class exception; 00239 #define ID_val const std::string & lexeme 00240 void all(); // all : head docs; 00241 void head(); // head : "<?" "xml" args "?>" | /* empty */; 00242 00243 void docs(); // docs : doc docs | /* empty */; 00244 void doc(); // doc : '<' ID args nest; 00245 void nest(ID_val); // nest : "/>" | '>' docs "</" ID '>' 00246 00247 void args(); // args : arg args | /* empty */; 00248 void arg(); // arg : ID ('=' STRING)? 00249 #undef ID_val 00250 private: 00251 void pushContext(); void setAttrib(); 00252 void popContext(); void setAttribVal(); 00253 void emit(); 00254 private: 00255 parser( const parser& ); // forbidden 00256 void operator= ( const parser& ); // forbidden 00257 private: 00258 token * m_lookahead; // flip~flop between token1 && token2 00259 token token1, token2; // last && current token 00260 00261 const char* m_XML; // yylex() big string input 00262 bool deleteXML; // true when m_XML is a copy 00263 const char* m_yytext; // scanner fields 00264 int m_yyleng; 00265 int m_yyline; 00266 const char* m_cursor; 00267 00268 context * m_context; // pushContext() && popContext() 00269 context * m_context_old; // reuse context structs 00270 00271 int m_id; // current entity id 00272 int m_nest_id; // current rel_id for nested records 00273 00274 int m_tag; // current XML tag being processed 00275 int m_attrib; // which attrib to set with m_str_val 00276 char m_rel_type; // type of m_attrib 00277 std::string m_str_val; // attribute value 00278 int m_attrib_ref; // reference in attrib argument 00279 00280 int m_id_word; // current word && string id 00281 bool m_inWord; // true <==> <word><descr> 00282 char m_lang[4]; // word && string language 00283 00284 std::list<ERAV::tuple> * m_L; // list<> where ERAV records get appended 00285 ERAV::WORD * m_WORD; // WORD dictionary 00286 ERAV::WORD * m_STRING; // STRING dictionary 00287 }; 00288 00289 class exception { // thrown from parser::error() 00290 const char * m_what; // string for last error 00291 friend void ERAV::parser::error( const char* ); 00292 public: 00293 exception( const char* w ) throw() : m_what(w) { } 00294 // exception( const exception & o ) : m_what(o.m_what) { } 00295 const char* what() const throw() { return m_what; } 00296 }; 00297 00298 } // namespace ERAV 00299 00300 /// (l == r) ??? 00301 inline bool operator==( const ERAV::token& l , int r ) { 00302 return l.num() == r; 00303 } 00304 00305 #if 0 00306 /// (l == r) ??? 00307 inline bool operator==( const ERAV::token& l , const ERAV::token& r ) { 00308 return ( l.num()== r.num()); 00309 } 00310 #endif 00311 00312 /// { L.clear(), W.clear(), S.clear(); } 00313 inline void erav_clear( 00314 std::list<ERAV::tuple>& L , 00315 ERAV::WORD& W , 00316 ERAV::WORD& S 00317 ) { 00318 L.clear(), W.clear(), S.clear(); 00319 } 00320 00321 // XML ==> [ L<tuple> && W<word> && S<string> ] ((append)) 00322 inline void xml2erav( // throws ERAV::exception on error 00323 const std::string& XML , 00324 std::list<ERAV::tuple>& L , // append to current value 00325 ERAV::WORD& W , // append to current value 00326 ERAV::WORD& S // append to current value 00327 ) { 00328 #if 1 00329 ERAV::parser P( XML , L , W, S ); 00330 P.parse(); 00331 #else 00332 try { 00333 ERAV::parser P( XML , L , W, S ); 00334 P.parse(); 00335 } 00336 catch ( ERAV::exception e ) { /* e.what() describes the error */ } 00337 catch ( ... ) { /* catch all */ } 00338 #endif 00339 } 00340 00341 inline 00342 void erav2xml( const ERAV::WORD& S , std::string& XML , const std::string& ) { 00343 erav2xml( S , XML , false ); 00344 } 00345 00346 #undef NOT_const 00347 #endif // ERAV_h 00348 00349 // EOF: ERAV.h