1 # $NetBSD: cond-op.mk,v 1.13 2021/01/19 18:20:30 rillig Exp $
3 # Tests for operators like &&, ||, ! in .if conditions.
9 # cond-op-parentheses.mk
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
20 # If make were to interpret the && and || operators like the shell, the
21 # previous condition would be interpreted as:
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.
30 # This kind of condition looks so unfamiliar that it doesn't occur in
36 # This is how the above condition is actually interpreted.
37 .if !("word" == "word")
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.
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.
54 # Surprisingly, the ampersand and pipe are allowed in bare strings.
55 # That's another opportunity for writing confusing code.
56 # See CondParser_String, which only has '!' in the list of stop characters.
57 .if "a&&b||c" != a&&b||c
61 # As soon as the parser sees the '$', it knows that the condition will
62 # be malformed. Therefore there is no point in evaluating it.
64 # As of 2021-01-20, that part of the condition is evaluated nevertheless,
65 # since CondParser_Or just requests the next token, without restricting
66 # the token to the expected tokens. If the parser were to restrict the
67 # valid follow tokens for the token "0" to those that can actually produce
68 # a correct condition (which in this case would be comparison operators,
69 # TOK_AND, TOK_OR or TOK_RPAREN), the variable expression would not have
72 # This would add a good deal of complexity to the code though, for almost
73 # no benefit, especially since most expressions and conditions are side
75 .if 0 ${ERR::=evaluated}
78 .if ${ERR:Uundefined} == evaluated
79 . info After detecting a parse error, the rest is evaluated.
82 # Just in case that parsing should ever stop on the first error.
83 .info Parsing continues until here.
85 # Demonstration that '&&' has higher precedence than '||'.
86 .info A B C => (A || B) && C A || B && C A || (B && C)
90 . for r1 in ${ ($a || $b) && $c :?1:0}
91 . for r2 in ${ $a || $b && $c :?1:0}
92 . for r3 in ${ $a || ($b && $c) :?1:0}
93 . info $a $b $c => ${r1} ${r2} ${r3}
101 # This condition is obviously malformed. It is properly detected and also
102 # was properly detected before 2021-01-19, but only because the left hand
103 # side of the '&&' evaluated to true.
110 # This obviously malformed condition was not detected as such before cond.c
111 # 1.238 from 2021-01-19.
118 # This obviously malformed condition was not detected as such before cond.c
119 # 1.238 from 2021-01-19.
126 # This condition is obviously malformed. It is properly detected and also
127 # was properly detected before 2021-01-19, but only because the left hand
128 # side of the '||' evaluated to false.