The TYPENAME ::NAME Problem --------------------------- 2005-08-14 This document explains the precedence and associativity of "::" in cc.gr, and the use of explicit precedence("::") annotations. The scope qualification operator "::" is syntactically ambiguous, because it can be used as either unary (::a) or binary (a::b), and C++ syntax allows identifiers to be juxtaposed in the declaration syntax (e.g. "a b;" declaring 'b' of type 'a'). For example, the syntax A :: B :: C :: D :: E; could be parsed as a declaration four different ways, since any of the four "::" could be interpreted as being just after the dividing point (and hence a unary qualifier). (You might object that you don't declare qualified names; but you do in a 'friend' declaration, out-of-line member definitions, and in a few other places, so the parser basically has to assume qualified declarators can occur anywhere. The type checker then deals with the ruling out the bad cases.) I cannot find any place in the standard that justifies this, but every C++ compiler I've experimented with regards "::" as binding very tightly, such that any occurrence of an identifier followed by "::" is always interpreted as an attempt to use the binary "::", even when the identifier is not a class or namespace (in/t0565.cc). Previously, my solution was to use the keep() function to discard parsing alternatives that juxtaposed an identifier with unary "::". However, this is too late to prevent a multi-yield problem with ElaboratedOrSpecifier (in/t0564.cc), and for performance reasons I do not want to allow multi-yield there. So, the new solution is to use precedence and associativity. I give "::" right associativity. Then, for all all rules involved in constructing qualified names (especially sibling rules of rules that include the "::" terminal in their RHS), I make sure all rules have the precedence of "::" (with an explicit precedence specification where necessary). The usual way this works is, given a nominal scenario: (1) PQName -> Identifier precedence("::") (2) PQName -> Identifier "::" PQName after the parser sees an identifier, and the lookahead symbol is "::", the parser must choose between reducing by rule (1) or shifting the "::" in hopes of eventually reducing by rule (2). As these rules will have the same precedence, the right-associativity of "::" means to shift, which is the intended resolution. (I also give "::" high precedence, in hopes of reducing the chances of unintended impacts of this change. It should not cause any problems since, indeed, no operator can bind more tightly.) There are a few places where rules that have siblings containing "::" are not explicitly annotated with precedence("::"): - IdExpression: not needed, it's above the S/R - ColonColonOpt: not needed, always followed by "new" - NameAfterDot and friends: I think you can't juxtapose after a dot, so the S/R conflict should not arise. - PQTypeName: above S/R (but PQTypeName_ncc is not, and in fact is the rule that was a problem for ElaboratedOrSpecifier) - PQDtorName: similar reasoning as NameAfterDot Though I'm not 100% sure about the above reasoning, I think that leaving out questionable annotations is less risky than adding them. ---------- 2005-08-16 I just now discovered that the prec/assoc specification of "::" interacts badly with prec/assoc in verifier/annot.gr. Perhaps the solution is to use forbid_next instead of prec/assoc, perhaps annot.gr should be changed. For now I've just hacked it by using smbase/codepatch.pl to remove the prec/assoc of "::", as the verifier isn't concerned with parsing C++ right now. This is a perfect example of the potential danger of prec/assoc in a modular parser generator, as the spec in cc.gr broke the extension in annot.gr. It would be interesting to consider trying to develop a scheme for static conflict resolution that had predictable effects across extension modules...