One other bit of randomness that I noticed: ecpg's parse.pl has this undocumented bit of logic:
if ($a eq 'IDENT' && $prior eq '%nonassoc') { # add more tokens to the list $str = $str . "\n%nonassoc CSTRING"; } The net effect of that is that, where gram.y writes %nonassoc UNBOUNDED NESTED /* ideally would have same precedence as IDENT */ %nonassoc IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP SET KEYS OBJECT_P SCALAR VALUE_P WITH WITHOUT PATH %left Op OPERATOR /* multi-character ops and user-defined operators */ preproc.c has %nonassoc UNBOUNDED NESTED %nonassoc IDENT %nonassoc CSTRING PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP SET KEYS OBJECT_P SCALAR VALUE_P WITH WITHOUT PATH %left Op OPERATOR If you don't find that scary as heck, I suggest reading the very long comment just in front of the cited lines of gram.y. The argument why assigning these keywords a precedence at all is OK depends heavily on it being the same precedence as IDENT, yet here's ECPG randomly breaking that. We seem to have avoided problems though, because if I fix things by manually editing preproc.y to re-join the lines: %nonassoc IDENT CSTRING PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP the generated preproc.c doesn't change at all. Actually, I can take CSTRING out of this list altogether and it still doesn't change the results ... although looking at how CSTRING is used, it looks safer to give it the same precedence as IDENT. I think we should change parse.pl to give one or the other of these results before something more serious breaks there. regards, tom lane