Bug Summary

File:src/mod/applications/mod_expr/exprpars.c
Location:line 1333, column 19
Description:Array access (from variable 'reftmp') results in a null pointer dereference

Annotated Source Code

1/*
2 File: exprpars.c
3 Auth: Brian Allen Vanderburg II
4 Date: Wednesday, April 30, 2003
5 Desc: Actual parsing routines for this library
6
7 This file is part of ExprEval.
8*/
9
10/* Includes */
11#include "exprincl.h"
12
13#include "exprpriv.h"
14#include "exprmem.h"
15
16/* Data structure used by parser */
17typedef struct _exprToken {
18 int type; /* token type */
19 int start; /* token start position */
20 int end; /* token end position */
21
22 union _tdata {
23 char *str; /* string data */
24 EXPRTYPE val; /* value data */
25 } data;
26} exprToken;
27
28/* Defines for token types */
29#define EXPR_TOKEN_UNKNOWN0 0
30#define EXPR_TOKEN_OPAREN1 1
31#define EXPR_TOKEN_CPAREN2 2
32#define EXPR_TOKEN_IDENTIFIER3 3
33#define EXPR_TOKEN_VALUE4 4
34#define EXPR_TOKEN_PLUS5 5
35#define EXPR_TOKEN_HYPHEN6 6
36#define EXPR_TOKEN_ASTERISK7 7
37#define EXPR_TOKEN_FSLASH8 8
38#define EXPR_TOKEN_AMPERSAND9 9
39#define EXPR_TOKEN_SEMICOLON10 10
40#define EXPR_TOKEN_COMMA11 11
41#define EXPR_TOKEN_EQUAL12 12
42#define EXPR_TOKEN_HAT13 13
43
44/* Internal functions */
45int exprMultiParse(exprObj * obj, exprNode * node, exprToken * tokens, int count);
46int exprInternalParse(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end);
47int exprInternalParseAssign(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index);
48int exprInternalParseAdd(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index);
49int exprInternalParseSub(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index);
50int exprInternalParseMul(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index);
51int exprInternalParseDiv(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index);
52int exprInternalParsePosNeg(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index);
53int exprInternalParseExp(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index);
54int exprInternalParseFunction(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int p1, int p2);
55int exprInternalParseVarVal(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end);
56int exprStringToTokenList(exprObj * obj, char *expr, exprToken ** tokens, int *count);
57void exprFreeTokenList(exprToken * tokens, int count);
58
59/* This frees a token list */
60void exprFreeTokenList(exprToken * tokens, int count)
61{
62 int pos;
63
64 if (tokens == NULL((void*)0))
65 return;
66
67 for (pos = 0; pos < count; pos++) {
68 if (tokens[pos].type == EXPR_TOKEN_IDENTIFIER3)
69 exprFreeMem(tokens[pos].data.str);
70 }
71
72 exprFreeMem(tokens);
73}
74
75/* This converts an expression string to a token list */
76int exprStringToTokenList(exprObj * obj, char *expr, exprToken ** tokens, int *count)
77{
78 int found;
79 exprToken *list;
80 int pass;
81 int pos, len;
82 int tpos;
83 int comment; /* Is a comment active */
84 int start, ilen;
85 char buf[EXPR_MAXIDENTSIZE255 + 1];
86
87 /* Set initial variables */
88 found = 0;
89 tpos = 0;
90 list = NULL((void*)0);
91 comment = 0;
92 *tokens = NULL((void*)0);
93 *count = 0;
94
95
96 /* Check string length */
97 len = (int) strlen(expr);
98 if (len == 0)
99 return EXPR_ERROR_EMPTYEXPR;
100
101 /* Two passes, one to count, one to tokenize */
102 for (pass = 0; pass <= 1; pass++) {
103 for (pos = 0; pos < len; pos++) {
104 switch (expr[pos]) {
105 /* Comment */
106 case '#':
107 {
108 /* Only set it if a comment is not already active */
109 if (!comment)
110 comment = 1;
111
112 break;
113 }
114
115 /* Newline characters turn off comments */
116 case '\r':
117 case '\n':
118 {
119 /* If a comment is active, unset it */
120 if (comment)
121 comment = 0;
122
123 break;
124 }
125
126 /* Open parenthesis */
127 case '(':
128 {
129 if (!comment) {
130 if (pass == 0)
131 found++;
132 else {
133 list[tpos].type = EXPR_TOKEN_OPAREN1;
134 list[tpos].start = pos;
135 list[tpos].end = pos;
136 tpos++;
137 }
138 }
139
140 break;
141 }
142
143 /* Close parenthesis */
144 case ')':
145 {
146 if (!comment) {
147 if (pass == 0)
148 found++;
149 else {
150 list[tpos].type = EXPR_TOKEN_CPAREN2;
151 list[tpos].start = pos;
152 list[tpos].end = pos;
153 tpos++;
154 }
155 }
156
157 break;
158 }
159
160 /* Plus */
161 case '+':
162 {
163 if (!comment) {
164 if (pass == 0)
165 found++;
166 else {
167 list[tpos].type = EXPR_TOKEN_PLUS5;
168 list[tpos].start = pos;
169 list[tpos].end = pos;
170 tpos++;
171 }
172 }
173
174 break;
175 }
176
177 /* Hyphen */
178 case '-':
179 {
180 if (!comment) {
181 if (pass == 0)
182 found++;
183 else {
184 list[tpos].type = EXPR_TOKEN_HYPHEN6;
185 list[tpos].start = pos;
186 list[tpos].end = pos;
187 tpos++;
188 }
189 }
190
191 break;
192 }
193
194 /* Asterisk */
195 case '*':
196 {
197 if (!comment) {
198 if (pass == 0)
199 found++;
200 else {
201 list[tpos].type = EXPR_TOKEN_ASTERISK7;
202 list[tpos].start = pos;
203 list[tpos].end = pos;
204 tpos++;
205 }
206 }
207
208 break;
209 }
210
211 /* Forward slash */
212 case '/':
213 {
214 if (!comment) {
215 if (pass == 0)
216 found++;
217 else {
218 list[tpos].type = EXPR_TOKEN_FSLASH8;
219 list[tpos].start = pos;
220 list[tpos].end = pos;
221 tpos++;
222 }
223 }
224
225 break;
226 }
227
228 /* Hat */
229 case '^':
230 {
231 if (!comment) {
232 if (pass == 0)
233 found++;
234 else {
235 list[tpos].type = EXPR_TOKEN_HAT13;
236 list[tpos].start = pos;
237 list[tpos].end = pos;
238 tpos++;
239 }
240 }
241
242 break;
243 }
244
245 /* Ampersand */
246 case '&':
247 {
248 if (!comment) {
249 if (pass == 0)
250 found++;
251 else {
252 list[tpos].type = EXPR_TOKEN_AMPERSAND9;
253 list[tpos].start = pos;
254 list[tpos].end = pos;
255 tpos++;
256 }
257 }
258
259 break;
260 }
261
262 /* Semicolon */
263 case ';':
264 {
265 if (!comment) {
266 if (pass == 0)
267 found++;
268 else {
269 list[tpos].type = EXPR_TOKEN_SEMICOLON10;
270 list[tpos].start = pos;
271 list[tpos].end = pos;
272 tpos++;
273 }
274 }
275
276 break;
277 }
278
279 /* Comma */
280 case ',':
281 {
282 if (!comment) {
283 if (pass == 0)
284 found++;
285 else {
286 list[tpos].type = EXPR_TOKEN_COMMA11;
287 list[tpos].start = pos;
288 list[tpos].end = pos;
289 tpos++;
290 }
291 }
292
293 break;
294 }
295
296 /* Equal sign */
297 case '=':
298 {
299 if (!comment) {
300 if (pass == 0)
301 found++;
302 else {
303 list[tpos].type = EXPR_TOKEN_EQUAL12;
304 list[tpos].start = pos;
305 list[tpos].end = pos;
306 tpos++;
307 }
308 }
309
310 break;
311 }
312
313 /* Identifiers and values */
314 default:
315 {
316 if (!comment) {
317 if (expr[pos] == '.' || switch_isdigit(expr[pos])) {
318 /* Value */
319 start = pos;
320
321 /* Find digits before a period */
322 while (switch_isdigit(expr[pos]))
323 pos++;
324
325 /* Find a period */
326 if (expr[pos] == '.')
327 pos++;
328
329 /* Find digits after a period */
330 while (switch_isdigit(expr[pos]))
331 pos++;
332
333 /* pos is AFTER last item, back up */
334 pos--;
335
336 if (pass == 0)
337 found++;
338 else {
339 ilen = pos - start + 1;
340
341 /* Is the value to large */
342 if (ilen > EXPR_MAXIDENTSIZE255) {
343 obj->starterr = start;
344 obj->enderr = pos;
345 exprFreeTokenList(list, found);
346 return EXPR_ERROR_BADIDENTIFIER;
347 }
348
349 /* Create value token */
350 strncpy(buf, expr + start, ilen)__builtin_strncpy (buf, expr + start, ilen);
351 buf[ilen] = '\0';
352
353 list[tpos].type = EXPR_TOKEN_VALUE4;
354 list[tpos].start = start;
355 list[tpos].end = pos;
356 list[tpos].data.val = (EXPRTYPE) atof(buf);
357 tpos++;
358 }
359 } else if (expr[pos] == '_' || switch_isalpha(expr[pos])) {
360 /* Identifier */
361 start = pos;
362
363 /* Find rest of identifier */
364 while (expr[pos] == '_' || switch_isalnum(expr[pos]))
365 pos++;
366
367 /* pos is AFTER last item, back up */
368 pos--;
369
370 if (pass == 0)
371 found++;
372 else {
373 ilen = pos - start + 1;
374
375 /* Is the value to large */
376 if (ilen > EXPR_MAXIDENTSIZE255) {
377 obj->starterr = start;
378 obj->enderr = pos;
379 exprFreeTokenList(list, found);
380 return EXPR_ERROR_BADIDENTIFIER;
381 }
382
383 /* Create value token */
384 strncpy(buf, expr + start, ilen)__builtin_strncpy (buf, expr + start, ilen);
385 buf[ilen] = '\0';
386
387 /* Allocate memory for identifier */
388 list[tpos].data.str = exprAllocMem(ilen + 1);
389 if (list[tpos].data.str == NULL((void*)0)) {
390 exprFreeTokenList(list, found);
391 return EXPR_ERROR_MEMORY;
392 }
393
394 list[tpos].type = EXPR_TOKEN_IDENTIFIER3;
395 list[tpos].start = start;
396 list[tpos].end = pos;
397 strcpy(list[tpos].data.str, buf);
398 tpos++;
399 }
400 } else if (switch_isspace(expr[pos])) {
401 /* Spaces are ignored, do nothing */
402 } else {
403 /* Unknown */
404 obj->starterr = obj->enderr = pos;
405 exprFreeTokenList(list, found);
406 return EXPR_ERROR_INVALIDCHAR;
407 }
408 }
409
410 break;
411 }
412 }
413 }
414
415 /* If pass is 0, allocate memory for next pass */
416 if (pass == 0) {
417 /* First, make sure all comments were ended */
418 if (comment)
419 comment = 0;
420
421 /* Make sure the expression is not empty */
422 if (found == 0)
423 return EXPR_ERROR_EMPTYEXPR;
424
425 /* Allocate memory for token list */
426 list = exprAllocMem(found * sizeof(exprToken));
427 if (list == NULL((void*)0))
428 return EXPR_ERROR_MEMORY;
429
430 tpos = 0;
431 }
432 }
433
434 *count = found;
435 *tokens = list;
436 return EXPR_ERROR_NOERROR;
437}
438
439
440/* This is the main parsing routine */
441int exprParse(exprObj * obj, char *expr)
442{
443 exprToken *tokens;
444 int count;
445 int err;
446 exprNode *tmp;
447
448 /* Make sure an object was passed */
449 if (obj == NULL((void*)0))
450 return EXPR_ERROR_NULLPOINTER;
451
452 /* Clear expression error position */
453 obj->starterr = obj->enderr = -1;
454
455 /* Have we already been parsed? */
456 if (obj->parsedbad != 0)
457 return EXPR_ERROR_ALREADYPARSEDBAD;
458
459 if (obj->parsedgood != 0)
460 return EXPR_ERROR_ALREADYPARSEDGOOD;
461
462 /* Make sure an expression was passed */
463 if (expr == NULL((void*)0))
464 return EXPR_ERROR_NULLPOINTER;
465
466 /* Create token list */
467 err = exprStringToTokenList(obj, expr, &tokens, &count);
468 if (err != EXPR_ERROR_NOERROR)
469 return err;
470
471 /* Create head pointer */
472 tmp = exprAllocNodes(1);
473 if (tmp == NULL((void*)0)) {
474 exprFreeTokenList(tokens, count);
475 return EXPR_ERROR_MEMORY;
476 }
477
478 obj->headnode = tmp;
479
480 /* Call the multiparse routine to parse subexpressions */
481 err = exprMultiParse(obj, tmp, tokens, count);
482
483 /* Free the token list */
484 exprFreeTokenList(tokens, count);
485
486 /* successful parse? */
487 if (err == EXPR_ERROR_NOERROR) {
488 obj->parsedgood = 1;
489 obj->parsedbad = 0;
490 } else {
491 obj->parsedbad = 1;
492 obj->parsedgood = 0;
493 }
494
495 return err;
496}
497
498
499/* Parse the subexpressions, each ending with semicolons */
500int exprMultiParse(exprObj * obj, exprNode * node, exprToken * tokens, int count)
501{
502 int pos, plevel, last;
503 int num, cur, err;
504 exprNode *tmp;
505
506 plevel = 0;
507 num = 0;
508 last = -1;
509
510 /* First count the number of arguments */
511 for (pos = 0; pos < count; pos++) {
512 switch (tokens[pos].type) {
513 case EXPR_TOKEN_OPAREN1:
514 /* increase plevel */
515 plevel++;
516 break;
517
518 case EXPR_TOKEN_CPAREN2:
519 /* decrease plevel */
520 plevel--;
521
522 if (plevel < 0) {
523 obj->starterr = tokens[pos].start;
524 obj->enderr = tokens[pos].end;
525 return EXPR_ERROR_UNMATCHEDPAREN;
526 }
527
528 break;
529
530 case EXPR_TOKEN_SEMICOLON10:
531 if (plevel == 0) {
532 if (last == pos - 1 || pos == 0) {
533 /* last semicolon is before us or we are at the start */
534 obj->starterr = tokens[pos].start;
535 obj->enderr = tokens[pos].end;
536 return EXPR_ERROR_SYNTAX;
537 } else {
538 /* last semicolon is not right before us */
539 num++;
540 }
541 } else {
542 /* Semicolon should not be in a parenthesis */
543 obj->starterr = tokens[pos].start;
544 obj->enderr = tokens[pos].end;
545 return EXPR_ERROR_SYNTAX;
546 }
547
548 last = pos; /* update position of last semicolon */
549 break;
550 }
551 }
552
553 /* plevel should be zero now */
554 if (plevel != 0)
555 return EXPR_ERROR_UNMATCHEDPAREN;
556
557 /* the last character should be a semicolon */
558 if (last != pos - 1)
559 return EXPR_ERROR_MISSINGSEMICOLON;
560
561 /* Now we know how many arguments there are */
562
563 /* Allocate array of subnodes */
564 tmp = exprAllocNodes(num);
565 if (tmp == NULL((void*)0))
566 return EXPR_ERROR_MEMORY;
567
568 /* Set the current node's data */
569 node->type = EXPR_NODETYPE_MULTI;
570 node->data.oper.nodes = tmp;
571 node->data.oper.nodecount = num;
572
573 /* now we parse each subexpression */
574 last = 0; /* Not for last semicolon, but for first char of subexpr */
575 cur = 0;
576
577 for (pos = 0; pos < count; pos++) {
578 if (tokens[pos].type == EXPR_TOKEN_SEMICOLON10) {
579 /* Everything from last up to pos - 1 is a parameter */
580 err = exprInternalParse(obj, &(tmp[cur]), tokens, last, pos - 1);
581 if (err != EXPR_ERROR_NOERROR)
582 return err;
583
584 /* Update last position and current argument */
585 last = pos + 1;
586 cur++;
587 }
588 }
589
590 return EXPR_ERROR_NOERROR;
591}
592
593/* This function parses each subnode and recurses if needed */
594int exprInternalParse(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end)
595{
596 int pos;
597 int plevel = 0; /* Paren level */
598 int fgopen = -1; /* First paren group open index */
599 int fgclose = -1; /* First paren group close index */
600 int assignindex = -1; /* First = at plevel 0 for assignment */
601 int addsubindex = -1; /* Last + or - at plevel 0 for adding or subtracting */
602 int muldivindex = -1; /* Last * or / at plevel 0 for multiplying or dividing */
603 int expindex = -1; /* Last ^ fount at plevel 0 for exponents */
604 int posnegindex = -1; /* First +,- at plevel 0 for positive,negative */
605
606 /* Make sure some conditions are right */
607 if (start > end)
608 return EXPR_ERROR_UNKNOWN;
609
610 /* Scan the string for certain characters */
611 for (pos = start; pos <= end; pos++) {
612 switch (tokens[pos].type) {
613 case EXPR_TOKEN_OPAREN1:
614 plevel++;
615
616 /* First group open? */
617 if (plevel == 1 && fgopen == -1)
618 fgopen = pos;
619 break;
620
621 case EXPR_TOKEN_CPAREN2:
622 plevel--;
623
624 /* First group close? */
625 if (plevel == 0 && fgclose == -1)
626 fgclose = pos;
627
628 if (plevel < 0) {
629 obj->starterr = tokens[pos].start;
630 obj->enderr = tokens[pos].end;
631 return EXPR_ERROR_UNMATCHEDPAREN;
632 }
633 break;
634
635 case EXPR_TOKEN_EQUAL12:
636 /* Assignment found */
637 if (plevel == 0) {
638 if (assignindex == -1)
639 assignindex = pos;
640 }
641 break;
642
643 case EXPR_TOKEN_ASTERISK7:
644 case EXPR_TOKEN_FSLASH8:
645 /* Multiplication or division */
646 if (plevel == 0)
647 muldivindex = pos;
648 break;
649
650 case EXPR_TOKEN_HAT13:
651 /* Exponent */
652 if (plevel == 0)
653 expindex = pos;
654 break;
655
656
657 case EXPR_TOKEN_PLUS5:
658 case EXPR_TOKEN_HYPHEN6:
659 /* Addition or positive or subtraction or negative */
660 if (plevel == 0) {
661 if (pos == start) {
662 /* At the start area, positive/negative */
663 if (posnegindex == -1)
664 posnegindex = pos;
665 } else {
666 /* Not at start, check item in front */
667 switch (tokens[pos - 1].type) {
668 case EXPR_TOKEN_EQUAL12: /* Equal sign */
669 case EXPR_TOKEN_PLUS5: /* Add/positive sign */
670 case EXPR_TOKEN_HYPHEN6: /* Subtract/negative sign */
671 case EXPR_TOKEN_ASTERISK7: /* Multiply sign */
672 case EXPR_TOKEN_FSLASH8: /* Divide sign */
673 case EXPR_TOKEN_HAT13: /* Exponent sign */
674
675 /* After theses, it is positive/negative */
676 if (posnegindex == -1)
677 posnegindex = pos;
678
679 break;
680
681 default:
682 /* Otherwise it is addition/subtraction */
683 addsubindex = pos;
684 break;
685 }
686 }
687 }
688 break;
689
690 }
691 }
692
693 /* plevel should now be zero */
694 if (plevel != 0)
695 return EXPR_ERROR_UNMATCHEDPAREN;
696
697 /* We must parse the data in a certain order to maintain the
698 correct order of operators at evaluation time */
699
700 /* First, take care of assignment */
701 if (assignindex != -1)
702 return exprInternalParseAssign(obj, node, tokens, start, end, assignindex);
703
704 /* Addition or subtraction is next */
705 if (addsubindex != -1) {
706 if (tokens[addsubindex].type == EXPR_TOKEN_PLUS5)
707 return exprInternalParseAdd(obj, node, tokens, start, end, addsubindex);
708 else
709 return exprInternalParseSub(obj, node, tokens, start, end, addsubindex);
710 }
711
712
713 /* Multiplycation or division */
714 if (muldivindex != -1) {
715 if (tokens[muldivindex].type == EXPR_TOKEN_ASTERISK7)
716 return exprInternalParseMul(obj, node, tokens, start, end, muldivindex);
717 else
718 return exprInternalParseDiv(obj, node, tokens, start, end, muldivindex);
719 }
720
721 /* Exponent */
722 if (expindex != -1)
723 return exprInternalParseExp(obj, node, tokens, start, end, expindex);
724
725 /* Negation */
726 if (posnegindex != -1)
727 return exprInternalParsePosNeg(obj, node, tokens, start, end, posnegindex);
728
729
730 /* Grouped parenthesis */
731 if (fgopen == start) {
732 /* Closing paren. should be at the end */
733 if (fgclose == end) {
734 /* Anything between them */
735 if (fgclose > fgopen + 1) {
736 return exprInternalParse(obj, node, tokens, fgopen + 1, fgclose - 1);
737 } else {
738 /* Nothing between them */
739 obj->starterr = tokens[fgopen].start;
740 obj->enderr = tokens[fgclose].end;
741 return EXPR_ERROR_SYNTAX;
742 }
743 } else /* Closing paren not at the end */
744 return EXPR_ERROR_SYNTAX;
745 }
746
747 /* Functions */
748 if (fgopen > start) {
749 /* Closing paren should be at end */
750 if (fgclose == end) {
751 return exprInternalParseFunction(obj, node, tokens, start, end, fgopen, fgclose);
752 } else /* Closing paren not at end */
753 return EXPR_ERROR_SYNTAX;
754 }
755
756 /* If it was none of the above, it must be a variable or value */
757 return exprInternalParseVarVal(obj, node, tokens, start, end);
758}
759
760/* Function to parse an assignment node */
761int exprInternalParseAssign(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index)
762{
763 exprNode *tmp;
764 exprValList *l;
765 EXPRTYPE *addr;
766
767 /* Make sure the equal sign is not at the start or end */
768 if (index != start + 1 || index >= end) {
769 obj->starterr = tokens[index].start;
770 obj->enderr = tokens[index].end;
771 return EXPR_ERROR_SYNTAX;
772 }
773
774 /* Make sure item before equal sign is an identifier */
775 if (tokens[index - 1].type != EXPR_TOKEN_IDENTIFIER3) {
776 obj->starterr = tokens[index - 1].start;
777 obj->enderr = tokens[index].end;
778 return EXPR_ERROR_SYNTAX;
779 }
780
781 /* Create expression subnode */
782 tmp = exprAllocNodes(1);
783 if (tmp == NULL((void*)0)) {
784 return EXPR_ERROR_MEMORY;
785 }
786
787
788 /* Set the data */
789 node->type = EXPR_NODETYPE_ASSIGN;
790 node->data.assign.node = tmp;
791
792
793 /*
794 The fast access method directly accesses the memory address
795 of the variable's value at evaluation time. Because of this,
796 we must make sure the variable does exists in the variable list.
797 */
798
799 /* Make sure name is not a constant name */
800 l = exprGetConstList(obj);
801 if (l) {
802 exprValListGetAddress(l, tokens[index - 1].data.str, &addr);
803 if (addr) {
804 obj->starterr = tokens[index - 1].start;
805 obj->enderr = tokens[index].end;
806 return EXPR_ERROR_CONSTANTASSIGN;
807 }
808 }
809
810 /* Get the variable list */
811 l = exprGetVarList(obj);
812 if (l == NULL((void*)0))
813 return EXPR_ERROR_NOVARLIST;
814
815 /* Get variable address if already in the list */
816 exprValListGetAddress(l, tokens[index - 1].data.str, &addr);
817 if (addr == NULL((void*)0)) { /* Variable not in the list, add it */
818 exprValListAdd(l, tokens[index - 1].data.str, 0.0);
819
820 /* Try to get address again */
821 exprValListGetAddress(l, tokens[index - 1].data.str, &addr);
822 if (addr == NULL((void*)0)) /* Could not add variable */
823 return EXPR_ERROR_MEMORY; /* Could not add variable to list */
824 }
825
826 node->data.assign.vaddr = addr;
827
828 /* Parse the subnode */
829 return exprInternalParse(obj, tmp, tokens, index + 1, end);
830}
831
832/* Function to parse an addition operator */
833int exprInternalParseAdd(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index)
834{
835 exprNode *tmp;
836 int err;
837
838 /* Make sure plus sign is at a good place */
839 if (index <= start || index >= end) {
840 obj->starterr = tokens[index].start;
841 obj->enderr = tokens[index].end;
842 return EXPR_ERROR_SYNTAX;
843 }
844
845 /* Allocate space for 2 subnodes */
846 tmp = exprAllocNodes(2);
847 if (tmp == NULL((void*)0))
848 return EXPR_ERROR_MEMORY;
849
850
851 /* Set the data */
852 node->type = EXPR_NODETYPE_ADD;
853 node->data.oper.nodes = tmp;
854 node->data.oper.nodecount = 2;
855
856 /* parse the left side */
857 err = exprInternalParse(obj, &(tmp[0]), tokens, start, index - 1);
858 if (err != EXPR_ERROR_NOERROR)
859 return err;
860
861 /* parse the right side */
862 return exprInternalParse(obj, &(tmp[1]), tokens, index + 1, end);
863}
864
865/* Function to parse a subtraction operator */
866int exprInternalParseSub(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index)
867{
868 exprNode *tmp;
869 int err;
870
871 /* Make sure minus sign is at a good place */
872 if (index <= start || index >= end) {
873 obj->starterr = tokens[index].start;
874 obj->enderr = tokens[index].end;
875 return EXPR_ERROR_SYNTAX;
876 }
877
878 /* Allocate space for 2 subnodes */
879 tmp = exprAllocNodes(2);
880 if (tmp == NULL((void*)0))
881 return EXPR_ERROR_MEMORY;
882
883
884 /* Set the data */
885 node->type = EXPR_NODETYPE_SUBTRACT;
886 node->data.oper.nodes = tmp;
887 node->data.oper.nodecount = 2;
888
889 /* parse the left side */
890 err = exprInternalParse(obj, &(tmp[0]), tokens, start, index - 1);
891 if (err != EXPR_ERROR_NOERROR)
892 return err;
893
894 /* parse the right side */
895 return exprInternalParse(obj, &(tmp[1]), tokens, index + 1, end);
896}
897
898/* Function to parse a multiplication operator */
899int exprInternalParseMul(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index)
900{
901 exprNode *tmp;
902 int err;
903
904 /* Make sure times sign is at a good place */
905 if (index <= start || index >= end) {
906 obj->starterr = tokens[index].start;
907 obj->enderr = tokens[index].end;
908 return EXPR_ERROR_SYNTAX;
909 }
910
911
912 /* Allocate space for 2 subnodes */
913 tmp = exprAllocNodes(2);
914 if (tmp == NULL((void*)0))
915 return EXPR_ERROR_MEMORY;
916
917
918 /* Set the data */
919 node->type = EXPR_NODETYPE_MULTIPLY;
920 node->data.oper.nodes = tmp;
921 node->data.oper.nodecount = 2;
922
923 /* parse the left side */
924 err = exprInternalParse(obj, &(tmp[0]), tokens, start, index - 1);
925 if (err != EXPR_ERROR_NOERROR)
926 return err;
927
928 /* parse the right side */
929 return exprInternalParse(obj, &(tmp[1]), tokens, index + 1, end);
930}
931
932/* Function to parse a division operator */
933int exprInternalParseDiv(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index)
934{
935 exprNode *tmp;
936 int err;
937
938 /* Make sure slash sign is at a good place */
939 if (index <= start || index >= end) {
940 obj->starterr = tokens[index].start;
941 obj->enderr = tokens[index].end;
942 return EXPR_ERROR_SYNTAX;
943 }
944
945
946 /* Allocate space for 2 subnodes */
947 tmp = exprAllocNodes(2);
948 if (tmp == NULL((void*)0))
949 return EXPR_ERROR_MEMORY;
950
951
952 /* Set the data */
953 node->type = EXPR_NODETYPE_DIVIDE;
954 node->data.oper.nodes = tmp;
955 node->data.oper.nodecount = 2;
956
957 /* parse the left side */
958 err = exprInternalParse(obj, &(tmp[0]), tokens, start, index - 1);
959 if (err != EXPR_ERROR_NOERROR)
960 return err;
961
962 /* parse the right side */
963 return exprInternalParse(obj, &(tmp[1]), tokens, index + 1, end);
964}
965
966/* Function to parse an exponent operator */
967int exprInternalParseExp(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index)
968{
969 exprNode *tmp;
970 int err;
971
972 /* Make sure exponent sign is at a good place */
973 if (index <= start || index >= end) {
974 obj->starterr = tokens[index].start;
975 obj->enderr = tokens[index].end;
976 return EXPR_ERROR_SYNTAX;
977 }
978
979
980 /* Allocate space for 2 subnodes */
981 tmp = exprAllocNodes(2);
982 if (tmp == NULL((void*)0))
983 return EXPR_ERROR_MEMORY;
984
985
986 /* Set the data */
987 node->type = EXPR_NODETYPE_EXPONENT;
988 node->data.oper.nodes = tmp;
989 node->data.oper.nodecount = 2;
990
991 /* parse the left side */
992 err = exprInternalParse(obj, &(tmp[0]), tokens, start, index - 1);
993 if (err != EXPR_ERROR_NOERROR)
994 return err;
995
996 /* parse the right side */
997 return exprInternalParse(obj, &(tmp[1]), tokens, index + 1, end);
998}
999
1000/* Function to parse for positive and negative */
1001int exprInternalParsePosNeg(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int index)
1002{
1003 exprNode *tmp;
1004
1005 /* Position should be the same as start */
1006 if (index != start) {
1007 obj->starterr = tokens[index].start;
1008 obj->enderr = tokens[index].end;
1009 return EXPR_ERROR_UNKNOWN;
1010 }
1011
1012 /* If it is a positive, just parse the internal of it */
1013 if (tokens[index].type == EXPR_TOKEN_PLUS5)
1014 return exprInternalParse(obj, node, tokens, index + 1, end);
1015 else {
1016 /* Allocate subnode */
1017 tmp = exprAllocNodes(1);
1018 if (tmp == NULL((void*)0))
1019 return EXPR_ERROR_NOERROR;
1020
1021
1022 /* Set data */
1023 node->type = EXPR_NODETYPE_NEGATE;
1024 node->data.oper.nodes = tmp;
1025 node->data.oper.nodecount = 1;
1026
1027 /* Parse the subnode */
1028 return exprInternalParse(obj, tmp, tokens, index + 1, end);
1029 }
1030}
1031
1032/* Function will parse a call to a function */
1033int exprInternalParseFunction(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end, int p1, int p2)
1034{
1035 int pos;
1036 int num, cur;
1037 int refnum, refcur;
1038 int plevel = 0;
1039 int lv, err;
1040 exprNode *tmp;
1041 exprFuncType fptr;
1042 int argmin, argmax;
1043 int refargmin, refargmax;
1044 int type;
1045 exprFuncList *l;
1046 exprValList *vars;
1047 EXPRTYPE *addr;
1048 EXPRTYPE **reftmp;
1049
1050 /* We should have a function list */
1051 l = exprGetFuncList(obj);
1052 if (l == NULL((void*)0))
1
Assuming 'l' is not equal to null
2
Taking false branch
1053 return EXPR_ERROR_NOSUCHFUNCTION;
1054
1055 /* check paren. location */
1056 if (p2 <= p1)
3
Taking false branch
1057 return EXPR_ERROR_SYNTAX;
1058
1059 /* second paren. should not be after the end */
1060 if (p2 > end)
4
Taking false branch
1061 return EXPR_ERROR_SYNTAX;
1062
1063 /* Item before parenthesis should be an identifier */
1064 if (tokens[p1 - 1].type != EXPR_TOKEN_IDENTIFIER3) {
5
Taking false branch
1065 obj->starterr = tokens[p1 - 1].start;
1066 obj->enderr = tokens[p1].end;
1067 return EXPR_ERROR_SYNTAX;
1068 }
1069
1070
1071 /* Look up the function */
1072 err = exprFuncListGet(l, tokens[p1 - 1].data.str, &fptr, &type, &argmin, &argmax, &refargmin, &refargmax);
1073 if (err != EXPR_ERROR_NOERROR) {
6
Assuming 'err' is equal to EXPR_ERROR_NOERROR
7
Taking false branch
1074 if (err == EXPR_ERROR_NOTFOUND) {
1075 obj->starterr = tokens[p1 - 1].start;
1076 obj->enderr = tokens[p1 - 1].end;
1077 return EXPR_ERROR_NOSUCHFUNCTION;
1078 } else
1079 return err;
1080 }
1081
1082 /* Make sure the function exists */
1083 if (fptr == NULL((void*)0) && type == 0) {
8
Assuming 'fptr' is not equal to null
1084 obj->starterr = tokens[p1 - 1].start;
1085 obj->enderr = tokens[p1 - 1].end;
1086 return EXPR_ERROR_NOSUCHFUNCTION;
1087 }
1088
1089 /* Count arguments */
1090 if (p2 == p1 + 1) {
9
Taking false branch
1091 num = 0;
1092 refnum = 0;
1093 } else {
1094 num = 1;
1095 refnum = 0;
1096
1097
1098 /* count commas */
1099 for (pos = p1 + 1; pos < p2; pos++) {
10
Loop condition is false. Execution continues on line 1134
1100 switch (tokens[pos].type) {
1101 case EXPR_TOKEN_OPAREN1:
1102 plevel++;
1103 break;
1104
1105 case EXPR_TOKEN_CPAREN2:
1106 plevel--;
1107 if (plevel < 0) {
1108 obj->starterr = tokens[pos].start;
1109 obj->enderr = tokens[pos].end;
1110 return EXPR_ERROR_UNMATCHEDPAREN;
1111 }
1112 break;
1113
1114 case EXPR_TOKEN_COMMA11:
1115 /* Found comma */
1116 if (plevel == 0)
1117 num++;
1118 break;
1119
1120 case EXPR_TOKEN_AMPERSAND9:
1121 /* Found reference mark */
1122 if (plevel == 0) {
1123 /* This may only occur after the open parenthesis or comma */
1124 if (tokens[pos - 1].type == EXPR_TOKEN_OPAREN1 || tokens[pos - 1].type == EXPR_TOKEN_COMMA11)
1125 refnum++;
1126 else
1127 return EXPR_ERROR_SYNTAX;
1128 }
1129 break;
1130 }
1131 }
1132
1133 /* plevel should be zero */
1134 if (plevel != 0)
11
Taking false branch
1135 return EXPR_ERROR_UNMATCHEDPAREN;
1136 }
1137
1138 /* We now have the number of total arguments and
1139 number of ref arguments. Get number of normal
1140 arguments */
1141 num = num - refnum;
1142
1143 /* Make sure number of arguments is correct */
1144 /* Here we make sure the limits are greater
1145 or equal to zero because any negative number
1146 could be used to specify no limit */
1147 if (argmin >= 0 && num < argmin) {
12
Assuming 'argmin' is < 0
1148 obj->starterr = tokens[p1 - 1].start;
1149 obj->enderr = tokens[p2].end;
1150 return EXPR_ERROR_BADNUMBERARGUMENTS;
1151 }
1152
1153 if (argmax >= 0 && num > argmax) {
13
Assuming 'argmax' is < 0
1154 obj->starterr = tokens[p1 - 1].start;
1155 obj->enderr = tokens[p2].end;
1156 return EXPR_ERROR_BADNUMBERARGUMENTS;
1157 }
1158
1159 if (refargmin >= 0 && refnum < refargmin) {
14
Assuming 'refargmin' is < 0
1160 obj->starterr = tokens[p1 - 1].start;
1161 obj->enderr = tokens[p2].end;
1162 return EXPR_ERROR_BADNUMBERARGUMENTS;
1163 }
1164
1165 if (refargmax >= 0 && refnum > refargmax) {
15
Assuming 'refargmax' is < 0
1166 obj->starterr = tokens[p1 - 1].start;
1167 obj->enderr = tokens[p2].end;
1168 return EXPR_ERROR_BADNUMBERARGUMENTS;
1169 }
1170
1171 /* Set tmp to null in case of no arguments */
1172 tmp = NULL((void*)0);
1173 reftmp = NULL((void*)0);
16
Null pointer value stored to 'reftmp'
1174
1175 if (num > 0) {
17
Taking true branch
1176 /* Allocate subnodes */
1177 tmp = exprAllocNodes(num);
1178 if (tmp == NULL((void*)0))
18
Assuming 'tmp' is not equal to null
19
Taking false branch
1179 return EXPR_ERROR_MEMORY;
1180 }
1181
1182 if (refnum > 0) {
20
Taking false branch
1183 /* Allocate ref pointers */
1184 reftmp = exprAllocMem(sizeof(EXPRTYPE *) * refnum);
1185 if (reftmp == NULL((void*)0)) {
1186 exprFreeMem(tmp);
1187 return EXPR_ERROR_MEMORY;
1188 }
1189 }
1190
1191
1192
1193 /* Set this node's data */
1194 node->type = EXPR_NODETYPE_FUNCTION;
1195 node->data.function.fptr = fptr;
1196 node->data.function.nodecount = num;
1197 node->data.function.nodes = tmp;
1198 node->data.function.refcount = refnum;
1199 node->data.function.refs = reftmp;
1200 node->data.function.type = type;
1201
1202 /* parse each subnode */
1203 if (num + refnum > 0) {
21
Taking true branch
1204 plevel = 0;
1205 cur = 0;
1206 refcur = 0;
1207 lv = p1 + 1;
1208
1209 /* look for commas if more than 1 arg */
1210 if (num + refnum > 1) {
22
Taking false branch
1211 for (pos = p1 + 1; pos < p2; pos++) {
1212 switch (tokens[pos].type) {
1213 case EXPR_TOKEN_OPAREN1:
1214 plevel++;
1215 break;
1216
1217 case EXPR_TOKEN_CPAREN2:
1218 plevel--;
1219 break; /* Already checked paren nesting above */
1220
1221 case EXPR_TOKEN_COMMA11:
1222 /* Found comma */
1223 if (plevel == 0) {
1224 /* parse inside */
1225 if (tokens[lv].type == EXPR_TOKEN_AMPERSAND9) {
1226 if (lv != pos - 2) {
1227 obj->starterr = tokens[lv].start;
1228 obj->enderr = tokens[pos].end;
1229 return EXPR_ERROR_SYNTAX;
1230 }
1231
1232 /* It is a reference */
1233 if (tokens[lv + 1].type != EXPR_TOKEN_IDENTIFIER3) {
1234 obj->starterr = tokens[lv].start;
1235 obj->enderr = tokens[lv + 1].end;
1236 return EXPR_ERROR_SYNTAX;
1237 }
1238
1239
1240 /* Make sure it is not a constant */
1241 vars = exprGetConstList(obj);
1242 if (vars) {
1243 exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr);
1244 if (addr) {
1245 obj->starterr = tokens[lv].start;
1246 obj->enderr = tokens[lv + 1].start;
1247 return EXPR_ERROR_REFCONSTANT;
1248 }
1249 }
1250
1251 /* Get variable list */
1252 vars = exprGetVarList(obj);
1253 if (vars == NULL((void*)0))
1254 return EXPR_ERROR_NOVARLIST;
1255
1256 /* Get variable address */
1257 exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr);
1258 if (addr == NULL((void*)0)) {
1259 /* Add variable to list */
1260 exprValListAdd(vars, tokens[lv + 1].data.str, 0.0);
1261
1262 /* Try to get address again */
1263 exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr);
1264 if (addr == NULL((void*)0))
1265 return EXPR_ERROR_MEMORY; /* Could not add variable */
1266 }
1267
1268 /* Set reference item */
1269 reftmp[refcur] = addr;
1270
1271 /* increase ref arg number and lv position */
1272 refcur++;
1273 lv = pos + 1;
1274 } else {
1275 err = exprInternalParse(obj, &(tmp[cur]), tokens, lv, pos - 1);
1276 if (err != EXPR_ERROR_NOERROR)
1277 return err;
1278
1279 /* increase arg number and lv position */
1280 lv = pos + 1;
1281 cur++;
1282 }
1283 }
1284 break;
1285 }
1286 }
1287 }
1288
1289 /* lv should point after the last comma, or open paren. if only 1 arg */
1290 if (tokens[lv].type == EXPR_TOKEN_AMPERSAND9) {
23
Taking true branch
1291 if (lv != p2 - 2) {
24
Taking false branch
1292 obj->starterr = tokens[lv].start;
1293 obj->enderr = tokens[p2].end;
1294 return EXPR_ERROR_SYNTAX;
1295 }
1296
1297 /* It is a reference */
1298 if (tokens[lv + 1].type != EXPR_TOKEN_IDENTIFIER3) {
25
Taking false branch
1299 obj->starterr = tokens[lv].start;
1300 obj->enderr = tokens[lv + 1].end;
1301 return EXPR_ERROR_SYNTAX;
1302 }
1303
1304 /* Make sure it is not a constant */
1305 vars = exprGetConstList(obj);
1306 if (vars) {
26
Assuming 'vars' is null
27
Taking false branch
1307 exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr);
1308 if (addr) {
1309 obj->starterr = tokens[lv].start;
1310 obj->enderr = tokens[lv + 1].start;
1311 return EXPR_ERROR_REFCONSTANT;
1312 }
1313 }
1314
1315 /* Get variable list */
1316 vars = exprGetVarList(obj);
1317 if (vars == NULL((void*)0))
28
Assuming 'vars' is not equal to null
29
Taking false branch
1318 return EXPR_ERROR_NOVARLIST;
1319
1320 /* Get variable address */
1321 exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr);
1322 if (addr == NULL((void*)0)) {
30
Assuming 'addr' is not equal to null
31
Taking false branch
1323 /* Add variable to list */
1324 exprValListAdd(vars, tokens[lv + 1].data.str, 0.0);
1325
1326 /* Try to get address again */
1327 exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr);
1328 if (addr == NULL((void*)0))
1329 return EXPR_ERROR_MEMORY; /* Could not add variable */
1330 }
1331
1332 /* Set reference item */
1333 reftmp[refcur] = addr;
32
Array access (from variable 'reftmp') results in a null pointer dereference
1334 } else {
1335 err = exprInternalParse(obj, &(tmp[cur]), tokens, lv, p2 - 1);
1336 if (err != EXPR_ERROR_NOERROR)
1337 return err;
1338 }
1339 }
1340
1341
1342 return EXPR_ERROR_NOERROR;
1343}
1344
1345/* Parse a variable or value */
1346int exprInternalParseVarVal(exprObj * obj, exprNode * node, exprToken * tokens, int start, int end)
1347{
1348 exprValList *l;
1349 EXPRTYPE *addr;
1350
1351
1352 /* Make sure positions are correct */
1353 if (start != end) {
1354 return EXPR_ERROR_UNKNOWN;
1355 }
1356
1357
1358 /* Are we an identifier */
1359 if (tokens[start].type == EXPR_TOKEN_IDENTIFIER3) {
1360 /* we are an identifier */
1361
1362 /* check to see if it is a constant */
1363 l = exprGetConstList(obj);
1364 if (l != NULL((void*)0)) {
1365 if (exprValListGetAddress(l, tokens[start].data.str, &addr) == EXPR_ERROR_NOERROR) {
1366 /* We found it in the constant list */
1367
1368 /*
1369 Treat is like a variable node so application can change
1370 constant value and it will reflect in expression
1371 */
1372
1373 node->type = EXPR_NODETYPE_VARIABLE;
1374 node->data.variable.vaddr = addr;
1375 return EXPR_ERROR_NOERROR;
1376 }
1377 }
1378
1379 /* Not found in the constant list, so it must be a variable */
1380
1381 /* Set node type */
1382 node->type = EXPR_NODETYPE_VARIABLE;
1383
1384 /*
1385 The fast access method directly accesses the memory address
1386 of the variable's value at evaluation time. Because of this,
1387 we must make sure the variable does exists in the variable list.
1388 */
1389
1390 /* Get the variable list */
1391 l = exprGetVarList(obj);
1392 if (l == NULL((void*)0))
1393 return EXPR_ERROR_NOVARLIST;
1394
1395 /* Get variable address if already in the list */
1396 exprValListGetAddress(l, tokens[start].data.str, &addr);
1397 if (addr == NULL((void*)0)) { /* Variable not in the list, add it */
1398 exprValListAdd(l, tokens[start].data.str, 0.0);
1399
1400 /* Try to get address again */
1401 exprValListGetAddress(l, tokens[start].data.str, &addr);
1402 if (addr == NULL((void*)0)) /* Could not add variable */
1403 return EXPR_ERROR_MEMORY; /* Could not add variable to list */
1404 }
1405
1406 node->data.variable.vaddr = addr;
1407
1408 return EXPR_ERROR_NOERROR;
1409 } else if (tokens[start].type == EXPR_TOKEN_VALUE4) {
1410 /* we are a value */
1411 node->type = EXPR_NODETYPE_VALUE;
1412 node->data.value.value = tokens[start].data.val;
1413 return EXPR_ERROR_NOERROR;
1414 } else {
1415 obj->starterr = tokens[start].start;
1416 obj->enderr = tokens[end].end;
1417 return EXPR_ERROR_UNKNOWN;
1418 }
1419}