1 /***************************************************************************
2  *  aGrUM modified frames and atg files for cocoR
3  *   Copyright (c) 2005-2021 by Christophe GONZALES(_at_AMU) and Pierre-Henri WUILLEMIN(_at_LIP6)
4  *   info_at_agrum_dot_org
5 ***************************************************************************/
6 /*----------------------------------------------------------------------
7 Compiler Generator Coco/R,
8 Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
9 extended by M. Loeberbauer & A. Woess, Univ. of Linz
10 ported to C++ by Csaba Balazs, University of Szeged
11 with improvements by Pat Terry, Rhodes University
12 
13 This program is free software; you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by the
15 Free Software Foundation; either version 2, or (at your option) any
16 later version.
17 
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 for more details.
22 
23 You should have received a copy of the GNU General Public License along
24 with this program; if not, write to the Free Software Foundation, Inc.,
25 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 
27 As an exception, it is allowed to write an extension of Coco/R that is
28 used as a plugin in non-free software.
29 
30 If not otherwise stated, any source code generated by Coco/R (other than
31 Coco/R itself) does not fall under the GNU General Public License.
32 -----------------------------------------------------------------------*/
33 
34 
35 #include <iostream>
36 #include <wchar.h>
37 
38 #include "Parser.h"
39 #include "Scanner.h"
40 
41 
42 namespace gum {
43 namespace MDPDAT {
44 
45 
SynErr(int n)46 void Parser::SynErr( int n ) {
47   if ( errDist >= minErrDist ) SynErr( scanner->filename(),la->line, la->col, n );
48 
49   errDist = 0;
50 }
51 
52 
errors(void) const53 const ErrorsContainer& Parser::errors( void ) const {
54   return  _errors_;
55 }
errors(void)56 ErrorsContainer& Parser::errors( void ) {
57   return  _errors_;
58 }
59 
Get()60 void Parser::Get() {
61   for ( ;; ) {
62     t = la;
63     la = scanner->Scan();
64 
65     if ( la->kind <= maxT ) { ++errDist; break; }
66 
67 
68 
69     if ( dummyToken != t ) {
70       dummyToken->kind = t->kind;
71       dummyToken->pos = t->pos;
72       dummyToken->col = t->col;
73       dummyToken->line = t->line;
74       dummyToken->next = nullptr;
75       coco_string_delete( dummyToken->val );
76       dummyToken->val = coco_string_create( t->val );
77       t = dummyToken;
78     }
79 
80     la = t;
81   }
82 }
83 
Expect(int n)84 void Parser::Expect( int n ) {
85   if ( la->kind==n ) Get(); else { SynErr( n ); }
86 }
87 
ExpectWeak(int n,int follow)88 void Parser::ExpectWeak( int n, int follow ) {
89   if ( la->kind == n ) Get();
90   else {
91     SynErr( n );
92 
93     while ( !StartOf( follow ) ) Get();
94   }
95 }
96 
WeakSeparator(int n,int syFol,int repFol)97 bool Parser::WeakSeparator( int n, int syFol, int repFol ) {
98   if ( la->kind == n ) {Get(); return true;}
99   else if ( StartOf( repFol ) ) {return false;}
100   else {
101     SynErr( n );
102 
103     while ( !( StartOf( syFol ) || StartOf( repFol ) || StartOf( 0 ) ) ) {
104       Get();
105     }
106 
107     return StartOf( syFol );
108   }
109 }
110 
MDPDAT()111 void Parser::MDPDAT() {
112 		VARIABLES_DECLARATION();
113 		while (la->kind == 10 /* "action" */) {
114 			ACTION();
115 		}
116 		REWARD_FUNCTION_GRAPH();
117 		DISCOUNT();
118 		TOLERANCE();
119 }
120 
VARIABLES_DECLARATION()121 void Parser::VARIABLES_DECLARATION() {
122 		Expect(_lpar);
123 		Expect(8 /* "variables" */);
124 		while (la->kind == _lpar) {
125 			VARIABLE();
126 		}
127 		Expect(9 /* ")" */);
128 }
129 
ACTION()130 void Parser::ACTION() {
131 		std::string name_of_action;
132 		float tolerance;
133 		Expect(10 /* "action" */);
134 		 _factory_->startActionDeclaration();
135 		if (la->kind == _ident) {
136 			IDENT(name_of_action);
137 		} else if (la->kind == _string) {
138 			STRING(name_of_action);
139 		} else SynErr(19);
140 		TRY(  _factory_->addAction( name_of_action ) );
141 		if (la->kind == _integer || la->kind == _number) {
142 			FLOAT(tolerance);
143 		}
144 		while (la->kind == _ident) {
145 			TRANSITION_FUNCTION_GRAPH();
146 		}
147 		if (la->kind == 12 /* "cost" */) {
148 			COST_FUNCTION_GRAPH();
149 		}
150 		Expect(11 /* "endaction" */);
151 		TRY(  _factory_->endActionDeclaration() );
152 }
153 
REWARD_FUNCTION_GRAPH()154 void Parser::REWARD_FUNCTION_GRAPH() {
155 		std::string name_of_var;
156 		                         _factory_->startRewardDeclaration();
157 		Expect(13 /* "reward" */);
158 		if (la->kind == _lpar) {
159 			if (IsFollowedByIdent() ) {
160 				Expect(_lpar);
161 				SUB_FUNCTION_GRAPH();
162 				Expect(9 /* ")" */);
163 			} else {
164 				Get();
165 				LEAF();
166 				Expect(9 /* ")" */);
167 			}
168 			TRY(  _factory_->addReward( ) );
169 			                    _parentModality_.clear();
170 			                    _parentNode_.clear();
171 		} else if (la->kind == 14 /* "[" */) {
172 			Get();
173 			std::string operand_type;
174 			OPERAND(operand_type);
175 			 _factory_->setOperationModeOn( operand_type );
176 			if (IsFollowedByIdent() ) {
177 				Expect(_lpar);
178 				SUB_FUNCTION_GRAPH();
179 				Expect(9 /* ")" */);
180 			} else if (la->kind == _lpar) {
181 				Get();
182 				LEAF();
183 				Expect(9 /* ")" */);
184 			} else SynErr(20);
185 			TRY(  _factory_->addReward( ) );
186 			                      _parentModality_.clear();
187 			                      _parentNode_.clear();
188 			while (la->kind == _lpar) {
189 				if (IsFollowedByIdent() ) {
190 					Expect(_lpar);
191 					SUB_FUNCTION_GRAPH();
192 					Expect(9 /* ")" */);
193 				} else {
194 					Get();
195 					LEAF();
196 					Expect(9 /* ")" */);
197 				}
198 				TRY(  _factory_->addReward( ) );
199 				                      _parentModality_.clear();
200 				                      _parentNode_.clear();
201 			}
202 			Expect(15 /* "]" */);
203 		} else SynErr(21);
204 		 _factory_->endRewardDeclaration();
205 }
206 
DISCOUNT()207 void Parser::DISCOUNT() {
208 		float value;
209 		         _factory_->startDiscountDeclaration( );
210 		Expect(16 /* "discount" */);
211 		FLOAT(value);
212 		 _factory_->addDiscount( value );
213 		           _factory_->endDiscountDeclaration( );
214 }
215 
TOLERANCE()216 void Parser::TOLERANCE() {
217 		float value;
218 		Expect(17 /* "tolerance" */);
219 		FLOAT(value);
220 }
221 
VARIABLE()222 void Parser::VARIABLE() {
223 		std::string name_of_var;
224 		Expect(_lpar);
225 		 _factory_->startVariableDeclaration();
226 		IDENT(name_of_var);
227 		TRY(  _factory_->variableName( name_of_var ) );
228 		MODALITY_LIST();
229 		Expect(9 /* ")" */);
230 		TRY(  _factory_->endVariableDeclaration() );
231 }
232 
IDENT(std::string & name)233 void Parser::IDENT(std::string& name) {
234 		Expect(_ident);
235 		name=narrow(t->val);
236 }
237 
MODALITY_LIST()238 void Parser::MODALITY_LIST() {
239 		std::string label;
240 		IDENT_OR_INTEGER(label);
241 		TRY(  _factory_->addModality( label ) );
242 		if (la->kind == _ident || la->kind == _integer) {
243 			MODALITY_LIST();
244 		}
245 }
246 
IDENT_OR_INTEGER(std::string & name)247 void Parser::IDENT_OR_INTEGER(std::string& name) {
248 		if (la->kind == _ident) {
249 			IDENT(name);
250 		} else if (la->kind == _integer) {
251 			Get();
252 			name=narrow(t->val);
253 		} else SynErr(22);
254 }
255 
STRING(std::string & str)256 void Parser::STRING(std::string& str) {
257 		Expect(_string);
258 		str=narrow(t->val);
259 }
260 
FLOAT(float & val)261 void Parser::FLOAT(float& val) {
262 		if (la->kind == _number) {
263 			Get();
264 			val=coco_atof(t->val);
265 		} else if (la->kind == _integer) {
266 			Get();
267 			val=float(coco_atoi(t->val));
268 		} else SynErr(23);
269 }
270 
TRANSITION_FUNCTION_GRAPH()271 void Parser::TRANSITION_FUNCTION_GRAPH() {
272 		std::string name_of_var;
273 		                          _factory_->startTransitionDeclaration();
274 		IDENT(name_of_var);
275 		std::string prime_name_of_var = name_of_var + "'";
276 		                _currentFunctionGraphVar_ = prime_name_of_var;
277 		if (IsFollowedByIdent() ) {
278 			Expect(_lpar);
279 			SUB_TRANSITION_FUNCTION_GRAPH();
280 			Expect(9 /* ")" */);
281 		} else if (la->kind == _lpar) {
282 			Get();
283 			TRANSITION_LEAF();
284 			Expect(9 /* ")" */);
285 		} else SynErr(24);
286 		TRY(  _factory_->addTransition( name_of_var ) );
287 		 _factory_->endTransitionDeclaration();
288 		 _parentModality_.clear();
289 		 _parentNode_.clear();
290 }
291 
COST_FUNCTION_GRAPH()292 void Parser::COST_FUNCTION_GRAPH() {
293 		std::string name_of_var;
294 		                      _factory_->startCostDeclaration();
295 		Expect(12 /* "cost" */);
296 		Expect(_lpar);
297 		SUB_FUNCTION_GRAPH();
298 		Expect(9 /* ")" */);
299 		TRY(  _factory_->addCost( ) );
300 		 _factory_->endCostDeclaration();
301 		 _parentModality_.clear();
302 		 _parentNode_.clear();
303 }
304 
SUB_TRANSITION_FUNCTION_GRAPH()305 void Parser::SUB_TRANSITION_FUNCTION_GRAPH() {
306 		std::string name_of_var;
307 		 std::string modality_of_var;
308 		 NodeId var_id;
309 		IDENT(name_of_var);
310 		var_id =  _factory_->addInternalNode( name_of_var );
311 		if( ! _parentNode_.empty() )
312 		  _factory_->addArc(  _parentNode_.back(), var_id,  _parentModality_.back() );
313 		else
314 		  _factory_->setRoot(var_id);
315 		while (la->kind == _lpar) {
316 			Get();
317 			IDENT_OR_INTEGER(modality_of_var);
318 			 _parentNode_.push_back( var_id );
319 			                         _parentModality_.push_back( (* ( _factory_->variable( name_of_var )))[modality_of_var] );
320 			if (IsFollowedByIdent() ) {
321 				Expect(_lpar);
322 				SUB_TRANSITION_FUNCTION_GRAPH();
323 				Expect(9 /* ")" */);
324 			} else if (la->kind == _lpar) {
325 				Get();
326 				TRANSITION_LEAF();
327 				Expect(9 /* ")" */);
328 			} else SynErr(25);
329 			 _parentModality_.pop_back();
330 			Expect(9 /* ")" */);
331 		}
332 		 _parentNode_.pop_back();
333 }
334 
TRANSITION_LEAF()335 void Parser::TRANSITION_LEAF() {
336 		float value;
337 		gum::Idx i = 0;
338 		NodeId var_id =  _factory_->addInternalNode(  _currentFunctionGraphVar_ );
339 		if( ! _parentNode_.empty() )
340 		   _factory_->addArc(  _parentNode_.back(), var_id,  _parentModality_.back() );
341 		else
342 		  _factory_->setRoot(var_id);
343 		FLOAT(value);
344 		NodeId val_id =  _factory_->addTerminalNode( value );
345 		 _factory_->addArc( var_id, val_id, i );
346 		while (la->kind == _integer || la->kind == _number) {
347 			FLOAT(value);
348 			++i;
349 			          val_id =  _factory_->addTerminalNode( value );
350 			          _factory_->addArc( var_id, val_id, i );
351 		}
352 }
353 
SUB_FUNCTION_GRAPH()354 void Parser::SUB_FUNCTION_GRAPH() {
355 		std::string name_of_var;
356 		 std::string modality_of_var;
357 		 NodeId var_id;
358 		IDENT(name_of_var);
359 		var_id =  _factory_->addInternalNode( name_of_var );
360 		if( ! _parentNode_.empty() )
361 		  _factory_->addArc(  _parentNode_.back(), var_id,  _parentModality_.back() );
362 		else
363 		 _factory_->setRoot(var_id);
364 		while (la->kind == _lpar) {
365 			Get();
366 			IDENT_OR_INTEGER(modality_of_var);
367 			 _parentNode_.push_back( var_id );
368 			                         _parentModality_.push_back( (* ( _factory_->variable( name_of_var )))[modality_of_var] );
369 			if (IsFollowedByIdent() ) {
370 				Expect(_lpar);
371 				SUB_FUNCTION_GRAPH();
372 				Expect(9 /* ")" */);
373 			} else if (la->kind == _lpar) {
374 				Get();
375 				LEAF();
376 				Expect(9 /* ")" */);
377 			} else SynErr(26);
378 			 _parentModality_.pop_back();
379 			Expect(9 /* ")" */);
380 		}
381 		 _parentNode_.pop_back();
382 }
383 
LEAF()384 void Parser::LEAF() {
385 		float value;
386 		FLOAT(value);
387 		NodeId val_id =  _factory_->addTerminalNode( value );
388 		          _factory_->addArc(  _parentNode_.back(), val_id,  _parentModality_.back() );
389 		while (la->kind == _integer || la->kind == _number) {
390 			FLOAT(value);
391 			NodeId val_id =  _factory_->addTerminalNode( value );
392 			           _factory_->addArc(  _parentNode_.back(), val_id,  _parentModality_.back() );
393 		}
394 }
395 
OPERAND(std::string & op)396 void Parser::OPERAND(std::string& op) {
397 		Expect(_operand);
398 		op=narrow(t->val);
399 }
400 
401 
402 
403 // If the user declared a method Init and a mehtod Destroy they should
404 // be called in the contructur and the destructor respctively.
405 //
406 // The following templates are used to recognize if the user declared
407 // the methods Init and Destroy.
408 
409 template<typename T>
410 struct ParserInitExistsRecognizer {
411   template<typename U, void ( U::* )() = &U::Init>
412   struct ExistsIfInitIsDefinedMarker {};
413 
414   struct InitIsMissingType {
415     char dummy1;
416   };
417 
418   struct InitExistsType {
419     char dummy1; char dummy2;
420   };
421 
422   // exists always
423   template<typename U>
424   static InitIsMissingType is_here( ... );
425 
426   // exist only if ExistsIfInitIsDefinedMarker is defined
427   template<typename U>
428   static InitExistsType is_here( ExistsIfInitIsDefinedMarker<U>* );
429 
430   enum { InitExists = ( sizeof( is_here<T>( nullptr ) ) == sizeof( InitExistsType ) ) };
431 };
432 
433 template<typename T>
434 struct ParserDestroyExistsRecognizer {
435   template<typename U, void ( U::* )() = &U::Destroy>
436   struct ExistsIfDestroyIsDefinedMarker {};
437 
438   struct DestroyIsMissingType {
439     char dummy1;
440   };
441 
442   struct DestroyExistsType {
443     char dummy1; char dummy2;
444   };
445 
446   // exists always
447   template<typename U>
448   static DestroyIsMissingType is_here( ... );
449 
450   // exist only if ExistsIfDestroyIsDefinedMarker is defined
451   template<typename U>
452   static DestroyExistsType is_here( ExistsIfDestroyIsDefinedMarker<U>* );
453 
454   enum { DestroyExists = ( sizeof( is_here<T>( nullptr ) ) == sizeof( DestroyExistsType ) ) };
455 };
456 
457 // The folloing templates are used to call the Init and Destroy methods if they exist.
458 
459 // Generic case of the ParserInitCaller, gets used if the Init method is missing
460 template<typename T, bool = ParserInitExistsRecognizer<T>::InitExists>
461 struct ParserInitCaller {
CallInitgum::MDPDAT::ParserInitCaller462   static void CallInit( T* t ) {
463     // nothing to do
464   }
465 };
466 
467 // True case of the ParserInitCaller, gets used if the Init method exists
468 template<typename T>
469 struct ParserInitCaller<T, true> {
CallInitgum::MDPDAT::ParserInitCaller470   static void CallInit( T* t ) {
471     t->Init();
472   }
473 };
474 
475 // Generic case of the ParserDestroyCaller, gets used if the Destroy method is missing
476 template<typename T, bool = ParserDestroyExistsRecognizer<T>::DestroyExists>
477 struct ParserDestroyCaller {
CallDestroygum::MDPDAT::ParserDestroyCaller478   static void CallDestroy( T* t ) {
479     // nothing to do
480   }
481 };
482 
483 // True case of the ParserDestroyCaller, gets used if the Destroy method exists
484 template<typename T>
485 struct ParserDestroyCaller<T, true> {
CallDestroygum::MDPDAT::ParserDestroyCaller486   static void CallDestroy( T* t ) {
487     t->Destroy();
488   }
489 };
Parse()490 void Parser::Parse() {
491   t = nullptr;
492   la = dummyToken = new Token();
493   la->val = coco_string_create( L"Dummy Token" );
494   Get();
495   	MDPDAT();
496 	Expect(0);
497 }
498 
Parser(Scanner * scanner)499 Parser::Parser( Scanner* scanner ) {
500   	maxT = 18;
501 
502   ParserInitCaller<Parser>::CallInit( this );
503   dummyToken = nullptr;
504   t = la = nullptr;
505   minErrDist = 2;
506   errDist = minErrDist;
507   this->scanner = scanner;
508 }
509 
StartOf(int s)510 bool Parser::StartOf( int s ) {
511   const bool T = true;
512   const bool x = false;
513 
514   	static bool set[1][20] = {
515 		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}
516 	};
517 
518 
519 
520   return set[s][la->kind];
521 }
522 
~Parser()523 Parser::~Parser() {
524   ParserDestroyCaller<Parser>::CallDestroy( this );
525   delete dummyToken;
526 }
SemErr(const wchar_t * msg)527 void Parser::SemErr( const wchar_t* msg ) {
528   if ( errDist >= minErrDist )  _errors_.Error( scanner->filename(),t->line, t->col, msg );
529 
530   errDist = 0;
531 }
532 
Warning(const wchar_t * msg)533 void Parser::Warning( const wchar_t* msg ) {
534    _errors_.Warning( scanner->filename(),t->line, t->col, msg );
535 }
536 
SynErr(const std::wstring & filename,int line,int col,int n)537 void Parser::SynErr( const std::wstring& filename,int line, int col, int n ) {
538   wchar_t* s;
539 
540   switch ( n ) {
541       			case 0: s = coco_string_create(L"EOF expected"); break;
542 			case 1: s = coco_string_create(L"operand expected"); break;
543 			case 2: s = coco_string_create(L"ident expected"); break;
544 			case 3: s = coco_string_create(L"integer expected"); break;
545 			case 4: s = coco_string_create(L"number expected"); break;
546 			case 5: s = coco_string_create(L"string expected"); break;
547 			case 6: s = coco_string_create(L"largestring expected"); break;
548 			case 7: s = coco_string_create(L"lpar expected"); break;
549 			case 8: s = coco_string_create(L"\"variables\" expected"); break;
550 			case 9: s = coco_string_create(L"\")\" expected"); break;
551 			case 10: s = coco_string_create(L"\"action\" expected"); break;
552 			case 11: s = coco_string_create(L"\"endaction\" expected"); break;
553 			case 12: s = coco_string_create(L"\"cost\" expected"); break;
554 			case 13: s = coco_string_create(L"\"reward\" expected"); break;
555 			case 14: s = coco_string_create(L"\"[\" expected"); break;
556 			case 15: s = coco_string_create(L"\"]\" expected"); break;
557 			case 16: s = coco_string_create(L"\"discount\" expected"); break;
558 			case 17: s = coco_string_create(L"\"tolerance\" expected"); break;
559 			case 18: s = coco_string_create(L"??? expected"); break;
560 			case 19: s = coco_string_create(L"invalid ACTION"); break;
561 			case 20: s = coco_string_create(L"invalid REWARD_FUNCTION_GRAPH"); break;
562 			case 21: s = coco_string_create(L"invalid REWARD_FUNCTION_GRAPH"); break;
563 			case 22: s = coco_string_create(L"invalid IDENT_OR_INTEGER"); break;
564 			case 23: s = coco_string_create(L"invalid FLOAT"); break;
565 			case 24: s = coco_string_create(L"invalid TRANSITION_FUNCTION_GRAPH"); break;
566 			case 25: s = coco_string_create(L"invalid SUB_TRANSITION_FUNCTION_GRAPH"); break;
567 			case 26: s = coco_string_create(L"invalid SUB_FUNCTION_GRAPH"); break;
568 
569 
570     default: {
571       wchar_t format[20];
572       coco_swprintf( format, 20, L"error %d", n );
573       s = coco_string_create( format );
574     }
575     break;
576   }
577 
578   //wprintf(L"-- line %d col %d: %ls\n", line, col, s);
579   std::wstring ss=L"Syntax error : "+std::wstring( s );
580    _errors_.Error( filename,line,col,ss.c_str() );
581   coco_string_delete( s );
582 }
583 
584 } // namespace
585 } // namespace
586 
587 
588 
589