docs: def p_propositional(self, p):
          """propositional : propositional EQUIVALENCE propositional
                           | propositional IMPLIES propositional
                           | propositional OR propositional
                           | propositional AND propositional
                           | NOT propositional
                           | FALSE
                           | TRUE
                           | ATOM"""
          if len(p)==4:
              if p[2] == Symbols.EQUIVALENCE.value:
                  p[0] = PLEquivalence([p[1], p[3]])
              elif p[2] == Symbols.IMPLIES.value:
                  p[0] = PLImplies([p[1], p[3]])
              elif p[2] == Symbols.OR.value:
                  p[0] = PLOr([p[1], p[3]])
              elif p[2] == Symbols.AND.value:
                  p[0] = PLAnd([p[1], p[3]])
              else:
                  raise ValueError
              # else:
              #     p[0] = p[2]
          elif len(p)==3:
              p[0] = PLNot(p[2])
          elif len(p)==2:
              if p[1]==Symbols.TRUE.value:
                  p[0] = PLTrue()
              elif p[1]==Symbols.FALSE.value:
                  p[0] = PLFalse()
              else:
                  p[0] = PLAtomic(Symbol(p[1]))
          else:
              raise ValueError