Version 0.3 (2014-06-??)
- Allow '&&' and '||'.
+ Allow '&&', '||', ' AND ' and ' and '.
Version 0.2 (2014-06-06)
-Allow ' AND ' and ' and '.
-
Allow ' OR ' and ' or '.
Allow 'NOT ' and 'not '.
# Parentheses are allowed to group expressions; for example:
# TAG & (TAG | TAG)
# !(TAG | TAG)
-# Allowed operators: conjunction - & &&
+# Allowed operators: conjunction - & && AND and
# disjunction - | ||
# negation - !
# This is a simple version of the grammar and it allows
expression : NAME
| expression SP0 AND_OP AND_OP SP0 expression
| expression SP0 AND_OP SP0 expression
+ | l_expression and_word r_expression
| NOT_OP SP0 expression
| expression SP0 OR_OP OR_OP SP0 expression
| expression SP0 OR_OP SP0 expression
- | '(' SP0 expression SP0 ')'
+ | expression_parens
+
+l_expression : expression_parens
+ | expression_sp
+
+r_expression : expression_parens
+ | sp_expression
+
+expression_parens : '(' SP0 expression SP0 ')'
+
+sp_expression : SP1 expression
+
+expression_sp : expression SP1
+
+and_word : 'A' 'N' 'D'
+ | 'a' 'n' 'd'
SP0 : SP1 | empty
"""expression : expression SP0 AND_OP SP0 expression"""
p[0] = ('AND', p[1], p[5])
+def p_expression_and_word(p):
+ """expression : l_expression and_word r_expression"""
+ p[0] = ('AND', p[1], p[3])
+
def p_expression_not(p):
"""expression : NOT_OP SP0 expression"""
p[0] = ('NOT', p[3])
"""expression : expression SP0 OR_OP SP0 expression"""
p[0] = ('OR', p[1], p[5])
+def p_expression_in_parens(p):
+ """expression : expression_parens"""
+ p[0] = p[1]
+
+def p_l_expression(p):
+ """l_expression : expression_parens
+ | expression SP1
+ """
+ if len(p) == 2:
+ p[0] = p[1]
+ elif len(p) == 3:
+ p[0] = p[1]
+ else:
+ raise ValueError(p)
+
+def p_r_expression(p):
+ """r_expression : expression_parens
+ | SP1 expression
+ """
+ if len(p) == 2:
+ p[0] = p[1]
+ elif len(p) == 3:
+ p[0] = p[2]
+ else:
+ raise ValueError(p)
+
def p_expression_parens(p):
- """expression : '(' SP0 expression SP0 ')'"""
+ """expression_parens : '(' SP0 expression SP0 ')'"""
p[0] = ('PARENS', p[3])
+def p_and_word(p):
+ """and_word : NAME"""
+ if p[1] in ('AND', 'and'):
+ p[0] = p[1]
+ else:
+ raise SyntaxError
+
def p_SP0(p):
"""SP0 : SP1
| empty
"""
def p_empty(p):
- """empty : """
+ """empty :"""
def p_error(p):
"""Avoid warnings on stderr"""
self.assertEqual(lextoken.lineno, 1)
self.assertEqual(lextoken.lexpos, 9)
+ def test_05_expression_2(self):
+ lexer.input('xxx and yyy')
+ tokens = list(lexer)
+ self.assertEqual(len(tokens), 5)
+ lextoken = tokens[0]
+ self.assertEqual(lextoken.type, 'NAME')
+ self.assertEqual(lextoken.value, 'xxx')
+ self.assertEqual(lextoken.lineno, 1)
+ self.assertEqual(lextoken.lexpos, 0)
+ lextoken = tokens[1]
+ self.assertEqual(lextoken.type, 'SP1')
+ self.assertEqual(lextoken.value, ' ')
+ self.assertEqual(lextoken.lineno, 1)
+ self.assertEqual(lextoken.lexpos, 3)
+ lextoken = tokens[2]
+ self.assertEqual(lextoken.type, 'NAME')
+ self.assertEqual(lextoken.value, 'and')
+ self.assertEqual(lextoken.lineno, 1)
+ self.assertEqual(lextoken.lexpos, 4)
+ lextoken = tokens[3]
+ self.assertEqual(lextoken.type, 'SP1')
+ self.assertEqual(lextoken.value, ' ')
+ self.assertEqual(lextoken.lineno, 1)
+ self.assertEqual(lextoken.lexpos, 7)
+ lextoken = tokens[4]
+ self.assertEqual(lextoken.type, 'NAME')
+ self.assertEqual(lextoken.value, 'yyy')
+ self.assertEqual(lextoken.lineno, 1)
+ self.assertEqual(lextoken.lexpos, 9)
+
if __name__ == "__main__":
unittest.main()
self.assertEqual(parser.parse('!(xxx || yyy)'),
('NOT', ('PARENS', ('OR', ('NAME', 'xxx'), ('NAME', 'yyy'))))
)
+ self.assertEqual(parser.parse('xxx and yyy'),
+ ('AND', ('NAME', 'xxx'), ('NAME', 'yyy'))
+ )
def test_05_bad_expression(self):
self.assertIs(parser.parse('!(xxx&yyy'), None)