Marsyas
0.6.0-alpha
|
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 }