Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/expr/ExSymTbl.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2007 George Tzanetakis <gtzan@cs.uvic.ca>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include <marsyas/expr/ExSymTbl.h>
00020 #include <marsyas/expr/ExNode.h>
00021 
00022 using std::ostringstream;
00023 using namespace Marsyas;
00024 
00025 ExRecord::ExRecord() : ExRefCount()
00026 {
00027   kind_=0;
00028   name_="";
00029   reserved_=false;
00030 }
00031 ExRecord::ExRecord(int kind) : ExRefCount()
00032 {
00033   kind_=kind;
00034   name_="";
00035   reserved_=false;
00036 }
00037 
00038 ExRecord::ExRecord(int kind, ExFun* fun, bool reserved) : ExRefCount()
00039 {
00040   kind_=kind;
00041   name_=fun->getSignature(); // fully qualified name
00042   value_.set(fun);
00043   reserved_=reserved;
00044 }
00045 ExRecord::ExRecord(int kind, std::string name, ExVal& value, bool reserved) : ExRefCount()
00046 {
00047   kind_=kind;
00048   name_=name;
00049   value_=value;
00050 
00051   reserved_=reserved;
00052 }
00053 //
00054 ExRecord::~ExRecord()
00055 {
00056   if (!syms_.empty()) {
00057     std::map<std::string,ExRecord*>::iterator it;
00058     for(it=syms_.begin(); it!=syms_.end(); ++it) {
00059       ((*it).second)->deref();
00060     }
00061   }
00062 }
00063 //
00064 std::string
00065 ExRecord::getType(std::string path)
00066 {
00067   if (path=="") return value_.getType();
00068   ExRecord* r=getRecord(path);
00069   return (r==NULL) ? "" : r->getType();
00070 }
00071 
00072 std::string
00073 ExRecord::getElemType(std::string path)
00074 {
00075   if (path=="") return value_.getElemType();
00076   ExRecord* r=getRecord(path);
00077   return (r==NULL) ? "" : r->getElemType();
00078 }
00079 //
00080 
00081 int
00082 ExRecord::getKind(std::string path)
00083 {
00084   if (path=="") return kind_;
00085   ExRecord* r=getRecord(path);
00086   return (r==NULL) ? 0 : r->getKind();
00087 }
00088 //
00089 
00090 bool
00091 ExRecord::is_reserved(std::string path)
00092 {
00093   if (path=="") return reserved_;
00094   ExRecord* r=getRecord(path);
00095   return (r==NULL) ? false : r->is_reserved();
00096 }
00097 
00098 bool
00099 ExRecord::is_list()
00100 {
00101   return value_.is_list();
00102 }
00103 
00104 bool
00105 ExRecord::is_seq()
00106 {
00107   return value_.is_seq();
00108 }
00109 //
00110 ExRecord*
00111 ExRecord::getRecord(std::string path)
00112 {
00113   ExRecord* r=find_sym(path);
00114   if (r==NULL&&imports_.size()>0) { // try the imports in case path is not fully qualified
00115     std::vector<std::string>::iterator iter_;
00116     for (iter_=imports_.begin(); r==NULL&&iter_!=imports_.end(); iter_++) {
00117       r=find_sym((*iter_)+"."+path);
00118     }
00119   }
00120   return r;
00121 }
00122 bool
00123 ExRecord::params_compare(std::string a, std::string b)
00124 {
00125   std::string::size_type p1=0;
00126   std::string::size_type p2=0;
00127   std::string::size_type len1 = a.length();
00128   std::string::size_type len2 = b.length();
00129   std::string::size_type start=1;
00130 
00131   while (p1<len1&&p2<len2) {
00132     if (a[p1]!=b[p2]) {
00133       if (a[p1]==','&&b[p2]=='|') {
00134         while (p2<len2) {
00135           if (b[p2]==',') break;
00136           if (b[p2]==')') return false;
00137           p2++;
00138         }
00139         p1++;
00140         p2++;
00141       }
00142       else if (a[p1]==')'&&b[p2]=='|') {
00143         while (p2<len2) {
00144           if (b[p2]==',') return false;
00145           if (b[p2]==')') return true;
00146           p2++;
00147         }
00148         return false;
00149       }
00150       else {
00151         while(p2<len2) {
00152           if (b[p2]=='|') break;
00153           if (b[p2]==','||b[p2]==')') return false;
00154           p2++;
00155         }
00156         p1=start; p2++;
00157       }
00158     }
00159     else {
00160       if (a[p1]==',') start=p1+1;
00161       p1++; p2++;
00162     }
00163     if (a[p1]==')'&&b[p2]==')') return true;
00164   }
00165   return false;
00166 }
00167 
00168 
00169 
00170 
00171 ExFun*
00172 ExRecord::getFunctionCopy(std::string path)
00173 {
00174   if (path=="") {
00175     if (kind_!=T_FUN) return NULL;
00176     ExFun* f=value_.toFun();
00177     return (f==NULL) ? NULL : f->copy();
00178   }
00179   ExRecord* r=getRecord(path);
00180   return (r==NULL) ? NULL : r->getFunctionCopy();
00181 }
00182 //
00183 void
00184 ExRecord::split_on(std::string p, char c, std::string& hd, std::string& tl, bool keep)
00185 {
00186   int adj=(keep) ? 0 : 1;
00187   size_t i;
00188   for(i=0; i<p.length()&&p[i]!=c; ++i);
00189   if (p[i]==c) { hd=p.substr(0,i); tl=p.substr(i+adj,p.length()-i-adj); }
00190   else { hd=p; tl=""; }
00191 }
00192 //
00193 void
00194 ExRecord::rsplit_on(std::string p, char c, std::string& hd, std::string& tl)
00195 {
00196   std::string::size_type i = p.length();
00197   while(i>0)
00198   {
00199     --i;
00200     if(p[i]==c)
00201     {
00202       hd=p.substr(0,i); tl=p.substr(i+1,p.length()-i-1); return;
00203     }
00204   }
00205   hd=""; tl=p;
00206 }
00207 //
00208 ExRecord*
00209 ExRecord::find_sym(std::string path)
00210 {
00211   // get leading name in group: a|b|c.d|e|f.g|h|i => a|b|c d|e|f.g|h|i
00212   std::string ghd, gtl; split_on(path,'.',ghd,gtl);
00213   if (gtl==""&&ghd[0]!='(') {
00214     split_on(ghd,'(',ghd,gtl,true);
00215   }
00216   if (gtl!="") { // then ghd is the variable name
00217     // get leading name in name: a|b|c => a b|c
00218     std::map<std::string, ExRecord*>::iterator gi=syms_.find(ghd);
00219     if (gi==syms_.end()) {
00220       std::map<std::string,std::string>::iterator it = syms_aliases_.find(ghd);
00221       // a possible error condition since the path given diverges from the possible paths
00222       if (it==syms_aliases_.end())
00223         return NULL;
00224       else
00225         return syms_[it->second]->find_sym(gtl);
00226     }
00227 
00228     return (gi->second)->find_sym(gtl);
00229   }
00230   if (path[0]=='(') {
00231     ExRecord* answer=NULL;
00232     std::map<std::string,ExRecord*>::iterator is=syms_.begin();
00233     while (is!=syms_.end()&&!answer) {
00234       if (params_compare((is->first),path)) { answer=is->second; }
00235       else is++;
00236     }
00237     if (!answer) {
00238       std::map<std::string,std::string>::iterator it=syms_aliases_.begin();
00239       while (it!=syms_aliases_.end()&&!answer) {
00240         if (params_compare((it->first),path))
00241           answer=syms_[it->second];
00242         else
00243           ++it;
00244       }
00245     }
00246     return answer;
00247   }
00248   std::map<std::string,ExRecord*>::iterator gi=syms_.find(ghd);
00249   if (gi==syms_.end()) {
00250     // name not found, so see if it is an alias
00251     std::map<std::string,std::string>::iterator ni=syms_aliases_.find(ghd);
00252     if (ni==syms_aliases_.end()) { return NULL; }
00253     return syms_[ni->second];
00254   }
00255   return (gi->second);
00256 }
00257 
00258 void
00259 ExRecord::addAliases(std::string path, std::string name)
00260 {
00261   std::string nhd, ntl;
00262   // the rest of the names are aliases
00263   split_on(path,'|',nhd,ntl);
00264   while (nhd!="") {
00265     syms_aliases_[nhd]=name;
00266     split_on(ntl,'|',nhd,ntl);
00267   }
00268 }
00269 //
00270 void
00271 ExRecord::addRecord(std::string path, ExRecord* sym)
00272 {
00273   // get leading name in group: a|b|c.d|e|f.g|h|i => a|b|c d|e|f.g|h|i
00274   std::string ghd; std::string gtl; split_on(path,'.',ghd,gtl);
00275   if (gtl!="") { // then ghd is the variable name
00276     // now split on '|' symbol, get leading name in name: a|b|c => a b|c
00277     std::string nhd, ntl; split_on(ghd,'|',nhd,ntl);
00278     std::string name_=nhd;
00279     std::map<std::string, ExRecord*>::iterator gi=syms_.find(name_);
00280     ExRecord* syms=NULL;
00281     // for first split, if name doesn't exist, add it as a record
00282     if (gi==syms_.end()) { syms=new ExRecord(T_LIB); syms_[name_]=syms; syms->inc_ref(); }
00283     else { syms=(gi->second); }
00284 
00285     // the rest of the names are aliases
00286     addAliases(ntl,name_);
00287     syms->addRecord(gtl,sym);
00288   }
00289   else {
00290     // discover parameters
00291     std::string params;
00292     if (ghd[0]!='(') split_on(ghd,'(',ghd,params,true);
00293     // get leading name in name: a|b|c => a b|c, becomes the master name
00294     std::string nhd, ntl; split_on(ghd,'|',nhd,ntl);
00295     std::map<std::string, ExRecord*>::iterator gi=syms_.find(nhd);
00296     if (gi==syms_.end()) { // not found, so must be a new name
00297       if (params!="") {
00298         ExRecord* e=new ExRecord(T_FUN); e->inc_ref();
00299         syms_[nhd]=e;
00300         e->addRecord(params,sym);
00301       }
00302       else {
00303         syms_[nhd]=sym;
00304         sym->inc_ref();
00305       }
00306     }
00307     else if (params!="") {
00308       (gi->second)->addRecord(params,sym);
00309     }
00310     else {
00311       MRSWARN("ExRecord::addRecord  '"+nhd+"' already refers to a symbol");
00312       sym->deref();
00313       return;
00314     }
00315     addAliases(ntl,nhd);
00316   }
00317 }
00318 ExRecord*
00319 ExRecord::rmvRecord(std::string path)
00320 {
00321   // get leading name in group: a|b|c.d|e|f.g|h|i => a|b|c d|e|f.g|h|i
00322   std::string ghd, gtl; split_on(path,'.',ghd,gtl);
00323   std::map<std::string, ExRecord*>::iterator rec_i;
00324   std::map<std::string,std::string>::iterator alias_i;
00325 
00326   if (gtl==""&&ghd[0]!='(') {
00327     split_on(ghd,'(',ghd,gtl,true);
00328   }
00329   rec_i=syms_.find(ghd);
00330   if (rec_i==syms_.end()) {
00331     alias_i=syms_aliases_.find(ghd);
00332     // a possible error condition since the path given diverges from the possible paths
00333     if (alias_i==syms_aliases_.end()) { return NULL; }
00334     ghd=alias_i->second;
00335     rec_i=syms_.find(ghd); // let's assume that gi is valid
00336   }
00337   ExRecord* r;
00338   bool del_rec=false;
00339   if (gtl!="") r=(rec_i->second)->rmvRecord(gtl);
00340   else { r=rec_i->second; del_rec=true; }
00341   if (r!=NULL) {
00342     std::vector<std::string> names_;
00343     // eliminate aliases to r by first getting their names
00344     for (alias_i=syms_aliases_.begin(); alias_i!=syms_aliases_.end(); ++alias_i) {
00345       if (alias_i->second==ghd) names_.push_back(alias_i->first);
00346     }
00347     if (names_.size()>0) {
00348       // delete aliases from syms_aliases_
00349       std::vector<std::string>::iterator nmi;
00350       for (nmi=names_.begin(); nmi!=names_.end(); ++nmi) {
00351         syms_aliases_.erase(*nmi);
00352       }
00353     }
00354     // eliminate the record from syms_
00355     syms_.erase(rec_i);
00356     if (del_rec&&r->size()>0) r->deref();
00357   }
00358   return r;
00359 }
00360 void
00361 ExRecord::addReserved(std::string path, ExFun* fun)
00362 {
00363   addRecord(path,new ExRecord(T_FUN,fun,true));
00364 }
00365 void
00366 ExRecord::addReserved(std::string path, ExVal v, std::string nm, int kind)
00367 {
00368   addRecord(path,new ExRecord(kind,nm,v,true));
00369 }
00370 //
00371 void
00372 ExRecord::setValue(ExVal& v, std::string path, int elem_pos)
00373 {
00374   if (path!="") {
00375     // get leading name in group: a|b|c.d|e|f.g|h|i => a|b|c d|e|f.g|h|i
00376     std::string name; split_on(path,'.',name,path);
00377     if (path!="") { // then ghd is the variable name
00378       // get leading name in name: a|b|c => a b|c
00379       std::map<std::string, ExRecord*>::iterator iter=syms_.find(name);
00380       ExRecord* syms=NULL;
00381       if (iter==syms_.end()) { syms=new ExRecord(); syms_[name]=syms; syms->inc_ref(); }
00382       else { syms=iter->second; }
00383       syms->setValue(v,path);
00384       return;
00385     }
00386     else {
00387       // get leading name in name: a|b|c => a b|c
00388       std::map<std::string, ExRecord*>::iterator iter=syms_.find(name);
00389       if (iter==syms_.end()) { // not in table, so add it
00390         ExRecord* r=new ExRecord(T_VAR,name,v,false); r->inc_ref();
00391         syms_[name]=r;
00392         return;
00393       }
00394       else {
00395         (iter->second)->setValue(v);
00396         return;
00397       }
00398     }
00399   }
00400   if (getKind()!=T_VAR) {
00401     MRSWARN("ExRecord::setValue   Attempting assignment to non-variable");
00402   }
00403   else if (elem_pos>=0) {
00404     if (getElemType()!=v.getType()) {
00405       MRSWARN("ExRecord::setValue   Type mismatch in assignment of element: "+getElemType()+" << "+v.getType());
00406     }
00407     else value_.setSeqElem(elem_pos, v);
00408   }
00409   else if (getType()!=v.getType()) {
00410     MRSWARN("ExRecord::setValue   Type mismatch in assignment: "+getType()+" << "+v.getType());
00411   } else value_=v;
00412 }
00413 
00414 // These are pathed names, with no | symbols
00415 ExVal
00416 ExRecord::getValue(std::string path)
00417 {
00418   if (path=="") return value_;
00419   ExRecord* s=getRecord(path);
00420   return (s==NULL) ? false : s->getValue();
00421 }
00422 // add the path 'a' to the imports list
00423 void
00424 ExRecord::import(std::string a)
00425 {
00426   std::vector<std::string>::iterator p; bool added=false;
00427   for (p=imports_.begin(); p!=imports_.end(); ++p) {
00428     if ((*p)==a) { added=true; break; }
00429   }
00430   if (!added) imports_.push_back(a);
00431 }
00432 //
00433 void
00434 ExRecord::rmv_import(std::string a)
00435 {
00436   std::vector<std::string>::iterator p;
00437   for (p=imports_.begin(); p!=imports_.end(); ++p) {
00438     if ((*p)==a) { imports_.erase(p); break; }
00439   }
00440 }
00441 
00442 /******************************************************************************/
00443 ExSymTbl::~ExSymTbl()
00444 {
00445   while (rho_.size()>0) {
00446     ExRecord* r=rho_.back();
00447     rho_.pop_back();
00448     r->deref();
00449   }
00450 }
00451 void ExSymTbl::block_open()
00452 {
00453   env_id++;
00454   ExRecord* r=new ExRecord();
00455   rho_.push_back(r);
00456   curr_=r;
00457   r->inc_ref();
00458 }
00459 void
00460 ExSymTbl::block_close()
00461 {
00462   if (rho_.size()>0) {
00463     ExRecord* r=rho_.back();
00464     rho_.pop_back();
00465     r->deref();
00466     if (rho_.size()>0) curr_=rho_.back();
00467     else curr_=NULL;
00468   }
00469 }
00470 void
00471 ExSymTbl::addTable(ExRecord* r)
00472 {
00473   if (r) {
00474     env_id++;
00475     rho_.push_back(r);
00476     curr_=r;
00477     r->inc_ref();
00478   }
00479 }
00480 ExRecord*
00481 ExSymTbl::getRecord(std::string nm)
00482 {
00483   if (rho_.size()>0) {
00484     std::vector<ExRecord*>::reverse_iterator i;
00485     for(i=rho_.rbegin(); i!=rho_.rend(); ++i) {
00486       ExRecord* r=(*i)->getRecord(nm);
00487       if (r!=NULL) return r;
00488     }
00489   }
00490   return NULL;
00491 }
00492 ExVal
00493 ExSymTbl::getValue(std::string path)
00494 {
00495   ExRecord* r=getRecord(path);
00496   return (r) ? r->getValue() : ExVal();
00497 }
00498 ExFun*
00499 ExSymTbl::getFunctionCopy(std::string path)
00500 {
00501   ExRecord* r=getRecord(path);
00502   return (r) ? r->getFunctionCopy() : NULL;
00503 }
00504 void
00505 ExSymTbl::import(std::string n)
00506 {
00507   if (curr_) curr_->import(n);
00508 }
00509 void
00510 ExSymTbl::rmv_import(std::string n)
00511 {
00512   if (curr_) curr_->rmv_import(n);
00513 }
00514 void
00515 ExSymTbl::addRecord(std::string path, ExRecord* sym)
00516 {
00517   if (curr_) curr_->addRecord(path,sym);
00518 }
00519 ExRecord*
00520 ExSymTbl::rmvRecord(std::string path)
00521 {
00522   return (curr_) ? curr_->rmvRecord(path) : NULL;
00523 }
00524 void
00525 ExSymTbl::addReserved(std::string path, ExFun* f)
00526 {
00527   if (curr_) curr_->addReserved(path,f);
00528 }
00529 void
00530 ExSymTbl::addReserved(std::string path, ExVal v, std::string nm, int kind)
00531 {
00532   if (curr_) curr_->addReserved(path,v,nm,kind);
00533 }
00534 void
00535 ExSymTbl::setValue(ExVal& v, std::string path)
00536 {
00537   if (curr_) curr_->setValue(v,path);
00538 }