#ifndef INC_GDLInterpreter_hpp_
#define INC_GDLInterpreter_hpp_

#include <antlr/config.hpp>
#include "GDLInterpreterTokenTypes.hpp"
/* $ANTLR 2.7.7 (2006-11-01): "gdlc.i.g" -> "GDLInterpreter.hpp"$ */
#include <antlr/TreeParser.hpp>


    // antlr header

    // make sure it gets included before the 'tweak'
#include "GDLParser.hpp" 
#include "GDLTreeParser.hpp" 

#include <map>
#include <iomanip>
//#include <exception>

#include "datatypes.hpp"
#include "objects.hpp"
#include "dpro.hpp"
#include "accessdesc.hpp"
#include "initsysvar.hpp"
#include "gdljournal.hpp"
#include "nullgdl.hpp"

//class ProgNode;
//typedef ProgNode* ProgNodeP;

// tweaking ANTLR
#define RefAST( xxx)     ConvertAST( xxx) /* antlr::RefAST( Ref type)  */

// print out AST tree
//#define GDL_DEBUG
//#undef GDL_DEBUG
//#define GDL_DEBUG_HEAP
bool IsEnabledGC(); // defined in GDLInterpreter.hpp with EnableGC(bool);
void EnableGC(bool);

class CUSTOM_API GDLInterpreter : public antlr::TreeParser, public GDLInterpreterTokenTypes
{

private:
    // ASTNULL replacement
    static ProgNode  NULLProgNode;
    static ProgNodeP NULLProgNodeP;

    friend class BaseGDL;
    friend class ProgNode;
    friend class ARRAYDEFNode;
    friend class ARRAYDEF_GENERALIZED_INDGENNode;
    friend class STRUCNode;
    friend class NSTRUCNode;
    friend class NSTRUC_REFNode;
    friend class ASSIGNNode;
    friend class ASSIGN_ARRAYEXPR_MFCALLNode;
    friend class ASSIGN_REPLACENode;
    friend class PCALL_LIBNode;//: public CommandNode
    friend class MPCALLNode;//: public CommandNode
    friend class MPCALL_PARENTNode;//: public CommandNode
    friend class PCALLNode;//: public CommandNode
    friend class RETFNode;
    friend class RETPNode;
    friend class FORNode;
    friend class FOR_LOOPNode;
    friend class FOREACHNode;
    friend class FOREACH_LOOPNode;
    friend class FOREACH_INDEXNode;
    friend class FOREACH_INDEX_LOOPNode;
    friend class FOR_STEPNode;
    friend class FOR_STEP_LOOPNode;
    friend class KEYDEFNode;
    friend class KEYDEF_REFNode;
    friend class KEYDEF_REF_CHECKNode;
    friend class KEYDEF_REF_EXPRNode;
    friend class REFNode;
    friend class REF_CHECKNode;
    friend class REF_EXPRNode;
    friend class ParameterNode;
    friend class REFVNNode;
    friend class REF_CHECKVNNode;
    friend class REF_EXPRVNNode;
    friend class ParameterVNNode;
    friend class WRAPPED_FUNNode;
    friend class WRAPPED_PRONode;

public: 
//     RetCode returnCode;    
    ProgNodeP GetNULLProgNodeP() const { return NULLProgNodeP;}


    void SetRetTree( ProgNodeP rT)
    {
        this->_retTree = rT;
    }
    ProgNodeP GetRetTree() const
    {
        return this->_retTree;
    }
//     void SetReturnCode( RetCode rC)
//     {
//         this->returnCode = rC;
//     }
    
//     enum RetCode {
//         RC_OK=0,
//         RC_BREAK,
//         RC_CONTINUE,
//         RC_RETURN, 
//         RC_ABORT, // checked as retCode >= RC_RETURN
//     };  

