1.2 Rule Inlining array_type

This time we remove the left-recursion of the rule type, right at the beginning:

type
    :    (type_name
        |    simple_type
        |    enum_type
        |    class_type
        |    interface_type
        |    array_type
        |    delegate_type
        |    type_parameter
        |    pointer_type
        ) INTERR*
    ;

Now we inline type and simplify further. I inline unmanaged_type as next and in-factor "INTERR* STAR" to each subrule, so that I can remove the left-recursion in pointer_type. Because of the assymmetric "VOID STAR" subrule I inline pointer_type instead doing some optimization, except turning the trailing into "(INTERR | STAR)*". Then we arrive at

non_array_type
    :    (type_name
        |    simple_type
        |    enum_type
        |    class_type
        |    interface_type
        |    array_type
        |    delegate_type
        |    type_parameter
        |   (type_name INTERR* STAR
            |    simple_type INTERR* STAR
            |    enum_type INTERR* STAR
            |    class_type INTERR* STAR
            |    interface_type INTERR* STAR
            |    array_type INTERR* STAR
            |    delegate_type INTERR* STAR
            |    type_parameter INTERR* STAR
            |    VOID STAR
            ) (INTERR | STAR)*
        ) INTERR*
    ;

Taking the near duplicates into account, "INTERR* STAR (INTERR | STAR)" is transformable into "INTERR* STAR? (INTERR | STAR)" and this is "(INTERR | STAR)*". We then obtain

non_array_type
    :   (type_name (INTERR | STAR)*
        |    simple_type (INTERR | STAR)*
        |    enum_type (INTERR | STAR)*
        |    class_type (INTERR | STAR)*
        |    interface_type (INTERR | STAR)*
        |    array_type (INTERR | STAR)*
        |    delegate_type (INTERR | STAR)*
        |    type_parameter (INTERR | STAR)*
        |    VOID STAR (INTERR | STAR)*
        ) INTERR*
    ;

The last INTERR* can be safely deleted. Then after some rule-inling, SLRR and simplification we arrive at

array_type
    :    type_name (STAR | INTERR)* rank_specifier+
    |    simple_type (STAR | INTERR)* rank_specifier+
    |    enum_type (STAR | INTERR)* rank_specifier+
    |    class_type (STAR | INTERR)* rank_specifier+
    |    interface_type (STAR | INTERR)* rank_specifier+
    |    array_type (STAR | INTERR)* rank_specifier+
    |    delegate_type (STAR | INTERR)* rank_specifier+
    |    type_parameter (STAR | INTERR)* rank_specifier+
    |    VOID STAR (STAR | INTERR)* rank_specifier+
;

Now repeat SLRR and simplify the result to

array_type
    :   (type_name
        |    simple_type
        |    enum_type
        |    class_type
        |    interface_type
        |    delegate_type
        |    type_parameter
        |    VOID STAR
        ) ((STAR | INTERR)* rank_specifier)+
;

"((STAR | INTERR)* rank_specifier)" is similar to "(STAR | INTERR | rank_specifier)", if there is at least one rank_specifier. This can be checked with:

array_type
    :   (type_name
        |    simple_type
        |    enum_type
        |    class_type
        |    interface_type
        |    delegate_type
        |    type_parameter
        |    VOID STAR
        ) (STAR | INTERR | r+=rank_specifier)+ {$r.Count >= 1}?
;

Sections

My siblings (including me):