1 /************************************************************************
2 ************************************************************************
4 Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ************************************************************************
20 ************************************************************************/
24 /*****************************************************************************
25 ******************************************************************************
27 Y. Orlarey, (c) Grame 2002
28 ------------------------------------------------------------------------------
29 This file contains several extensions to the tree library :
30 - lists : based on a operations like cons, hd , tl, ...
31 - environments : list of associations (key value)
32 - property list : used to annotate trees
41 nil = predefined empty list
42 cons (x,l) = create a nex list of head x and tail l
45 nth(l,i) = ith element of l (or nil)
46 replace(l,i,e) = a copy of l where the ith element is e
47 len(l) = number of elements of l
48 isNil(nil) = true (false otherwise)
49 isList(cons(x,l)) = true (false otherwise)
50 list(a,b,..) = cons(a, list(b,...))
52 lmap(f, cons(x,l)) = cons(f(x), lmap(f,l))
53 reverse([a,b,..,z]) = [z,..,b,a]
54 reverseall([a,b,..,z]) = [ra(z),..,ra(b),ra(a)] where ra is reverseall
58 (Sets are implemented as ordered lists of elements without duplication)
60 isElement(e,s) = true if e is an element of set s, false otherwise
61 addElement(e,s) = s U {e}
62 remElement(e,s) = s - {e}
64 list2set(l) = convert a list into a set
65 setUnion(s1,s2) = s1 U s2
66 setIntersection(s1,s2) = s1 intersection s2
67 setDifference(s1,s2) = s1 - s2
72 An 'environment' is a stack of pairs (key x value) used to keep track of lexical bindings
74 pushEnv (key, val, env) -> env' create a new environment
75 searchEnv (key,&v,env) -> bool search for key in env and set v accordingly
77 search(k1,&v, push(k2,x,env)) = true and v is set to x if k1==k2
78 = search(k1,&v,env) if k1 != k2
82 Every tree can be annotated with an 'attribut' field. This attribute field
83 can be used to manage a property list (pl). A property list is a list of pairs
84 key x value, with three basic operations :
86 setProperty (t, key, val) -> t add the association (key x val) to the pl of t
87 getProperty (t, key, &val) -> bool search the pp of t for the value associated to key
88 remProperty (t, key) -> t remove any association (key x ?) from the pl of t
92 Since reference counters are used for garbage collecting, one must be careful not to
93 create cycles in trees. The only possible source of cycles is by setting the attribut
94 of a tree t to a tree t' that contains t as a subtree.
98 2002-02-08 : First version
99 2002-02-20 : New description of the API, non recursive lmap and reverse
100 2002-03-29 : Added function remElement(e,set), corrected comment error
102 ******************************************************************************
103 *****************************************************************************/
107 #include "compatibility.hh"
111 // predefined symbols CONS and NIL
112 Sym CONS
= symbol("cons");
113 Sym NIL
= symbol("nil");
115 // predefined nil tree
116 Tree nil
= tree(NIL
);
119 //------------------------------------------------------------------------------
120 // Printing of trees with special case for lists
121 //------------------------------------------------------------------------------
123 static bool printlist (Tree l
, FILE* out
)
130 fputc(sep
, out
); sep
= ',';
143 } else if (isNil(l
)) {
154 void print (Tree t
, FILE* out
)
156 int i
; double f
; Sym s
; void* p
;
158 if (printlist(t
, out
)) return;
161 if (isInt(n
, &i
)) fprintf (out
, "%d", i
);
162 else if (isDouble(n
, &f
)) fprintf (out
, "%f", f
);
163 else if (isSym(n
, &s
)) fprintf (out
, "%s", name(s
));
164 else if (isPointer(n
, &p
)) fprintf (out
, "#%p", p
);
169 for (int i
=0; i
<k
; i
++) {
170 fputc(sep
, out
); sep
= ',';
171 print(t
->branch(i
), out
);
178 //------------------------------------------------------------------------------
180 //------------------------------------------------------------------------------
182 Tree
nth (Tree l
, int i
)
185 if (i
== 0) return hd(l
);
192 Tree
replace(Tree l
, int i
, Tree e
)
194 return (i
==0) ? cons(e
,tl(l
)) : cons( hd(l
), replace(tl(l
),i
-1,e
) );
201 while (isList(l
)) { l
= tl(l
); n
++; }
206 //------------------------------------------------------------------------------
207 // Mapping and reversing
208 //------------------------------------------------------------------------------
210 Tree
rconcat (Tree l
, Tree q
)
212 while (isList(l
)) { q
= cons(hd(l
),q
); l
= tl(l
); }
216 Tree
concat (Tree l
, Tree q
)
218 return rconcat(reverse(l
), q
);
221 Tree
lrange (Tree l
, int i
, int j
)
225 while (c
>i
) r
= cons( nth(l
,--c
), r
);
229 //------------------------------------------------------------------------------
230 // Mapping and reversing
231 //------------------------------------------------------------------------------
233 static Tree
rmap (tfun f
, Tree l
)
236 while (isList(l
)) { r
= cons(f(hd(l
)),r
); l
= tl(l
); }
240 Tree
reverse (Tree l
)
243 while (isList(l
)) { r
= cons(hd(l
),r
); l
= tl(l
); }
247 Tree
lmap (tfun f
, Tree l
)
249 return reverse(rmap(f
,l
));
252 Tree
reverseall (Tree l
)
254 return isList(l
) ? rmap(reverseall
, l
) : l
;
258 //------------------------------------------------------------------------------
259 // Sets : implemented as ordered list
260 //------------------------------------------------------------------------------
262 bool isElement (Tree e
, Tree l
)
265 if (hd(l
) == e
) return true;
266 if (hd(l
) > e
) return false;
272 Tree
addElement(Tree e
, Tree l
)
277 } else if (e
== hd(l
)) {
280 return cons(hd(l
), addElement(e
,tl(l
)));
287 Tree
remElement(Tree e
, Tree l
)
292 } else if (e
== hd(l
)) {
295 return cons(hd(l
), remElement(e
,tl(l
)));
302 Tree
singleton (Tree e
)
307 Tree
list2set (Tree l
)
311 s
= addElement(hd(l
),s
);
317 Tree
setUnion (Tree A
, Tree B
)
319 if (isNil(A
)) return B
;
320 if (isNil(B
)) return A
;
322 if (hd(A
) == hd(B
)) return cons(hd(A
), setUnion(tl(A
),tl(B
)));
323 if (hd(A
) < hd(B
)) return cons(hd(A
), setUnion(tl(A
),B
));
324 /* hd(A) > hd(B) */ return cons(hd(B
), setUnion(A
,tl(B
)));
327 Tree
setIntersection (Tree A
, Tree B
)
329 if (isNil(A
)) return A
;
330 if (isNil(B
)) return B
;
331 if (hd(A
) == hd(B
)) return cons(hd(A
), setIntersection(tl(A
),tl(B
)));
332 if (hd(A
) < hd(B
)) return setIntersection(tl(A
),B
);
333 /* (hd(A) > hd(B)*/ return setIntersection(A
,tl(B
));
336 Tree
setDifference (Tree A
, Tree B
)
338 if (isNil(A
)) return A
;
339 if (isNil(B
)) return A
;
340 if (hd(A
) == hd(B
)) return setDifference(tl(A
),tl(B
));
341 if (hd(A
) < hd(B
)) return cons(hd(A
), setDifference(tl(A
),B
));
342 /* (hd(A) > hd(B)*/ return setDifference(A
,tl(B
));
347 //------------------------------------------------------------------------------
349 //------------------------------------------------------------------------------
351 Tree
pushEnv (Tree key
, Tree val
, Tree env
)
353 return cons (cons(key
,val
), env
);
356 bool searchEnv (Tree key
, Tree
& v
, Tree env
)
358 while (isList(env
)) {
359 if (hd(hd(env
)) == key
) {
369 //------------------------------------------------------------------------------
371 //------------------------------------------------------------------------------
373 static bool findKey (Tree pl
, Tree key
, Tree
& val
)
375 if (isNil(pl
)) return false;
376 if (left(hd(pl
)) == key
) { val
= right(hd(pl
)); return true; }
377 /* left(hd(pl)) != key */ return findKey (tl(pl
), key
, val
);
380 static Tree
updateKey (Tree pl
, Tree key
, Tree val
)
382 if (isNil(pl
)) return cons ( cons(key
,val
), nil
);
383 if (left(hd(pl
)) == key
) return cons ( cons(key
,val
), tl(pl
) );
384 /* left(hd(pl)) != key */ return cons ( hd(pl
), updateKey( tl(pl
), key
, val
));
387 static Tree
removeKey (Tree pl
, Tree key
)
389 if (isNil(pl
)) return nil
;
390 if (left(hd(pl
)) == key
) return tl(pl
);
391 /* left(hd(pl)) != key */ return cons (hd(pl
), removeKey(tl(pl
), key
));
396 void setProperty (Tree t
, Tree key
, Tree val
)
398 CTree
* pl
= t
->attribut();
399 if (pl
) t
->attribut(updateKey(pl
, key
, val
));
400 else t
->attribut(updateKey(nil
, key
, val
));
403 void remProperty (Tree t
, Tree key
)
405 CTree
* pl
= t
->attribut();
406 if (pl
) t
->attribut(removeKey(pl
, key
));
409 bool getProperty (Tree t
, Tree key
, Tree
& val
)
411 CTree
* pl
= t
->attribut();
412 if (pl
) return findKey(pl
, key
, val
);
417 // nouvelle implementation
418 void setProperty (Tree t
, Tree key
, Tree val
)
420 t
->setProperty(key
, val
);
423 bool getProperty (Tree t
, Tree key
, Tree
& val
)
425 CTree
* pl
= t
->getProperty(key
);
434 void remProperty (Tree t
, Tree key
)
436 exit(1); // fonction not implemented
441 //------------------------------------------------------------------------------
442 // Bottom Up Tree Mapping
443 //------------------------------------------------------------------------------
445 Tree
tmap (Tree key
, tfun f
, Tree t
)
447 //printf("start tmap\n");
450 if (getProperty(t
, key
, p
)) {
452 return (isNil(p
)) ? t
: p
; // truc pour eviter les boucles
457 switch (t
->arity()) {
463 r1
= tree(t
->node(), tmap(key
,f
,t
->branch(0)));
466 r1
= tree(t
->node(), tmap(key
,f
,t
->branch(0)), tmap(key
,f
,t
->branch(1)));
469 r1
= tree(t
->node(), tmap(key
,f
,t
->branch(0)), tmap(key
,f
,t
->branch(1)),
470 tmap(key
,f
,t
->branch(2)));
473 r1
= tree(t
->node(), tmap(key
,f
,t
->branch(0)), tmap(key
,f
,t
->branch(1)),
474 tmap(key
,f
,t
->branch(2)), tmap(key
,f
,t
->branch(3)));
479 setProperty(t
, key
, nil
);
481 setProperty(t
, key
, r2
);
491 //------------------------------------------------------------------------------
492 // substitute :remplace toutes les occurences de 'id' par 'val' dans 't'
493 //------------------------------------------------------------------------------
495 // genere une clef unique propre � cette substitution
496 static Tree
substkey(Tree t
, Tree id
, Tree val
)
499 snprintf(name
, 255, "SUBST<%p,%p,%p> : ", (CTree
*)t
, (CTree
*)id
, (CTree
*)val
);
500 return tree(unique(name
));
503 // realise la substitution proprement dite tout en mettant � jour la propriete
504 // pour ne pas avoir � la calculer deux fois
506 static Tree
subst (Tree t
, Tree propkey
, Tree id
, Tree val
)
513 } else if (t
->arity() == 0) {
515 } else if (getProperty(t
, propkey
, p
)) {
516 return (isNil(p
)) ? t
: p
;
519 switch (t
->arity()) {
523 subst(t
->branch(0), propkey
, id
, val
));
528 subst(t
->branch(0), propkey
, id
, val
),
529 subst(t
->branch(1), propkey
, id
, val
));
534 subst(t
->branch(0), propkey
, id
, val
),
535 subst(t
->branch(1), propkey
, id
, val
),
536 subst(t
->branch(2), propkey
, id
, val
));
541 subst(t
->branch(0), propkey
, id
, val
),
542 subst(t
->branch(1), propkey
, id
, val
),
543 subst(t
->branch(2), propkey
, id
, val
),
544 subst(t
->branch(3), propkey
, id
, val
));
549 setProperty(t
, propkey
, nil
);
551 setProperty(t
, propkey
, r
);
558 // remplace toutes les occurences de 'id' par 'val' dans 't'
559 Tree
substitute (Tree t
, Tree id
, Tree val
)
561 return subst (t
, substkey(t
,id
,val
), id
, val
);
569 //------------------------------------------------------------------------------
570 // Fun : implementation of functions as set of pairs (key x value)
571 // such that key are uniques : forall (k1,v1) and (k2,v2) in F, k1=k2 ==> v1=v2
572 // Uses the order on key to speedup search
573 //------------------------------------------------------------------------------
576 * Add a pair key x value to "function" l
578 Tree
addFun(Tree k
, Tree v
, Tree l
)
583 return cons(cons(k
,v
),l
);
585 return cons(cons(k
,v
),tl(l
));
587 return cons(hd(l
), addFun(k
,v
,tl(l
)));
590 return cons(cons(k
,v
),nil
);
595 * Get value associated to key k in "function" l
596 * returns true if a value was found.
599 bool getFun(Tree k
, Tree
& v
, Tree l
)
612 return getFun(k
,v
,tl(l
));