    // code in: dinterpreter.cpp
    // procedure (searchForPro == true) or function (searchForPro == false)
    static bool SearchCompilePro(const std::string& pro, bool searchForPro); 
    static int GetFunIx( ProgNodeP);
    static int GetFunIx( const std::string& subName);
    static int GetProIx( ProgNodeP);//const std::string& subName);
    static bool CheckProExist( const std::string& subName);
    static int GetProIx( const std::string& subName);
    DStructGDL* ObjectStruct( DObjGDL* self, ProgNodeP mp);
    void SetRootR( ProgNodeP tt, DotAccessDescT* aD, BaseGDL* r, ArrayIndexListT* aL);
    void SetRootL( ProgNodeP tt, DotAccessDescT* aD, BaseGDL* r, ArrayIndexListT* aL);
    // DStructGDL* ObjectStructCheckAccess( DObjGDL* self, ProgNodeP mp);
    // DStructDesc* GDLObjectDesc( DObjGDL* self, ProgNodeP mp);

    // code in: dinterpreter.cpp
    static void SetFunIx( ProgNodeP f); // triggers read/compile


private: 

    static void SetProIx( ProgNodeP f); // triggers read/compile
    static void AdjustTypes( BaseGDL*&, BaseGDL*&);


protected:
    std::istringstream executeLine; // actual interactive executed line

//     std::vector<BaseGDL*> tmpList;
//     void ClearTmpList()
//     {
//         std::vector<BaseGDL*>::iterator i;
//         for(i = tmpList.begin(); i != tmpList.end(); ++i) 
//             { delete *i;}
//         tmpList.clear();
//     }

    class RetAllException 
    {
        public:
        enum ExCode {
            NONE=0 // normal RETALL
            ,RUN   // RETALL from .RUN command
            ,RESET // RETALL from .RESET command
            ,FULL_RESET // RETALL from .FULL_RESET command
        };  

        private:
        ExCode code;

        public:
        RetAllException( ExCode code_=NONE): code( code_) {}

        ExCode Code() { return code;}
    };
    
    // code in: dinterpreter.cpp
//    static bool CompleteFileName(std::string& fn); -> str.cpp

    BaseGDL*  returnValue;  // holding the return value for functions
    BaseGDL** returnValueL; // holding the return value for l_functions

    bool interruptEnable;
public:
    bool InterruptEnable() const { return interruptEnable;}
    // procedure (searchForPro == true) or function (searchForPro == false)
    static bool CompileFile(const std::string& f, 
                            const std::string& untilPro="",
                            bool searchForPro=true); 
    static bool CompileSaveFile(RefDNode theAST); 
    typedef RefHeap<BaseGDL> RefBaseGDL;
    typedef RefHeap<DStructGDL> RefDStructGDL;

    typedef std::map<SizeT, RefBaseGDL> HeapT;
    typedef std::map<SizeT, RefDStructGDL> ObjHeapT;

protected:
//     typedef std::map<SizeT, BaseGDL*> HeapT;
//     typedef std::map<SizeT, DStructGDL*> ObjHeapT;

    // the following must be all static because several interpreter might be active
    // the heap for all dynamic variables
    // ease the handling, no memory leaks, gc possible
    static HeapT     heap; 
    static ObjHeapT  objHeap; 

    // index for newly allocated heap variables
    static SizeT heapIx;

    static EnvStackT  callStack; 
    static bool noInteractive;
    static bool InBatchProcedureAtMain;
    static DLong stepCount;
    static std::string MyProName;

// smuggle optimizations in
//#include "GDLInterpreterOptimized.inc"


public:
    // triggers read/compile/interpret
    DStructDesc* GetStruct(const std::string& name, const ProgNodeP cN); 

//     bool Called( std::string proName)
//     {
//         for( EnvStackT::reverse_iterator env = callStack.rbegin();
//             env != callStack.rend();
//             ++env)
//             {
//                 //std::cout <<  (*env)->GetPro()->ObjectFileName() << std::endl;
//                 if( proName == (*env)->GetPro()->ObjectFileName()) return true;
//             }
//         return false;
//     }

//   static bool IsEnabledGC() { return enable_GC;}
	static bool IsEnabledGC() { return true;}

