Consider the two groups of productions:
PackageName:
Identifier
PackageName.
Identifier TypeName:
Identifier
PackageName.
Identifier
MethodName:
Identifier
AmbiguousName.
Identifier AmbiguousName:
Identifier
AmbiguousName.
Identifier
Now consider the partial input:
class Problem1 { int m() { hayden.
When the parser is considering the token hayden
, with one-token lookahead to
symbol ".
", it cannot yet tell whether hayden
should be a PackageName that
qualifies a type name, as in:
hayden.Dinosaur rex = new Hayden.Dinosaur(2);
or an AmbiguousName that qualifies a method name, as in:
hayden.print("Dinosaur Rex!");
Therefore, the productions shown above result in a grammar that is not LALR(1). There are also other problems with drawing distinctions among different kinds of names in the grammar.
The solution is to eliminate the nonterminals PackageName, TypeName, ExpressionName, MethodName, and AmbiguousName, replacing them all with a single nonterminal Name:
Name:
SimpleName
QualifiedName SimpleName:
Identifier QualifiedName:
Name.
Identifier
A later stage of compiler analysis then sorts out the precise role of each name or name qualifier.
For related reasons, these productions in §4.3:
ClassOrInterfaceType:
ClassType
InterfaceType ClassType:
TypeName InterfaceType:
TypeName
ClassOrInterfaceType:
Name ClassType:
ClassOrInterfaceType InterfaceType:
ClassOrInterfaceType