1

I'm trying to implement a context-free grammar for the language of logical operators with parentheses including operator precedence.

For example, the follows:

{1} or {2}
{1} and {2} or {3}
({1} or {2}) and {3}
not {1} and ({2} or {3})
...

I've started from the following grammar:

expr := control | expr and expr | expr or expr | not expr | (expr)
control := {d+}

To implement operator precedence and eliminate left recursion, I changed it in the following way:

S ::= expr
expr ::= control or expr1 | expr1
expr1 ::= control and expr2 | expr2
expr2 ::= not expr3 | expr3
expr3 ::= (expr) | expr | control
control := {d+}

But such grammar doesn't support examples like: ({1} or {2}) and {3} that contain 'and' / 'or' after parentheses.

For now, I have the following grammar:

S ::= expr
expr ::= control or expr1 | expr1
expr1 ::= control and expr2 | expr2
expr2 ::= not expr3 | expr3
expr3 ::= (expr) | (expr) expr4 | expr | control
expr4 :: = and expr | or expr
control := {d+}

Is this grammar correct? Can it be simplified in some way?

Thanks!

Miriam Zusin
  • 186
  • 3
  • 9
  • How do derive your second example from that grammar? I don't think it's possible, in which case the grammar is not correct. An algebraic language with two binary and one unary operator can be written with a total of seven productions (counting alternatives as productions). Yours has 15 or so, so yes it can be simplified. To start with, there's no need to stitch together a Frankenstein of two different grammar writing styles. I'd start by ditching expr5, 6 and 7. – rici Dec 05 '20 at 23:16
  • Let's say I remove expr5, 6, and 7. In this case, examples like "({1} or {2}) and {3}" don't work. – Miriam Zusin Dec 06 '20 at 04:23
  • 1
    You need the production `expr3 -> ( expr )` to get parentheses to work, but you seem to have that. The problem is your use of "control" in the first two productions. Those should instead be left-recursive (although associativity doesn't matter much for boolean operators) and cascading, just like the standard algebraic grammar you'll find all over the internet (for example, [here](http://users.monash.edu/~lloyd/tildeProgLang/Grammar/Arith-Exp/). I chose that one because it's not a PDF unlike the rest of the first two dozen results Google gave me. ) – rici Dec 06 '20 at 04:40
  • Thank you @rici, I'll check the example you sent me. Also, I edited my question to have more details. – Miriam Zusin Dec 06 '20 at 04:53

1 Answers1

1

To implement your operator precedence, you want just:

S ::= expr
expr ::= expr or expr1 | expr1
expr1 ::= expr1 and expr2 | expr2
expr2 ::= not expr2 | expr3
expr3 ::= (expr) | control
control := {d+}

This is left-recursive in order to be left-associative, as that's generally what you want (both for correctness and most parser-generators), but if you need to avoid left recursion for some reason, you can use a right-recursive, right associative grammar:

S ::= expr
expr ::= expr1 or expr | expr1
expr1 ::= expr2 and expr1 | expr2
expr2 ::= not expr2 | expr3
expr3 ::= (expr) | control
control := {d+}

as both and and or are associative operators, so left-vs-right doesn't matter.

In both cases, you can "simplify" it by folding expr3 and control into expr2:

expr2 ::= not expr2 | ( expr ) | {d+}
Chris Dodd
  • 119,907
  • 13
  • 134
  • 226