    // the New... functions 'own' their BaseGDL*
    SizeT NewObjHeap( SizeT n=1, DStructGDL* var=NULL)
    {
        SizeT tmpIx=heapIx;
        for( SizeT i=0; i<n; i++)
        objHeap.insert( objHeap.end(),
            std::pair<SizeT, RefDStructGDL>( heapIx++, (DStructGDL*)var));
        return tmpIx;
    }
    SizeT NewHeap( SizeT n=1, BaseGDL* var=NULL)
    {
        SizeT tmpIx=heapIx;
        for( SizeT i=0; i<n; i++)
        heap.insert( heap.end(),
            std::pair<SizeT, RefBaseGDL>( heapIx++, var));
        return tmpIx;
    }
    static void FreeObjHeapDirect( DObj id, ObjHeapT::iterator it)
    {
        BaseGDL* del = (*it).second.get();
        objHeap.erase( id); 
        if (!NullGDL::IsNULLorNullGDL(del)) delete del; //avoid destroying !NULL
    }
    static void FreeObjHeap( DObj id)
    {
        if( id != 0)
        {       
            ObjHeapT::iterator it=objHeap.find( id);
            if  ( it != objHeap.end()) 
            { 
                FreeObjHeapDirect( id, it);
            }
        }
    }
    static void FreeHeapDirect( DPtr id, HeapT::iterator it)
    {
        BaseGDL* del = (*it).second.get();
        heap.erase( id); 
        if (!NullGDL::IsNULLorNullGDL(del)) delete del; //avoid destroying !NULL
    }
    static void FreeHeap( DPtr id)
    {
        if( id != 0)
            {
                HeapT::iterator it=heap.find( id);
                if( it != heap.end()) 
                    { 
                        FreeHeapDirect( id, it);
                    }
            }
    }
    static void HeapErase( DPtr id) // for LIST
    {
        if( id != 0)
            {
              heap.erase( id); 
            }
    }

   static void FreeHeap( DPtrGDL* p)
    {
        SizeT nEl=p->N_Elements();
        for( SizeT ix=0; ix < nEl; ix++)
        {
            DPtr id= (*p)[ix];
            FreeHeap( id);
       }
    }

   static DByteGDL* IsEnabledGC( DPtrGDL* p)
   {
		SizeT nEl=p->N_Elements();
		if( nEl == 0) return new DByteGDL( 0);
		DByteGDL* ret = new DByteGDL( p->Dim());
		Guard<DByteGDL> guard(ret);
		for( SizeT ix=0; ix < nEl; ix++)
		{
			DPtr id= (*p)[ix];
		   if( id != 0)
			   {
			   HeapT::iterator it=heap.find( id);
			   if( it != heap.end() and (*it).second.IsEnabledGC())
					(*ret)[ix] = 1;
			   }
		}
		return guard.release();
   }
   static DByteGDL* IsEnabledGCObj( DObjGDL* p)
   {
        SizeT nEl=p->N_Elements();
        if( nEl == 0) return new DByteGDL( 0);
        DByteGDL* ret = new DByteGDL( p->Dim());
        Guard<DByteGDL> guard(ret);
        for( SizeT ix=0; ix < nEl; ix++)
   {
            DObj id= (*p)[ix];
		   if( id != 0)
			   {
			   ObjHeapT::iterator it=objHeap.find( id);
			   if( it != objHeap.end() and (*it).second.IsEnabledGC())
					(*ret)[ix] = 1;
			   }
        }
        return guard.release();
   }

   static void EnableGC( DPtr id, bool set=true)
   {
       if( id != 0)
           {
		   HeapT::iterator it=heap.find( id);
		   if( it != heap.end()) (*it).second.EnableGC(set);
           }
   }
   static void EnableGC( DPtrGDL* p, bool set=true)
   {
        SizeT nEl=p->N_Elements();
        for( SizeT ix=0; ix < nEl; ix++)
        {
            DPtr id= (*p)[ix];
            EnableGC( id, set);
       }
   }
   static void EnableAllGC() {
        for( HeapT::iterator it=heap.begin(); it != heap.end(); ++it)
			it->second.EnableGC(true);
        for( ObjHeapT::iterator it=objHeap.begin(); it != objHeap.end(); ++it)
			it->second.EnableGC(true);
   }

   static void EnableGCObj( DObj id, bool set=true)
   {
       if( id != 0)
           {
		   ObjHeapT::iterator it=objHeap.find( id);
		   if( it != objHeap.end()) (*it).second.EnableGC(set);
           }
   }
   static void EnableGCObj( DObjGDL* p, bool set=true)
   {
        SizeT nEl=p->N_Elements();
        for( SizeT ix=0; ix < nEl; ix++)
        {
            DObj id= (*p)[ix];
            EnableGCObj( id, set);
       }
   }

