FAUST compiler  0.9.9.6b8
tree.cpp
Go to the documentation of this file.
00001 /************************************************************************
00002  ************************************************************************
00003     FAUST compiler
00004     Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
00005     ---------------------------------------------------------------------
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  ************************************************************************
00020  ************************************************************************/
00021  
00022  
00023  
00024 /*****************************************************************************
00025 ******************************************************************************
00026                                 TREE 
00027                         Y. Orlarey, (c) Grame 2002
00028 ------------------------------------------------------------------------------
00029 Trees are made of a Node associated with a list of branches : (Node x [CTree]).
00030 Up to 4 branches are allowed in this implementation. A hash table is used to 
00031 maximize the sharing of trees during construction : trees at different 
00032 addresses always have a different content. Reference counting is used for 
00033 garbage collection, and smart pointers P<CTree> should be used for permanent
00034 storage of trees.
00035 
00036  API:
00037  ----
00038  tree (n)               : tree of node n with no branch             
00039  tree (n, t1)           : tree of node n with a branch t
00040  tree (n, t1,...,tm)    : tree of node n with m branches t1,...,tm
00041  
00042  Pattern matching :
00043  
00044  if (isTree (t, n))         ... : t has node n and no branches; 
00045  if (isTree (t, n, &t1)     ... : t has node n and 1 branch, t1 is set accordingly; 
00046  if (isTree (t, n, &t1...&tm)...: t has node n and m branches, ti's are set accordingly; 
00047  
00048  Accessors :
00049          
00050  t->node()          : the node of t     { return fNode; }
00051  t->arity()         : the number of branches of t return fArity; }
00052  t->branch(i)       : the ith branch of t
00053 
00054  Attributs :
00055          
00056  t->attribut()      : return the attribut (also a tree) of t
00057  t->attribut(t')    : set the attribut of t to t' 
00058          
00059  Warning :
00060  ---------
00061  Since reference counters are used for garbage collecting, one must be careful not to 
00062  create cycles in trees The only possible source of cycles is by setting the attribut
00063  of a tree t to a tree t' that contains t as a subtree.  
00064     
00065  Properties:
00066  -----------
00067     If p and q are two CTree pointers  : 
00068         p != q  <=>  *p != *q
00069 
00070  History :
00071  ---------
00072     2002-02-08 : First version
00073     2002-10-14 : counts for height and recursiveness added
00074     
00075 ******************************************************************************
00076 *****************************************************************************/
00077 
00078 #include <stdlib.h>
00079 #include <stdio.h>
00080 #include <string.h>
00081 #include <limits.h>
00082 #include "tree.hh"
00083 #include <fstream>
00084 #include <cstdlib>
00085 
00086 Tabber TABBER(1);   
00087 extern Tabber TABBER;
00088 
00089 
00090 static void error(const char * s, Tree t)
00091 {
00092     //fprintf(stderr, "ERROR : %s (%p)\n", s, t);
00093     cerr << "ERROR : " << s << " : " << *t << endl;
00094 }
00095 
00096 #define ERROR(s,t) { error(s,t); exit(1); }
00097 
00098 
00099 Tree CTree::gHashTable[kHashTableSize];
00100 bool CTree::gDetails = false;
00101 unsigned int  CTree::gVisitTime = 0;
00102 
00103 // Constructor : add the tree to the hash table
00104 CTree::CTree (unsigned int hk, const Node& n, const tvec& br) 
00105     :   fNode(n), 
00106         fType(0),
00107         fHashKey(hk), 
00108         fAperture(calcTreeAperture(n,br)), 
00109         fVisitTime(0),
00110         fBranch(br) 
00111 { 
00112     // link dans la hash table
00113     int j = hk % kHashTableSize;
00114     fNext = gHashTable[j];
00115     gHashTable[j] = this;
00116 
00117 }
00118 
00119 // Destructor : remove the tree form the hash table
00120 CTree::~CTree () 
00121 {
00122     int     i = fHashKey % kHashTableSize;
00123     Tree    t = gHashTable[i];
00124     
00125     //printf("Delete of "); this->print(); printf("\n");
00126     if (t == this) {
00127         gHashTable[i] = fNext;
00128     } else {
00129         Tree p;
00130         while (t != this) {
00131             p = t;
00132             t = t->fNext;
00133         }
00134         p->fNext = fNext;
00135     }
00136 }
00137 
00138 // equivalence 
00139 bool CTree::equiv (const Node& n, const tvec& br) const
00140 {
00141     return (fNode == n) && (fBranch == br);
00142 }
00143 
00144 Sym PROCESS = symbol("process"); 
00145 
00146         
00147 
00148 
00149 unsigned int CTree::calcTreeHash( const Node& n, const tvec& br )
00150 {
00151     unsigned int            hk = n.type() ^ n.getInt();
00152     tvec::const_iterator  b = br.begin();
00153     tvec::const_iterator  z = br.end();
00154     
00155     while (b != z) {
00156         hk = (hk << 1) ^ (hk >> 20) ^ ((*b)->fHashKey);
00157         ++b;
00158     }
00159     return hk;
00160 }
00161 
00162 
00163 Tree CTree::make(const Node& n, int ar, Tree* tbl)
00164 {
00165     tvec    br(ar); 
00166     
00167     for (int i=0; i<ar; i++)  br[i] = tbl[i];
00168     
00169     unsigned int    hk  = calcTreeHash(n, br);
00170     Tree    t = gHashTable[hk % kHashTableSize];
00171     
00172     while (t && !t->equiv(n, br)) {
00173         t = t->fNext;
00174     }
00175     return (t) ? t : new CTree(hk, n, br);
00176 }
00177 
00178 
00179 Tree CTree::make(const Node& n, const tvec& br)
00180 {
00181     unsigned int    hk  = calcTreeHash(n, br);
00182     Tree    t = gHashTable[hk % kHashTableSize];
00183     
00184     while (t && !t->equiv(n, br)) {
00185         t = t->fNext;
00186     }
00187     return (t) ? t : new CTree(hk, n, br);
00188 }
00189 
00190 ostream& CTree::print (ostream& fout) const
00191 {
00192     if (gDetails) {
00193         // print the adresse of the tree
00194         fout << "<" << this << ">@"; 
00195     }
00196     fout << node();
00197     int a = arity();
00198     if (a > 0) {
00199         int i; char sep;
00200         for (sep = '[', i = 0; i < a; sep = ',', i++) {
00201             fout << sep; branch(i)->print(fout); 
00202         }
00203         fout << ']';
00204     } 
00205     
00206     return fout;
00207 }
00208 
00209 
00210 void CTree::control ()
00211 {
00212     printf("\ngHashTable Content :\n\n");
00213     for (int i = 0; i < kHashTableSize; i++) {
00214         Tree t = gHashTable[i];
00215         if (t) {
00216             printf ("%4d = ", i);
00217             while (t) {
00218                 /*t->print();*/
00219                 printf(" => ");
00220                 t = t->fNext;
00221             }
00222             printf("VOID\n");
00223         }
00224     }
00225     printf("\nEnd gHashTable\n");
00226 
00227 }
00228 
00229 // if t has a node of type int, return it otherwise error
00230 int tree2int (Tree t)
00231 {
00232     double  x;
00233     int     i;
00234 
00235     if (isInt(t->node(), &i)) {
00236         // nothing to do
00237     } else if (isDouble(t->node(), &x)) {
00238         i = int(x);
00239     } else {
00240         ERROR("the node of the tree is not an int nor a float", t);
00241     }
00242     return i;
00243 }   
00244     
00245 // if t has a node of type float, return it otherwise error
00246 double tree2float (Tree t)
00247 {
00248     double   x;
00249     int     i;
00250 
00251     if (isInt(t->node(), &i)) {
00252         x = double(i);
00253     } else if (isDouble(t->node(), &x)) {
00254         //nothing to do
00255     } else {
00256         ERROR("the node of the tree is not a float nor an int", t);
00257     }
00258     return x;
00259 }   
00260     
00261 // if t has a node of type float, return it as a double otherwise error
00262 double tree2double (Tree t)
00263 {
00264     double   x;
00265     int     i;
00266 
00267     if (isInt(t->node(), &i)) {
00268         x = double(i);
00269     } else if (isDouble(t->node(), &x)) {
00270         //nothing to do
00271     } else {
00272         ERROR("the node of the tree is not a float nor an int", t);
00273     }
00274     return double(x);
00275 }   
00276     
00277 // if t has a node of type symbol, return its name otherwise error      
00278 const char* tree2str (Tree t)
00279 {
00280     Sym s;
00281     if (!isSym(t->node(), &s)) {
00282         ERROR("the node of the tree is not a symbol", t);
00283     }
00284     return name(s);
00285 }   
00286 
00287 // if t has a node of type ptr, return it otherwise error           
00288 void* tree2ptr (Tree t)
00289 {
00290     void*   x;
00291     if (! isPointer(t->node(), &x)) {
00292         ERROR("the node of the tree is not a pointer", t);
00293     }
00294     return x;
00295 }   
00296             
00297 /*
00298 bool isTree (const Tree& t, const Node& n) 
00299 { 
00300     return (t->node() == n) && (t->arity() == 0);
00301 }
00302 */
00303 
00304 // Si ca ne pose pas de probl�es, c'est plus pratique 
00305 bool isTree (const Tree& t, const Node& n) 
00306 { 
00307     return (t->node() == n);
00308 }
00309 
00310 bool isTree (const Tree& t, const Node& n, Tree& a) 
00311 { 
00312     if ((t->node() == n) && (t->arity() == 1)) { 
00313         a=t->branch(0); 
00314         return true; 
00315     } else {
00316         return false;
00317     }
00318 }
00319 
00320 bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b)
00321 { 
00322     if ((t->node() == n) && (t->arity() == 2)) { 
00323         a=t->branch(0); 
00324         b=t->branch(1); 
00325         return true; 
00326     } else {
00327         return false;
00328     }
00329 }
00330 
00331 bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b, Tree& c) 
00332 { 
00333     if ((t->node() == n) && (t->arity() == 3)) { 
00334         a=t->branch(0); 
00335         b=t->branch(1); 
00336         c=t->branch(2); 
00337         return true; 
00338     } else {
00339         return false;
00340     }
00341 }
00342 
00343 bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b, Tree& c, Tree& d)  
00344 { 
00345     if ((t->node() == n) && (t->arity() == 4)) { 
00346         a=t->branch(0); 
00347         b=t->branch(1); 
00348         c=t->branch(2); 
00349         d=t->branch(3); 
00350         return true; 
00351     } else {
00352         return false;
00353     }
00354 }
00355 
00356 bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b, Tree& c, Tree& d, Tree& e)  
00357 { 
00358     if ((t->node() == n) && (t->arity() == 5)) { 
00359         a=t->branch(0); 
00360         b=t->branch(1); 
00361         c=t->branch(2); 
00362         d=t->branch(3); 
00363         e=t->branch(4); 
00364         return true; 
00365     } else {
00366         return false;
00367     }
00368 }
00369 
00370 // July 2005, support for symbol user data
00371 
00372 void* getUserData(Tree t)
00373 {
00374     Sym s;
00375     if (isSym(t->node(), &s)) {
00376         return getUserData(s);
00377     } else {
00378         return 0;
00379     }
00380 }
00381 
00382 
00388 void CTree::exportProperties(vector<Tree>& keys, vector<Tree>& values)
00389 {
00390     for (plist::const_iterator p = fProperties.begin(); p != fProperties.end(); p++) {
00391         keys.push_back(p->first);
00392         values.push_back(p->second);
00393     }
00394 }
00395