0

This is how my current code looks like, it only supports a AND NOT b. Is there a way to make it also return the same tree for a NOT b? Any suggestions will be appreciated.

from lark import Lark


grammar = r'''
    start: or_test

    ?or_test: and_test ("OR" and_test)*
    ?and_test: not_test ("AND" not_test)*
    ?not_test: "NOT" not_test -> not
             | atom
    
    atom: WORD -> term
         | "(" or_test ")"

    WORD: /[a-zA-Z0-9]+/
    
    %import common.WS_INLINE
    %ignore WS_INLINE
'''

parser = Lark(grammar)

s = 'NOT a AND b AND NOT c'
tree = parser.parse(s)
print(tree.pretty())

output

start
  and_test
    not
      term  a
    term    b
    not
      term  c
ppwater
  • 2,315
  • 4
  • 15
  • 29
Harrison
  • 2,560
  • 7
  • 29
  • 55
  • "it only supports a AND NOT b" I don't understand; the rule looks right to me, and the output also looks right to me. What were you expecting instead? – Karl Knechtel Nov 25 '20 at 06:08
  • @KarlKnechtel I want `a NOT b` also returns the same result at the same time. – Harrison Nov 25 '20 at 06:10
  • That... doesn't make any sense. `NOT` is a unary operator, not a binary one. – Karl Knechtel Nov 25 '20 at 06:12
  • @KarlKnechtel I know... but unfortunately it's the grammar of our queries. what I really need is the support of `NOT a` and `a NOT b`, `a NOT AND b` is actually optional since people mostly use the first 2 cases. – Harrison Nov 25 '20 at 06:16
  • `NOT a` is totally normal, and should already be supported by your grammar. I assume `a NOT AND b` is supposed to mean the same thing as `a AND NOT b`? But what does `a NOT b` actually mean? The same thing again? – Karl Knechtel Nov 25 '20 at 06:20
  • @KarlKnechtel right, `a NOT AND b` and `a NOT b` are the same. – Harrison Nov 25 '20 at 06:24

1 Answers1

0

I think that should do what you asked:

from lark import Lark

grammar = r'''
    start: or_test

    ?or_test: and_test ("OR" and_test)*
    ?and_test: not_test ("AND" not_test | and_not)*
    and_not: "NOT" not_test -> not
    ?not_test: "NOT" not_test -> not
            | atom

    atom: WORD -> term
        | "(" or_test ")"

    WORD: /[a-zA-Z0-9]+/

    %import common.WS_INLINE
    %ignore WS_INLINE
'''

parser = Lark(grammar)

s = 'NOT a AND b AND NOT c NOT d'
tree = parser.parse(s)
print(tree.pretty())
Erez
  • 1,287
  • 12
  • 18