FAUST compiler  0.9.9.6b8
list.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                                 LIST 
00027                         Y. Orlarey, (c) Grame 2002
00028 ------------------------------------------------------------------------------
00029 This file contains several extensions to the tree library : 
00030     - lists : based on a operations like cons, hd , tl, ... 
00031     - environments : list of associations (key value)
00032     - property list : used to annotate trees
00033 
00034 
00035  API:
00036  ---- 
00037 
00038     List :
00039     -----
00040     
00041     nil                 = predefined empty list
00042     cons (x,l)          = create a nex list of head x and tail l
00043     hd(cons(x,l))       = x, 
00044     tl (cons(x,l))      = l
00045     nth(l,i)            = ith element of l (or nil)
00046     replace(l,i,e)      = a copy of l where the ith element is e
00047     len(l)              = number of elements of l
00048     isNil(nil)          = true      (false otherwise)
00049     isList(cons(x,l))   = true      (false otherwise)
00050     list(a,b,..)        = cons(a, list(b,...))
00051     
00052     lmap(f, cons(x,l))  = cons(f(x), lmap(f,l))
00053     reverse([a,b,..,z]) = [z,..,b,a]
00054     reverseall([a,b,..,z])  = [ra(z),..,ra(b),ra(a)] where ra is reverseall
00055     
00056     Set :
00057     -----
00058     (Sets are implemented as ordered lists of elements without duplication)
00059     
00060     isElement(e,s)          = true if e is an element of set s, false otherwise
00061     addElement(e,s)         = s U {e}
00062     remElement(e,s)         = s - {e}
00063     singleton(e)            = {e}
00064     list2set(l)             = convert a list into a set 
00065     setUnion(s1,s2)         = s1 U s2
00066     setIntersection(s1,s2)  = s1 intersection s2
00067     setDifference(s1,s2)    = s1 - s2
00068     
00069     Environment : 
00070     -------------
00071     
00072     An 'environment' is a stack of pairs (key x value) used to keep track of lexical bindings
00073     
00074     pushEnv (key, val, env) -> env' create a new environment
00075     searchEnv (key,&v,env) -> bool  search for key in env and set v accordingly
00076     
00077     search(k1,&v, push(k2,x,env))   = true and v is set to x if k1==k2
00078                                     = search(k1,&v,env) if k1 != k2
00079     Property list :
00080     ---------------
00081     
00082     Every tree can be annotated with an 'attribut' field. This attribute field 
00083     can be used to manage a property list (pl). A property list is a list of pairs
00084     key x value, with three basic operations :
00085     
00086     setProperty (t, key, val) -> t      add the association (key x val) to the pl of t
00087     getProperty (t, key, &val) -> bool  search the pp of t for the value associated to key
00088     remProperty (t, key) -> t           remove any association (key x ?) from the pl of t
00089     
00090  Warning :
00091  ---------
00092  Since reference counters are used for garbage collecting, one must be careful not to 
00093  create cycles in trees. The only possible source of cycles is by setting the attribut
00094  of a tree t to a tree t' that contains t as a subtree.  
00095     
00096  History :
00097  ---------
00098     2002-02-08 : First version
00099     2002-02-20 : New description of the API, non recursive lmap and reverse
00100     2002-03-29 : Added function remElement(e,set), corrected comment error
00101     
00102 ******************************************************************************
00103 *****************************************************************************/
00104 
00105 #include <stdlib.h>
00106 #include "list.hh"
00107 #include "compatibility.hh"
00108 #include <map>
00109 #include <cstdlib>
00110 
00111 // predefined symbols CONS and NIL
00112 Sym CONS = symbol("cons");
00113 Sym NIL  = symbol("nil");
00114 
00115 // predefined nil tree
00116 Tree nil = tree(NIL);
00117 
00118 
00119 //------------------------------------------------------------------------------
00120 // Printing of trees with special case for lists
00121 //------------------------------------------------------------------------------
00122 
00123 static bool printlist (Tree l, FILE* out)
00124 {
00125     if (isList(l)) {
00126         
00127         char sep = '(';
00128         
00129         do {
00130             fputc(sep, out); sep = ',';
00131             print(hd(l));
00132             l = tl(l);
00133         } while (isList(l));
00134         
00135         if (! isNil(l)) {
00136             fprintf(out, " . ");
00137             print(l, out);
00138         }
00139         
00140         fputc(')', out);
00141         return true;
00142         
00143     } else if (isNil(l)) {
00144         
00145         fprintf(out, "nil");
00146         return true;
00147         
00148     } else {
00149         
00150         return false;
00151     }
00152 }
00153 
00154 void print (Tree t, FILE* out)
00155 {
00156     int i; double f; Sym s; void* p;
00157     
00158     if (printlist(t, out))      return;
00159     
00160     Node n = t->node();
00161          if (isInt(n, &i))      fprintf (out, "%d", i);
00162     else if (isDouble(n, &f))   fprintf (out, "%f", f);
00163     else if (isSym(n, &s))      fprintf (out, "%s", name(s));
00164     else if (isPointer(n, &p))  fprintf (out, "#%p", p);
00165     
00166     int k = t->arity();
00167     if (k > 0) {
00168         char sep = '[';
00169         for (int i=0; i<k; i++) {
00170             fputc(sep, out); sep = ',';
00171             print(t->branch(i), out);
00172         }
00173         fputc(']', out);
00174     } 
00175 }
00176 
00177 
00178 //------------------------------------------------------------------------------
00179 // Elements of list
00180 //------------------------------------------------------------------------------
00181 
00182 Tree nth (Tree l, int i)
00183 {
00184     while (isList(l)) {
00185         if (i == 0)  return hd(l);
00186         l = tl(l);
00187         i--;
00188     }
00189     return nil;
00190 }
00191 
00192 Tree replace(Tree l, int i, Tree e)
00193 {
00194     return (i==0) ? cons(e,tl(l)) : cons( hd(l), replace(tl(l),i-1,e) );
00195 }
00196 
00197 
00198 int len (Tree l)
00199 {
00200     int     n = 0;
00201     while (isList(l)) { l = tl(l); n++; }
00202     return n;
00203 }
00204 
00205 
00206 //------------------------------------------------------------------------------
00207 // Mapping and reversing
00208 //------------------------------------------------------------------------------
00209 
00210 Tree rconcat (Tree l, Tree q)
00211 {
00212     while (isList(l)) { q = cons(hd(l),q); l = tl(l); }
00213     return q;
00214 }
00215 
00216 Tree concat (Tree l, Tree q)
00217 {
00218     return rconcat(reverse(l), q);
00219 }
00220 
00221 Tree lrange (Tree l, int i, int j)
00222 {
00223     Tree    r = nil;
00224     int     c = j;
00225     while (c>i) r = cons( nth(l,--c), r);
00226     return r;
00227 }
00228 
00229 //------------------------------------------------------------------------------
00230 // Mapping and reversing
00231 //------------------------------------------------------------------------------
00232 
00233 static Tree rmap (tfun f, Tree l)
00234 {
00235     Tree r = nil;
00236     while (isList(l)) { r = cons(f(hd(l)),r); l = tl(l); }
00237     return r;
00238 }
00239 
00240 Tree reverse (Tree l)
00241 {
00242     Tree r = nil;
00243     while (isList(l)) { r = cons(hd(l),r); l = tl(l); }
00244     return r;
00245 }
00246 
00247 Tree lmap (tfun f, Tree l)
00248 {
00249     return reverse(rmap(f,l));
00250 }
00251 
00252 Tree reverseall (Tree l)
00253 {
00254     return isList(l) ? rmap(reverseall, l) : l;
00255 }
00256 
00257 
00258 //------------------------------------------------------------------------------
00259 // Sets : implemented as ordered list
00260 //------------------------------------------------------------------------------
00261 
00262 bool isElement (Tree e, Tree l)
00263 {
00264     while (isList(l)) {
00265         if (hd(l) == e) return true;
00266         if (hd(l) > e) return false;
00267         l = tl(l);
00268     }
00269     return false;
00270 }
00271 
00272 Tree addElement(Tree e, Tree l)
00273 {
00274     if (isList(l)) {
00275         if (e < hd(l)) {
00276             return cons(e,l);
00277         } else if (e == hd(l)) {
00278             return l;
00279         } else {
00280             return cons(hd(l), addElement(e,tl(l)));
00281         }
00282     } else {
00283         return cons(e,nil);
00284     }
00285 }
00286 
00287 Tree remElement(Tree e, Tree l)
00288 {
00289     if (isList(l)) {
00290         if (e < hd(l)) {
00291             return l;
00292         } else if (e == hd(l)) {
00293             return tl(l);
00294         } else {
00295             return cons(hd(l), remElement(e,tl(l)));
00296         }
00297     } else {
00298         return nil;
00299     }
00300 }
00301 
00302 Tree singleton (Tree e)
00303 {
00304     return list1(e);
00305 }
00306 
00307 Tree list2set (Tree l)
00308 {
00309     Tree s = nil;
00310     while (isList(l)) {
00311         s = addElement(hd(l),s);
00312         l = tl(l);
00313     }
00314     return s;
00315 }
00316 
00317 Tree setUnion (Tree A, Tree B)
00318 {
00319     if (isNil(A))       return B;
00320     if (isNil(B))       return A;
00321     
00322     if (hd(A) == hd(B)) return cons(hd(A), setUnion(tl(A),tl(B)));
00323     if (hd(A) < hd(B))  return cons(hd(A), setUnion(tl(A),B));
00324     /* hd(A) > hd(B) */ return cons(hd(B), setUnion(A,tl(B)));
00325 }
00326 
00327 Tree setIntersection (Tree A, Tree B)
00328 {
00329     if (isNil(A))       return A;
00330     if (isNil(B))       return B;
00331     if (hd(A) == hd(B)) return cons(hd(A), setIntersection(tl(A),tl(B)));
00332     if (hd(A) < hd(B))  return setIntersection(tl(A),B);
00333     /* (hd(A) > hd(B)*/ return setIntersection(A,tl(B));
00334 }
00335 
00336 Tree setDifference (Tree A, Tree B)
00337 {
00338     if (isNil(A))       return A;
00339     if (isNil(B))       return A;
00340     if (hd(A) == hd(B)) return setDifference(tl(A),tl(B));
00341     if (hd(A) < hd(B))  return cons(hd(A), setDifference(tl(A),B));
00342     /* (hd(A) > hd(B)*/ return setDifference(A,tl(B));
00343 }
00344     
00345         
00346 
00347 //------------------------------------------------------------------------------
00348 // Environments
00349 //------------------------------------------------------------------------------
00350 
00351 Tree pushEnv (Tree key, Tree val, Tree env)
00352 {
00353     return cons (cons(key,val), env);
00354 }
00355 
00356 bool searchEnv (Tree key, Tree& v, Tree env)
00357 {
00358     while (isList(env)) {
00359         if (hd(hd(env)) == key) {
00360             v = tl(hd(env));
00361             return true;
00362         }
00363         env = tl(env);
00364     }
00365     return false;
00366 }
00367 
00368 
00369 //------------------------------------------------------------------------------
00370 // Property list
00371 //------------------------------------------------------------------------------
00372 
00373 static bool findKey (Tree pl, Tree key, Tree& val)
00374 {
00375     if (isNil(pl))              return false;
00376     if (left(hd(pl)) == key)    { val= right(hd(pl)); return true; }
00377     /*  left(hd(pl)) != key */  return findKey (tl(pl), key, val); 
00378 }
00379 
00380 static Tree updateKey (Tree pl, Tree key, Tree val)
00381 {
00382     if (isNil(pl))              return cons ( cons(key,val), nil );
00383     if (left(hd(pl)) == key)    return cons ( cons(key,val), tl(pl) );
00384     /*  left(hd(pl)) != key */  return cons ( hd(pl), updateKey( tl(pl), key, val ));
00385 }
00386 
00387 static Tree removeKey (Tree pl, Tree key)
00388 {
00389     if (isNil(pl))              return nil;
00390     if (left(hd(pl)) == key)    return tl(pl);
00391     /*  left(hd(pl)) != key */  return cons (hd(pl), removeKey(tl(pl), key));
00392 }
00393 
00394 
00395 #if 0
00396 void setProperty (Tree t, Tree key, Tree val)
00397 {
00398     CTree* pl = t->attribut();
00399     if (pl) t->attribut(updateKey(pl, key, val)); 
00400     else    t->attribut(updateKey(nil, key, val));
00401 }
00402 
00403 void remProperty (Tree t, Tree key)
00404 {
00405     CTree* pl = t->attribut();
00406     if (pl) t->attribut(removeKey(pl, key));
00407 }
00408 
00409 bool getProperty (Tree t, Tree key, Tree& val)
00410 {
00411     CTree* pl = t->attribut();
00412     if (pl) return findKey(pl, key, val);
00413     else    return false;
00414 }
00415 
00416 #else
00417 // nouvelle implementation
00418 void setProperty (Tree t, Tree key, Tree val)
00419 {
00420     t->setProperty(key, val);
00421 }
00422 
00423 bool getProperty (Tree t, Tree key, Tree& val)
00424 {
00425     CTree* pl = t->getProperty(key);
00426     if (pl) {
00427         val = pl;
00428         return true;
00429     } else {
00430         return false;
00431     }
00432 }
00433 
00434 void remProperty (Tree t, Tree key)
00435 {
00436     exit(1); // fonction not implemented
00437 }
00438 #endif
00439 
00440 
00441 //------------------------------------------------------------------------------
00442 // Bottom Up Tree Mapping
00443 //------------------------------------------------------------------------------
00444 
00445 Tree tmap (Tree key, tfun f, Tree t)
00446 {   
00447     //printf("start tmap\n");
00448     Tree p; 
00449     
00450     if (getProperty(t, key, p)) {
00451         
00452         return (isNil(p)) ? t : p;  // truc pour eviter les boucles
00453         
00454     } else {
00455         
00456         Tree r1=nil;
00457         switch (t->arity()) {
00458             
00459             case 0 : 
00460                 r1 = t; 
00461                 break;
00462             case 1 : 
00463                 r1 = tree(t->node(), tmap(key,f,t->branch(0))); 
00464                 break;
00465             case 2 : 
00466                 r1 = tree(t->node(), tmap(key,f,t->branch(0)), tmap(key,f,t->branch(1))); 
00467                 break;
00468             case 3 : 
00469                 r1 = tree(t->node(), tmap(key,f,t->branch(0)), tmap(key,f,t->branch(1)),
00470                                            tmap(key,f,t->branch(2))); 
00471                 break;
00472             case 4 : 
00473                 r1 = tree(t->node(), tmap(key,f,t->branch(0)), tmap(key,f,t->branch(1)),
00474                                            tmap(key,f,t->branch(2)), tmap(key,f,t->branch(3))); 
00475                 break;
00476         }
00477         Tree r2 = f(r1);
00478         if (r2 == t) {
00479             setProperty(t, key, nil);
00480         } else {
00481             setProperty(t, key, r2);
00482         }
00483         return r2;
00484     }
00485 }
00486         
00487 
00488 
00489 
00490 
00491 //------------------------------------------------------------------------------
00492 // substitute :remplace toutes les occurences de 'id' par 'val' dans 't'
00493 //------------------------------------------------------------------------------
00494 
00495 // genere une clef unique propre � cette substitution
00496 static Tree substkey(Tree t, Tree id, Tree val) 
00497 {
00498     char    name[256];
00499     snprintf(name, 255, "SUBST<%p,%p,%p> : ", (CTree*)t, (CTree*)id, (CTree*)val);
00500     return tree(unique(name));
00501 }   
00502 
00503 // realise la substitution proprement dite tout en mettant � jour la propriete
00504 // pour ne pas avoir � la calculer deux fois
00505 
00506 static Tree subst (Tree t, Tree propkey, Tree id, Tree val)
00507 {
00508     Tree p;
00509     
00510     if (t==id) {
00511         return val;
00512         
00513     } else if (t->arity() == 0) {
00514         return t;
00515     } else if (getProperty(t, propkey, p)) {
00516         return (isNil(p)) ?  t : p;
00517     } else {
00518         Tree r=nil;
00519         switch (t->arity()) {
00520             
00521             case 1 : 
00522                 r = tree(t->node(), 
00523                             subst(t->branch(0), propkey, id, val)); 
00524                 break;
00525                 
00526             case 2 : 
00527                 r = tree(t->node(), 
00528                             subst(t->branch(0), propkey, id, val), 
00529                             subst(t->branch(1), propkey, id, val)); 
00530                 break;
00531                 
00532             case 3 : 
00533                 r = tree(t->node(), 
00534                             subst(t->branch(0), propkey, id, val), 
00535                             subst(t->branch(1), propkey, id, val), 
00536                             subst(t->branch(2), propkey, id, val)); 
00537                 break;
00538                 
00539             case 4 : 
00540                 r = tree(t->node(), 
00541                             subst(t->branch(0), propkey, id, val), 
00542                             subst(t->branch(1), propkey, id, val), 
00543                             subst(t->branch(2), propkey, id, val), 
00544                             subst(t->branch(3), propkey, id, val)); 
00545                 break;
00546             
00547         }
00548         if (r == t) {
00549             setProperty(t, propkey, nil);
00550         } else {
00551             setProperty(t, propkey, r);
00552         }
00553         return r;
00554     }
00555         
00556 }
00557 
00558 // remplace toutes les occurences de 'id' par 'val' dans 't'
00559 Tree substitute (Tree t, Tree id, Tree val)
00560 {
00561     return subst (t, substkey(t,id,val), id, val);
00562 }
00563     
00564     
00565     
00566 
00567