   static void DecRef( DPtr id)
   {
       if( id != 0 and IsEnabledGC())
           {
#ifdef GDL_DEBUG_HEAP
               std::cout << "-- <PtrHeapVar" << id << ">" << std::endl; 
#endif
               HeapT::iterator it=heap.find( id);
               if( it != heap.end()) 
                   { 
                       if( (*it).second.Dec() and (*it).second.IsEnabledGC() )
                           {
#ifdef GDL_DEBUG_HEAP
                               std::cout << "Out of scope (garbage collected): <PtrHeapVar" << id 
                                         << ">"
                                         << " at: " << callStack.back()->GetProName()
                                         << "  line: " << callStack.back()->GetLineNumber()
                                         << std::endl; 
#endif
                               FreeHeapDirect( id, it);
                           }
#ifdef GDL_DEBUG_HEAP
                       else
                           std::cout << "<PtrHeapVar" << id << "> = " << (*it).second.Count() << std::endl; 
#endif
                   }
           }
   }
   static void DecRef( DPtrGDL* p)
    {
        SizeT nEl=p->N_Elements();
        for( SizeT ix=0; ix < nEl; ix++)
        {
            DPtr id= (*p)[ix];
            DecRef( id);
       }
    }
   static void DecRefObj( DObj id)
    {
        if( id != 0 and IsEnabledGC())
            {
#ifdef GDL_DEBUG_HEAP
std::cout << "-- <ObjHeapVar" << id << ">" << std::endl; 
#endif
                ObjHeapT::iterator it=objHeap.find( id);
                if( it != objHeap.end()) 
                    { 
                       if( (*it).second.Dec() and (*it).second.IsEnabledGC() )
                           {
#ifdef GDL_DEBUG_HEAP
                               std::cout << "Out of scope (garbage collected): <ObjHeapVar" << id 
                                         << ">"
                                         << " at: " << callStack.back()->GetProName()
                                         << "  line: " << callStack.back()->GetLineNumber()
                                         << std::endl; 
#endif
                               callStack.back()->ObjCleanup( id);
//                             FreeObjHeapDirect( id, it);
                           }
#ifdef GDL_DEBUG_HEAP
                        else
std::cout << "<ObjHeapVar" << id << "> = " << (*it).second.Count() << std::endl; 
#endif
                        
                     }
            }
    }
   static void DecRefObj( DObjGDL* p)
    {
        SizeT nEl=p->Size();//N_Elements();
        for( SizeT ix=0; ix < nEl; ix++)
        {
            DObj id= (*p)[ix];
            DecRefObj( id);
       }
    }
   static void IncRef( DPtr id)
    {
        if( id != 0 and IsEnabledGC())
            {
#ifdef GDL_DEBUG_HEAP
std::cout << "++ <PtrHeapVar" << id << ">" << std::endl; 
#endif
                HeapT::iterator it=heap.find( id);
                if( it != heap.end()) 
                    { 
                        (*it).second.Inc(); 
#ifdef GDL_DEBUG_HEAP
std::cout << "<PtrHeapVar" << id << "> = " << (*it).second.Count() << std::endl; 
#endif
                    }
            }
    }
   static void AddRef( DPtr id, SizeT add)
    {
        if( id != 0)
            {
#ifdef GDL_DEBUG_HEAP
std::cout << add << " + <PtrHeapVar" << id << ">" << std::endl; 
#endif
                HeapT::iterator it=heap.find( id);
                if( it != heap.end()) 
                    { 
                        (*it).second.Add(add); 
                    }
            }
    }
   static SizeT RefCountHeap( DPtr id)
    {
		SizeT result = 0;
        if( id != 0)
            {
                HeapT::iterator it=heap.find( id);
                if( it != heap.end()) result = (*it).second.Count();
			}
		return result;
	   }
   static SizeT RefCountHeapObj( DObj id)
    {
		SizeT result = 0;
        if( id != 0)
            {
                ObjHeapT::iterator it=objHeap.find( id);
                if( it != objHeap.end()) result = (*it).second.Count();
			}
		return result;
	   }
   static void IncRef( DPtrGDL* p)
    {
        SizeT nEl=p->N_Elements();
        for( SizeT ix=0; ix < nEl; ix++)
        {
            DPtr id= (*p)[ix];
            IncRef( id);
       }
    }
   static void IncRefObj( DObj id)
    {
        if( id != 0 and IsEnabledGC())
            {
#ifdef GDL_DEBUG_HEAP
std::cout << "++ <ObjHeapVar" << id << ">" << std::endl; 
#endif
                ObjHeapT::iterator it=objHeap.find( id);
                if( it != objHeap.end()) 
                    { 
                        (*it).second.Inc(); 
                    }
            }
    }
   static void AddRefObj( DObj id, SizeT add)
    {
        if( id != 0)
            {
#ifdef GDL_DEBUG_HEAP
std::cout << add << " + <ObjHeapVar" << id << ">" << std::endl; 
#endif
                ObjHeapT::iterator it=objHeap.find( id);
                if( it != objHeap.end()) 
                    { 
                        (*it).second.Add(add); 
                    }
            }
    }
   static void IncRefObj( DObjGDL* p)
    {
        SizeT nEl=p->Size();//N_Elements();
        for( SizeT ix=0; ix < nEl; ix++)
        {
            DObj id= (*p)[ix];
            IncRefObj( id);
       }
    }

