1 1.18 rillig # $NetBSD: cond-op.mk,v 1.18 2025/06/28 22:39:28 rillig Exp $ 2 1.1 rillig # 3 1.2 rillig # Tests for operators like &&, ||, ! in .if conditions. 4 1.3 rillig # 5 1.3 rillig # See also: 6 1.3 rillig # cond-op-and.mk 7 1.3 rillig # cond-op-not.mk 8 1.3 rillig # cond-op-or.mk 9 1.3 rillig # cond-op-parentheses.mk 10 1.3 rillig 11 1.3 rillig # In make, && binds more tightly than ||, like in C. 12 1.10 rillig # If make had the same precedence for both && and ||, like in the shell, 13 1.10 rillig # the result would be different. 14 1.3 rillig # If || were to bind more tightly than &&, the result would be different 15 1.3 rillig # as well. 16 1.3 rillig .if !(1 || 1 && 0) 17 1.8 rillig . error 18 1.3 rillig .endif 19 1.3 rillig 20 1.3 rillig # If make were to interpret the && and || operators like the shell, the 21 1.10 rillig # previous condition would be interpreted as: 22 1.3 rillig .if (1 || 1) && 0 23 1.8 rillig . error 24 1.3 rillig .endif 25 1.3 rillig 26 1.3 rillig # The precedence of the ! operator is different from C though. It has a 27 1.10 rillig # lower precedence than the comparison operators. Negating a condition 28 1.10 rillig # does not need parentheses. 29 1.10 rillig # 30 1.10 rillig # This kind of condition looks so unfamiliar that it doesn't occur in 31 1.10 rillig # practice. 32 1.3 rillig .if !"word" == "word" 33 1.8 rillig . error 34 1.3 rillig .endif 35 1.3 rillig 36 1.3 rillig # This is how the above condition is actually interpreted. 37 1.3 rillig .if !("word" == "word") 38 1.8 rillig . error 39 1.3 rillig .endif 40 1.1 rillig 41 1.3 rillig # TODO: Demonstrate that the precedence of the ! and == operators actually 42 1.3 rillig # makes a difference. There is a simple example for sure, I just cannot 43 1.10 rillig # wrap my head around it right now. See the truth table generator below 44 1.10 rillig # for an example that doesn't require much thought. 45 1.1 rillig 46 1.4 rillig # This condition is malformed because the '!' on the right-hand side must not 47 1.4 rillig # appear unquoted. If any, it must be enclosed in quotes. 48 1.4 rillig # In any case, it is not interpreted as a negation of an unquoted string. 49 1.6 rillig # See CondParser_String. 50 1.18 rillig # expect+1: Malformed conditional ""!word" == !word" 51 1.4 rillig .if "!word" == !word 52 1.8 rillig . error 53 1.4 rillig .endif 54 1.4 rillig 55 1.4 rillig # Surprisingly, the ampersand and pipe are allowed in bare strings. 56 1.4 rillig # That's another opportunity for writing confusing code. 57 1.5 rillig # See CondParser_String, which only has '!' in the list of stop characters. 58 1.4 rillig .if "a&&b||c" != a&&b||c 59 1.8 rillig . error 60 1.4 rillig .endif 61 1.4 rillig 62 1.15 rillig # In the following malformed conditions, as soon as the parser sees the '$' 63 1.15 rillig # after the '0' or the '1', it knows that the condition will be malformed. 64 1.15 rillig # Therefore there is no point in evaluating the misplaced expression. 65 1.15 rillig # 66 1.15 rillig # Before cond.c 1.286 from 2021-12-10, the extra expression was evaluated 67 1.15 rillig # nevertheless, since CondParser_Or and CondParser_And asked for the expanded 68 1.15 rillig # next token, even though in this position of the condition, only comparison 69 1.15 rillig # operators, TOK_AND, TOK_OR or TOK_RPAREN are allowed. 70 1.14 rillig .undef ERR 71 1.18 rillig # expect+1: Malformed conditional "0 ${ERR::=evaluated}" 72 1.6 rillig .if 0 ${ERR::=evaluated} 73 1.6 rillig . error 74 1.6 rillig .endif 75 1.15 rillig .if ${ERR:Uundefined} == undefined 76 1.16 rillig # expect+1: A misplaced expression after 0 is not evaluated. 77 1.15 rillig . info A misplaced expression after 0 is not evaluated. 78 1.14 rillig .endif 79 1.14 rillig 80 1.14 rillig .undef ERR 81 1.18 rillig # expect+1: Malformed conditional "1 ${ERR::=evaluated}" 82 1.14 rillig .if 1 ${ERR::=evaluated} 83 1.14 rillig . error 84 1.14 rillig .endif 85 1.15 rillig .if ${ERR:Uundefined} == undefined 86 1.16 rillig # expect+1: A misplaced expression after 1 is not evaluated. 87 1.15 rillig . info A misplaced expression after 1 is not evaluated. 88 1.6 rillig .endif 89 1.6 rillig 90 1.4 rillig 91 1.9 rillig # Demonstration that '&&' has higher precedence than '||'. 92 1.16 rillig # expect+1: A B C => (A || B) && C A || B && C A || (B && C) 93 1.9 rillig .info A B C => (A || B) && C A || B && C A || (B && C) 94 1.9 rillig .for a in 0 1 95 1.9 rillig . for b in 0 1 96 1.9 rillig . for c in 0 1 97 1.9 rillig . for r1 in ${ ($a || $b) && $c :?1:0} 98 1.9 rillig . for r2 in ${ $a || $b && $c :?1:0} 99 1.9 rillig . for r3 in ${ $a || ($b && $c) :?1:0} 100 1.16 rillig # expect+8: 0 0 0 => 0 0 0 101 1.16 rillig # expect+7: 0 0 1 => 0 0 0 102 1.16 rillig # expect+6: 0 1 0 => 0 0 0 103 1.16 rillig # expect+5: 0 1 1 => 1 1 1 104 1.16 rillig # expect+4: 1 0 0 => 0 1 1 105 1.16 rillig # expect+3: 1 0 1 => 1 1 1 106 1.16 rillig # expect+2: 1 1 0 => 0 1 1 107 1.16 rillig # expect+1: 1 1 1 => 1 1 1 108 1.9 rillig . info $a $b $c => ${r1} ${r2} ${r3} 109 1.9 rillig . endfor 110 1.9 rillig . endfor 111 1.9 rillig . endfor 112 1.9 rillig . endfor 113 1.9 rillig . endfor 114 1.9 rillig .endfor 115 1.9 rillig 116 1.11 rillig # This condition is obviously malformed. It is properly detected and also 117 1.11 rillig # was properly detected before 2021-01-19, but only because the left hand 118 1.11 rillig # side of the '&&' evaluated to true. 119 1.18 rillig # expect+1: Malformed conditional "1 &&" 120 1.11 rillig .if 1 && 121 1.11 rillig . error 122 1.11 rillig .else 123 1.11 rillig . error 124 1.11 rillig .endif 125 1.11 rillig 126 1.12 rillig # This obviously malformed condition was not detected as such before cond.c 127 1.12 rillig # 1.238 from 2021-01-19. 128 1.18 rillig # expect+1: Malformed conditional "0 &&" 129 1.11 rillig .if 0 && 130 1.11 rillig . error 131 1.11 rillig .else 132 1.11 rillig . error 133 1.11 rillig .endif 134 1.11 rillig 135 1.12 rillig # This obviously malformed condition was not detected as such before cond.c 136 1.12 rillig # 1.238 from 2021-01-19. 137 1.18 rillig # expect+1: Malformed conditional "1 ||" 138 1.11 rillig .if 1 || 139 1.11 rillig . error 140 1.11 rillig .else 141 1.11 rillig . error 142 1.11 rillig .endif 143 1.11 rillig 144 1.11 rillig # This condition is obviously malformed. It is properly detected and also 145 1.11 rillig # was properly detected before 2021-01-19, but only because the left hand 146 1.11 rillig # side of the '||' evaluated to false. 147 1.18 rillig # expect+1: Malformed conditional "0 ||" 148 1.11 rillig .if 0 || 149 1.11 rillig . error 150 1.11 rillig .else 151 1.11 rillig . error 152 1.11 rillig .endif 153 1.11 rillig 154 1.1 rillig all: 155 1.1 rillig @:; 156