-# Grammar rules for tag searching
+# Grammar rules for tag searching; EBNF.
# The grammar defines expressions in the following forms:
# TAG - search blog posts that contain the tag;
# Allowed operators: conjunction - & && AND and
# disjunction - | || OR or
# negation - ! NOT not
-# Usual priority: NOT recognized before AND, AND before OR.
# This is a simple version of the grammar and it allows
-# rather stupid expressions, like (TAG) or ((TAG)) or !(!(TAG)).
+# rather stupid expressions, like !!TAG or ((TAG)); in the future
+# it will be fixed by making the grammar more complex and stricter.
-expression = inner_expression:e end -> e
+?start : expression
-inner_expression = (or_expression | aterm_expression):e -> e
+?expression : or_expression
+ | and_expression
+ | and_sub_expression
-or_expression = aterm_expression:a or_op inner_expression:e -> ('OR', a, e)
+or_expression : or_sub_expression (or or_sub_expression)+
-and_expression = term_expression:t and_op aterm_expression:a -> ('AND',
-t, a)
+?or_sub_expression : and_expression
+ | and_sub_expression
-not_expression = not_op ws (parens_expression | name):n -> ('NOT', n)
+and_expression : and_sub_expression (and and_sub_expression)+
-aterm_expression = (and_expression | term_expression):e -> e
+?and_sub_expression : not_expression
+ | expression_parens
+ | name
-term_expression = (not_expression:e -> e) | (parens_expression:p -> p) | (name:n space_b4letter -> n)
+not_expression: not and_sub_expression
-parens_expression = '(' ws inner_expression:e ws ')' -> ('PARENS', e)
+expression_parens : "(" expression ")"
-and_op = (ws ('&&' | '&') ws) | (ws ('AND' | 'and') space_b4letter)
+name : /[A-Za-zА-Яа-яЁё][A-Za-zА-Яа-яЁё0-9_]*[A-Za-zА-Яа-яЁё0-9]/
-or_op = (ws ('||' | '|') ws) | (ws ('OR' | 'or') space_b4letter)
+?and : and_op
+ | and_op and_op
+ | and_word
-not_op = (ws '!' ws) | (ws ('NOT' | 'not') space_b4letter)
+?or : or_op
+ | or_op or_op
+ | or_word
-name = <lletter lletterOrDigit*>:n -> ('NAME', n)
+?not : not_op
+ | not_word
-lletter = :l ?(l in 'abcdefghijklmnopqrstuvwxyz') -> l
+?and_op : "&"
-digit = :d ?(d in '0123456789') -> d
+?or_op : "|"
-lletterOrDigit = (lletter | digit):c -> c
+?not_op : "!"
-space_b4letter = (' '+ ~~letter) | ws
+?and_word : "AND"
+ | "and"
+ | "И"
+ | "и"
-# vim: set ft=text :
+?or_word : "OR"
+ | "or"
+ | "ИЛИ"
+ | "или"
+
+?not_word : "NOT"
+ | "not"
+ | "НЕ"
+ | "не"
+
+%import common.WS
+%ignore WS