    class HeapException {};

    static BaseGDL*& GetHeap( DPtr ID)
    {
        HeapT::iterator it=heap.find( ID);
        if( it == heap.end()) 
            throw HeapException();
        return it->second.get();
    }
    static BaseGDL* GetHeapNoThrow( DPtr ID)
    {
        HeapT::iterator it=heap.find( ID);
        if( it == heap.end())  return NULL;
        return it->second.get();
    }
    static DStructGDL*& GetObjHeap( DObj ID)
    {
        ObjHeapT::iterator it=objHeap.find( ID);
        if( it == objHeap.end()) 
            throw HeapException();
        return it->second.get();
    }

    // for overload functions
    static DSubUD* GetObjHeapOperator( DObj ID, int opIx)
    {
        if( ID == 0) return NULL;
        ObjHeapT::iterator it=objHeap.find( ID);
        if( it == objHeap.end()) return NULL;
        return it->second.get()->Desc()->GetOperator( opIx);
    }
    static DStructGDL* GetObjHeapNoThrow( DObj ID)
    {
        ObjHeapT::iterator it=objHeap.find( ID);
        if( it == objHeap.end()) return NULL;
        return it->second.get();
    }
//     static DStructGDL*& GetObjHeap( DObj ID, ObjHeapT::iterator& it)
//     {
// //         ObjHeapT::iterator it=objHeap.find( ID);
//         it=objHeap.find( ID);
//         if( it == objHeap.end()) throw HeapException();
//         return it->second.get();
//     }

    static bool PtrValid( DPtr ID)
    {
        HeapT::iterator it=heap.find( ID);
        return  (it != heap.end());
    }

    static SizeT HeapSize()
    {
        return heap.size();
    }

    static DPtr FindInHeap( BaseGDL** p)
    {
        for( HeapT::iterator it=heap.begin(); it != heap.end(); ++it)
        {
            if( &it->second.get() == p)
                return it->first;
        }
        return 0;
    }
    // static BaseGDL** GetPtrToHeap( BaseGDL* p)
    // {
    //     for( HeapT::iterator it=heap.begin(); it != heap.end(); ++it)
    //     {
    //         if( it->second.get() == p)
    //             return &it->second.get();
    //     }
    //     return NULL;
    // }
    static DPtrGDL* GetAllHeap()
    {
        SizeT nEl = heap.size();
        if( nEl == 0) return new DPtrGDL( 0);
        DPtrGDL* ret = new DPtrGDL( dimension( &nEl, 1), BaseGDL::NOZERO);
        SizeT i=0;
        for( HeapT::iterator it=heap.begin(); it != heap.end(); ++it)
        {
            IncRef( it->first);
            (*ret)[ i++] = it->first;
        }
        return ret;
    }

