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