> The POSIX Awk specifies *no* associativity for the relational operators
> (<, <=, >, >=, ==, !=, ~, !~). But the 'in' operator is defined to have
> left-asscotiativity.
Historic notes.
In 1979, Awk already had "for (x in y) ...", but not the "x in y"
expression.
The "x in y" expression appeared surprisingly late, between 1992 and 1996.
The IN operator token was classified as %nonassoc at that time.
It remained %nonassoc after that.
However, the grammar is actually
ppattern IN varname
Where ppatern can derive a varname via ppatern -> term -> var -> varname.
The productions for ppattern are all left-recursive.
This left recursion determines the parse for x in y in z, making it
left-associative.
The %nonassoc declaration that was introduced for the IN token
is effectively useless.
It seems that the *intent* was to make it non-associative,
that wish being expressed clearly with the %nonassoc. But because of the way
the operator was worked into a left-recursive grammar production, it became
effectively left-associative.
Given an input like
x in y in z
the parser will shift the x token (the position indicated by the dot).
x . in y in z
There is no ambiguity; the parser must reduce the previous material
through several reductions:
varname . in y in z
var . in y in z
term . in y in z
ppattern . in y in z
Now the parse can continue by shifting the two tokens:
ppattern in y . in z
There is no ambiguity here, either; the left part "pattern in y" in the parse
stack must be reduced to a ppattern, because only ppattern as a whole
takes an 'in' operator:
ppattern . in z
Now there is a pattern which matches the production rule, and so
the parse continues:
ppattern in . z # shift 'in' onto stack
ppattern in z . # now reduce z -> varname
ppattern in varname . # then reduce ppattern in varname -> ppattern
ppattern # left-associative parse done.