// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_columns #define tools_columns #include "vmanip" #include "forit" #include "sout" #include "schar" #ifdef TOOLS_MEM #include "mem" #include "S_STRING" #endif namespace tools { namespace columns { class tree { #ifdef TOOLS_MEM TOOLS_SCLASS(tools::columns::tree) #endif public: tree(tree* a_parent,const std::string& a_dcl):m_parent(a_parent),m_dcl(a_dcl){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif if(a_parent) a_parent->m_sub.push_back(this); } virtual ~tree(){ clear(); #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } protected: tree(const tree&) {} tree& operator=(const tree&) {return *this;} public: void clear() { m_dcl.clear(); safe_reverse_clear(m_sub); } void dump_tree(std::ostream& a_out,const std::string& a_margin) { if(m_dcl.size()) a_out << a_margin << m_dcl << std::endl; {tools_vforit(tree*,m_sub,it) { (*it)->dump_tree(a_out,a_margin+" "); }} } 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; } void dump(std::ostream& a_out) {m_top.dump_tree(a_out,"");} protected: tree m_top; }; }} #include "words" #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); } } } inline void dump_columns(std::ostream& a_out,const std::vector& a_vars,const std::string& a_margin = "") { std::vector::const_iterator it; for(it=a_vars.begin();it!=a_vars.end();++it) { if((*it).type()==value::VOID_STAR) { a_out << a_margin << "ITuple : " << (*it).label() << " : begin " << std::endl; std::vector* vars = (std::vector*)(*it).get_void_star(); dump_columns(a_out,*vars,a_margin+" "); //a_out << a_margin // << "ITuple : " << (*it).label() << " : end " // << std::endl; } else { std::string stype; (*it).s_type(stype); std::string sval; (*it).tos(sval); a_out << a_margin << stype << " : " << (*it).label() << " : " << sval << std::endl; } } } 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; } /* const std::string& script() const { return m_script;} //bool isSuccess() const { return fSuccess;} std::ostream& out() const {return m_out;} */ protected: bool analyse(columns::tree& a_tree,std::vector& a_stack) { if(a_tree.m_dcl.empty()) { //top //std::cout << "debug : dcl empty" << std::endl; tools_vforit(columns::tree*,a_tree.m_sub,it) { if(!analyse(*(*it),a_stack)) return false; } } else { //std::cout << "debug : dcl not empty" << std::endl; if(is_spaces(a_tree.m_dcl)) return true; value* v = analyse_dcl(a_tree.m_dcl); if(!v) return false; //std::cout << "debug : dcl label " << v->label() << std::endl; 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=="char") { // a_type = value::CHAR; } 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=="byte") { // a_type = value::UNSIGNED_CHAR; } else if(a_s=="float[]") { a_type = value::ARRAY_FLOAT; } else if(a_s=="double[]") { a_type = value::ARRAY_DOUBLE; //} else if(a_s=="char[]") { // a_type = value::ARRAY_CHAR; //} else if(a_s=="byte[]") { // a_type = value::ARRAY_UNSIGNED_CHAR; } 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::CHAR) { // char 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_CHAR) { // unsigned short v = 0; // if(a_v.size()) {if(!to(a_v,v)) return 0;} // return new value((unsigned char)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_UNSIGNED_CHAR) { // if(a_v.size()) return 0; // value* v = new value(); // v->set_type(value::ARRAY_UNSIGNED_CHAR); // return v; //} else if(a_type==value::ARRAY_CHAR) { // if(a_v.size()) return 0; // value* v = new value(); // v->set_type(value::ARRAY_CHAR); // 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; //bool fSuccess; }; }} #endif