    // no ref counting here
    static std::vector<DPtr>* GetAllHeapSTL()
    {
        SizeT nEl = heap.size();
        if( nEl == 0) return new std::vector<DPtr>();
        std::vector<DPtr>* ret = new std::vector<DPtr>( nEl);
        SizeT i=0;
        for( HeapT::iterator it=heap.begin(); it != heap.end(); ++it)
        {
            (*ret)[ i++] = it->first;
        }
        return ret;
    }

    static bool ObjValid( DObj ID)
    {
        ObjHeapT::iterator it=objHeap.find( ID);
        return  (it != objHeap.end());
    }

    static SizeT ObjHeapSize()
    {
        return objHeap.size();
    }

//     static DObj FindInObjHeap( BaseGDL** p)
//     {
//         for( ObjHeapT::iterator it=objHeap.begin(); it != objHeap.end(); ++it)
//         {
//             if( &it->second == reinterpret_cast<DStructGDL**>(p))
//                 return it->first;
//         }
//         return 0;
//     }
    static DObjGDL* GetAllObjHeap()
    {
        SizeT nEl = objHeap.size();
        if( nEl == 0) return new DObjGDL( 0);
        DObjGDL* ret = new DObjGDL( dimension( &nEl, 1), BaseGDL::NOZERO);
        SizeT i=0;
        for( ObjHeapT::iterator it=objHeap.begin(); it != objHeap.end(); ++it)
        {
            IncRefObj( it->first);
            (*ret)[ i++] = it->first;
        }
        return ret;
    }

    // no ref counting here
    static std::vector<DObj>* GetAllObjHeapSTL()
    {
        SizeT nEl = objHeap.size();
        if( nEl == 0) return new std::vector<DObj>();
        std::vector<DObj>* ret = new std::vector<DObj>( nEl);
        SizeT i=0;
        for( ObjHeapT::iterator it=objHeap.begin(); it != objHeap.end(); ++it)
        {
            (*ret)[ i++] = it->first;
        }
        return ret;
    }


    static void ResetHeap() // purges both heaps
    {
        for( HeapT::iterator it=heap.begin(); it != heap.end(); ++it)
        {
           BaseGDL* del = (*it).second.get();
           if (!NullGDL::IsNULLorNullGDL(del)) delete del; //avoid destroying !NULL
           heap.erase( it->first); 
        }
        for( ObjHeapT::iterator it=objHeap.begin(); it != objHeap.end(); ++it)
        {
           BaseGDL* del = (*it).second.get();
           if (!NullGDL::IsNULLorNullGDL(del)) delete del; //avoid destroying !NULL
           heap.erase( it->first);
        }
// The counters are reset for easier human readability.
       heapIx = 1;
    }

    // name of data
    static const std::string Name( BaseGDL* p) // const
    {
        return callStack.back()->GetString( p);
    }

    static const std::string Name( BaseGDL** p) // const
    {
        assert( *p == NULL);
        DPtr h = FindInHeap( p);
        if( h != 0) return std::string("<PtrHeapVar")+i2s(h)+">";
//         DObj o = FindInObjHeap( p);
//         if( o != 0) return std::string("<ObjHeapVar")+i2s(o)+">";
        return "<(ptr to undefined expression not found on the heap)>";
    }




    // compiler (lexer, parser, treeparser) def in dinterpreter.cpp
    static void ReportCompileError( GDLException& e, const std::string& file = "");

    // interpreter
    static void ReportError( GDLException& e, const std::string &emsg, 
                             bool dumpStack=true)
    {
        DString msgPrefix = SysVar::MsgPrefix();

        std::cout << std::flush;
        if( dumpStack)
            {
                if( e.Prefix())
                    {
                      std::cerr << msgPrefix << e.toString() << std::endl;
                      lib::write_journal_comment(msgPrefix+e.toString());
                    }
                else
                    {
                        std::cerr << e.toString() << std::endl;
                        lib::write_journal_comment(e.toString());
                    }
            }

        std::cerr << msgPrefix << emsg << " " << 
        std::left << std::setw(16) << callStack.back()->GetProName();
        std::string file=callStack.back()->GetFilename();
        if( file != "")
        {
            SizeT line = callStack.back()->GetLineNumber(); //e.getLine();
            if( line != 0)
            {       
                std::cerr << std::right << std::setw(6) << line;
            }
            else
            {
                std::cerr << std::right << std::setw(6) << "";
            }
            std::cerr << std::left << " " << file;
        }
        std::cerr << std::endl;
        
        if( dumpStack) DumpStack( emsg.size() + 1);
        if (noInteractive) exit(EXIT_SUCCESS); //strangely, IDL exits on error when non interactive with 0 not 1.
    }
    
