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