1 #include "parser.h"
2
3 #ifdef DEBUG
4 static unsigned int shiftwidth = 0;
shiftout(void)5 void shiftout(void) { shiftwidth += 4; }
shiftin(void)6 void shiftin(void) { shiftwidth -= 4; }
debug(const char * info)7 void debug(const char *info)
8 {
9 int n;
10 for (n = 0; n < shiftwidth; n++)
11 fprintf(stderr, " ");
12 fprintf(stderr, "%s\n", info);
13 }
14 #endif
15
16 /**
17 * Creates the main code block of a program.
18 *
19 * \param [in] block The first code block to execute.
20 *
21 * \return A pointer to the main code block with the desired properties.
22 *
23 * \retval NULL Memory allocation failed.
24 */
createMainNode(BlockNode * block)25 MainNode *createMainNode(BlockNode *block)
26 {
27 MainNode *p = malloc(sizeof(MainNode));
28 if (!p) {
29 perror("malloc");
30 return NULL;
31 }
32 p->block = block;
33 return p;
34 }
35
36 /**
37 * Deletes the main code block of a program.
38 *
39 * \param [in,out] node The main code block to delete.
40 *
41 * \post The memory at \a node and all of its members will be freed.
42 */
deleteMainNode(MainNode * node)43 void deleteMainNode(MainNode *node)
44 {
45 if (!node) return;
46 deleteBlockNode(node->block);
47 free(node);
48 }
49
50 /**
51 * Creates a code block.
52 *
53 * \param [in] stmts The list of statements which comprise the code block.
54 *
55 * \return A pointer to the code block with the desired properties.
56 *
57 * \retval NULL Memory allocation failed.
58 */
createBlockNode(StmtNodeList * stmts)59 BlockNode *createBlockNode(StmtNodeList *stmts)
60 {
61 BlockNode *p = malloc(sizeof(BlockNode));
62 if (!p) {
63 perror("malloc");
64 return NULL;
65 }
66 p->stmts = stmts;
67 return p;
68 }
69
70 /**
71 * Deletes a code block.
72 *
73 * \param [in,out] node The code block to delete.
74 *
75 * \post The memory at \a node and all of its members will be freed.
76 */
deleteBlockNode(BlockNode * node)77 void deleteBlockNode(BlockNode *node)
78 {
79 if (!node) return;
80 deleteStmtNodeList(node->stmts);
81 free(node);
82 }
83
84 /**
85 * Creates an empty code block list.
86 *
87 * \return A pointer to an empty code block list.
88 *
89 * \retval NULL Memory allocation failed.
90 */
createBlockNodeList(void)91 BlockNodeList *createBlockNodeList(void)
92 {
93 BlockNodeList *p = malloc(sizeof(BlockNodeList));
94 if (!p) {
95 perror("malloc");
96 return NULL;
97 }
98 p->num = 0;
99 p->blocks = NULL;
100 return p;
101 }
102
103 /**
104 * Adds a code block to a list.
105 *
106 * \param [in,out] list The code block list to add \a node to.
107 *
108 * \param [in] node The code block to add to \a list.
109 *
110 * \post \a node will be added to \a list and its size will be updated.
111 *
112 * \retval 0 Memory allocation failed.
113 *
114 * \retval 1 \a node was added to \a list.
115 */
addBlockNode(BlockNodeList * list,BlockNode * node)116 int addBlockNode(BlockNodeList *list,
117 BlockNode *node)
118 {
119 unsigned int newsize = list->num + 1;
120 void *mem = realloc(list->blocks, sizeof(BlockNode *) * newsize);
121 if (!mem) {
122 perror("realloc");
123 return 0;
124 }
125 list->blocks = mem;
126 list->blocks[list->num] = node;
127 list->num = newsize;
128 return 1;
129 }
130
131 /**
132 * Deletes a code block list.
133 *
134 * \param [in,out] list The code block list to delete.
135 *
136 * \post The memory at \a list and all of its members will be freed.
137 */
deleteBlockNodeList(BlockNodeList * list)138 void deleteBlockNodeList(BlockNodeList *list)
139 {
140 unsigned int n;
141 if (!list) return;
142 for (n = 0; n < list->num; n++)
143 deleteBlockNode(list->blocks[n]);
144 free(list->blocks);
145 free(list);
146 }
147
148 /**
149 * Creates a boolean constant.
150 *
151 * \param [in] data The boolean constant value.
152 *
153 * \return A pointer to a boolean constant which will be FALSE if \a data is \c
154 * 0 and TRUE otherwise.
155 *
156 * \retval NULL Memory allocation failed.
157 */
createBooleanConstantNode(int data)158 ConstantNode *createBooleanConstantNode(int data)
159 {
160 ConstantNode *p = malloc(sizeof(ConstantNode));
161 if (!p) {
162 perror("malloc");
163 return NULL;
164 }
165 p->type = CT_BOOLEAN;
166 p->data.i = (data != 0);
167 return p;
168 }
169
170 /**
171 * Creates an integer constant.
172 *
173 * \param [in] data The integer constant value.
174 *
175 * \return A pointer to an integer constant whose value is \a data.
176 *
177 * \retval NULL Memory allocation failed.
178 */
createIntegerConstantNode(long long data)179 ConstantNode *createIntegerConstantNode(long long data)
180 {
181 ConstantNode *p = malloc(sizeof(ConstantNode));
182 if (!p) {
183 perror("malloc");
184 return NULL;
185 }
186 p->type = CT_INTEGER;
187 p->data.i = data;
188 return p;
189 }
190
191 /**
192 * Creates a float constant.
193 *
194 * \param [in] data The float constant value.
195 *
196 * \return A pointer to a float constant whose value is \a data.
197 *
198 * \retval NULL Memory allocation failed.
199 */
createFloatConstantNode(float data)200 ConstantNode *createFloatConstantNode(float data)
201 {
202 ConstantNode *p = malloc(sizeof(ConstantNode));
203 if (!p) {
204 perror("malloc");
205 return NULL;
206 }
207 p->type = CT_FLOAT;
208 p->data.f = data;
209 return p;
210 }
211
212 /**
213 * Creates a string constant.
214 *
215 * \param [in] data The string constant value.
216 *
217 * \return A pointer to the string constant whose value is \a data.
218 *
219 * \retval NULL Memory allocation failed.
220 */
createStringConstantNode(char * data)221 ConstantNode *createStringConstantNode(char *data)
222 {
223 ConstantNode *p = malloc(sizeof(ConstantNode));
224 if (!p) {
225 perror("malloc");
226 return NULL;
227 }
228 p->type = CT_STRING;
229 p->data.s = data;
230 return p;
231 }
232
233 /**
234 * Deletes a constant.
235 *
236 * \param [in,out] node The constant to delete.
237 *
238 * \post The memory at \a node and all of its members will be freed.
239 */
deleteConstantNode(ConstantNode * node)240 void deleteConstantNode(ConstantNode *node)
241 {
242 if (!node) return;
243 if (node->type == CT_STRING) free(node->data.s);
244 free(node);
245 }
246
247 /**
248 * Creates an indentifier.
249 *
250 * \param [in] type The type of the identifier \a id.
251 *
252 * \param [in] id The identifier data.
253 *
254 * \param [in] slot An optional slot to index.
255 *
256 * \param [in] fname The file containing the identifier.
257 *
258 * \param [in] line The line the identifier occurred on.
259 *
260 * \return A pointer to the identifier with the desired properties.
261 *
262 * \retval NULL Memory allocation failed.
263 */
createIdentifierNode(IdentifierType type,void * id,IdentifierNode * slot,const char * fname,unsigned int line)264 IdentifierNode *createIdentifierNode(IdentifierType type,
265 void *id,
266 IdentifierNode *slot,
267 const char *fname,
268 unsigned int line)
269 {
270 IdentifierNode *p = malloc(sizeof(IdentifierNode));
271 if (!p) {
272 perror("malloc");
273 return NULL;
274 }
275 p->type = type;
276 p->id = id;
277 p->slot = slot;
278 if (fname) {
279 p->fname = malloc(sizeof(char) * (strlen(fname) + 1));
280 strcpy(p->fname, fname);
281 }
282 else {
283 p->fname = NULL;
284 }
285 p->line = line;
286 return p;
287 }
288
289 /**
290 * Deletes an identifier.
291 *
292 * \param [in,out] node The identifier to delete.
293 *
294 * \post The memory at \a node and all of its members will be freed.
295 */
deleteIdentifierNode(IdentifierNode * node)296 void deleteIdentifierNode(IdentifierNode *node)
297 {
298 if (!node) return;
299 switch (node->type) {
300 case IT_DIRECT: {
301 free(node->id);
302 break;
303 }
304 case IT_INDIRECT: {
305 deleteExprNode(node->id);
306 break;
307 }
308 default:
309 error(PR_UNKNOWN_IDENTIFIER_TYPE, node->fname, node->line);
310 break;
311 }
312 if (node->slot) deleteIdentifierNode(node->slot);
313 if (node->fname) free(node->fname);
314 free(node);
315 }
316
317 /**
318 * Creates an identifier list.
319 *
320 * \return A pointer to an identifier list.
321 *
322 * \retval NULL Memory allocation failed.
323 */
createIdentifierNodeList(void)324 IdentifierNodeList *createIdentifierNodeList(void)
325 {
326 IdentifierNodeList *p = malloc(sizeof(IdentifierNodeList));
327 if (!p) {
328 perror("malloc");
329 return NULL;
330 }
331 p->num = 0;
332 p->ids = NULL;
333 return p;
334 }
335
336 /**
337 * Adds an identifier to a list.
338 *
339 * \param [in,out] list The list of identifiers to add \a node to.
340 *
341 * \param [in] node The identifier to add to \a list.
342 *
343 * \post \a token will be added to the end of \a list and the size of \a list
344 * will be updated.
345 *
346 * \retval 0 Memory allocation failed.
347 *
348 * \retval 1 \a node was added to \a list.
349 */
addIdentifierNode(IdentifierNodeList * list,IdentifierNode * node)350 int addIdentifierNode(IdentifierNodeList *list,
351 IdentifierNode *node)
352 {
353 unsigned int newsize = list->num + 1;
354 void *mem = realloc(list->ids, sizeof(IdentifierNode *) * newsize);
355 if (!mem) {
356 perror("realloc");
357 return 0;
358 }
359 list->ids = mem;
360 list->ids[list->num] = node;
361 list->num = newsize;
362 return 1;
363 }
364
365 /**
366 * Deletes an identifier list.
367 *
368 * \param [in,out] list The list of identifiers to delete.
369 *
370 * \post The memory at \a list and all of its members will be freed.
371 */
deleteIdentifierNodeList(IdentifierNodeList * list)372 void deleteIdentifierNodeList(IdentifierNodeList *list)
373 {
374 unsigned int n;
375 if (!list) return;
376 for (n = 0; n < list->num; n++)
377 deleteIdentifierNode(list->ids[n]);
378 free(list->ids);
379 free(list);
380 }
381
382 /**
383 * Creates a type.
384 *
385 * \param [in] type The type to create.
386 *
387 * \return A pointer to a new type with the desired properties.
388 *
389 * \retval NULL Memory allocatin failed.
390 */
createTypeNode(ConstantType type)391 TypeNode *createTypeNode(ConstantType type)
392 {
393 TypeNode *p = malloc(sizeof(TypeNode));
394 if (!p) {
395 perror("malloc");
396 return NULL;
397 }
398 p->type = type;
399 return p;
400 }
401
402 /**
403 * Deletes a type.
404 *
405 * \param [in,out] node The type to delete.
406 *
407 * \post The memory at \a node and all of its members will be freed.
408 */
deleteTypeNode(TypeNode * node)409 void deleteTypeNode(TypeNode *node)
410 {
411 if (!node) return;
412 free(node);
413 }
414
415 /**
416 * Creates a statement.
417 *
418 * \param [in] type The type of statement.
419 *
420 * \param [in] stmt The statement data.
421 *
422 * \return A pointer to a statement with the desired properties.
423 *
424 * \retval NULL malloc was unable to allocate memory.
425 */
createStmtNode(StmtType type,void * stmt)426 StmtNode *createStmtNode(StmtType type,
427 void *stmt)
428 {
429 StmtNode *p = malloc(sizeof(StmtNode));
430 if (!p) {
431 perror("malloc");
432 return NULL;
433 }
434 p->type = type;
435 p->stmt = stmt;
436 return p;
437 }
438
439 /**
440 * Deletes a statement.
441 *
442 * \param [in,out] node The statement to delete.
443 *
444 * \post The memory at \a node and all of its members will be freed.
445 */
deleteStmtNode(StmtNode * node)446 void deleteStmtNode(StmtNode *node)
447 {
448 if (!node) return;
449 switch (node->type) {
450 case ST_CAST: {
451 CastStmtNode *stmt = (CastStmtNode *)node->stmt;
452 deleteCastStmtNode(stmt);
453 break;
454 }
455 case ST_PRINT: {
456 PrintStmtNode *stmt = (PrintStmtNode *)node->stmt;
457 deletePrintStmtNode(stmt);
458 break;
459 }
460 case ST_INPUT: {
461 InputStmtNode *stmt = (InputStmtNode *)node->stmt;
462 deleteInputStmtNode(stmt);
463 break;
464 }
465 case ST_ASSIGNMENT: {
466 AssignmentStmtNode *stmt = (AssignmentStmtNode *)node->stmt;
467 deleteAssignmentStmtNode(stmt);
468 break;
469 }
470 case ST_DECLARATION: {
471 DeclarationStmtNode *stmt = (DeclarationStmtNode *)node->stmt;
472 deleteDeclarationStmtNode(stmt);
473 break;
474 }
475 case ST_IFTHENELSE: {
476 IfThenElseStmtNode *stmt = (IfThenElseStmtNode *)node->stmt;
477 deleteIfThenElseStmtNode(stmt);
478 break;
479 }
480 case ST_SWITCH: {
481 SwitchStmtNode *stmt = (SwitchStmtNode *)node->stmt;
482 deleteSwitchStmtNode(stmt);
483 break;
484 }
485 case ST_BREAK:
486 break; /* This statement type does not have any content */
487 case ST_RETURN: {
488 ReturnStmtNode *stmt = (ReturnStmtNode *)node->stmt;
489 deleteReturnStmtNode(stmt);
490 break;
491 }
492 case ST_LOOP: {
493 LoopStmtNode *stmt = (LoopStmtNode *)node->stmt;
494 deleteLoopStmtNode(stmt);
495 break;
496 }
497 case ST_DEALLOCATION: {
498 DeallocationStmtNode *stmt = (DeallocationStmtNode *)node->stmt;
499 deleteDeallocationStmtNode(stmt);
500 break;
501 }
502 case ST_FUNCDEF: {
503 FuncDefStmtNode *stmt = (FuncDefStmtNode *)node->stmt;
504 deleteFuncDefStmtNode(stmt);
505 break;
506 }
507 case ST_EXPR: {
508 ExprNode *expr = (ExprNode *)node->stmt;
509 deleteExprNode(expr);
510 break;
511 }
512 case ST_ALTARRAYDEF: {
513 AltArrayDefStmtNode *stmt = (AltArrayDefStmtNode *)node->stmt;
514 deleteAltArrayDefStmtNode(stmt);
515 break;
516 }
517 case ST_BINDING: {
518 BindingStmtNode *stmt = (BindingStmtNode *)node->stmt;
519 deleteBindingStmtNode(stmt);
520 break;
521 }
522 case ST_IMPORT: {
523 ImportStmtNode *stmt = (ImportStmtNode *)node->stmt;
524 deleteImportStmtNode(stmt);
525 break;
526 }
527 default:
528 error(PR_UNKNOWN_STATEMENT_TYPE);
529 break;
530 }
531 free(node);
532 }
533
534 /**
535 * Creates an empty statement list.
536 *
537 * \return A pointer to an empty statement list.
538 *
539 * \retval NULL Memory allocation failed.
540 */
createStmtNodeList(void)541 StmtNodeList *createStmtNodeList(void)
542 {
543 StmtNodeList *p = malloc(sizeof(StmtNodeList));
544 if (!p) {
545 perror("malloc");
546 return NULL;
547 }
548 p->num = 0;
549 p->stmts = NULL;
550 return p;
551 }
552
553 /**
554 * Adds a statement to a list.
555 *
556 * \param [in,out] list The statement list to add \a node to.
557 *
558 * \param [in] node The statement to add to \a list.
559 *
560 * \post \a node will be added to \a list and its size will be updated.
561 *
562 * \retval 0 Memory allocation failed.
563 *
564 * \retval 1 \a node was added to \a list.
565 */
addStmtNode(StmtNodeList * list,StmtNode * node)566 int addStmtNode(StmtNodeList *list,
567 StmtNode *node)
568 {
569 unsigned int newsize = list->num + 1;
570 void *mem = realloc(list->stmts, sizeof(StmtNode *) * newsize);
571 if (!mem) {
572 perror("realloc");
573 return 0;
574 }
575 list->stmts = mem;
576 list->stmts[list->num] = node;
577 list->num = newsize;
578 return 1;
579 }
580
581 /**
582 * Deletes a statement list.
583 *
584 * \param [in,out] list The statement list to delete.
585 *
586 * \post The memory at \a list and all of its members will be freed.
587 */
deleteStmtNodeList(StmtNodeList * list)588 void deleteStmtNodeList(StmtNodeList *list)
589 {
590 unsigned int n;
591 if (!list) return;
592 for (n = 0; n < list->num; n++)
593 deleteStmtNode(list->stmts[n]);
594 free(list->stmts);
595 free(list);
596 }
597
598 /**
599 * Creates a cast statement.
600 *
601 * \param [in] target The variable to cast to \a newtype.
602 *
603 * \param [in] newtype The type to cast \a target to.
604 *
605 * \return A pointer to a cast statement with the desired properties.
606 *
607 * \retval NULL Memory allocation failed.
608 */
createCastStmtNode(IdentifierNode * target,TypeNode * newtype)609 CastStmtNode *createCastStmtNode(IdentifierNode *target,
610 TypeNode *newtype)
611 {
612 CastStmtNode *p = malloc(sizeof(CastStmtNode));
613 if (!p) {
614 perror("malloc");
615 return NULL;
616 }
617 p->target = target;
618 p->newtype = newtype;
619 return p;
620 }
621
622 /**
623 * Deletes a cast statement.
624 *
625 * \param [in,out] node The cast statement to delete.
626 *
627 * \post The memory at \a node and all of its members will be freed.
628 */
deleteCastStmtNode(CastStmtNode * node)629 void deleteCastStmtNode(CastStmtNode *node)
630 {
631 if (!node) return;
632 deleteIdentifierNode(node->target);
633 deleteTypeNode(node->newtype);
634 free(node);
635 }
636
637 /**
638 * Creates a print statement.
639 *
640 * \param [in] args The expressions to print.
641 *
642 * \param [in] nonl Whether an ending newline should be surpressed.
643 *
644 * \return A pointer to the print statement with the desired properties.
645 *
646 * \retval NULL Memory allocation failed.
647 */
createPrintStmtNode(ExprNodeList * args,int nonl)648 PrintStmtNode *createPrintStmtNode(ExprNodeList *args,
649 int nonl)
650 {
651 PrintStmtNode *p = malloc(sizeof(PrintStmtNode));
652 if (!p) {
653 perror("malloc");
654 return NULL;
655 }
656 p->args = args;
657 p->nonl = nonl;
658 return p;
659 }
660
661 /**
662 * Deletes a print statement.
663 *
664 * \param [in,out] node The print statement to delete.
665 *
666 * \post The memory at \a node and all of its members will be freed.
667 */
deletePrintStmtNode(PrintStmtNode * node)668 void deletePrintStmtNode(PrintStmtNode *node)
669 {
670 if (!node) return;
671 deleteExprNodeList(node->args);
672 free(node);
673 }
674
675 /**
676 * Creates an input statement.
677 *
678 * \param [in] target The variable to store input in.
679 *
680 * \return A pointer to an input statement with the desired properties.
681 *
682 * \retval NULL Memory allocation failed.
683 */
createInputStmtNode(IdentifierNode * target)684 InputStmtNode *createInputStmtNode(IdentifierNode *target)
685 {
686 InputStmtNode *p = malloc(sizeof(InputStmtNode));
687 if (!p) {
688 perror("malloc");
689 return NULL;
690 }
691 p->target = target;
692 return p;
693 }
694
695 /**
696 * Deletes an input statement.
697 *
698 * \param [in,out] node The input statement to delete.
699 *
700 * \post The memory at \a node and all of its members will be freed.
701 */
deleteInputStmtNode(InputStmtNode * node)702 void deleteInputStmtNode(InputStmtNode *node)
703 {
704 if (!node) return;
705 deleteIdentifierNode(node->target);
706 free(node);
707 }
708
709 /**
710 * Creates an assignment statement.
711 *
712 * \param [in] target The variable to store \a expr in.
713 *
714 * \param [in] expr The expression to store in \a target.
715 *
716 * \return A pointer to an assignment statement with the desired properties.
717 *
718 * \retval NULL Memory allocation failed.
719 */
createAssignmentStmtNode(IdentifierNode * target,ExprNode * expr)720 AssignmentStmtNode *createAssignmentStmtNode(IdentifierNode *target,
721 ExprNode *expr)
722 {
723 AssignmentStmtNode *p = malloc(sizeof(AssignmentStmtNode));
724 if (!p) {
725 perror("malloc");
726 return NULL;
727 }
728 p->target = target;
729 p->expr = expr;
730 return p;
731 }
732
733 /**
734 * Deletes an assignment statement.
735 *
736 * \param [in,out] node The assignment statement to delete.
737 *
738 * \post The memory at \a node and all of its members will be freed.
739 */
deleteAssignmentStmtNode(AssignmentStmtNode * node)740 void deleteAssignmentStmtNode(AssignmentStmtNode *node)
741 {
742 if (!node) return;
743 deleteIdentifierNode(node->target);
744 deleteExprNode(node->expr);
745 free(node);
746 }
747
748 /**
749 * Creates a declaration statement.
750 *
751 * \param [in] scope The scope to create the variable in.
752 *
753 * \param [in] target The variable to create.
754 *
755 * \param [in] expr An optional expression to initialize \a target to.
756 *
757 * \param [in] type An optional type to initialize \a target to.
758 *
759 * \param [in] parent The optional parent to inherit from.
760 *
761 * \return A pointer to a declaration statement with the desired properties.
762 *
763 * \retval NULL Memory allocation failed.
764 */
createDeclarationStmtNode(IdentifierNode * scope,IdentifierNode * target,ExprNode * expr,TypeNode * type,IdentifierNode * parent)765 DeclarationStmtNode *createDeclarationStmtNode(IdentifierNode *scope,
766 IdentifierNode *target,
767 ExprNode *expr,
768 TypeNode *type,
769 IdentifierNode *parent)
770 {
771 DeclarationStmtNode *p = malloc(sizeof(DeclarationStmtNode));
772 if (!p) {
773 perror("malloc");
774 return NULL;
775 }
776 p->scope = scope;
777 p->target = target;
778 p->expr = expr;
779 p->type = type;
780 p->parent = parent;
781 return p;
782 }
783
784 /**
785 * Deletes a declaration statement.
786 *
787 * \param [in,out] node The declaration statement to delete.
788 *
789 * \post The memory at \a node and all of its members will be freed.
790 */
deleteDeclarationStmtNode(DeclarationStmtNode * node)791 void deleteDeclarationStmtNode(DeclarationStmtNode *node)
792 {
793 if (!node) return;
794 deleteIdentifierNode(node->scope);
795 deleteIdentifierNode(node->target);
796 deleteExprNode(node->expr);
797 deleteTypeNode(node->type);
798 deleteIdentifierNode(node->parent);
799 free(node);
800 }
801
802 /**
803 * Creates an if/then/else statement.
804 *
805 * \param [in] yes The code block to execute if the \ref impvar "implicit
806 * variable" is \c true.
807 *
808 * \param [in] no The code block to execute if the \ref impvar "implicit
809 * variable" is \c false and all \a guards are \c false.
810 *
811 * \param [in] guards The expressions to test if the \ref impvar "implicit
812 * variable" is \c false.
813 *
814 * \param [in] blocks The code blocks to execute if the respective guard is \c
815 * true.
816 *
817 * \return A pointer to the if/then/else statement with the desired properties.
818 *
819 * \retval NULL Memory allocation failed.
820 */
createIfThenElseStmtNode(BlockNode * yes,BlockNode * no,ExprNodeList * guards,BlockNodeList * blocks)821 IfThenElseStmtNode *createIfThenElseStmtNode(BlockNode *yes,
822 BlockNode *no,
823 ExprNodeList *guards,
824 BlockNodeList *blocks)
825 {
826 IfThenElseStmtNode *p = malloc(sizeof(IfThenElseStmtNode));
827 if (!p) {
828 perror("malloc");
829 return NULL;
830 }
831 p->yes = yes;
832 p->no = no;
833 p->guards = guards;
834 p->blocks = blocks;
835 return p;
836 }
837
838 /**
839 * Deletes an if/then/else statement.
840 *
841 * \param [in,out] node The if/then/else statement to delete.
842 *
843 * \post The memory at \a node and all of its members will be freed.
844 */
deleteIfThenElseStmtNode(IfThenElseStmtNode * node)845 void deleteIfThenElseStmtNode(IfThenElseStmtNode *node)
846 {
847 if (!node) return;
848 deleteBlockNode(node->yes);
849 deleteBlockNode(node->no);
850 deleteExprNodeList(node->guards);
851 deleteBlockNodeList(node->blocks);
852 free(node);
853 }
854
855 /**
856 * Creates a switch statement.
857 *
858 * \param [in] guards The expressions to compare the the \ref impvar "implicit
859 * variable".
860 *
861 * \param [in] blocks The code blocks to execute if a respective guard matches
862 * the \ref impvar "implicit variable".
863 *
864 * \param [in] def The default code block to execute if none of the \a guards
865 * match the \ref impvar "implicit variable".
866 *
867 * \return A pointer to a switch statement with the desired properties.
868 *
869 * \retval NULL Memory allocation failed.
870 */
createSwitchStmtNode(ExprNodeList * guards,BlockNodeList * blocks,BlockNode * def)871 SwitchStmtNode *createSwitchStmtNode(ExprNodeList *guards,
872 BlockNodeList *blocks,
873 BlockNode *def)
874 {
875 SwitchStmtNode *p = malloc(sizeof(SwitchStmtNode));
876 if (!p) {
877 perror("malloc");
878 return NULL;
879 }
880 p->guards = guards;
881 p->blocks = blocks;
882 p->def = def;
883 return p;
884 }
885
886 /**
887 * Deletes a switch statement.
888 *
889 * \param [in,out] node The switch statement to delete.
890 *
891 * \post The memory at \a node and all of its members will be freed.
892 */
deleteSwitchStmtNode(SwitchStmtNode * node)893 void deleteSwitchStmtNode(SwitchStmtNode *node)
894 {
895 if (!node) return;
896 deleteExprNodeList(node->guards);
897 deleteBlockNodeList(node->blocks);
898 deleteBlockNode(node->def);
899 free(node);
900 }
901
902 /**
903 * Creates a return statement.
904 *
905 * \param [in] value The return value.
906 *
907 * \return A pointer to a return statement of the desired properties.
908 *
909 * \retval NULL Memory allocation failed.
910 */
createReturnStmtNode(ExprNode * value)911 ReturnStmtNode *createReturnStmtNode(ExprNode *value)
912 {
913 ReturnStmtNode *p = malloc(sizeof(ReturnStmtNode));
914 if (!p) {
915 perror("malloc");
916 return NULL;
917 }
918 p->value = value;
919 return p;
920 }
921
922 /**
923 * Deletes a return statement.
924 *
925 * \param [in,out] node The return statement to delete.
926 *
927 * \post The memory at \a node and all of its members will be freed.
928 */
deleteReturnStmtNode(ReturnStmtNode * node)929 void deleteReturnStmtNode(ReturnStmtNode *node)
930 {
931 if (!node) return;
932 deleteExprNode(node->value);
933 free(node);
934 }
935
936 /**
937 * Creates a loop statement.
938 *
939 * \param [in] name The name of the loop.
940 *
941 * \param [in] var The induction variable.
942 *
943 * \param [in] guard The expression to determine if the loop continues.
944 *
945 * \param [in] update The expression to update \a var using.
946 *
947 * \param [in] body The code block to execute with each loop iteration.
948 *
949 * \return A pointer to a loop statement with the desired properties.
950 *
951 * \retval NULL Memory allocation failed.
952 */
createLoopStmtNode(IdentifierNode * name,IdentifierNode * var,ExprNode * guard,ExprNode * update,BlockNode * body)953 LoopStmtNode *createLoopStmtNode(IdentifierNode *name,
954 IdentifierNode *var,
955 ExprNode *guard,
956 ExprNode *update,
957 BlockNode *body)
958 {
959 LoopStmtNode *p = malloc(sizeof(LoopStmtNode));
960 if (!p) {
961 perror("malloc");
962 return NULL;
963 }
964 p->name = name;
965 p->var = var;
966 p->guard = guard;
967 p->update = update;
968 p->body = body;
969 return p;
970 }
971
972 /**
973 * Deletes a loop statement.
974 *
975 * \param [in,out] node The loop statement to delete.
976 *
977 * \post The memory at \a node and all of its members will be freed.
978 */
deleteLoopStmtNode(LoopStmtNode * node)979 void deleteLoopStmtNode(LoopStmtNode *node)
980 {
981 if (!node) return;
982 deleteIdentifierNode(node->name);
983 deleteIdentifierNode(node->var);
984 deleteExprNode(node->guard);
985 deleteExprNode(node->update);
986 deleteBlockNode(node->body);
987 free(node);
988 }
989
990 /**
991 * Creates a deallocation statement.
992 *
993 * \param [in] target The variable to deallocate.
994 *
995 * \return A pointer to a deallocation statement with the desired properties.
996 *
997 * \retval NULL Memory allocation failed.
998 */
createDeallocationStmtNode(IdentifierNode * target)999 DeallocationStmtNode *createDeallocationStmtNode(IdentifierNode *target)
1000 {
1001 DeallocationStmtNode *p = malloc(sizeof(DeallocationStmtNode));
1002 if (!p) {
1003 perror("malloc");
1004 return NULL;
1005 }
1006 p->target = target;
1007 return p;
1008 }
1009
1010 /**
1011 * Deletes a deallocation statement.
1012 *
1013 * \param [in,out] node The deallocation statement to delete.
1014 *
1015 * \post The memory at \a node and all of its members will be freed.
1016 */
deleteDeallocationStmtNode(DeallocationStmtNode * node)1017 void deleteDeallocationStmtNode(DeallocationStmtNode *node)
1018 {
1019 if (!node) return;
1020 deleteIdentifierNode(node->target);
1021 free(node);
1022 }
1023
1024 /**
1025 * Creates a function definition statement.
1026 *
1027 * \param [in] scope The scope to define the function in.
1028 *
1029 * \param [in] name The name of the function.
1030 *
1031 * \param [in] args The function arguments names.
1032 *
1033 * \param [in] body The function's code block.
1034 *
1035 * \return A pointer to a function definition statement with the desired
1036 * properties.
1037 *
1038 * \retval NULL Memory allocation failed.
1039 */
createFuncDefStmtNode(IdentifierNode * scope,IdentifierNode * name,IdentifierNodeList * args,BlockNode * body)1040 FuncDefStmtNode *createFuncDefStmtNode(IdentifierNode *scope,
1041 IdentifierNode *name,
1042 IdentifierNodeList *args,
1043 BlockNode *body)
1044 {
1045 FuncDefStmtNode *p = malloc(sizeof(FuncDefStmtNode));
1046 if (!p) {
1047 perror("malloc");
1048 return NULL;
1049 }
1050 p->scope = scope;
1051 p->name = name;
1052 p->args = args;
1053 p->body = body;
1054 return p;
1055 }
1056
1057 /**
1058 * Deletes a function definition statement.
1059 *
1060 * \param [in,out] node The function definition statement to delete.
1061 *
1062 * \post The memory at \a node and all of its members will be freed.
1063 */
deleteFuncDefStmtNode(FuncDefStmtNode * node)1064 void deleteFuncDefStmtNode(FuncDefStmtNode *node)
1065 {
1066 if (!node) return;
1067 deleteIdentifierNode(node->scope);
1068 deleteIdentifierNode(node->name);
1069 deleteIdentifierNodeList(node->args);
1070 deleteBlockNode(node->body);
1071 free(node);
1072 }
1073
1074 /**
1075 * Creates an alternate array definition statement.
1076 *
1077 * \param [in] name The name of the array to define.
1078 *
1079 * \param [in] body The body of the array to define.
1080 *
1081 * \param [in] parent The optional parent to inherit from.
1082 *
1083 * \return A pointer to an array definition statement with the desired
1084 * properties.
1085 *
1086 * \retval NULL Memory allocation failed.
1087 */
createAltArrayDefStmtNode(IdentifierNode * name,BlockNode * body,IdentifierNode * parent)1088 AltArrayDefStmtNode *createAltArrayDefStmtNode(IdentifierNode *name,
1089 BlockNode *body,
1090 IdentifierNode *parent)
1091 {
1092 AltArrayDefStmtNode *p = malloc(sizeof(AltArrayDefStmtNode));
1093 if (!p) {
1094 perror("malloc");
1095 return NULL;
1096 }
1097 p->name = name;
1098 p->body = body;
1099 p->parent = parent;
1100 return p;
1101 }
1102
1103 /**
1104 * Deletes an alternate array definition statement.
1105 *
1106 * \param [in,out] node The alternate array definition statement to delete.
1107 *
1108 * \post The memory at \a node and all of its members will be freed.
1109 */
deleteAltArrayDefStmtNode(AltArrayDefStmtNode * node)1110 void deleteAltArrayDefStmtNode(AltArrayDefStmtNode *node)
1111 {
1112 if (!node) return;
1113 deleteIdentifierNode(node->name);
1114 deleteBlockNode(node->body);
1115 free(node);
1116 }
1117
1118 /**
1119 * Creates a library import statement.
1120 *
1121 * \param [in] name The name of the library to import.
1122 *
1123 * \return A pointer to a library import statement with the desired properties.
1124 *
1125 * \retval NULL Memory allocation failed.
1126 */
createImportStmtNode(IdentifierNode * name)1127 ImportStmtNode *createImportStmtNode(IdentifierNode *name)
1128 {
1129 ImportStmtNode *p = malloc(sizeof(ImportStmtNode));
1130 if (!p) {
1131 perror("malloc");
1132 return NULL;
1133 }
1134 p->name = name;
1135 return p;
1136 }
1137
1138 /**
1139 * Deletes a library import statement.
1140 *
1141 * \param [in,out] node The library import statement to delete.
1142 *
1143 * \post The memory at \a node and all of its members will be freed.
1144 */
deleteImportStmtNode(ImportStmtNode * node)1145 void deleteImportStmtNode(ImportStmtNode *node)
1146 {
1147 if (!node) return;
1148 deleteIdentifierNode(node->name);
1149 free(node);
1150 }
1151
1152 /**
1153 * Creates a binding statement.
1154 *
1155 * \param [in] binding A pointer to the function that defines the binding.
1156 *
1157 * \return A pointer to a binding statement with the desired properties.
1158 *
1159 * \retval NULL Memory allocation failed.
1160 */
createBindingStmtNode(struct returnobject * (* binding)(struct scopeobject *))1161 BindingStmtNode *createBindingStmtNode(struct returnobject *(*binding)(struct scopeobject *))
1162 {
1163 BindingStmtNode *p = malloc(sizeof(BindingStmtNode));
1164 if (!p) {
1165 perror("malloc");
1166 return NULL;
1167 }
1168 p->binding = binding;
1169 return p;
1170 }
1171
1172 /**
1173 * Deletes a binding statement.
1174 *
1175 * \param [in,out] node The binding statement to delete.
1176 *
1177 * \post The memory at \a node and all of its members will be freed.
1178 */
deleteBindingStmtNode(BindingStmtNode * node)1179 void deleteBindingStmtNode(BindingStmtNode *node)
1180 {
1181 if (!node) return;
1182 free(node);
1183 }
1184
1185 /**
1186 * Creates an expression.
1187 *
1188 * \param [in] type The type of expression.
1189 *
1190 * \param [in] expr The expression data.
1191 *
1192 * \return A pointer to an expression with the desired properties.
1193 *
1194 * \retval NULL Memory allocation failed.
1195 */
createExprNode(ExprType type,void * expr)1196 ExprNode *createExprNode(ExprType type,
1197 void *expr)
1198 {
1199 ExprNode *p = malloc(sizeof(ExprNode));
1200 if (!p) {
1201 perror("malloc");
1202 return NULL;
1203 }
1204 p->type = type;
1205 p->expr = expr;
1206 return p;
1207 }
1208
1209 /**
1210 * Deletes an expression.
1211 *
1212 * \param [in,out] node The expression to delete.
1213 *
1214 * \post The memory at \a node and all of its members will be freed.
1215 */
deleteExprNode(ExprNode * node)1216 void deleteExprNode(ExprNode *node)
1217 {
1218 if (!node) return;
1219 switch (node->type) {
1220 case ET_CAST:
1221 deleteCastExprNode((CastExprNode *)node->expr);
1222 break;
1223 case ET_CONSTANT:
1224 deleteConstantNode((ConstantNode *)node->expr);
1225 break;
1226 case ET_IDENTIFIER:
1227 deleteIdentifierNode((IdentifierNode *)node->expr);
1228 break;
1229 case ET_FUNCCALL:
1230 deleteFuncCallExprNode((FuncCallExprNode *)node->expr);
1231 break;
1232 case ET_OP:
1233 deleteOpExprNode((OpExprNode *)node->expr);
1234 break;
1235 case ET_IMPVAR:
1236 break; /* This expression type does not have any content */
1237 case ET_SYSTEMCOMMAND:
1238 deleteSystemCommandExprNode((SystemCommandExprNode *)node->expr);
1239 break;
1240 default:
1241 error(PR_UNKNOWN_EXPRESSION_TYPE);
1242 break;
1243 }
1244 free(node);
1245 }
1246
1247 /**
1248 * Creates an empty expression list.
1249 *
1250 * \return A pointer to an empty expression list.
1251 *
1252 * \retval NULL Memory allocation failed.
1253 */
createExprNodeList(void)1254 ExprNodeList *createExprNodeList(void)
1255 {
1256 ExprNodeList *p = malloc(sizeof(ExprNodeList));
1257 if (!p) {
1258 perror("malloc");
1259 return NULL;
1260 }
1261 p->num = 0;
1262 p->exprs = NULL;
1263 return p;
1264 }
1265
1266 /**
1267 * Adds an expression to a list.
1268 *
1269 * \param [in,out] list The expression list to add \a node to.
1270 *
1271 * \param [in] node The expression to add to \a list.
1272 *
1273 * \post \a node will be added to \a list and its size will be updated.
1274 *
1275 * \retval 0 Memory allocation failed.
1276 *
1277 * \retval 1 \a node was added to \a list.
1278 */
addExprNode(ExprNodeList * list,ExprNode * node)1279 int addExprNode(ExprNodeList *list,
1280 ExprNode *node)
1281 {
1282 unsigned int newsize = list->num + 1;
1283 void *mem = realloc(list->exprs, sizeof(ExprNode *) * newsize);
1284 if (!mem) {
1285 perror("realloc");
1286 return 0;
1287 }
1288 list->exprs = mem;
1289 list->exprs[list->num] = node;
1290 list->num = newsize;
1291 return 1;
1292 }
1293
1294 /**
1295 * Deletes an expression list.
1296 *
1297 * \param [in,out] list The expression list to delete.
1298 *
1299 * \post The memory at \a list and all of its members will be freed.
1300 */
deleteExprNodeList(ExprNodeList * list)1301 void deleteExprNodeList(ExprNodeList *list)
1302 {
1303 unsigned int n;
1304 if (!list) return;
1305 for (n = 0; n < list->num; n++)
1306 deleteExprNode(list->exprs[n]);
1307 free(list->exprs);
1308 free(list);
1309 }
1310
1311 /**
1312 * Creates a cast expression.
1313 *
1314 * \param [in] target The expression to cast.
1315 *
1316 * \param [in] newtype The type to cast \a target to.
1317 *
1318 * \return A pointer to a cast expression with the desired properties.
1319 *
1320 * \retval NULL Memory allocation failed.
1321 */
createCastExprNode(ExprNode * target,TypeNode * newtype)1322 CastExprNode *createCastExprNode(ExprNode *target,
1323 TypeNode *newtype)
1324 {
1325 CastExprNode *p = malloc(sizeof(CastExprNode));
1326 if (!p) {
1327 perror("malloc");
1328 return NULL;
1329 }
1330 p->target = target;
1331 p->newtype = newtype;
1332 return p;
1333 }
1334
1335 /**
1336 * Deletes a cast expression.
1337 *
1338 * \param [in,out] node The cast expression to delete.
1339 *
1340 * \post The memory at \a node and all of its members will be freed.
1341 */
deleteCastExprNode(CastExprNode * node)1342 void deleteCastExprNode(CastExprNode *node)
1343 {
1344 if (!node) return;
1345 deleteExprNode(node->target);
1346 deleteTypeNode(node->newtype);
1347 free(node);
1348 }
1349
1350 /**
1351 * Creates a function call expression.
1352 *
1353 * \param [in] scope The scope to lookup the function in.
1354 *
1355 * \param [in] name The name of the function.
1356 *
1357 * \param [in] args The arguments to supply the function.
1358 *
1359 * \return A pointer to a function call expression with the desired properties.
1360 *
1361 * \retval NULL Memory allocation failed.
1362 */
createFuncCallExprNode(IdentifierNode * scope,IdentifierNode * name,ExprNodeList * args)1363 FuncCallExprNode *createFuncCallExprNode(IdentifierNode *scope,
1364 IdentifierNode *name,
1365 ExprNodeList *args)
1366 {
1367 FuncCallExprNode *p = malloc(sizeof(FuncCallExprNode));
1368 if (!p) {
1369 perror("malloc");
1370 return NULL;
1371 }
1372 p->scope = scope;
1373 p->name = name;
1374 p->args = args;
1375 return p;
1376 }
1377
1378 /**
1379 * Creates a system command expression.
1380 *
1381 * \param [in] cmd The command to execute.
1382 *
1383 * \return A pointer to a system command expression with the desired properties.
1384 *
1385 * \retval NULL Memory allocation failed.
1386 */
createSystemCommandExprNode(ExprNode * cmd)1387 SystemCommandExprNode *createSystemCommandExprNode(ExprNode *cmd)
1388 {
1389 SystemCommandExprNode *p = malloc(sizeof(SystemCommandExprNode));
1390 if (!p) {
1391 perror("malloc");
1392 return NULL;
1393 }
1394 p->cmd = cmd;
1395 return p;
1396 }
1397
1398 /**
1399 * Deletes a function call expression.
1400 *
1401 * \param [in,out] node The function call expression to delete.
1402 *
1403 * \post The memory at \a node and all of its members will be freed.
1404 */
deleteFuncCallExprNode(FuncCallExprNode * node)1405 void deleteFuncCallExprNode(FuncCallExprNode *node)
1406 {
1407 if (!node) return;
1408 deleteIdentifierNode(node->scope);
1409 deleteIdentifierNode(node->name);
1410 deleteExprNodeList(node->args);
1411 free(node);
1412 }
1413
1414 /**
1415 * Deletes a system command expression.
1416 *
1417 * \param [in,out] node The system command expression to delete.
1418 *
1419 * \post The memory at \a node and all of its members will be freed.
1420 */
deleteSystemCommandExprNode(SystemCommandExprNode * node)1421 void deleteSystemCommandExprNode(SystemCommandExprNode *node)
1422 {
1423 if (!node) return;
1424 deleteExprNode(node->cmd);
1425 free(node);
1426 }
1427
1428 /**
1429 * Creates an operation expression.
1430 *
1431 * \param [in] type The type of operation to perform.
1432 *
1433 * \param [in] args The operands.
1434 *
1435 * \return A pointer to an operation expression with the desired properties.
1436 *
1437 * \retval NULL Memroy allocation failed.
1438 */
createOpExprNode(OpType type,ExprNodeList * args)1439 OpExprNode *createOpExprNode(OpType type,
1440 ExprNodeList *args)
1441 {
1442 OpExprNode *p = malloc(sizeof(OpExprNode));
1443 if (!p) {
1444 perror("malloc");
1445 return NULL;
1446 }
1447 p->type = type;
1448 p->args = args;
1449 return p;
1450 }
1451
1452 /**
1453 * Deletes an operation expression.
1454 *
1455 * \param [in,out] node The operation expression to delete.
1456 *
1457 * \post The memory at \a node and all of its members will be freed.
1458 */
deleteOpExprNode(OpExprNode * node)1459 void deleteOpExprNode(OpExprNode *node)
1460 {
1461 if (!node) return;
1462 deleteExprNodeList(node->args);
1463 free(node);
1464 }
1465
1466 /**
1467 * Checks if a type of token is at a position in a token list, and if so,
1468 * advances the position.
1469 *
1470 * \param [in,out] tokenp The position in a token list to check.
1471 *
1472 * \param [in] token The type of token to check for.
1473 *
1474 * \post If the type of \a tokenp is not \a token, \a tokenp will remain
1475 * unchanged, else, it will point to the token after the one matched.
1476 *
1477 * \retval 0 The type of \a tokenp is \a token.
1478 *
1479 * \retval 1 The type of \a tokenp is not \a token.
1480 */
acceptToken(Token *** tokenp,TokenType token)1481 int acceptToken(Token ***tokenp,
1482 TokenType token)
1483 {
1484 Token **tokens = *tokenp;
1485 if ((*tokens)->type != token) return 0;
1486 tokens++;
1487 *tokenp = tokens;
1488 return 1;
1489 }
1490
1491 /**
1492 * Checks if a type of token is at a position in a token list.
1493 *
1494 * \param [in] tokenp The position in a token list to check.
1495 *
1496 * \param [in] token The type of token to check for.
1497 *
1498 * \post \a tokenp will remain unchanged.
1499 *
1500 * \retval 0 The type of \a tokenp is \a token.
1501 *
1502 * \retval 1 The type of \a tokenp is not \a token.
1503 */
peekToken(Token *** tokenp,TokenType token)1504 int peekToken(Token ***tokenp,
1505 TokenType token)
1506 {
1507 Token **tokens = *tokenp;
1508 if ((*tokens)->type != token) return 0;
1509 return 1;
1510 }
1511
1512 /**
1513 * Checks if a type of token is after a position in a token list.
1514 *
1515 * \param [in] tokenp The position in a token list to check after.
1516 *
1517 * \param [in] token The type of token to check for.
1518 *
1519 * \post \a tokenp will remain unchanged.
1520 *
1521 * \retval 0 The type of the token after \a tokenp is \a token.
1522 *
1523 * \retval 1 The type of the token after \a tokenp is not \a token.
1524 */
nextToken(Token *** tokenp,TokenType token)1525 int nextToken(Token ***tokenp,
1526 TokenType token)
1527 {
1528 Token **tokens = *tokenp;
1529 if ((*(tokens + 1))->type != token) return 0;
1530 return 1;
1531 }
1532
1533 /**
1534 * A simple wrapper around the global error printing function tailored to
1535 * general parser errors.
1536 *
1537 * \param [in] type The type of error.
1538 *
1539 * \param [in] tokens The tokens being parsed when the error occurred.
1540 */
parser_error(ErrorType type,Token ** tokens)1541 void parser_error(ErrorType type,
1542 Token **tokens)
1543 {
1544 error(type, (*tokens)->fname, (*tokens)->line, (*tokens)->image);
1545 }
1546
1547 /**
1548 * A simple wrapper around the global error printing function tailored to
1549 * expected token parser errors.
1550 *
1551 * \param [in] token The expected token's image.
1552 *
1553 * \param [in] tokens The tokens being parsed when the error occurred.
1554 */
parser_error_expected_token(TokenType token,Token ** tokens)1555 void parser_error_expected_token(TokenType token,
1556 Token **tokens)
1557 {
1558 error(PR_EXPECTED_TOKEN,
1559 (*tokens)->fname,
1560 (*tokens)->line,
1561 keywords[token],
1562 (*tokens)->image);
1563 }
1564
1565 /**
1566 * A simple wrapper around the global error printing function tailored to
1567 * expected two token parser errors.
1568 *
1569 * \param [in] token1 The first expected token's image.
1570 *
1571 * \param [in] token2 The second expected token's image.
1572 *
1573 * \param [in] tokens The tokens being parsed when the error occurred.
1574 */
parser_error_expected_either_token(TokenType token1,TokenType token2,Token ** tokens)1575 void parser_error_expected_either_token(TokenType token1,
1576 TokenType token2,
1577 Token **tokens)
1578 {
1579 error(PR_EXPECTED_TOKEN,
1580 (*tokens)->fname,
1581 (*tokens)->line,
1582 keywords[token1],
1583 keywords[token2],
1584 (*tokens)->image);
1585 }
1586
1587 /**
1588 * Parses tokens into a constant.
1589 *
1590 * \param [in] tokenp The position in a token list to start parsing at.
1591 *
1592 * \post \a tokenp will point to the next unparsed token.
1593 *
1594 * \return A pointer to a constant.
1595 *
1596 * \retval NULL Unable to parse.
1597 */
parseConstantNode(Token *** tokenp)1598 ConstantNode *parseConstantNode(Token ***tokenp)
1599 {
1600 ConstantNode *ret = NULL;
1601 char *data = NULL;
1602 int status;
1603
1604 /* Work from a copy of the token stream in case something goes wrong */
1605 Token **tokens = *tokenp;
1606
1607 #ifdef DEBUG
1608 shiftout();
1609 #endif
1610
1611 /* Boolean */
1612 if (peekToken(&tokens, TT_BOOLEAN)) {
1613 #ifdef DEBUG
1614 debug("CT_BOOLEAN");
1615 #endif
1616 /* Create the ConstantNode structure */
1617 ret = createBooleanConstantNode((*tokens)->data.i);
1618 if (!ret) goto parseConstantNodeAbort;
1619
1620 /* This should succeed; it was checked for above */
1621 status = acceptToken(&tokens, TT_BOOLEAN);
1622 if (!status) {
1623 parser_error(PR_EXPECTED_BOOLEAN, tokens);
1624 goto parseConstantNodeAbort;
1625 }
1626 }
1627 /* Integer */
1628 else if (peekToken(&tokens, TT_INTEGER)) {
1629 #ifdef DEBUG
1630 debug("CT_INTEGER");
1631 #endif
1632 /* Create the ConstantNode structure */
1633 ret = createIntegerConstantNode((*tokens)->data.i);
1634 if (!ret) goto parseConstantNodeAbort;
1635
1636 /* This should succeed; it was checked for above */
1637 status = acceptToken(&tokens, TT_INTEGER);
1638 if (!status) {
1639 parser_error(PR_EXPECTED_INTEGER, tokens);
1640 goto parseConstantNodeAbort;
1641 }
1642 }
1643 /* Float */
1644 else if (peekToken(&tokens, TT_FLOAT)) {
1645 #ifdef DEBUG
1646 debug("CT_FLOAT");
1647 #endif
1648 /* Create the ConstantNode structure */
1649 ret = createFloatConstantNode((*tokens)->data.f);
1650 if (!ret) goto parseConstantNodeAbort;
1651
1652 /* This should succeed; it was checked for above */
1653 status = acceptToken(&tokens, TT_FLOAT);
1654 if (!status) {
1655 parser_error(PR_EXPECTED_FLOAT, tokens);
1656 goto parseConstantNodeAbort;
1657 }
1658 }
1659 /* String */
1660 else if (peekToken(&tokens, TT_STRING)) {
1661 size_t len = strlen((*tokens)->image);
1662 data = malloc(sizeof(char) * (len - 1));
1663 if (!data) {
1664 perror("malloc");
1665 goto parseConstantNodeAbort;
1666 }
1667 strncpy(data, (*tokens)->image + 1, len - 2);
1668 data[len - 2] = '\0';
1669 #ifdef DEBUG
1670 debug("CT_STRING");
1671 #endif
1672 /* Create the ConstantNode structure */
1673 ret = createStringConstantNode(data);
1674 if (!ret) goto parseConstantNodeAbort;
1675 data = NULL;
1676
1677 /* This should succeed; it was checked for above */
1678 status = acceptToken(&tokens, TT_STRING);
1679 if (!status) {
1680 parser_error(PR_EXPECTED_STRING, tokens);
1681 goto parseConstantNodeAbort;
1682 }
1683 }
1684 else {
1685 parser_error(PR_EXPECTED_CONSTANT, tokens);
1686 }
1687
1688 #ifdef DEBUG
1689 shiftin();
1690 #endif
1691
1692 /* Since we're successful, update the token stream */
1693 *tokenp = tokens;
1694
1695 return ret;
1696
1697 parseConstantNodeAbort: /* Exception handling */
1698
1699 /* Clean up any allocated structures */
1700 if (data) free(data);
1701 if (ret) deleteConstantNode(ret);
1702
1703 return NULL;
1704 }
1705
1706 /**
1707 * Parses tokens into a type.
1708 *
1709 * \param [in] tokenp The position in a token list to start parsing at.
1710 *
1711 * \post \a tokenp will point to the next unparsed token.
1712 *
1713 * \return A pointer to a type.
1714 *
1715 * \retval NULL Unable to parse.
1716 */
parseTypeNode(Token *** tokenp)1717 TypeNode *parseTypeNode(Token ***tokenp)
1718 {
1719 TypeNode *ret = NULL;
1720
1721 /* Work from a copy of the token stream in case something goes wrong */
1722 Token **tokens = *tokenp;
1723
1724 #ifdef DEBUG
1725 shiftout();
1726 #endif
1727
1728 /* Nil */
1729 if (acceptToken(&tokens, TT_NOOB)) {
1730 #ifdef DEBUG
1731 debug("CT_NIL");
1732 #endif
1733 ret = createTypeNode(CT_NIL);
1734 if (!ret) goto parseTypeNodeAbort;
1735 }
1736 /* Boolean */
1737 else if (acceptToken(&tokens, TT_TROOF)) {
1738 #ifdef DEBUG
1739 debug("CT_BOOLEAN");
1740 #endif
1741 ret = createTypeNode(CT_BOOLEAN);
1742 if (!ret) goto parseTypeNodeAbort;
1743 }
1744 /* Integer */
1745 else if (acceptToken(&tokens, TT_NUMBR)) {
1746 #ifdef DEBUG
1747 debug("CT_INTEGER");
1748 #endif
1749 ret = createTypeNode(CT_INTEGER);
1750 if (!ret) goto parseTypeNodeAbort;
1751 }
1752 /* Float */
1753 else if (acceptToken(&tokens, TT_NUMBAR)) {
1754 #ifdef DEBUG
1755 debug("CT_FLOAT");
1756 #endif
1757 ret = createTypeNode(CT_FLOAT);
1758 if (!ret) goto parseTypeNodeAbort;
1759 }
1760 /* String */
1761 else if (acceptToken(&tokens, TT_YARN)) {
1762 #ifdef DEBUG
1763 debug("CT_STRING");
1764 #endif
1765 ret = createTypeNode(CT_STRING);
1766 if (!ret) goto parseTypeNodeAbort;
1767 }
1768 /* Associative array */
1769 else if (acceptToken(&tokens, TT_BUKKIT)) {
1770 #ifdef DEBUG
1771 debug("CT_ARRAY");
1772 #endif
1773 ret = createTypeNode(CT_ARRAY);
1774 if (!ret) goto parseTypeNodeAbort;
1775 }
1776 else {
1777 parser_error(PR_EXPECTED_TYPE, tokens);
1778 }
1779
1780 #ifdef DEBUG
1781 shiftin();
1782 #endif
1783
1784 /* Since we're successful, update the token stream */
1785 *tokenp = tokens;
1786
1787 return ret;
1788
1789 parseTypeNodeAbort: /* Exception handling */
1790
1791 /* Clean up any allocated structures */
1792 if (ret) deleteTypeNode(ret);
1793
1794 return NULL;
1795 }
1796
1797 /**
1798 * Parses tokens into an identifier.
1799 *
1800 * \param [in] tokenp The position in a token list to start parsing at.
1801 *
1802 * \post \a tokenp will point to the next unparsed token.
1803 *
1804 * \return A pointer to an identifier.
1805 *
1806 * \retval NULL Unable to parse.
1807 */
parseIdentifierNode(Token *** tokenp)1808 IdentifierNode *parseIdentifierNode(Token ***tokenp)
1809 {
1810 IdentifierType type;
1811 void *data = NULL;
1812 IdentifierNode *slot = NULL;
1813 const char *fname = NULL;
1814 unsigned int line;
1815
1816 /* For direct identifier */
1817 char *temp = NULL;
1818
1819 /* For indirect identifier */
1820 ExprNode *expr = NULL;
1821
1822 IdentifierNode *ret = NULL;
1823 int status;
1824
1825 /* Work from a copy of the token stream in case something goes wrong */
1826 Token **tokens = *tokenp;
1827
1828 #ifdef DEBUG
1829 shiftout();
1830 #endif
1831
1832 fname = (*tokens)->fname;
1833 line = (*tokens)->line;
1834
1835 /* Direct identifier */
1836 if (peekToken(&tokens, TT_IDENTIFIER)) {
1837 type = IT_DIRECT;
1838 #ifdef DEBUG
1839 debug("IT_DIRECT");
1840 #endif
1841 /* Copy the token image */
1842 temp = malloc(sizeof(char) * (strlen((*tokens)->image) + 1));
1843 if (!temp) goto parseIdentifierNodeAbort;
1844 strcpy(temp, (*tokens)->image);
1845 data = temp;
1846
1847 /* This should succeed; it was checked for above */
1848 status = acceptToken(&tokens, TT_IDENTIFIER);
1849 if (!status) {
1850 parser_error(PR_EXPECTED_IDENTIFIER, tokens);
1851 goto parseIdentifierNodeAbort;
1852 }
1853 }
1854 else if (acceptToken(&tokens, TT_SRS)) {
1855 type = IT_INDIRECT;
1856 #ifdef DEBUG
1857 debug("IT_INDIRECT");
1858 #endif
1859 /* Parse the expression representing the identifier */
1860 expr = parseExprNode(&tokens);
1861 if (!expr) goto parseIdentifierNodeAbort;
1862 data = expr;
1863 }
1864 else {
1865 parser_error(PR_EXPECTED_IDENTIFIER, tokens);
1866 }
1867
1868 /* Check if there is a slot access */
1869 if (acceptToken(&tokens, TT_APOSTROPHEZ)) {
1870 slot = parseIdentifierNode(&tokens);
1871 if (!slot) goto parseIdentifierNodeAbort;
1872 }
1873
1874 #ifdef DEBUG
1875 shiftin();
1876 #endif
1877
1878 /* Create the new IdentifierNode structure */
1879 ret = createIdentifierNode(type, data, slot, fname, line);
1880 if (!ret) goto parseIdentifierNodeAbort;
1881
1882 /* Since we're successful, update the token stream */
1883 *tokenp = tokens;
1884
1885 return ret;
1886
1887 parseIdentifierNodeAbort: /* Exception handling */
1888
1889 /* Clean up any allocated structures */
1890 if (ret) deleteIdentifierNode(ret);
1891 else {
1892 /* For indirect identifier */
1893 if (expr) deleteExprNode(expr);
1894
1895 /* For direct identifier */
1896 if (temp) free(temp);
1897
1898 if (slot) deleteIdentifierNode(slot);
1899 }
1900
1901 return NULL;
1902 }
1903
1904 /**
1905 * Parses tokens into a cast expression.
1906 *
1907 * \param [in] tokenp The position in a token list to start parsing at.
1908 *
1909 * \post \a tokenp will point to the next unparsed token.
1910 *
1911 * \return A pointer to a cast expression.
1912 *
1913 * \retval NULL Unable to parse.
1914 */
parseCastExprNode(Token *** tokenp)1915 ExprNode *parseCastExprNode(Token ***tokenp)
1916 {
1917 ExprNode *target = NULL;
1918 TypeNode *newtype = NULL;
1919 CastExprNode *expr = NULL;
1920 ExprNode *ret = NULL;
1921 int status;
1922
1923 /* Work from a copy of the token stream in case something goes wrong */
1924 Token **tokens = *tokenp;
1925
1926 #ifdef DEBUG
1927 debug("ET_CAST");
1928 #endif
1929
1930 /* Parse the cast token */
1931 status = acceptToken(&tokens, TT_MAEK);
1932 if (!status) {
1933 parser_error_expected_token(TT_MAEK, tokens);
1934 goto parseCastExprNodeAbort;
1935 }
1936
1937 /* Parse the expression to cast */
1938 target = parseExprNode(&tokens);
1939 if (!target) goto parseCastExprNodeAbort;
1940
1941 /* Optionally parse the cast-to token */
1942 status = acceptToken(&tokens, TT_A);
1943
1944 /* Parse the type to cast to */
1945 newtype = parseTypeNode(&tokens);
1946 if (!newtype) goto parseCastExprNodeAbort;
1947
1948 /* Create the new CastExprNode structure */
1949 expr = createCastExprNode(target, newtype);
1950 if (!expr) goto parseCastExprNodeAbort;
1951
1952 /* Create the new ExprNode structure */
1953 ret = createExprNode(ET_CAST, expr);
1954 if (!ret) goto parseCastExprNodeAbort;
1955
1956 /* Since we're successful, update the token stream */
1957 *tokenp = tokens;
1958
1959 return ret;
1960
1961 parseCastExprNodeAbort: /* Exception handling */
1962
1963 /* Clean up any allocated structures */
1964 if (ret) deleteExprNode(ret);
1965 else if (expr) deleteCastExprNode(expr);
1966 else {
1967 if (newtype) deleteTypeNode(newtype);
1968 if (target) deleteExprNode(target);
1969 }
1970
1971 return NULL;
1972 }
1973
1974 /**
1975 * Parses tokens into a constant expression.
1976 *
1977 * \param [in] tokenp The position in a token list to start parsing at.
1978 *
1979 * \post \a tokenp will point to the next unparsed token.
1980 *
1981 * \return A pointer to a constant expression.
1982 *
1983 * \retval NULL Unable to parse.
1984 */
parseConstantExprNode(Token *** tokenp)1985 ExprNode *parseConstantExprNode(Token ***tokenp)
1986 {
1987 ConstantNode *node = NULL;
1988 ExprNode *ret = NULL;
1989
1990 /* Work from a copy of the token stream in case something goes wrong */
1991 Token **tokens = *tokenp;
1992
1993 #ifdef DEBUG
1994 debug("ET_CONSTANT");
1995 #endif
1996
1997 /* Parse the constant */
1998 node = parseConstantNode(&tokens);
1999 if (!node) goto parseConstantExprNodeAbort;
2000
2001 /* Create the new ExprNode structure */
2002 ret = createExprNode(ET_CONSTANT, node);
2003 if (!ret) goto parseConstantExprNodeAbort;
2004
2005 /* Since we're successful, update the token stream */
2006 *tokenp = tokens;
2007
2008 return ret;
2009
2010 parseConstantExprNodeAbort: /* Exception handling */
2011
2012 /* Clean up any allocated structures */
2013 if (ret) deleteExprNode(ret);
2014 else {
2015 if (node) deleteConstantNode(node);
2016 }
2017
2018 return NULL;
2019 }
2020
2021 /**
2022 * Parses tokens into an identifier expression.
2023 *
2024 * \param [in] tokenp The position in a token list to start parsing at.
2025 *
2026 * \post \a tokenp will point to the next unparsed token.
2027 *
2028 * \return A pointer to an identifier expression.
2029 *
2030 * \retval NULL Unable to parse.
2031 */
parseIdentifierExprNode(Token *** tokenp)2032 ExprNode *parseIdentifierExprNode(Token ***tokenp)
2033 {
2034 IdentifierNode *node = NULL;
2035 ExprNode *ret = NULL;
2036
2037 /* Work from a copy of the token stream in case something goes wrong */
2038 Token **tokens = *tokenp;
2039
2040 #ifdef DEBUG
2041 debug("ET_IDENTIFIER");
2042 #endif
2043
2044 /* Parse the identifier node */
2045 node = parseIdentifierNode(&tokens);
2046 if (!node) goto parseIdentifierExprNodeAbort;
2047
2048 /* Create the new ExprNode structure */
2049 ret = createExprNode(ET_IDENTIFIER, node);
2050 if (!ret) goto parseIdentifierExprNodeAbort;
2051
2052 /* Since we're successful, update the token stream */
2053 *tokenp = tokens;
2054
2055 return ret;
2056
2057 parseIdentifierExprNodeAbort: /* Exception handling */
2058
2059 /* Clean up any allocated structures */
2060 if (ret) deleteExprNode(ret);
2061 else {
2062 if (node) deleteIdentifierNode(node);
2063 }
2064
2065 return NULL;
2066 }
2067
2068 /**
2069 * Parses tokens into a function call expression.
2070 *
2071 * \param [in] tokenp The position in a token list to start parsing at.
2072 *
2073 * \post \a Tokenp will point to the next unparsed token.
2074 *
2075 * \return A pointer to a function call expression.
2076 *
2077 * \retval NULL Unable to parse.
2078 */
parseFuncCallExprNode(Token *** tokenp)2079 ExprNode *parseFuncCallExprNode(Token ***tokenp)
2080 {
2081 IdentifierNode *scope = NULL;
2082 IdentifierNode *name = NULL;
2083 ExprNodeList *args = NULL;
2084 ExprNode *arg = NULL;
2085 FuncCallExprNode *expr = NULL;
2086 ExprNode *ret = NULL;
2087 int status;
2088
2089 /* Work from a copy of the token stream in case something goes wrong */
2090 Token **tokens = *tokenp;
2091
2092 #ifdef DEBUG
2093 debug("ET_FUNCCALL");
2094 #endif
2095
2096 /* Parse the scope name */
2097 scope = parseIdentifierNode(&tokens);
2098 if (!scope) goto parseFuncCallExprNodeAbort;
2099
2100 /* Parse the function call token */
2101 status = acceptToken(&tokens, TT_IZ);
2102 if (!status) {
2103 parser_error_expected_token(TT_IZ, tokens);
2104 goto parseFuncCallExprNodeAbort;
2105 }
2106
2107 /* Parse the function name */
2108 name = parseIdentifierNode(&tokens);
2109 if (!name) goto parseFuncCallExprNodeAbort;
2110
2111 /* Create an argument list */
2112 args = createExprNodeList();
2113 if (!args) goto parseFuncCallExprNodeAbort;
2114
2115 /* Parse the first argument token */
2116 if (acceptToken(&tokens, TT_YR)) {
2117 /* Parse the first argument */
2118 arg = parseExprNode(&tokens);
2119 if (!arg) goto parseFuncCallExprNodeAbort;
2120
2121 /* Add the first argument to the argument list */
2122 status = addExprNode(args, arg);
2123 if (!status) goto parseFuncCallExprNodeAbort;
2124 arg = NULL;
2125
2126 /* Parse additional arguments */
2127 while (acceptToken(&tokens, TT_ANYR)) {
2128 /* Parse the argument */
2129 arg = parseExprNode(&tokens);
2130 if (!arg) goto parseFuncCallExprNodeAbort;
2131
2132 /* Add the argument to the argument list */
2133 status = addExprNode(args, arg);
2134 if (!status) goto parseFuncCallExprNodeAbort;
2135 arg = NULL;
2136 }
2137 }
2138
2139 /* Parse the end-of-argument token */
2140 status = acceptToken(&tokens, TT_MKAY);
2141 if (!status) {
2142 parser_error_expected_token(TT_MKAY, tokens);
2143 goto parseFuncCallExprNodeAbort;
2144 }
2145
2146 /* Create the new FuncCallExprNode structure */
2147 expr = createFuncCallExprNode(scope, name, args);
2148 if (!expr) goto parseFuncCallExprNodeAbort;
2149
2150 /* Create the new ExprNode structure */
2151 ret = createExprNode(ET_FUNCCALL, expr);
2152 if (!ret) goto parseFuncCallExprNodeAbort;
2153
2154 /* Since we're successful, update the token stream */
2155 *tokenp = tokens;
2156
2157 return ret;
2158
2159 parseFuncCallExprNodeAbort: /* Exception handling */
2160
2161 /* Clean up any allocated structures */
2162 if (ret) deleteExprNode(ret);
2163 else if (expr) deleteFuncCallExprNode(expr);
2164 else {
2165 if (args) deleteExprNodeList(args);
2166 if (arg) deleteExprNode(arg);
2167 if (name) deleteIdentifierNode(name);
2168 if (scope) deleteIdentifierNode(scope);
2169 }
2170
2171 return NULL;
2172 }
2173
2174 /**
2175 * Parses tokens into a system command expression.
2176 *
2177 * \param [in] tokenp The position in a token list to start parsing at.
2178 *
2179 * \post \a Tokenp will point to the next unparsed token.
2180 *
2181 * \return A pointer to a system command expression.
2182 *
2183 * \retval NULL Unable to parse.
2184 */
parseSystemCommandExprNode(Token *** tokenp)2185 ExprNode *parseSystemCommandExprNode(Token ***tokenp)
2186 {
2187 ExprNode *name = NULL;
2188 SystemCommandExprNode *expr = NULL;
2189 ExprNode *ret = NULL;
2190 int status;
2191
2192 /* Work from a copy of the token stream in case something goes wrong */
2193 Token **tokens = *tokenp;
2194
2195 #ifdef DEBUG
2196 debug("ET_SYSTEMCOMMAND");
2197 #endif
2198
2199 /* Parse the system command token */
2200 status = acceptToken(&tokens, TT_IDUZ);
2201 if (!status) {
2202 parser_error_expected_token(TT_IDUZ, tokens);
2203 goto parseSystemCommandExprNodeAbort;
2204 }
2205
2206 /* Parse the expression name */
2207 name = parseExprNode(&tokens);
2208 if (!name) goto parseSystemCommandExprNodeAbort;
2209
2210 /* Create the new SystemCommandExprNode structure */
2211 expr = createSystemCommandExprNode(name);
2212 if (!expr) goto parseSystemCommandExprNodeAbort;
2213
2214 /* Create the new ExprNode structure */
2215 ret = createExprNode(ET_SYSTEMCOMMAND, expr);
2216 if (!ret) goto parseSystemCommandExprNodeAbort;
2217
2218 /* Since we're successful, update the token stream */
2219 *tokenp = tokens;
2220
2221 return ret;
2222
2223 parseSystemCommandExprNodeAbort: /* Exception handling */
2224
2225 /* Clean up any allocated structures */
2226 if (ret) deleteExprNode(ret);
2227 else if (expr) deleteSystemCommandExprNode(expr);
2228 else if (name) deleteExprNode(name);
2229
2230 return NULL;
2231 }
2232
2233 /**
2234 * Parses tokens into an operation expression.
2235 *
2236 * \param [in] tokenp The position in a token list to start parsing at.
2237 *
2238 * \post \a tokenp will point to the next unparsed token.
2239 *
2240 * \return A pointer to a operation expression.
2241 *
2242 * \retval NULL Unable to parse.
2243 */
parseOpExprNode(Token *** tokenp)2244 ExprNode *parseOpExprNode(Token ***tokenp)
2245 {
2246 enum ArityType {
2247 AT_UNARY,
2248 AT_BINARY,
2249 AT_NARY
2250 };
2251 enum ArityType arity;
2252 ExprNodeList *args = NULL;
2253 ExprNode *arg = NULL;
2254 OpExprNode *expr = NULL;
2255 OpType type;
2256 ExprNode *ret = NULL;
2257 int status;
2258
2259 /* Work from a copy of the token stream in case something goes wrong */
2260 Token **tokens = *tokenp;
2261
2262 /* Unary operations */
2263 if (acceptToken(&tokens, TT_NOT)) {
2264 type = OP_NOT;
2265 arity = AT_UNARY;
2266 #ifdef DEBUG
2267 debug("ET_OP (OP_NOT)");
2268 #endif
2269 }
2270 /* Binary operations */
2271 else if (acceptToken(&tokens, TT_SUMOF)) {
2272 type = OP_ADD;
2273 arity = AT_BINARY;
2274 #ifdef DEBUG
2275 debug("ET_OP (OP_ADD)");
2276 #endif
2277 }
2278 else if(acceptToken(&tokens, TT_DIFFOF)) {
2279 type = OP_SUB;
2280 arity = AT_BINARY;
2281 #ifdef DEBUG
2282 debug("ET_OP (OP_SUB)");
2283 #endif
2284 }
2285 else if(acceptToken(&tokens, TT_PRODUKTOF)) {
2286 type = OP_MULT;
2287 arity = AT_BINARY;
2288 #ifdef DEBUG
2289 debug("ET_OP (OP_MULT)");
2290 #endif
2291 }
2292 else if(acceptToken(&tokens, TT_QUOSHUNTOF)) {
2293 type = OP_DIV;
2294 arity = AT_BINARY;
2295 #ifdef DEBUG
2296 debug("ET_OP (OP_DIV)");
2297 #endif
2298 }
2299 else if(acceptToken(&tokens, TT_MODOF)) {
2300 type = OP_MOD;
2301 arity = AT_BINARY;
2302 #ifdef DEBUG
2303 debug("ET_OP (OP_MOD)");
2304 #endif
2305 }
2306 else if(acceptToken(&tokens, TT_BIGGROF)) {
2307 type = OP_MAX;
2308 arity = AT_BINARY;
2309 #ifdef DEBUG
2310 debug("ET_OP (OP_MAX)");
2311 #endif
2312 }
2313 else if(acceptToken(&tokens, TT_SMALLROF)) {
2314 type = OP_MIN;
2315 arity = AT_BINARY;
2316 #ifdef DEBUG
2317 debug("ET_OP (OP_MIN)");
2318 #endif
2319 }
2320 else if(acceptToken(&tokens, TT_BOTHOF)) {
2321 type = OP_AND;
2322 arity = AT_BINARY;
2323 #ifdef DEBUG
2324 debug("ET_OP (OP_AND)");
2325 #endif
2326 }
2327 else if(acceptToken(&tokens, TT_EITHEROF)) {
2328 type = OP_OR;
2329 arity = AT_BINARY;
2330 #ifdef DEBUG
2331 debug("ET_OP (OP_OR)");
2332 #endif
2333 }
2334 else if(acceptToken(&tokens, TT_WONOF)) {
2335 type = OP_XOR;
2336 arity = AT_BINARY;
2337 #ifdef DEBUG
2338 debug("ET_OP (OP_XOR)");
2339 #endif
2340 }
2341 else if(acceptToken(&tokens, TT_BOTHSAEM)) {
2342 type = OP_EQ;
2343 arity = AT_BINARY;
2344 #ifdef DEBUG
2345 debug("ET_OP (OP_EQ)");
2346 #endif
2347 }
2348 else if(acceptToken(&tokens, TT_DIFFRINT)) {
2349 type = OP_NEQ;
2350 arity = AT_BINARY;
2351 #ifdef DEBUG
2352 debug("ET_OP (OP_NEQ)");
2353 #endif
2354 }
2355 /* N-ary operators */
2356 else if (acceptToken(&tokens, TT_ALLOF)) {
2357 type = OP_AND;
2358 arity = AT_NARY;
2359 #ifdef DEBUG
2360 debug("ET_OP (OP_AND)");
2361 #endif
2362 }
2363 else if(acceptToken(&tokens, TT_ANYOF)) {
2364 type = OP_OR;
2365 arity = AT_NARY;
2366 #ifdef DEBUG
2367 debug("ET_OP (OP_OR)");
2368 #endif
2369 }
2370 else if(acceptToken(&tokens, TT_SMOOSH)) {
2371 type = OP_CAT;
2372 arity = AT_NARY;
2373 #ifdef DEBUG
2374 debug("ET_OP (OP_CAT)");
2375 #endif
2376 }
2377 else {
2378 parser_error(PR_INVALID_OPERATOR, tokens);
2379 return NULL;
2380 }
2381
2382 /* Create the argument list */
2383 args = createExprNodeList();
2384 if (!args) goto parseOpExprNodeAbort;
2385
2386 /* Parse the operation arguments */
2387 if (arity == AT_UNARY) {
2388 /* Parse the argument */
2389 arg = parseExprNode(&tokens);
2390 if (!arg) goto parseOpExprNodeAbort;
2391
2392 /* Add the argument to the argument list */
2393 status = addExprNode(args, arg);
2394 if (!status) goto parseOpExprNodeAbort;
2395 arg = NULL;
2396 }
2397 else if (arity == AT_BINARY) {
2398 /* Parse the first argument */
2399 arg = parseExprNode(&tokens);
2400 if (!arg) goto parseOpExprNodeAbort;
2401
2402 /* Add the first argument to the argument list */
2403 status = addExprNode(args, arg);
2404 if (!status) goto parseOpExprNodeAbort;
2405 arg = NULL;
2406
2407 /* Optionally parse the argument-separator token */
2408 status = acceptToken(&tokens, TT_AN);
2409
2410 /* Parse the second argument */
2411 arg = parseExprNode(&tokens);
2412 if (!arg) goto parseOpExprNodeAbort;
2413
2414 /* Add the second argument to the argument list */
2415 status = addExprNode(args, arg);
2416 if (!status) goto parseOpExprNodeAbort;
2417 arg = NULL;
2418 }
2419 else if (arity == AT_NARY) {
2420 /* Parse as many arguments as possible */
2421 while (1) {
2422 /* Parse an argument */
2423 arg = parseExprNode(&tokens);
2424 if (!arg) goto parseOpExprNodeAbort;
2425
2426 /* Add the argument to the argument list */
2427 status = addExprNode(args, arg);
2428 if (!status) goto parseOpExprNodeAbort;
2429 arg = NULL;
2430
2431 /* Stop if the end-of-arguments token is present */
2432 if (acceptToken(&tokens, TT_MKAY)) break;
2433
2434 /* Optionally parse the argument-separator token */
2435 status = acceptToken(&tokens, TT_AN);
2436 }
2437 }
2438
2439 /* Create the new OpExprNode structure */
2440 expr = createOpExprNode(type, args);
2441 if (!expr) goto parseOpExprNodeAbort;
2442
2443 /* Create the new ExprNode structure */
2444 ret = createExprNode(ET_OP, expr);
2445 if (!ret) goto parseOpExprNodeAbort;
2446
2447 /* Since we're successful, update the token stream */
2448 *tokenp = tokens;
2449
2450 return ret;
2451
2452 parseOpExprNodeAbort: /* Exception handling */
2453
2454 /* Clean up any allocated structures */
2455 if (ret) deleteExprNode(ret);
2456 else if (expr) deleteOpExprNode(expr);
2457 else {
2458 if (arg) deleteExprNode(arg);
2459 if (args) deleteExprNodeList(args);
2460 }
2461
2462 return NULL;
2463 }
2464
2465 /**
2466 * Parses tokens into an expression.
2467 *
2468 * \param [in] tokenp The position in a token list to start parsing at.
2469 *
2470 * \post \a tokenp will point to the next unparsed token.
2471 *
2472 * \return A pointer to an expression.
2473 *
2474 * \retval NULL Unable to parse.
2475 */
parseExprNode(Token *** tokenp)2476 ExprNode *parseExprNode(Token ***tokenp)
2477 {
2478 Token **tokens = *tokenp;
2479 ExprNode *ret = NULL;
2480
2481 #ifdef DEBUG
2482 shiftout();
2483 #endif
2484
2485 /* Parse context-sensitive expressions */
2486 if (peekToken(&tokens, TT_IDENTIFIER)
2487 || peekToken(&tokens, TT_SRS)) {
2488 IdentifierNode *id = NULL;
2489
2490 /* Remove the identifier from the token stream */
2491 id = parseIdentifierNode(&tokens);
2492 if (!id) return NULL;
2493
2494 /* We do not need to hold onto it */
2495 deleteIdentifierNode(id);
2496
2497 /* Function call (must come before identifier) */
2498 if (peekToken(&tokens, TT_IZ)) {
2499 ret = parseFuncCallExprNode(tokenp);
2500 }
2501 /* Identifier */
2502 else {
2503 ret = parseIdentifierExprNode(tokenp);
2504 }
2505 }
2506 /* Cast */
2507 else if (peekToken(&tokens, TT_MAEK)) {
2508 ret = parseCastExprNode(tokenp);
2509 }
2510 /* Constant value */
2511 else if (peekToken(&tokens, TT_BOOLEAN)
2512 || peekToken(&tokens, TT_INTEGER)
2513 || peekToken(&tokens, TT_FLOAT)
2514 || peekToken(&tokens, TT_STRING))
2515 ret = parseConstantExprNode(tokenp);
2516 /* Operation */
2517 else if (peekToken(&tokens, TT_SUMOF)
2518 || peekToken(&tokens, TT_DIFFOF)
2519 || peekToken(&tokens, TT_PRODUKTOF)
2520 || peekToken(&tokens, TT_QUOSHUNTOF)
2521 || peekToken(&tokens, TT_MODOF)
2522 || peekToken(&tokens, TT_BIGGROF)
2523 || peekToken(&tokens, TT_SMALLROF)
2524 || peekToken(&tokens, TT_BOTHOF)
2525 || peekToken(&tokens, TT_EITHEROF)
2526 || peekToken(&tokens, TT_WONOF)
2527 || peekToken(&tokens, TT_BOTHSAEM)
2528 || peekToken(&tokens, TT_DIFFRINT)
2529 || peekToken(&tokens, TT_ANYOF)
2530 || peekToken(&tokens, TT_ALLOF)
2531 || peekToken(&tokens, TT_SMOOSH)
2532 || peekToken(&tokens, TT_NOT)) {
2533 ret = parseOpExprNode(tokenp);
2534 }
2535 /* Implicit variable */
2536 else if (acceptToken(&tokens, TT_IT)) {
2537 #ifdef DEBUG
2538 debug("ET_IMPVAR");
2539 #endif
2540
2541 /* Create the new ExprNode structure */
2542 ret = createExprNode(ET_IMPVAR, NULL);
2543 if (!ret) return NULL;
2544
2545 /* Since we're successful, update the token stream */
2546 *tokenp = tokens;
2547 }
2548 else if (peekToken(&tokens, TT_IDUZ)) {
2549 /* System command */
2550 ret = parseSystemCommandExprNode(tokenp);
2551 }
2552 else {
2553 parser_error(PR_EXPECTED_EXPRESSION, tokens);
2554 }
2555
2556 #ifdef DEBUG
2557 shiftin();
2558 #endif
2559
2560 return ret;
2561 }
2562
2563 /**
2564 * Parses tokens into a cast statement.
2565 *
2566 * \param [in] tokenp The position in a token list to start parsing at.
2567 *
2568 * \post \a tokenp will point to the next unparsed token.
2569 *
2570 * \return A pointer to a cast statement.
2571 *
2572 * \retval NULL Unable to parse.
2573 */
parseCastStmtNode(Token *** tokenp)2574 StmtNode *parseCastStmtNode(Token ***tokenp)
2575 {
2576 IdentifierNode *target = NULL;
2577 TypeNode *newtype = NULL;
2578 CastStmtNode *stmt = NULL;
2579 StmtNode *ret = NULL;
2580 int status;
2581
2582 /* Work from a copy of the token stream in case something goes wrong */
2583 Token **tokens = *tokenp;
2584
2585 #ifdef DEBUG
2586 debug("ST_CAST");
2587 #endif
2588
2589 /* Parse the target of the cast statement */
2590 target = parseIdentifierNode(&tokens);
2591 if (!target) goto parseCastStmtNodeAbort;
2592
2593 /* Remove the cast keywords from the token stream */
2594 status = acceptToken(&tokens, TT_ISNOWA);
2595 if (!status) {
2596 parser_error_expected_token(TT_ISNOWA, tokens);
2597 goto parseCastStmtNodeAbort;
2598 }
2599
2600 /* Parse the type to cast to */
2601 newtype = parseTypeNode(&tokens);
2602 if (!newtype) goto parseCastStmtNodeAbort;
2603
2604 /* Make sure the statement ends with a newline */
2605 status = acceptToken(&tokens, TT_NEWLINE);
2606 if (!status) {
2607 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
2608 goto parseCastStmtNodeAbort;
2609 }
2610
2611 /* Create the new CastStmtNode structure */
2612 stmt = createCastStmtNode(target, newtype);
2613 if (!stmt) goto parseCastStmtNodeAbort;
2614
2615 /* Create the new StmtNode structure */
2616 ret = createStmtNode(ST_CAST, stmt);
2617 if (!ret) goto parseCastStmtNodeAbort;
2618
2619 /* Since we're successful, update the token stream */
2620 *tokenp = tokens;
2621
2622 return ret;
2623
2624 parseCastStmtNodeAbort: /* Exception handling */
2625
2626 /* Clean up any allocated structures */
2627 if (ret) deleteStmtNode(ret);
2628 else if (stmt) deleteCastStmtNode(stmt);
2629 else {
2630 if (newtype) deleteTypeNode(newtype);
2631 if (target) deleteIdentifierNode(target);
2632 }
2633
2634 return NULL;
2635 }
2636
2637 /**
2638 * Parses tokens into a print statement.
2639 *
2640 * \param [in] tokenp The position in a token list to start parsing at.
2641 *
2642 * \post \a tokenp will point to the next unparsed token.
2643 *
2644 * \return A pointer to a print statement.
2645 *
2646 * \retval NULL Unable to parse.
2647 */
parsePrintStmtNode(Token *** tokenp)2648 StmtNode *parsePrintStmtNode(Token ***tokenp)
2649 {
2650 ExprNode *arg = NULL;
2651 ExprNodeList *args = NULL;
2652 int nonl = 0;
2653 PrintStmtNode *stmt = NULL;
2654 StmtNode *ret = NULL;
2655 int status;
2656
2657 /* Work from a copy of the token stream in case something goes wrong */
2658 Token **tokens = *tokenp;
2659
2660 #ifdef DEBUG
2661 debug("ST_PRINT");
2662 #endif
2663
2664 /* Remove the print keyword from the token stream */
2665 status = acceptToken(&tokens, TT_VISIBLE);
2666 if (!status) {
2667 parser_error_expected_token(TT_VISIBLE, tokens);
2668 goto parsePrintStmtNodeAbort;
2669 }
2670
2671 /* Parse the arguments to the print statement */
2672 args = createExprNodeList();
2673 if (!args) goto parsePrintStmtNodeAbort;
2674 do {
2675 /* Parse an argument; it should be an expression */
2676 arg = parseExprNode(&tokens);
2677 if (!arg) goto parsePrintStmtNodeAbort;
2678
2679 /* Add it to the list of arguments */
2680 status = addExprNode(args, arg);
2681 if (!status) goto parsePrintStmtNodeAbort;
2682 arg = NULL;
2683
2684 /* Arguments can optionally be separated by an AN keyword */
2685 status = acceptToken(&tokens, TT_AN);
2686 } while (!peekToken(&tokens, TT_NEWLINE)
2687 && !peekToken(&tokens, TT_BANG));
2688
2689 /* Check for the no-newline token */
2690 if(acceptToken(&tokens, TT_BANG)) nonl = 1;
2691
2692 /* Make sure the statement ends with a newline */
2693 status = acceptToken(&tokens, TT_NEWLINE);
2694 if (!status) {
2695 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
2696 goto parsePrintStmtNodeAbort;
2697 }
2698
2699 /* Create the new PrintStmtNode structure */
2700 stmt = createPrintStmtNode(args, nonl);
2701 if (!stmt) goto parsePrintStmtNodeAbort;
2702
2703 /* Create the new StmtNode structure */
2704 ret = createStmtNode(ST_PRINT, stmt);
2705 if (!ret) goto parsePrintStmtNodeAbort;
2706
2707 /* Since we're successful, update the token stream */
2708 *tokenp = tokens;
2709
2710 return ret;
2711
2712 parsePrintStmtNodeAbort: /* Exception handling */
2713
2714 /* Clean up any allocated structures */
2715 if (ret) deleteStmtNode(ret);
2716 else if (stmt) deletePrintStmtNode(stmt);
2717 else {
2718 if (arg) deleteExprNode(arg);
2719 if (args) deleteExprNodeList(args);
2720 }
2721
2722 return NULL;
2723 }
2724
2725 /**
2726 * Parses tokens into an input statement.
2727 *
2728 * \param [in] tokenp The position in a token list to start parsing at.
2729 *
2730 * \post \a tokenp will point to the next unparsed token.
2731 *
2732 * \return A pointer to an input statement.
2733 *
2734 * \retval NULL Unable to parse.
2735 */
parseInputStmtNode(Token *** tokenp)2736 StmtNode *parseInputStmtNode(Token ***tokenp)
2737 {
2738 IdentifierNode *target = NULL;
2739 InputStmtNode *stmt = NULL;
2740 StmtNode *ret = NULL;
2741 int status;
2742
2743 /* Work from a copy of the token stream in case something goes wrong */
2744 Token **tokens = *tokenp;
2745
2746 #ifdef DEBUG
2747 debug("ST_INPUT");
2748 #endif
2749
2750 /* Remove the input keyword from the token stream */
2751 status = acceptToken(&tokens, TT_GIMMEH);
2752 if (!status) {
2753 parser_error_expected_token(TT_GIMMEH, tokens);
2754 goto parseInputStmtNodeAbort;
2755 }
2756
2757 /* Parse the identifier to store the input into */
2758 target = parseIdentifierNode(&tokens);
2759 if (!target) goto parseInputStmtNodeAbort;
2760
2761 /* Make sure the statement ends with a newline */
2762 status = acceptToken(&tokens, TT_NEWLINE);
2763 if (!status) {
2764 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
2765 goto parseInputStmtNodeAbort;
2766 }
2767
2768 /* Create the new InputStmtNode structure */
2769 stmt = createInputStmtNode(target);
2770 if (!stmt) goto parseInputStmtNodeAbort;
2771
2772 /* Create the new StmtNode structure */
2773 ret = createStmtNode(ST_INPUT, stmt);
2774 if (!ret) goto parseInputStmtNodeAbort;
2775
2776 /* Since we're successful, update the token stream */
2777 *tokenp = tokens;
2778
2779 return ret;
2780
2781 parseInputStmtNodeAbort: /* Exception handling */
2782
2783 /* Clean up any allocated structures */
2784 if (ret) deleteStmtNode(ret);
2785 else if (stmt) deleteInputStmtNode(stmt);
2786 else {
2787 if (target) deleteIdentifierNode(target);
2788 }
2789
2790 return NULL;
2791 }
2792
2793 /**
2794 * Parses tokens into an assignment statement.
2795 *
2796 * \param [in] tokenp The position in a token list to start parsing at.
2797 *
2798 * \post \a tokenp will point to the next unparsed token.
2799 *
2800 * \return A pointer to an assignment statement.
2801 *
2802 * \retval NULL unable to parse.
2803 */
parseAssignmentStmtNode(Token *** tokenp)2804 StmtNode *parseAssignmentStmtNode(Token ***tokenp)
2805 {
2806 IdentifierNode *target = NULL;
2807 ExprNode *expr = NULL;
2808 AssignmentStmtNode *stmt = NULL;
2809 StmtNode *ret = NULL;
2810 int status;
2811
2812 /* Work from a copy of the token stream in case something goes wrong */
2813 Token **tokens = *tokenp;
2814
2815 #ifdef DEBUG
2816 debug("ST_ASSIGNMENT");
2817 #endif
2818
2819 /* Parse the target of the assignment */
2820 target = parseIdentifierNode(&tokens);
2821 if (!target) goto parseAssignmentStmtNodeAbort;
2822
2823 /* Remove the assignment keyword from the token stream */
2824 if (!acceptToken(&tokens, TT_R)) {
2825 parser_error_expected_token(TT_R, tokens);
2826 goto parseAssignmentStmtNodeAbort;
2827 }
2828
2829 /* Parse the expression to assign */
2830 expr = parseExprNode(&tokens);
2831 if (!expr) goto parseAssignmentStmtNodeAbort;
2832
2833 /* Make sure the statement ends with a newline */
2834 status = acceptToken(&tokens, TT_NEWLINE);
2835 if (!status) {
2836 parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
2837 goto parseAssignmentStmtNodeAbort;
2838 }
2839
2840 /* Create the new AssignmentStmtNode structure */
2841 stmt = createAssignmentStmtNode(target, expr);
2842 if (!stmt) goto parseAssignmentStmtNodeAbort;
2843
2844 /* Create the new StmtNode structure */
2845 ret = createStmtNode(ST_ASSIGNMENT, stmt);
2846 if (!ret) goto parseAssignmentStmtNodeAbort;
2847
2848 /* Since we're successful, update the token stream */
2849 *tokenp = tokens;
2850
2851 return ret;
2852
2853 parseAssignmentStmtNodeAbort: /* Exception handling */
2854
2855 /* Clean up any allocated structures */
2856 if (ret) deleteStmtNode(ret);
2857 else if (stmt) deleteAssignmentStmtNode(stmt);
2858 else {
2859 if (expr) deleteExprNode(expr);
2860 if (target) deleteIdentifierNode(target);
2861 }
2862
2863 return NULL;
2864 }
2865
2866 /**
2867 * Parses tokens into a declaration statement.
2868 *
2869 * \param [in] tokenp The position in a token list to start parsing at.
2870 *
2871 * \post \a tokenp will point to the next unparsed token.
2872 *
2873 * \return A pointer to a declaration statement.
2874 *
2875 * \retval NULL Unable to parse.
2876 */
parseDeclarationStmtNode(Token *** tokenp)2877 StmtNode *parseDeclarationStmtNode(Token ***tokenp)
2878 {
2879 IdentifierNode *scope = NULL;
2880 IdentifierNode *target = NULL;
2881 ExprNode *expr = NULL;
2882 TypeNode *type = NULL;
2883 IdentifierNode *parent = NULL;
2884 DeclarationStmtNode *stmt = NULL;
2885 StmtNode *ret = NULL;
2886 int status;
2887
2888 /* Work from a copy of the token stream in case something goes wrong */
2889 Token **tokens = *tokenp;
2890
2891 #ifdef DEBUG
2892 debug("ST_DECLARATION");
2893 #endif
2894
2895 /* Parse the scope to declare the variable in */
2896 scope = parseIdentifierNode(&tokens);
2897 if (!scope) goto parseDeclarationStmtNodeAbort;
2898
2899 /* Remove the declaration keywords from the token stream */
2900 if (!acceptToken(&tokens, TT_HASA)) {
2901 parser_error_expected_token(TT_HASA, tokens);
2902 goto parseDeclarationStmtNodeAbort;
2903 }
2904
2905 /* Parse the identifier to declare */
2906 target = parseIdentifierNode(&tokens);
2907 if (!target) goto parseDeclarationStmtNodeAbort;
2908
2909 /* Check for an optional initialization */
2910 if (acceptToken(&tokens, TT_ITZ)) {
2911 /* Parse the expression to initialize to */
2912 expr = parseExprNode(&tokens);
2913 if (!expr) goto parseDeclarationStmtNodeAbort;
2914 }
2915 /* Check for an optional type initialization */
2916 else if (acceptToken(&tokens, TT_ITZA)) {
2917 /* Parse the type to initialize to */
2918 type = parseTypeNode(&tokens);
2919 if (!type) goto parseDeclarationStmtNodeAbort;
2920 }
2921 /* Check for an optional array inheritance */
2922 else if (acceptToken(&tokens, TT_ITZLIEKA)) {
2923 /* Parse the parent to inherit from */
2924 parent = parseIdentifierNode(&tokens);
2925 if (!parent) goto parseDeclarationStmtNodeAbort;
2926 }
2927
2928 /* Make sure the statement ends with a newline */
2929 status = acceptToken(&tokens, TT_NEWLINE);
2930 if (!status) {
2931 parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
2932 goto parseDeclarationStmtNodeAbort;
2933 }
2934
2935 /* Create the new DeclarationStmtNode structure */
2936 stmt = createDeclarationStmtNode(scope, target, expr, type, parent);
2937 if (!stmt) goto parseDeclarationStmtNodeAbort;
2938
2939 /* Create the new StmtNode structure */
2940 ret = createStmtNode(ST_DECLARATION, stmt);
2941 if (!ret) goto parseDeclarationStmtNodeAbort;
2942
2943 /* Since we're successful, update the token stream */
2944 *tokenp = tokens;
2945
2946 return ret;
2947
2948 parseDeclarationStmtNodeAbort: /* Exception handling */
2949
2950 /* Clean up any allocated structures */
2951 if (ret) deleteStmtNode(ret);
2952 else if (stmt) deleteDeclarationStmtNode(stmt);
2953 else {
2954 if (type) deleteTypeNode(type);
2955 if (expr) deleteExprNode(expr);
2956 if (target) deleteIdentifierNode(target);
2957 if (scope) deleteIdentifierNode(scope);
2958 }
2959
2960 return NULL;
2961 }
2962
2963 /**
2964 * Parses tokens into an if/then/else statement.
2965 *
2966 * \param [in] tokenp The position in a token list to start parsing at.
2967 *
2968 * \post \a tokenp will point to the next unparsed token.
2969 *
2970 * \return A pointer to an if/then/else statement.
2971 *
2972 * \retval NULL Unable to parse.
2973 */
parseIfThenElseStmtNode(Token *** tokenp)2974 StmtNode *parseIfThenElseStmtNode(Token ***tokenp)
2975 {
2976 BlockNode *yes = NULL;
2977 ExprNodeList *guards = NULL;
2978 BlockNodeList *blocks = NULL;
2979 ExprNode *guard = NULL;
2980 BlockNode *block = NULL;
2981 BlockNode *no = NULL;
2982 IfThenElseStmtNode *stmt = NULL;
2983 StmtNode *ret = NULL;
2984 int status;
2985
2986 /* Work from a copy of the token stream in case something goes wrong */
2987 Token **tokens = *tokenp;
2988
2989 #ifdef DEBUG
2990 debug("ST_CONDITIONAL");
2991 #endif
2992
2993 /* Remove the if keyword from the token stream */
2994 status = acceptToken(&tokens, TT_ORLY);
2995 if (!status) {
2996 parser_error_expected_token(TT_ORLY, tokens);
2997 goto parseIfThenElseStmtNodeAbort;
2998 }
2999
3000 /* Remove the question mark from the token stream */
3001 status = acceptToken(&tokens, TT_QUESTION);
3002 if (!status) {
3003 parser_error_expected_token(TT_QUESTION, tokens);
3004 goto parseIfThenElseStmtNodeAbort;
3005 }
3006
3007 /* The if keyword must appear on its own line */
3008 if (!acceptToken(&tokens, TT_NEWLINE)) {
3009 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3010 goto parseIfThenElseStmtNodeAbort;
3011 }
3012
3013 /* Parse the true branch keyword */
3014 status = acceptToken(&tokens, TT_YARLY);
3015 if (!status) {
3016 parser_error_expected_token(TT_YARLY, tokens);
3017 goto parseIfThenElseStmtNodeAbort;
3018 }
3019
3020 /* The true branch keyword must appear on its own line */
3021 status = acceptToken(&tokens, TT_NEWLINE);
3022 if (!status) {
3023 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3024 goto parseIfThenElseStmtNodeAbort;
3025 }
3026
3027 /* Parse the true part of the branch */
3028 yes = parseBlockNode(&tokens);
3029 if (!yes) goto parseIfThenElseStmtNodeAbort;
3030
3031 /* Set up lists of guards and blocks */
3032 guards = createExprNodeList();
3033 if (!guards) goto parseIfThenElseStmtNodeAbort;
3034 blocks = createBlockNodeList();
3035 if (!blocks) goto parseIfThenElseStmtNodeAbort;
3036
3037 /* Parse the else-if keyword */
3038 while (acceptToken(&tokens, TT_MEBBE)) {
3039 /* Parse an else-if guard */
3040 guard = parseExprNode(&tokens);
3041 if (!guard) goto parseIfThenElseStmtNodeAbort;
3042
3043 /* Add the else-if guard to the guard list */
3044 status = addExprNode(guards, guard);
3045 if (!status) goto parseIfThenElseStmtNodeAbort;
3046 guard = NULL;
3047
3048 /* The else-if keyword and guard must be on their own line */
3049 status = acceptToken(&tokens, TT_NEWLINE);
3050 if (!status) {
3051 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3052 goto parseIfThenElseStmtNodeAbort;
3053 }
3054
3055 /* Parse the else-if block */
3056 block = parseBlockNode(&tokens);
3057 if (!block) goto parseIfThenElseStmtNodeAbort;
3058
3059 /* Add the else-if block to the block list */
3060 status = addBlockNode(blocks, block);
3061 if (!status) goto parseIfThenElseStmtNodeAbort;
3062 block = NULL;
3063 }
3064
3065 /* Parse the else keyword */
3066 if (acceptToken(&tokens, TT_NOWAI)) {
3067 /* The else keyword must appear on its own line */
3068 status = acceptToken(&tokens, TT_NEWLINE);
3069 if (!status) {
3070 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3071 goto parseIfThenElseStmtNodeAbort;
3072 }
3073
3074 /* Parse the else block */
3075 no = parseBlockNode(&tokens);
3076 if (!no) goto parseIfThenElseStmtNodeAbort;
3077 }
3078
3079 /* Parse the end-if-block keyword */
3080 status = acceptToken(&tokens, TT_OIC);
3081 if (!status) {
3082 parser_error_expected_token(TT_OIC, tokens);
3083 goto parseIfThenElseStmtNodeAbort;
3084 }
3085
3086 /* The end-if-block keyword must appear on its own line */
3087 status = acceptToken(&tokens, TT_NEWLINE);
3088 if (!status) {
3089 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3090 goto parseIfThenElseStmtNodeAbort;
3091 }
3092
3093 /* Create the new IfThenElseStmtNode structure */
3094 stmt = createIfThenElseStmtNode(yes, no, guards, blocks);
3095 if (!stmt) goto parseIfThenElseStmtNodeAbort;
3096
3097 /* Create the new StmtNode structure */
3098 ret = createStmtNode(ST_IFTHENELSE, stmt);
3099 if (!ret) goto parseIfThenElseStmtNodeAbort;
3100
3101 /* Since we're successful, update the token stream */
3102 *tokenp = tokens;
3103
3104 return ret;
3105
3106 parseIfThenElseStmtNodeAbort: /* Exception handling */
3107
3108 /* Clean up any allocated structures */
3109 if (ret) deleteStmtNode(ret);
3110 else if (stmt) deleteIfThenElseStmtNode(stmt);
3111 else {
3112 if (no) deleteBlockNode(no);
3113 if (blocks) deleteBlockNodeList(blocks);
3114 if (guards) deleteExprNodeList(guards);
3115 if (block) deleteBlockNode(block);
3116 if (guard) deleteExprNode(guard);
3117 if (yes) deleteBlockNode(yes);
3118 }
3119
3120 return NULL;
3121 }
3122
3123 /**
3124 * Parses tokens into a switch statement.
3125 *
3126 * \param [in] tokenp The position in a token list to start parsing at.
3127 *
3128 * \post \a tokenp will point to the next unparsed token.
3129 *
3130 * \return A pointer to a switch statement.
3131 *
3132 * \retval NULL Unable to parse.
3133 */
parseSwitchStmtNode(Token *** tokenp)3134 StmtNode *parseSwitchStmtNode(Token ***tokenp)
3135 {
3136 ExprNodeList *guards = NULL;
3137 BlockNodeList *blocks = NULL;
3138 ConstantNode *c = NULL;
3139 ExprNode *guard = NULL;
3140 BlockNode *block = NULL;
3141 BlockNode *def = NULL;
3142 SwitchStmtNode *stmt = NULL;
3143 StmtNode *ret = NULL;
3144 int status;
3145
3146 /* Work from a copy of the token stream in case something goes wrong */
3147 Token **tokens = *tokenp;
3148
3149 #ifdef DEBUG
3150 debug("ST_SWITCH");
3151 #endif
3152
3153 /* Remove the switch keyword from the token stream */
3154 status = acceptToken(&tokens, TT_WTF);
3155 if (!status) {
3156 parser_error_expected_token(TT_WTF, tokens);
3157 goto parseSwitchStmtNodeAbort;
3158 }
3159
3160 /* Remove the question mark from the token stream */
3161 status = acceptToken(&tokens, TT_QUESTION);
3162 if (!status) {
3163 parser_error_expected_token(TT_QUESTION, tokens);
3164 goto parseSwitchStmtNodeAbort;
3165 }
3166
3167 /* The switch keyword must appear on its own line */
3168 status = acceptToken(&tokens, TT_NEWLINE);
3169 if (!status) {
3170 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3171 goto parseSwitchStmtNodeAbort;
3172 }
3173
3174 /* Set up lists of guards and blocks */
3175 guards = createExprNodeList();
3176 if (!guards) goto parseSwitchStmtNodeAbort;
3177 blocks = createBlockNodeList();
3178 if (!blocks) goto parseSwitchStmtNodeAbort;
3179
3180 /* Parse at least one case */
3181 do {
3182 unsigned int n = 0;
3183
3184 /* Parse the case keyword */
3185 status = acceptToken(&tokens, TT_OMG);
3186 if (!status) {
3187 parser_error_expected_token(TT_OMG, tokens);
3188 goto parseSwitchStmtNodeAbort;
3189 }
3190
3191 /* Parse a constant for the case */
3192 /** \note The 1.2 specification only allows constant
3193 * values for OMG guards thus this function
3194 * explicitly checks for them. */
3195 c = parseConstantNode(&tokens);
3196 if (!c) goto parseSwitchStmtNodeAbort;
3197
3198 /* String interpolation is not allowed */
3199 if (c->type == CT_STRING && strstr(c->data.s, ":{")) {
3200 parser_error(PR_CANNOT_USE_STR_AS_LITERAL, tokens);
3201 goto parseSwitchStmtNodeAbort;
3202 }
3203
3204 /* Make sure the constant is unique to this switch statement */
3205 for (n = 0; n < guards->num; n++) {
3206 ConstantNode *test = guards->exprs[n]->expr;
3207 if (c->type != test->type) continue;
3208 /* Check for equivalent types and values */
3209 if (((c->type == CT_BOOLEAN || c->type == CT_INTEGER)
3210 && c->data.i == test->data.i)
3211 || (c->type == CT_FLOAT
3212 && fabs(c->data.f - test->data.f) < FLT_EPSILON)
3213 || (c->type == CT_STRING
3214 && !strcmp(c->data.s, test->data.s))) {
3215 parser_error(PR_LITERAL_MUST_BE_UNIQUE, tokens);
3216 goto parseSwitchStmtNodeAbort;
3217 }
3218 }
3219
3220 /* Package the constant in an expression */
3221 guard = createExprNode(ET_CONSTANT, c);
3222 if (!guard) goto parseSwitchStmtNodeAbort;
3223
3224 /* Add the guard to the list of guards */
3225 status = addExprNode(guards, guard);
3226 if (!status) goto parseSwitchStmtNodeAbort;
3227 guard = NULL;
3228
3229 /* Make sure the guard appears on its own line */
3230 status = acceptToken(&tokens, TT_NEWLINE);
3231 if (!status) {
3232 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3233 goto parseSwitchStmtNodeAbort;
3234 }
3235
3236 /* Parse the block associated with the guard */
3237 block = parseBlockNode(&tokens);
3238 if (!block) goto parseSwitchStmtNodeAbort;
3239
3240 /* Add the block to the list of blocks */
3241 status = addBlockNode(blocks, block);
3242 if (!status) goto parseSwitchStmtNodeAbort;
3243 block = NULL;
3244 } while (peekToken(&tokens, TT_OMG));
3245
3246 /* Check for the default case */
3247 if (acceptToken(&tokens, TT_OMGWTF)) {
3248 /* Make sure the default case keyword appears on its own line */
3249 status = acceptToken(&tokens, TT_NEWLINE);
3250 if (!status) {
3251 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3252 goto parseSwitchStmtNodeAbort;
3253 }
3254
3255 /* Parse the default case block */
3256 def = parseBlockNode(&tokens);
3257 if (!def) goto parseSwitchStmtNodeAbort;
3258 }
3259
3260 /* Parse the end-switch keyword */
3261 status = acceptToken(&tokens, TT_OIC);
3262 if (!status) {
3263 parser_error_expected_token(TT_OIC, tokens);
3264 goto parseSwitchStmtNodeAbort;
3265 }
3266
3267 /* Make sure the end-switch keyword appears on its own line */
3268 status = acceptToken(&tokens, TT_NEWLINE);
3269 if (!status) {
3270 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3271 goto parseSwitchStmtNodeAbort;
3272 }
3273
3274 /* Create the new SwitchStmtNode structure */
3275 stmt = createSwitchStmtNode(guards, blocks, def);
3276 if (!stmt) goto parseSwitchStmtNodeAbort;
3277
3278 /* Create the new StmtNode structure */
3279 ret = createStmtNode(ST_SWITCH, stmt);
3280 if (!ret) goto parseSwitchStmtNodeAbort;
3281
3282 /* Since we're successful, update the token stream */
3283 *tokenp = tokens;
3284
3285 return ret;
3286
3287 parseSwitchStmtNodeAbort: /* Exception handling */
3288
3289 /* Clean up any allocated structures */
3290 if (ret) deleteStmtNode(ret);
3291 else if (stmt) deleteSwitchStmtNode(stmt);
3292 else {
3293 if (def) deleteBlockNode(def);
3294 if (block) deleteBlockNode(block);
3295 if (guard) deleteExprNode(guard);
3296 if (c) deleteConstantNode(c);
3297 if (blocks) deleteBlockNodeList(blocks);
3298 if (guards) deleteExprNodeList(guards);
3299 }
3300
3301 return NULL;
3302 }
3303
3304 /**
3305 * Parses tokens into a break statement.
3306 *
3307 * \param [in] tokenp The position in a token list to start parsing at.
3308 *
3309 * \post \a tokenp will point to the next unparsed token.
3310 *
3311 * \return A pointer to a break statement.
3312 *
3313 * \retval NULL Unable to parse.
3314 */
parseBreakStmtNode(Token *** tokenp)3315 StmtNode *parseBreakStmtNode(Token ***tokenp)
3316 {
3317 StmtNode *ret = NULL;
3318 int status;
3319
3320 /* Work from a copy of the token stream in case something goes wrong */
3321 Token **tokens = *tokenp;
3322
3323 #ifdef DEBUG
3324 debug("ST_BREAK");
3325 #endif
3326
3327 /* Remove the break keyword from the token stream */
3328 status = acceptToken(&tokens, TT_GTFO);
3329 if (!status) {
3330 parser_error_expected_token(TT_GTFO, tokens);
3331 goto parseBreakStmtNodeAbort;
3332 }
3333
3334 /* The break keyword must appear on its own line */
3335 status = acceptToken(&tokens, TT_NEWLINE);
3336 if (!status) {
3337 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3338 goto parseBreakStmtNodeAbort;
3339 }
3340
3341 /* Create the new StmtNode structure */
3342 ret = createStmtNode(ST_BREAK, NULL);
3343 if (!ret) goto parseBreakStmtNodeAbort;
3344
3345 /* Since we're successful, update the token stream */
3346 *tokenp = tokens;
3347
3348 return ret;
3349
3350 parseBreakStmtNodeAbort: /* Exception handling */
3351
3352 /* Clean up any allocated structures */
3353 if (ret) deleteStmtNode(ret);
3354 return NULL;
3355 }
3356
3357 /**
3358 * Parses tokens into a return statement.
3359 *
3360 * \param [in] tokenp The position in a token list to start parsing at.
3361 *
3362 * \post \a tokenp will point to the next unparsed token.
3363 *
3364 * \return A pointer to a return statement.
3365 *
3366 * \retval NULL Unable to parse.
3367 */
parseReturnStmtNode(Token *** tokenp)3368 StmtNode *parseReturnStmtNode(Token ***tokenp)
3369 {
3370 ExprNode *value = NULL;
3371 ReturnStmtNode *stmt = NULL;
3372 StmtNode *ret = NULL;
3373 int status;
3374
3375 /* Work from a copy of the token stream in case something goes wrong */
3376 Token **tokens = *tokenp;
3377
3378 #ifdef DEBUG
3379 debug("ST_RETURN");
3380 #endif
3381
3382 /* Remove the return keyword from the token stream */
3383 status = acceptToken(&tokens, TT_FOUNDYR);
3384 if (!status) {
3385 parser_error_expected_token(TT_FOUNDYR, tokens);
3386 goto parseReturnStmtNodeAbort;
3387 }
3388
3389 /* Parse the return value */
3390 value = parseExprNode(&tokens);
3391 if (!value) goto parseReturnStmtNodeAbort;
3392
3393 /* The return statement must reside on its own line */
3394 status = acceptToken(&tokens, TT_NEWLINE);
3395 if (!status) {
3396 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3397 goto parseReturnStmtNodeAbort;
3398 }
3399
3400 /* Create the new ReturnStmtNode structure */
3401 stmt = createReturnStmtNode(value);
3402 if (!stmt) goto parseReturnStmtNodeAbort;
3403
3404 /* Create the new StmtNode structure */
3405 ret = createStmtNode(ST_RETURN, stmt);
3406 if (!ret) goto parseReturnStmtNodeAbort;
3407
3408 /* Since we're successful, update the token stream */
3409 *tokenp = tokens;
3410
3411 return ret;
3412
3413 parseReturnStmtNodeAbort: /* Exception handling */
3414
3415 /* Clean up any allocated structures */
3416 if (ret) deleteStmtNode(ret);
3417 else if (stmt) deleteReturnStmtNode(stmt);
3418 else {
3419 if (value) deleteExprNode(value);
3420 }
3421 return NULL;
3422 }
3423
3424 /**
3425 * Parses tokens into a loop statement.
3426 *
3427 * \param [in] tokenp The position in a token list to start parsing at.
3428 *
3429 * \post \a tokenp will point to the next unparsed token.
3430 *
3431 * \return A pointer to a loop statement.
3432 *
3433 * \retval NULL Unable to parse.
3434 */
parseLoopStmtNode(Token *** tokenp)3435 StmtNode *parseLoopStmtNode(Token ***tokenp)
3436 {
3437 IdentifierNode *name1 = NULL;
3438 IdentifierNode *var = NULL;
3439 ExprNode *update = NULL;
3440 ExprNode *guard = NULL;
3441 BlockNode *body = NULL;
3442 FuncDefStmtNode *def = NULL;
3443 IdentifierNode *name2 = NULL;
3444 LoopStmtNode *stmt = NULL;
3445 ExprNodeList *args = NULL;
3446 char *id = NULL;
3447
3448 /* For increment and decrement loops */
3449 IdentifierNode *varcopy = NULL;
3450 ExprNode *arg1 = NULL;
3451 ConstantNode *one = NULL;
3452 ExprNode *arg2 = NULL;
3453 OpExprNode *op = NULL;
3454
3455 /* For function loops */
3456 IdentifierNode *scope = NULL;
3457 IdentifierNode *name = NULL;
3458 FuncCallExprNode *node = NULL;
3459 ExprNode *arg = NULL;
3460
3461 /* For loop predicates */
3462 ExprNode *predarg = NULL;
3463 ExprNodeList *predargs = NULL;
3464 OpExprNode *predop = NULL;
3465
3466 StmtNode *ret = NULL;
3467 int status;
3468
3469 /* Work from a copy of the token stream in case something goes wrong */
3470 Token **tokens = *tokenp;
3471
3472 #ifdef DEBUG
3473 debug("ST_LOOP");
3474 #endif
3475
3476 /* Remove the loop-start keyword from the token stream */
3477 status = acceptToken(&tokens, TT_IMINYR);
3478 if (!status) {
3479 parser_error_expected_token(TT_IMINYR, tokens);
3480 goto parseLoopStmtNodeAbort;
3481 }
3482
3483 /* Parse the loop name */
3484 name1 = parseIdentifierNode(&tokens);
3485 if (!name1) goto parseLoopStmtNodeAbort;
3486 else if (name1->type != IT_DIRECT) {
3487 parser_error(PR_EXPECTED_LOOP_NAME, tokens);
3488 goto parseLoopStmtNodeAbort;
3489 }
3490
3491 /* Check if an increment or decrement loop */
3492 if (peekToken(&tokens, TT_UPPIN) || peekToken(&tokens, TT_NERFIN)) {
3493 OpType type;
3494
3495 /* Parse the increment token or decrement token */
3496 if (acceptToken(&tokens, TT_UPPIN)) {
3497 type = OP_ADD;
3498 #ifdef DEBUG
3499 shiftout();
3500 debug("ET_OP (OP_ADD)");
3501 #endif
3502 }
3503 else if (acceptToken(&tokens, TT_NERFIN)) {
3504 type = OP_SUB;
3505 #ifdef DEBUG
3506 shiftout();
3507 debug("ET_OP (OP_SUB)");
3508 #endif
3509 }
3510 else {
3511 parser_error_expected_either_token(TT_UPPIN, TT_NERFIN, tokens);
3512 goto parseLoopStmtNodeAbort;
3513 }
3514
3515 /* Parse the required syntax */
3516 if (!acceptToken(&tokens, TT_YR)) {
3517 parser_error_expected_token(TT_YR, tokens);
3518 goto parseLoopStmtNodeAbort;
3519 }
3520
3521 /* Parse the variable to operate on */
3522 var = parseIdentifierNode(&tokens);
3523 if (!var) goto parseLoopStmtNodeAbort;
3524 #ifdef DEBUG
3525 shiftout();
3526 debug("ET_CONSTANT (CT_INTEGER)");
3527 shiftin();
3528 shiftin();
3529 #endif
3530 /* Make a copy of the variable for use as a function argument */
3531 id = malloc(sizeof(char) * (strlen(var->id) + 1));
3532 if (!id) goto parseLoopStmtNodeAbort;
3533 strcpy(id, var->id);
3534 varcopy = createIdentifierNode(IT_DIRECT, id, NULL, var->fname, var->line);
3535 if (!varcopy) goto parseLoopStmtNodeAbort;
3536 id = NULL;
3537
3538 /* Package the variable into an identifier expression */
3539 arg1 = createExprNode(ET_IDENTIFIER, varcopy);
3540 if (!arg1) goto parseLoopStmtNodeAbort;
3541
3542 /* Create a constant integer "1" */
3543 one = createIntegerConstantNode(1);
3544 if (!one) goto parseLoopStmtNodeAbort;
3545
3546 /* Package the constant into an expression */
3547 arg2 = createExprNode(ET_CONSTANT, one);
3548 if (!arg2) goto parseLoopStmtNodeAbort;
3549
3550 /* Create a list of arguments */
3551 args = createExprNodeList();
3552 if (!args) goto parseLoopStmtNodeAbort;
3553
3554 /* Add the packaged arguments to the argument list */
3555 status = addExprNode(args, arg1);
3556 if (!status) goto parseLoopStmtNodeAbort;
3557 arg1 = NULL;
3558 status = addExprNode(args, arg2);
3559 if (!status) goto parseLoopStmtNodeAbort;
3560 arg2 = NULL;
3561
3562 /* Package the arguments and operation type in an expression */
3563 op = createOpExprNode(type, args);
3564 if (!op) goto parseLoopStmtNodeAbort;
3565
3566 /* Create the update expression */
3567 update = createExprNode(ET_OP, op);
3568 if (!update) goto parseLoopStmtNodeAbort;
3569 }
3570 /* Check if a function loop */
3571 else if (nextToken(&tokens, TT_IZ)) {
3572 IdentifierNode *temp = NULL;
3573 #ifdef DEBUG
3574 debug("ET_FUNCCALL");
3575 #endif
3576 /* Parse the function scope */
3577 scope = parseIdentifierNode(&tokens);
3578 if (!scope) goto parseLoopStmtNodeAbort;
3579
3580 /* Parse the function indicator */
3581 status = acceptToken(&tokens, TT_IZ);
3582 if (!status) {
3583 parser_error_expected_token(TT_IZ, tokens);
3584 goto parseLoopStmtNodeAbort;
3585 }
3586
3587 /* Parse the function name */
3588 name = parseIdentifierNode(&tokens);
3589 if (!name) goto parseLoopStmtNodeAbort;
3590
3591 /* Create a list of arguments */
3592 args = createExprNodeList();
3593 if (!args) goto parseLoopStmtNodeAbort;
3594
3595 /* Check for unary function */
3596 status = acceptToken(&tokens, TT_YR);
3597 if (!status) {
3598 parser_error(PR_EXPECTED_UNARY_FUNCTION, tokens);
3599 goto parseLoopStmtNodeAbort;
3600 }
3601
3602 /* Parse the unary function's single argument */
3603 arg = parseExprNode(&tokens);
3604 if (!arg) goto parseLoopStmtNodeAbort;
3605
3606 /* Make sure the argument is an identifier */
3607 if (arg->type != ET_IDENTIFIER) {
3608 parser_error(PR_EXPECTED_IDENTIFIER, tokens);
3609 goto parseLoopStmtNodeAbort;
3610 }
3611
3612 /* Add the argument to the argument list */
3613 status = addExprNode(args, arg);
3614 if (!status) goto parseLoopStmtNodeAbort;
3615 /* (Save a pointer to its expression for use, below) */
3616 temp = (IdentifierNode *)(arg->expr);
3617 arg = NULL;
3618
3619 /* Copy the identifier to make it the loop variable */
3620 id = malloc(sizeof(char) * (strlen(temp->id) + 1));
3621 if (!id) goto parseLoopStmtNodeAbort;
3622 strcpy(id, temp->id);
3623 var = createIdentifierNode(IT_DIRECT, id, NULL, temp->fname, temp->line);
3624 if (!var) goto parseLoopStmtNodeAbort;
3625 id = NULL;
3626
3627 /* Check for unary function */
3628 status = acceptToken(&tokens, TT_MKAY);
3629 if (!status) {
3630 parser_error_expected_token(TT_MKAY, tokens);
3631 goto parseLoopStmtNodeAbort;
3632 }
3633
3634 /* Create a function call expression */
3635 node = createFuncCallExprNode(scope, name, args);
3636 if (!node) goto parseLoopStmtNodeAbort;
3637
3638 /* Package the function call in an expression */
3639 update = createExprNode(ET_FUNCCALL, node);
3640 if (!update) goto parseLoopStmtNodeAbort;
3641 }
3642
3643 /* If there is an update, parse any predicates */
3644 if (update) {
3645 /* Check for a while token */
3646 if (acceptToken(&tokens, TT_WILE)) {
3647 /* Parse the while predicate */
3648 guard = parseExprNode(&tokens);
3649 if (!guard) goto parseLoopStmtNodeAbort;
3650 }
3651 /* Check for an until token */
3652 else if (acceptToken(&tokens, TT_TIL)) {
3653 #ifdef DEBUG
3654 shiftout();
3655 debug("ET_OP (OP_NOT)");
3656 #endif
3657 /* Parse the until predicate */
3658 predarg = parseExprNode(&tokens);
3659 if (!predarg) goto parseLoopStmtNodeAbort;
3660
3661 /* Create a list for predicate arguments */
3662 predargs = createExprNodeList();
3663 if (!predargs) goto parseLoopStmtNodeAbort;
3664
3665 /* Add the until predicate to the list */
3666 status = addExprNode(predargs, predarg);
3667 if (!status) goto parseLoopStmtNodeAbort;
3668 predarg = NULL;
3669 #ifdef DEBUG
3670 shiftin();
3671 #endif
3672 /* Create a NOT operation with the predicate */
3673 predop = createOpExprNode(OP_NOT, predargs);
3674 if (!predop) goto parseLoopStmtNodeAbort;
3675
3676 /* Package the NOT operation in an expression */
3677 guard = createExprNode(ET_OP, predop);
3678 if (!guard) goto parseLoopStmtNodeAbort;
3679 }
3680 }
3681
3682 /* All of the above should be on its own line */
3683 status = acceptToken(&tokens, TT_NEWLINE);
3684 if (!status) {
3685 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3686 goto parseLoopStmtNodeAbort;
3687 }
3688
3689 /* Parse the body of the loop */
3690 body = parseBlockNode(&tokens);
3691 if (!body) goto parseLoopStmtNodeAbort;
3692
3693 /* Parse the end-loop keywords */
3694 status = acceptToken(&tokens, TT_IMOUTTAYR);
3695 if (!status) {
3696 parser_error_expected_token(TT_IMOUTTAYR, tokens);
3697 goto parseLoopStmtNodeAbort;
3698 }
3699
3700 /* Parse the end-of-loop name */
3701 name2 = parseIdentifierNode(&tokens);
3702 if (!name2) goto parseLoopStmtNodeAbort;
3703 else if (name2->type != IT_DIRECT) {
3704 parser_error(PR_EXPECTED_LOOP_NAME, tokens);
3705 goto parseLoopStmtNodeAbort;
3706 }
3707
3708 /* Make sure the beginning-of-loop and end-of-loop names match */
3709 if (strcmp((char *)(name1->id), (char *)(name2->id))) {
3710 parser_error(PR_EXPECTED_MATCHING_LOOP_NAME, tokens);
3711 goto parseLoopStmtNodeAbort;
3712 }
3713
3714 /* We no longer need the end-of-loop name */
3715 deleteIdentifierNode(name2);
3716
3717 /* The end-of-loop structure should appear on its own line */
3718 status = acceptToken(&tokens, TT_NEWLINE);
3719 if (!status) {
3720 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
3721 goto parseLoopStmtNodeAbort;
3722 }
3723
3724 /* Create the new LoopStmtNode structure */
3725 stmt = createLoopStmtNode(name1, var, guard, update, body);
3726 if (!stmt) goto parseLoopStmtNodeAbort;
3727
3728 /* Create the new StmtNode structure */
3729 ret = createStmtNode(ST_LOOP, stmt);
3730 if (!ret) goto parseLoopStmtNodeAbort;
3731
3732 /* Since we're successful, update the token stream */
3733 *tokenp = tokens;
3734
3735 return ret;
3736
3737 parseLoopStmtNodeAbort: /* Exception handling */
3738
3739 /* Clean up any allocated structures */
3740 if (ret) deleteStmtNode(ret);
3741 else if (stmt) deleteLoopStmtNode(stmt);
3742 else {
3743 if (name2) deleteIdentifierNode(name2);
3744 if (def) deleteFuncDefStmtNode(def);
3745 if (body) deleteBlockNode(body);
3746 if (guard) deleteExprNode(guard);
3747 if (update) deleteExprNode(update);
3748 if (var) deleteIdentifierNode(var);
3749 if (name1) deleteIdentifierNode(name1);
3750 if (id) free(id);
3751
3752 /* For increment and decrement loops */
3753 if (op) deleteOpExprNode(op);
3754 if (args) deleteExprNodeList(args);
3755 if (arg2) deleteExprNode(arg2);
3756 if (one) deleteConstantNode(one);
3757 if (arg1) deleteExprNode(arg1);
3758 if (varcopy) deleteIdentifierNode(varcopy);
3759
3760 /* For function loops */
3761 if (arg) deleteExprNode(arg);
3762 if (node) deleteFuncCallExprNode(node);
3763 if (name) deleteIdentifierNode(name);
3764 if (scope) deleteIdentifierNode(scope);
3765
3766 /* For loop predicates */
3767 if (predarg) deleteExprNode(predarg);
3768 if (predargs) deleteExprNodeList(predargs);
3769 if (predop) deleteOpExprNode(predop);
3770 }
3771 return NULL;
3772 }
3773
3774 /**
3775 * Parses tokens into a deallocation statement.
3776 *
3777 * \param [in] tokenp The position in a token list to start parsing at.
3778 *
3779 * \post \a tokenp will point to the next unparsed token.
3780 *
3781 * \return A pointer to a deallocation statement.
3782 *
3783 * \retval NULL Unable to parse.
3784 */
parseDeallocationStmtNode(Token *** tokenp)3785 StmtNode *parseDeallocationStmtNode(Token ***tokenp)
3786 {
3787 IdentifierNode *target = NULL;
3788 DeallocationStmtNode *stmt = NULL;
3789 StmtNode *ret = NULL;
3790 int status;
3791
3792 /* Work from a copy of the token stream in case something goes wrong */
3793 Token **tokens = *tokenp;
3794
3795 #ifdef DEBUG
3796 debug("ST_DEALLOCATION");
3797 #endif
3798
3799 /* Parse the variable to deallocate */
3800 target = parseIdentifierNode(&tokens);
3801 if (!target) goto parseDeallocationStmtNodeAbort;
3802
3803 /* Parse the deallocation token */
3804 status = acceptToken(&tokens, TT_RNOOB);
3805 if (!status) {
3806 parser_error_expected_token(TT_RNOOB, tokens);
3807 goto parseDeallocationStmtNodeAbort;
3808 }
3809
3810 /* The deallocation statement must reside on its own line */
3811 status = acceptToken(&tokens, TT_NEWLINE);
3812 if (!status) {
3813 parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
3814 goto parseDeallocationStmtNodeAbort;
3815 }
3816
3817 /* Create the new DeallocationStmtNode structure */
3818 stmt = createDeallocationStmtNode(target);
3819 if (!stmt) goto parseDeallocationStmtNodeAbort;
3820
3821 /* Create the new StmtNode structure */
3822 ret = createStmtNode(ST_DEALLOCATION, stmt);
3823 if (!ret) goto parseDeallocationStmtNodeAbort;
3824
3825 /* Since we're successful, update the token stream */
3826 *tokenp = tokens;
3827
3828 return ret;
3829
3830 parseDeallocationStmtNodeAbort: /* Exception handling */
3831
3832 /* Clean up any allocated structures */
3833 if (ret) deleteStmtNode(ret);
3834 else if (stmt) deleteDeallocationStmtNode(stmt);
3835 else {
3836 if (target) deleteIdentifierNode(target);
3837 }
3838
3839 return NULL;
3840 }
3841
3842 /**
3843 * Parses tokens into a function definition statement.
3844 *
3845 * \param [in] tokenp The position in a token list to start parsing at.
3846 *
3847 * \post \a tokenp will point to the next unparsed token.
3848 *
3849 * \return A pointer to a function definition statement.
3850 *
3851 * \retval NULL Unable to parse.
3852 */
parseFuncDefStmtNode(Token *** tokenp)3853 StmtNode *parseFuncDefStmtNode(Token ***tokenp)
3854 {
3855 IdentifierNode *scope = NULL;
3856 IdentifierNode *name = NULL;
3857 IdentifierNodeList *args = NULL;
3858 IdentifierNode *arg = NULL;
3859 BlockNode *body = NULL;
3860 FuncDefStmtNode *stmt = NULL;
3861 StmtNode *ret = NULL;
3862 int status;
3863
3864 /* Work from a copy of the token stream in case something goes wrong */
3865 Token **tokens = *tokenp;
3866
3867 #ifdef DEBUG
3868 debug("ST_FUNCDEF");
3869 #endif
3870
3871 /* Parse the function definition token */
3872 status = acceptToken(&tokens, TT_HOWIZ);
3873 if (!status) {
3874 parser_error_expected_token(TT_HOWIZ, tokens);
3875 goto parseFuncDefStmtNodeAbort;
3876 }
3877
3878 /* Parse the scope to define the function in */
3879 scope = parseIdentifierNode(&tokens);
3880 if (!scope) goto parseFuncDefStmtNodeAbort;
3881
3882 /* Parse the name of the function */
3883 name = parseIdentifierNode(&tokens);
3884 if (!name) goto parseFuncDefStmtNodeAbort;
3885
3886 /* Create a list of arguments */
3887 args = createIdentifierNodeList();
3888 if (!args) goto parseFuncDefStmtNodeAbort;
3889
3890 /* Parse the first argument indicator */
3891 if (acceptToken(&tokens, TT_YR)) {
3892 /* Parse the first argument name */
3893 arg = parseIdentifierNode(&tokens);
3894 if (!arg) goto parseFuncDefStmtNodeAbort;
3895
3896 /* Add the first argument to the arguments list */
3897 status = addIdentifierNode(args, arg);
3898 if (!status) goto parseFuncDefStmtNodeAbort;
3899 arg = NULL;
3900
3901 /* Continue parsing argument indicators */
3902 while (acceptToken(&tokens, TT_ANYR)) {
3903 /* Parse the argument */
3904 arg = parseIdentifierNode(&tokens);
3905 if (!arg) goto parseFuncDefStmtNodeAbort;
3906
3907 /* Add the argument to the arguments list */
3908 status = addIdentifierNode(args, arg);
3909 if (!status) goto parseFuncDefStmtNodeAbort;
3910 arg = NULL;
3911 }
3912 }
3913
3914 /* The function declaration should appear on its own line */
3915 status = acceptToken(&tokens, TT_NEWLINE);
3916 if (!status) {
3917 parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
3918 goto parseFuncDefStmtNodeAbort;
3919 }
3920
3921 /* Parse the body of the function */
3922 body = parseBlockNode(&tokens);
3923 if (!body) goto parseFuncDefStmtNodeAbort;
3924
3925 /* Parse the end-function token */
3926 status = acceptToken(&tokens, TT_IFUSAYSO);
3927 if (!status) {
3928 parser_error_expected_token(TT_IFUSAYSO, tokens);
3929 goto parseFuncDefStmtNodeAbort;
3930 }
3931
3932 /* The end-function token should appear on its own line */
3933 status = acceptToken(&tokens, TT_NEWLINE);
3934 if (!status) {
3935 parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
3936 goto parseFuncDefStmtNodeAbort;
3937 }
3938
3939 /* Create the new FuncDefStmtNode structure */
3940 stmt = createFuncDefStmtNode(scope, name, args, body);
3941 if (!stmt) goto parseFuncDefStmtNodeAbort;
3942
3943 /* Create the new StmtNode structure */
3944 ret = createStmtNode(ST_FUNCDEF, stmt);
3945 if (!ret) goto parseFuncDefStmtNodeAbort;
3946
3947 /* Since we're successful, update the token stream */
3948 *tokenp = tokens;
3949
3950 return ret;
3951
3952 parseFuncDefStmtNodeAbort: /* Exception handling */
3953
3954 /* Clean up any allocated structures */
3955 if (ret) deleteStmtNode(ret);
3956 else if (stmt) deleteFuncDefStmtNode(stmt);
3957 else {
3958 if (body) deleteBlockNode(body);
3959 if (args) deleteIdentifierNodeList(args);
3960 if (arg) deleteIdentifierNode(arg);
3961 if (name) deleteIdentifierNode(name);
3962 if (scope) deleteIdentifierNode(scope);
3963 }
3964
3965 return NULL;
3966 }
3967
3968 /**
3969 * Parses tokens into an alternate array definition statement.
3970 *
3971 * \param [in] tokenp The position in a token list to start parsing at.
3972 *
3973 * \post \a tokenp will point to the next unparsed token.
3974 *
3975 * \return A pointer to an alternate array definition statement.
3976 *
3977 * \retval NULL Unable to parse.
3978 */
parseAltArrayDefStmtNode(Token *** tokenp)3979 StmtNode *parseAltArrayDefStmtNode(Token ***tokenp)
3980 {
3981 IdentifierNode *name = NULL;
3982 BlockNode *body = NULL;
3983 IdentifierNode *parent = NULL;
3984 AltArrayDefStmtNode *stmt = NULL;
3985 StmtNode *ret = NULL;
3986 int status;
3987
3988 /* Work from a copy of the token stream in case something goes wrong */
3989 Token **tokens = *tokenp;
3990
3991 #ifdef DEBUG
3992 debug("ST_ALTARRAYDEF");
3993 #endif
3994
3995 /* Parse the alternate array definition token */
3996 status = acceptToken(&tokens, TT_OHAIIM);
3997 if (!status) {
3998 parser_error_expected_token(TT_OHAIIM, tokens);
3999 goto parseAltArrayDefStmtNodeAbort;
4000 }
4001
4002 /* Parse the array name */
4003 name = parseIdentifierNode(&tokens);
4004 if (!name) goto parseAltArrayDefStmtNodeAbort;
4005
4006 /* Check for an optional array inheritance */
4007 if (acceptToken(&tokens, TT_IMLIEK)) {
4008 /* Parse the parent to inherit from */
4009 parent = parseIdentifierNode(&tokens);
4010 if (!parent) goto parseAltArrayDefStmtNodeAbort;
4011 }
4012
4013 /* The alternate array definition token and name should appear on their
4014 * own line */
4015 status = acceptToken(&tokens, TT_NEWLINE);
4016 if (!status) {
4017 parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
4018 goto parseAltArrayDefStmtNodeAbort;
4019 }
4020
4021 /* Parse the array definition body */
4022 body = parseBlockNode(&tokens);
4023 if (!body) goto parseAltArrayDefStmtNodeAbort;
4024
4025 /* The end-alternate array definition token should appear on its own
4026 * line */
4027 status = acceptToken(&tokens, TT_KTHX);
4028 if (!status) {
4029 parser_error_expected_token(TT_KTHX, tokens);
4030 goto parseAltArrayDefStmtNodeAbort;
4031 }
4032
4033 /* The end-function token should appear on its own line */
4034 status = acceptToken(&tokens, TT_NEWLINE);
4035 if (!status) {
4036 parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
4037 goto parseAltArrayDefStmtNodeAbort;
4038 }
4039
4040 /* Create the new AltArrayDefStmtNode structure */
4041 stmt = createAltArrayDefStmtNode(name, body, parent);
4042 if (!stmt) goto parseAltArrayDefStmtNodeAbort;
4043
4044 /* Create the new StmtNode structure */
4045 ret = createStmtNode(ST_ALTARRAYDEF, stmt);
4046 if (!ret) goto parseAltArrayDefStmtNodeAbort;
4047
4048 /* Since we're successful, update the token stream */
4049 *tokenp = tokens;
4050
4051 return ret;
4052
4053 parseAltArrayDefStmtNodeAbort: /* Exception handling */
4054
4055 /* Clean up any allocated structures */
4056 if (ret) deleteStmtNode(ret);
4057 else if (stmt) deleteAltArrayDefStmtNode(stmt);
4058 else {
4059 if (name) deleteIdentifierNode(name);
4060 if (body) deleteBlockNode(body);
4061 }
4062
4063 return NULL;
4064 }
4065
4066 /**
4067 * Parses tokens into a library import statement.
4068 *
4069 * \param [in] tokenp The position in a token list to start parsing at.
4070 *
4071 * \post \a tokenp will point to the next unparsed token.
4072 *
4073 * \return A pointer to a return statement.
4074 *
4075 * \retval NULL Unable to parse.
4076 */
parseImportStmtNode(Token *** tokenp)4077 StmtNode *parseImportStmtNode(Token ***tokenp)
4078 {
4079 IdentifierNode *value = NULL;
4080 ImportStmtNode *stmt = NULL;
4081 StmtNode *ret = NULL;
4082 int status;
4083
4084 /* Work from a copy of the token stream in case something goes wrong */
4085 Token **tokens = *tokenp;
4086
4087 #ifdef DEBUG
4088 debug("ST_IMPORT");
4089 #endif
4090
4091 /* Remove the library import keyword from the token stream */
4092 status = acceptToken(&tokens, TT_CANHAS);
4093 if (!status) {
4094 parser_error_expected_token(TT_CANHAS, tokens);
4095 goto parseImportStmtNodeAbort;
4096 }
4097
4098 /* Parse the library name */
4099 value = parseIdentifierNode(&tokens);
4100 if (!value) goto parseImportStmtNodeAbort;
4101
4102 /* Check for the question mark token (currently optional) */
4103 acceptToken(&tokens, TT_QUESTION);
4104
4105 /* The library import statement must reside on its own line */
4106 status = acceptToken(&tokens, TT_NEWLINE);
4107 if (!status) {
4108 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
4109 goto parseImportStmtNodeAbort;
4110 }
4111
4112 /* Create the new ImportStmtNode structure */
4113 stmt = createImportStmtNode(value);
4114 if (!stmt) goto parseImportStmtNodeAbort;
4115
4116 /* Create the new StmtNode structure */
4117 ret = createStmtNode(ST_IMPORT, stmt);
4118 if (!ret) goto parseImportStmtNodeAbort;
4119
4120 /* Since we're successful, update the token stream */
4121 *tokenp = tokens;
4122
4123 return ret;
4124
4125 parseImportStmtNodeAbort: /* Exception handling */
4126
4127 /* Clean up any allocated structures */
4128 if (ret) deleteStmtNode(ret);
4129 else if (stmt) deleteImportStmtNode(stmt);
4130 else {
4131 if (value) deleteIdentifierNode(value);
4132 }
4133 return NULL;
4134 }
4135
4136 /**
4137 * Parses tokens into a statement.
4138 *
4139 * \param [in] tokenp The position in a token list to start parsing at.
4140 *
4141 * \post \a tokenp will point to the next unparsed token.
4142 *
4143 * \return A pointer to a statement.
4144 *
4145 * \retval NULL Unable to parse.
4146 */
parseStmtNode(Token *** tokenp)4147 StmtNode *parseStmtNode(Token ***tokenp)
4148 {
4149 StmtNode *ret = NULL;
4150 ExprNode *expr = NULL;
4151
4152 /* Work from a copy of the token stream in case something goes wrong */
4153 Token **tokens = *tokenp;
4154
4155 #ifdef DEBUG
4156 shiftout();
4157 #endif
4158
4159 /* Parse context-sensitive expressions */
4160 if (peekToken(&tokens, TT_IDENTIFIER)
4161 || peekToken(&tokens, TT_SRS)) {
4162 IdentifierNode *id = NULL;
4163
4164 /* Remove the identifier from the token stream */
4165 id = parseIdentifierNode(&tokens);
4166 if (!id) return NULL;
4167
4168 /* We do not need to hold onto it */
4169 deleteIdentifierNode(id);
4170
4171 /* Casting */
4172 if (peekToken(&tokens, TT_ISNOWA)) {
4173 ret = parseCastStmtNode(tokenp);
4174 }
4175 /* Assignment */
4176 else if (peekToken(&tokens, TT_R)) {
4177 ret = parseAssignmentStmtNode(tokenp);
4178 }
4179 /* Variable declaration */
4180 else if (peekToken(&tokens, TT_HASA)) {
4181 ret = parseDeclarationStmtNode(tokenp);
4182 }
4183 /* Deallocation */
4184 else if (peekToken(&tokens, TT_RNOOB)) {
4185 ret = parseDeallocationStmtNode(tokenp);
4186 }
4187 /* Bare identifier expression */
4188 else {
4189 /* Reset state and continue parsing */
4190 tokens = *tokenp;
4191
4192 #ifdef DEBUG
4193 debug("ST_EXPR");
4194 #endif
4195
4196 /* Parse the expression */
4197 expr = parseExprNode(&tokens);
4198 if (!expr) return NULL;
4199
4200 /* The expression should appear on its own line */
4201 if (!acceptToken(&tokens, TT_NEWLINE)) {
4202 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
4203 deleteExprNode(expr);
4204 return NULL;
4205 }
4206
4207 /* Create the new StmtNode structure */
4208 ret = createStmtNode(ST_EXPR, expr);
4209 if (!ret) {
4210 deleteExprNode(expr);
4211 return NULL;
4212 }
4213
4214 /* Since we're successful, update the token stream */
4215 *tokenp = tokens;
4216 }
4217 }
4218 /* Print */
4219 else if (peekToken(&tokens, TT_VISIBLE)) {
4220 ret = parsePrintStmtNode(tokenp);
4221 }
4222 /* Input */
4223 else if (peekToken(&tokens, TT_GIMMEH)) {
4224 ret = parseInputStmtNode(tokenp);
4225 }
4226 /* If/then/else */
4227 else if (peekToken(&tokens, TT_ORLY)) {
4228 ret = parseIfThenElseStmtNode(tokenp);
4229 }
4230 /* Switch */
4231 else if (peekToken(&tokens, TT_WTF)) {
4232 ret = parseSwitchStmtNode(tokenp);
4233 }
4234 /* Break */
4235 else if (peekToken(&tokens, TT_GTFO)) {
4236 ret = parseBreakStmtNode(tokenp);
4237 }
4238 /* Return */
4239 else if (peekToken(&tokens, TT_FOUNDYR)) {
4240 ret = parseReturnStmtNode(tokenp);
4241 }
4242 /* Loop */
4243 else if (peekToken(&tokens, TT_IMINYR)) {
4244 ret = parseLoopStmtNode(tokenp);
4245 }
4246 /* Function definition */
4247 else if (peekToken(&tokens, TT_HOWIZ)) {
4248 ret = parseFuncDefStmtNode(tokenp);
4249 }
4250 /* Alternate array definition */
4251 else if (peekToken(&tokens, TT_OHAIIM)) {
4252 ret = parseAltArrayDefStmtNode(tokenp);
4253 }
4254 /* Library import statement */
4255 else if (peekToken(&tokens, TT_CANHAS)) {
4256 ret = parseImportStmtNode(tokenp);
4257 }
4258 /* Bare expression */
4259 else if ((expr = parseExprNode(&tokens))) {
4260 int status;
4261
4262 #ifdef DEBUG
4263 debug("ST_EXPR");
4264 #endif
4265
4266 /* The expression should appear on its own line */
4267 status = acceptToken(&tokens, TT_NEWLINE);
4268 if (!status) {
4269 parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
4270 deleteExprNode(expr);
4271 return NULL;
4272 }
4273
4274 /* Create the new StmtNode structure */
4275 ret = createStmtNode(ST_EXPR, expr);
4276 if (!ret) {
4277 deleteExprNode(expr);
4278 return NULL;
4279 }
4280
4281 /* Since we're successful, update the token stream */
4282 *tokenp = tokens;
4283 }
4284 else {
4285 parser_error(PR_EXPECTED_STATEMENT, tokens);
4286 }
4287
4288 #ifdef DEBUG
4289 shiftin();
4290 #endif
4291
4292 return ret;
4293 }
4294
4295 /**
4296 * Parses tokens into a code block.
4297 *
4298 * \param [in] tokenp The position in a token list to start parsing at.
4299 *
4300 * \post \a tokenp will point to the next unparsed token.
4301 *
4302 * \return A pointer to a code block.
4303 *
4304 * \retval NULL Unable to parse.
4305 */
parseBlockNode(Token *** tokenp)4306 BlockNode *parseBlockNode(Token ***tokenp)
4307 {
4308 StmtNodeList *stmts = NULL;
4309 StmtNode *stmt = NULL;
4310 BlockNode *block = NULL;
4311 int status;
4312
4313 /* Work from a copy of the token stream in case something goes wrong */
4314 Token **tokens = *tokenp;
4315
4316 #ifdef DEBUG
4317 shiftout();
4318 debug(">ET_BLOCK");
4319 #endif
4320
4321 /* Create a list of statements */
4322 stmts = createStmtNodeList();
4323 if (!stmts) goto parseBlockNodeAbort;
4324 /* Parse block until certain tokens are found */
4325 while (!peekToken(&tokens, TT_EOF)
4326 && !peekToken(&tokens, TT_KTHXBYE)
4327 && !peekToken(&tokens, TT_OIC)
4328 && !peekToken(&tokens, TT_YARLY)
4329 && !peekToken(&tokens, TT_NOWAI)
4330 && !peekToken(&tokens, TT_MEBBE)
4331 && !peekToken(&tokens, TT_OMG)
4332 && !peekToken(&tokens, TT_OMGWTF)
4333 && !peekToken(&tokens, TT_IMOUTTAYR)
4334 && !peekToken(&tokens, TT_IFUSAYSO)
4335 && !peekToken(&tokens, TT_KTHX)) {
4336 /* Parse the next statement */
4337 stmt = parseStmtNode(&tokens);
4338 if (!stmt) goto parseBlockNodeAbort;
4339
4340 /* Add the statement to the list */
4341 status = addStmtNode(stmts, stmt);
4342 if (!status) goto parseBlockNodeAbort;
4343 stmt = NULL;
4344 }
4345
4346 #ifdef DEBUG
4347 debug("<ET_BLOCK");
4348 shiftin();
4349 #endif
4350
4351 /* Create the BlockNode structure */
4352 block = createBlockNode(stmts);
4353 if (!block) goto parseBlockNodeAbort;
4354
4355 /* Since we're successful, update the token stream */
4356 *tokenp = tokens;
4357
4358 return block;
4359
4360 parseBlockNodeAbort: /* Exception handling */
4361
4362 /* Clean up any allocated structures */
4363 if (block) deleteBlockNode(block);
4364 else {
4365 if (stmt) deleteStmtNode(stmt);
4366 if (stmts) deleteStmtNodeList(stmts);
4367 }
4368 return NULL;
4369 }
4370
4371 /**
4372 * Parses tokens into a main code block.
4373 *
4374 * \param [in] tokens The position in a token list to start parsing at.
4375 *
4376 * \post \a tokenp will point to the next unparsed token.
4377 *
4378 * \return A pointer to a main node block.
4379 *
4380 * \retval NULL Unable to parse.
4381 */
parseMainNode(Token ** tokens)4382 MainNode *parseMainNode(Token **tokens)
4383 {
4384 BlockNode *block = NULL;
4385 MainNode *_main = NULL;
4386 int status;
4387
4388 /* All programs must start with the HAI token */
4389 status = acceptToken(&tokens, TT_HAI);
4390 if (!status) {
4391 parser_error_expected_token(TT_HAI, tokens);
4392 goto parseMainNodeAbort;
4393 }
4394
4395 /* Accept any version */
4396 tokens++;
4397
4398 #ifdef DEBUG
4399 debug("ET_MAINBLOCK");
4400 #endif
4401
4402 /* Make sure the header line ends with a newline */
4403 status = acceptToken(&tokens, TT_NEWLINE);
4404 if (!status) {
4405 parser_error(PR_EXPECTED_END_OF_STATEMENT, tokens);
4406 goto parseMainNodeAbort;
4407 }
4408
4409 /* Parse the main block of code */
4410 block = parseBlockNode(&tokens);
4411 if (!block) goto parseMainNodeAbort;
4412
4413 /* Make sure the program ends with KTHXBYE */
4414 status = acceptToken(&tokens, TT_KTHXBYE);
4415 if (!status) {
4416 parser_error_expected_token(TT_KTHXBYE, tokens);
4417 goto parseMainNodeAbort;
4418 }
4419
4420 /* Create the MainBlockNode structure */
4421 _main = createMainNode(block);
4422 if (!_main) goto parseMainNodeAbort;
4423
4424 return _main;
4425
4426 parseMainNodeAbort: /* In case something goes wrong... */
4427
4428 /* Clean up any allocated structures */
4429 if (_main) deleteMainNode(_main);
4430 else if (block) deleteBlockNode(block);
4431
4432 return NULL;
4433 }
4434