Consider the two groups of productions:
FieldDeclaration:
FieldModifiersoptType
VariableDeclarators
;
FieldModifiers:
FieldModifier
FieldModifiersFieldModifier FieldModifier: one of
public
protected
private
final static transient volatile
MethodHeader:
MethodModifiersoptResultType
MethodDeclarator
Throwsopt MethodModifiers:
MethodModifier
MethodModifiersMethodModifier MethodModifier: one of
public
protected
private
static
abstract final native synchronized
Now consider the partial input:
class Problem2 { public static int
When the parser is considering the token static
, with one-token lookahead to
symbol int
-or, worse yet, considering the token public
with lookahead to
static
-it cannot yet tell whether this will be a field declaration such as:
public static int maddie = 0;
or a method declaration such as:
public static int maddie(String art) { return art.length(); }
Therefore, the parser cannot tell with only one-token lookahead whether static
(or, similarly, public
) should be reduced to FieldModifier or MethodModifier.
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
modifiers in the grammar.
While not all contexts provoke the problem, the simplest solution is to combine all contexts in which such modifiers are used, eliminating all six of the nonterminals ClassModifiers (§8.1.2), FieldModifiers (§8.3.1), MethodModifiers (§8.4.3), ConstructorModifiers (§8.6.3), InterfaceModifiers (§9.1.2), and ConstantModifiers (§9.3) from the grammar, replacing them all with a single nonterminal Modifiers:
Modifiers:
Modifier
ModifiersModifier Modifier: one of
public protected private
static
abstract final native synchronized transient volatile
A later stage of compiler analysis then sorts out the precise role of each modifier and whether it is permitted in a given context.