Hi jan, thanks for the answer
I think you probably misunderstood me. Let me clarify.
In your example, '-' or 'not' can be a puop. Several things:
1. There are times when I want to make "puop puop puop x" illegal. Think about it, is it really okay to write "not not not not my_business"? If this example is not convincing enough, think about "load_address_of_variable", here we shorten as 'la'. Does it make sense to do "la la la x"??
2. For some binary operations such as binary comparison, associativity sometimes does not make sense, or at least we want to make it illegal. The answer given in the stackoverflow post is mutually left-recursive. Using post-processing as suggested in the comments looks like a hack. Now, consider these 2 natural solutions
Method 1:
expr
: ID
| expr '*' expr
| expr '+' expr
| expr '<' expr; // this is undesirable, since we intend for comparison to be non-associative. But we can recover from this using post-processing
Method 2:
expr1
: ID
| expr '*' expr
| expr '+' expr;
expr2 : expr1 | expr1 '<' expr1; // this introduces a new non-terminal
Method1 is undesirable because it requires extra post-processing. Method2 is also undesirable because for something as simple as ID you get a 2-level parse tree expr2(expr1(ID)) instead of a simple expr(ID). This is what I mean by ugly parse tree: it is unnecessarily deeply nested. Suppose we could use <assoc=none>, then the above grammar could be written as:
Method 3:
expr
: ID
| expr '*' expr
| eppr '+' expr
| <assoc=none> expr '<' expr;
which resolves all our problems. In the example I've given, expr2(expr1(ID)) does not seem that deep. In real, serious grammar, it can be much deeper, with a long chain of precedence like assoc_op > nonassoc_op > assoc_op > nonassoc_op and so on. When we encounter this kind of grammar, deeply-nested parse tree with a single branch that goes all the way down is really ugly. Even though we can produce decent-looking AST with trivial post-processing on the parse tree, the parse tree itself sometimes must be preserved. Some processing are run directly on the parse tree instead of on the AST. I'm doing one of such applications, which is why I am complaining.
I think <assoc=none> is not absolutely essential. However, in some applications, it does get pretty handy if it is supported. I understand supporting it makes recursive-descent parsers a bit trickier to write. But antlr already supports left recursion, so I suppose supporting nonassoc is relatively straightforward.
Please comment.
Thanks,
Yunqing