Avoid common prefixes without change lookahead

442 views Asked by At

I'm using JavaCC to make a specification to recognize a language. The problem I have is that JavaCC gives me a warning because public is a common prefix of Member() declaration. Member() can has Attributes() and/or Method() but must have at least one Method, the order does not matter.

The warning JavaCC gives me is:

Choice conflict in (...)+ construct at line 66, column 23. Expansion nested within construct and expansion following construct have common prefixes, one of which is: "public". Consider using a lookahead of 2 or more for nested expansion.

The line 66 is the only line of Member(). Also I need to do this without change lookahead value.

Here is the code:

void Member() : {}
    {
        (Attribute())* (Method())+ (Attribute() | Method())*
    }

void Attribute() : {}
    {
        "private" Type() <Id> [":=" Expr()]";"
    }

void Method() : {}
    {
        MethodHead() MethodBody()
    }

void MethodHead() : {}
    {
        ("public")? (<Id> | Type() | "void") <Id> "(" Parameter() ")"
    }

Thanks.

1

There are 1 answers

1
Theodore Norvell On BEST ANSWER

The problem is that this regular expression

 (Method())+ (Attribute() | Method())*

is ambiguous. Let's abbreviate methods by M and attributes by A. If the input is MAM, there no problem. The (Method())+ matches the first M and the (Attribute() | Method())* matches the remaining AM. But if the input is MMA, where should the divide be? Either (Method())+ matches M and (Attribute() | Method())* matches MA or (Method())+ matches MM and (Attribute() | Method())* matches A. Both parses are possible. JavaCC doesn't know which parse you want, so it complains.

What you can do:

  • Nothing. Ignore the warning. The default behaviour is that as many Methods as possible will be recognized by (Method())+ and only methods after the first attribute will be recognized by (Attribute() | Method())*.
  • Suppress the warning using lookahead. You said you don't want to add lookahead, but for completeness, I'll mention that you could change (Method())+ to (LOOKAHEAD(1) Method())+. That won't change the behaviour of the parser, but it will suppress the warning.
  • Rewrite the grammar.

The offending line could be rewritten as either

(Attribute())* Method() (Attribute() | Method())*

or as

(Attribute())* (Method())+ [Attribute() (Attribute() | Method())*]