X-Git-Url: https://git.phdru.name/?a=blobdiff_plain;f=parser%2Fgrammar.ebnf;h=3be4d166e0ed7eac1643b7e0176d35e2e75f7d8a;hb=refs%2Ftags%2Fv0.7;hp=43752574a181addd522514c7ff8e0e16d6346e6a;hpb=102d30993b1698195ea44db3a6e3c2d9402564fa;p=phdru.name%2Fcgi-bin%2Fblog-ru%2Fsearch-tags.git diff --git a/parser/grammar.ebnf b/parser/grammar.ebnf index 4375257..3be4d16 100644 --- a/parser/grammar.ebnf +++ b/parser/grammar.ebnf @@ -1,4 +1,4 @@ -# 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; @@ -11,41 +11,58 @@ # 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-z][a-z0-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 = :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