proj home

Files   Classes   Functions   Hierarchy  

rpn2.h

Go to the documentation of this file.
00001 #ifndef RPN_H
00002 #define RPN_H
00003 
00004 #include <iostream>
00005 #include <iomanip>
00006 #include <deque>
00007 #include <string>
00008 
00009 // Toggle ALL debug code. 
00010 //#define NDEBUG
00011 #include <cassert>
00012 
00013 using namespace std;
00014 
00015 #include <html.h>
00016 
00017 #ifndef NDEBUG
00018 // Toggle Debug code.
00019 #define DEBUG_RFC
00020 #endif
00021 
00022 
00023 class rpnfunction;
00024 
00025 class rpnbase 
00026 {
00027 public:
00028 
00029   /* Reference counting for memory management. */
00030   unsigned int counter;
00031   virtual void inc() 
00032     { ++counter; }
00033   void dec() 
00034     { --counter; if (counter==0) delete this; }
00035 
00036   /* Constructors, destructors and deep copy. */
00037   rpnbase() : counter(1) {}
00038   virtual ~rpnbase()=0;
00039   virtual rpnbase* copy() const=0;
00040 
00041   virtual ostream& print(ostream& os) const 
00042     { return os << this->name(); }
00043   /* Associated symbol with the class. */
00044   virtual string const name() const 
00045     { return string("undefined"); }
00046 
00047   /* Evaluation on the stack. */
00048   virtual void eval( deque<rpnbase*>& ds )
00049     { ds.push_front(this); }
00050   
00051   /* Visitor patterns accept function forwards data type. */
00052   virtual void accept(deque<rpnbase*>& ds,rpnfunction& f) {}
00053 
00054   /* Real time type information. */
00055   virtual bool const isinteger() const  { return false; } 
00056   virtual bool const isreal() const     { return false; }
00057   virtual bool const isstring() const   { return false; }
00058   virtual bool const isprogram() const  { return false; } 
00059   virtual bool const isvariable() const { return false; }
00060   virtual bool const isvector() const   { return false; }
00061   bool const isnumber() const 
00062     { return this->isreal() || this->isinteger(); }
00063 
00064 };
00065 
00066 ostream& operator << (ostream& os, rpnbase* const p) 
00067   { return p->print(os); }
00068 
00069 class rpnprogram;
00070 class rpnstring;
00071 class rpnreal;
00072 class rpninteger;
00073 class rpnvar;
00074 class rpnvector;
00075 
00076 
00077 /* Derive functions */
00078 class rpnfunction : public rpnbase
00079 {
00080 public:
00081 
00082   rpnfunction() {}
00083   ~rpnfunction() {}
00084   rpnbase* copy() const;
00085 
00086   virtual void visit(deque<rpnbase*>& ds,rpnprogram& p) {}
00087   virtual void visit(deque<rpnbase*>& ds,rpnstring& s) {}
00088   virtual void visit(deque<rpnbase*>& ds,rpnreal& n) {}
00089   virtual void visit(deque<rpnbase*>& ds,rpninteger& n) {}
00090   virtual void visit(deque<rpnbase*>& ds,rpnvar& n) {}
00091   virtual void visit(deque<rpnbase*>& ds,rpnvector& v) {}
00092 
00093   string const name() const 
00094     { return string("rpnfunction"); }
00095 };
00096 
00097 
00098 class rpnreal : public rpnbase
00099 {
00100 public:
00101 
00102   long double num;
00103   typedef long double type;
00104 
00105   rpnreal() {}
00106   rpnreal(double const n) : num(n) {} /* <TODO> Is this necessary? */
00107   rpnreal(deque<rpnbase*>& ds,double const n); 
00108   ~rpnreal() {}
00109   rpnbase* copy() const;
00110 
00111   void accept(deque<rpnbase*>& ds,rpnfunction& f) 
00112     { f.visit(ds,*this); }
00113 
00114   ostream& print(ostream& os) const;
00115   string const name() const 
00116     { return string("rpnreal"); }
00117 
00118   bool const isreal() const 
00119     { return true; }
00120 };
00121 
00122 
00123 class rpninteger: public rpnbase
00124 {
00125 public:
00126 /* <TODO>  - template the integer so much better integer arithmetic
00127  * can be used. 
00128  */
00129   long int num;
00130   typedef long int type;
00131 
00132   rpninteger() {}
00133   rpninteger(deque<rpnbase*>& ds,long int const n);
00134   ~rpninteger() {}
00135   rpnbase* copy() const;
00136 
00137   void accept(deque<rpnbase*>& ds,rpnfunction& f) 
00138     { f.visit(ds,*this); }
00139 
00140   ostream& print(ostream& os) const;
00141   string const name() const 
00142     { return string("rpninteger"); }
00143 
00144   bool const isinteger() const 
00145     { return true; }
00146 };
00147 
00148 
00149 class rpnstring : public rpnbase
00150 {
00151 public:
00152 
00153   string str;
00154 
00155   rpnstring() {}
00156   rpnstring(deque<rpnbase*>& ds,string const & s);
00157   ~rpnstring() {}
00158   rpnbase* copy() const;
00159 
00160   void accept(deque<rpnbase*>& ds,rpnfunction& f) 
00161     { f.visit(ds,*this); }
00162 
00163   ostream& print(ostream& os) const;
00164 
00165   void eval( deque<rpnbase*>& ds );
00166 
00167   bool const isstring() const 
00168     { return true; }
00169 };
00170 
00171 
00172 /* <TODO> Restrict to access by rpnprogram, don't create on the stack. */
00173 
00174 /* Rpn Variable class. - Used by rpnprogram. 
00175  */
00176 class rpnvar : public rpnbase
00177 {
00178 public:
00179 
00180   string varname;
00181   rpnbase* x;  
00182 
00183   void inc();
00184 
00185   rpnvar(rpnbase* x_, string const & s);
00186   rpnvar(rpnprogram& prog, rpnbase* x_, string const & s);
00187   ~rpnvar();
00188 
00189   rpnbase* copy() const;
00190   void accept(deque<rpnbase*>& ds,rpnfunction& f) 
00191     { f.visit(ds,*this); }
00192 
00193   void eval( deque<rpnbase*>& ds )
00194     { rpnbase* w = x->copy(); w->eval(ds); }
00195 
00196   ostream& print(ostream& os) const;
00197   string const name() const 
00198     { return varname; }
00199 
00200   bool const isvariable() const 
00201     { return true; }
00202 };
00203 
00204 
00205 
00206 
00207 class rpnvector : public rpnbase
00208 {
00209 /* Counting from the stack bottom is 0 as the first element.
00210    Counting from the stack end is 1 as the first element.
00211    Then can convert between the two with the same formula:
00212      f(k) = n-k  eg n=6, k=1 then f(1)=5 which is 1: ,f( f(1) ) = 1.
00213 */
00214 public:
00215 
00216   /* Counting from  the end of the stack. */
00217   int reverseindex;
00218   
00219   rpnvector(int index);
00220 
00221   rpnbase* copy() const;
00222   void accept(deque<rpnbase*>& ds,rpnfunction& f) 
00223     { f.visit(ds,*this); }
00224 
00225   ostream& print(ostream& os) const;
00226   string const name() const 
00227     { return "rpnvector"; }
00228 
00229   /* Convert between counting from the start of the stack 
00230      and the end of the stack. */
00231   int const indexcomplement(int const n) const;
00232   /* Return the index relative to the current stack. */
00233   const int rpnvector::index() const;
00234 
00235   bool const isvector() const 
00236     { return true; }
00237 };
00238 
00239 
00240 
00241 class rpnprogram : public rpnbase 
00242 {
00243 public:
00244 
00245   deque<rpnbase*> v;
00246   deque<rpnvar*> variables;
00247 
00248   void inc();
00249 
00250   bool const valid() const;
00251 
00252   rpnprogram();
00253   rpnprogram(deque<rpnbase*>& ds);
00254   rpnprogram
00255   (
00256     deque<rpnbase*>& ds,
00257     deque<rpnbase*>& ds2,
00258     bool const evaluate=true
00259   );
00260   ~rpnprogram();
00261   rpnbase* copy() const;
00262 
00263   void accept(deque<rpnbase*>& ds,rpnfunction& f) 
00264     { f.visit(ds,*this); }
00265 
00266   ostream& print(ostream& os) const;
00267 
00268   void eval( deque<rpnbase*>& ds ); 
00269 
00270   bool const isprogram() const 
00271     { return true; }
00272 };
00273 
00274 
00275 /* Access the programs state. Its a singleton class
00276  * which holds pointers to the systems state.
00277  * Also supports variable operations for var suggesting
00278  * that this class should be made into two classes. */ 
00279 
00280 class rpnprogramstackstate
00281 {
00282   static string findprogrampath;
00283   void findprogram
00284   (
00285     bool& found, 
00286     rpnprogram* p, 
00287     string const path, 
00288     rpnprogram* targ
00289   );
00290 public:
00291 
00292   static rpnprogram rpnhome;
00293 
00294   /* The primary program pointer, is never empty. */
00295   static deque<rpnprogram*>* ps;
00296 
00297   /* Minor stack. */
00298   static deque<rpnbase*> ds2;
00299 
00300   rpnprogramstackstate() {}
00301 
00302   /* Client must call before and after use. */
00303   void init();
00304 
00305   /* Access the most recent program's stack. */
00306   deque<rpnbase*>& ds() 
00307     { return ps->front()->v; }
00308   /* Access the most recent programs's variables. */
00309   deque<rpnvar*>& vs() 
00310     { return ps->front()->variables; }
00311 
00312   ostream& print(ostream& os) const;
00313 
00314   /* Control scoping/visability of programs and consequently variables. */
00315   void push(rpnprogram* p)
00316     { ps->push_front(p); }
00317   void pop()
00318     { if(ps->size()>1) ps->pop_front(); }
00319 
00320   /* Add a variable to the most rescent stack program. */
00321   void add(rpnbase* x, string const & s);
00322 
00323   /* Find the program in the rpnhome tree. */
00324   void findprogram(bool& found, string& path, rpnprogram* targ);
00325 
00326   /* Searches for a named variable, in the stack order. */
00327   void find
00328   (
00329     bool & result,
00330     unsigned int & indexi,
00331     unsigned int & indexk,
00332     rpnvar* & x,
00333     string const & nm
00334   ) const;
00335 
00336   /* Support operations on variables. */
00337   void erase(string const &nm);
00338   void replace(rpnbase* x, string const & nm);
00339   void exists(bool& res, string const & nm) const;
00340   void evaluate(deque<rpnbase*>& ds, string const & nm) const;
00341   void recall(deque<rpnbase*>& ds, string const & nm) const; 
00342   void recallpointer(deque<rpnbase*>& ds, string const & nm) const;
00343 
00344 };
00345 
00346 ostream& operator << (ostream& os, rpnprogramstackstate const & ps)
00347   { return ps.print(os); }
00348 
00349 
00350 // Implementation
00351 // ------------------------------------------------------------ 
00352 //
00353 
00354 /* g++ wants these. */
00355 rpnbase::~rpnbase() {}
00356 rpnbase* rpnbase::copy() const { return 0; }
00357 
00358 
00359 rpnreal::rpnreal(deque<rpnbase*>& ds, double const n)
00360   : num(n)
00361 {
00362   eval(ds);
00363 }
00364 
00365 /*
00366 This is a MAGIC NUMBER. 
00367 
00368  <TODO> Make configurable for user.
00369 
00370   Why 30?  I do not know, but it is beyond the accuracy
00371   of my type and hence displaysed the computers approximation.
00372 
00373   eg. On my machine
00374     73.4 resulted in 
00375     0: 73.40000000000000568434
00376 
00377   An accuracy of 15 digits. Ofcourse the computer has
00378    a binary representation/approximation.
00379 
00380   The good thing about displaying the garbage is you
00381   get to see how inaccurate the computer actually is,
00382   and its scary.
00383 
00384 */
00385 ostream& rpnreal::print(ostream& os) const
00386 {
00387   return os << fixed << showpoint 
00388     << setprecision( 30 ) << num;
00389 } 
00390 
00391 rpnbase* rpnreal::copy() const
00392 {
00393   rpnreal* n = new rpnreal();
00394   n->num = num;
00395   return n;
00396 }
00397 
00398 
00399 rpninteger::rpninteger(deque<rpnbase*>& ds, long int const n)
00400   : num(n)
00401 {
00402   eval(ds);
00403 }
00404 
00405 ostream& rpninteger::print(ostream& os) const
00406 {
00407   return os << num;
00408 }
00409 
00410 rpnbase* rpninteger::copy() const
00411 {
00412   rpninteger* n = new rpninteger();
00413   n->num = num;
00414   return n;
00415 }
00416 
00417 
00418 rpnstring::rpnstring(deque<rpnbase*>& ds,string const & s)
00419   :str(s)
00420 {
00421   eval(ds);
00422 }
00423 
00424 ostream& rpnstring::print(ostream& os) const
00425 {
00426   if (str != "/")
00427     return os << str;
00428 
00429   /* To distinguish between division and root node. */
00430   return os << string("\"/");
00431 }
00432 
00433 rpnbase* rpnstring::copy() const
00434 {
00435   rpnstring* s = new rpnstring();
00436   s->str = str;
00437   return s;
00438 }
00439 
00440 inline void rpnstring::eval( deque<rpnbase*>& ds )
00441 {
00442   ds.push_front(this); 
00443 }
00444 
00445 
00446 void rpnprogram::inc()
00447 {
00448   ++ counter;
00449 
00450   if (!v.empty())
00451   {
00452     for (unsigned int i=0, imax=v.size(); i<imax; ++i)
00453       v[i]->inc();
00454   }
00455 
00456   if (!variables.empty())
00457   {
00458     for (unsigned int i=0, imax=variables.size(); i<imax; ++i)
00459       variables[i]->inc();
00460   }
00461 }
00462 
00463 
00464 rpnprogram::rpnprogram
00465 (
00466   deque<rpnbase*>& ds, 
00467   deque<rpnbase*>& ds2,
00468   bool const evaluate 
00469 )
00470 {
00471   v = ds2;
00472   reverse(v.begin(),v.end()); /* <TODO> make efficent with reverse copy? */
00473 
00474   if (evaluate)
00475   {
00476     eval(ds);
00477     return;
00478   }
00479 
00480   ds.push_front(this);
00481 }
00482 
00483 rpnprogram::rpnprogram(deque<rpnbase*>& ds)
00484 {
00485   ds.push_front(this);
00486 }
00487 
00488 rpnprogram::rpnprogram()
00489 {
00490 }
00491 
00492 ostream& rpnprogram::print(ostream& os) const
00493 {
00494   os << "{";
00495   if( v.empty())
00496     return os << " }";
00497 
00498   for (unsigned int i=0,imax=v.size(); i<imax; ++i)
00499   {
00500     os << " ";
00501     v[i]->print(os);
00502   }
00503 
00504   return os << " }";
00505 }
00506 
00507 rpnbase* rpnprogram::copy() const
00508 {
00509   /* A deep copy is required. */
00510 
00511   rpnprogram* p = new rpnprogram();
00512 
00513   if (v.empty())
00514   {  
00515     if (variables.empty())
00516       return p;
00517 
00518     for (unsigned int i=0, imax=variables.size(); i<imax; ++i)
00519     {
00520       rpnbase* tmp = variables[i]->copy();
00521       p->variables.push_back( (rpnvar*)tmp ); 
00522     }
00523 
00524     return p;
00525   }
00526 
00527   deque<rpnbase*> &v2 = p->v;
00528 
00529   for (unsigned int i=0, imax=v.size(); i<imax; ++i)
00530     v2.push_back( v[i]->copy() );
00531 
00532   if (variables.empty())
00533     return p;
00534 
00535   for (unsigned int i=0, imax=variables.size(); i<imax; ++i)
00536   {
00537     rpnbase* tmp = variables[i]->copy();
00538     p->variables.push_back( (rpnvar*)tmp );
00539   }
00540 
00541   return p;
00542 };
00543   
00544 rpnprogram::~rpnprogram()
00545 {
00546   if (!v.empty())
00547   {
00548     for (unsigned int i=0, imax=v.size(); i<imax; ++i)
00549       v[i]->dec();
00550     v.clear();
00551   }
00552 
00553   if (!variables.empty())
00554   {
00555     for (unsigned int i=0, imax=variables.size(); i<imax; ++i)
00556       variables[i]->dec();
00557     variables.clear();
00558   }
00559 }
00560 
00561 void rpnprogram::eval( deque<rpnbase*>& ds )
00562 {
00563   rpnprogramstackstate().push(this);
00564 
00565   if(!v.empty())
00566   {
00567     for (unsigned int i=0,imax=v.size(); i<imax; ++i )
00568     {
00569       if (v[i]->isprogram())
00570         ds.push_front(v[i]);
00571       else
00572         v[i]->eval(ds);
00573     }
00574   }
00575 
00576   rpnprogramstackstate().pop();
00577  
00578   dec();
00579 }
00580 
00581 inline void rpnvar::inc()
00582 { 
00583   ++counter;
00584   x->inc();
00585 }
00586 
00587 inline rpnvar::~rpnvar()
00588 {
00589   if (x==0)
00590     return;
00591 
00592   x->dec();
00593 }
00594 
00595 inline rpnvar::rpnvar(rpnprogram& prog, rpnbase* x_, string const & s)
00596   : varname(s), x(x_)
00597 {
00598   prog.variables.push_front(this);
00599 }
00600 
00601 inline rpnvar::rpnvar(rpnbase* x_, string const & s)
00602   : varname(s), x(x_)
00603 {
00604 }
00605 
00606 rpnbase* rpnvar::copy() const
00607 {
00608   return new rpnvar( x->copy(),varname);
00609 }
00610 
00611 ostream& rpnvar::print(ostream& os) const
00612 {
00613   os << varname << " : ";
00614   return x->print(os);
00615 }
00616 
00617 
00618 rpnvector::rpnvector(int index)
00619 {
00620   reverseindex = indexcomplement(index);
00621 }
00622 
00623 rpnbase* rpnvector::copy() const
00624 {
00625   /* I do not want a default contructor, so put a dummy
00626      argument in.  The reverseindex should be preserved
00627      with a copy as they point to the same place.
00628   */
00629   rpnvector* p = new rpnvector((int)0);
00630   p->reverseindex = reverseindex;
00631   return p;
00632 }
00633 
00634 int const rpnvector::indexcomplement(int const n) const
00635 {
00636   int k = rpnprogramstackstate().ds().size();
00637   k -= n;
00638   return k;
00639 }
00640 
00641 const int rpnvector::index() const
00642 {
00643   return indexcomplement(reverseindex);
00644 }
00645 
00646 
00647 ostream& rpnvector::print(ostream& os) const
00648 {
00649   return os << " " << index() << " [] ";
00650   //return os << " " << indexcomplement(reverseindex) << " [] ";
00651 }
00652   
00653 
00654 rpnbase* rpnfunction::copy() const
00655 {
00656   return 0;
00657 }
00658 
00659 
00660 deque<rpnbase*> rpnprogramstackstate::ds2;
00661 deque<rpnprogram*>* rpnprogramstackstate::ps =
00662   new deque<rpnprogram*>();
00663 rpnprogram rpnprogramstackstate::rpnhome;
00664 string rpnprogramstackstate::findprogrampath;
00665 
00666 void rpnprogramstackstate::find 
00667 (
00668   bool & result,
00669   unsigned int & indexi,
00670   unsigned int & indexk,
00671   rpnvar* & x,
00672   string const & nm
00673 ) const
00674 {
00675   result=false;
00676 
00677   for (unsigned int i=0, imax=ps->size(); i<imax; ++i)
00678   {
00679     deque<rpnprogram*>& w = *ps; // <TODO> optimize.
00680     if ( ! w[i]->variables.empty() )
00681     {
00682       deque<rpnvar*>& z = w[i]->variables;
00683       for (unsigned int k=0, kmax=z.size(); k<kmax; ++k)
00684       {
00685         if (z[k]->varname==nm)
00686         {
00687           result=true;
00688           indexi = i;
00689           indexk = k;
00690           x = z[k];
00691 
00692           return;
00693         }
00694       }
00695     }
00696   }
00697 }
00698 
00699 
00700 
00701 /* While developing rely on general find, optimize at a later date. */
00702 
00703 
00704 
00705 void rpnprogramstackstate::exists
00706 (
00707   bool & res,
00708   string const & nm
00709 ) const
00710 {
00711   unsigned int i,k;
00712   rpnvar* x;
00713 
00714   find(res,i,k,x,nm);
00715 }
00716 
00717 
00718 void rpnprogramstackstate::evaluate
00719 (
00720   deque<rpnbase*>& ds,
00721   string const & nm
00722 ) const
00723 {
00724   bool res;
00725   unsigned int i,k;
00726   rpnvar* x;
00727 
00728   find(res,i,k,x,nm);
00729   if (res)
00730     x->x->copy()->eval(ds);
00731 }
00732 
00733 void rpnprogramstackstate::recall
00734 (
00735   deque<rpnbase*>& ds,
00736   string const & nm
00737 ) const
00738 {
00739   bool res;
00740   unsigned int i,k;
00741   rpnvar* x;
00742 
00743   find(res,i,k,x,nm);
00744   if (res)
00745     ds.push_front(x->x->copy());
00746 }
00747 
00748 void rpnprogramstackstate::recallpointer
00749 (
00750   deque<rpnbase*>& ds,
00751   string const & nm
00752 ) const
00753 {
00754   bool res;
00755   unsigned int i,k;
00756   rpnvar* x;
00757 
00758   find(res,i,k,x,nm);
00759   if (res)
00760   {
00761     x->x->inc();
00762     ds.push_front(x->x);
00763   }
00764 }
00765 
00766 
00767 void rpnprogramstackstate::replace(rpnbase* x, string const & nm)
00768 {
00769   bool res;
00770   unsigned int i,k;
00771   rpnvar* x2;
00772 
00773   find(res,i,k,x2,nm);
00774   if (res)
00775   {
00776     x2->x->dec();
00777     x2->x = x; 
00778   }
00779   else
00780     x->dec();  /* harsh */
00781 }
00782 
00783 void rpnprogramstackstate::erase(string const & nm)
00784 {
00785   bool res;
00786   unsigned int i,k;
00787   rpnvar* x2;
00788 
00789   find(res,i,k,x2,nm);
00790   if (res)
00791   {
00792     deque<rpnprogram*>& w = *ps;
00793     w[i]->variables.erase( w[i]->variables.begin()+k );
00794   }
00795 }
00796 
00797 void rpnprogramstackstate::init()
00798 {
00799   ps->push_front( &rpnhome );
00800 }
00801 
00802 ostream& rpnprogramstackstate::print(ostream& os) const
00803 {
00804   for (unsigned int i=0, imax=ps->size(); i<imax; ++i)
00805   {
00806     os << "{ ";
00807     deque<rpnprogram*>& w = *ps;
00808     if ( ! w[i]->variables.empty() )
00809     {
00810       deque<rpnvar*>& z = w[i]->variables;
00811       for (unsigned int k=0, kmax=z.size(); k<kmax; ++k)
00812       {
00813         os << "(" << z[k]->varname << ",";
00814         z[k]->x->print(os);
00815         os << ") ";
00816       }
00817     }
00818     os << "}" << endl;
00819   }
00820   return os;
00821 }
00822 
00823 void rpnprogramstackstate::add(rpnbase* x, string const & s)
00824 {
00825   ps->front()->variables.push_front( new rpnvar(x,s) );
00826 }
00827 
00828 
00829 void rpnprogramstackstate::findprogram
00830 (
00831   bool& found, 
00832   string& path, 
00833   rpnprogram* targ
00834 )
00835 {
00836   found = false;
00837 
00838 
00839   if (targ==&rpnhome)
00840   {
00841     findprogrampath = path = "/";
00842     found = true;
00843     return;
00844   }
00845 
00846   findprogram(found,&rpnhome,"",targ);
00847 
00848   if (found)
00849     path = findprogrampath;
00850 }
00851 
00852 void rpnprogramstackstate::findprogram
00853 (
00854   bool& found, 
00855   rpnprogram* p, 
00856   string const path, 
00857   rpnprogram* targ
00858 )
00859 {
00860   /* Depth first search. */
00861   /* Assume non-cyclic data structure. */
00862 
00863   if (!p->variables.empty())
00864   {
00865     for (unsigned int i=0, imax=p->variables.size(); i<imax; ++i)
00866     {
00867       if (found)
00868         return;
00869 
00870       if (p->variables[i]->x->isprogram())
00871       {
00872         rpnprogram* pr = (rpnprogram*)(p->variables[i]->x);
00873 
00874         string pathnew( path + string("/") + p->variables[i]->varname );
00875 
00876         if (pr == targ)
00877         {
00878           found = true;
00879           findprogrampath = pathnew;
00880           return;
00881         }
00882         else
00883           findprogram(found,pr,pathnew,targ);
00884 
00885       }
00886     }
00887   }
00888 }
00889 
00890 
00891 
00892 
00893 
00894 #endif
00895 
00896 
00897 

Generated on Fri Mar 4 00:49:30 2011 for Chelton Evans Source by  doxygen 1.5.8