source: trunk/src/kmk/expreval.c@ 1726

Last change on this file since 1726 was 1726, checked in by bird, 17 years ago

kmk/expreval.c: Warnings and a couple of bugs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.8 KB
Line 
1#ifdef CONFIG_WITH_IF_CONDITIONALS
2/* $Id: expreval.c 1726 2008-09-05 01:44:07Z bird $ */
3/** @file
4 * expreval - Expressions evaluator, C / BSD make / nmake style.
5 */
6
7/*
8 * Copyright (c) 2008 knut st. osmundsen <bird-src-spam@anduin.net>
9 *
10 * This file is part of kBuild.
11 *
12 * kBuild is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * kBuild is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with kBuild; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 *
26 */
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "make.h"
32#include <assert.h>
33
34#include <glob.h>
35
36#include "dep.h"
37#include "filedef.h"
38#include "job.h"
39#include "commands.h"
40#include "variable.h"
41#include "rule.h"
42#include "debug.h"
43#include "hash.h"
44#include <ctype.h>
45#ifndef _MSC_VER
46# include <stdint.h>
47#endif
48#include <stdarg.h>
49
50
51/*******************************************************************************
52* Defined Constants And Macros *
53*******************************************************************************/
54/** The max length of a string representation of a number. */
55#define EXPR_NUM_LEN ((sizeof("-9223372036854775802") + 4) & ~3)
56
57/** The max operator stack depth. */
58#define EXPR_MAX_OPERATORS 72
59/** The max operand depth. */
60#define EXPR_MAX_OPERANDS 128
61
62
63/*******************************************************************************
64* Structures and Typedefs *
65*******************************************************************************/
66/** The 64-bit signed integer type we're using. */
67#ifdef _MSC_VER
68typedef __int64 EXPRINT64;
69#else
70# include <stdint.h>
71typedef int64_t EXPRINT64;
72#endif
73
74/** Pointer to a evaluator instance. */
75typedef struct EXPR *PEXPR;
76
77
78/**
79 * Operand variable type.
80 */
81typedef enum
82{
83 /** Invalid zero entry. */
84 kExprVar_Invalid = 0,
85 /** A number. */
86 kExprVar_Num,
87 /** A string in need of expanding (perhaps). */
88 kExprVar_String,
89 /** A simple string that doesn't need expanding. */
90 kExprVar_SimpleString,
91 /** A quoted string in need of expanding (perhaps). */
92 kExprVar_QuotedString,
93 /** A simple quoted string that doesn't need expanding. */
94 kExprVar_QuotedSimpleString,
95 /** The end of the valid variable types. */
96 kExprVar_End
97} EXPRVARTYPE;
98
99/**
100 * Operand variable.
101 */
102typedef struct
103{
104 /** The variable type. */
105 EXPRVARTYPE enmType;
106 /** The variable. */
107 union
108 {
109 /** Pointer to the string. */
110 char *psz;
111 /** The variable. */
112 EXPRINT64 i;
113 } uVal;
114} EXPRVAR;
115/** Pointer to a operand variable. */
116typedef EXPRVAR *PEXPRVAR;
117/** Pointer to a const operand variable. */
118typedef EXPRVAR const *PCEXPRVAR;
119
120/**
121 * Operator return statuses.
122 */
123typedef enum
124{
125 kExprRet_Error = -1,
126 kExprRet_Ok = 0,
127 kExprRet_Operator,
128 kExprRet_Operand,
129 kExprRet_EndOfExpr,
130 kExprRet_End
131} EXPRRET;
132
133/**
134 * Operator.
135 */
136typedef struct
137{
138 /** The operator. */
139 char szOp[11];
140 /** The length of the operator string. */
141 char cchOp;
142 /** The pair operator.
143 * This is used with '(' and '?'. */
144 char chPair;
145 /** The precedence. Higher means higher. */
146 char iPrecedence;
147 /** The number of arguments it takes. */
148 signed char cArgs;
149 /** Pointer to the method implementing the operator. */
150 EXPRRET (*pfn)(PEXPR pThis);
151} EXPROP;
152/** Pointer to a const operator. */
153typedef EXPROP const *PCEXPROP;
154
155/**
156 * Expression evaluator instance.
157 */
158typedef struct EXPR
159{
160 /** The full expression. */
161 const char *pszExpr;
162 /** The current location. */
163 const char *psz;
164 /** The current file location, used for errors. */
165 const struct floc *pFileLoc;
166 /** Pending binary operator. */
167 PCEXPROP pPending;
168 /** Top of the operator stack. */
169 int iOp;
170 /** Top of the operand stack. */
171 int iVar;
172 /** The operator stack. */
173 PCEXPROP apOps[EXPR_MAX_OPERATORS];
174 /** The operand stack. */
175 EXPRVAR aVars[EXPR_MAX_OPERANDS];
176} EXPR;
177
178
179/*******************************************************************************
180* Global Variables *
181*******************************************************************************/
182/** Operator start character map.
183 * This indicates which characters that are starting operators and which aren't. */
184static char g_auchOpStartCharMap[256];
185/** Whether we've initialized the map. */
186static int g_fExprInitializedMap = 0;
187
188
189/*******************************************************************************
190* Internal Functions *
191*******************************************************************************/
192static void expr_unget_op(PEXPR pThis);
193static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis);
194
195
196
197
198/**
199 * Displays an error message.
200 *
201 * The total string length must not exceed 256 bytes.
202 *
203 * @param pThis The evaluator instance.
204 * @param pszError The message format string.
205 * @param ... The message format args.
206 */
207static void expr_error(PEXPR pThis, const char *pszError, ...)
208{
209 char szTmp[256];
210 va_list va;
211
212 va_start(va, pszError);
213 vsprintf(szTmp, pszError, va);
214 va_end(va);
215
216 fatal(pThis->pFileLoc, "%s", szTmp);
217}
218
219
220/**
221 * Converts a number to a string.
222 *
223 * @returns pszDst.
224 * @param pszDst The string buffer to write into. Assumes length of EXPR_NUM_LEN.
225 * @param iSrc The number to convert.
226 */
227static char *expr_num_to_string(char *pszDst, EXPRINT64 iSrc)
228{
229 static const char s_szDigits[17] = "0123456789abcdef";
230 char szTmp[EXPR_NUM_LEN];
231 char *psz = &szTmp[EXPR_NUM_LEN - 1];
232 int fNegative;
233
234 fNegative = iSrc < 0;
235 if (fNegative)
236 {
237 /** @todo this isn't right for INT64_MIN. */
238 iSrc = -iSrc;
239 }
240
241 *psz = '\0';
242 do
243 {
244#if 0
245 *--psz = s_szDigits[iSrc & 0xf];
246 iSrc >>= 4;
247#else
248 *--psz = s_szDigits[iSrc % 10];
249 iSrc /= 10;
250#endif
251 } while (iSrc);
252
253#if 0
254 *--psz = 'x';
255 *--psz = '0';
256#endif
257
258 if (fNegative)
259 *--psz = '-';
260
261 /* copy it into the output buffer. */
262 return (char *)memcpy(pszDst, psz, &szTmp[EXPR_NUM_LEN] - psz);
263}
264
265
266/**
267 * Attempts to convert a (simple) string into a number.
268 *
269 * @returns status code.
270 * @param pThis The evaluator instance. This is optional when fQuiet is true.
271 * @param piSrc Where to store the numeric value on success.
272 * @param pszSrc The string to try convert.
273 * @param fQuiet Whether we should be quiet or grumpy on failure.
274 */
275static EXPRRET expr_string_to_num(PEXPR pThis, EXPRINT64 *piDst, const char *pszSrc, int fQuiet)
276{
277 EXPRRET rc = kExprRet_Ok;
278 char const *psz = pszSrc;
279 EXPRINT64 i;
280 unsigned uBase;
281 int fNegative;
282
283
284 /*
285 * Skip blanks.
286 */
287 while (isblank(*psz))
288 psz++;
289
290 /*
291 * Check for '-'.
292 *
293 * At this point we will not need to deal with operators, this is
294 * just an indicator of negative numbers. If some operator ends up
295 * here it's because it came from a string expansion and thus shall
296 * not be interpreted. If this turns out to be an stupid restriction
297 * it can be fixed, but for now it stays like this.
298 */
299 fNegative = *psz == '-';
300 if (fNegative)
301 psz++;
302
303 /*
304 * Determin base .
305 * .
306 * Recognize some exsotic prefixes here in addition to the two standard ones.
307 */
308 if (*psz != '0' || psz[1] == '\0' || isblank((unsigned int)psz[1]))
309 uBase = 10;
310 else if (psz[1] == 'x' || psz[1] == 'X')
311 {
312 uBase = 16;
313 psz += 2;
314 }
315 else if (psz[1] == 'b' || psz[1] == 'B')
316 {
317 uBase = 2;
318 psz += 2;
319 }
320 else if (psz[1] == 'd' || psz[1] == 'D')
321 {
322 uBase = 10;
323 psz += 2;
324 }
325 else if (psz[1] == 'o' || psz[1] == 'O')
326 {
327 uBase = 8;
328 psz += 2;
329 }
330 else if (isdigit(psz[1]) && psz[1] != '9' && psz[1] != '8')
331 {
332 uBase = 8;
333 psz++;
334 }
335 else
336 uBase = 10;
337
338 /*
339 * Convert until we hit a non-digit.
340 */
341 i = 0;
342 for (;;)
343 {
344 unsigned iDigit;
345 int ch = *psz;
346 switch (ch)
347 {
348 case '0': iDigit = 0; break;
349 case '1': iDigit = 1; break;
350 case '2': iDigit = 2; break;
351 case '3': iDigit = 3; break;
352 case '4': iDigit = 4; break;
353 case '5': iDigit = 5; break;
354 case '6': iDigit = 6; break;
355 case '7': iDigit = 7; break;
356 case '8': iDigit = 8; break;
357 case '9': iDigit = 9; break;
358 case 'a':
359 case 'A': iDigit = 10; break;
360 case 'b':
361 case 'B': iDigit = 11; break;
362 case 'c':
363 case 'C': iDigit = 12; break;
364 case 'd':
365 case 'D': iDigit = 13; break;
366 case 'e':
367 case 'E': iDigit = 14; break;
368 case 'f':
369 case 'F': iDigit = 15; break;
370
371 default:
372 /* is the rest white space? */
373 while (isspace((unsigned int)*psz))
374 psz++;
375 if (*psz != '\0')
376 {
377 iDigit = uBase;
378 break;
379 }
380 /* fall thru */
381
382 case '\0':
383 if (fNegative)
384 i = -i;
385 *piDst = i;
386 return rc;
387 }
388 if (iDigit >= uBase)
389 {
390 if (fNegative)
391 i = -i;
392 *piDst = i;
393 if (!fQuiet)
394 expr_error(pThis, "Invalid a number \"%.80s\"", pszSrc);
395 return kExprRet_Error;
396 }
397
398 /* add the digit and advance */
399 i *= uBase;
400 i += iDigit;
401 psz++;
402 }
403 /* not reached */
404}
405
406
407/**
408 * Checks if the variable is a string or not.
409 *
410 * @returns 1 if it's a string, 0 otherwise.
411 * @param pVar The variable.
412 */
413static int expr_var_is_string(PCEXPRVAR pVar)
414{
415 return pVar->enmType >= kExprVar_String;
416}
417
418
419/**
420 * Checks if the variable contains a string that was quoted
421 * in the expression.
422 *
423 * @returns 1 if if was a quoted string, otherwise 0.
424 * @param pVar The variable.
425 */
426static int expr_var_was_quoted(PCEXPRVAR pVar)
427{
428 return pVar->enmType >= kExprVar_QuotedString;
429}
430
431
432/**
433 * Deletes a variable.
434 *
435 * @param pVar The variable.
436 */
437static void expr_var_delete(PEXPRVAR pVar)
438{
439 if (expr_var_is_string(pVar))
440 {
441 free(pVar->uVal.psz);
442 pVar->uVal.psz = NULL;
443 }
444 pVar->enmType = kExprVar_Invalid;
445}
446
447
448/**
449 * Initializes a new variables with a sub-string value.
450 *
451 * @param pVar The new variable.
452 * @param psz The start of the string value.
453 * @param cch The number of chars to copy.
454 * @param enmType The string type.
455 */
456static void expr_var_init_substring(PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType)
457{
458 /* convert string needing expanding into simple ones if possible. */
459 if ( enmType == kExprVar_String
460 && !memchr(psz, '$', cch))
461 enmType = kExprVar_SimpleString;
462 else if ( enmType == kExprVar_QuotedString
463 && !memchr(psz, '$', cch))
464 enmType = kExprVar_QuotedSimpleString;
465
466 pVar->enmType = enmType;
467 pVar->uVal.psz = xmalloc(cch + 1);
468 memcpy(pVar->uVal.psz, psz, cch);
469 pVar->uVal.psz[cch] = '\0';
470}
471
472
473#if 0 /* unused */
474/**
475 * Initializes a new variables with a string value.
476 *
477 * @param pVar The new variable.
478 * @param psz The string value.
479 * @param enmType The string type.
480 */
481static void expr_var_init_string(PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType)
482{
483 expr_var_init_substring(pVar, psz, strlen(psz), enmType);
484}
485
486
487/**
488 * Assigns a sub-string value to a variable.
489 *
490 * @param pVar The new variable.
491 * @param psz The start of the string value.
492 * @param cch The number of chars to copy.
493 * @param enmType The string type.
494 */
495static void expr_var_assign_substring(PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType)
496{
497 expr_var_delete(pVar);
498 expr_var_init_substring(pVar, psz, cch, enmType);
499}
500
501
502/**
503 * Assignes a string value to a variable.
504 *
505 * @param pVar The variable.
506 * @param psz The string value.
507 * @param enmType The string type.
508 */
509static void expr_var_assign_string(PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType)
510{
511 expr_var_delete(pVar);
512 expr_var_init_string(pVar, psz, enmType);
513}
514#endif /* unused */
515
516
517/**
518 * Simplifies a string variable.
519 *
520 * @param pVar The variable.
521 */
522static void expr_var_make_simple_string(PEXPRVAR pVar)
523{
524 switch (pVar->enmType)
525 {
526 case kExprVar_Num:
527 {
528 char *psz = (char *)xmalloc(EXPR_NUM_LEN);
529 expr_num_to_string(psz, pVar->uVal.i);
530 pVar->uVal.psz = psz;
531 pVar->enmType = kExprVar_SimpleString;
532 break;
533 }
534
535 case kExprVar_String:
536 case kExprVar_QuotedString:
537 {
538 char *psz;
539 assert(strchr(pVar->uVal.psz, '$'));
540
541 psz = allocated_variable_expand(pVar->uVal.psz);
542 free(pVar->uVal.psz);
543 pVar->uVal.psz = psz;
544
545 pVar->enmType = pVar->enmType == kExprVar_String
546 ? kExprVar_SimpleString
547 : kExprVar_QuotedSimpleString;
548 break;
549 }
550
551 case kExprVar_SimpleString:
552 case kExprVar_QuotedSimpleString:
553 /* nothing to do. */
554 break;
555
556 default:
557 assert(0);
558 }
559}
560
561
562#if 0 /* unused */
563/**
564 * Turns a variable into a string value.
565 *
566 * @param pVar The variable.
567 */
568static void expr_var_make_string(PEXPRVAR pVar)
569{
570 switch (pVar->enmType)
571 {
572 case kExprVar_Num:
573 expr_var_make_simple_string(pVar);
574 break;
575
576 case kExprVar_String:
577 case kExprVar_SimpleString:
578 case kExprVar_QuotedString:
579 case kExprVar_QuotedSimpleString:
580 /* nothing to do. */
581 break;
582
583 default:
584 assert(0);
585 }
586}
587#endif /* unused */
588
589
590/**
591 * Initializes a new variables with a integer value.
592 *
593 * @param pVar The new variable.
594 * @param i The integer value.
595 */
596static void expr_var_init_num(PEXPRVAR pVar, EXPRINT64 i)
597{
598 pVar->enmType = kExprVar_Num;
599 pVar->uVal.i = i;
600}
601
602
603/**
604 * Assigns a integer value to a variable.
605 *
606 * @param pVar The variable.
607 * @param i The integer value.
608 */
609static void expr_var_assign_num(PEXPRVAR pVar, EXPRINT64 i)
610{
611 expr_var_delete(pVar);
612 expr_var_init_num(pVar, i);
613}
614
615
616/**
617 * Turns the variable into a number.
618 *
619 * @returns status code.
620 * @param pThis The evaluator instance.
621 * @param pVar The variable.
622 */
623static EXPRRET expr_var_make_num(PEXPR pThis, PEXPRVAR pVar)
624{
625 switch (pVar->enmType)
626 {
627 case kExprVar_Num:
628 /* nothing to do. */
629 break;
630
631 case kExprVar_String:
632 expr_var_make_simple_string(pVar);
633 /* fall thru */
634 case kExprVar_SimpleString:
635 {
636 EXPRINT64 i;
637 EXPRRET rc = expr_string_to_num(pThis, &i, pVar->uVal.psz, 0 /* fQuiet */);
638 if (rc < kExprRet_Ok)
639 return rc;
640 expr_var_assign_num(pVar, i);
641 break;
642 }
643
644 case kExprVar_QuotedString:
645 case kExprVar_QuotedSimpleString:
646 expr_error(pThis, "Cannot convert a quoted string to a number");
647 return kExprRet_Error;
648
649 default:
650 assert(0);
651 return kExprRet_Error;
652 }
653
654 return kExprRet_Ok;
655}
656
657
658/**
659 * Try to turn the variable into a number.
660 *
661 * @returns status code.
662 * @param pVar The variable.
663 */
664static EXPRRET expr_var_try_make_num(PEXPRVAR pVar)
665{
666 switch (pVar->enmType)
667 {
668 case kExprVar_Num:
669 /* nothing to do. */
670 break;
671
672 case kExprVar_String:
673 expr_var_make_simple_string(pVar);
674 /* fall thru */
675 case kExprVar_SimpleString:
676 {
677 EXPRINT64 i;
678 EXPRRET rc = expr_string_to_num(NULL, &i, pVar->uVal.psz, 1 /* fQuiet */);
679 if (rc < kExprRet_Ok)
680 return rc;
681 expr_var_assign_num(pVar, i);
682 break;
683 }
684
685 default:
686 assert(0);
687 case kExprVar_QuotedString:
688 case kExprVar_QuotedSimpleString:
689 /* can't do this */
690 return kExprRet_Error;
691 }
692
693 return kExprRet_Ok;
694}
695
696
697/**
698 * Initializes a new variables with a boolean value.
699 *
700 * @param pVar The new variable.
701 * @param f The boolean value.
702 */
703static void expr_var_init_bool(PEXPRVAR pVar, int f)
704{
705 pVar->enmType = kExprVar_Num;
706 pVar->uVal.i = !!f;
707}
708
709
710/**
711 * Assigns a boolean value to a variable.
712 *
713 * @param pVar The variable.
714 * @param f The boolean value.
715 */
716static void expr_var_assign_bool(PEXPRVAR pVar, int f)
717{
718 expr_var_delete(pVar);
719 expr_var_init_bool(pVar, f);
720}
721
722
723/**
724 * Turns the variable into an boolean.
725 *
726 * @returns the boolean interpretation.
727 * @param pVar The variable.
728 */
729static int expr_var_make_bool(PEXPRVAR pVar)
730{
731 switch (pVar->enmType)
732 {
733 case kExprVar_Num:
734 pVar->uVal.i = !!pVar->uVal.i;
735 break;
736
737 case kExprVar_String:
738 expr_var_make_simple_string(pVar);
739 /* fall thru */
740 case kExprVar_SimpleString:
741 {
742 /*
743 * Try convert it to a number. If that fails, use the
744 * GNU make boolean logic - not empty string means true.
745 */
746 EXPRINT64 iVal;
747 char const *psz = pVar->uVal.psz;
748 while (isblank((unsigned char)*psz))
749 psz++;
750 if ( *psz
751 && expr_string_to_num(NULL, &iVal, psz, 1 /* fQuiet */) >= kExprRet_Ok)
752 expr_var_assign_bool(pVar, iVal != 0);
753 else
754 expr_var_assign_bool(pVar, *psz != '\0');
755 break;
756 }
757
758 case kExprVar_QuotedString:
759 expr_var_make_simple_string(pVar);
760 /* fall thru */
761 case kExprVar_QuotedSimpleString:
762 /*
763 * Use GNU make boolean logic (not empty string means true).
764 * No stripping here, the string is quoted.
765 */
766 expr_var_assign_bool(pVar, *pVar->uVal.psz != '\0');
767 break;
768
769 default:
770 assert(0);
771 break;
772 }
773
774 return pVar->uVal.i;
775}
776
777
778/**
779 * Pops a varable off the stack and deletes it.
780 * @param pThis The evaluator instance.
781 */
782static void expr_pop_and_delete_var(PEXPR pThis)
783{
784 expr_var_delete(&pThis->aVars[pThis->iVar]);
785 pThis->iVar--;
786}
787
788
789
790/**
791 * Tries to make the variables the same type.
792 *
793 * This will not convert numbers to strings, unless one of them
794 * is a quoted string.
795 *
796 * this will try convert both to numbers if neither is quoted. Both
797 * conversions will have to suceed for this to be commited.
798 *
799 * All strings will be simplified.
800 *
801 * @returns status code. Done complaining on failure.
802 *
803 * @param pThis The evaluator instance.
804 * @param pVar1 The first variable.
805 * @param pVar2 The second variable.
806 */
807static EXPRRET expr_var_unify_types(PEXPR pThis, PEXPRVAR pVar1, PEXPRVAR pVar2, const char *pszOp)
808{
809 /*
810 * Try make the variables the same type before comparing.
811 */
812 if ( !expr_var_was_quoted(pVar1)
813 && !expr_var_was_quoted(pVar2))
814 {
815 if ( expr_var_is_string(pVar1)
816 || expr_var_is_string(pVar2))
817 {
818 if (!expr_var_is_string(pVar1))
819 expr_var_try_make_num(pVar2);
820 else if (!expr_var_is_string(pVar2))
821 expr_var_try_make_num(pVar1);
822 else
823 {
824 /*
825 * Both are strings, simplify them then see if both can be made into numbers.
826 */
827 EXPRINT64 iVar1;
828 EXPRINT64 iVar2;
829
830 expr_var_make_simple_string(pVar1);
831 expr_var_make_simple_string(pVar2);
832
833 if ( expr_string_to_num(NULL, &iVar1, pVar1->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok
834 && expr_string_to_num(NULL, &iVar2, pVar2->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok)
835 {
836 expr_var_assign_num(pVar1, iVar1);
837 expr_var_assign_num(pVar2, iVar2);
838 }
839 }
840 }
841 }
842 else
843 {
844 expr_var_make_simple_string(pVar1);
845 expr_var_make_simple_string(pVar2);
846 }
847
848 /*
849 * Complain if they aren't the same type now.
850 */
851 if (expr_var_is_string(pVar1) != expr_var_is_string(pVar2))
852 {
853 expr_error(pThis, "Unable to unify types for \"%s\"", pszOp);
854 return kExprRet_Error;
855 }
856 return kExprRet_Ok;
857}
858
859
860/**
861 * Is variable defined, unary.
862 *
863 * @returns Status code.
864 * @param pThis The instance.
865 */
866static EXPRRET expr_op_defined(PEXPR pThis)
867{
868 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
869 struct variable *pMakeVar;
870 assert(pThis->iVar >= 0);
871
872 expr_var_make_simple_string(pVar);
873 pMakeVar = lookup_variable(pVar->uVal.psz, strlen(pVar->uVal.psz));
874 expr_var_assign_bool(pVar, pMakeVar && *pMakeVar->value != '\0');
875
876 return kExprRet_Ok;
877}
878
879
880/**
881 * Is target defined, unary.
882 *
883 * @returns Status code.
884 * @param pThis The instance.
885 */
886static EXPRRET expr_op_target(PEXPR pThis)
887{
888 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
889 struct file *pFile = NULL;
890 assert(pThis->iVar >= 0);
891
892 /*
893 * Because of secondary target expansion, lookup the unexpanded
894 * name first.
895 */
896#ifdef CONFIG_WITH_2ND_TARGET_EXPANSION
897 if ( pVar->enmType == kExprVar_String
898 || pVar->enmType == kExprVar_QuotedString)
899 {
900 pFile = lookup_file(pVar->uVal.psz);
901 if ( pFile
902 && !pFile->need_2nd_target_expansion)
903 pFile = NULL;
904 }
905 if (pFile)
906#endif
907 {
908 expr_var_make_simple_string(pVar);
909 pFile = lookup_file(pVar->uVal.psz);
910 }
911
912 /*
913 * Always inspect the head of a multiple target rule
914 * and look for a file with commands.
915 */
916#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET
917 if (pFile && pFile->multi_head)
918 pFile = pFile->multi_head;
919#endif
920
921 while (pFile && !pFile->cmds)
922 pFile = pFile->prev;
923
924 expr_var_assign_bool(pVar, pFile != NULL && pFile->is_target);
925
926 return kExprRet_Ok;
927}
928
929
930/**
931 * Pluss (dummy / make_integer)
932 *
933 * @returns Status code.
934 * @param pThis The instance.
935 */
936static EXPRRET expr_op_pluss(PEXPR pThis)
937{
938 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
939 assert(pThis->iVar >= 0);
940
941 return expr_var_make_num(pThis, pVar);
942}
943
944
945
946/**
947 * Minus (negate)
948 *
949 * @returns Status code.
950 * @param pThis The instance.
951 */
952static EXPRRET expr_op_minus(PEXPR pThis)
953{
954 EXPRRET rc;
955 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
956 assert(pThis->iVar >= 0);
957
958 rc = expr_var_make_num(pThis, pVar);
959 if (rc >= kExprRet_Ok)
960 pVar->uVal.i = -pVar->uVal.i;
961
962 return rc;
963}
964
965
966
967/**
968 * Bitwise NOT.
969 *
970 * @returns Status code.
971 * @param pThis The instance.
972 */
973static EXPRRET expr_op_bitwise_not(PEXPR pThis)
974{
975 EXPRRET rc;
976 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
977 assert(pThis->iVar >= 0);
978
979 rc = expr_var_make_num(pThis, pVar);
980 if (rc >= kExprRet_Ok)
981 pVar->uVal.i = ~pVar->uVal.i;
982
983 return rc;
984}
985
986
987/**
988 * Logical NOT.
989 *
990 * @returns Status code.
991 * @param pThis The instance.
992 */
993static EXPRRET expr_op_logical_not(PEXPR pThis)
994{
995 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
996 assert(pThis->iVar >= 0);
997
998 expr_var_assign_bool(pVar, !expr_var_make_bool(pVar));
999
1000 return kExprRet_Ok;
1001}
1002
1003
1004/**
1005 * Multiplication.
1006 *
1007 * @returns Status code.
1008 * @param pThis The instance.
1009 */
1010static EXPRRET expr_op_multiply(PEXPR pThis)
1011{
1012 EXPRRET rc = kExprRet_Ok;
1013 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1014 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1015 assert(pThis->iVar >= 1);
1016
1017 rc = expr_var_make_num(pThis, pVar1);
1018 if (rc >= kExprRet_Ok)
1019 {
1020 rc = expr_var_make_num(pThis, pVar2);
1021 if (rc >= kExprRet_Ok)
1022 pVar1->uVal.i *= pVar2->uVal.i;
1023 }
1024
1025 expr_pop_and_delete_var(pThis);
1026 return rc;
1027}
1028
1029
1030
1031/**
1032 * Division.
1033 *
1034 * @returns Status code.
1035 * @param pThis The instance.
1036 */
1037static EXPRRET expr_op_divide(PEXPR pThis)
1038{
1039 EXPRRET rc = kExprRet_Ok;
1040 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1041 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1042 assert(pThis->iVar >= 1);
1043
1044 rc = expr_var_make_num(pThis, pVar1);
1045 if (rc >= kExprRet_Ok)
1046 {
1047 rc = expr_var_make_num(pThis, pVar2);
1048 if (rc >= kExprRet_Ok)
1049 pVar1->uVal.i /= pVar2->uVal.i;
1050 }
1051
1052 expr_pop_and_delete_var(pThis);
1053 return rc;
1054}
1055
1056
1057
1058/**
1059 * Modulus.
1060 *
1061 * @returns Status code.
1062 * @param pThis The instance.
1063 */
1064static EXPRRET expr_op_modulus(PEXPR pThis)
1065{
1066 EXPRRET rc = kExprRet_Ok;
1067 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1068 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1069 assert(pThis->iVar >= 1);
1070
1071 rc = expr_var_make_num(pThis, pVar1);
1072 if (rc >= kExprRet_Ok)
1073 {
1074 rc = expr_var_make_num(pThis, pVar2);
1075 if (rc >= kExprRet_Ok)
1076 pVar1->uVal.i %= pVar2->uVal.i;
1077 }
1078
1079 expr_pop_and_delete_var(pThis);
1080 return rc;
1081}
1082
1083
1084
1085/**
1086 * Addition (numeric).
1087 *
1088 * @returns Status code.
1089 * @param pThis The instance.
1090 */
1091static EXPRRET expr_op_add(PEXPR pThis)
1092{
1093 EXPRRET rc = kExprRet_Ok;
1094 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1095 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1096 assert(pThis->iVar >= 1);
1097
1098 rc = expr_var_make_num(pThis, pVar1);
1099 if (rc >= kExprRet_Ok)
1100 {
1101 rc = expr_var_make_num(pThis, pVar2);
1102 if (rc >= kExprRet_Ok)
1103 pVar1->uVal.i += pVar2->uVal.i;
1104 }
1105
1106 expr_pop_and_delete_var(pThis);
1107 return rc;
1108}
1109
1110
1111/**
1112 * Subtract (numeric).
1113 *
1114 * @returns Status code.
1115 * @param pThis The instance.
1116 */
1117static EXPRRET expr_op_sub(PEXPR pThis)
1118{
1119 EXPRRET rc = kExprRet_Ok;
1120 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1121 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1122 assert(pThis->iVar >= 1);
1123
1124 rc = expr_var_make_num(pThis, pVar1);
1125 if (rc >= kExprRet_Ok)
1126 {
1127 rc = expr_var_make_num(pThis, pVar2);
1128 if (rc >= kExprRet_Ok)
1129 pVar1->uVal.i -= pVar2->uVal.i;
1130 }
1131
1132 expr_pop_and_delete_var(pThis);
1133 return rc;
1134}
1135
1136/**
1137 * Bitwise left shift.
1138 *
1139 * @returns Status code.
1140 * @param pThis The instance.
1141 */
1142static EXPRRET expr_op_shift_left(PEXPR pThis)
1143{
1144 EXPRRET rc = kExprRet_Ok;
1145 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1146 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1147 assert(pThis->iVar >= 1);
1148
1149 rc = expr_var_make_num(pThis, pVar1);
1150 if (rc >= kExprRet_Ok)
1151 {
1152 rc = expr_var_make_num(pThis, pVar2);
1153 if (rc >= kExprRet_Ok)
1154 pVar1->uVal.i <<= pVar2->uVal.i;
1155 }
1156
1157 expr_pop_and_delete_var(pThis);
1158 return rc;
1159}
1160
1161
1162/**
1163 * Bitwise right shift.
1164 *
1165 * @returns Status code.
1166 * @param pThis The instance.
1167 */
1168static EXPRRET expr_op_shift_right(PEXPR pThis)
1169{
1170 EXPRRET rc = kExprRet_Ok;
1171 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1172 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1173 assert(pThis->iVar >= 1);
1174
1175 rc = expr_var_make_num(pThis, pVar1);
1176 if (rc >= kExprRet_Ok)
1177 {
1178 rc = expr_var_make_num(pThis, pVar2);
1179 if (rc >= kExprRet_Ok)
1180 pVar1->uVal.i >>= pVar2->uVal.i;
1181 }
1182
1183 expr_pop_and_delete_var(pThis);
1184 return rc;
1185}
1186
1187
1188/**
1189 * Less than or equal
1190 *
1191 * @returns Status code.
1192 * @param pThis The instance.
1193 */
1194static EXPRRET expr_op_less_or_equal_than(PEXPR pThis)
1195{
1196 EXPRRET rc = kExprRet_Ok;
1197 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1198 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1199 assert(pThis->iVar >= 1);
1200
1201 rc = expr_var_unify_types(pThis, pVar1, pVar2, "<=");
1202 if (rc >= kExprRet_Ok)
1203 {
1204 if (!expr_var_is_string(pVar1))
1205 expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i);
1206 else
1207 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) <= 0);
1208 }
1209
1210 expr_pop_and_delete_var(pThis);
1211 return rc;
1212}
1213
1214
1215/**
1216 * Less than.
1217 *
1218 * @returns Status code.
1219 * @param pThis The instance.
1220 */
1221static EXPRRET expr_op_less_than(PEXPR pThis)
1222{
1223 EXPRRET rc = kExprRet_Ok;
1224 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1225 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1226 assert(pThis->iVar >= 1);
1227
1228 rc = expr_var_unify_types(pThis, pVar1, pVar2, "<");
1229 if (rc >= kExprRet_Ok)
1230 {
1231 if (!expr_var_is_string(pVar1))
1232 expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i);
1233 else
1234 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) < 0);
1235 }
1236
1237 expr_pop_and_delete_var(pThis);
1238 return rc;
1239}
1240
1241
1242/**
1243 * Greater or equal than
1244 *
1245 * @returns Status code.
1246 * @param pThis The instance.
1247 */
1248static EXPRRET expr_op_greater_or_equal_than(PEXPR pThis)
1249{
1250 EXPRRET rc = kExprRet_Ok;
1251 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1252 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1253 assert(pThis->iVar >= 1);
1254
1255 rc = expr_var_unify_types(pThis, pVar1, pVar2, ">=");
1256 if (rc >= kExprRet_Ok)
1257 {
1258 if (!expr_var_is_string(pVar1))
1259 expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i);
1260 else
1261 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) >= 0);
1262 }
1263
1264 expr_pop_and_delete_var(pThis);
1265 return rc;
1266}
1267
1268
1269/**
1270 * Greater than.
1271 *
1272 * @returns Status code.
1273 * @param pThis The instance.
1274 */
1275static EXPRRET expr_op_greater_than(PEXPR pThis)
1276{
1277 EXPRRET rc = kExprRet_Ok;
1278 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1279 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1280 assert(pThis->iVar >= 1);
1281
1282 rc = expr_var_unify_types(pThis, pVar1, pVar2, ">");
1283 if (rc >= kExprRet_Ok)
1284 {
1285 if (!expr_var_is_string(pVar1))
1286 expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i);
1287 else
1288 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) > 0);
1289 }
1290
1291 expr_pop_and_delete_var(pThis);
1292 return rc;
1293}
1294
1295
1296/**
1297 * Equal.
1298 *
1299 * @returns Status code.
1300 * @param pThis The instance.
1301 */
1302static EXPRRET expr_op_equal(PEXPR pThis)
1303{
1304 EXPRRET rc = kExprRet_Ok;
1305 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1306 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1307 assert(pThis->iVar >= 1);
1308
1309 /*
1310 * The same type?
1311 */
1312 if (expr_var_is_string(pVar1) == expr_var_is_string(pVar2))
1313 {
1314 if (!expr_var_is_string(pVar1))
1315 /* numbers are simple */
1316 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1317 else
1318 {
1319 /* try a normal string compare. */
1320 expr_var_make_simple_string(pVar1);
1321 expr_var_make_simple_string(pVar2);
1322 if (!strcmp(pVar1->uVal.psz, pVar2->uVal.psz))
1323 expr_var_assign_bool(pVar1, 1);
1324 /* try convert and compare as number instead. */
1325 else if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok
1326 && expr_var_try_make_num(pVar2) >= kExprRet_Ok)
1327 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1328 /* ok, they really aren't equal. */
1329 else
1330 expr_var_assign_bool(pVar1, 0);
1331 }
1332 }
1333 else
1334 {
1335 /*
1336 * If the type differs, there are now two options:
1337 * 1. Convert the string to a valid number and compare the numbers.
1338 * 2. Convert an empty string to a 'false' boolean value and compare
1339 * numerically. This one is a bit questionable, so we don't try this.
1340 */
1341 if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok
1342 && expr_var_try_make_num(pVar2) >= kExprRet_Ok)
1343 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1344 else
1345 {
1346 expr_error(pThis, "Cannot compare strings and numbers");
1347 rc = kExprRet_Error;
1348 }
1349 }
1350
1351 expr_pop_and_delete_var(pThis);
1352 return kExprRet_Ok;
1353}
1354
1355
1356/**
1357 * Not equal.
1358 *
1359 * @returns Status code.
1360 * @param pThis The instance.
1361 */
1362static EXPRRET expr_op_not_equal(PEXPR pThis)
1363{
1364 EXPRRET rc = expr_op_equal(pThis);
1365 if (rc >= kExprRet_Ok)
1366 rc = expr_op_logical_not(pThis);
1367 return rc;
1368}
1369
1370
1371/**
1372 * Bitwise AND.
1373 *
1374 * @returns Status code.
1375 * @param pThis The instance.
1376 */
1377static EXPRRET expr_op_bitwise_and(PEXPR pThis)
1378{
1379 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1380 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1381 EXPRRET rc;
1382 assert(pThis->iVar >= 1);
1383
1384 rc = expr_var_make_num(pThis, pVar1);
1385 if (rc >= kExprRet_Ok)
1386 {
1387 rc = expr_var_make_num(pThis, pVar2);
1388 if (rc >= kExprRet_Ok)
1389 pVar1->uVal.i &= pVar2->uVal.i;
1390 }
1391
1392 expr_pop_and_delete_var(pThis);
1393 return kExprRet_Ok;
1394}
1395
1396
1397/**
1398 * Bitwise XOR.
1399 *
1400 * @returns Status code.
1401 * @param pThis The instance.
1402 */
1403static EXPRRET expr_op_bitwise_xor(PEXPR pThis)
1404{
1405 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1406 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1407 EXPRRET rc;
1408 assert(pThis->iVar >= 1);
1409
1410 rc = expr_var_make_num(pThis, pVar1);
1411 if (rc >= kExprRet_Ok)
1412 {
1413 rc = expr_var_make_num(pThis, pVar2);
1414 if (rc >= kExprRet_Ok)
1415 pVar1->uVal.i ^= pVar2->uVal.i;
1416 }
1417
1418 expr_pop_and_delete_var(pThis);
1419 return kExprRet_Ok;
1420}
1421
1422
1423/**
1424 * Bitwise OR.
1425 *
1426 * @returns Status code.
1427 * @param pThis The instance.
1428 */
1429static EXPRRET expr_op_bitwise_or(PEXPR pThis)
1430{
1431 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1432 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1433 EXPRRET rc;
1434 assert(pThis->iVar >= 1);
1435
1436 rc = expr_var_make_num(pThis, pVar1);
1437 if (rc >= kExprRet_Ok)
1438 {
1439 rc = expr_var_make_num(pThis, pVar2);
1440 if (rc >= kExprRet_Ok)
1441 pVar1->uVal.i |= pVar2->uVal.i;
1442 }
1443
1444 expr_pop_and_delete_var(pThis);
1445 return kExprRet_Ok;
1446}
1447
1448
1449/**
1450 * Logical AND.
1451 *
1452 * @returns Status code.
1453 * @param pThis The instance.
1454 */
1455static EXPRRET expr_op_logical_and(PEXPR pThis)
1456{
1457 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1458 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1459 assert(pThis->iVar >= 1);
1460
1461 if ( expr_var_make_bool(pVar1)
1462 && expr_var_make_bool(pVar2))
1463 expr_var_assign_bool(pVar1, 1);
1464 else
1465 expr_var_assign_bool(pVar1, 0);
1466
1467 expr_pop_and_delete_var(pThis);
1468 return kExprRet_Ok;
1469}
1470
1471
1472/**
1473 * Logical OR.
1474 *
1475 * @returns Status code.
1476 * @param pThis The instance.
1477 */
1478static EXPRRET expr_op_logical_or(PEXPR pThis)
1479{
1480 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1481 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1482 assert(pThis->iVar >= 1);
1483
1484 if ( expr_var_make_bool(pVar1)
1485 || expr_var_make_bool(pVar2))
1486 expr_var_assign_bool(pVar1, 1);
1487 else
1488 expr_var_assign_bool(pVar1, 0);
1489
1490 expr_pop_and_delete_var(pThis);
1491 return kExprRet_Ok;
1492}
1493
1494
1495/**
1496 * Left parenthesis.
1497 *
1498 * @returns Status code.
1499 * @param pThis The instance.
1500 */
1501static EXPRRET expr_op_left_parenthesis(PEXPR pThis)
1502{
1503 /*
1504 * There should be a right parenthesis operator lined up for us now,
1505 * eat it. If not found there is an inbalance.
1506 */
1507 EXPRRET rc = expr_get_binary_or_eoe_or_rparen(pThis);
1508 if ( rc == kExprRet_Operator
1509 && pThis->apOps[pThis->iOp]->szOp[0] == ')')
1510 {
1511 /* pop it and get another one which we can leave pending. */
1512 pThis->iOp--;
1513 rc = expr_get_binary_or_eoe_or_rparen(pThis);
1514 if (rc >= kExprRet_Ok)
1515 expr_unget_op(pThis);
1516 }
1517 else
1518 {
1519 expr_error(pThis, "Missing ')'");
1520 rc = kExprRet_Error;
1521 }
1522
1523 return rc;
1524}
1525
1526
1527/**
1528 * Right parenthesis, dummy that's never actually called.
1529 *
1530 * @returns Status code.
1531 * @param pThis The instance.
1532 */
1533static EXPRRET expr_op_right_parenthesis(PEXPR pThis)
1534{
1535 (void)pThis;
1536 return kExprRet_Ok;
1537}
1538
1539
1540
1541
1542
1543/**
1544 * The operator table.
1545 *
1546 * This table is NOT ordered by precedence, but for linear search
1547 * allowing for first match to return the correct operator. This
1548 * means that || must come before |, or else | will match all.
1549 */
1550static const EXPROP g_aExprOps[] =
1551{
1552#define EXPR_OP(szOp, iPrecedence, cArgs, pfn) { szOp, sizeof(szOp) - 1, '\0', iPrecedence, cArgs, pfn }
1553 /* Name, iPrecedence, cArgs, pfn */
1554 EXPR_OP("defined", 90, 1, expr_op_defined),
1555 EXPR_OP("target", 90, 1, expr_op_target),
1556 EXPR_OP("+", 80, 1, expr_op_pluss),
1557 EXPR_OP("-", 80, 1, expr_op_minus),
1558 EXPR_OP("~", 80, 1, expr_op_bitwise_not),
1559 EXPR_OP("*", 75, 2, expr_op_multiply),
1560 EXPR_OP("/", 75, 2, expr_op_divide),
1561 EXPR_OP("%", 75, 2, expr_op_modulus),
1562 EXPR_OP("+", 70, 2, expr_op_add),
1563 EXPR_OP("-", 70, 2, expr_op_sub),
1564 EXPR_OP("<<", 65, 2, expr_op_shift_left),
1565 EXPR_OP(">>", 65, 2, expr_op_shift_right),
1566 EXPR_OP("<=", 60, 2, expr_op_less_or_equal_than),
1567 EXPR_OP("<", 60, 2, expr_op_less_than),
1568 EXPR_OP(">=", 60, 2, expr_op_greater_or_equal_than),
1569 EXPR_OP(">", 60, 2, expr_op_greater_than),
1570 EXPR_OP("==", 55, 2, expr_op_equal),
1571 EXPR_OP("!=", 55, 2, expr_op_not_equal),
1572 EXPR_OP("!", 80, 1, expr_op_logical_not),
1573 EXPR_OP("^", 45, 2, expr_op_bitwise_xor),
1574 EXPR_OP("&&", 35, 2, expr_op_logical_and),
1575 EXPR_OP("&", 50, 2, expr_op_bitwise_and),
1576 EXPR_OP("||", 30, 2, expr_op_logical_or),
1577 EXPR_OP("|", 40, 2, expr_op_bitwise_or),
1578 { "(", 1, ')', 10, 1, expr_op_left_parenthesis },
1579 { ")", 1, '(', 10, 0, expr_op_right_parenthesis },
1580 /* { "?", 1, ':', 5, 2, expr_op_question },
1581 { ":", 1, '?', 5, 2, expr_op_colon }, -- too weird for now. */
1582#undef EXPR_OP
1583};
1584
1585/** Dummy end of expression fake. */
1586static const EXPROP g_ExprEndOfExpOp =
1587{
1588 "", 0, '\0', 0, 0, NULL
1589};
1590
1591
1592/**
1593 * Initializes the opcode character map if necessary.
1594 */
1595static void expr_map_init(void)
1596{
1597 unsigned i;
1598 if (g_fExprInitializedMap)
1599 return;
1600
1601 /*
1602 * Initialize it.
1603 */
1604 memset(&g_auchOpStartCharMap, 0, sizeof(g_auchOpStartCharMap));
1605 for (i = 0; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++)
1606 {
1607 unsigned int ch = (unsigned int)g_aExprOps[i].szOp[0];
1608 if (!g_auchOpStartCharMap[ch])
1609 g_auchOpStartCharMap[ch] = (i << 1) | 1;
1610 }
1611
1612 g_fExprInitializedMap = 1;
1613}
1614
1615
1616/**
1617 * Looks up a character in the map.
1618 *
1619 * @returns the value for that char.
1620 * @retval 0 if not a potential opcode start char.
1621 * @retval non-zero if it's a potential operator. The low bit is always set
1622 * while the remaining 7 bits is the index into the operator table
1623 * of the first match.
1624 *
1625 * @param ch The character.
1626 */
1627static unsigned char expr_map_get(char ch)
1628{
1629 return g_auchOpStartCharMap[(unsigned int)ch];
1630}
1631
1632
1633/**
1634 * Searches the operator table given a potential operator start char.
1635 *
1636 * @returns Pointer to the matching operator. NULL if not found.
1637 * @param psz Pointer to what can be an operator.
1638 * @param uchVal The expr_map_get value.
1639 * @param fUnary Whether it must be an unary operator or not.
1640 */
1641static PCEXPROP expr_lookup_op(char const *psz, unsigned char uchVal, int fUnary)
1642{
1643 char ch = *psz;
1644 unsigned i;
1645
1646 for (i = uchVal >> 1; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++)
1647 {
1648 /* compare the string... */
1649 switch (g_aExprOps[i].cchOp)
1650 {
1651 case 1:
1652 if (g_aExprOps[i].szOp[0] != ch)
1653 continue;
1654 break;
1655 case 2:
1656 if ( g_aExprOps[i].szOp[0] != ch
1657 || g_aExprOps[i].szOp[1] != psz[1])
1658 continue;
1659 break;
1660 default:
1661 if ( g_aExprOps[i].szOp[0] != ch
1662 || strncmp(&g_aExprOps[i].szOp[1], psz + 1, g_aExprOps[i].cchOp - 1))
1663 continue;
1664 break;
1665 }
1666
1667 /* ... and the operator type. */
1668 if (fUnary == (g_aExprOps[i].cArgs == 1))
1669 {
1670 /* got a match! */
1671 return &g_aExprOps[i];
1672 }
1673 }
1674
1675 return NULL;
1676}
1677
1678
1679/**
1680 * Ungets a binary operator.
1681 *
1682 * The operator is poped from the stack and put in the pending position.
1683 *
1684 * @param pThis The evaluator instance.
1685 */
1686static void expr_unget_op(PEXPR pThis)
1687{
1688 assert(pThis->pPending == NULL);
1689 assert(pThis->iOp >= 0);
1690
1691 pThis->pPending = pThis->apOps[pThis->iOp];
1692 pThis->apOps[pThis->iOp] = NULL;
1693 pThis->iOp--;
1694}
1695
1696
1697
1698/**
1699 * Get the next token, it should be a binary operator, or the end of
1700 * the expression, or a right parenthesis.
1701 *
1702 * The operator is pushed onto the stack and the status code indicates
1703 * which of the two we found.
1704 *
1705 * @returns status code. Will grumble on failure.
1706 * @retval kExprRet_EndOfExpr if we encountered the end of the expression.
1707 * @retval kExprRet_Operator if we encountered a binary operator or right
1708 * parenthesis. It's on the operator stack.
1709 *
1710 * @param pThis The evaluator instance.
1711 */
1712static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis)
1713{
1714 /*
1715 * See if there is anything pending first.
1716 */
1717 PCEXPROP pOp = pThis->pPending;
1718 if (pOp)
1719 pThis->pPending = NULL;
1720 else
1721 {
1722 /*
1723 * Eat more of the expression.
1724 */
1725 char const *psz = pThis->psz;
1726
1727 /* spaces */
1728 while (isspace((unsigned int)*psz))
1729 psz++;
1730 /* see what we've got. */
1731 if (*psz)
1732 {
1733 unsigned char uchVal = expr_map_get(*psz);
1734 if (uchVal)
1735 pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */);
1736 if (!pOp)
1737 {
1738 expr_error(pThis, "Expected binary operator, found \"%.42s\"...", psz);
1739 return kExprRet_Error;
1740 }
1741 psz += pOp->cchOp;
1742 }
1743 else
1744 pOp = &g_ExprEndOfExpOp;
1745 pThis->psz = psz;
1746 }
1747
1748 /*
1749 * Push it.
1750 */
1751 if (pThis->iOp >= EXPR_MAX_OPERATORS - 1)
1752 {
1753 expr_error(pThis, "Operator stack overflow");
1754 return kExprRet_Error;
1755 }
1756 pThis->apOps[++pThis->iOp] = pOp;
1757
1758 return pOp->iPrecedence
1759 ? kExprRet_Operator
1760 : kExprRet_EndOfExpr;
1761}
1762
1763
1764
1765/**
1766 * Get the next token, it should be an unary operator or an operand.
1767 *
1768 * This will fail if encountering the end of the expression since
1769 * it is implied that there should be something more.
1770 *
1771 * The token is pushed onto the respective stack and the status code
1772 * indicates which it is.
1773 *
1774 * @returns status code. On failure we'll be done bitching already.
1775 * @retval kExprRet_Operator if we encountered an unary operator.
1776 * It's on the operator stack.
1777 * @retval kExprRet_Operand if we encountered an operand operator.
1778 * It's on the operand stack.
1779 *
1780 * @param This The evaluator instance.
1781 */
1782static EXPRRET expr_get_unary_or_operand(PEXPR pThis)
1783{
1784 EXPRRET rc;
1785 unsigned char uchVal;
1786 PCEXPROP pOp;
1787 char const *psz = pThis->psz;
1788
1789 /*
1790 * Eat white space and make sure there is something after it.
1791 */
1792 while (isspace((unsigned int)*psz))
1793 psz++;
1794 if (!*psz)
1795 {
1796 expr_error(pThis, "Unexpected end of expression");
1797 return kExprRet_Error;
1798 }
1799
1800 /*
1801 * Is it an operator?
1802 */
1803 pOp = NULL;
1804 uchVal = expr_map_get(*psz);
1805 if (uchVal)
1806 pOp = expr_lookup_op(psz, uchVal, 1 /* fUnary */);
1807 if (pOp)
1808 {
1809 /*
1810 * Push the operator onto the stack.
1811 */
1812 if (pThis->iVar < EXPR_MAX_OPERANDS - 1)
1813 {
1814 pThis->apOps[++pThis->iOp] = pOp;
1815 rc = kExprRet_Operator;
1816 }
1817 else
1818 {
1819 expr_error(pThis, "Operator stack overflow");
1820 rc = kExprRet_Error;
1821 }
1822 psz += pOp->cchOp;
1823 }
1824 else if (pThis->iVar < EXPR_MAX_OPERANDS - 1)
1825 {
1826 /*
1827 * It's an operand. Figure out where it ends and
1828 * push it onto the stack.
1829 */
1830 const char *pszStart = psz;
1831
1832 rc = kExprRet_Ok;
1833 if (*psz == '"')
1834 {
1835 pszStart++;
1836 while (*psz && *psz != '"')
1837 psz++;
1838 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedString);
1839 }
1840 else if (*psz == '\'')
1841 {
1842 pszStart++;
1843 while (*psz && *psz != '\'')
1844 psz++;
1845 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedSimpleString);
1846 }
1847 else
1848 {
1849 char achPars[20];
1850 int iPar = -1;
1851 char chEndPar = '\0';
1852 char ch;
1853
1854 while ((ch = *psz) != '\0')
1855 {
1856 /* $(adsf) or ${asdf} needs special handling. */
1857 if ( ch == '$'
1858 && ( psz[1] == '('
1859 || psz[1] == '{'))
1860 {
1861 psz++;
1862 if (iPar > (int)(sizeof(achPars) / sizeof(achPars[0])))
1863 {
1864 expr_error(pThis, "Too deep nesting of variable expansions");
1865 rc = kExprRet_Error;
1866 break;
1867 }
1868 achPars[++iPar] = chEndPar = ch == '(' ? ')' : '}';
1869 }
1870 else if (ch == chEndPar)
1871 {
1872 iPar--;
1873 chEndPar = iPar >= 0 ? achPars[iPar] : '\0';
1874 }
1875 else if (!chEndPar)
1876 {
1877 /** @todo combine isspace and expr_map_get! */
1878 unsigned chVal = expr_map_get(ch);
1879 if (chVal)
1880 {
1881 PCEXPROP pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */);
1882 if (pOp)
1883 break;
1884 }
1885 if (isspace((unsigned char)ch))
1886 break;
1887 }
1888
1889 /* next */
1890 psz++;
1891 }
1892
1893 if (rc == kExprRet_Ok)
1894 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_String);
1895 }
1896 }
1897 else
1898 {
1899 expr_error(pThis, "Operand stack overflow");
1900 rc = kExprRet_Error;
1901 }
1902 pThis->psz = psz;
1903
1904 return rc;
1905}
1906
1907
1908/**
1909 * Evaluates the current expression.
1910 *
1911 * @returns status code.
1912 *
1913 * @param pThis The instance.
1914 */
1915static EXPRRET expr_eval(PEXPR pThis)
1916{
1917 EXPRRET rc;
1918 PCEXPROP pOp;
1919
1920 /*
1921 * The main loop.
1922 */
1923 for (;;)
1924 {
1925 /*
1926 * Eat unary operators until we hit an operand.
1927 */
1928 do rc = expr_get_unary_or_operand(pThis);
1929 while (rc == kExprRet_Operator);
1930 if (rc < kExprRet_Error)
1931 break;
1932
1933 /*
1934 * Look for a binary operator, right parenthesis or end of expression.
1935 */
1936 rc = expr_get_binary_or_eoe_or_rparen(pThis);
1937 if (rc < kExprRet_Error)
1938 break;
1939 expr_unget_op(pThis);
1940
1941 /*
1942 * Pop operators and apply them.
1943 *
1944 * Parenthesis will be handed via precedence, where the left parenthesis
1945 * will go pop the right one and make another operator pending.
1946 */
1947 while ( pThis->iOp >= 0
1948 && pThis->apOps[pThis->iOp]->iPrecedence >= pThis->pPending->iPrecedence)
1949 {
1950 pOp = pThis->apOps[pThis->iOp--];
1951 rc = pOp->pfn(pThis);
1952 if (rc < kExprRet_Error)
1953 break;
1954 }
1955 if (rc < kExprRet_Error)
1956 break;
1957
1958 /*
1959 * Get the next binary operator or end of expression.
1960 * There should be no right parenthesis here.
1961 */
1962 rc = expr_get_binary_or_eoe_or_rparen(pThis);
1963 if (rc < kExprRet_Error)
1964 break;
1965 pOp = pThis->apOps[pThis->iOp];
1966 if (!pOp->iPrecedence)
1967 break; /* end of expression */
1968 if (!pOp->cArgs)
1969 {
1970 expr_error(pThis, "Unexpected \"%s\"", pOp->szOp);
1971 rc = kExprRet_Error;
1972 break;
1973 }
1974 }
1975
1976 return rc;
1977}
1978
1979
1980/**
1981 * Destroys the given instance.
1982 *
1983 * @param pThis The instance to destroy.
1984 */
1985static void expr_destroy(PEXPR pThis)
1986{
1987 while (pThis->iVar >= 0)
1988 {
1989 expr_var_delete(pThis->aVars);
1990 pThis->iVar--;
1991 }
1992 free(pThis);
1993}
1994
1995
1996/**
1997 * Instantiates an expression evaluator.
1998 *
1999 * @returns The instance.
2000 *
2001 * @param pszExpr What to parse.
2002 * This must stick around until expr_destroy.
2003 */
2004static PEXPR expr_create(char const *pszExpr)
2005{
2006 PEXPR pThis = (PEXPR)xmalloc(sizeof(*pThis));
2007 pThis->pszExpr = pszExpr;
2008 pThis->psz = pszExpr;
2009 pThis->pFileLoc = NULL;
2010 pThis->pPending = NULL;
2011 pThis->iVar = -1;
2012 pThis->iOp = -1;
2013
2014 expr_map_init();
2015 return pThis;
2016}
2017
2018
2019/**
2020 * Evaluates the given if expression.
2021 *
2022 * @returns -1, 0 or 1.
2023 * @retval -1 if the expression is invalid.
2024 * @retval 0 if the expression is true
2025 * @retval 1 if the expression is false.
2026 *
2027 * @param line The expression. Can modify this as we like.
2028 * @param flocp The file location, used for errors.
2029 */
2030int expr_eval_if_conditionals(char *line, const struct floc *flocp)
2031{
2032 /*
2033 * Instantiate the expression evaluator and let
2034 * it have a go at it.
2035 */
2036 int rc = -1;
2037 PEXPR pExpr = expr_create(line);
2038 pExpr->pFileLoc = flocp;
2039 if (expr_eval(pExpr) >= kExprRet_Ok)
2040 {
2041 /*
2042 * Convert the result (on top of the stack) to boolean and
2043 * set our return value accordingly.
2044 */
2045 if (expr_var_make_bool(&pExpr->aVars[0]))
2046 rc = 0;
2047 else
2048 rc = 1;
2049 }
2050 expr_destroy(pExpr);
2051
2052 return rc;
2053}
2054
2055
2056/**
2057 * Evaluates the given expression and returns the result as a string.
2058 *
2059 * @returns variable buffer position.
2060 *
2061 * @param o The current variable buffer position.
2062 * @param expr The expression.
2063 */
2064char *expr_eval_to_string(char *o, char *expr)
2065{
2066 /*
2067 * Instantiate the expression evaluator and let
2068 * it have a go at it.
2069 */
2070 PEXPR pExpr = expr_create(expr);
2071 if (expr_eval(pExpr) >= kExprRet_Ok)
2072 {
2073 /*
2074 * Convert the result (on top of the stack) to a string
2075 * and copy it out the variable buffer.
2076 */
2077 PEXPRVAR pVar = &pExpr->aVars[0];
2078 expr_var_make_simple_string(pVar);
2079 o = variable_buffer_output(o, pVar->uVal.psz, strlen(pVar->uVal.psz));
2080 }
2081 else
2082 o = variable_buffer_output(o, "<expression evaluation failed>", sizeof("<expression evaluation failed>") - 1);
2083 expr_destroy(pExpr);
2084
2085 return o;
2086}
2087
2088
2089#endif /* CONFIG_WITH_IF_CONDITIONALS */
2090
Note: See TracBrowser for help on using the repository browser.