--- /dev/null
+/************************************************************************
+ ************************************************************************
+ FAUST compiler
+ Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ************************************************************************
+ ************************************************************************/
+
+
+
+/*****************************************************************************
+******************************************************************************
+ TREE
+ Y. Orlarey, (c) Grame 2002
+------------------------------------------------------------------------------
+Trees are made of a Node associated with a list of branches : (Node x [CTree]).
+Up to 4 branches are allowed in this implementation. A hash table is used to
+maximize the sharing of trees during construction : trees at different
+addresses always have a different content. Reference counting is used for
+garbage collection, and smart pointers P<CTree> should be used for permanent
+storage of trees.
+
+ API:
+ ----
+ tree (n) : tree of node n with no branch
+ tree (n, t1) : tree of node n with a branch t
+ tree (n, t1,...,tm) : tree of node n with m branches t1,...,tm
+
+ Pattern matching :
+
+ if (isTree (t, n)) ... : t has node n and no branches;
+ if (isTree (t, n, &t1) ... : t has node n and 1 branch, t1 is set accordingly;
+ if (isTree (t, n, &t1...&tm)...: t has node n and m branches, ti's are set accordingly;
+
+ Accessors :
+
+ t->node() : the node of t { return fNode; }
+ t->arity() : the number of branches of t return fArity; }
+ t->branch(i) : the ith branch of t
+
+ Attributs :
+
+ t->attribut() : return the attribut (also a tree) of t
+ t->attribut(t') : set the attribut of t to t'
+
+ Warning :
+ ---------
+ Since reference counters are used for garbage collecting, one must be careful not to
+ create cycles in trees The only possible source of cycles is by setting the attribut
+ of a tree t to a tree t' that contains t as a subtree.
+
+ Properties:
+ -----------
+ If p and q are two CTree pointers :
+ p != q <=> *p != *q
+
+ History :
+ ---------
+ 2002-02-08 : First version
+ 2002-10-14 : counts for height and recursiveness added
+
+******************************************************************************
+*****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include "tree.hh"
+#include <fstream>
+#include <cstdlib>
+
+Tabber TABBER(1);
+extern Tabber TABBER;
+
+
+static void error(const char * s, Tree t)
+{
+ //fprintf(stderr, "ERROR : %s (%p)\n", s, t);
+ cerr << "ERROR : " << s << " : " << *t << endl;
+}
+
+#define ERROR(s,t) { error(s,t); exit(1); }
+
+
+Tree CTree::gHashTable[kHashTableSize];
+bool CTree::gDetails = false;
+unsigned int CTree::gVisitTime = 0; ///< Should be incremented for each new visit to keep track of visited tree.
+
+// Constructor : add the tree to the hash table
+CTree::CTree (unsigned int hk, const Node& n, const tvec& br)
+ : fNode(n),
+ fType(0),
+ fHashKey(hk),
+ fAperture(calcTreeAperture(n,br)),
+ fVisitTime(0),
+ fBranch(br)
+{
+ // link dans la hash table
+ int j = hk % kHashTableSize;
+ fNext = gHashTable[j];
+ gHashTable[j] = this;
+
+}
+
+// Destructor : remove the tree form the hash table
+CTree::~CTree ()
+{
+ int i = fHashKey % kHashTableSize;
+ Tree t = gHashTable[i];
+
+ //printf("Delete of "); this->print(); printf("\n");
+ if (t == this) {
+ gHashTable[i] = fNext;
+ } else {
+ Tree p;
+ while (t != this) {
+ p = t;
+ t = t->fNext;
+ }
+ p->fNext = fNext;
+ }
+}
+
+// equivalence
+bool CTree::equiv (const Node& n, const tvec& br) const
+{
+ return (fNode == n) && (fBranch == br);
+}
+
+Sym PROCESS = symbol("process");
+
+
+
+
+unsigned int CTree::calcTreeHash( const Node& n, const tvec& br )
+{
+ unsigned int hk = n.type() ^ n.getInt();
+ tvec::const_iterator b = br.begin();
+ tvec::const_iterator z = br.end();
+
+ while (b != z) {
+ hk = (hk << 1) ^ (hk >> 20) ^ ((*b)->fHashKey);
+ ++b;
+ }
+ return hk;
+}
+
+
+Tree CTree::make(const Node& n, int ar, Tree* tbl)
+{
+ tvec br(ar);
+
+ for (int i=0; i<ar; i++) br[i] = tbl[i];
+
+ unsigned int hk = calcTreeHash(n, br);
+ Tree t = gHashTable[hk % kHashTableSize];
+
+ while (t && !t->equiv(n, br)) {
+ t = t->fNext;
+ }
+ return (t) ? t : new CTree(hk, n, br);
+}
+
+
+Tree CTree::make(const Node& n, const tvec& br)
+{
+ unsigned int hk = calcTreeHash(n, br);
+ Tree t = gHashTable[hk % kHashTableSize];
+
+ while (t && !t->equiv(n, br)) {
+ t = t->fNext;
+ }
+ return (t) ? t : new CTree(hk, n, br);
+}
+
+ostream& CTree::print (ostream& fout) const
+{
+ if (gDetails) {
+ // print the adresse of the tree
+ fout << "<" << this << ">@";
+ }
+ fout << node();
+ int a = arity();
+ if (a > 0) {
+ int i; char sep;
+ for (sep = '[', i = 0; i < a; sep = ',', i++) {
+ fout << sep; branch(i)->print(fout);
+ }
+ fout << ']';
+ }
+
+ return fout;
+}
+
+
+void CTree::control ()
+{
+ printf("\ngHashTable Content :\n\n");
+ for (int i = 0; i < kHashTableSize; i++) {
+ Tree t = gHashTable[i];
+ if (t) {
+ printf ("%4d = ", i);
+ while (t) {
+ /*t->print();*/
+ printf(" => ");
+ t = t->fNext;
+ }
+ printf("VOID\n");
+ }
+ }
+ printf("\nEnd gHashTable\n");
+
+}
+
+// if t has a node of type int, return it otherwise error
+int tree2int (Tree t)
+{
+ double x;
+ int i;
+
+ if (isInt(t->node(), &i)) {
+ // nothing to do
+ } else if (isDouble(t->node(), &x)) {
+ i = int(x);
+ } else {
+ ERROR("the node of the tree is not an int nor a float", t);
+ }
+ return i;
+}
+
+// if t has a node of type float, return it otherwise error
+double tree2float (Tree t)
+{
+ double x;
+ int i;
+
+ if (isInt(t->node(), &i)) {
+ x = double(i);
+ } else if (isDouble(t->node(), &x)) {
+ //nothing to do
+ } else {
+ ERROR("the node of the tree is not a float nor an int", t);
+ }
+ return x;
+}
+
+// if t has a node of type float, return it as a double otherwise error
+double tree2double (Tree t)
+{
+ double x;
+ int i;
+
+ if (isInt(t->node(), &i)) {
+ x = double(i);
+ } else if (isDouble(t->node(), &x)) {
+ //nothing to do
+ } else {
+ ERROR("the node of the tree is not a float nor an int", t);
+ }
+ return double(x);
+}
+
+// if t has a node of type symbol, return its name otherwise error
+const char* tree2str (Tree t)
+{
+ Sym s;
+ if (!isSym(t->node(), &s)) {
+ ERROR("the node of the tree is not a symbol", t);
+ }
+ return name(s);
+}
+
+// if t has a node of type ptr, return it otherwise error
+void* tree2ptr (Tree t)
+{
+ void* x;
+ if (! isPointer(t->node(), &x)) {
+ ERROR("the node of the tree is not a pointer", t);
+ }
+ return x;
+}
+
+/*
+bool isTree (const Tree& t, const Node& n)
+{
+ return (t->node() == n) && (t->arity() == 0);
+}
+*/
+
+// Si ca ne pose pas de probl�es, c'est plus pratique
+bool isTree (const Tree& t, const Node& n)
+{
+ return (t->node() == n);
+}
+
+bool isTree (const Tree& t, const Node& n, Tree& a)
+{
+ if ((t->node() == n) && (t->arity() == 1)) {
+ a=t->branch(0);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b)
+{
+ if ((t->node() == n) && (t->arity() == 2)) {
+ a=t->branch(0);
+ b=t->branch(1);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b, Tree& c)
+{
+ if ((t->node() == n) && (t->arity() == 3)) {
+ a=t->branch(0);
+ b=t->branch(1);
+ c=t->branch(2);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b, Tree& c, Tree& d)
+{
+ if ((t->node() == n) && (t->arity() == 4)) {
+ a=t->branch(0);
+ b=t->branch(1);
+ c=t->branch(2);
+ d=t->branch(3);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b, Tree& c, Tree& d, Tree& e)
+{
+ if ((t->node() == n) && (t->arity() == 5)) {
+ a=t->branch(0);
+ b=t->branch(1);
+ c=t->branch(2);
+ d=t->branch(3);
+ e=t->branch(4);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// July 2005, support for symbol user data
+
+void* getUserData(Tree t)
+{
+ Sym s;
+ if (isSym(t->node(), &s)) {
+ return getUserData(s);
+ } else {
+ return 0;
+ }
+}
+
+
+/**
+ * export the properties of a CTree as two vectors, one for the keys
+ * and one for the associated values
+ */
+
+void CTree::exportProperties(vector<Tree>& keys, vector<Tree>& values)
+{
+ for (plist::const_iterator p = fProperties.begin(); p != fProperties.end(); p++) {
+ keys.push_back(p->first);
+ values.push_back(p->second);
+ }
+}
+