1*a8c56be4SSimon J. Gerraty# $NetBSD: cond-op.mk,v 1.18 2025/06/28 22:39:28 rillig Exp $ 22c3632d1SSimon J. Gerraty# 32c3632d1SSimon J. Gerraty# Tests for operators like &&, ||, ! in .if conditions. 42c3632d1SSimon J. Gerraty# 52c3632d1SSimon J. Gerraty# See also: 62c3632d1SSimon J. Gerraty# cond-op-and.mk 72c3632d1SSimon J. Gerraty# cond-op-not.mk 82c3632d1SSimon J. Gerraty# cond-op-or.mk 92c3632d1SSimon J. Gerraty# cond-op-parentheses.mk 102c3632d1SSimon J. Gerraty 112c3632d1SSimon J. Gerraty# In make, && binds more tightly than ||, like in C. 12e2eeea75SSimon J. Gerraty# If make had the same precedence for both && and ||, like in the shell, 13e2eeea75SSimon J. Gerraty# the result would be different. 142c3632d1SSimon J. Gerraty# If || were to bind more tightly than &&, the result would be different 152c3632d1SSimon J. Gerraty# as well. 162c3632d1SSimon J. Gerraty.if !(1 || 1 && 0) 172c3632d1SSimon J. Gerraty. error 182c3632d1SSimon J. Gerraty.endif 192c3632d1SSimon J. Gerraty 202c3632d1SSimon J. Gerraty# If make were to interpret the && and || operators like the shell, the 21e2eeea75SSimon J. Gerraty# previous condition would be interpreted as: 222c3632d1SSimon J. Gerraty.if (1 || 1) && 0 232c3632d1SSimon J. Gerraty. error 242c3632d1SSimon J. Gerraty.endif 252c3632d1SSimon J. Gerraty 262c3632d1SSimon J. Gerraty# The precedence of the ! operator is different from C though. It has a 27e2eeea75SSimon J. Gerraty# lower precedence than the comparison operators. Negating a condition 28e2eeea75SSimon J. Gerraty# does not need parentheses. 29e2eeea75SSimon J. Gerraty# 30e2eeea75SSimon J. Gerraty# This kind of condition looks so unfamiliar that it doesn't occur in 31e2eeea75SSimon J. Gerraty# practice. 322c3632d1SSimon J. Gerraty.if !"word" == "word" 332c3632d1SSimon J. Gerraty. error 342c3632d1SSimon J. Gerraty.endif 352c3632d1SSimon J. Gerraty 362c3632d1SSimon J. Gerraty# This is how the above condition is actually interpreted. 372c3632d1SSimon J. Gerraty.if !("word" == "word") 382c3632d1SSimon J. Gerraty. error 392c3632d1SSimon J. Gerraty.endif 402c3632d1SSimon J. Gerraty 412c3632d1SSimon J. Gerraty# TODO: Demonstrate that the precedence of the ! and == operators actually 422c3632d1SSimon J. Gerraty# makes a difference. There is a simple example for sure, I just cannot 43e2eeea75SSimon J. Gerraty# wrap my head around it right now. See the truth table generator below 44e2eeea75SSimon J. Gerraty# for an example that doesn't require much thought. 452c3632d1SSimon J. Gerraty 462c3632d1SSimon J. Gerraty# This condition is malformed because the '!' on the right-hand side must not 472c3632d1SSimon J. Gerraty# appear unquoted. If any, it must be enclosed in quotes. 482c3632d1SSimon J. Gerraty# In any case, it is not interpreted as a negation of an unquoted string. 49956e45f6SSimon J. Gerraty# See CondParser_String. 50*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional ""!word" == !word" 512c3632d1SSimon J. Gerraty.if "!word" == !word 522c3632d1SSimon J. Gerraty. error 532c3632d1SSimon J. Gerraty.endif 542c3632d1SSimon J. Gerraty 552c3632d1SSimon J. Gerraty# Surprisingly, the ampersand and pipe are allowed in bare strings. 562c3632d1SSimon J. Gerraty# That's another opportunity for writing confusing code. 57956e45f6SSimon J. Gerraty# See CondParser_String, which only has '!' in the list of stop characters. 582c3632d1SSimon J. Gerraty.if "a&&b||c" != a&&b||c 592c3632d1SSimon J. Gerraty. error 602c3632d1SSimon J. Gerraty.endif 612c3632d1SSimon J. Gerraty 6212904384SSimon J. Gerraty# In the following malformed conditions, as soon as the parser sees the '$' 6312904384SSimon J. Gerraty# after the '0' or the '1', it knows that the condition will be malformed. 6412904384SSimon J. Gerraty# Therefore there is no point in evaluating the misplaced expression. 65956e45f6SSimon J. Gerraty# 6612904384SSimon J. Gerraty# Before cond.c 1.286 from 2021-12-10, the extra expression was evaluated 6712904384SSimon J. Gerraty# nevertheless, since CondParser_Or and CondParser_And asked for the expanded 6812904384SSimon J. Gerraty# next token, even though in this position of the condition, only comparison 6912904384SSimon J. Gerraty# operators, TOK_AND, TOK_OR or TOK_RPAREN are allowed. 7012904384SSimon J. Gerraty.undef ERR 71*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "0 ${ERR::=evaluated}" 72956e45f6SSimon J. Gerraty.if 0 ${ERR::=evaluated} 73956e45f6SSimon J. Gerraty. error 74956e45f6SSimon J. Gerraty.endif 7512904384SSimon J. Gerraty.if ${ERR:Uundefined} == undefined 76148ee845SSimon J. Gerraty# expect+1: A misplaced expression after 0 is not evaluated. 7712904384SSimon J. Gerraty. info A misplaced expression after 0 is not evaluated. 7812904384SSimon J. Gerraty.endif 7912904384SSimon J. Gerraty 8012904384SSimon J. Gerraty.undef ERR 81*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "1 ${ERR::=evaluated}" 8212904384SSimon J. Gerraty.if 1 ${ERR::=evaluated} 8312904384SSimon J. Gerraty. error 8412904384SSimon J. Gerraty.endif 8512904384SSimon J. Gerraty.if ${ERR:Uundefined} == undefined 86148ee845SSimon J. Gerraty# expect+1: A misplaced expression after 1 is not evaluated. 8712904384SSimon J. Gerraty. info A misplaced expression after 1 is not evaluated. 88956e45f6SSimon J. Gerraty.endif 89956e45f6SSimon J. Gerraty 902c3632d1SSimon J. Gerraty 91e2eeea75SSimon J. Gerraty# Demonstration that '&&' has higher precedence than '||'. 92148ee845SSimon J. Gerraty# expect+1: A B C => (A || B) && C A || B && C A || (B && C) 93e2eeea75SSimon J. Gerraty.info A B C => (A || B) && C A || B && C A || (B && C) 94e2eeea75SSimon J. Gerraty.for a in 0 1 95e2eeea75SSimon J. Gerraty. for b in 0 1 96e2eeea75SSimon J. Gerraty. for c in 0 1 97e2eeea75SSimon J. Gerraty. for r1 in ${ ($a || $b) && $c :?1:0} 98e2eeea75SSimon J. Gerraty. for r2 in ${ $a || $b && $c :?1:0} 99e2eeea75SSimon J. Gerraty. for r3 in ${ $a || ($b && $c) :?1:0} 100148ee845SSimon J. Gerraty# expect+8: 0 0 0 => 0 0 0 101148ee845SSimon J. Gerraty# expect+7: 0 0 1 => 0 0 0 102148ee845SSimon J. Gerraty# expect+6: 0 1 0 => 0 0 0 103148ee845SSimon J. Gerraty# expect+5: 0 1 1 => 1 1 1 104148ee845SSimon J. Gerraty# expect+4: 1 0 0 => 0 1 1 105148ee845SSimon J. Gerraty# expect+3: 1 0 1 => 1 1 1 106148ee845SSimon J. Gerraty# expect+2: 1 1 0 => 0 1 1 107148ee845SSimon J. Gerraty# expect+1: 1 1 1 => 1 1 1 108e2eeea75SSimon J. Gerraty. info $a $b $c => ${r1} ${r2} ${r3} 109e2eeea75SSimon J. Gerraty. endfor 110e2eeea75SSimon J. Gerraty. endfor 111e2eeea75SSimon J. Gerraty. endfor 112e2eeea75SSimon J. Gerraty. endfor 113e2eeea75SSimon J. Gerraty. endfor 114e2eeea75SSimon J. Gerraty.endfor 115e2eeea75SSimon J. Gerraty 116dba7b0efSSimon J. Gerraty# This condition is obviously malformed. It is properly detected and also 117dba7b0efSSimon J. Gerraty# was properly detected before 2021-01-19, but only because the left hand 118dba7b0efSSimon J. Gerraty# side of the '&&' evaluated to true. 119*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "1 &&" 120dba7b0efSSimon J. Gerraty.if 1 && 121dba7b0efSSimon J. Gerraty. error 122dba7b0efSSimon J. Gerraty.else 123dba7b0efSSimon J. Gerraty. error 124dba7b0efSSimon J. Gerraty.endif 125dba7b0efSSimon J. Gerraty 126dba7b0efSSimon J. Gerraty# This obviously malformed condition was not detected as such before cond.c 127dba7b0efSSimon J. Gerraty# 1.238 from 2021-01-19. 128*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "0 &&" 129dba7b0efSSimon J. Gerraty.if 0 && 130dba7b0efSSimon J. Gerraty. error 131dba7b0efSSimon J. Gerraty.else 132dba7b0efSSimon J. Gerraty. error 133dba7b0efSSimon J. Gerraty.endif 134dba7b0efSSimon J. Gerraty 135dba7b0efSSimon J. Gerraty# This obviously malformed condition was not detected as such before cond.c 136dba7b0efSSimon J. Gerraty# 1.238 from 2021-01-19. 137*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "1 ||" 138dba7b0efSSimon J. Gerraty.if 1 || 139dba7b0efSSimon J. Gerraty. error 140dba7b0efSSimon J. Gerraty.else 141dba7b0efSSimon J. Gerraty. error 142dba7b0efSSimon J. Gerraty.endif 143dba7b0efSSimon J. Gerraty 144dba7b0efSSimon J. Gerraty# This condition is obviously malformed. It is properly detected and also 145dba7b0efSSimon J. Gerraty# was properly detected before 2021-01-19, but only because the left hand 146dba7b0efSSimon J. Gerraty# side of the '||' evaluated to false. 147*a8c56be4SSimon J. Gerraty# expect+1: Malformed conditional "0 ||" 148dba7b0efSSimon J. Gerraty.if 0 || 149dba7b0efSSimon J. Gerraty. error 150dba7b0efSSimon J. Gerraty.else 151dba7b0efSSimon J. Gerraty. error 152dba7b0efSSimon J. Gerraty.endif 153dba7b0efSSimon J. Gerraty 1542c3632d1SSimon J. Gerratyall: 1552c3632d1SSimon J. Gerraty @:; 156