    static void DumpStack( SizeT w)
    {
        DString msgPrefix = SysVar::MsgPrefix();

        // EnvStackT::reverse_iterator upEnv = callStack.rbegin();
        // //EnvStackT::reverse_iterator env = upEnv++;
        // upEnv++;
        // for(; 
        //     upEnv != callStack.rend();
        //     ++upEnv /*,++env*/)
        
        long actIx = callStack.size() - 2;
        for( ; actIx >= 0; --actIx)
        {
            EnvStackT::pointer_type upEnv = callStack[ actIx]; 

            std::cerr << msgPrefix << std::right << std::setw( w) << "";
            std::cerr << std::left << std::setw(16) << upEnv->GetProName();

            std::string file = upEnv->GetFilename();
            if( file != "")
            {              
//                 ProgNodeP cNode= (*env)->CallingNode();
//                 if( cNode != NULL)
//                 {       
//                     std::cerr << std::right << std::setw(6) << cNode->getLine();
//                 }
//                 else
//                 {
//                     std::cerr << std::right << std::setw(6) << "";
//                 }                
//                 ProgNodeP cNode= (*env)->CallingNode();
//                 if( cNode != NULL && cNode->getLine() != 0)
//                 {       
//                     (*upEnv)->SetLineNumber( cNode->getLine());
//                 }

                int lineNumber = upEnv->GetLineNumber();
                if( lineNumber != 0)
                {       
                    std::cerr << std::right << std::setw(6) << lineNumber;
                }
                else
                {
                    std::cerr << std::right << std::setw(6) << "";
                }
                std::cerr << std::left << " " << file;
            }
            std::cerr << std::endl;
        }
    }

    static void DebugMsg( ProgNodeP _t, const std::string& msg)
    {    
        DString msgPrefix = SysVar::MsgPrefix();

        std::cout << std::flush;
        std::cerr << msgPrefix << msg
        << std::left << std::setw(16) << callStack.back()->GetProName();
        std::string file=callStack.back()->GetFilename();
        if( file != "")
        {
            ProgNodeP eNode = _t;
            if( eNode != NULL)
            {       
                std::cerr << std::right << std::setw(6) << eNode->getLine();
            }
            else
            {
                std::cerr << std::right << std::setw(6) << "";
            }
            std::cerr << std::left << " " << file;
        }
        std::cerr << std::endl;
        if (noInteractive) exit(EXIT_SUCCESS);
    }

    static void RetAll( RetAllException::ExCode c=RetAllException::NONE)    
    {
        throw RetAllException( c);
    }

    static EnvStackT& CallStack() { return callStack;} // the callstack
//    static EnvBaseT*  CallStackBack() { return callStack.back();} 
    static EnvUDT*  CallStackBack() { return callStack.back();} 
    
    std::string GetClearActualLine()
    {
        std::string ret = executeLine.str();
        executeLine.str("");
        return ret;
    }

    RetCode NewInterpreterInstance(SizeT lineOffset); // code in dinterpreter.cpp

