Version 0.3 (2014-06-??)
- Allow '&&', '||', ' AND ', ' and ', ' OR ' and ' or '.
+ Allow '&&', '||', ' AND ', ' and ', ' OR ', ' or ', 'NOT ' and 'not '.
Version 0.2 (2014-06-06)
-Allow 'NOT ' and 'not '.
-
Forbid stupid expressions: double NOT, extra parens and so on.
# !(TAG | TAG)
# Allowed operators: conjunction - & && AND and
# disjunction - | || OR or
-# negation - !
+# negation - ! NOT not
# This is a simple version of the grammar and it allows
# rather stupid expressions, like !!TAG or ((TAG)); in the future
# it will be fixed by making the grammar more complex and stricter.
| expression SP0 OR_OP SP0 expression
| l_expression or_word r_expression
| NOT_OP SP0 expression
+ | not_word r_expression
| expression_parens
l_expression : expression_parens
or_word : 'O' 'R'
| 'o' 'r'
+not_word : 'N' 'O' 'T'
+ | 'n' 'o' 't'
+
SP0 : SP1 | empty
empty :
literals = '()'
-tokens = ('NAME', 'AND_OP', 'OR_OP', 'NOT_OP', 'SP1')
+tokens = ('OP_WORD', 'NAME', 'AND_OP', 'OR_OP', 'NOT_OP', 'SP1')
-t_NAME = '([a-z][a-z0-9_]*)|AND|OR|NOT'
+t_OP_WORD = '(AND|and|OR|or|NOT|not)'
+
+t_NAME = '([a-z][a-z0-9_]*)'
t_AND_OP = '&'
p[0] = ('AND', p[1], p[3])
elif p[2] in ('OR', 'or'):
p[0] = ('OR', p[1], p[3])
+ else:
+ raise ValueError(p)
def p_expression_or_or(p):
"""expression : expression SP0 OR_OP OR_OP SP0 expression"""
"""expression : NOT_OP SP0 expression"""
p[0] = ('NOT', p[3])
+def p_expression_not_word(p):
+ """expression : op_word r_expression"""
+ if p[1] in ('NOT', 'not'):
+ p[0] = ('NOT', p[2])
+ else:
+ raise ValueError(p)
+
def p_expression_in_parens(p):
"""expression : expression_parens"""
p[0] = p[1]
p[0] = ('PARENS', p[3])
def p_op_word(p):
- """op_word : NAME"""
- if p[1] in ('AND', 'and', 'OR', 'or'):
+ """op_word : OP_WORD"""
+ if p[1] in ('AND', 'and', 'OR', 'or', 'NOT', 'not'):
p[0] = p[1]
else:
raise SyntaxError
self.assertEqual(lextoken.lineno, 1)
self.assertEqual(lextoken.lexpos, 3)
lextoken = tokens[2]
- self.assertEqual(lextoken.type, 'NAME')
+ self.assertEqual(lextoken.type, 'OP_WORD')
self.assertEqual(lextoken.value, 'and')
self.assertEqual(lextoken.lineno, 1)
self.assertEqual(lextoken.lexpos, 4)
self.assertEqual(parser.parse('xxx OR yyy'),
('OR', ('NAME', 'xxx'), ('NAME', 'yyy'))
)
+ self.assertEqual(parser.parse('not xxx'),
+ ('NOT', ('NAME', 'xxx'))
+ )
+ self.assertEqual(parser.parse('NOT xxx'),
+ ('NOT', ('NAME', 'xxx'))
+ )
def test_05_bad_expression(self):
self.assertIs(parser.parse('!(xxx&yyy'), None)