1 /***************************************************************************
2                        dinterpreter.cpp  -  main class which controls it all
3                              -------------------
4     begin                : July 22 2002
5     copyright            : (C) 2002 by Marc Schellens
6     email                : m_schellens@users.sourceforge.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "includefirst.hpp"
19 
20 #include <iostream>
21 #ifdef _MSC_VER
22 #include <io.h> // isatty, windows
23 #else
24 #include <unistd.h> // isatty, usleep
25 #endif
26 
27 //#include <wordexp.h>
28 
29 #include "dnodefactory.hpp"
30 #include "str.hpp"
31 #include "envt.hpp"
32 #include "dinterpreter.hpp"
33 #include "gdljournal.hpp"
34 #include "gdleventhandler.hpp"
35 #include "basic_pro_jmg.hpp"
36 
37 #ifdef USE_MPI
38 #include "mpi.h"
39 #endif
40 
41 #include <cassert>
42 
43 // print out AST tree
44 //#define GDL_DEBUG
45 //#undef GDL_DEBUG
46 
47 #ifdef GDL_DEBUG
48 #include "print_tree.hpp"
49 #endif
50 
51 #include <thread> // C++11
52 
53 using namespace std;
54 using namespace antlr;
55 
56 string inputstr;
57 bool historyIntialized = false;
58 
59 // instantiation of static data
60 GDLInterpreter::HeapT     GDLInterpreter::heap;
61 GDLInterpreter::ObjHeapT  GDLInterpreter::objHeap;
62 SizeT                     GDLInterpreter::heapIx;
63 EnvStackT                 GDLInterpreter::callStack;
64 DLong                     GDLInterpreter::stepCount;
65 bool                      GDLInterpreter::noInteractive; // To exit on error or stop in line execution mode (gdl -e do_something)
66 ProgNode                  GDLInterpreter::NULLProgNode;
67 ProgNodeP GDLInterpreter::NULLProgNodeP = &GDLInterpreter::NULLProgNode;
68 
69 void LibInit(); // defined in libinit.cpp
70 
DInterpreter()71 DInterpreter::DInterpreter(): GDLInterpreter()
72 {
73 //  DataStackT::Init();
74 
75   //    heap.push_back(NULL); // init heap index 0 (used as NULL ptr)
76   //    objHeap.push_back(NULL); // init heap index 0 (used as NULL ptr)
77   interruptEnable = true;
78   heapIx=1;    // map version (0 is NULL ptr)
79   returnValue  = NULL;
80   returnValueL = NULL;
81 
82 	stepCount = 0;
83 
84     // setup main level environment
85   DPro* mainPro=new DPro();        // $MAIN$  NOT inserted into proList
86   EnvUDT* mainEnv=new EnvUDT(NULL, mainPro);
87   callStack.push_back(mainEnv);   // push main environment (necessary)
88 
89   assert( ProgNode::interpreter == NULL);
90   GDLException::SetInterpreter( this);
91   ProgNode::interpreter = this; // interface to expr( ProgNodeP)
92   EnvT::interpreter = this;
93   BaseGDL::interpreter = this;
94 
95   //  tmpList.reserve(100);
96 }
97 
98 // void SetActualCompileOpt( unsigned int cOpt)
99 // {
100 // if( BaseGDL::interpreter!=NULL && BaseGDL::interpreter->CallStack().size()>0)
101 // 	BaseGDL::interpreter->CallStack().back()->SetCompileOpt( cOpt);
102 // }
103 
104 // used in the statement function.
105 // runs a new instance of the interpreter if not
106 // at main level
NewInterpreterInstance(SizeT lineOffset)107 RetCode GDLInterpreter::NewInterpreterInstance( SizeT lineOffset)
108 {
109   if( callStack.size() <= 1 && lineOffset == 0) return RC_ABORT; // stay in main loop
110 
111   assert( dynamic_cast<DInterpreter*>( this) != NULL);
112   return static_cast<DInterpreter*>( this)->InnerInterpreterLoop(lineOffset);
113 }
114 
ObjectStruct(DObjGDL * self,ProgNodeP mp)115 DStructGDL* GDLInterpreter::ObjectStruct( DObjGDL* self, ProgNodeP mp)
116 {
117 //   DType selfType = self->Type();
118 //   if( selfType != GDL_OBJ)
119 //     throw GDLException( mp, "Object reference type"
120 // 			" required in this context: "+Name(self));
121 
122   DObjGDL* obj=self;//static_cast<DObjGDL*>(self);
123 
124   SizeT o;
125   if( !obj->Scalar( o))
126     throw GDLException( mp, "Object reference"
127 			" must be scalar in this context: "+Name(self));
128 
129   if( o == 0)
130     throw GDLException( mp, "Unable to invoke method"
131 			" on NULL object reference: "+Name(self));
132 
133   DStructGDL* oStructGDL;
134   try {
135     oStructGDL= GetObjHeap( o);
136   }
137   catch ( HeapException&)
138     {
139       throw GDLException( mp, "Object not valid: "+Name(self));
140     }
141 
142   return oStructGDL;
143 }
144 
SetRootL(ProgNodeP tt,DotAccessDescT * aD,BaseGDL * r,ArrayIndexListT * aL)145 void GDLInterpreter::SetRootL( ProgNodeP tt, DotAccessDescT* aD, BaseGDL* r, ArrayIndexListT* aL)
146 {
147   if( r->Type() == GDL_STRUCT)
148   {
149       if( r->IsAssoc())
150 	  {
151 	      ArrayIndexListGuard guard( aL);
152 	      throw GDLException( tt, "File expression not allowed in this context: "+
153 					Name(r),true,false);
154 	  }
155       DStructGDL* structR=static_cast<DStructGDL*>(r);
156       aD->ADRoot(structR, aL);
157   }
158   else
159   {
160       if( r->Type() != GDL_OBJ)
161 	  {
162 	      throw GDLException( tt, "Expression must be a STRUCT in this context: "+
163 					Name(r),true,false);
164 	  }
165 
166       ArrayIndexListGuard guard( aL);
167 
168       DStructGDL* oStruct = ObjectStruct( static_cast<DObjGDL*>(r), tt);
169       DStructDesc* desc = oStruct->Desc();
170 
171       bool isObj = callStack.back()->IsObject(); // called from member subroutine?
172 
173       if( desc->IsParent( GDL_OBJECT_NAME))
174 	  {
175 	    SizeT sss = 0;
176 	    SizeT ooo = 0;
177 	    if( isObj)
178 	    {
179 	      static_cast<DObjGDL*>(r)->Scalar( ooo); // checked in ObjectStruct
180 
181 	      BaseGDL* self = callStack.back()->GetKW(callStack.back()->GetPro()->NKey()); // SELF
182 
183 	      assert( dynamic_cast<DObjGDL*>(self) != NULL);
184 
185 	      if( !static_cast<DObjGDL*>(self)->Scalar( sss))
186 		  throw GDLException( tt, "Internal error: SELF Object reference"
187 				    " must be scalar in this context: "+Name(self));
188 
189 	      assert( sss != 0);
190 	    }
191 
192 	    if( !isObj || (sss != ooo))
193 	    {
194 	      // call SetProperty
195 	      throw GDLException( tt, "Calling SetProperty not yet implemented: "+Name(r));
196 	      //return;
197 	    }
198 	  }
199 
200       if( isObj) // member access to object?
201 	  {
202 	      if( !desc->IsParent( callStack.back()->GetPro()->Object()))
203 		  {
204 		      throw GDLException( tt, "Object of type "+desc->Name()+
205 					  " is not accessible within "+
206 					  callStack.back()->GetProName() +
207 					  ": "+Name(r));
208 		  }
209 	      // DStructGDL* oStruct =
210 	      //        ObjectStructCheckAccess( static_cast<DObjGDL*>(r), tt);
211 
212 	      // oStruct cannot be "Assoc_"
213 	      aD->ADRoot( oStruct, guard.release());
214 	  }
215       else
216 	  {
217 	      throw GDLException( tt, "Expression must be a"
218 				  " STRUCT in this context: "+Name(r),
219 				  true,false);
220 	  }
221   }
222 }
223 
SetRootR(ProgNodeP tt,DotAccessDescT * aD,BaseGDL * r,ArrayIndexListT * aL)224 void GDLInterpreter::SetRootR( ProgNodeP tt, DotAccessDescT* aD, BaseGDL* r, ArrayIndexListT* aL)
225 {
226 // check here for object and get struct
227 if( r->Type() == GDL_STRUCT)
228   {
229       if( r->IsAssoc())
230 	  {
231 	      ArrayIndexListGuard guard( aL);
232 	      throw GDLException( tt, "File expression not allowed in this context: "+
233 				       Name(r),true,false);
234 	  }
235       DStructGDL* structR=static_cast<DStructGDL*>(r);
236       aD->ADRoot( structR, aL);
237   }
238 else
239   {
240       ArrayIndexListGuard guard( aL);
241 
242       if( r->Type() != GDL_OBJ)
243 	  {
244 	      throw GDLException( tt, "Expression must be a"
245 				  " STRUCT in this context: "+Name(r),
246 				  true,false);
247 	  }
248 
249       DStructGDL* oStruct = ObjectStruct( static_cast<DObjGDL*>(r), tt);
250       DStructDesc* desc = oStruct->Desc();
251 
252       bool isObj = callStack.back()->IsObject();
253 
254       if( desc->IsParent( GDL_OBJECT_NAME))
255 	  {
256 	    SizeT sss = 0;
257 	    SizeT ooo = 0;
258 	    if( isObj)
259 	    {
260 	      static_cast<DObjGDL*>(r)->Scalar( ooo); // checked in ObjectStruct
261 
262 	      BaseGDL* self = callStack.back()->GetKW(callStack.back()->GetPro()->NKey()); // SELF
263 
264 	      assert( dynamic_cast<DObjGDL*>(self) != NULL);
265 
266 	      if( !static_cast<DObjGDL*>(self)->Scalar( sss))
267 		  throw GDLException( tt, "Internal error: SELF Object reference"
268 				    " must be scalar in this context: "+Name(self));
269 
270 	      assert( sss != 0);
271 	    }
272 
273 	    if( !isObj || (sss != ooo))
274 	    {
275 	      // call GetProperty
276 	      throw GDLException( tt, "Calling GetProperty not yet implemented: "+Name(r));
277 
278 	      //aD->ADRootGetProperty( oStruct, guard.release());
279 	      return;
280 	    }
281 	  }
282 
283       if( isObj)
284 	  {
285 	      if( !desc->IsParent( callStack.back()->GetPro()->Object()))
286 		  {
287 		      throw GDLException( tt, "Object of type "+desc->Name()+
288 					  " is not accessible within "+
289 					  callStack.back()->GetProName() +
290 					  ": "+Name(r));
291 		  }
292 	      // DStructGDL* oStruct =
293 	      //     ObjectStructCheckAccess( static_cast<DObjGDL*>(r), tt);
294 
295 	      if( aD->IsOwner()) delete r;
296 	      aD->SetOwner( false); // object struct, not owned
297 
298 	      aD->ADRoot( oStruct, guard.release());
299 	  }
300       else
301 	  {
302 	      throw GDLException( tt, "Expression must be a"
303 				  " STRUCT in this context: "+Name(r),true,false);
304 	  }
305   }
306 }
307 
308 // DStructDesc* GDLInterpreter::GDLObjectDesc( DStructGDL* oStruct, ProgNodeP mp)
309 // {
310 //   //DStructGDL* oStruct = ObjectStruct( self, mp);
311 //
312 //   // check accessibility
313 //   DStructDesc* desc = oStruct->Desc();
314 //   if( !desc->IsParent( GDL_OBJECT_NAME))
315 //     {
316 //       return NULL;
317 //     }
318 //
319 //   return desc;
320 // }
321 //
322 // void GDLInterpreter::ObjectStructCheckAccess( DStructGDL* oStruct, ProgNodeP mp)
323 // {
324 //   //DStructGDL* oStruct = ObjectStruct( self, mp);
325 //
326 //   // check accessibility
327 //   DStructDesc* desc = oStruct->Desc();
328 //   if( !desc->IsParent( callStack.back()->GetPro()->Object()))
329 //     {
330 //       throw GDLException( mp, "Object of type "+desc->Name()+
331 // 			  " is not accessible within "+
332 // 			  callStack.back()->GetProName() + ": "+Name(self));
333 //     }
334 //
335 //   //return oStruct;
336 // }
337 
338 // searches and compiles procedure (searchForPro == true) or function (searchForPro == false)  'pro'
SearchCompilePro(const string & pro,bool searchForPro)339 bool GDLInterpreter::SearchCompilePro(const string& pro, bool searchForPro)
340 {
341   static StrArr openFiles;
342 
343   string proFile=StrLowCase(pro)+".pro";
344   //AppendIfNeeded( proFile, ".pro");
345 
346   bool found=CompleteFileName(proFile);
347   if( !found) return false;
348 
349   // file already opened?
350   for( StrArr::iterator i=openFiles.begin(); i != openFiles.end(); ++i)
351     {
352       if( proFile == *i) return false;
353     }
354 
355   StackSizeGuard<StrArr> guard( openFiles);
356 
357   // append file to list
358   openFiles.push_back(proFile);
359 
360   return CompileFile( proFile, pro, searchForPro); // this might trigger recursion
361 }
362 
363 // returns the struct descriptor with name 'name'
364 // read/compiles 'name'__define.pro if necessary
365 // cN is the calling node, passed for (runtime) debug information
GetStruct(const string & name,ProgNodeP cN)366 DStructDesc* GDLInterpreter::GetStruct(const string& name, ProgNodeP cN)
367 {
368   // find struct 'id'
369   DStructDesc* dStruct=FindInStructList( structList, name);
370 
371   // member function/pro declaration inserts an empty DStructDesc
372   if( dStruct != NULL && dStruct->NTags() > 0) return dStruct;
373 
374   static StrArr getStructList;
375 
376   // read/compile of IDENTIFIER__define.pro
377   string proName=name+"__DEFINE";
378 
379   for( StrArr::iterator i=getStructList.begin(); i != getStructList.end(); ++i)
380     {
381       if( proName == *i)
382 		throw GDLException(cN, "Structure type not defined (recursive call): "+name,true,false);
383     }
384 
385   StackSizeGuard<StrArr> guardStructList( getStructList);
386 
387   // append file to list
388   getStructList.push_back(proName);
389 
390 //   if( Called( proName))
391 //     {
392 //       throw GDLException(cN, "Structure type not defined (recursive call): "+name);
393 //     }
394 
395   /*bool found=*/ SearchCompilePro(proName, true);
396 
397   // if an exception occurs in SearchCompilePro, the struct is not compiled
398 
399   int proIx=ProIx(proName);
400   if( proIx == -1)
401     {
402 	throw GDLException(cN, "Procedure not found: "+proName, true, false);
403     }
404 
405   // 'guard' call stack
406   StackGuard<EnvStackT> guard(callStack);
407 
408   // interpret it
409   EnvUDT* newEnv=new EnvUDT( cN, proList[proIx]);
410 
411   // push id.pro onto call stack
412   callStack.push_back(newEnv);
413 
414   // make the call
415   call_pro(static_cast<DSubUD*>(callStack.back()->GetPro())->GetTree());
416 
417   dStruct=FindInStructList( structList, name);
418   if( dStruct == NULL)
419     {
420       throw GDLException(cN, "Structure type not defined: "+name,true,false);
421     }
422 
423   return dStruct;
424 }
425 
SetFunIx(ProgNodeP f)426 void GDLInterpreter::SetFunIx( ProgNodeP f)
427 {
428   if( f->funIx == -1)
429     f->funIx=GetFunIx(f);
430 }
431 
GetFunIx(ProgNodeP f)432 int GDLInterpreter::GetFunIx( ProgNodeP f)
433 {
434   string subName = f->getText();
435   int funIx=FunIx(subName);
436   if( funIx == -1)
437     {
438       // trigger reading/compiling of source file
439       /*bool found=*/ SearchCompilePro(subName, false);
440 
441       funIx=FunIx(subName);
442       if( funIx == -1)
443 	{
444 	  throw GDLException(f, "Function not found: "+subName, true, false);
445 	}
446     }
447   return funIx;
448 }
GetFunIx(const string & subName)449 int GDLInterpreter::GetFunIx( const string& subName)
450 {
451   int funIx=FunIx(subName);
452   if( funIx == -1)
453     {
454       // trigger reading/compiling of source file
455       /*bool found=*/ SearchCompilePro(subName, false);
456 
457       funIx=FunIx(subName);
458       if( funIx == -1)
459 	{
460 	  throw GDLException("Function not found: "+subName);
461 	}
462     }
463   return funIx;
464 }
465 
SetProIx(ProgNodeP f)466 void GDLInterpreter::SetProIx( ProgNodeP f)
467 {
468   if( f->proIx == -1)
469     f->proIx=GetProIx(f);//->getText());
470 }
471 
GetProIx(ProgNodeP f)472 int GDLInterpreter::GetProIx(ProgNodeP f)
473 {
474   string subName = f->getText();
475   int proIx = ProIx(subName);
476   if (proIx == -1) {
477     // trigger reading/compiling of source file
478     /*bool found=*/ SearchCompilePro(subName, true);
479 
480     proIx = ProIx(subName);
481 
482     //eliminate the simple case
483     if (proIx != -1) return proIx;
484 #ifdef 	AUTO_PRINT_EXPR
485     //noInteractive: throw
486     if (noInteractive) throw GDLException(f, "Procedure not found: " + subName, true, false);
487     //attempts an implied print. All this should be done in the ANTLR stuff of course.
488     //We are here because the text is interpreted as a procedure. It is not (otherwise it would have been found),
489     //but it could just be one or a series of variable names, such as in "a=dist(3) & b=findgen(2) & a,b"
490     //If it is not a variable, doing "print,a" will produce an error "PRINT: Variable is undefined: A". This is not what
491     //we want, we want "% Procedure not found: A". So we "print" only if all the names are indeed bona fide variables.
492     //gather types of siblings. if they are not all "ref", do not tempt anything
493     EnvStackT& callStack = ProgNode::interpreter->CallStack();
494     DLong curlevnum = callStack.size();
495     if (curlevnum > 1) throw GDLException(f, "Procedure not found: " + subName, true, false);
496     DSubUD* pro = static_cast<DSubUD*> (callStack[curlevnum - 1]->GetPro());
497     bool ok = true;
498     ProgNodeP test = f;
499     std::string what = test->getText();
500     int xI = pro->FindVar(what);
501     if (xI == -1) {
502       BaseGDL** varPtr = pro->GetCommonVarPtr(what);
503       if (varPtr == NULL) ok = false;
504     }
505     while (ok) {
506       test = test->GetNextSibling();
507       if (!test) break;
508       string type = test->getText();
509       string varName = test->GetFirstChild()->getText();
510       ok = (type == "ref"); //only simple variables.
511       if (ok) { //test it is a REAL variable.
512         xI = pro->FindVar(varName);
513         if (xI == -1) {
514           BaseGDL** varPtr = pro->GetCommonVarPtr(varName);
515           if (varPtr == NULL) ok = false;
516         }
517       }
518       if (!ok) break;
519       what += "," + test->GetFirstChild()->getText(); //for "ref" firstChild contains the name to be printed
520     }
521     if (ok) { //only simple things like "a,b,c"
522       try {
523         ProgNode::interpreter->executeLine.clear(); // clear EOF (for executeLine)
524         ProgNode::interpreter->executeLine.str("print,/implied_print," + what);
525         std::istream execute_me(ProgNode::interpreter->executeLine.rdbuf());
526         ProgNode::interpreter->ExecuteLine(&execute_me, 0);
527         ProgNode::interpreter->SetRetTree(f->GetLastSibling()->GetNextSibling());
528         return proIx;
529       } catch (GDLException& e) {
530         throw GDLException(f, "Procedure not found: " + subName, true, false);
531       }
532     } else throw GDLException(f, "Procedure not found: " + subName, true, false);
533 #else
534       throw GDLException(f, "Procedure not found: " + subName, true, false);
535 #endif
536   }
537   return proIx;
538 }
539 
GetProIx(const string & subName)540 int GDLInterpreter::GetProIx( const string& subName)
541 {
542   int proIx=ProIx(subName);
543   if( proIx == -1)
544     {
545       // trigger reading/compiling of source file
546       /*bool found=*/ SearchCompilePro(subName, true);
547 
548       proIx=ProIx(subName);
549       if( proIx == -1)
550 	{
551 	  throw GDLException("Procedure not found: "+subName);
552 	}
553     }
554   return proIx;
555 }
556 
557 // converts inferior type to superior type
AdjustTypes(BaseGDL * & a,BaseGDL * & b)558 void GDLInterpreter::AdjustTypes(BaseGDL* &a, BaseGDL* &b)
559 {
560   DType aTy=a->Type();
561   DType bTy=b->Type();
562   if( aTy == bTy) return;
563   if( DTypeOrder[aTy] > 100 || DTypeOrder[bTy] > 100)
564     {
565       //exception
566       throw GDLException( "Expressions of this type cannot be converted.");
567     }
568   if( DTypeOrder[aTy] > DTypeOrder[bTy])
569     {
570       // convert b to a
571       b=b->Convert2( aTy);
572     }
573   else
574     {
575       // convert a to b
576       a=a->Convert2( bTy);
577     }
578 }
579 
ReportCompileError(GDLException & e,const string & file)580 void GDLInterpreter::ReportCompileError( GDLException& e, const string& file)
581 {
582   cout << flush;
583   cerr << SysVar::MsgPrefix() << e.toString() << endl;
584   if( file != "")
585     {
586       cerr << "  At: " << file;
587       SizeT line = e.getLine();
588       if( line != 0)
589 	{
590 	  cerr  << ", Line " << line;
591 	  SizeT col = e.getColumn();
592 	  if( col != 0)
593 	    cerr << "  Column " << e.getColumn();
594 	}
595       cerr << endl;
596     }
597 }
598 
599 // compiles file, returns success
600 // if untilPro is set to "" the whole file is compiled
601 // procedure (searchForPro == true (default)) or function (searchForPro == false)
CompileFile(const string & f,const string & untilPro,bool searchForPro)602 bool GDLInterpreter::CompileFile(const string& f, const string& untilPro, bool searchForPro)
603 {
604   ifstream in(f.c_str());
605   if( !in) return false; // maybe throw exception here
606 
607   RefDNode theAST;
608   try {
609     GDLLexer   lexer(in, f, GDLParser::NONE, untilPro, searchForPro);
610     GDLParser& parser=lexer.Parser();
611 
612     // parsing
613     parser.translation_unit();
614 
615     theAST=parser.getAST();
616 
617     if( !theAST)
618       {
619 	cout << "No parser output generated." << endl;
620 	return false;
621       }
622   }
623   catch( GDLException& e)
624     {
625       ReportCompileError( e, f);
626       return false;
627     }
628   catch( ANTLRException& e)
629     {
630       cerr << "Lexer/Parser exception: " <<  e.getMessage() << endl;
631       return false;
632     }
633 
634 #ifdef GDL_DEBUG
635   cout << "Parser output:" << endl;
636   antlr::print_tree pt;
637   pt.pr_tree(static_cast<antlr::RefAST>(theAST));
638   cout << "CompileFile: Parser end." << endl;
639 #endif
640 
641 #ifdef GDL_DEBUG
642   RefDNode trAST;
643 #endif
644 
645   GDLTreeParser treeParser( f, untilPro);
646   try
647     {
648       treeParser.translation_unit(theAST);
649 
650 // #ifdef GDL_DEBUG
651 // nothing is returned (pro/funList are changed)
652 //       trAST=treeParser.getAST();
653 // #endif
654 
655       if( treeParser.ActiveProCompiled()) RetAll();
656     }
657   catch( GDLException& e)
658     {
659       ReportCompileError( e, f);
660       if( treeParser.ActiveProCompiled()) RetAll();
661       return false;
662     }
663   catch( ANTLRException& e)
664     {
665       cerr << "Compiler exception: " <<  e.getMessage() << endl;
666       if( treeParser.ActiveProCompiled()) RetAll();
667       return false;
668     }
669 // #ifdef GDL_DEBUG
670 //   cout << "Tree parser output:" << endl;
671 //   pt.pr_tree(static_cast<antlr::RefAST>(trAST));
672 //   cout << "ExecuteLine: Tree parser end." << endl;
673 // #endif
674 /*#ifdef GDL_DEBUG
675       cout << "Tree parser output:" << endl;
676       antlr::print_tree ptTP;
677       ptTP.pr_tree(static_cast<antlr::RefAST>(trAST));
678       cout << "CompileFile: Tree parser end." << endl;
679 #endif*/
680 
681   return true;
682 }
683 
AppendExtension(string & argstr)684 void AppendExtension( string& argstr)
685 {
686   SizeT slPos = argstr.find_last_of( '/');
687   SizeT dotPos = argstr.find_last_of( '.');
688 
689   if( dotPos == string::npos || (slPos != string::npos && slPos > dotPos))
690     //  if( argstr.length() <= 4 || argstr.find( '.', 1) == string::npos)
691     //	      StrLowCase( argstr.substr(argstr.length()-4,4)) != ".pro")
692     {
693       argstr += ".pro";
694     }
695 }
696 
CmdReset()697 DInterpreter::CommandCode DInterpreter::CmdReset()
698 {
699   RetAll( RetAllException::RESET);
700   return CC_OK;
701 }
CmdFullReset()702 DInterpreter::CommandCode DInterpreter::CmdFullReset()
703 {
704   RetAll( RetAllException::FULL_RESET);
705   return CC_OK;
706 }
707 
CmdCompile(const string & command)708 DInterpreter::CommandCode DInterpreter::CmdCompile( const string& command)
709 {
710   string cmdstr = command;
711   size_t sppos = cmdstr.find(" ",0);
712   if (sppos == string::npos)
713     {
714       cout << "Interactive COMPILE not implemented yet." << endl;
715       return CC_OK;
716     }
717 
718   bool retAll = false; // Remember if Retall is needed
719 
720   // Parse each file name
721   size_t pos = sppos + 1;
722   while (pos < command.length())
723     {
724       sppos = command.find(" ",pos);
725       if (sppos == string::npos) sppos = command.length();
726 
727       // Found a file
728       if ((sppos - pos) > 0)
729 	{
730 	  string argstr  = command.substr(pos, sppos-pos);
731 	  string origstr = argstr;
732 
733 	  // try first with extension
734 	  AppendExtension( argstr);
735 	  bool found = CompleteFileName( argstr);
736 
737 	  // 2nd try without extension
738 	  if( !found)
739 	    {
740 	      argstr = origstr;
741 	      found = CompleteFileName( argstr);
742 	    }
743 
744 	  if (found)
745 	    {
746 	      try {
747 		// default is more verbose
748 		CompileFile( argstr); //, origstr);
749 	      }
750 	      catch( RetAllException&)
751 		{
752 		  // delay the RetAllException until finished
753 		  retAll = true;
754 		}
755 	    }
756 	  else
757 	    {
758 	      Message( "Error opening file. File: "+origstr+".");
759 	      return CC_OK;
760 	    }
761 	}
762       pos = sppos + 1;
763     }
764   if( retAll) RetAll();
765 
766   return CC_OK;
767 }
768 
CmdRun(const string & command)769 DInterpreter::CommandCode DInterpreter::CmdRun( const string& command)
770 {
771   string cmdstr = command;
772   size_t sppos = cmdstr.find(" ",0);
773   if (sppos == string::npos)
774     {
775       cout << "Interactive RUN not implemented yet." << endl;
776       return CC_OK;
777     }
778 
779   bool retAll = false; // Remember if Retall is needed
780 
781   // Parse each file name
782   size_t pos = sppos + 1;
783   while (pos < command.length())
784     {
785       sppos = command.find(" ",pos);
786       size_t spposComma = command.find(",",pos);
787       if (sppos == string::npos && spposComma == string::npos)
788 	sppos = command.length();
789       else if (sppos == string::npos)
790 	sppos = spposComma;
791 
792 
793       // Found a file
794       if ((sppos - pos) > 0)
795 	{
796 	  string argstr  = command.substr(pos, sppos-pos);
797 	  string origstr = argstr;
798 
799 	  // try 1st with extension
800 	  AppendExtension( argstr);
801 	  bool found = CompleteFileName(argstr);
802 
803 	  // 2nd try without extension
804 	  if( !found)
805 	    {
806 	      argstr = origstr;
807 	      found = CompleteFileName( argstr);
808 	    }
809 
810 	  if (found)
811 	    {
812 	      try {
813 		// default is more verbose
814 		CompileFile( argstr); //, origstr);
815 	      }
816 	      catch( RetAllException&)
817 		{
818 		  // delay the RetAllException until finished
819 		  retAll = true;
820 		}
821 	    }
822 	  else
823 	    {
824 	      Message( "Error opening file. File: "+origstr+".");
825 	      return CC_OK;
826 	    }
827 	}
828       pos = sppos + 1;
829     }
830   if( retAll)
831     Warning( "Compiled a main program while inside a procedure. "
832 	     "Returning.");
833 
834   // actual run is perfomed in InterpreterLoop()
835   RetAll( RetAllException::RUN); // throws (always)
836   return CC_OK; //avoid warnings
837 }
838 
839 // execute GDL command (.run, .step, ...)
ExecuteCommand(const string & command)840 DInterpreter::CommandCode DInterpreter::ExecuteCommand(const string& command)
841 {
842   string cmdstr = command;
843   string args;
844   size_t sppos = cmdstr.find(" ",0);
845   if (sppos != string::npos) {
846     args = cmdstr.substr(sppos+1);
847     cmdstr = cmdstr.substr(0, sppos);
848   }
849 
850   //   cout << "Execute command: " << command << endl;
851 
852   String_abbref_eq cmd( StrUpCase( cmdstr));
853 
854   // AC: Continue before Compile to have ".c" giving ".continue"
855   if( cmd( "CONTINUE"))
856     {
857       return CC_CONTINUE;
858     }
859   if( cmd( "COMPILE"))
860     {
861       return CmdCompile( command);
862     }
863   if( cmd( "EDIT"))
864     {
865       cout << "Can't edit file without running GDLDE." << endl;
866       return CC_OK;
867     }
868   if( cmd( "FULL_RESET_SESSION"))
869     {
870       return CmdFullReset();
871     }
872   if( cmd( "GO"))
873     {
874       cout << "GO not implemented yet." << endl;
875       return CC_OK;
876     }
877   if( cmd( "OUT"))
878     {
879       cout << "OUT not implemented yet." << endl;
880       return CC_OK;
881     }
882   if( cmd( "RUN"))
883     {
884       return CmdRun( command);
885     }
886   if( cmd( "RETURN"))
887     {
888       cout << "RETURN not implemented yet." << endl;
889       return CC_OK;
890     }
891   if( cmd( "RESET_SESSION"))
892     {
893       return CmdReset();
894     }
895   if( cmd( "RNEW"))
896     {
897 	    EnvUDT* mainEnv =
898 		   static_cast<EnvUDT*>(GDLInterpreter::callStack[0]);
899 			  SizeT nEnv = mainEnv->EnvSize();
900 
901 		dynamic_cast<DSubUD*>(mainEnv->GetPro())->Reset();
902 		if(!mainEnv->Removeall())
903 			cout << " Danger ! Danger! Unexpected result. Please exit asap & report" <<endl;
904 
905       return CmdRun( command);
906     }
907   // GD:Here to have ".s" giving ".step"
908   if( cmd( "STEP"))
909     {
910       DLong sCount;
911       if( args == "")
912       {
913 	  sCount = 1;
914       }
915       else
916       {
917 	  const char* cStart=args.c_str();
918 	  char* cEnd;
919 	  sCount = strtol(cStart,&cEnd,10);
920 	  if( cEnd == cStart)
921 	  {
922 	    cout << "Type conversion error: Unable to convert given STRING: '"+args+"' to LONG." << endl;
923 	    return CC_OK;
924 	  }
925 	}
926 	stepCount = sCount;
927 	debugMode = DEBUG_STEP;
928 	return CC_STEP;
929     }
930 
931   if( cmd( "SKIP"))
932     {
933       DLong sCount;
934       if( args == "")
935       {
936 	  sCount = 1;
937       }
938       else
939       {
940 	const char* cStart=args.c_str();
941 	char* cEnd;
942 	sCount = strtol(cStart,&cEnd,10);
943 	if( cEnd == cStart)
944 	{
945 	  cout << "Type conversion error: Unable to convert given STRING: '"+args+"' to LONG." << endl;
946 	  return CC_OK;
947 	}
948       }
949       stepCount = sCount;
950       return CC_SKIP;
951     }
952   if( cmd( "STEPOVER"))
953     {
954       cout << "STEPOVER not implemented yet." << endl;
955       return CC_OK;
956     }
957   if( cmd( "SIZE"))
958     {
959       cout << "SIZE not implemented yet." << endl;
960       return CC_OK;
961     }
962   if( cmd( "TRACE"))
963     {
964       cout << "TRACE not implemented yet." << endl;
965       return CC_OK;
966     }
967   cout << SysVar::MsgPrefix() <<
968     "Unknown command: "<< command << endl;
969   return CC_OK; // get rid of warning
970 }
971 
972 // execute OS shell command (interactive shell if command == "")
973 // by Peter Messmer
ExecuteShellCommand(const string & command)974 void DInterpreter::ExecuteShellCommand(const string& command)
975 {
976   string commandLine = command;
977   if(commandLine == "") {
978      char* shellEnv = getenv("SHELL");
979 	 if (shellEnv == NULL) shellEnv = getenv("COMSPEC");
980 	 if (shellEnv == NULL) {
981         cout << "Error managing child process. " <<
982 		" Environment variable SHELL or COMSPEC not set." << endl;
983       return;
984     }
985 	 commandLine = shellEnv;
986   }
987 
988   int ignored = system( commandLine.c_str());
989 }
990 
991 
992 
GetLine(istream * in)993 string GetLine( istream* in)
994 {
995   string line = "";
996   while( in->good() &&
997     (  line == ""
998     || line[0] == ';' )) // skip also comment lines (bug #663)
999     {
1000       getline( *in, line);
1001       StrTrim(line);
1002     }
1003   return line;
1004 }
1005 
AddLineOffset(SizeT lineOffset,RefDNode astR)1006 void AddLineOffset( SizeT lineOffset, RefDNode astR)
1007 {
1008 astR->SetLine( astR->getLine() + lineOffset);
1009 if( astR->getFirstChild() != NULL) AddLineOffset( lineOffset, (RefDNode)astR->getFirstChild() );
1010 if( astR->getNextSibling() != NULL) AddLineOffset( lineOffset, (RefDNode)astR->getNextSibling() );
1011 }
1012 
1013 // execute one line of code (commands and statements)
ExecuteLine(istream * in,SizeT lineOffset)1014 DInterpreter::CommandCode DInterpreter::ExecuteLine( istream* in, SizeT lineOffset)
1015 {
1016   string line = (in != NULL) ? ::GetLine(in) : GetLine();
1017 
1018   // cout << "ExecuteLine: " << line << endl;
1019 
1020   string firstChar = line.substr(0,1);
1021 
1022   // command
1023   if( firstChar == ".")
1024     {
1025       return ExecuteCommand( line.substr(1));
1026     }
1027 
1028   //  online help (if possible, start a browser)
1029   if( firstChar == "?")
1030     {
1031       // later, we will have to check whether we have X11/Display or not
1032       // on some computing nodes on supercomputers, this is de-activated.
1033       if (line.substr(1).length() > 0) {
1034 	line=line.substr(1);
1035 	StrTrim(line);
1036 	line="online_help, '"+line+"'"; //'
1037       } else {
1038 	line="online_help";
1039       }
1040     }
1041 
1042   // shell command
1043   if( firstChar == "#")
1044     {
1045       if (line.substr(1).length() > 0) {
1046 	line=line.substr(1);
1047 	StrTrim(line);
1048 	line=StrUpCase(line);
1049 	//cout << "yes ! >>"<<StrUpCase(line)<<"<<" << endl;
1050 	SizeT nProFun;
1051 	int nbFound=0;
1052 	// looking in internal procedures
1053 	nProFun=libProList.size();
1054 	for( SizeT i = 0; i<nProFun; ++i)
1055 	  {
1056 	    if (line.compare(libProList[ i]->Name()) == 0) {
1057 	      cout << "Internal PROCEDURE : " << libProList[ i]->ToString() << endl;
1058 	      nbFound++;
1059 	      break;
1060 	    }
1061 	  }
1062 	// looking in internal functions
1063 	nProFun = libFunList.size();
1064 	for( SizeT i = 0; i<nProFun; ++i)
1065 	  {
1066 	    if (line.compare(libFunList[ i]->Name()) == 0) {
1067 	      cout << "Internal FUNCTION : " << libFunList[ i]->ToString() << endl;
1068 	      nbFound++;
1069 	      break;
1070 	    }
1071 	  }
1072 	// looking in compiled functions
1073 	nProFun = funList.size();
1074 	for( SizeT i = 0; i<nProFun; ++i)
1075 	  {
1076 	    if (line.compare(funList[ i]->Name()) == 0) {
1077 	      cout << "Compiled FUNCTION : " << funList[ i]->ToString() << endl;
1078 	      nbFound++;
1079 	      break;
1080 	    }
1081 	  }
1082 	// looking in compiled procedures
1083 	nProFun = proList.size();
1084 	for( SizeT i = 0; i<nProFun; ++i)
1085 	  {
1086 	    if (line.compare(proList[ i]->Name()) == 0) {
1087 	      cout << "Compiled PROCEDURE : " << proList[ i]->ToString() << endl;
1088 	      nbFound++;
1089 	      break;
1090 	    }
1091 	  }
1092 	if (nbFound == 0) {
1093 	  cout << "No Procedure/Function, internal or compiled, with name : "<< line << endl;
1094 	}
1095       } else {
1096 	cout << "Please provide a pro/fun name !" << endl;
1097       }
1098       return CC_OK;
1099     }
1100 
1101   // shell command
1102   if( firstChar == "$")
1103     {
1104       ExecuteShellCommand( line.substr(1));
1105       return CC_OK;
1106     }
1107 
1108   // include (only when at $MAIN$)
1109   // during compilation this is handled by the interpreter
1110   if( firstChar == "@" && callStack.size() <= 1)
1111     {
1112       string fileRaw = line.substr(1);
1113       StrTrim( fileRaw);
1114 
1115       string file = fileRaw;
1116       AppendExtension( file);
1117 
1118       bool found = CompleteFileName( file);
1119       if( !found)
1120 	{
1121 	  file = fileRaw;
1122 	  CompleteFileName( file);
1123 	}
1124 
1125       ExecuteFile( file);
1126       return CC_OK;
1127     }
1128 
1129   // statement -> execute it
1130   executeLine.clear(); // clear EOF (for executeLine)
1131   executeLine.str( line + "\n"); // append new line
1132 
1133   RefDNode theAST;
1134   try {
1135     Guard<GDLLexer> lexer;
1136 
1137     // LineContinuation LC
1138     // conactenate the strings and insert \n
1139     // the resulting string can be fed to the lexer
1140 
1141     // print if expr parse ok
1142     int lCNum = 0;
1143     for(;;)
1144       {
1145 	lexer.Reset( new GDLLexer(executeLine, "", callStack.back()->CompileOpt()));
1146 	try {
1147 	  // works, but ugly -> depends from parser detecting an error
1148 	  // (which it always will due to missing END_U token in case of LC)
1149  	  //lexer->Parser().SetCompileOpt(callStack.back()->CompileOpt());
1150  	  lexer.Get()->Parser().interactive();
1151 	  break; // no error -> everything ok
1152 	}
1153 	catch( GDLException& e)
1154 	  {
1155 	    int lCNew = lexer.Get()->LineContinuation();
1156 	    if( lCNew == lCNum)
1157 // 	      throw; // no LC -> real error
1158 	{
1159 #ifdef 	AUTO_PRINT_EXPR
1160 #ifndef GDL_DEBUG
1161  		try {
1162 // 			executeLine.clear(); // clear EOF (for executeLine)
1163 // 			lexer.reset( new GDLLexer(executeLine, "", callStack.back()->CompileOpt()));
1164 // 			lexer->Parser().expr();
1165 
1166 			executeLine.clear(); // clear EOF (for executeLine)
1167 			executeLine.str( "print,/implied_print," + executeLine.str()); // append new line
1168 
1169 			lexer.reset( new GDLLexer(executeLine, "", callStack.back()->CompileOpt()));
1170 			lexer->Parser().interactive();
1171 
1172 			break; // no error -> everything ok
1173 		}
1174 		catch( GDLException& e2)
1175 #endif
1176 #endif
1177 		{
1178 			throw e;
1179 		}
1180 	}
1181 
1182 	    lCNum = lCNew; // save number to see if next line also has LC
1183 	  }
1184 
1185 
1186 
1187 	// line continuation -> get next line
1188 	if( in != NULL && !in->good())
1189 	  throw GDLException( "End of file encountered during line continuation.");
1190 
1191 	string cLine = (in != NULL) ? ::GetLine(in) : GetLine();
1192 
1193 	executeLine.clear(); // clear EOF (for executeLine)
1194 	executeLine.str( executeLine.str() + cLine + "\n"); // append new line
1195       }
1196 
1197     //    lexer->Parser().interactive();
1198     theAST = lexer.Get()->Parser().getAST();
1199 
1200   }
1201   catch( GDLException& e)
1202     {
1203       ReportCompileError( e);
1204       return CC_OK;
1205     }
1206   catch( ANTLRException& e)
1207     {
1208       cerr << "Lexer/Parser exception: " <<  e.getMessage() << endl;
1209       return CC_OK;
1210     }
1211 
1212   if( theAST == NULL) return CC_OK;
1213 
1214     // consider line offset
1215     if( lineOffset > 0)
1216 		AddLineOffset( lineOffset, theAST);
1217 
1218 #ifdef GDL_DEBUG
1219   antlr::print_tree pt;
1220   cout << "Parser output:" << endl;
1221   pt.pr_tree(static_cast<antlr::RefAST>(theAST));
1222   cout << "ExecuteLine: Parser end." << endl;
1223 #endif
1224 
1225   ProgNodeP progAST = NULL;
1226 
1227   RefDNode trAST;
1228 
1229   assert( dynamic_cast<EnvUDT*>(callStack.back()) != NULL);
1230   EnvUDT* env = static_cast<EnvUDT*>(callStack.back());
1231   int nForLoopsIn = env->NForLoops();
1232   try
1233     {
1234       GDLTreeParser treeParser( callStack.back());
1235 
1236       treeParser.interactive(theAST);
1237 
1238       trAST=treeParser.getAST();
1239 
1240   if( trAST == NULL)
1241     {
1242       // normal condition for cmd line procedure calls
1243       return CC_OK;
1244     }
1245 
1246 #ifdef GDL_DEBUG
1247   cout << "Tree parser output (RefDNode):" << endl;
1248   pt.pr_tree(static_cast<antlr::RefAST>(trAST));
1249   cout << "ExecuteLine: Tree parser end." << endl;
1250 #endif
1251 
1252 	// **************************************
1253 	// this is the call of the ProgNode factory
1254 	// **************************************
1255     progAST = ProgNode::NewProgNode( trAST);
1256 
1257 	assert( dynamic_cast<EnvUDT*>(callStack.back()) != NULL);
1258     EnvUDT* env = static_cast<EnvUDT*>(callStack.back());
1259     int nForLoops = ProgNode::NumberForLoops( progAST, nForLoopsIn);
1260 	env->ResizeForLoops( nForLoops);
1261     }
1262   catch( GDLException& e)
1263     {
1264 	  env->ResizeForLoops( nForLoopsIn);
1265 
1266       ReportCompileError( e);
1267       return CC_OK;
1268     }
1269   catch( ANTLRException& e)
1270     {
1271 	  env->ResizeForLoops( nForLoopsIn);
1272 
1273       cerr << "Compiler exception: " <<  e.getMessage() << endl;
1274       return CC_OK;
1275     }
1276   Guard< ProgNode> progAST_guard( progAST);
1277 
1278   try
1279     {
1280 
1281 #ifdef GDL_DEBUG
1282   cout << "Converted tree (ProgNode):" << endl;
1283   pt.pr_tree( progAST);
1284   cout << "end." << endl;
1285 #endif
1286 
1287       RetCode retCode = interactive( progAST);
1288 
1289 	  env->ResizeForLoops( nForLoopsIn);
1290 
1291       // write to journal file
1292       string actualLine = GetClearActualLine();
1293       if( actualLine != "") lib::write_journal( actualLine);
1294 
1295       if( retCode == RC_RETURN) return CC_RETURN;
1296       return CC_OK;
1297     }
1298   catch( GDLException& e)
1299     {
1300 	  env->ResizeForLoops( nForLoopsIn);
1301 
1302       cerr << "Unhandled GDL exception: " <<  e.toString() << endl;
1303       return CC_OK;
1304     }
1305   catch( ANTLRException& e)
1306     {
1307 	  env->ResizeForLoops( nForLoopsIn);
1308 
1309       cerr << "Interpreter exception: " <<  e.getMessage() << endl;
1310       return CC_OK;
1311     }
1312 
1313   return CC_OK;
1314 }
1315 
inputThread()1316 void inputThread() {
1317     while (1) {
1318       // patch by Ole, 2017-01-06
1319       //char ch = getchar(); if (ch==EOF) return NULL;
1320       char ch = getchar();
1321       if (ch==EOF) {
1322 	return;
1323       }
1324       inputstr += ch;
1325       if (ch == '\n')
1326 	break;
1327     }
1328 }
1329 
1330 // if readline is not available or !EDIT_INPUT set to zero
NoReadline(const string & prompt)1331 char* DInterpreter::NoReadline( const string& prompt)
1332 {
1333   if (isatty(0)) cout << prompt << flush;
1334   if( feof(stdin)) return NULL;
1335 
1336   thread th(inputThread);
1337 
1338   for (;;)
1339     {
1340         GDLEventHandler();
1341         if (inputstr.size() && inputstr[inputstr.size() - 1] == '\n') break;
1342         if (feof(stdin))
1343         {
1344           th.join();
1345           return NULL;
1346         }
1347 #ifdef _WIN32
1348         Sleep(10);
1349 #else
1350         usleep(10);
1351 #endif
1352     }
1353   inputstr = inputstr.substr(0, inputstr.size() - 1); // removes '\n'
1354   //if (inputstr[inputstr.size() - 1] == '\r')
1355   //    inputstr = inputstr.substr(0, inputstr.size() - 1); // removes '\r' too, if exists
1356   char *result = (char*)malloc((inputstr.length() + 1) * sizeof(char));
1357   strcpy(result, inputstr.c_str()); // copies including terminating '\0'
1358   inputstr.clear();
1359 
1360   th.join();
1361 
1362   return result;
1363 }
1364 
1365 bool  lineEdit = false;
1366 string actualPrompt;
1367 
ControlCHandler(int)1368 void ControlCHandler(int)
1369 {
1370   cout << SysVar::MsgPrefix() << "Interrupt encountered." << endl;
1371   if( lineEdit) cout << actualPrompt /*SysVar::Prompt()*/ /*.c_str()*/ << flush;
1372   sigControlC = true;
1373   signal(SIGINT,ControlCHandler);
1374 }
1375 
GetLine()1376 string DInterpreter::GetLine()
1377 {
1378   clog << flush; cout << flush;
1379 
1380 #if defined(HAVE_LIBREADLINE)
1381   int edit_input = SysVar::Edit_Input() && isatty(0);
1382 #endif
1383 
1384   string line;
1385   do {
1386 
1387     char *cline;
1388 
1389 	actualPrompt = SysVar::Prompt();
1390 
1391     lineEdit = true;
1392 
1393 #if defined(HAVE_LIBREADLINE)
1394 
1395     if( edit_input != 0)
1396       cline = readline(const_cast<char*>(actualPrompt.c_str()));
1397     else
1398       cline = NoReadline(actualPrompt);
1399 #else
1400 
1401     cline = NoReadline(actualPrompt);
1402 #endif
1403 
1404     lineEdit = false;
1405     sigControlC = false; // reset all control-c which occured during line editing
1406 
1407     if( !cline)
1408       {
1409 	if (isatty(0)) cout << endl;
1410 	// instead or going out (EXITing) immediately, we go to
1411 	// the "exitgdl" in order to save the history
1412 	// exit( EXIT_SUCCESS); //break; // readline encountered eof
1413 	line="EXIT";
1414 	StrTrim(line);
1415 	break;
1416       }
1417     else
1418     // make a string
1419     line = cline;
1420 
1421 #ifndef _MSC_VER
1422     free(cline);        // done here for compatibility with readline
1423 #endif
1424 
1425     StrTrim(line);
1426   } while( line == ""
1427 	|| line[0] == ';'); // skip also comment lines (bug #663)
1428 
1429 #if defined(HAVE_LIBREADLINE)
1430   // SA: commented out to comply with IDL behaviour- allowing to
1431   //     set the history-file length only in the startup file
1432   //if( edit_input > 20)
1433   //  {
1434   //    stifle_history( edit_input);
1435   //  }
1436 
1437 static string lastAdded;
1438 
1439   // we would not like to add the current command if is "EXIT" !!
1440   if ( StrUpCase(line) != "EXIT" && line != lastAdded) {
1441     // const_cast to make it work with older readline versions
1442     add_history(const_cast<char*>(line.c_str()));
1443 
1444     lastAdded = line;
1445   }
1446 
1447 /*
1448 cout << "################ " << history_length << endl;
1449 for( int h=0;h<history_length; ++h)
1450 {
1451 HIST_ENTRY *lH = history_get (h);
1452 if( lH != NULL)
1453 	cout << h << ": " << string(lH->line) << endl;
1454 else
1455 	cout << h << ": NULL" << endl;
1456 }
1457 */
1458 #endif
1459 
1460   return line;
1461 }
1462 
1463 // reads user input and executes it
1464 // inner loop (called via Control-C, STOP, error)
InnerInterpreterLoop(SizeT lineOffset)1465 RetCode DInterpreter::InnerInterpreterLoop(SizeT lineOffset)
1466 {
1467   ProgNodeP retTreeSave = _retTree;
1468   for (;;) {
1469 #if defined (_MSC_VER) && _MSC_VER < 1800
1470 	_clearfp();
1471 #else
1472     feclearexcept(FE_ALL_EXCEPT);
1473 #endif
1474 
1475     DInterpreter::CommandCode ret=ExecuteLine(NULL, lineOffset);
1476 
1477     _retTree = retTreeSave; // on return, _retTree should be kept
1478 
1479     if( ret == CC_SKIP)
1480     {
1481       for( int s=0; s<stepCount; ++s)
1482       {
1483 	if( _retTree == NULL)
1484 	  break;
1485 
1486 	_retTree = _retTree->getNextSibling();
1487       }
1488 //       cout << ".SKIP " << stepCount << "   " << _retTree << endl;
1489 
1490       stepCount = 0;
1491       retTreeSave = _retTree;
1492       // we stay at the command line here
1493       if( _retTree == NULL)
1494 	Message( "Can't continue from this point.");
1495       else
1496 	DebugMsg( _retTree, "Skipped to: ");
1497     }
1498     else if( ret == CC_RETURN) return RC_RETURN;
1499     else if( ret == CC_CONTINUE) return RC_OK;
1500     else if( ret == CC_STEP) return RC_OK;
1501   }
1502 }
1503 
1504 // used by pyhton module
RunBatch(istream * in)1505 bool DInterpreter::RunBatch( istream* in)
1506 {
1507   ValueGuard<bool> guard( interruptEnable);
1508   interruptEnable = false;
1509 
1510   while( in->good())
1511     {
1512 #if defined (_MSC_VER) && _MSC_VER < 1800
1513 	  _clearfp();
1514 #else
1515       feclearexcept(FE_ALL_EXCEPT);
1516 #endif
1517 
1518       try
1519 	{
1520 	  DInterpreter::CommandCode ret=ExecuteLine( in);
1521 
1522 	  if( debugMode != DEBUG_CLEAR)
1523 	    {
1524 	      debugMode = DEBUG_CLEAR;
1525 	      return false;
1526 	    }
1527 	}
1528       catch( RetAllException& retAllEx)
1529 	{
1530 	}
1531       catch( exception& e)
1532 	{
1533 	  cerr << "Batch" << ": Exception: " << e.what() << endl;
1534 	}
1535       catch (...)
1536 	{
1537 	  cerr << "Batch" << ": Unhandled Error." << endl;
1538 	}
1539     } // while
1540 
1541   return true;
1542 }
1543 
1544 // used for @file
1545 // Note: As long as we are in batch mode we are at $MAIN$
ExecuteFile(const string & file)1546 void DInterpreter::ExecuteFile( const string& file)
1547 {
1548   ifstream in(file.c_str());
1549 
1550   if( in.fail())
1551     Warning( "Error opening file: "+file);
1552 
1553   //  ValueGuard<bool> guard( interruptEnable);
1554   //  interruptEnable = false;
1555 
1556   bool runCmd = false;
1557   while( in.good())
1558     {
1559 #if defined (_MSC_VER) && _MSC_VER < 1800
1560 	  _clearfp();
1561 #else
1562       feclearexcept(FE_ALL_EXCEPT);
1563 #endif
1564 
1565       try
1566  	{
1567 	  if( runCmd)
1568 	    {
1569 	      runCmd = false;
1570 	      RunDelTree();
1571 	    }
1572 	  else
1573 	    {
1574 	      DInterpreter::CommandCode ret=ExecuteLine( &in);
1575 
1576 	      if( debugMode != DEBUG_CLEAR)
1577 		{
1578 		  debugMode = DEBUG_CLEAR;
1579 		  // Warning( "Prematurely closing batch file: "+startup);
1580 		  break;
1581 		}
1582 	    }
1583 	}
1584       catch( RetAllException& retAllEx)
1585 	{
1586 
1587         //Do nothing, as we are at Main. A RETALL or RESET etc shoul not be harmful.
1588 //	  runCmd = (retAllEx.Code() == RetAllException::RUN );
1589 //	  if( !runCmd) throw;
1590 	}
1591       //       catch( exception& e)
1592       // 	{
1593       // 	  cerr << file << ": Exception: " << e.what() << endl;
1594       // 	}
1595       //       catch (...)
1596       // 	{
1597       // 	  cerr << file << ": Unhandled Error." << endl;
1598       // 	}
1599     } // while
1600 }
1601 
1602 // this must be run only from $MAIN$
RunDelTree()1603 void DInterpreter::RunDelTree()
1604 {
1605   if( static_cast<DSubUD*>
1606       (callStack.back()->GetPro())->GetTree() != NULL)
1607     {
1608       try
1609 	{
1610 	  call_pro(static_cast<DSubUD*>
1611 		   (callStack.back()->GetPro())->GetTree());
1612 
1613 	  static_cast<DSubUD*>
1614 	    (callStack.back()->GetPro())->DelTree();
1615 	}
1616       catch( RetAllException&)
1617 	{
1618 	  static_cast<DSubUD*>
1619 	    (callStack.back()->GetPro())->DelTree();
1620 	  throw;
1621 	}
1622     }
1623 }
1624 
1625 
1626 // reads user input and executes it
1627 // the main loop
1628 
InterpreterLoop(const string & startup,vector<string> & batch_files,const std::string & statement)1629 RetCode DInterpreter::InterpreterLoop(const string& startup,
1630   vector<string>& batch_files, const std::string& statement) {
1631   // process startup file
1632   if (startup != "") {
1633     ifstream in(startup.c_str());
1634 
1635     if (in.fail())
1636       Warning("Error opening startup file: " + startup);
1637 
1638     ValueGuard<bool> guard(interruptEnable);
1639     interruptEnable = false;
1640 
1641     bool runCmd = false;
1642     try {
1643       while (in.good()) {
1644 #if defined (_MSC_VER) && _MSC_VER < 1800
1645         _clearfp();
1646 #else
1647         feclearexcept(FE_ALL_EXCEPT);
1648 #endif
1649 
1650         try {
1651           if (runCmd) {
1652             runCmd = false;
1653             RunDelTree();
1654           } else {
1655             DInterpreter::CommandCode ret = ExecuteLine(&in);
1656 
1657             if (debugMode != DEBUG_CLEAR) {
1658               debugMode = DEBUG_CLEAR;
1659               Warning("Prematurely closing batch file: " + startup);
1660               break;
1661             }
1662           }
1663         } catch (RetAllException& retAllEx) {
1664           runCmd = (retAllEx.Code() == RetAllException::RUN);
1665           if (!runCmd) throw;
1666         } catch (exception& e) {
1667           cerr << startup << ": Exception: " << e.what() << endl;
1668         } catch (...) {
1669           cerr << startup << ": Unhandled Error." << endl;
1670         }
1671       } // while
1672     } catch (RetAllException& retAllEx) {
1673     }
1674   } // if( startup...
1675 
1676 #ifdef USE_MPI
1677   int myrank = 0;
1678   int tag = 0;
1679   char mpi_procedure[256];
1680   MPI_Status status;
1681   MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
1682   int size;
1683   MPI_Comm_size(MPI_COMM_WORLD, &size);
1684   if (size > 1) {
1685     MPI_Recv(mpi_procedure, 256, MPI_CHAR, 0, tag, MPI_COMM_WORLD, &status);
1686 
1687     istringstream istr(StrUpCase(mpi_procedure) + "\n");
1688     DInterpreter::CommandCode ret = ExecuteLine(&istr);
1689 
1690     MPI_Finalize();
1691     exit(EXIT_SUCCESS);
1692   }
1693 #endif
1694 
1695   if (statement.length() > 0) {
1696     // execute single statement and exit (a new-line is added to statement in gdl.cpp)
1697     // (e.g. $ gdl -e "print, 'hello world'")
1698     noInteractive=true;
1699     istringstream iss(statement, ios_base::out);
1700     try {
1701       ExecuteLine(&iss);
1702     } catch (RetAllException& retAllEx) {
1703     }
1704     return RC_OK;
1705   } else {
1706     // execute batch files (e.g. $ gdl script.pro)
1707     // before entering the interactive mode
1708     for (vector<string>::iterator it = batch_files.begin(); it < batch_files.end(); ++it)
1709       ExecuteFile(*it);
1710     batch_files.clear(); // not needed anymore...
1711   }
1712 
1713 #if defined(HAVE_LIBREADLINE)
1714 
1715   // initialize readline (own version - not pythons one)
1716   // in includefirst.hpp readline is disabled for python_module
1717   // http://www.delorie.com/gnu/docs/readline/rlman.html
1718   char rlName[] = "GDL";
1719   rl_readline_name = rlName;
1720   rl_outstream = stderr;
1721   //Our handler takes too long
1722   //when editing the command line with ARROW keys. (bug 562). (used also in gdl.cpp)
1723   //but... without it we have no graphics event handler! FIXME!!!
1724   rl_event_hook = GDLEventHandler;
1725   {
1726     int edit_input = SysVar::Edit_Input();
1727     stifle_history(edit_input == 1 || edit_input < 0 ? 200 : edit_input);
1728   }
1729 
1730   // Eventually read back the ".gdl" path in user $HOME
1731   // we do not make one commun function with the save side
1732   // because on the save side we may need to create the .gdl/ PATH ...
1733   int result, debug = 0;
1734 #ifdef _WIN32
1735   char *homeDir = getenv("HOMEPATH");
1736 #else
1737   char *homeDir = getenv("HOME");
1738 #endif
1739   if (homeDir != NULL) {
1740     string pathToGDL_history;
1741     pathToGDL_history = homeDir;
1742     AppendIfNeeded(pathToGDL_history, lib::PathSeparator());
1743     pathToGDL_history = pathToGDL_history + ".gdl";
1744     string history_filename;
1745     AppendIfNeeded(pathToGDL_history, lib::PathSeparator());
1746     history_filename = pathToGDL_history + "history";
1747     if (debug) cout << "History file name: " << history_filename << endl;
1748 
1749     result = read_history(history_filename.c_str());
1750     if (debug) {
1751       if (result == 0) cout << "Successfull reading of ~/.gdl/history" << endl;
1752       else cout << "Fail to read back ~/.gdl/history" << endl;
1753     }
1754   }
1755 
1756   historyIntialized = true;
1757 
1758 #endif
1759 
1760 
1761   bool runCmd = false; // should tree from $MAIN$ be executed?
1762   bool continueCmd = false; // .CONTINUE command given already?
1763 
1764   // go into main loop
1765   for (;;) {
1766 #if defined (_MSC_VER) && _MSC_VER < 1800
1767     _clearfp();
1768 #else
1769     feclearexcept(FE_ALL_EXCEPT);
1770 #endif
1771 
1772     try {
1773       if (runCmd) {
1774         runCmd = false;
1775         continueCmd = false;
1776         RunDelTree();
1777       } else {
1778         DInterpreter::CommandCode ret = ExecuteLine();
1779 
1780         // stop steppig when at main level
1781         stepCount = 0;
1782         debugMode = DEBUG_CLEAR;
1783 
1784         if (ret == CC_SKIP) {
1785           Message("Can't continue from this point.");
1786         }
1787         else if (ret == CC_CONTINUE) {
1788           if (static_cast<DSubUD*>
1789             (callStack.back()->GetPro())->GetTree() != NULL) {
1790             if (continueCmd)
1791               runCmd = true;
1792             else {
1793               cout << SysVar::MsgPrefix() <<
1794                 "Starting at: $MAIN$" << endl;
1795               continueCmd = true;
1796             }
1797           } else
1798             cout << SysVar::MsgPrefix() <<
1799             "Cannot continue from this point." << endl;
1800         }
1801       }
1802     }    catch (RetAllException& retAllEx) {
1803       runCmd = (retAllEx.Code() == RetAllException::RUN);
1804       bool resetCmd = (retAllEx.Code() == RetAllException::RESET);
1805       bool fullResetCmd = (retAllEx.Code() == RetAllException::FULL_RESET);
1806       if (resetCmd || fullResetCmd) {
1807         // remove $MAIN$
1808         delete callStack.back();
1809         callStack.pop_back();
1810         assert(callStack.empty());
1811 
1812         ResetObjects();
1813         ResetHeap();
1814         if (fullResetCmd) {
1815           lib::ResetDLLs();
1816           PurgeContainer(libFunList);
1817           PurgeContainer(libProList);
1818         }
1819         // initially done in InitGDL()
1820         // initializations
1821         InitObjects();
1822         // init library functions
1823         if (fullResetCmd) {
1824           LibInit();
1825         }
1826 
1827         // initially done in constructor: setup main level environment
1828         DPro* mainPro = new DPro(); // $MAIN$  NOT inserted into proList
1829         EnvUDT* mainEnv = new EnvUDT(NULL, mainPro);
1830         callStack.push_back(mainEnv); // push main environment (necessary)
1831 
1832         // re-process startup file
1833         if (startup != "") {
1834           ifstream in(startup.c_str());
1835 
1836           if (in.fail())
1837             Warning("Error opening startup file: " + startup);
1838 
1839           ValueGuard<bool> guard(interruptEnable);
1840           interruptEnable = false;
1841 
1842           bool runCmd = false;
1843           try {
1844             while (in.good()) {
1845 #if defined (_MSC_VER) && _MSC_VER < 1800
1846               _clearfp();
1847 #else
1848               feclearexcept(FE_ALL_EXCEPT);
1849 #endif
1850 
1851               try {
1852                 if (runCmd) {
1853                   runCmd = false;
1854                   RunDelTree();
1855                 } else {
1856                   DInterpreter::CommandCode ret = ExecuteLine(&in);
1857 
1858                   if (debugMode != DEBUG_CLEAR) {
1859                     debugMode = DEBUG_CLEAR;
1860                     Warning("Prematurely closing batch file: " + startup);
1861                     break;
1862                   }
1863                 }
1864               } catch (RetAllException& retAllEx) {
1865                 runCmd = (retAllEx.Code() == RetAllException::RUN);
1866                 if (!runCmd) throw;
1867               } catch (exception& e) {
1868                 cerr << startup << ": Exception: " << e.what() << endl;
1869               } catch (...) {
1870                 cerr << startup << ": Unhandled Error." << endl;
1871               }
1872             } // while
1873           } catch (RetAllException& retAllEx) {
1874           }
1875         } // if( startup...
1876       }
1877     }    catch (exception& e) {
1878       cerr << "InterpreterLoop: Exception: " << e.what() << endl;
1879     }    catch (GDLException &e ) {
1880       Warning(e.getMessage());
1881     }   catch (...) {
1882       cerr << "InterpreterLoop: Unhandled Error." << endl;
1883     }
1884   }
1885 }
1886 
1887