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