We inline primary_expression and in-factor all rules before we save a new copy of the grammar:
primary_no_array_creation_expression
: literal
| simple_name
| parenthesized_expression
| member_access
| invocation_expression
| primary_no_array_creation_expression OPEN_BRACKET expression_list CLOSE_BRACKET
| this_access
| base_access
| post_increment_expression
| post_decrement_expression
| object_creation_expression
| delegate_creation_expression
| anonymous_object_creation_expression
| typeof_expression
| checked_expression
| unchecked_expression
| default_value_expression
| anonymous_method_expression
| sizeof_expression
| array_creation_expression OP_PTR IDENTIFIER
| primary_no_array_creation_expression OP_PTR IDENTIFIER
| primary_no_array_creation_expression OPEN_BRACKET expression CLOSE_BRACKET
;
member_access
: array_creation_expression DOT IDENTIFIER type_argument_list?
| primary_no_array_creation_expression DOT IDENTIFIER type_argument_list?
| predefined_type DOT IDENTIFIER type_argument_list?
| qualified_alias_member DOT IDENTIFIER type_argument_list?
;
invocation_expression
: array_creation_expression OPEN_PARENS argument_list? CLOSE_PARENS
| primary_no_array_creation_expression OPEN_PARENS argument_list? CLOSE_PARENS
;
post_increment_expression
: array_creation_expression OP_INC
| primary_no_array_creation_expression OP_INC
;
post_decrement_expression
: array_creation_expression OP_DEC
| primary_no_array_creation_expression OP_DEC
;
We postpone the SLRR on primary_no_array_creation_expression and its inlining until the last moment as this rule is referenced by other to-be-inlined rules. We inline now invocation_expression, post_increment_expression and post_decrement_expression and remove SLRR on primary_no_array_creation_expression to get:
primary_no_array_creation_expression
: (literal
| simple_name
| parenthesized_expression
| member_access
| this_access
| base_access
| array_creation_expression OPEN_PARENS argument_list? CLOSE_PARENS
| array_creation_expression OP_INC
| array_creation_expression OP_DEC
| array_creation_expression OP_PTR IDENTIFIER
| object_creation_expression
| delegate_creation_expression
| anonymous_object_creation_expression
| typeof_expression
| checked_expression
| unchecked_expression
| default_value_expression
| anonymous_method_expression
| sizeof_expression
) (OPEN_PARENS argument_list? CLOSE_PARENS
| OPEN_BRACKET (expression_list | expression) CLOSE_BRACKET
| OP_INC
| OP_DEC
| OP_PTR IDENTIFIER
)*
;
Now after inlining member_access, it has to be in-factored to allow SLRR. Due to the size of the trailing it was out-factored into a separate rule temporarily:
member_access
: (array_creation_expression DOT IDENTIFIER type_argument_list?
| predefined_type DOT IDENTIFIER type_argument_list?
| qualified_alias_member DOT IDENTIFIER type_argument_list?
| literal member_access_trailing
| simple_name member_access_trailing
| parenthesized_expression member_access_trailing
| this_access member_access_trailing
| base_access member_access_trailing
| array_creation_expression OPEN_PARENS argument_list? CLOSE_PARENS member_access_trailing
| array_creation_expression OP_INC member_access_trailing
| array_creation_expression OP_DEC member_access_trailing
| array_creation_expression OP_PTR IDENTIFIER member_access_trailing
| object_creation_expression member_access_trailing
| delegate_creation_expression member_access_trailing
| anonymous_object_creation_expression member_access_trailing
| typeof_expression member_access_trailing
| checked_expression member_access_trailing
| unchecked_expression member_access_trailing
| default_value_expression member_access_trailing
| anonymous_method_expression member_access_trailing
| sizeof_expression member_access_trailing
) member_access_trailing*
;
member_access_trailing
: (OPEN_PARENS argument_list? CLOSE_PARENS
| OPEN_BRACKET (expression_list | expression) CLOSE_BRACKET
| OP_INC
| OP_DEC
| OP_PTR IDENTIFIER
)* DOT IDENTIFIER type_argument_list?
;
As one can easily see, most alternatives of member_access include member_access_trailing. Looking more closely, the only three alternatives, which don't include the member_access_trailing, use only the zero-or-more-closure of member_access_trailing.
The simplification is complicated by the fact that there are four other array_creation_expression-s. Taking all five alternatives into account, we can actually combine all array_creation_expression-s into one. Using our "we check it in the next pass"-trick we can simplify member_access to:
member_access
: (array_creation_expression
| predefined_type
| qualified_alias_member
| literal
| simple_name
| parenthesized_expression
| this_access
| base_access
| object_creation_expression
| delegate_creation_expression
| anonymous_object_creation_expression
| typeof_expression
| checked_expression
| unchecked_expression
| default_value_expression
| anonymous_method_expression
| sizeof_expression
) (OPEN_PARENS argument_list? CLOSE_PARENS
| OPEN_BRACKET (expression_list | expression) CLOSE_BRACKET
| OP_INC
| OP_DEC
| OP_PTR IDENTIFIER
| DOT IDENTIFIER type_argument_list?
)+
;
The second pass has to check for the alternatives predefined_type and qualified_alias_member, that they are directly followed by a DOT. array_creation_expression may not be followed by OPEN_BRACKET. It has to be also checked that DOT IDENTIFIER type_argument_list? is the last matched sequence.
Sections
My siblings (including me):