diff --git a/hist/inc/TF1.h b/hist/inc/TF1.h
index f5444186daa3114b0331a02dc1f3bba7724ade14..be0a6bc8fd7784f590ec021afa5193362e5fe87e 100644
--- a/hist/inc/TF1.h
+++ b/hist/inc/TF1.h
@@ -1,4 +1,4 @@
-// @(#)root/hist:$Name:  $:$Id: TF1.h,v 1.34 2003/05/06 13:14:46 brun Exp $
+// @(#)root/hist:$Name:  $:$Id: TF1.h,v 1.35 2003/05/15 13:56:29 brun Exp $
 // Author: Rene Brun   18/08/95
 
 /*************************************************************************
@@ -83,6 +83,7 @@ public:
    TF1(const char *name, void *fcn, Double_t xmin, Double_t xmax, Int_t npar);
    TF1(const char *name, Double_t (*fcn)(Double_t *, Double_t *), Double_t xmin=0, Double_t xmax=1, Int_t npar=0);
    TF1(const TF1 &f1);
+   TF1& operator=(const TF1 &rhs);
    virtual   ~TF1();
    virtual void     Browse(TBrowser *b);
    virtual void     Copy(TObject &f1) const;
diff --git a/hist/inc/TF2.h b/hist/inc/TF2.h
index bc160cc3372e7f2f9ac0193f6199fb7682782ce3..c82d1faa9d9a5e6a94c9f3075e9e62ad28aa5514 100644
--- a/hist/inc/TF2.h
+++ b/hist/inc/TF2.h
@@ -1,4 +1,4 @@
-// @(#)root/hist:$Name:  $:$Id: TF2.h,v 1.14 2003/01/15 21:45:39 brun Exp $
+// @(#)root/hist:$Name:  $:$Id: TF2.h,v 1.15 2003/03/31 16:04:35 brun Exp $
 // Author: Rene Brun   23/08/95
 
 /*************************************************************************
@@ -44,6 +44,7 @@ public:
    TF2(const char *name, void *fcn, Double_t xmin=0, Double_t xmax=1, Double_t ymin=0, Double_t ymax=1, Int_t npar=0);
    TF2(const char *name, Double_t (*fcn)(Double_t *, Double_t *), Double_t xmin=0, Double_t xmax=1, Double_t ymin=0, Double_t ymax=1, Int_t npar=0);
    TF2(const TF2 &f2);
+   TF2 &operator=(const TF2& rhs);
    virtual   ~TF2();
    virtual void     Copy(TObject &f2) const;
    virtual Int_t    DistancetoPrimitive(Int_t px, Int_t py);
diff --git a/hist/inc/TF3.h b/hist/inc/TF3.h
index b5a759f5926f5e021819d5cf73d01b2633649a32..f1f97f24af684af215a07e62d6c7f4840dece105 100644
--- a/hist/inc/TF3.h
+++ b/hist/inc/TF3.h
@@ -1,4 +1,4 @@
-// @(#)root/hist:$Name:  $:$Id: TF3.h,v 1.9 2002/12/02 18:50:03 rdm Exp $
+// @(#)root/hist:$Name:  $:$Id: TF3.h,v 1.10 2003/03/31 16:04:35 brun Exp $
 // Author: Rene Brun   27/10/95
 
 /*************************************************************************
@@ -44,6 +44,7 @@ public:
        Double_t ymax=1, Double_t zmin=0, Double_t zmax=1, Int_t npar=0);
 
    TF3(const TF3 &f3);
+   TF3& operator=(const TF3 &rhs);
    virtual   ~TF3();
    virtual void     Copy(TObject &f3) const;
    virtual Int_t    DistancetoPrimitive(Int_t px, Int_t py);
diff --git a/hist/inc/TFormula.h b/hist/inc/TFormula.h
index 4f93027a7db0697a214ca2f6db234fee9c8f065d..d6a34e5efdd71aa22d7f8631de4592a8e5c82277 100644
--- a/hist/inc/TFormula.h
+++ b/hist/inc/TFormula.h
@@ -1,4 +1,4 @@
-// @(#)root/hist:$Name:  $:$Id: TFormula.h,v 1.19 2003/06/17 20:07:33 brun Exp $
+// @(#)root/hist:$Name:  $:$Id: TFormula.h,v 1.20 2003/06/18 16:48:28 brun Exp $
 // Author: Nicolas Brun   19/08/95
 
 /*************************************************************************
@@ -54,9 +54,10 @@ protected:
    TObjArray  fFunctions;       //Array of function calls to make
    TBits      fAlreadyFound;    //! cache for information
 
-   void       ClearFormula(Option_t *option="");
-   Bool_t     IsInitialized() { return TestBit(kInitialized); }
-   Int_t      GetOperType(Int_t oper) const;
+           void    ClearFormula(Option_t *option="");
+           Bool_t  IsInitialized() { return TestBit(kInitialized); }
+           Int_t   GetOperType(Int_t oper) const;
+   virtual Bool_t  IsString(Int_t oper) const;
 
    enum {
       kConstants    =  50000,
@@ -76,6 +77,7 @@ public:
               TFormula();
               TFormula(const char *name,const char *formula);
               TFormula(const TFormula &formula);
+   TFormula& operator=(const TFormula &rhs);
    virtual   ~TFormula();
 
  public:
diff --git a/hist/src/TF1.cxx b/hist/src/TF1.cxx
index d93839ae8114639c0a37e3b32f4d7196d60d4aff..382e6d8488c66031c6fcad728b49ffcc201bfedb 100644
--- a/hist/src/TF1.cxx
+++ b/hist/src/TF1.cxx
@@ -1,4 +1,4 @@
-// @(#)root/hist:$Name:  $:$Id: TF1.cxx,v 1.63 2003/05/21 20:13:09 brun Exp $
+// @(#)root/hist:$Name:  $:$Id: TF1.cxx,v 1.64 2003/06/10 16:45:57 brun Exp $
 // Author: Rene Brun   18/08/95
 
 /*************************************************************************
@@ -454,6 +454,15 @@ TF1::TF1(const char *name,Double_t (*fcn)(Double_t *, Double_t *), Double_t xmin
 
 }
 
+//______________________________________________________________________________
+TF1& TF1::operator=(const TF1 &rhs) 
+{
+   if (this != &rhs) {
+      rhs.Copy(*this);
+   }
+   return *this;
+}
+
 //______________________________________________________________________________
 TF1::~TF1()
 {
diff --git a/hist/src/TF2.cxx b/hist/src/TF2.cxx
index 31ba9f0b6a6e8952f755332596b35e22e56d12c8..5de5b868303fcd90816c2f14fee61cdf314f047a 100644
--- a/hist/src/TF2.cxx
+++ b/hist/src/TF2.cxx
@@ -1,4 +1,4 @@
-// @(#)root/hist:$Name:  $:$Id: TF2.cxx,v 1.19 2003/03/31 16:04:35 brun Exp $
+// @(#)root/hist:$Name:  $:$Id: TF2.cxx,v 1.20 2003/04/20 20:03:04 brun Exp $
 // Author: Rene Brun   23/08/95
 
 /*************************************************************************
@@ -117,6 +117,15 @@ TF2::TF2(const char *name, Double_t (*fcn)(Double_t *, Double_t *), Double_t xmi
 
 }
 
+//______________________________________________________________________________
+TF2& TF2::operator=(const TF2 &rhs)
+{
+   if (this != &rhs) {
+      rhs.Copy(*this);
+   }
+   return *this;
+}
+
 //______________________________________________________________________________
 TF2::~TF2()
 {
diff --git a/hist/src/TF3.cxx b/hist/src/TF3.cxx
index e0ec80d1968c4d0d6640fb9bc5ec49a07eb019c8..ead667df666b4a386a6f93c49b9f00bd3385cf6c 100644
--- a/hist/src/TF3.cxx
+++ b/hist/src/TF3.cxx
@@ -1,4 +1,4 @@
-// @(#)root/hist:$Name:  $:$Id: TF3.cxx,v 1.9 2002/10/31 07:27:36 brun Exp $
+// @(#)root/hist:$Name:  $:$Id: TF3.cxx,v 1.10 2003/03/31 16:04:35 brun Exp $
 // Author: Rene Brun   27/10/95
 
 /*************************************************************************
@@ -98,6 +98,15 @@ TF3::TF3(const char *name,Double_t (*fcn)(Double_t *, Double_t *), Double_t xmin
    fNdim   = 3;
 }
 
+//______________________________________________________________________________
+TF3& TF3::operator=(const TF3 &rhs) 
+{
+   if (this != &rhs) {
+      rhs.Copy(*this);
+   }
+   return *this;
+}
+
 //______________________________________________________________________________
 TF3::~TF3()
 {
diff --git a/hist/src/TFormula.cxx b/hist/src/TFormula.cxx
index ab010594199bce68423f2a45a8dcf076e26c88bf..20180c3a2edcc389f3186bcf8e9311602c555c9c 100644
--- a/hist/src/TFormula.cxx
+++ b/hist/src/TFormula.cxx
@@ -1,4 +1,4 @@
-// @(#)root/hist:$Name:  $:$Id: TFormula.cxx,v 1.43 2003/06/21 13:27:19 brun Exp $
+// @(#)root/hist:$Name:  $:$Id: TFormula.cxx,v 1.44 2003/06/26 17:44:29 rdm Exp $
 // Author: Nicolas Brun   19/08/95
 
 /*************************************************************************
@@ -164,6 +164,15 @@ TFormula::TFormula(const TFormula &formula) : TNamed()
    ((TFormula&)formula).Copy(*this);
 }
 
+//______________________________________________________________________________
+TFormula& TFormula::operator=(const TFormula &rhs) 
+{
+   if (this != &rhs) {
+      rhs.Copy(*this);
+   }
+   return *this;
+}
+
 //______________________________________________________________________________
 TFormula::~TFormula()
 {
@@ -175,7 +184,6 @@ TFormula::~TFormula()
    ClearFormula();
 }
 
-
 //______________________________________________________________________________
 Bool_t TFormula::AnalyzeFunction(TString &chaine, Int_t &err, Int_t offset)
 {
@@ -404,7 +412,7 @@ void TFormula::Analyze(const char *schain, Int_t &err, Int_t offset)
 //*-*
 //*-*   * strings :
 //*-*
-//*-*    s0  80000      s1  80001  etc..
+//*-*    sX  80000      (80001 to 99999) to not used yet
 //*-*
 //*-*   * variables :
 //*-*
@@ -879,8 +887,8 @@ if (err==0) {
           if (find == 0) {
 //*-*- Check if chaine is a defined variable.
 //*-*- Note that DefinedVariable can be overloaded
-  	       ctemp = chaine;
-	       ctemp.ReplaceAll(escapedSlash, slash);
+  	            ctemp = chaine;
+               ctemp.ReplaceAll(escapedSlash, slash);
                k = DefinedVariable(ctemp);
                if (k >= 5000 && k < 10000) {
                   fExpr[fNoper] = ctemp;
@@ -1490,7 +1498,7 @@ if (err==0) {
             if (chaine(0,1)=="\"" && chaine(chaine.Length()-1,1)=="\"") {
                //*-* It is a string !!!
                fExpr[fNoper] = chaine(1,chaine.Length()-2);
-               fOper[fNoper] = 80000;
+               fOper[fNoper] = kStrings;
                fNoper++;
             }
             else {
@@ -1776,42 +1784,43 @@ Int_t TFormula::Compile(const char *expression)
   Int_t is_it_string,last_string=0,before_last_string=0;
   if (!fOper) fNoper = 0;
    enum { kIsCharacter = BIT(12) };
-  for (i=0; i<fNoper; i++) {
-     is_it_string = 0;
-     if ((fOper[i]>=105000 && fOper[i]<110000) || fOper[i] == 80000) is_it_string = 1;
-     else if (last_string) {
-
-       if (fOper[i] == 62) {
-          if (!before_last_string) {
-             Error("Compile", "Both operands of the operator == have to be either numbers or strings");
-             return -1;
-          }
-          fOper[i] = 76;
-          SetBit(kIsCharacter);
-       } else if (fOper[i] == 63) {
-          if (!before_last_string) {
-             Error("Compile", "Both operands of the operator != have to be either numbers or strings");
-             return -1;
-          }
-          fOper[i] = 77;
-          SetBit(kIsCharacter);
-       }
-       else if (fOper[i] == 23) {
-          if (! (before_last_string && last_string) ) {
-             Error("Compile", "strstr requires 2 string arguments");
-             return -1;
-          }
-          SetBit(kIsCharacter);
-       } else if (before_last_string) {
-          // the i-2 element is a string not used in a string operation, let's down grade it
-          // to a char array:
-          if (fOper[i-2]>=105000) {
-            fOper[i-2] -= 5000;
-            fNval++;
-            fNstring--;
-          }
-       }
-
+  for (i=0; i<fNoper; i++,
+                      before_last_string = last_string,
+                      last_string = is_it_string) {
+     is_it_string = IsString(i);
+     if (is_it_string) continue;
+     if (last_string) {
+        if (fOper[i] == 62) {
+           if (!before_last_string) {
+              Error("Compile", "Both operands of the operator == have to be either numbers or strings");
+              return -1;
+           }
+           fOper[i] = 76;
+           SetBit(kIsCharacter);
+        } else if (fOper[i] == 63) {
+           if (!before_last_string) {
+              Error("Compile", "Both operands of the operator != have to be either numbers or strings");
+              return -1;
+           }
+           fOper[i] = 77;
+           SetBit(kIsCharacter);
+        }
+        else if (fOper[i] == 23) {
+           if (! (before_last_string && last_string) ) {
+              Error("Compile", "strstr requires 2 string arguments");
+              return -1;
+           }
+           SetBit(kIsCharacter);
+        } else if (before_last_string) {
+           // the i-2 element is a string not used in a string operation, let's down grade it
+           // to a char array:
+           if (fOper[i-2]>=105000) {
+              fOper[i-2] -= 5000;
+              fNval++;
+              fNstring--;
+           }
+        }
+        
      } else if (before_last_string) {
         // the i-2 element is a string not used in a string operation, let's down grade it
         // to a char array:
@@ -1821,8 +1830,6 @@ Int_t TFormula::Compile(const char *expression)
            fNstring--;
         }
      }
-     before_last_string = last_string;
-     last_string = is_it_string;
   }
 
   if (err) { fNdim = 0; return 1; }
@@ -2097,7 +2104,7 @@ Double_t TFormula::EvalPar(const Double_t *x, const Double_t *params)
        continue;
     }
 //*-*- String
-    if (action == 80000) {
+    if (action == kStrings) {
        pos2++; tab2[pos2-1] = (char*)fExpr[i].Data();
        continue;
     }
@@ -2408,6 +2415,15 @@ Int_t TFormula::GetParNumber(const char *parName) const
   return -1;
 }
 
+//______________________________________________________________________________
+Bool_t TFormula::IsString(Int_t oper) const
+{
+   // return true if the expression at the index 'oper' is to be treated as 
+   // as string
+
+   return fOper[oper] == kStrings;
+}
+
 //______________________________________________________________________________
 void TFormula::Print(Option_t *) const
 {
diff --git a/test/dt_DrawTest.C b/test/dt_DrawTest.C
index bd794e725c0293e4353fd2167d2d9fdebbdcc26b..d32e323e15322b892ce18b760c60824656b53434 100644
--- a/test/dt_DrawTest.C
+++ b/test/dt_DrawTest.C
@@ -105,6 +105,8 @@ TDirectory* GenerateDrawHist(TTree *tree,int level = 2, int quietLevel = 0)
    tree->Draw("fNpoint>>hNpoint","fPx < 0","goff");
    tree->Draw("fValid>>hValid",  "fPx < 0","goff");
    DrawSkippable(tree,"fPointValue","hPointValue", gBranchStyle!=0);
+   tree->SetAlias("mult","fPx*fPy");
+   DrawSkippable(tree,"fEvtHdr.fEvtNum*6+mult", "hAlias", 1);
 
    tree->Draw("fMatrix>>hFullMatrix","","goff");
    tree->Draw("fMatrix[][0]>>hColMatrix","","goff");
@@ -137,6 +139,8 @@ TDirectory* GenerateDrawHist(TTree *tree,int level = 2, int quietLevel = 0)
    // Test string operations
    DrawSkippable(tree,"fEvtHdr.fEvtNum","fType==\"type1\" ","hString",(level>0));
    DrawSkippable(tree,"fEvtHdr.fEvtNum","strstr(fType,\"1\") ","+hString",(level>0));
+   tree->SetAlias("typ","fType");
+   DrawSkippable(tree,"strstr(typ,\"1\") ", "hAliasStr", 1);
 
    // Test binary operators
    DrawSkippable(tree,"fValid<<4","hShiftValid",(level>0));
diff --git a/test/dt_MakeRef.C b/test/dt_MakeRef.C
index ce34ad47321d071cbf1e81daf4d79194980812b3..a27a39c13e6a0b2b1f692e51fbe77248028fdfea 100644
--- a/test/dt_MakeRef.C
+++ b/test/dt_MakeRef.C
@@ -70,6 +70,7 @@ void MakeHisto(TTree *tree, TDirectory* To) {
    TH1F *refNpoint = RefClone(where,"hNpoint");
    TH1F *refValid  = RefClone(where,"hValid");
    TH1F *refPointValue  = RefClone(where,"hPointValue");
+   TH1F *refAlias  = RefClone(where,"hAlias");
 
    TH1F *refFullMatrix   = RefClone(where,"hFullMatrix");
    TH1F *refColMatrix    = RefClone(where,"hColMatrix");
@@ -97,6 +98,7 @@ void MakeHisto(TTree *tree, TDirectory* To) {
    TH1F *refAndValid = RefClone(where,"hAndValid");
 
    TH1F *refString = RefClone(where,"hString");
+   TH1F *refAliasStr = RefClone(where,"hAliasStr");
 
    TH1F *refPxBx = RefClone(where,"hPxBx");
    TH1F *refPxBxWeight =  RefClone(where,"hPxBxWeight");
@@ -140,8 +142,10 @@ void MakeHisto(TTree *tree, TDirectory* To) {
       
       if (!strcmp("type1",event->GetType())) 
         refString->Fill(event->GetHeader()->GetEvtNum());
-      if (strstr(event->GetType(),"1"))
+      if (strstr(event->GetType(),"1")) {
         refString->Fill(event->GetHeader()->GetEvtNum());
+      }
+      refAliasStr->Fill(strstr(event->GetType(),"1")!=0);
 
       Nvertex = event->GetNvertex();
       for(i0=0;i0<Nvertex;i0++) {
@@ -250,6 +254,8 @@ void MakeHisto(TTree *tree, TDirectory* To) {
          }
          if (bits.TestBitNumber(5)) refFiltTrackTrigger->Fill(t->GetPx());
          refBreit->Fill(TMath::BreitWigner(t->GetPx(),3,2));
+
+         refAlias->Fill(head->GetEvtNum()*6+t->GetPx()*t->GetPy());
       }
    }
 
diff --git a/tree/inc/TChain.h b/tree/inc/TChain.h
index 54bc710910363b8f20fc12ffe3635dc131f73a8f..2a3f8b5c14b6226f62637753eda91ba9588f3373 100644
--- a/tree/inc/TChain.h
+++ b/tree/inc/TChain.h
@@ -1,4 +1,4 @@
-// @(#)root/tree:$Name:  $:$Id: TChain.h,v 1.30 2003/03/19 14:01:50 rdm Exp $
+// @(#)root/tree:$Name:  $:$Id: TChain.h,v 1.31 2003/06/24 14:00:59 brun Exp $
 // Author: Rene Brun   03/02/97
 
 /*************************************************************************
@@ -82,6 +82,7 @@ public:
     TObjArray        *GetListOfBranches();
     TObjArray        *GetListOfFiles() const {return fFiles;}
     TObjArray        *GetListOfLeaves();
+    const char       *GetAlias(const char *aliasName) const;
     virtual Double_t  GetMaximum(const char *columname);
     virtual Double_t  GetMinimum(const char *columname);
     virtual Int_t     GetNbranches();
diff --git a/tree/inc/TTree.h b/tree/inc/TTree.h
index 8e019830547a519ff5538cc1f1d3be97a2b9c551..bbd5632467911e86bfabc3764066eba15402ef54 100644
--- a/tree/inc/TTree.h
+++ b/tree/inc/TTree.h
@@ -1,4 +1,4 @@
-// @(#)root/tree:$Name:  $:$Id: TTree.h,v 1.45 2003/01/17 17:48:56 brun Exp $
+// @(#)root/tree:$Name:  $:$Id: TTree.h,v 1.46 2003/03/19 14:01:50 rdm Exp $
 // Author: Rene Brun   12/01/96
 
 /*************************************************************************
@@ -111,6 +111,7 @@ protected:
     TDirectory   *fDirectory;         //! Pointer to directory holding this tree
     TObjArray     fBranches;          //  List of Branches
     TObjArray     fLeaves;            //  Direct pointers to individual branch leaves
+    TList        *fAliases;           //  List of aliases for expressions based on the tree branches.
     TEventList   *fEventList;         //! Pointer to event selection list (if one)
     TArrayD       fIndexValues;       //  Sorted index values
     TArrayI       fIndex;             //  Index of sorted values
@@ -170,6 +171,7 @@ public:
     virtual Int_t     Fit(const char *funcname ,const char *varexp, const char *selection="",Option_t *option="" ,Option_t *goption=""
                        ,Int_t nentries=1000000000, Int_t firstentry=0); // *MENU*
 
+    virtual const char *GetAlias(const char *aliasName) const;
     virtual TBranch  *GetBranch(const char *name);
     virtual Bool_t    GetBranchStatus(const char *branchname) const;
     static  Int_t     GetBranchStyle();
@@ -200,6 +202,7 @@ public:
     virtual TObjArray       *GetListOfBranches() {return &fBranches;}
     virtual TObjArray       *GetListOfLeaves()   {return &fLeaves;}
     virtual TList    *GetListOfFriends() const  {return fFriends;}
+    virtual TSeqCollection *GetListOfAliases() const {return fAliases;}
     virtual Int_t     GetMakeClass() const {return fMakeClass;}
     virtual Int_t     GetMaxEntryLoop() const {return fMaxEntryLoop;}
     virtual Double_t  GetMaximum(const char *columname);
@@ -251,6 +254,7 @@ public:
     virtual void      Reset(Option_t *option="");
     virtual Int_t     Scan(const char *varexp="", const char *selection="", Option_t *option=""
                        ,Int_t nentries=1000000000, Int_t firstentry=0); // *MENU*
+    virtual Bool_t    SetAlias(const char *aliasName, const char *aliasFormula);
     virtual void      SetAutoSave(Int_t autos=10000000) {fAutoSave=autos;}
     virtual void      SetBasketSize(const char *bname,Int_t buffsize=16000);
     virtual void      SetBranchAddress(const char *bname,void *add);
@@ -278,7 +282,7 @@ public:
                        ,Int_t nentries=1000000000, Int_t firstentry=0);
     void              UseCurrentStyle();
 
-    ClassDef(TTree,9)  //Tree descriptor (the main ROOT I/O class)
+    ClassDef(TTree,10)  //Tree descriptor (the main ROOT I/O class)
 };
 
 //////////////////////////////////////////////////////////////////////////
diff --git a/tree/src/TChain.cxx b/tree/src/TChain.cxx
index 8cd402ad7de9d18aa1e8d1b1218eaecc5826a502..6b2ca253da2fe451b2fb23c44f70b194f165e9ad 100644
--- a/tree/src/TChain.cxx
+++ b/tree/src/TChain.cxx
@@ -1,4 +1,4 @@
-// @(#)root/tree:$Name:  $:$Id: TChain.cxx,v 1.67 2003/06/02 10:36:05 brun Exp $
+// @(#)root/tree:$Name:  $:$Id: TChain.cxx,v 1.68 2003/06/24 14:00:59 brun Exp $
 // Author: Rene Brun   03/02/97
 
 /*************************************************************************
@@ -651,6 +651,19 @@ Int_t TChain::GetNbranches()
    return 0;
 }
 
+//______________________________________________________________________________
+const char *TChain::GetAlias(const char *aliasName) const
+{
+   // Returns the expanded value of the alias.  Search in the friend if any
+
+   const char *alias = TTree::GetAlias(aliasName);
+   if (alias) return alias;
+   
+   if (fTree) return fTree->GetAlias(aliasName);
+   const_cast<TChain*>(this)->LoadTree(0);
+   if (fTree) return fTree->GetAlias(aliasName);
+   return 0;
+}
 
 //______________________________________________________________________________
 Double_t TChain::GetWeight() const
diff --git a/tree/src/TTree.cxx b/tree/src/TTree.cxx
index 96c59b645cb785e646f096d18d73aa6a5f3fd974..64e83a6ef869d004eadc2b0e27c73e6f536a5097 100644
--- a/tree/src/TTree.cxx
+++ b/tree/src/TTree.cxx
@@ -1,4 +1,4 @@
-// @(#)root/tree:$Name:  $:$Id: TTree.cxx,v 1.147 2003/04/17 07:44:45 brun Exp $
+// @(#)root/tree:$Name:  $:$Id: TTree.cxx,v 1.148 2003/06/10 20:52:50 rdm Exp $
 // Author: Rene Brun   12/01/96
 
 /*************************************************************************
@@ -332,6 +332,7 @@ TTree::TTree(): TNamed()
    fDebugMin       = 0;
    fDebugMax       = 9999999;
    fFriends        = 0;
+   fAliases        = 0;
    fMakeClass      = 0;
    fNotify         = 0;
    fFileNumber     = 0;
@@ -374,6 +375,7 @@ TTree::TTree(const char *name,const char *title, Int_t splitlevel)
    fDebugMin       = 0;
    fDebugMax       = 9999999;
    fFriends        = 0;
+   fAliases        = 0;
    fMakeClass      = 0;
    fNotify         = 0;
    fFileNumber     = 0;
@@ -417,6 +419,11 @@ TTree::~TTree()
       delete fFriends;
       fFriends = 0;
    }
+   if (fAliases) {
+      fAliases->Delete();
+      delete fAliases;
+      fAliases = 0;
+   }
    fDirectory  = 0; //must be done after the destruction of friends
 }
 
@@ -2197,6 +2204,32 @@ Int_t TTree::Fit(const char *funcname ,const char *varexp, const char *selection
    else         return -1;
 }
 
+//______________________________________________________________________________
+const char *TTree::GetAlias(const char *aliasName) const
+{
+   // Returns the expanded value of the alias.  Search in the friends if any
+
+   if (fAliases) {
+      TObject *alias = fAliases->FindObject(aliasName);
+      if (alias) return alias->GetTitle();
+   }
+   TIter nextf(fFriends);
+   TFriendElement *fe;
+   while ((fe = (TFriendElement*)nextf())) {
+      TTree *t = fe->GetTree();
+      if (t) {
+         const char *alias = t->GetAlias(aliasName);
+         if (alias) return alias;
+         const char *subAliasName = strstr(aliasName,fe->GetName());
+         if (subAliasName && subAliasName[strlen(fe->GetName())]=='.') {
+            alias = t->GetAlias(aliasName+strlen(fe->GetName())+1);
+            if (alias) return alias;
+         }
+      }
+   }
+   return 0;
+}
+
 //______________________________________________________________________________
 TBranch *TTree::GetBranch(const char *name)
 {
@@ -2514,6 +2547,17 @@ Int_t TTree::GetEntryWithIndex(Int_t major, Int_t minor)
 const char *TTree::GetFriendAlias(TTree *tree) const
 {
 // If the the 'tree' is a friend, this method returns its alias name
+// This 'alias' is a an alias for the TTree itself.
+// It can be used in conjunction with a branch or leaf name in a TTreeFormula.
+//  Is can alos be used in conjunction with an alias created using
+//  TTree::SetAlias in a TTreeFormula, eg:
+//     maintree->Draw("treealias.fPx - treealias.myAlias");
+//  where fPx is a branch of the friend tree aliased as 'treealias' and 'myAlias;
+//  was created using TTree::SetAlias on the tree aliases as 'treealias'.
+//
+//  However, note that 'treealias.myAlias' will be expanded literally, without
+//  'remembering' it comes from the aliased friend and thus might the branch
+//  name might not be disambiguated properly.
 
    if (!fFriends) return 0;
    TIter nextf(fFriends);
@@ -3167,6 +3211,50 @@ Int_t  TTree::Scan(const char *varexp, const char *selection, Option_t *option,
    else         return -1;
 }
 
+//______________________________________________________________________________
+Bool_t TTree::SetAlias(const char *aliasName, const char *aliasFormula) 
+{
+//*-*-*-*-*-*-*-*-*-*-*Set a tree variable alias*-*-*-*-*-*
+//*-*                  ====================================
+//
+//  Set an alias for an expression/formula based on the tree 'variables'.  
+//
+//  The content of 'aliasName' can be used in TTreeFormula (i.e. TTree::Draw,
+//  TTree::Scan, TTreeViewer) and will be evaluated as the content of
+//  'aliasFormula'.
+//  If the alias 'aliasName' already existed, it is replaced by the new
+//  value.
+//  When being used, the alias can be preceded by an eventual 'Friend Alias'
+//  (see TTree::GetFriendAlias)
+//
+//  Return true if it was added properly.
+//
+//  For example:
+//     tree->SetAlias("x1","(tdc1[1]-tdc1[0])/49");
+//     tree->SetAlias("y1","(tdc1[3]-tdc1[2])/47");
+//     tree->SetAlias("x2","(tdc2[1]-tdc2[0])/49");
+//     tree->SetAlias("y2","(tdc2[3]-tdc2[2])/47");
+//     tree->Draw("y2-y1:x2-x1");
+//
+
+   if (aliasName==0 || aliasFormula==0) return false;
+   if (strlen(aliasName)==0 || strlen(aliasFormula)==0) return false;
+
+   if (fAliases==0) fAliases = new TList;
+   else {
+      TNamed *oldHolder = (TNamed*)fAliases->FindObject(aliasName);
+      if (oldHolder) {
+         oldHolder->SetTitle(aliasFormula);
+         return kTRUE;
+      }
+   }
+   
+   TNamed *holder = new TNamed(aliasName,aliasFormula);
+   fAliases->Add(holder);
+
+   return kTRUE;
+}
+
 //_______________________________________________________________________
  void TTree::SetBasketSize(const char *bname, Int_t buffsize)
 {
diff --git a/treeplayer/inc/TTreeFormula.h b/treeplayer/inc/TTreeFormula.h
index 335d21f928ff0a09ff9e7edd63894f47c32ed846..dea8b5ffebef5adc6c656ab63163248bb5b1f03c 100644
--- a/treeplayer/inc/TTreeFormula.h
+++ b/treeplayer/inc/TTreeFormula.h
@@ -1,4 +1,4 @@
-// @(#)root/treeplayer:$Name:  $:$Id: TTreeFormula.h,v 1.27 2003/01/30 06:40:33 brun Exp $
+// @(#)root/treeplayer:$Name:  $:$Id: TTreeFormula.h,v 1.28 2003/02/27 21:10:52 brun Exp $
 // Author: Rene Brun   19/01/96
 
 /*************************************************************************
@@ -56,6 +56,9 @@ protected:
    enum { kIsCharacter = BIT(12) };
    enum { kDirect, kDataMember, kMethod, 
           kIndexOfEntry, kEntries, kLength, kIteration };
+   enum { kAlias = TFormula::kVariable+10000+1,
+          kAliasString = kAlias+1
+   };
 
    TTree       *fTree;            //! pointer to Tree
    Short_t     fCodes[kMAXCODES]; //  List of leaf numbers referenced in formula
@@ -68,8 +71,9 @@ protected:
    TObjArray   fLeaves;           //!  List of leaf used in this formula.
    TObjArray   fDataMembers;      //!  List of leaf data members
    TObjArray   fMethods;          //!  List of leaf method calls
+   TObjArray   fAliases;          //!  List of TTreeFormula for each alias used.
    TObjArray   fLeafNames;        //   List of TNamed describing leaves
-   
+
    Int_t         fNdimensions[kMAXCODES];              //Number of array dimensions in each leaf
    Int_t         fFixedSizes[kMAXCODES][kMAXFORMDIM];  //Physical sizes of lower dimensions for each leaf
    UChar_t       fHasMultipleVarDim[kMAXCODES];        //True if the corresponding variable is an array with more than one variable dimension.
@@ -103,35 +107,45 @@ protected:
 
    void       ResetDimensions();
    Bool_t     LoadCurrentDim();
+   
+   virtual Bool_t     IsLeafInteger(Int_t code) const;
+
+   virtual Bool_t     IsString(Int_t oper) const;
+   virtual Bool_t     IsLeafString(Int_t code) const;
+private:
+   // Not implemented yet
+   TTreeFormula(const TTreeFormula&);
+   TTreeFormula& operator=(const TTreeFormula&);
 
 public:
              TTreeFormula();
              TTreeFormula(const char *name,const char *formula, TTree *tree);
    virtual   ~TTreeFormula();
-   virtual Int_t      DefinedVariable(TString &variable);
-   virtual TClass*    EvalClass() const;
-   virtual Double_t   EvalInstance(Int_t i=0);
-   virtual void*      EvalObject(Int_t i=0);
+   virtual Int_t       DefinedVariable(TString &variable);
+   virtual TClass*     EvalClass() const;
+   virtual Double_t    EvalInstance(Int_t i=0, const char *stringStack[]=0);
+   virtual const char *EvalStringInstance(Int_t i=0);
+   virtual void*       EvalObject(Int_t i=0);
    // EvalInstance should be const.  See comment on GetNdata()
-   TFormLeafInfo     *GetLeafInfo(Int_t code) const;
-   TMethodCall       *GetMethodCall(Int_t code) const;
-   virtual Int_t      GetMultiplicity() const {return fMultiplicity;}
-   virtual TLeaf     *GetLeaf(Int_t n) const;
-   virtual Int_t      GetNcodes() const {return fNcodes;}
-   virtual Int_t      GetNdata();
+   TFormLeafInfo      *GetLeafInfo(Int_t code) const;
+   TMethodCall        *GetMethodCall(Int_t code) const;
+   virtual Int_t       GetMultiplicity() const {return fMultiplicity;}
+   virtual TLeaf      *GetLeaf(Int_t n) const;
+   virtual Int_t       GetNcodes() const {return fNcodes;}
+   virtual Int_t       GetNdata();
    //GetNdata should probably be const.  However it need to cache some information about the actual dimension
    //of arrays, so if GetNdata is const, the variables fUsedSizes and fCumulUsedSizes need to be declared
    //mutable.  We will be able to do that only when all the compilers supported for ROOT actually implemented
    //the mutable keyword. 
    //NOTE: Also modify the code in PrintValue which current goes around this limitation :(
-   virtual Bool_t     IsInteger(Int_t code = 0) const;
-   virtual Bool_t     IsString(Int_t code = 0) const;
-   virtual char      *PrintValue(Int_t mode=0) const;
-   virtual void       SetAxis(TAxis *axis=0);
-   virtual void       SetTree(TTree *tree) {fTree = tree;}
-   virtual void       UpdateFormulaLeaves();
-
-   ClassDef(TTreeFormula,7)  //The Tree formula
+   virtual Bool_t      IsInteger() const;
+   virtual Bool_t      IsString() const;
+   virtual char       *PrintValue(Int_t mode=0) const;
+   virtual void        SetAxis(TAxis *axis=0);
+   virtual void        SetTree(TTree *tree) {fTree = tree;}
+   virtual void        UpdateFormulaLeaves();
+
+   ClassDef(TTreeFormula,8)  //The Tree formula
 };
 
 #endif
diff --git a/treeplayer/src/TTreeFormula.cxx b/treeplayer/src/TTreeFormula.cxx
index 360c8bafac97318c8b01ae796e3d4c9475da8033..9a5fc29e3145d57b57afb32be45058977fcd1382 100644
--- a/treeplayer/src/TTreeFormula.cxx
+++ b/treeplayer/src/TTreeFormula.cxx
@@ -1,4 +1,4 @@
-// @(#)root/treeplayer:$Name:  $:$Id: TTreeFormula.cxx,v 1.119 2003/06/21 13:27:19 brun Exp $
+// @(#)root/treeplayer:$Name:  $:$Id: TTreeFormula.cxx,v 1.120 2003/06/25 07:16:22 brun Exp $
 // Author: Rene Brun   19/01/96
 
 /*************************************************************************
@@ -1361,13 +1361,13 @@ TTreeFormula::TTreeFormula(const char *name,const char *expression, TTree *tree)
       fNcodes = kMAXFOUND;
    }
    SetName(name);
-   for (i=0;i<fNcodes;i++) {
-      if (fCodes[i] < 0) continue;
 
-      TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(i);
-      if (!leaf) continue;
+   for (i=0;i<fNoper;i++) {
+      if (fOper[i] >= 105000 && fOper[i]<110000) {
+         Int_t string_code = fOper[i]-105000;
+         TLeaf *leafc = (TLeaf*)fLeaves.UncheckedAt(string_code);
+         if (!leafc) continue;
 
-      if (fOper[i] >= 105000) {
          // We have a string used as a string
 
          // This dormant portion of code would be used if (when?) we allow the histogramming
@@ -1385,11 +1385,16 @@ TTreeFormula::TTreeFormula(const char *name,const char *expression, TTree *tree)
             // just make part of a useless expression (for example: mystring+0)
             SetBit(kIsCharacter);
          }
+         continue;
       }
-
+   }
+   if (fNoper==1 && fOper[0]==kAliasString) {
+      TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
+      Assert(subform);
+      if (subform->TestBit(kIsCharacter)) SetBit(kIsCharacter);
    }
 
-   fManager->Sync();
+   fManager->Sync(); 
 
    // Let's verify the indexes and dies if we need to.
    Int_t k0,k1;
@@ -1424,6 +1429,7 @@ TTreeFormula::~TTreeFormula()
    }
    fLeafNames.Delete();
    fDataMembers.Delete();
+   fAliases.Delete();
    if (fLookupType) delete [] fLookupType;
    for (int j=0; j<fNcodes; j++) {
       for (int k = 0; k<fNdimensions[j]; k++) {
@@ -1994,6 +2000,23 @@ Int_t TTreeFormula::DefinedVariable(TString &name)
       final = leaf->IsOnTerminalBranch();
    }
 
+   if (!leaf) {
+      // Check for an alias.
+      const char *aliasValue = fTree->GetAlias(work);
+      if (aliasValue) {
+         TTreeFormula *subform = new TTreeFormula(work,aliasValue,fTree); 
+            
+         fManager->Add(subform);
+         fAliases.AddAtAndExpand(subform,fNoper);
+         
+         if (subform->IsString()) {
+            return kAliasString - kVariable; // need to compensate for the TFormula induced offset
+         } else {
+            return kAlias - kVariable; // need to compensate for the TFormula induced offset
+         }
+      }
+   }
+
    if (leaf) { // We found a Leaf.
 
       if (leaf->GetBranch() && leaf->GetBranch()->TestBit(kDoNotProcess)) {
@@ -2271,7 +2294,7 @@ Int_t TTreeFormula::DefinedVariable(TString &name)
                         maininfo = clonesinfo;
 
                         clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
-                        //clones = *(TClonesArray**)((TBranchElement*)branch)->GetAddress();
+                        //clones = *(TClonesArray**)((TBranchElement*)branch)->GetAdress();
                      } else {
                         TClass *mother_cl;
                         if (leaf->IsA()==TLeafObject::Class()) {
@@ -2619,7 +2642,7 @@ Int_t TTreeFormula::DefinedVariable(TString &name)
          }
       }
 
-      if (IsString(code)) {
+      if (IsLeafString(code)) {
          if (fLookupType[code]==kDirect && leaf->InheritsFrom("TLeafElement")) {
             TBranchElement * br = (TBranchElement*)leaf->GetBranch();
             if (br->GetType()==31) {
@@ -3154,9 +3177,34 @@ void* TTreeFormula::EvalObject(int instance)
 }
 
 
+//______________________________________________________________________________
+const char* TTreeFormula::EvalStringInstance(Int_t instance)
+{
+   const Int_t kMAXSTRINGFOUND = 10;
+   const char *stringStack[kMAXSTRINGFOUND];
+
+   if (fNoper==1 && fNcodes>0 && IsString()) {
+      TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0);
+
+      Int_t real_instance = GetRealInstance(instance,0);
+
+      if (!instance) leaf->GetBranch()->GetEntry(leaf->GetBranch()->GetTree()->GetReadEntry());
+      else if (real_instance>fNdata[0]) return 0;
+
+      if (fLookupType[0]==kDirect) {
+         return (char*)leaf->GetValuePointer();
+      } else {
+         return  (char*)GetLeafInfo(0)->GetValuePointer(leaf,0);
+      }
+   }
+
+   EvalInstance(instance,stringStack);
+
+   return stringStack[0];
+}
 
 //______________________________________________________________________________
-Double_t TTreeFormula::EvalInstance(Int_t instance)
+Double_t TTreeFormula::EvalInstance(Int_t instance, const char *stringStackArg[])
 {
 //*-*-*-*-*-*-*-*-*-*-*Evaluate this treeformula*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
 //*-*                  =========================
@@ -3167,7 +3215,8 @@ Double_t TTreeFormula::EvalInstance(Int_t instance)
    Float_t aresult;
    Double_t tab[kMAXFOUND];
    Double_t dexp;
-   char *tab2[kMAXSTRINGFOUND];
+   const char *stringStackLocal[kMAXSTRINGFOUND];
+   const char **stringStack = stringStackArg?stringStackArg:stringStackLocal;
 
    if (fNoper == 1 && fNcodes > 0) {
       switch (fCodes[0]) {
@@ -3185,6 +3234,17 @@ Double_t TTreeFormula::EvalInstance(Int_t instance)
             return fx->EvalInstance(instance);
          }
       }
+//       if (fOper[0]==kAlias) {
+//          TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
+//          Assert(subform);
+//          return subform->EvalInstance(instance);
+//       }
+//       if (fOper[0]==kAliasString) {
+//          TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
+//          Assert(subform);
+//          if (fAxis) ... 
+//          return subform->EvalInstance(instance);
+//       }
       switch (fLookupType[0]) {
         case kIndexOfEntry: return fTree->GetReadEntry();
         case kEntries:      return fTree->GetEntries();
@@ -3201,7 +3261,7 @@ Double_t TTreeFormula::EvalInstance(Int_t instance)
       if (fAxis) {
          char * label;
          // This portion is a duplicate (for speed reason) of the code
-         // located  in the main for loop at "a tree string".
+         // located  in the main for loop at "a tree string" (and in EvalStringInstance)
          if (fLookupType[0]==kDirect) {
             label = (char*)leaf->GetValuePointer();
          } else {
@@ -3227,7 +3287,7 @@ Double_t TTreeFormula::EvalInstance(Int_t instance)
       if (action >= kFunctionCall) {
          int fno   = (action-kFunctionCall) / 1000;
          int nargs = (action-kFunctionCall) % 1000;
-         
+
          // Retrieve the function
          TMethodCall *method = (TMethodCall*)fFunctions.At(fno);
          
@@ -3252,6 +3312,27 @@ Double_t TTreeFormula::EvalInstance(Int_t instance)
          method->Execute(args,ret);
          tab[pos-1] = ret; // check for the correct conversion!
          
+         continue;
+      }
+//*-*- a TTree Variable Alias (i.e. a sub-TTreeFormula)
+      if (action == kAlias) {
+         int aliasN = i;
+         TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(aliasN));
+         Assert(subform);
+
+         Double_t param = subform->EvalInstance(instance);
+
+         tab[pos] = param; pos++;
+         continue;
+      }
+//*-*- a TTree Variable Alias String (i.e. a sub-TTreeFormula)
+      if (action == kAliasString) {
+         int aliasN = i;
+         TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(aliasN));
+         Assert(subform);
+
+         pos2++;
+         stringStack[pos2-1] = subform->EvalStringInstance(instance);
          continue;
       }
 //*-*- a tree string
@@ -3267,9 +3348,9 @@ Double_t TTreeFormula::EvalInstance(Int_t instance)
 
          pos2++;
          if (fLookupType[string_code]==kDirect) {
-            tab2[pos2-1] = (char*)leafc->GetValuePointer();
+            stringStack[pos2-1] = (char*)leafc->GetValuePointer();
          } else {
-            tab2[pos2-1] = (char*)GetLeafInfo(string_code)->GetValuePointer(leafc,real_instance);
+            stringStack[pos2-1] = (char*)GetLeafInfo(string_code)->GetValuePointer(leafc,real_instance);
          }
          continue;
       }
@@ -3327,8 +3408,8 @@ Double_t TTreeFormula::EvalInstance(Int_t instance)
          continue;
       }
 //*-*- String
-      if (action == 80000) {
-         pos2++; tab2[pos2-1] = (char*)fExpr[i].Data();
+      if (action == kStrings) {
+         pos2++; stringStack[pos2-1] = (char*)fExpr[i].Data();
          continue;
       }
 //*-*- numerical value
@@ -3378,7 +3459,8 @@ Double_t TTreeFormula::EvalInstance(Int_t instance)
             case  20 : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); break;
             case  21 : tab[pos-1] = tab[pos-1]*tab[pos-1]; break;
             case  22 : tab[pos-1] = TMath::Sqrt(TMath::Abs(tab[pos-1])); break;
-            case  23 : pos2 -= 2; pos++;if (tab2[pos2] && strstr(tab2[pos2],tab2[pos2+1])) tab[pos-1]=1;
+            case  23 : pos2 -= 2; pos++;if (stringStack[pos2] && 
+                                            strstr(stringStack[pos2],stringStack[pos2+1])) tab[pos-1]=1;
                             else tab[pos-1]=0; break;
             case  24 : pos--; tab[pos-1] = TMath::Min(tab[pos-1],tab[pos]); break;
             case  25 : pos--; tab[pos-1] = TMath::Max(tab[pos-1],tab[pos]); break;
@@ -3414,9 +3496,9 @@ Double_t TTreeFormula::EvalInstance(Int_t instance)
             case  67 : pos--; if (tab[pos-1]>=tab[pos]) tab[pos-1]=1;
                               else tab[pos-1]=0; break;
             case  68 : if (tab[pos-1]!=0) tab[pos-1] = 0; else tab[pos-1] = 1; break;
-            case  76 : pos2 -= 2; pos++; if (!strcmp(tab2[pos2+1],tab2[pos2])) tab[pos-1]=1;
+            case  76 : pos2 -= 2; pos++; if (!strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
                               else tab[pos-1]=0; break;
-            case  77 : pos2 -= 2; pos++;if (strcmp(tab2[pos2+1],tab2[pos2])) tab[pos-1]=1;
+            case  77 : pos2 -= 2; pos++;if (strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
                               else tab[pos-1]=0; break;
             case  78 : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) & ((Int_t) tab[pos]); break;
             case  79 : pos--; tab[pos-1]= ((Int_t) tab[pos-1]) | ((Int_t) tab[pos]); break;
@@ -3561,16 +3643,23 @@ void* TTreeFormula::GetValuePointerFromMethod(Int_t i, TLeaf *leaf) const
 }
 
 //______________________________________________________________________________
-Bool_t TTreeFormula::IsInteger(Int_t code) const
+Bool_t TTreeFormula::IsInteger() const
 {
    // return TRUE if the formula corresponds to one single Tree leaf
    // and this leaf is short, int or unsigned short, int
    // When a leaf is of type integer, the generated histogram is forced
    // to have an integer bin width
+
    if (fNoper > 1) return kFALSE;
 
+   if (fOper[0]==kAlias) {
+      TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
+      Assert(subform);
+      return subform->IsInteger();
+   }
+   
    if (fLeaves.GetEntries() != 1) {
-      switch (fLookupType[code]) {
+      switch (fLookupType[0]) {
          case kIndexOfEntry:
          case kEntries:
          case kLength:
@@ -3583,8 +3672,29 @@ Bool_t TTreeFormula::IsInteger(Int_t code) const
    
    if (EvalClass()==TBits::Class()) return kTRUE;
 
+   return IsLeafInteger(0);
+}
+
+//______________________________________________________________________________
+Bool_t TTreeFormula::IsLeafInteger(Int_t code) const
+{
+   // return TRUE if the leaf corresponding to code is short, int or unsigned
+   // short, int When a leaf is of type integer, the generated histogram is
+   // forced to have an integer bin width
+
    TLeaf *leaf = (TLeaf*)fLeaves.At(code);
-   if (!leaf) return kFALSE;
+   if (!leaf) {
+      switch (fLookupType[code]) {
+         case kIndexOfEntry:
+         case kEntries:
+         case kLength:
+         case kIteration:
+           return kTRUE;
+         default:
+           return kFALSE;
+      }      
+      return kFALSE;
+   }
    if (fAxis) return kTRUE;
    TFormLeafInfo * info;
    switch (fLookupType[code]) {
@@ -3602,64 +3712,83 @@ Bool_t TTreeFormula::IsInteger(Int_t code) const
    return kFALSE;
 }
 
-
 //______________________________________________________________________________
-Bool_t TTreeFormula::IsString(Int_t code) const
+Bool_t TTreeFormula::IsString() const
 {
-   // return TRUE if the leaf or data member corresponding to code is a string
+   // return TRUE if the formula is a string
+
+   return TestBit(kIsCharacter) || (fNoper==1 && IsString(0));
+}
 
+//______________________________________________________________________________
+Bool_t TTreeFormula::IsString(Int_t oper) const
+{ 
+   // (fOper[i]>=105000 && fOper[i]<110000) || fOper[i] == kStrings) 
+
+   // return true if the expression at the index 'oper' is to be treated as 
+   // as string
+
+   if (TFormula::IsString(oper)) return kTRUE;
+   if (fOper[oper]>=105000 && fOper[oper]<110000) return kTRUE;
+   if (fOper[oper]==kAliasString) return kTRUE;
+   return kFALSE;
+}
+
+//______________________________________________________________________________
+Bool_t  TTreeFormula::IsLeafString(Int_t code) const
+{   
+   // return TRUE if the leaf or data member corresponding to code is a string
    TLeaf *leaf = (TLeaf*)fLeaves.At(code);
    if (!leaf) return kFALSE;
-
+   
    TFormLeafInfo * info;
    switch(fLookupType[code]) {
-   case kDirect:
-     if ( !leaf->IsUnsigned() && (leaf->InheritsFrom("TLeafC") || leaf->InheritsFrom("TLeafB") ) ) {
-        // Need to find out if it is an 'array' or a pointer.
-        if (leaf->GetLenStatic() > 1) return kTRUE;
-
-        // Now we need to differantiate between a variable length array and
-        // a TClonesArray.
-        if (leaf->GetLeafCount()) {
-           const char* indexname = leaf->GetLeafCount()->GetName();
-           if (indexname[strlen(indexname)-1] == '_' ) {
-              // This in a clones array
-             return kFALSE;
-           } else {
-              // this is a variable length char array
-              return kTRUE;
-           }
-        }
-     } else if (leaf->InheritsFrom("TLeafElement")) {
-        TBranchElement * br = (TBranchElement*)leaf->GetBranch();
-        Int_t bid = br->GetID();
-        if (bid < 0) return kFALSE;
-        TStreamerElement * elem = (TStreamerElement*) br->GetInfo()->GetElems()[bid];
-        if (elem->GetType()== TStreamerInfo::kOffsetL +kChar_t) {
-           // Check whether a specific element of the string is specified!
-           if (fIndexes[code][fNdimensions[code]-1] != -1) return kFALSE;
-           return kTRUE;
-        }
-        if ( elem->GetType()== TStreamerInfo::kCharStar) {
-           // Check whether a specific element of the string is specified!
-           if (fNdimensions[code] && fIndexes[code][fNdimensions[code]-1] != -1) return kFALSE;
-           return kTRUE;
-        }
-        return kFALSE;
-     } else {
-        return kFALSE;
-     }
-   case kMethod:
-      //TMethodCall *m = GetMethodCall(code);
-      //TMethodCall::EReturnType r = m->ReturnType();
-      return kFALSE;
-   case kDataMember:
-      info = GetLeafInfo(code);
-      return info->IsString();
-   default:
-      return kFALSE;
+      case kDirect:
+         if ( !leaf->IsUnsigned() && (leaf->InheritsFrom("TLeafC") || leaf->InheritsFrom("TLeafB") ) ) {
+            // Need to find out if it is an 'array' or a pointer.
+            if (leaf->GetLenStatic() > 1) return kTRUE;
+            
+            // Now we need to differantiate between a variable length array and
+            // a TClonesArray.
+            if (leaf->GetLeafCount()) {
+               const char* indexname = leaf->GetLeafCount()->GetName();
+               if (indexname[strlen(indexname)-1] == '_' ) {
+                  // This in a clones array
+                  return kFALSE;
+               } else {
+                  // this is a variable length char array
+                  return kTRUE;
+               }
+               }
+         } else if (leaf->InheritsFrom("TLeafElement")) {
+            TBranchElement * br = (TBranchElement*)leaf->GetBranch();
+            Int_t bid = br->GetID();
+            if (bid < 0) return kFALSE;
+            TStreamerElement * elem = (TStreamerElement*) br->GetInfo()->GetElems()[bid];
+            if (elem->GetType()== TStreamerInfo::kOffsetL +kChar_t) {
+               // Check whether a specific element of the string is specified!
+               if (fIndexes[code][fNdimensions[code]-1] != -1) return kFALSE;
+               return kTRUE;
+            }
+            if ( elem->GetType()== TStreamerInfo::kCharStar) {
+               // Check whether a specific element of the string is specified!
+               if (fNdimensions[code] && fIndexes[code][fNdimensions[code]-1] != -1) return kFALSE;
+               return kTRUE;
+            }
+            return kFALSE;
+         } else {
+            return kFALSE;
+         }
+      case kMethod:
+         //TMethodCall *m = GetMethodCall(code);
+         //TMethodCall::EReturnType r = m->ReturnType();
+         return kFALSE;
+      case kDataMember:
+         info = GetLeafInfo(code);
+         return info->IsString();
+      default:
+         return kFALSE;
    }
-
 }
 
 //______________________________________________________________________________
@@ -3724,7 +3853,14 @@ char *TTreeFormula::PrintValue(Int_t mode) const
 void TTreeFormula::SetAxis(TAxis *axis)
 {
    if (!axis) {fAxis = 0; return;}
-   if (TestBit(kIsCharacter)) fAxis = axis;
+   if (TestBit(kIsCharacter)) {
+      fAxis = axis;
+      if (fNoper==1 && fOper[0]==kAliasString){
+         TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(0));
+         Assert(subform); 
+         subform->SetAxis(axis);
+      }
+   }
    if (IsInteger()) axis->SetBit(TAxis::kIsInteger);
 }
 
@@ -3798,6 +3934,13 @@ void TTreeFormula::UpdateFormulaLeaves()
          }
       }
    }
+   for(Int_t k=0;k<fNoper;k++) {
+      if (fOper[k]==kAlias || (fOper[k]==kAliasString) ) {
+         TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(k));
+         Assert(subform);
+         subform->UpdateFormulaLeaves();
+      }
+   }
 }
 
 //______________________________________________________________________________
@@ -3821,7 +3964,7 @@ void TTreeFormula::ResetDimensions() {
          last_code = info->fCode;
          fNdimensions[last_code] = 0;
       }
-      if (fOper[last_code]>=105000) {
+      if (fOper[last_code]>=105000 && fOper[last_code]<110000) {
          // We have a string used as a string (and not an array of number)
          // We need to determine which is the last dimension and skip it.
          DimensionInfo *nextinfo = (DimensionInfo*)next();
@@ -3844,6 +3987,36 @@ void TTreeFormula::ResetDimensions() {
    }
 
    fMultiplicity = 0;
+   for(i=0;i<fNoper;i++) {
+      if (fOper[i]==kAlias || fOper[i]==kAliasString) {
+         TTreeFormula *subform = dynamic_cast<TTreeFormula*>(fAliases.UncheckedAt(i));
+         Assert(subform);
+         switch(subform->GetMultiplicity()) {
+            case 0: break;
+            case 1: fMultiplicity = 1; break;
+            case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
+         }
+         fManager->Add(subform);
+         // since we are addint to this manager 'subform->ResetDimensions();'
+         // will be called a little latter
+         continue;
+      }
+      if (fOper[i] >= 105000 && fOper[i]<110000) {
+         // We have a string used as a string
+
+         // This dormant portion of code would be used if (when?) we allow the histogramming
+         // of the integral content (as opposed to the string content) of strings
+         // held in a variable size container delimited by a null (as opposed to
+         // a fixed size container or variable size container whose size is controlled
+         // by a variable).  In GetNdata, we will then use strlen to grab the current length.
+         //fCumulSizes[i][fNdimensions[i]-1] = 1;
+         //fUsedSizes[fNdimensions[i]-1] = -TMath::Abs(fUsedSizes[fNdimensions[i]-1]);
+         //fUsedSizes[0] = - TMath::Abs( fUsedSizes[0]);
+
+         //continue;
+      }
+   }
+
    for (i=0;i<fNcodes;i++) {
       if (fCodes[i] < 0) {
          TCutG *gcut = (TCutG*)fMethods.At(i);
@@ -3870,22 +4043,6 @@ void TTreeFormula::ResetDimensions() {
          continue;
       }
 
-      if (fOper[i] >= 105000) {
-         // We have a string used as a string
-
-         // This dormant portion of code would be used if (when?) we allow the histogramming
-         // of the integral content (as opposed to the string content) of strings
-         // held in a variable size container delimited by a null (as opposed to
-         // a fixed size container or variable size container whose size is controlled
-         // by a variable).  In GetNdata, we will then use strlen to grab the current length.
-         //fCumulSizes[i][fNdimensions[i]-1] = 1;
-         //fUsedSizes[fNdimensions[i]-1] = -TMath::Abs(fUsedSizes[fNdimensions[i]-1]);
-         //fUsedSizes[0] = - TMath::Abs( fUsedSizes[0]);
-
-         //continue;
-      }
-
-
       if (fLookupType[i]==kIteration) {
           fMultiplicity = 1;
           continue;
diff --git a/treeplayer/src/TTreeFormulaManager.cxx b/treeplayer/src/TTreeFormulaManager.cxx
index 00ac2057528f7305b0f30bd732e46899a6276cfb..470f0a046fc0f0956d75a695978ea715af08581e 100644
--- a/treeplayer/src/TTreeFormulaManager.cxx
+++ b/treeplayer/src/TTreeFormulaManager.cxx
@@ -1,4 +1,4 @@
-// @(#)root/treeplayer:$Name:  $:$Id: TTreeFormulaManager.cxx,v 1.1 2002/03/26 08:24:01 brun Exp $
+// @(#)root/treeplayer:$Name:  $:$Id: TTreeFormulaManager.cxx,v 1.2 2002/04/04 17:28:52 rdm Exp $
 // Author: Philippe Canal   20/03/02
 
 /*************************************************************************
@@ -79,7 +79,6 @@ void TTreeFormulaManager::Add(TTreeFormula* adding)
   TTreeFormulaManager * old = adding->fManager;
 
   if (old) {
-
      if (old==this) {
         if (fFormulas.FindObject(adding)) return;
      } else {