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