Search code examples
parsingcompiler-constructiongrammarcontext-free-grammarlr-grammar

Find an equivalent LR grammar


I am trying to find an LR(1) or LR(0) grammar for pascal. Here is a part of my grammar which is not LR(0) as it has shift/reduce conflict.

EXPR --> AEXPR | AEXPR realop AEXPR
AEXPR --> TERM | SIGN TERM | AEXPR addop TERM
TERM --> TERM mulop FACTOR | FACTOR
FACTOR --> id | num | ( EXPR )
SIGN --> + | - 

(Uppercase words are variables and lowercase words, + , - are terminals)

As you see , EXPR --> AEXPR | AEXPR realop AEXPR cause a shift/reduce conflict on LR(0) parsing. I tried adding a new variable , and some other ways to find an equivalent LR (0) grammar for this, but I was not successful.

I have two problems.

First: Is this grammar a LR(1) grammar?

Second: Is it possible to find a LR(0) equivalent for this grammar? what about LR(1) equivalent?


Solution

  • Yes, your grammar is an LR(1) grammar. [see note below]

    It is not just the first production which causes an LR(0) conflict. In an LR(0) grammar, you must be able to predict whether to shift or reduce (and which production to reduce) without consulting the lookahead symbol. That's a highly restrictive requirement.

    Nonetheless, there is a grammar which will recognize the same language. It's not an equivalent grammar in the sense that it does not produce the same parse tree (or any useful parse tree), so it depends on what you consider equivalent.

    EXPR → TERM | EXPR OP TERM
    TERM → num | id | '(' EXPR ')' | addop TERM
    OP   → addop | mulop | realop
    

    The above works by ignoring operator precedence; it regards an expression as simply the regular language TERM (op TERM)*. (I changed + | - to addop because I couldn't see how your scanner could work otherwise, but that's not significant.)

    There is a transformation normally used to make LR(1) expression grammars suitable for LL(1) parsing, but since LL(1) is allowed to examine the lookahead character, it is able to handle operator precedence in a normal way. The LL(1) "equivalent" grammar does not produce a parse tree with the correct operator associativity -- all operators become right-associative -- but it is possible to recover the correct parse tree by a simple tree rotation.

    In the case of the LR(0) grammar, where operator precedence has been lost, the tree transformation would be almost equivalent to reparsing the input, using something like the shunting yard algorithm to create the true parse tree.


    Note

    I don't believe the grammar presented is the correct grammar, because it makes unary plus and minus bind less tightly than multiplication, with the result that -3*4 is parsed as -(3*4). As it happens, there is no semantic difference most of the time, but it still feels wrong to me. I would have written the grammar as:

    EXPR   → AEXPR  | AEXPR realop AEXPR
    AEXPR  → TERM   | AEXPR addop  TERM
    TERM   → FACTOR | TERM  mulop  FACTOR
    FACTOR → num | id | '(' EXPR ')' | addop FACTOR
    

    which makes unary operators bind more tightly. (As above, I assume that addop is precisely + or -.)