From fc9a4ef6e9dcde7e48ca54609ba7c9e80a1f20a7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Jun 2014 03:27:13 +0400 Subject: [PATCH] Change handling of spaces AND/NOT/OR operators require spaces if subexpressions are not in parentheses so ignoring whitespace no longer works. --- parser/grammar | 16 ++++++++++------ parser/parser.py | 36 ++++++++++++++++++++++-------------- parser/test_parser.py | 2 +- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/parser/grammar b/parser/grammar index 5a0c3d5..7c34096 100644 --- a/parser/grammar +++ b/parser/grammar @@ -26,9 +26,13 @@ NOT_OP : '!' SP1 : '[ \t]+' expression : NAME - | expression AND_OP AND_OP expression - | expression AND_OP expression - | expression OR_OP OR_OP expression - | expression OR_OP expression - | NOT_OP expression - | '(' expression ')' + | expression SP0 AND_OP AND_OP SP0 expression + | expression SP0 AND_OP SP0 expression + | NOT_OP SP0 expression + | expression SP0 OR_OP OR_OP SP0 expression + | expression SP0 OR_OP SP0 expression + | '(' SP0 expression SP0 ')' + +SP0 : SP1 | empty + +empty : diff --git a/parser/parser.py b/parser/parser.py index 1fb9903..0af77f6 100644 --- a/parser/parser.py +++ b/parser/parser.py @@ -4,7 +4,7 @@ from ply import lex, yacc literals = '()' -tokens = ('NAME', 'AND_OP', 'OR_OP', 'NOT_OP') +tokens = ('NAME', 'AND_OP', 'OR_OP', 'NOT_OP', 'SP1') t_NAME = '[a-z][a-z0-9_]*' @@ -14,7 +14,7 @@ t_OR_OP = r'\|' t_NOT_OP = '!' -t_ignore = '[ \t]+' +t_SP1 = '[ \t]+' def t_error(t): """Avoid warnings on stderr""" @@ -26,28 +26,36 @@ def p_expression_name(p): p[0] = ('NAME', p[1]) def p_expression_and_and(p): - """expression : expression AND_OP AND_OP expression""" - p[0] = ('AND', p[1], p[4]) + """expression : expression SP0 AND_OP AND_OP SP0 expression""" + p[0] = ('AND', p[1], p[6]) def p_expression_and(p): - """expression : expression AND_OP expression""" - p[0] = ('AND', p[1], p[3]) + """expression : expression SP0 AND_OP SP0 expression""" + p[0] = ('AND', p[1], p[5]) def p_expression_not(p): - """expression : NOT_OP expression""" - p[0] = ('NOT', p[2]) + """expression : NOT_OP SP0 expression""" + p[0] = ('NOT', p[3]) def p_expression_or_or(p): - """expression : expression OR_OP OR_OP expression""" - p[0] = ('OR', p[1], p[4]) + """expression : expression SP0 OR_OP OR_OP SP0 expression""" + p[0] = ('OR', p[1], p[6]) def p_expression_or(p): - """expression : expression OR_OP expression""" - p[0] = ('OR', p[1], p[3]) + """expression : expression SP0 OR_OP SP0 expression""" + p[0] = ('OR', p[1], p[5]) def p_expression_parens(p): - """expression : '(' expression ')'""" - p[0] = ('PARENS', p[2]) + """expression : '(' SP0 expression SP0 ')'""" + p[0] = ('PARENS', p[3]) + +def p_SP0(p): + """SP0 : SP1 + | empty + """ + +def p_empty(p): + """empty : """ def p_error(p): """Avoid warnings on stderr""" diff --git a/parser/test_parser.py b/parser/test_parser.py index 628c984..d7363c0 100755 --- a/parser/test_parser.py +++ b/parser/test_parser.py @@ -24,7 +24,7 @@ class TestParser(unittest.TestCase): self.assertEqual(parser.parse('!xxx&yyy&zzz|ooo'), ('OR', ('AND', ('AND', ('NOT', ('NAME', 'xxx')), ('NAME', 'yyy')), ('NAME', 'zzz')), ('NAME', 'ooo')) ) - self.assertEqual(parser.parse('!(xxx && yyy)'), + self.assertEqual(parser.parse('!(xxx && yyy)'), ('NOT', ('PARENS', ('AND', ('NAME', 'xxx'), ('NAME', 'yyy')))) ) self.assertEqual(parser.parse('!(xxx || yyy)'), -- 2.39.2