    ~GDLInterpreter()
    {
    }
public:
	GDLInterpreter();
	static void initializeASTFactory( antlr::ASTFactory& factory );
	int getNumTokens() const
	{
		return GDLInterpreter::NUM_TOKENS;
	}
	const char* getTokenName( int type ) const
	{
		if( type > getNumTokens() ) return 0;
		return GDLInterpreter::tokenNames[type];
	}
	const char* const* getTokenNames() const
	{
		return GDLInterpreter::tokenNames;
	}
	public:  RetCode  interactive(ProgNodeP _t);
	public:  RetCode  statement(ProgNodeP _t);
	public:  RetCode  execute(ProgNodeP _t);
	public:  RetCode  statement_list(ProgNodeP _t);
	public:  BaseGDL*  call_fun(ProgNodeP _t);
	public:  BaseGDL**  call_lfun(ProgNodeP _t);
	public: void call_pro(ProgNodeP _t);
	public: BaseGDL**  l_deref(ProgNodeP _t);
	public: BaseGDL**  l_decinc_indexable_expr(ProgNodeP _t,
		 BaseGDL*& res
	);
	public:  BaseGDL**  l_function_call_internal(ProgNodeP _t);
	public: BaseGDL**  l_defined_simple_var(ProgNodeP _t);
	public: BaseGDL**  l_sys_var(ProgNodeP _t);
	public: BaseGDL**  l_decinc_array_expr(ProgNodeP _t,
		int dec_inc, BaseGDL*& res
	);
	public: BaseGDL*  l_decinc_dot_expr(ProgNodeP _t,
		int dec_inc
	);
	public: BaseGDL**  l_decinc_expr(ProgNodeP _t,
		int dec_inc, BaseGDL*& res
	);
	public: BaseGDL*  expr(ProgNodeP _t);
	public: BaseGDL*  indexable_expr(ProgNodeP _t);
	public: BaseGDL*  indexable_tmp_expr(ProgNodeP _t);
	public:  BaseGDL*  lib_function_call_internal(ProgNodeP _t);
	public: BaseGDL**  l_expr_internal(ProgNodeP _t,
		BaseGDL* right
	);
	public: BaseGDL*  tmp_expr(ProgNodeP _t);
	public: BaseGDL**  l_simple_var(ProgNodeP _t);
	public: void parameter_def(ProgNodeP _t,
		EnvBaseT* actEnv
	);
	public: BaseGDL*  r_expr(ProgNodeP _t);
	public: BaseGDL**  l_indexable_expr(ProgNodeP _t);
	public:  BaseGDL**  l_arrayexpr_mfcall_as_mfcall(ProgNodeP _t);
	public: BaseGDL**  unused_l_array_expr(ProgNodeP _t,
		BaseGDL* right
	);
	public: ArrayIndexListT*  arrayindex_list(ProgNodeP _t,
		 bool noAssoc
	);
	public: void l_dot_array_expr(ProgNodeP _t,
		DotAccessDescT* aD
	);
	public: BaseGDL**  l_arrayexpr_mfcall(ProgNodeP _t,
		BaseGDL* right
	);
	public: void tag_expr(ProgNodeP _t,
		DotAccessDescT* aD
	);
	public: void tag_array_expr(ProgNodeP _t,
		DotAccessDescT* aD
	);
	public: BaseGDL*  r_dot_indexable_expr(ProgNodeP _t,
		DotAccessDescT* aD
	);
	public: void r_dot_array_expr(ProgNodeP _t,
		DotAccessDescT* aD
	);
	public: BaseGDL*  assign_expr(ProgNodeP _t);
	public:  BaseGDL*  unused_function_call(ProgNodeP _t);
	public:  BaseGDL*  lib_function_call_retnew_internal(ProgNodeP _t);
	public: BaseGDL*  simple_var(ProgNodeP _t);
	public: BaseGDL*  sys_var(ProgNodeP _t);
	public: BaseGDL**  l_arrayexpr_mfcall_as_arrayexpr(ProgNodeP _t,
		BaseGDL* right
	);
	public: void parameter_def_n_elements(ProgNodeP _t,
		EnvBaseT* actEnv
	);
	public: void parameter_def_nocheck(ProgNodeP _t,
		EnvBaseT* actEnv
	);
	public: void arrayindex_list_overload(ProgNodeP _t,
		IxExprListT& indexList
	);
public:
	antlr::RefAST getAST()
	{
		return antlr::RefAST(returnAST);
	}
	
protected:
	ProgNodeP returnAST;
	ProgNodeP _retTree;
private:
	static const char* tokenNames[];
#ifndef NO_STATIC_CONSTS
	static const int NUM_TOKENS = 238;
#else
	enum {
		NUM_TOKENS = 238
	};
#endif
	
	static const unsigned long _tokenSet_0_data_[];
	static const antlr::BitSet _tokenSet_0;
};

#endif /*INC_GDLInterpreter_hpp_*/
