VirtualBox

source: kBuild/trunk/src/kmk/expreval.c@ 3387

Last change on this file since 3387 was 3141, checked in by bird, 6 years ago

kmk: linux merge fixes.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use