source: liacs/coco/assignment2/comp.y@ 76

Last change on this file since 76 was 2, checked in by Rick van der Zwet, 15 years ago

Initial import of data of old repository ('data') worth keeping (e.g. tracking
means of URL access statistics)

File size: 34.3 KB
Line 
1/* C declarations */
2%{
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <math.h>
8#include <assert.h>
9#include <sysexits.h>
10#include "debug.h"
11#include "SyntaxTree.h"
12#include "SymbolTable.h"
13#include "Node.h"
14#include "messages.h"
15#include "coercion.h"
16#include "lookup.h"
17
18/* Prototypes */
19static void yyerror(const char *);
20
21/* Import from comp.l */
22extern int yylex(void); /* Lexer function */
23extern int lineno; /* Current line number */
24extern string lastID; /* The most recently read ID */
25extern string lastNUM; /* The most recently read value expression */
26extern string lastOP; /* The most recently read MULOP or RELOP */
27
28/* Other declarations */
29SyntaxTree * tree; /* The syntax tree */
30SymbolTable * symtab; /* The symbol table */
31string mainScopeName; /* The name of the main scope */
32Messages messages; /* Keeps track of warning/error messages */
33
34#ifdef DEBUG
35int msglevel = 90; /* higher = more debugging messages */
36#else
37int msglevel = 0; /* don't bother sensitive souls */
38#endif
39
40/* Macro to allow pretty display of parser tree calling stack debug print calls */
41#define pdebug(x) pmesg(100, "Parser: '"); pmesg(100, x); pmesg(100, "'\n")
42
43%}
44
45/* Start symbol */
46%start program
47
48/* Tokens */
49%token PROGRAM ID VAR NUM INTEGER REAL FUNCTION PROCEDURE
50%token PASCALBEGIN /* BEGIN is used internally by flex :-( */
51%token END ADDOP ASSIGNOP IF THEN ELSE WHILE DO RELOP
52%token MULOP NOT PROG_PARAMETER IRRELEVANT
53%token UMINUS /* unary minus */
54
55/* We wish to pass Node, Symbols and ReturnType pointers between the rules and
56 * actions
57 */
58%union {
59 Node *node;
60 ReturnType returntype;
61 Symbol *symbol;
62}
63
64%expect 1 /* shift/reduce conflict: dangling ELSE */
65%%
66
67/* GRAMMAR RULES AND ACTIONS */
68
69program: PROGRAM ID {
70 pdebug("program: PROGRAM ID");
71 /* The program name has just been read; save it */
72 mainScopeName = lastID;
73
74 /* Put the program name into the syntax tree */
75 tree->SetProgramName (mainScopeName);
76
77 /* Create a new scope in the symbol table */
78 symtab->AddScope (mainScopeName);
79
80 /* Add builtin functions and procedures */
81
82 /* function readinteger() : integer; */
83 Symbol * freshFunction = new Symbol_Subprogram();
84 freshFunction->SetName("readinteger");
85 freshFunction->SetReturnType(RT_INT);
86 freshFunction->SetSymbolType(ST_FUNCTION);
87 freshFunction->SetLine(0);
88 symtab->AddSymbol(freshFunction);
89
90 /* procedure writeinteger(i: integer); */
91 freshFunction = new Symbol_Subprogram();
92 freshFunction->SetName("writeinteger");
93 freshFunction->SetReturnType(RT_VOID);
94 freshFunction->SetSymbolType(ST_PROCEDURE);
95 freshFunction->SetLine(0);
96
97 Symbol * freshParam = new Symbol();
98 freshParam->SetReturnType(RT_INT);
99 freshParam->SetName("i");
100 freshFunction->AddParameter(freshParam);
101
102 symtab->AddSymbol(freshFunction);
103
104 /* function readreal() : real; */
105 freshFunction = new Symbol_Subprogram();
106 freshFunction->SetName("readreal");
107 freshFunction->SetReturnType(RT_REAL);
108 freshFunction->SetSymbolType(ST_FUNCTION);
109 freshFunction->SetLine(0);
110 symtab->AddSymbol(freshFunction);
111
112 /* procedure writereal(r: real); */
113 freshFunction = new Symbol_Subprogram();
114 freshFunction->SetName("writereal");
115 freshFunction->SetReturnType(RT_VOID);
116 freshFunction->SetSymbolType(ST_PROCEDURE);
117 freshFunction->SetLine(0);
118
119 freshParam = new Symbol();
120 freshParam->SetReturnType(RT_REAL);
121 freshParam->SetName("r");
122 freshFunction->AddParameter(freshParam);
123
124 symtab->AddSymbol(freshFunction);
125
126 }
127 ';' declarations subprogram_declarations compound_statement '.' {
128 tree->SetProgramBody($<node>7);
129 }
130 ;
131
132
133type_identifier_list:
134 ',' ID {
135 /* Create new symbol */
136 check_id(lastID);
137 Symbol * freshVar = new Symbol();
138 symtab->AddSymbol(freshVar);
139 /* Fill with yet known values */
140 freshVar->SetSymbolType(ST_UNKNOWN);
141 freshVar->SetName(lastID);
142 freshVar->SetLine(lineno);
143 $<node>$ = tree->CreateLeaf(freshVar);
144
145 } type_identifier_list {
146 pdebug("type_identifier_list: ',' ID type_identifier_list");
147 $<node>3->GetSymbol()->SetReturnType($<node>4->GetReturnType());
148
149 /* Create list out of it */
150 $<node>$ = tree->CreateParentNode(NODE_ID, $<node>4->GetReturnType(),
151 $<node>3, $<node>4); //XXX: Check: NODE_ID that's not a leaf?
152 }
153 | ':' type {
154 pdebug("type_identifier_list: ':' type");
155 /* Closing of list is a Node of type NODE_EMPTY */
156 Node * freshNode = tree->CreateLeaf();
157 freshNode->SetReturnType($<returntype>2);
158 $<node>$ = freshNode;
159 }
160 ;
161
162
163declarations: /* In declarations the VAR-variables are listed for the
164 program as well as for the procedures and functions. */
165
166 declarations VAR ID {
167 pdebug("declarations: declarations VAR ID");
168 /* Create new symbol */
169 check_id(lastID);
170 Symbol * freshVar = new Symbol();
171 symtab->AddSymbol(freshVar);
172
173 /* Fill with yet known values */
174 freshVar->SetSymbolType(ST_UNKNOWN);
175 freshVar->SetName(lastID);
176 freshVar->SetLine(lineno);
177 /* Temporary fill first Node with leaf value, as official value is not yet known */
178 $<node>$ = tree->CreateParentNode(NODE_ID, RT_UNKNOWN, tree->CreateLeaf(freshVar), tree->CreateLeaf());
179 }
180 type_identifier_list ';' {
181 pdebug("declarations: type_identifier_list ';'");
182 /* Fix temporary node */
183 Node * ptrNode = $<node>4;
184 ptrNode->SetReturnType($<node>5->GetReturnType());
185 ptrNode->GetLeftChild()->GetSymbol()->SetReturnType($<node>5->GetReturnType());
186 ptrNode->SetRightChild($<node>5);
187
188 /* Set all symbols to be parameters */
189 while ( ptrNode->GetNodeType() != NODE_EMPTY ) {
190 ptrNode->GetLeftChild()->GetSymbol()->SetSymbolType(ST_VARIABLE);
191 ptrNode = ptrNode->GetRightChild();
192 }
193 $<node>$ = $<node>4;
194 }
195 | /* lambda */ {
196 pdebug("declarations: <lambda>");
197 $<node>$ = tree->CreateLeaf() ;
198 }
199 ;
200
201
202type: standard_type {
203 pdebug("type: standard_type");
204 $<returntype>$ = $<returntype>1;
205 }
206 ;
207
208
209standard_type: INTEGER {
210 pdebug("standard_type: INTEGER");
211 $<returntype>$ = RT_INT;
212 }
213
214
215 | REAL {
216 pdebug("standard_type: REAL");
217 $<returntype>$ = RT_REAL;
218 }
219 ;
220
221
222subprogram_declarations:
223 subprogram_declarations subprogram_declaration ';' {
224 pdebug("subprogram_declaration: subprogram_declarations subprogram_declarations ';'");
225 /* Empty, no actions required */
226 }
227 | /* lambda */ {
228 pdebug("subprogram_declarations: <lambda>");
229 /* Empty, no actions required */
230 }
231 ;
232
233
234subprogram_declaration:
235 subprogram_head declarations compound_statement {
236 pdebug("subprogram_declaration: subprogram_head declarations compound_statement");
237 tree->AddSubprogram($<symbol>1->GetName(), $<node>3);
238 // leave subprogram scope
239 symtab->SetCurrentScope(symtab->GetRootScope()->GetName());
240 }
241 ;
242
243
244subprogram_head:
245 FUNCTION ID {
246 pdebug("subprogram_head: FUNCTION ID");
247 check_id(lastID);
248 /* Create New subprogram */
249 Symbol * freshProgram = new Symbol_Subprogram();
250 freshProgram->SetLine(lineno);
251 freshProgram->SetName(lastID);
252 freshProgram->SetSymbolType(ST_FUNCTION);
253 symtab->AddSymbol(freshProgram);
254
255 /* Subprogram means new scope */
256 symtab->AddScope(lastID);
257 symtab->SetCurrentScope(lastID);
258 Node * freshNode = tree->CreateLeaf(freshProgram);
259 /* Push fresh function into passing variable */
260 $<node>$ = freshNode;
261 }
262 arguments ':' standard_type ';' {
263 pdebug("subprogram_head: arguments ':' standard_type ';'");
264 /* Set returntype of new function */
265 Node * ptrNode = $<node>3;
266 Symbol * ptrSymbol = ptrNode->GetSymbol();
267 ptrNode->SetReturnType($<returntype>6);
268 ptrSymbol->SetReturnType($<returntype>6);
269
270 /* Add parameters to new function */
271 Node * ptrNodeParam;
272 ptrNode = $<node>4;
273 while (ptrNode->GetNodeType() != NODE_EMPTY) {
274 ptrNodeParam = ptrNode->GetLeftChild();
275 while (ptrNodeParam->GetNodeType() != NODE_EMPTY) {
276 ptrSymbol->AddParameter(ptrNodeParam->GetLeftChild()->GetSymbol());
277 ptrNodeParam = ptrNodeParam->GetRightChild();
278 }
279 ptrNode = ptrNode->GetRightChild();
280 }
281
282 $<symbol>$ = $<node>3->GetSymbol();
283 }
284 | PROCEDURE ID {
285 pdebug("subprogram_head: PROCEDURE ID");
286 /* Looks a bit like a FUNCTION ID clone, but got subtle
287 * differences in arguments and return values
288 */
289 check_id(lastID);
290
291 /* Procedure mean new subprogram */
292 Symbol * freshProgram = new Symbol_Subprogram();
293 freshProgram->SetLine(lineno);
294 freshProgram->SetName(lastID);
295 freshProgram->SetSymbolType(ST_PROCEDURE);
296 freshProgram->SetReturnType(RT_VOID);
297 symtab->AddSymbol(freshProgram);
298
299 /* Procedure mean new scope */
300 symtab->AddScope(lastID);
301 symtab->SetCurrentScope(lastID);
302 Node * freshNode = tree->CreateLeaf(freshProgram);
303 freshNode->SetReturnType(RT_VOID);
304 $<node>$ = freshNode;
305
306 }
307 arguments ';' {
308 pdebug("subprogram_head: arguments ';'");
309 /* Add parameters to procedure */
310 Node * ptrNode = $<node>4;
311 Node * ptrNodeParam;
312 Symbol * ptrSymbol = $<node>3->GetSymbol();
313 while (ptrNode->GetNodeType() != NODE_EMPTY) {
314 ptrNodeParam = ptrNode->GetLeftChild();
315 while (ptrNodeParam->GetNodeType() != NODE_EMPTY) {
316 ptrSymbol->AddParameter(ptrNodeParam->GetLeftChild()->GetSymbol());
317 ptrNodeParam = ptrNodeParam->GetRightChild();
318 }
319 ptrNode = ptrNode->GetRightChild();
320 }
321 $<symbol>$ = $<node>3->GetSymbol();
322 }
323 ;
324
325
326arguments: '(' parameter_lists ')' {
327 pdebug("arguments: '(' parameter_lists ')'");
328 $<node>$ = $<node>2;
329 }
330 | /* lambda */ {
331 pdebug("arguments: <lambda>");
332 $<node>$ = tree->CreateLeaf();
333 }
334 ;
335
336
337parameter_lists: parameter_list ';' parameter_lists {
338 pdebug("parameter_lists: parameter_lists ';' parameter_lists");
339 $<node>$ = tree->CreateParentNode(NODE_UNKNOWN, RT_VOID, $<node>1, $<node>3);
340 }
341 | parameter_list {
342 pdebug("parameter_lists: parameter_list");
343 $<node>$ = tree->CreateParentNode(NODE_UNKNOWN, RT_VOID, $<node>1, tree->CreateLeaf());
344 }
345 ;
346
347
348parameter_list: ID {
349 pdebug("parameter_list: ID");
350 /* Create new symbol */
351 check_id(lastID);
352 Symbol * freshVar = new Symbol();
353 symtab->AddSymbol(freshVar);
354
355 /* Fill with yet known values */
356 freshVar->SetSymbolType(ST_UNKNOWN);
357 freshVar->SetName(lastID);
358 freshVar->SetLine(lineno);
359
360 /* Temporary add leaf as end node, not yet fully fillable */
361 $<node>$ = tree->CreateParentNode(NODE_ID, RT_UNKNOWN, tree->CreateLeaf(freshVar), tree->CreateLeaf());
362 }
363 type_identifier_list {
364 pdebug("parameter_list: type_identifier_list");
365 /* Fill missing (returnType) information */
366 Node * ptrNode = $<node>2;
367 ptrNode->SetReturnType($<node>3->GetReturnType());
368 ptrNode->GetLeftChild()->GetSymbol()->SetReturnType($<node>3->GetReturnType());
369 ptrNode->SetRightChild($<node>3);
370
371 /* Set all symbols to be parameters */
372 while ( ptrNode->GetNodeType() != NODE_EMPTY ) {
373 ptrNode->GetLeftChild()->GetSymbol()->SetSymbolType(ST_PARAMETER);
374 ptrNode = ptrNode->GetRightChild();
375 }
376 $<node>$ = $<node>2;
377 }
378 ;
379
380
381compound_statement:
382 PASCALBEGIN optional_statements END {
383 pdebug("compound_statement: PASCALBEGIN optional_statements END");
384 $<node>$ = $<node>2;
385 }
386 ;
387
388
389optional_statements:
390 statement_list {
391 pdebug("optional_statements: statement_list");
392 $<node>$ = $<node>1;
393 }
394 | /* lambda */ {
395 pdebug("optional_statements: <lambda>");
396 $<node>$ = tree->CreateLeaf();
397 }
398 ;
399
400
401statement_list: statement {
402 pdebug("statement_list: statement");
403 $<node>$ = tree->CreateParentNode(NODE_STATEMENT_LIST, RT_VOID,
404 $<node>1, tree->CreateLeaf());
405 }
406 | statement_list ';' statement {
407 pdebug("statement_list: statement_list ';' statement");
408 /* Make sure statements, get appended the right way e.g.
409 * always rightmost of the list
410 */
411
412 /* Find the last statement list */
413 Node *statement_list = $<node>1;
414 while (statement_list->GetRightChild()->GetNodeType() != NODE_EMPTY) {
415 statement_list = statement_list->GetRightChild();
416 }
417 /* Replace empty node with new statement list */
418 Node *new_statement_list = tree->CreateParentNode(NODE_STATEMENT_LIST, RT_VOID,
419 $<node>3, statement_list->GetRightChild());
420 statement_list->SetRightChild(new_statement_list);
421 $<node>$ = $<node>1;
422 }
423 ;
424
425
426statement: variable ASSIGNOP expression {
427 pdebug("statement: variable ASSIGNOP expression");
428 ReturnType returntype = $<node>1->GetReturnType();
429 $<node>$ = tree->CreateParentNode(NODE_ASSIGNMENT, returntype, $<node>1, coerce(returntype, $<node>3));
430 }
431 | procedure_statement {
432 pdebug("statement: procedure_statement");
433 $<node>$ = $<node>1;
434 }
435 | compound_statement {
436 pdebug("statement: compound_statement");
437 $<node>$ = $<node>1;
438 }
439 | IF boollikeexp THEN statement optional_else_statement {
440 pdebug("statement: IF boollikeexp THEN statement optional_else_statement");
441 if ($<node>5->GetNodeType() == NODE_EMPTY) {
442 /* No ELSE part */
443 $<node>$ = tree->CreateParentNode(NODE_IF, RT_VOID, $<node>2, $<node>4);
444 } else {
445 $<node>$ = tree->CreateParentNode(NODE_IF, RT_VOID, $<node>2,
446 tree->CreateParentNode(NODE_IF_TARGETS, RT_VOID, $<node>4, $<node>5));
447 }
448 }
449 | WHILE boollikeexp DO statement {
450 pdebug("statement: WHILE boollikeexp DO statement");
451 $<node>$ = tree->CreateParentNode(NODE_WHILE, RT_VOID, $<node>2, $<node>4);
452 }
453 ;
454
455
456optional_else_statement:
457 ELSE statement {
458 pdebug("optional_else_statement: ELSE statement");
459 $<node>$ = $<node>2;
460 }
461
462 | /* lambda */ {
463 pdebug("optional_else_statement: <lambda>");
464 $<node>$ = tree->CreateLeaf();
465 }
466 ;
467
468
469variable:
470 ID {
471 pdebug("variable: ID");
472 /* Find ID in symbol table */
473 Symbol *symbol = lookup(lastID, ST_VARIABLE);
474
475 /* symbol found: make sure it is a variable or a function return value */
476 SymbolType symboltype = symbol->GetSymbolType();
477 bool isvariable = (symboltype == ST_VARIABLE || symboltype == ST_PARAMETER);
478 bool isfuncretval = (symboltype == ST_FUNCTION && symtab->GetCurrentScopeName() == lastID);
479 if ( !isvariable && !isfuncretval ) {
480 messages.LValueError(lineno, lastID);
481 }
482 $<node>$ = tree->CreateLeaf(symbol);
483 }
484 ;
485
486
487procedure_statement:
488 ID {
489 pdebug("procedure_statement: ID");
490 /* Lookup ID */
491 Symbol *symbol = lookup(lastID, ST_PROCEDURE);
492
493 /* check the type of the symbol */
494 Node *node = NULL;
495 switch (symbol->GetSymbolType()) {
496 case ST_FUNCTION:
497 node = tree->CreateParentNode(NODE_FUNCTIONCALL, symbol->GetReturnType(),
498 tree->CreateLeaf(symbol), tree->CreateLeaf());
499 messages.ReturnValueError(lineno, lastID, symbol->GetReturnType());
500 check_parameters(node);
501 break;
502 case ST_PROCEDURE:
503 node = tree->CreateParentNode(NODE_PROCCALL, RT_VOID,
504 tree->CreateLeaf(symbol), tree->CreateLeaf());
505 check_parameters(node);
506 break;
507 case ST_VARIABLE: /* fall through */
508 case ST_PARAMETER:
509 case ST_UNKNOWN:
510 case ST_ERROR:
511 case ST_PROGRAM:
512 case ST_TEMPVAR:
513 case ST_LABEL:
514 default:
515 messages.CallError(lineno, lastID, symbol->GetSymbolType());
516 /* return dummy NODE_EMPTY, to avoid freeze/crashing tree */
517 node = tree->CreateLeaf();
518 }
519 assert(node != NULL);
520 $<node>$ = node;
521 }
522 | ID {
523 /* Lookup ID */
524 $<symbol>$ = lookup(lastID, ST_PROCEDURE);
525 }
526 '(' expression_list ')' {
527 pdebug("procedure_statement: ID '(' expression_list ')'");
528 /* check the type of the symbol */
529 Symbol *symbol = $<symbol>2;
530 Node *node = NULL;
531 switch (symbol->GetSymbolType()) {
532 case ST_FUNCTION:
533 node = tree->CreateParentNode(NODE_FUNCTIONCALL, symbol->GetReturnType(),
534 tree->CreateLeaf(symbol), $<node>4);
535 messages.ReturnValueError(lineno, lastID, symbol->GetReturnType());
536 check_parameters(node);
537 break;
538 case ST_PROCEDURE:
539 node = tree->CreateParentNode(NODE_PROCCALL, symbol->GetReturnType(),
540 tree->CreateLeaf(symbol), $<node>4);
541 check_parameters(node);
542 break;
543 case ST_VARIABLE: /* fall through */
544 case ST_PARAMETER:
545 case ST_UNKNOWN:
546 case ST_ERROR:
547 case ST_PROGRAM:
548 case ST_TEMPVAR:
549 case ST_LABEL:
550 default:
551 messages.CallError(lineno, symbol->GetName(), symbol->GetSymbolType());
552 /* return dummy NODE_EMPTY, to avoid freeze/crashing tree */
553 node = tree->CreateLeaf();
554 }
555 assert(node != NULL);
556 $<node>$ = node;
557 }
558 ;
559
560expression_list:
561 expression {
562 pdebug("expression_list: expression");
563 $<node>$ = tree->CreateParentNode(NODE_EXPRLIST, RT_VOID, $<node>1, tree->CreateLeaf());
564 }
565 | expression ',' expression_list {
566 pdebug("expression_list: expression ',' expression_list");
567 $<node>$ = tree->CreateParentNode(NODE_EXPRLIST, RT_VOID, $<node>1, $<node>3);
568 }
569 ;
570
571boollikeexp: expression RELOP expression {
572 pdebug("boollikeexp: expression RELOP expression");
573 ReturnType returnType = minimumtype($<node>1->GetReturnType(), $<node>3->GetReturnType());
574 Node *node_relop = NULL;
575 /* Find proper nodeType = mapping lastOP 1:1 NODE_* */
576 NodeType nodeType = NODE_UNKNOWN;
577 if (lastOP == "=") {
578 nodeType = NODE_REL_EQUAL;
579 } else if (lastOP == "<") {
580 nodeType = NODE_REL_LT;
581 } else if (lastOP == ">") {
582 nodeType = NODE_REL_GT;
583 } else if (lastOP == "<=") {
584 nodeType = NODE_REL_LTE;
585 } else if (lastOP == ">=") {
586 nodeType = NODE_REL_GTE;
587 } else if (lastOP == "<>") {
588 nodeType = NODE_REL_NOTEQUAL;
589 }
590 node_relop = tree->CreateParentNode(nodeType, RT_BOOL, coerce(returnType, $<node>1),
591 coerce(returnType, $<node>3));
592 $<node>$ = tree->CreateParentNode(NODE_BOOLEXPR, RT_BOOL, node_relop);
593 }
594 | '(' boollikeexp ')' {
595 pdebug("boollikeexp: '(' boollikeexp ')'");
596 /* to allow stuff like "if (a > 3) then" */
597 $<node>$ = $<node>2;
598 }
599 ;
600
601
602expression: simple_expression {
603 pdebug("expression: simple_expression");
604 $<node>$ = $<node>1;
605 }
606 ;
607
608
609simple_expression:
610 term {
611 pdebug("simple_expression: term");
612 $<node>$ = $<node>1;
613 }
614 | signplus term {
615 pdebug("simple_expression: signplus term");
616 $<node>$ = tree->CreateParentNode(NODE_SIGNMINUS, $<node>2->GetReturnType(), $<node>2);
617 }
618 | signminus term {
619 pdebug("simple_expression: signminus term");
620 $<node>$ = tree->CreateParentNode(NODE_SIGNPLUS, $<node>2->GetReturnType(), $<node>2);
621 }
622 | simple_expression '+' term {
623 pdebug("simple_expression: simple_expression '+' term");
624 ReturnType returnType = minimumtype($<node>1->GetReturnType(), $<node>3->GetReturnType());
625 $<node>$ = tree->CreateParentNode(NODE_ADD, returnType, coerce(returnType, $<node>1),
626 coerce(returnType, $<node>3));
627 }
628
629 | simple_expression '-' term {
630 pdebug("simple_expression: simple_expression '-' term");
631 ReturnType returnType = minimumtype($<node>1->GetReturnType(), $<node>3->GetReturnType());
632 $<node>$ = tree->CreateParentNode(NODE_SUB, returnType, coerce(returnType, $<node>1),
633 coerce(returnType, $<node>3));
634 }
635 | simple_expression ADDOP term {
636 pdebug("simple_expression: simple_expression ADDOP term");
637 /* According to ../tests/varia/no_real_in_boolean_expr.p1 no
638 * reals allowed in boolean expressions, so set returnType and coerce will TypeError
639 */
640 ReturnType returnType = RT_INT;
641 $<node>$ = tree->CreateParentNode(NODE_OR, returnType, coerce(returnType, $<node>1),
642 coerce(returnType, $<node>3));
643 }
644 ;
645
646
647term: factor {
648 pdebug("term: factor");
649 $<node>$ = $<node>1;
650 }
651 | term MULOP factor {
652 pdebug("term: term MULOP factor");
653 ReturnType returnType = minimumtype($<node>1->GetReturnType(), $<node>3->GetReturnType());
654 if (lastOP == "*") {
655 $<node>$ = tree->CreateParentNode(NODE_MUL, returnType, coerce(returnType, $<node>1),
656 coerce(returnType, $<node>3));
657 } else if (lastOP == "/") {
658 // real division operator always returns real
659 $<node>$ = tree->CreateParentNode(NODE_DIV, RT_REAL, coerce(RT_REAL, $<node>1),
660 coerce(RT_REAL, $<node>3));
661 } else if (lastOP == "div") {
662 // integer division operator always returns integer
663 $<node>$ = tree->CreateParentNode(NODE_IDIV, RT_INT, coerce(RT_INT, $<node>1),
664 coerce(RT_INT, $<node>3));
665 } else if (lastOP == "mod") {
666 // only works on integers
667 $<node>$ = tree->CreateParentNode(NODE_MOD, RT_INT, coerce(RT_INT, $<node>1),
668 coerce(RT_INT, $<node>3));
669 } else if (lastOP == "and") {
670 /* Bitwise operator, not allowed on reals, coerce will TypeError */
671 returnType = RT_INT;
672 $<node>$ = tree->CreateParentNode(NODE_AND, returnType, coerce(returnType, $<node>1),
673 coerce(returnType, $<node>3));
674 }
675 }
676 ;
677
678
679factor: ID {
680 pdebug("factor: ID");
681 /* Lookup ID */
682 Symbol *symbol = lookup(lastID, ST_VARIABLE);
683
684 /* check the type of the symbol */
685 Node *node = NULL;
686 switch (symbol->GetSymbolType()) {
687 case ST_VARIABLE: /* fall through */
688 case ST_PARAMETER:
689 node = tree->CreateLeaf(symbol);
690 break;
691 case ST_FUNCTION:
692 node = tree->CreateParentNode(NODE_FUNCTIONCALL, symbol->GetReturnType(),
693 tree->CreateLeaf(symbol), tree->CreateLeaf());
694 check_parameters(node);
695 break;
696 case ST_PROCEDURE: /* fall through */
697 case ST_UNKNOWN:
698 case ST_ERROR:
699 case ST_PROGRAM:
700 case ST_TEMPVAR:
701 case ST_LABEL:
702 default:
703 messages.RValueError(lineno, lastID, symbol->GetSymbolType());
704 /* return dummy NODE_EMPTY, to avoid crashing/freezing tree */
705 node = tree->CreateLeaf();
706 }
707 assert(node != NULL);
708 $<node>$ = node;
709 }
710 | ID {
711 /* Lookup ID */
712 $<symbol>$ = lookup(lastID, ST_FUNCTION);
713 }
714 '(' expression_list ')' {
715 pdebug("factor: ID '(' expression_list ')'");
716 /* check the type of the symbol */
717 Node *node = NULL;
718 Symbol *symbol = $<symbol>2;
719 switch (symbol->GetSymbolType()) {
720 case ST_FUNCTION:
721 node = tree->CreateParentNode(NODE_FUNCTIONCALL, symbol->GetReturnType(),
722 tree->CreateLeaf(symbol), $<node>4);
723 check_parameters(node);
724 break;
725 case ST_PROCEDURE:
726 node = tree->CreateParentNode(NODE_PROCCALL, symbol->GetReturnType(),
727 tree->CreateLeaf(symbol), $<node>4);
728 check_parameters(node);
729 break;
730 case ST_VARIABLE: /* fall through */
731 case ST_PARAMETER:
732 case ST_UNKNOWN:
733 case ST_ERROR:
734 case ST_PROGRAM:
735 case ST_TEMPVAR:
736 case ST_LABEL:
737 default:
738 messages.CallError(lineno, symbol->GetName(), symbol->GetSymbolType());
739 /* return dummy NODE_EMPTY, to avoid crashing/freezing tree */
740 node = tree->CreateLeaf();
741 }
742 assert(node != NULL);
743 $<node>$ = node;
744 }
745 | NUM {
746 pdebug("factor: NUM");
747 /* XXX: Hack to find out whether value is set to be real or
748 * integer, should really be something which needs to be done
749 * by the lexer, but we are not allowed to alter the language
750 * during this assignment
751 */
752 if (lastNUM.find_first_of(".E") != string::npos) {
753 /* found real */
754 float value = atof(lastNUM.c_str());
755 $<node>$ = tree->CreateLeaf(value);
756 } else {
757 /* found integer */
758 int value = atoi(lastNUM.c_str());
759 $<node>$ = tree->CreateLeaf(value);
760 }
761 }
762 | '(' expression ')' {
763 pdebug("factor: '(' expression ')'");
764 $<node>$ = $<node>2;
765 }
766 | NOT factor {
767 pdebug("factor: NOT factor");
768 /* Bitwise operator, no real allowed, coerce will TypeError */
769 ReturnType returnType = RT_INT;
770 $<node>$ = tree->CreateParentNode(NODE_NOT, returnType, coerce(returnType, $<node>2));
771 }
772 ;
773
774
775signplus: '+' {
776 pdebug("signplus: '+'");
777 }
778 ;
779
780signminus: '-' %prec UMINUS {
781 pdebug("signminus: '-' \%prec UMINUS");
782 }
783 ;
784
785%%
786
787/* End of rules, more C code will follow now */
788
789void initialize()
790{
791 /* Create & initialize the abstract data structures */
792 tree = new SyntaxTree;
793 symtab = new SymbolTable;
794}
795
796void cleanup()
797{
798 /* Free objects */
799 delete tree;
800 delete symtab;
801}
802
803/* Nice usage warning, for the ones in need */
804void usage()
805{
806 fprintf(stderr, "Arguments:\n");
807 fprintf(stderr, "-v[vv] = more verbose output\n");
808 fprintf(stderr, "-q[qq] = less verbose output\n");
809 fprintf(stderr, "-w = turn on warning messages\n");
810 fprintf(stderr, "-n = turn off warning messages\n");
811 fprintf(stderr, "-h = usage\n");
812 exit(EX_USAGE);
813}
814
815int main(int argc, char * argv[])
816{
817 int parseResult;
818 int ch;
819
820 /* Set trace settings */
821 while ((ch = getopt(argc, argv, "hnqvw")) != -1) {
822 switch (ch) {
823 case 'v':
824 msglevel += 30;
825 break;
826 case 'q':
827 msglevel -= 30;
828 break;
829 case 'w':
830 messages.EnableWarnings();
831 break;
832 case 'n':
833 messages.DisableWarnings();
834 break;
835 case 'h':
836 default:
837 usage();
838 }
839 }
840
841 initialize();
842
843 /* Start the parsing procedure */
844 parseResult = yyparse();
845 messages.ShowNumbers();
846
847 /* Dump the syntax tree & symbol table */
848 tree->Dump (stdout);
849 printf("\n");
850 symtab->Dump (stdout);
851
852 cleanup();
853
854 /* Return the exit code. Note that the exit code does not depend on
855 * parseResult only, but also on the result of your semantic checks
856 */
857 return (parseResult == 0 && messages.GetErrors() == 0) ? 0 : 1;
858}
859
860
861static void yyerror(const char *s)
862{
863 fprintf(stderr, "line %d: %s\n", lineno, s);
864}
865
866int yywrap()
867{
868 return(1);
869}
Note: See TracBrowser for help on using the repository browser.