// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_columns #define tools_columns #include "forit" #include "sout" #include "schar" #include "vmanip" namespace tools { namespace columns { class tree { public: tree(tree* a_parent,const std::string& a_dcl):m_parent(a_parent),m_dcl(a_dcl){ if(a_parent) a_parent->m_sub.push_back(this); } virtual ~tree(){ clear(); } protected: tree(const tree&) {} tree& operator=(const tree&) {return *this;} public: void clear() { m_dcl.clear(); safe_reverse_clear(m_sub); } public: tree* m_parent; std::string m_dcl; std::vector m_sub; }; }} #include "strip" namespace tools { namespace columns { class parser { public: parser():m_top(0,""){} virtual ~parser(){m_top.clear();} protected: parser(const parser&):m_top(0,"") {} parser& operator=(const parser&){return *this;} public: bool parse(const std::string& a_s){ m_top.clear(); tree* prev = &m_top; {std::string _s; for(std::string::const_iterator it=a_s.begin();;++it) { if(it==a_s.end()) { if(_s.size()) { new tree(prev,_s); _s.clear(); } break; } else { const char& c = *it; if(c==',') { if(_s.size()) { new tree(prev,_s); _s.clear(); } } else if(c=='{') { tree* _tree = new tree(prev,_s); _s.clear(); prev = _tree; } else if(c=='}') { if(_s.size()) { new tree(prev,_s); _s.clear(); } prev = prev->m_parent; if(!prev) return false; //should not happen. } else { _s += c; } } }} return true; } protected: tree m_top; }; }} #include "tokenize" #include "value" namespace tools { namespace columns { inline void delete_columns(std::vector& a_vars) { tools_vforit(value,a_vars,it) { if((*it).type()==value::VOID_STAR) { std::vector* vars = (std::vector*)(*it).get_void_star(); delete_columns(*vars); delete vars; } } a_vars.clear(); } inline void copy_columns(const std::vector& a_from,std::vector& a_to) { std::vector::const_iterator it; for(it=a_from.begin();it!=a_from.end();++it) { if((*it).type()==value::VOID_STAR) { std::vector* vars = new std::vector(); value v((void*)vars); v.set_label((*it).label()); a_to.push_back(v); std::vector* p = (std::vector*)(*it).get_void_star(); copy_columns(*p,*vars); } else { a_to.push_back(*it); } } } class finder : public columns::parser { typedef columns::parser parent; public: finder(std::ostream& a_out,const std::string& a_script) :m_out(a_out) ,m_script(a_script) //,fSuccess(false) ,m_cur_type(value::NONE) {} virtual ~finder() {clear();} protected: finder(const finder& a_from):parent(a_from),m_out(a_from.m_out){} finder& operator=(const finder&){return *this;} public: //void setScript(const std::string& a_string) { m_script = a_string;} bool find_variables() { clear(); if(m_script.empty()) return false; //keep old version logic. if(!parse(m_script)) return false; //dump(m_out); //analyse m_top : if(!analyse(m_top,m_stack)) {clear();return false;} return true; } void result(std::vector& a_vars) const { a_vars.clear(); copy_columns(m_stack,a_vars); } void clear() { m_top.clear(); delete_columns(m_stack); m_cur_type = value::NONE; } protected: bool analyse(columns::tree& a_tree,std::vector& a_stack) { if(a_tree.m_dcl.empty()) { //top tools_vforit(columns::tree*,a_tree.m_sub,it) { if(!analyse(*(*it),a_stack)) return false; } } else { if(is_spaces(a_tree.m_dcl)) return true; value* v = analyse_dcl(a_tree.m_dcl); if(!v) return false; if(a_tree.m_sub.size()) { if(v->type()!=value::VOID_STAR) { m_out << "tools::columns::finder::analyse :" << " Expect a VOID_STAR." << std::endl; delete v; return false; } m_cur_type = value::NONE; std::vector* stk = new std::vector(); tools_vforit(columns::tree*,a_tree.m_sub,it) { if(!analyse(*(*it),*stk)) { delete v; return false; } } v->set((void*)stk); } else { m_cur_type = v->type(); } a_stack.push_back(*v); delete v; } return true; } value* analyse_dcl(const std::string& a_s) { std::vector ws; words(a_s,"=",false,ws); if(ws.size()==2) { // = std::vector swords; words(ws[0]," ",false,swords); if(swords.size()==2) { strip(swords[0]); strip(swords[1]); if(swords[0]=="ITuple") { //create a value::VOID_STAR : value* v = new value((void*)0); v->set_label(swords[1]); return v; } else { value::e_type type; if(!s2type(swords[0],type)){ m_out << "tools::columns::finder::analyse_dcl :" << " s2type failed for " << sout(swords[0]) << "." << std::endl; return 0; } strip(ws[1]); value* v = new_value(type,ws[1]); if(!v) { m_out << "tools::columns::finder::analyse_dcl :" << " syntax error in " << sout(a_s) << "." << " new_value() failed." << std::endl; return 0; } v->set_label(swords[1]); return v; } } else if(swords.size()==1) { if(m_cur_type==value::NONE) { m_out << "tools::columns::finder::analyse_dcl :" << " (1) current type is NONE." << std::endl; return 0; } strip(ws[1]); value* v = new_value(m_cur_type,ws[1]); if(!v) { m_out << "tools::columns::finder::analyse_dcl :" << " syntax error in " << sout(a_s) << "." << " Bad value " << sout(ws[1]) << "." << std::endl; return 0; } v->set_label(swords[0]); return v; } else { m_out << "tools::columns::finder::analyse_dcl :" << " syntax error in " << sout(a_s) << ". Case 1." << std::endl; return 0; } } else if(ws.size()==1) { // // ={ std::vector swords; words(ws[0]," ",false,swords); if(swords.size()==2) { strip(swords[0]); strip(swords[1]); if(swords[0]=="ITuple") { //create a value::VOID_STAR : value* v = new value((void*)0); v->set_label(swords[1]); return v; } else { value::e_type type; if(!s2type(swords[0],type)){ m_out << "tools::columns::finder::analyse_dcl :" << " s2type failed for " << sout(swords[0]) << "." << std::endl; return 0; } value* v = new_value(type,""); if(!v) { m_out << "tools::columns::finder::analyse_dcl :" << " (2) syntax error in " << sout(ws[0]) << "." << " Unknown type " << sout(swords[0]) << "." << std::endl; return 0; } v->set_label(swords[1]); return v; } } else if(swords.size()==1) { if(m_cur_type==value::NONE) { m_out << "tools::columns::finder::analyse_dcl :" << " (1) current type is NONE." << std::endl; return 0; } value* v = new value(); v->set_type(m_cur_type); v->set_label(swords[0]); return v; } else { m_out << "tools::columns::finder::analyse_dcl :" << " syntax error in " << sout(a_s) << ". Case 2." << std::endl; return 0; } } else { m_out << "tools::columns::finder::analyse_dcl :" << " syntax error in " << sout(a_s) << ". Case 3." << std::endl; return 0; } } protected: static bool s2type(const std::string& a_s,value::e_type& a_type){ if(a_s=="float") { a_type = value::FLOAT; } else if(a_s=="double") { a_type = value::DOUBLE; } else if(a_s=="short") { a_type = value::SHORT; } else if(a_s=="int") { a_type = value::INT; } else if(a_s=="long") { a_type = value::INT64; } else if((a_s=="bool")||(a_s=="boolean")) { a_type = value::BOOL; } else if((a_s=="string")||(a_s=="java.lang.String")){ a_type = value::STRING; } else if(a_s=="float[]") { a_type = value::ARRAY_FLOAT; } else if(a_s=="double[]") { a_type = value::ARRAY_DOUBLE; } else if(a_s=="short[]") { a_type = value::ARRAY_SHORT; } else if(a_s=="int[]") { a_type = value::ARRAY_INT; } else if(a_s=="long[]") { a_type = value::ARRAY_INT64; } else if((a_s=="bool[]")||(a_s=="boolean[]")) { a_type = value::ARRAY_BOOL; } else if((a_s=="string[]")||(a_s=="java.lang.String[]")){ a_type = value::ARRAY_STRING; // not AIDA : //} else if(a_s=="uchar") { // a_type = value::UNSIGNED_CHAR; } else if(a_s=="ushort") { a_type = value::UNSIGNED_SHORT; } else if(a_s=="uint") { a_type = value::UNSIGNED_INT; } else if(a_s=="ulong") { a_type = value::UNSIGNED_INT64; } else { return false; } return true; } static value* new_value(value::e_type a_type,const std::string& a_v) { if(a_type==value::FLOAT) { float v = 0; if(a_v.size()) {if(!to(a_v,v)) return 0;} return new value(v); } else if(a_type==value::DOUBLE) { double v = 0; if(a_v.size()) {if(!to(a_v,v)) return 0;} return new value(v); } else if(a_type==value::SHORT) { short v = 0; if(a_v.size()) {if(!to(a_v,v)) return 0;} return new value(v); } else if(a_type==value::INT) { int v = 0; if(a_v.size()) {if(!to(a_v,v)) return 0;} return new value(v); } else if(a_type==value::INT64) { int64 v = 0; if(a_v.size()) {if(!to(a_v,v)) return 0;} return new value(v); } else if(a_type==value::BOOL) { bool v = false; if(a_v.size()) {if(!to(a_v,v)) return 0;} return new value(v); } else if(a_type==value::STRING) { if( (a_v.size()>=2) && (a_v[0]=='"') && (a_v[a_v.size()-1]=='"') ){ return new value(a_v.substr(1,a_v.size()-2)); } else { return new value(a_v); } } else if(a_type==value::UNSIGNED_SHORT) { unsigned short v = 0; if(a_v.size()) {if(!to(a_v,v)) return 0;} return new value(v); } else if(a_type==value::UNSIGNED_INT) { unsigned int v = 0; if(a_v.size()) {if(!to(a_v,v)) return 0;} return new value(v); } else if(a_type==value::UNSIGNED_INT64) { uint64 v = 0; if(a_v.size()) {if(!to(a_v,v)) return 0;} return new value(v); } else if(a_type==value::ARRAY_FLOAT) { if(a_v.size()) return 0; value* v = new value(); v->set_type(value::ARRAY_FLOAT); return v; } else if(a_type==value::ARRAY_DOUBLE) { if(a_v.size()) return 0; value* v = new value(); v->set_type(value::ARRAY_DOUBLE); return v; } else if(a_type==value::ARRAY_SHORT) { if(a_v.size()) return 0; value* v = new value(); v->set_type(value::ARRAY_SHORT); return v; } else if(a_type==value::ARRAY_INT) { if(a_v.size()) return 0; value* v = new value(); v->set_type(value::ARRAY_INT); return v; } else if(a_type==value::ARRAY_INT64) { if(a_v.size()) return 0; value* v = new value(); v->set_type(value::ARRAY_INT64); return v; } else if(a_type==value::ARRAY_BOOL) { if(a_v.size()) return 0; value* v = new value(); v->set_type(value::ARRAY_BOOL); return v; } else if(a_type==value::ARRAY_STRING) { if(a_v.size()) return 0; value* v = new value(); v->set_type(value::ARRAY_STRING); return v; } else { return 0; } } public: std::ostream& m_out; std::string m_script; std::vector m_stack; value::e_type m_cur_type; }; }} #endif