1 /*
2 * cParser.cc
3 * Avida
4 *
5 * Created by David on 1/16/06.
6 * Copyright 1999-2011 Michigan State University. All rights reserved.
7 *
8 *
9 * This file is part of Avida.
10 *
11 * Avida is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
13 *
14 * Avida is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License along with Avida.
18 * If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "cParser.h"
23
24 #include "AvidaScript.h"
25 #include "cFile.h"
26 #include "tAutoRelease.h"
27
28 using namespace AvidaScript;
29
30 /*
31 The following represents the grammar for AvidaScript in BNF, adjusted so that it is compatible with recursive descent
32 parsing (to be) implemented by cParser.
33
34
35 script: statement_list
36
37 statement_list: statement statement_list
38 |
39
40 statement: assign_expr lineterm
41 | var_declare lineterm
42 | loose_block
43 | if_block lineterm
44 | while_block lineterm
45 | foreach_block lineterm
46 | declare_function lineterm
47 | define_function lineterm
48 | call_expr lineterm
49 | return_stmt lineterm
50 | lineterm
51
52 lineterm: SUPPRESS | ENDL
53
54 type_def: TYPE_ARRAY | TYPE_BOOL | TYPE_CHAR | TYPE_FLOAT | TYPE_INT | TYPE_MATRIX | TYPE_STRING | ID REF
55 type_any: type_def | TYPE_VOID
56
57 assign_expr: assign_dest ASSIGN expr
58
59 assign_dest: ID
60 | REF ARR_OPEN id_list ARR_CLOSE
61
62 id_list: ID id_list_1
63
64 id_list_1: COMMA ID id_list_1
65 | COMMA ID ARR_WILD
66 | COMMA ARR_WILD
67 |
68
69
70 expr: p0_expr
71
72 p0_expr: p1_expr p0_expr_1
73
74 p0_expr_1: ARR_RANGE p1_expr p0_expr_1
75 | ARR_EXPAN p1_expr p0_expr_1
76 |
77
78 p1_expr: p2_expr p1_expr_1
79
80 p1_expr_1: OP_LOGIC_AND p2_expr p1_expr_1
81 | OP_LOGIC_OR p2_expr p1_expr_1
82 |
83
84 p2_expr: p3_expr p2_expr_1
85
86 p2_expr_1: OP_BIT_AND p3_expr p2_expr_1
87 | OP_BIT_OR p3_expr p2_expr_1
88 |
89
90
91 p3_expr: p4_expr p3_expr_1
92
93 p3_expr_1: OP_EQ p4_expr p3_expr_1
94 | OP_LE p4_expr p3_expr_1
95 | OP_GE p4_expr p3_expr_1
96 | OP_LT p4_expr p3_expr_1
97 | OP_GT p4_expr p3_expr_1
98 | OP_NEQ p4_expr p3_expr_1
99 |
100
101
102 p4_expr: p5_expr p4_expr_1
103
104 p4_expr_1: OP_ADD p5_expr p4_expr_1
105 | OP_SUB p5_expr p4_expr_1
106 |
107
108
109 p5_expr: p6_expr p5_expr_1
110
111 p5_expr_1: OP_MUL p6_expr p5_expr_1
112 | OP_DIV p6_expr p5_expr_1
113 | OP_MOD p6_expr p5_expr_1
114 |
115
116 p6_expr: value p6_expr_1
117 | OP_BIT_NOT expr
118 | OP_LOGIC_NOT expr
119 | OP_SUB expr
120
121 p6_expr_1: DOT ID id_expr p6_expr_1
122 | IDX_OPEN expr IDX_CLOSE
123 |
124
125 value: FLOAT
126 | INT
127 | STRING
128 | CHAR
129 | ID id_expr
130 | PREC_OPEN expr PREC_CLOSE
131 | ARR_OPEN argument_list ARR_CLOSE
132 | MAT_MODIFY ARR_OPEN argument_list ARR_CLOSE
133
134 id_expr: PREC_OPEN argument_list PREC_CLOSE
135 |
136
137
138 call_expr: call_trgt PREC_OPEN argument_list PREC_CLOSE
139
140 call_trgt: ID call_value
141
142 call_value: DOT ID call_value
143 | PREC_OPEN argument_list PREC_CLOSE call_sub_idx DOT ID call_value
144 | IDX_OPEN expr IDX_CLOSE call_sub_idx DOT ID call_value
145 |
146
147 call_sub_idx: IDX_OPEN expr IDX_CLOSE call_sub_idx
148 |
149
150
151 argument_list: argument_list_1
152 |
153
154 argument_list_1: expr argument_list_2
155
156 argument_list_2: COMMA expr argument_list_2
157 |
158
159 loose_block: ARR_OPEN statement_list ARR_CLOSE
160
161 if_block: CMD_IF PREC_OPEN expr PREC_CLOSE loose_block
162 | CMD_IF PREC_OPEN expr PREC_CLOSE loose_block CMD_ELSE loose_block
163
164 while_block: CMD_WHILE PREC_OPEN expr PREC_CLOSE loose_block
165
166 foreach_block: CMD_FOREACH type_def ID PREC_OPEN expr PREC_CLOSE loose_block
167
168 var_declare: type_def ID
169 | type_def ID ASSIGN expr
170 | type_def ID PREC_OPEN argument_list PREC_CLOSE
171
172 var_declare_list: var_declare_list_1
173 |
174
175 var_declare_list_1: var_declare var_declare_list_2
176
177 var_declare_list_2: COMMA var_declare var_declare_list_2
178 |
179
180 declare_function: REF CMD_FUNCTION type_any ID PREC_OPEN var_declare_list PREC_CLOSE
181 define_function: CMD_FUNCTION type_any ID PREC_OPEN var_declare_list PREC_CLOSE loose_block
182
183 return_stmt: CMD_RETURN expr
184
185 */
186
187 #ifndef DEBUG_AS_PARSER
188 #define DEBUG_AS_PARSER 0
189 #endif
190
191 #if DEBUG_AS_PARSER
192 # define PARSE_DEBUG(x) { std::cerr << x << std::endl; }
193 # define PARSE_TRACE(x) { std::cerr << "trace: " << x << std::endl; }
194 #else
195 # define PARSE_DEBUG(x)
196 # define PARSE_TRACE(x)
197 #endif
198
199 #define PARSE_ERROR(x) reportError(AS_PARSE_ERR_ ## x, __LINE__)
200 #define PARSE_UNEXPECT() { if (currentToken()) { PARSE_ERROR(UNEXPECTED_TOKEN); } else { PARSE_ERROR(EOF); } return NULL; }
201
202 #define FILEPOS cASFilePosition(m_filename, m_lexer ? m_lexer->lineno() : 0)
203
204 #define TOKEN(x) AS_TOKEN_ ## x
205
206
cParser()207 cParser::cParser()
208 : m_filename("(unknown)")
209 , m_eof(false)
210 , m_success(true)
211 , m_cur_tok(TOKEN(INVALID))
212 , m_next_tok(TOKEN(INVALID))
213 , m_cur_text(NULL)
214 , m_err_eof(false)
215 {
216 }
217
Parse(cFile & input)218 bool cParser::Parse(cFile& input)
219 {
220 m_filename = input.GetFilename();
221 m_lexer = new cLexer(input.GetFileStream());
222
223 m_tree = parseStatementList();
224
225 if (!m_eof && m_success) PARSE_ERROR(UNEXPECTED_TOKEN);
226 if (!m_tree) PARSE_ERROR(EMPTY);
227
228 delete m_lexer;
229 m_lexer = NULL;
230
231 return m_success;
232 }
233
~cParser()234 cParser::~cParser()
235 {
236 delete m_tree;
237 delete m_lexer;
238 }
239
240
241
nextToken()242 ASToken_t cParser::nextToken()
243 {
244 if (m_next_tok != TOKEN(INVALID)) {
245 m_cur_tok = m_next_tok;
246 m_next_tok = TOKEN(INVALID);
247 } else {
248 m_cur_tok = (ASToken_t)m_lexer->yylex();
249 }
250 delete m_cur_text;
251 m_cur_text = NULL;
252 PARSE_DEBUG("nextToken: " << m_cur_tok);
253 return m_cur_tok;
254 }
255
peekToken()256 ASToken_t cParser::peekToken()
257 {
258 if (m_next_tok == TOKEN(INVALID)) {
259 delete m_cur_text;
260 m_cur_text = new cString(m_lexer->YYText());
261 m_next_tok = (ASToken_t)m_lexer->yylex();
262 }
263 return m_next_tok;
264 }
265
currentText()266 const cString& cParser::currentText()
267 {
268 if (!m_cur_text) m_cur_text = new cString(m_lexer->YYText());
269 return *m_cur_text;
270 }
271
272
parseArrayUnpack()273 cASTNode* cParser::parseArrayUnpack()
274 {
275 PARSE_TRACE("parseArrayUnpack");
276
277 if (nextToken() != TOKEN(ID)) PARSE_UNEXPECT();
278
279 tAutoRelease<cASTUnpackTarget> ut(new cASTUnpackTarget(FILEPOS));
280 (*ut).AddVar(currentText());
281
282 while (nextToken()) {
283 if (currentToken() == TOKEN(COMMA)) {
284 nextToken();
285 if (currentToken() == TOKEN(ID)) {
286 (*ut).AddVar(currentText());
287 continue;
288 } else if (currentToken() == TOKEN(ARR_WILD)) {
289 (*ut).SetLastWild();
290 break;
291 } else {
292 PARSE_ERROR(UNEXPECTED_TOKEN);
293 break;
294 }
295 } else if (currentToken() == TOKEN(ARR_WILD)) {
296 (*ut).SetLastNamed();
297 break;
298 } else {
299 PARSE_UNEXPECT();
300 }
301 }
302
303 if (nextToken() != TOKEN(ARR_CLOSE)) PARSE_UNEXPECT();
304 if (nextToken() != TOKEN(ASSIGN)) PARSE_UNEXPECT();
305 nextToken(); // consume '='
306
307 (*ut).SetExpression(parseExpression());
308
309 return ut.Release();
310 }
311
parseArgumentList()312 cASTArgumentList* cParser::parseArgumentList()
313 {
314 PARSE_TRACE("parseArgumentList");
315 cASTArgumentList* al = new cASTArgumentList(FILEPOS);
316
317 al->AddNode(parseExpression());
318 while (currentToken() == TOKEN(COMMA)) {
319 nextToken(); // consume ','
320 al->AddNode(parseExpression());
321 }
322
323 return al;
324 }
325
parseAssignment()326 cASTNode* cParser::parseAssignment()
327 {
328 PARSE_TRACE("parseAssignment");
329 cASTAssignment* an = new cASTAssignment(FILEPOS, currentText());
330
331 nextToken(); // consume id
332
333 nextToken(); // consume '='
334 cASTNode* expr = parseExpression();
335 an->SetExpression(expr);
336
337 return an;
338 }
339
parseCallExpression(cASTNode * target,bool required)340 cASTNode* cParser::parseCallExpression(cASTNode* target, bool required)
341 {
342 PARSE_TRACE("parseCallExpression");
343 tAutoRelease<cASTNode> ce(target);
344
345 if (currentToken() == TOKEN(DOT) && peekToken() == TOKEN(BUILTIN_METHOD)) {
346 nextToken(); // consume '.'
347
348 cASTBuiltInCall* bi = new cASTBuiltInCall(FILEPOS, currentText(), ce.Release());
349 ce.Set(bi);
350
351 if (nextToken() != TOKEN(PREC_OPEN)) PARSE_UNEXPECT();
352 if (nextToken() != TOKEN(PREC_CLOSE)) bi->SetArguments(parseArgumentList());
353 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
354 nextToken(); // consume ')'
355
356 if (currentToken() != TOKEN(DOT) || currentToken() != TOKEN(IDX_OPEN)) return ce.Release();
357 }
358
359
360 bool eoe = false;
361 while (!eoe) {
362 if (currentToken() == TOKEN(DOT)) {
363 if (nextToken() != TOKEN(ID)) PARSE_UNEXPECT();
364 cString name(currentText());
365 nextToken(); // consume id
366
367 if (currentToken() == TOKEN(PREC_OPEN)) {
368 cASTObjectCall* oc = new cASTObjectCall(FILEPOS, ce.Release(), name);
369 ce.Set(oc);
370 if (nextToken() != TOKEN(PREC_CLOSE)) oc->SetArguments(parseArgumentList());
371 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
372 nextToken(); // consume ')'
373
374 // If the next token is not a continued call expression, then set the end-of-expression flag
375 if (currentToken() != TOKEN(IDX_OPEN) && currentToken() != TOKEN(DOT)) eoe = true;
376 } else {
377 ce.Set(new cASTObjectReference(FILEPOS, ce.Release(), name));
378
379 if (required && currentToken() == TOKEN(ASSIGN)) {
380 cASTObjectAssignment* oa = new cASTObjectAssignment(FILEPOS, ce.Release());
381 ce.Set(oa);
382 nextToken(); // consume '='
383 oa->SetExpression(parseExpression());
384 eoe = true;
385 }
386 }
387 } else if (currentToken() == TOKEN(IDX_OPEN)) {
388 do {
389 nextToken(); // consume '['
390 ce.Set(new cASTExpressionBinary(FILEPOS, TOKEN(IDX_OPEN), ce.Release(), parseExpression()));
391 if (currentToken() != TOKEN(IDX_CLOSE)) PARSE_UNEXPECT();
392 } while (nextToken() == TOKEN(IDX_OPEN));
393
394 if (required && currentToken() == TOKEN(ASSIGN)) {
395 cASTObjectAssignment* oa = new cASTObjectAssignment(FILEPOS, ce.Release());
396 ce.Set(oa);
397 nextToken(); // consume '='
398 oa->SetExpression(parseExpression());
399 eoe = true;
400 }
401 } else {
402 if (required) { PARSE_UNEXPECT(); }
403 else eoe = true;
404 }
405 }
406
407 return ce.Release();
408 }
409
parseCodeBlock()410 cASTNode* cParser::parseCodeBlock()
411 {
412 PARSE_TRACE("parseCodeBlock");
413
414 // Swallow all newlines and suppress tokens
415 while (currentToken() == TOKEN(ENDL) || currentToken() == TOKEN(SUPPRESS)) nextToken();
416
417 if (currentToken() == TOKEN(ARR_OPEN)) return parseLooseBlock();
418
419 PARSE_UNEXPECT();
420 }
421
parseExpression()422 cASTNode* cParser::parseExpression()
423 {
424 PARSE_TRACE("parseExpression");
425 cASTNode* expr = NULL;
426
427 expr = parseExprP0();
428 if (!expr) {
429 if (currentToken())
430 PARSE_ERROR(NULL_EXPR);
431 else
432 PARSE_ERROR(EOF);
433 }
434
435 return expr;
436 }
437
parseExprP0()438 cASTNode* cParser::parseExprP0()
439 {
440 PARSE_TRACE("parseExprP0");
441 cASTNode* l = parseExprP1();
442 cASTNode* r = NULL;
443
444 while(true) {
445 switch (currentToken()) {
446 case TOKEN(ARR_RANGE):
447 case TOKEN(ARR_EXPAN):
448 ASToken_t op = currentToken();
449 nextToken();
450 r = parseExprP1();
451 if (!r) PARSE_ERROR(NULL_EXPR);
452 l = new cASTExpressionBinary(FILEPOS, op, l, r);
453 break;
454
455 default:
456 return l;
457 }
458 }
459
460 return l;
461 }
462
parseExprP1()463 cASTNode* cParser::parseExprP1()
464 {
465 PARSE_TRACE("parseExprP1");
466 cASTNode* l = parseExprP2();
467 cASTNode* r = NULL;
468
469 while(true) {
470 switch (currentToken()) {
471 case TOKEN(OP_LOGIC_AND):
472 case TOKEN(OP_LOGIC_OR):
473 ASToken_t op = currentToken();
474 nextToken();
475 r = parseExprP2();
476 if (!r) PARSE_ERROR(NULL_EXPR);
477 l = new cASTExpressionBinary(FILEPOS, op, l, r);
478 break;
479
480 default:
481 return l;
482 }
483 }
484
485 return l;
486 }
487
parseExprP2()488 cASTNode* cParser::parseExprP2()
489 {
490 PARSE_TRACE("parseExprP2");
491 cASTNode* l = parseExprP3();
492 cASTNode* r = NULL;
493
494 while(true) {
495 switch (currentToken()) {
496 case TOKEN(OP_BIT_AND):
497 case TOKEN(OP_BIT_OR):
498 ASToken_t op = currentToken();
499 nextToken();
500 r = parseExprP3();
501 if (!r) PARSE_ERROR(NULL_EXPR);
502 l = new cASTExpressionBinary(FILEPOS, op, l, r);
503 break;
504
505 default:
506 return l;
507 }
508 }
509
510 return l;
511 }
512
parseExprP3()513 cASTNode* cParser::parseExprP3()
514 {
515 PARSE_TRACE("parseExprP3");
516 cASTNode* l = parseExprP4();
517 cASTNode* r = NULL;
518
519 while(true) {
520 switch (currentToken()) {
521 case TOKEN(OP_EQ):
522 case TOKEN(OP_LE):
523 case TOKEN(OP_GE):
524 case TOKEN(OP_LT):
525 case TOKEN(OP_GT):
526 case TOKEN(OP_NEQ):
527 ASToken_t op = currentToken();
528 nextToken();
529 r = parseExprP4();
530 if (!r) PARSE_ERROR(NULL_EXPR);
531 l = new cASTExpressionBinary(FILEPOS, op, l, r);
532 break;
533
534 default:
535 return l;
536 }
537 }
538
539 return l;
540 }
541
parseExprP4()542 cASTNode* cParser::parseExprP4()
543 {
544 PARSE_TRACE("parseExprP4");
545 cASTNode* l = parseExprP5();
546 cASTNode* r = NULL;
547
548 while(true) {
549 switch (currentToken()) {
550 case TOKEN(OP_ADD):
551 case TOKEN(OP_SUB):
552 ASToken_t op = currentToken();
553 nextToken();
554 r = parseExprP5();
555 if (!r) PARSE_ERROR(NULL_EXPR);
556 l = new cASTExpressionBinary(FILEPOS, op, l, r);
557 break;
558
559 default:
560 return l;
561 }
562 }
563
564 return l;
565 }
566
parseExprP5()567 cASTNode* cParser::parseExprP5()
568 {
569 PARSE_TRACE("parseExprP5");
570 cASTNode* l = parseExprP6();
571 cASTNode* r = NULL;
572
573 while(true) {
574 switch (currentToken()) {
575 case TOKEN(OP_MUL):
576 case TOKEN(OP_DIV):
577 case TOKEN(OP_MOD):
578 ASToken_t op = currentToken();
579 nextToken();
580 r = parseExprP6();
581 if (!r) PARSE_ERROR(NULL_EXPR);
582 l = new cASTExpressionBinary(FILEPOS, op, l, r);
583 break;
584
585 default:
586 return l;
587 }
588 }
589
590 return l;
591 }
592
parseExprP6()593 cASTNode* cParser::parseExprP6()
594 {
595 PARSE_TRACE("parseExprP6");
596 tAutoRelease<cASTNode> expr;
597
598 bool is_matrix = false;
599
600 switch (currentToken()) {
601 case TOKEN(FLOAT):
602 expr.Set(new cASTLiteral(FILEPOS, AS_TYPE_FLOAT, currentText()));
603 break;
604 case TOKEN(INT):
605 expr.Set(new cASTLiteral(FILEPOS, AS_TYPE_INT, currentText()));
606 break;
607 case TOKEN(CHAR):
608 expr.Set(new cASTLiteral(FILEPOS, AS_TYPE_CHAR,
609 currentText().Substring(1, currentText().GetSize() - 2).ParseEscapeSequences()));
610 break;
611 case TOKEN(BOOL):
612 expr.Set(new cASTLiteral(FILEPOS, AS_TYPE_BOOL, currentText()));
613 break;
614 case TOKEN(STRING):
615 expr.Set(new cASTLiteral(FILEPOS, AS_TYPE_STRING,
616 currentText().Substring(1, currentText().GetSize() - 2).ParseEscapeSequences()));
617 break;
618 case TOKEN(ID):
619 if (peekToken() == TOKEN(PREC_OPEN)) {
620 cASTFunctionCall* fc = new cASTFunctionCall(FILEPOS, currentText());
621 expr.Set(fc);
622 nextToken(); // consume id token
623 if (nextToken() != TOKEN(PREC_CLOSE)) fc->SetArguments(parseArgumentList());
624 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
625 } else {
626 expr = new cASTVariableReference(FILEPOS, currentText());
627 }
628 break;
629 case TOKEN(BUILTIN_CALL):
630 if (peekToken() == TOKEN(PREC_OPEN)) {
631 cASTBuiltInCall* bi = new cASTBuiltInCall(FILEPOS, currentText());
632 expr.Set(bi);
633 nextToken(); // consume builtin methon name token
634 if (nextToken() != TOKEN(PREC_CLOSE)) bi->SetArguments(parseArgumentList());
635 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
636 } else {
637 PARSE_UNEXPECT();
638 }
639 break;
640 case TOKEN(PREC_OPEN):
641 nextToken(); // consume '('
642 expr.Set(parseExpression());
643 if (expr.IsNull()) PARSE_ERROR(NULL_EXPR);
644 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
645 break;
646
647 case TOKEN(LITERAL_DICT):
648 expr.Set(parseLiteralDict());
649 if (currentToken() != TOKEN(ARR_CLOSE)) PARSE_UNEXPECT();
650 break;
651
652 case TOKEN(LITERAL_MATRIX):
653 is_matrix = true;
654 case TOKEN(ARR_OPEN):
655 {
656 tAutoRelease<cASTArgumentList> al;
657 if (nextToken() != TOKEN(ARR_CLOSE)) al.Set(parseArgumentList());
658 if (currentToken() != TOKEN(ARR_CLOSE)) PARSE_UNEXPECT();
659 expr.Set(new cASTLiteralArray(FILEPOS, al.Release(), is_matrix));
660 }
661 break;
662
663 case TOKEN(OP_BIT_NOT):
664 case TOKEN(OP_LOGIC_NOT):
665 case TOKEN(OP_SUB):
666 ASToken_t op = currentToken();
667 nextToken(); // consume operation
668 cASTNode* r = parseExprP6();
669 if (!r) {
670 PARSE_ERROR(NULL_EXPR);
671 return NULL;
672 }
673 expr.Set(new cASTExpressionUnary(FILEPOS, op, r));
674 return expr.Release();
675
676 default:
677 return NULL;
678 }
679
680 nextToken();
681 if (!expr.IsNull()) return parseCallExpression(expr.Release());
682
683 return NULL;
684 }
685
686
parseForeachStatement()687 cASTNode* cParser::parseForeachStatement()
688 {
689 PARSE_TRACE("parseForeachStatement");
690
691 sASTypeInfo type(AS_TYPE_INVALID);
692 switch (nextToken()) {
693 case TOKEN(TYPE_ARRAY): type.type = AS_TYPE_ARRAY; break;
694 case TOKEN(TYPE_BOOL): type.type = AS_TYPE_BOOL; break;
695 case TOKEN(TYPE_CHAR): type.type = AS_TYPE_CHAR; break;
696 case TOKEN(TYPE_DICT): type.type = AS_TYPE_DICT; break;
697 case TOKEN(TYPE_FLOAT): type.type = AS_TYPE_FLOAT; break;
698 case TOKEN(TYPE_INT): type.type = AS_TYPE_INT; break;
699 case TOKEN(TYPE_MATRIX): type.type = AS_TYPE_MATRIX; break;
700 case TOKEN(TYPE_STRING): type.type = AS_TYPE_STRING; break;
701 case TOKEN(TYPE_VAR): type.type = AS_TYPE_VAR; break;
702 case TOKEN(TYPE_VOID): type.type = AS_TYPE_VOID; break;
703 case TOKEN(ID):
704 if (peekToken() != TOKEN(REF)) {
705 nextToken();
706 PARSE_UNEXPECT();
707 }
708
709 type.type = AS_TYPE_OBJECT_REF;
710 type.info = currentText();
711
712 nextToken(); // consume id
713 break;
714
715 default:
716 PARSE_UNEXPECT();
717 return NULL;
718 }
719
720 if (nextToken() != TOKEN(ID)) {
721 PARSE_UNEXPECT();
722 return NULL;
723 }
724
725 tAutoRelease<cASTVariableDefinition> var(new cASTVariableDefinition(FILEPOS, type, currentText()));
726
727 if (nextToken() != TOKEN(PREC_OPEN)) {
728 PARSE_UNEXPECT();
729 return NULL;
730 }
731 nextToken(); // consume '('
732
733 tAutoRelease<cASTNode> expr(parseExpression());
734
735 if (currentToken() != TOKEN(PREC_CLOSE)) {
736 PARSE_UNEXPECT();
737 return NULL;
738 }
739 nextToken(); // consume ')'
740
741 cASTNode* code = parseCodeBlock();
742
743 return new cASTForeachBlock(FILEPOS, var.Release(), expr.Release(), code);
744 }
745
parseFunctionDefine()746 cASTNode* cParser::parseFunctionDefine()
747 {
748 PARSE_TRACE("parseFunctionDefine");
749 cASTFunctionDefinition* fd = parseFunctionHeader();
750
751 // If the returned function definition is valid, parse the body
752 if (fd) fd->SetCode(parseCodeBlock());
753
754 return fd;
755 }
756
parseFunctionHeader()757 cASTFunctionDefinition* cParser::parseFunctionHeader()
758 {
759 PARSE_TRACE("parseFunctionHeader");
760
761 sASTypeInfo type(AS_TYPE_INVALID);
762 switch (nextToken()) {
763 case TOKEN(TYPE_ARRAY): type.type = AS_TYPE_ARRAY; break;
764 case TOKEN(TYPE_BOOL): type.type = AS_TYPE_BOOL; break;
765 case TOKEN(TYPE_CHAR): type.type = AS_TYPE_CHAR; break;
766 case TOKEN(TYPE_DICT): type.type = AS_TYPE_DICT; break;
767 case TOKEN(TYPE_FLOAT): type.type = AS_TYPE_FLOAT; break;
768 case TOKEN(TYPE_INT): type.type = AS_TYPE_INT; break;
769 case TOKEN(TYPE_MATRIX): type.type = AS_TYPE_MATRIX; break;
770 case TOKEN(TYPE_STRING): type.type = AS_TYPE_STRING; break;
771 case TOKEN(TYPE_VAR): type.type = AS_TYPE_VAR; break;
772 case TOKEN(TYPE_VOID): type.type = AS_TYPE_VOID; break;
773 case TOKEN(ID):
774 if (peekToken() != TOKEN(REF)) {
775 nextToken();
776 PARSE_UNEXPECT();
777 }
778
779 type.type = AS_TYPE_OBJECT_REF;
780 type.info = currentText();
781
782 nextToken(); // consume id
783 break;
784
785 default:
786 PARSE_UNEXPECT();
787 }
788
789 if (nextToken() != TOKEN(ID)) {
790 PARSE_UNEXPECT();
791 }
792 cString name(currentText());
793
794 if (nextToken() != TOKEN(PREC_OPEN)) PARSE_UNEXPECT();
795
796 tAutoRelease<cASTVariableDefinitionList> args;
797 if (nextToken() != TOKEN(PREC_CLOSE)) args.Set(parseVariableDefinitionList());
798 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
799 nextToken(); // consume ')'
800
801 return new cASTFunctionDefinition(FILEPOS, type, name, args.Release());
802 }
803
parseIDStatement()804 cASTNode* cParser::parseIDStatement()
805 {
806 PARSE_TRACE("parseIDStatement");
807
808 switch (peekToken()) {
809 case TOKEN(ASSIGN):
810 return parseAssignment();
811 break;
812 case TOKEN(PREC_OPEN):
813 {
814 cASTFunctionCall* fc = new cASTFunctionCall(FILEPOS, currentText());
815 nextToken(); // consume id token
816 if (nextToken() != TOKEN(PREC_CLOSE)) fc->SetArguments(parseArgumentList());
817 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
818 nextToken(); // consume ')'
819
820 if (currentToken() == TOKEN(DOT) || currentToken() == TOKEN(IDX_OPEN)) {
821 return parseCallExpression(fc, true);
822 }
823
824 return fc;
825 }
826 break;
827 case TOKEN(DOT):
828 case TOKEN(IDX_OPEN):
829 cASTNode* target = new cASTVariableReference(FILEPOS, currentText());
830 nextToken(); // consume id
831 return parseCallExpression(target, true);
832 break;
833 case TOKEN(REF):
834 return parseVariableDefinition();
835 break;
836
837 default:
838 PARSE_UNEXPECT();
839 }
840 }
841
parseIfStatement()842 cASTNode* cParser::parseIfStatement()
843 {
844 PARSE_TRACE("parseIfStatement");
845
846 if (nextToken() != TOKEN(PREC_OPEN)) PARSE_UNEXPECT();
847
848 nextToken();
849 tAutoRelease<cASTNode> cond(parseExpression());
850 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
851 nextToken();
852
853 tAutoRelease<cASTIfBlock> is(new cASTIfBlock(FILEPOS, cond.Release(), parseCodeBlock()));
854
855 while (currentToken() == TOKEN(CMD_ELSEIF)) {
856
857 if (nextToken() != TOKEN(PREC_OPEN)) PARSE_UNEXPECT();
858 nextToken(); // consume '('
859
860 tAutoRelease<cASTNode> elifcond(parseExpression());
861
862 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
863 nextToken(); // consume ')'
864
865 cASTNode* elifcode = parseCodeBlock();
866 (*is).AddElseIf(elifcond.Release(), elifcode);
867 }
868
869 if (currentToken() == TOKEN(CMD_ELSE)) {
870 nextToken(); // consume 'else'
871 cASTNode* code = parseCodeBlock();
872 (*is).SetElseCode(code);
873 }
874
875 return is.Release();
876 }
877
878
parseLiteralDict()879 cASTNode* cParser::parseLiteralDict()
880 {
881 PARSE_TRACE("parseLiteralDict");
882 cASTLiteralDict* ld = new cASTLiteralDict(FILEPOS);
883
884 if (peekToken() != TOKEN(ARR_CLOSE)) {
885 do {
886 nextToken(); // consume ',' (or '@{' on first pass)
887 cASTNode* idxexpr = parseExpression();
888 if (currentToken() != TOKEN(DICT_MAPPING)) PARSE_UNEXPECT();
889 nextToken(); // consume '=>'
890 cASTNode* valexpr = parseExpression();
891
892 ld->AddMapping(idxexpr, valexpr);
893 } while (currentToken() == TOKEN(COMMA));
894 } else {
895 nextToken();
896 }
897
898 return ld;
899 }
900
parseLooseBlock()901 cASTNode* cParser::parseLooseBlock()
902 {
903 PARSE_TRACE("parseLooseBlock");
904 //nextToken();
905 tAutoRelease<cASTNode> sl(parseStatementList());
906
907 if (currentToken() != TOKEN(ARR_CLOSE)) PARSE_UNEXPECT();
908 nextToken(); // consume '}'
909
910 return sl.Release();
911 }
912
parseRefStatement()913 cASTNode* cParser::parseRefStatement()
914 {
915 PARSE_TRACE("parseRefStatement");
916
917 switch (nextToken()) {
918 case TOKEN(ARR_OPEN):
919 return parseArrayUnpack();
920 case TOKEN(CMD_FUNCTION):
921 return parseFunctionHeader();
922 default:
923 PARSE_UNEXPECT();
924 }
925 }
926
parseReturnStatement()927 cASTNode* cParser::parseReturnStatement()
928 {
929 PARSE_TRACE("parseReturnStatement");
930
931 nextToken(); // consume 'return'
932 cASTNode* rs = new cASTReturnStatement(FILEPOS, parseExpression());
933
934 return rs;
935 }
936
937
parseStatementList()938 cASTNode* cParser::parseStatementList()
939 {
940 PARSE_TRACE("parseStatementList");
941 tAutoRelease<cASTStatementList> sl(new cASTStatementList(FILEPOS));
942
943 tAutoRelease<cASTNode> node;
944
945 while (nextToken()) {
946 switch (currentToken()) {
947 case TOKEN(ARR_OPEN):
948 node.Set(parseLooseBlock());
949 break;
950 case TOKEN(CMD_IF):
951 node.Set(parseIfStatement());
952 break;
953 case TOKEN(CMD_FOREACH):
954 node.Set(parseForeachStatement());
955 break;
956 case TOKEN(CMD_FUNCTION):
957 node.Set(parseFunctionDefine());
958 break;
959 case TOKEN(CMD_RETURN):
960 node.Set(parseReturnStatement());
961 break;
962 case TOKEN(CMD_WHILE):
963 node.Set(parseWhileStatement());
964 break;
965 case TOKEN(ENDL):
966 continue;
967 case TOKEN(ID):
968 node.Set(parseIDStatement());
969 break;
970 case TOKEN(REF):
971 node.Set(parseRefStatement());
972 break;
973 case TOKEN(SUPPRESS):
974 continue;
975 case TOKEN(TYPE_ARRAY):
976 case TOKEN(TYPE_BOOL):
977 case TOKEN(TYPE_CHAR):
978 case TOKEN(TYPE_DICT):
979 case TOKEN(TYPE_FLOAT):
980 case TOKEN(TYPE_INT):
981 case TOKEN(TYPE_MATRIX):
982 case TOKEN(TYPE_STRING):
983 case TOKEN(TYPE_VAR):
984 node.Set(parseVariableDefinition());
985 break;
986
987 default:
988 return sl.Release();
989 }
990
991 if (node.IsNull() && m_success) PARSE_ERROR(INTERNAL); // Should not receive a null response without an error flag
992
993 if (currentToken() == TOKEN(SUPPRESS)) {
994 if (!node.IsNull()) (*node).SuppressOutput();
995 } else if (currentToken() != TOKEN(ENDL)) {
996 PARSE_ERROR(UNTERMINATED_EXPR);
997 }
998
999 (*sl).AddNode(node.Release());
1000 }
1001
1002 if (!currentToken()) m_eof = true;
1003 return sl.Release();
1004 }
1005
1006
parseVariableDefinition()1007 cASTVariableDefinition* cParser::parseVariableDefinition()
1008 {
1009 PARSE_TRACE("parseVariableDefinition");
1010
1011 sASTypeInfo vtype(AS_TYPE_INVALID);
1012 switch (currentToken()) {
1013 case TOKEN(TYPE_ARRAY): vtype.type = AS_TYPE_ARRAY; break;
1014 case TOKEN(TYPE_BOOL): vtype.type = AS_TYPE_BOOL; break;
1015 case TOKEN(TYPE_CHAR): vtype.type = AS_TYPE_CHAR; break;
1016 case TOKEN(TYPE_DICT): vtype.type = AS_TYPE_DICT; break;
1017 case TOKEN(TYPE_FLOAT): vtype.type = AS_TYPE_FLOAT; break;
1018 case TOKEN(TYPE_INT): vtype.type = AS_TYPE_INT; break;
1019 case TOKEN(TYPE_MATRIX): vtype.type = AS_TYPE_MATRIX; break;
1020 case TOKEN(TYPE_STRING): vtype.type = AS_TYPE_STRING; break;
1021 case TOKEN(TYPE_VAR): vtype.type = AS_TYPE_VAR; break;
1022 case TOKEN(ID):
1023 if (peekToken() != TOKEN(REF)) {
1024 nextToken();
1025 PARSE_UNEXPECT();
1026 }
1027
1028 vtype.type = AS_TYPE_OBJECT_REF;
1029 vtype.info = currentText();
1030
1031 nextToken(); // consume id
1032 break;
1033
1034 default:
1035 PARSE_UNEXPECT();
1036 }
1037
1038 if (nextToken() != TOKEN(ID)) PARSE_UNEXPECT();
1039
1040 tAutoRelease<cASTVariableDefinition> vd(new cASTVariableDefinition(FILEPOS, vtype, currentText()));
1041
1042 switch (nextToken()) {
1043 case TOKEN(ASSIGN):
1044 nextToken();
1045 cASTNode* expr = parseExpression();
1046 (*vd).SetAssignmentExpression(expr);
1047 break;
1048 case TOKEN(PREC_OPEN):
1049 if (nextToken() != TOKEN(PREC_CLOSE)) (*vd).SetDimensions(parseArgumentList());
1050 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
1051 nextToken(); // consume ')'
1052 break;
1053
1054 default:
1055 break;
1056 }
1057
1058 return vd.Release();
1059 }
1060
parseVariableDefinitionList()1061 cASTVariableDefinitionList* cParser::parseVariableDefinitionList()
1062 {
1063 PARSE_TRACE("parseVariableDefinitionList");
1064 tAutoRelease<cASTVariableDefinitionList> vl(new cASTVariableDefinitionList(FILEPOS));
1065
1066 cASTVariableDefinition* vd = parseVariableDefinition();
1067 if (!vd) return NULL;
1068
1069 (*vl).AddNode(vd);
1070 while (currentToken() == TOKEN(COMMA)) {
1071 nextToken(); // consume ','
1072 vd = parseVariableDefinition();
1073 if (!vd) return NULL;
1074 (*vl).AddNode(vd);
1075 }
1076
1077 return vl.Release();
1078 }
1079
parseWhileStatement()1080 cASTNode* cParser::parseWhileStatement()
1081 {
1082 PARSE_TRACE("parseWhileStatement");
1083
1084 if (nextToken() != TOKEN(PREC_OPEN)) PARSE_UNEXPECT();
1085
1086 nextToken();
1087 tAutoRelease<cASTNode> cond(parseExpression());
1088 if (currentToken() != TOKEN(PREC_CLOSE)) PARSE_UNEXPECT();
1089 nextToken();
1090
1091 cASTNode* code = parseCodeBlock();
1092 return new cASTWhileBlock(FILEPOS, cond.Release(), code);
1093 }
1094
1095
reportError(ASParseError_t err,const int line)1096 void cParser::reportError(ASParseError_t err, const int line)
1097 {
1098 #if DEBUG_AS_PARSER
1099 # define ERR_ENDL " (cParser.cc:" << line << ")" << std::endl
1100 #else
1101 # define ERR_ENDL std::endl
1102 #endif
1103
1104 m_success = false;
1105
1106 std::cerr << m_filename << ":";
1107
1108 int lineno = m_lexer ? m_lexer->lineno() : 0;
1109 if (lineno) std::cerr << lineno;
1110 else std::cerr << "?";
1111
1112 std::cerr << ": error: ";
1113
1114 switch (err) {
1115 case AS_PARSE_ERR_UNEXPECTED_TOKEN:
1116 std::cerr << "unexpected token '" << currentText() << "'" << ERR_ENDL;
1117 break;
1118 case AS_PARSE_ERR_UNTERMINATED_EXPR:
1119 std::cerr << "unterminated expression" << ERR_ENDL;
1120 break;
1121 case AS_PARSE_ERR_NULL_EXPR:
1122 std::cerr << "expected expression, found '" << currentText() << "'" << ERR_ENDL;
1123 break;
1124 case AS_PARSE_ERR_EOF:
1125 if (!m_err_eof) {
1126 std::cerr << "unexpected end of file" << ERR_ENDL;
1127 m_err_eof = true;
1128 }
1129 break;
1130 case AS_PARSE_ERR_EMPTY:
1131 std::cerr << "empty script, no valid statements found" << ERR_ENDL;
1132 break;
1133 case AS_PARSE_ERR_INTERNAL:
1134 std::cerr << "internal parser error at cParser.cc:" << line << std::endl;
1135 break;
1136 case AS_PARSE_ERR_UNKNOWN:
1137 default:
1138 std::cerr << "parse error" << std::endl;
1139 }
1140
1141 #undef ERR_ENDL
1142 }
1143
1144 #undef PARSE_DEBUG()
1145 #undef PARSE_TRACE()
1146
1147 #undef PARSE_ERROR()
1148 #undef PARSE_UNEXPECT()
1149
1150 #undef FILEPOS
1151
1152 #undef TOKEN()
1153