X-Git-Url: https://git.phdru.name/?a=blobdiff_plain;f=parser%2Fgrammar.ebnf;h=43752574a181addd522514c7ff8e0e16d6346e6a;hb=3db3a1c52868d865cac4e96d6521f62feb15cf77;hp=b657738ad5f30a6ab29508f8364b212faffa4708;hpb=3eadd8423e41b70e89854bd63e0e9875e259978c;p=phdru.name%2Fcgi-bin%2Fblog-ru%2Fsearch-tags.git diff --git a/parser/grammar.ebnf b/parser/grammar.ebnf index b657738..4375257 100644 --- a/parser/grammar.ebnf +++ b/parser/grammar.ebnf @@ -1,4 +1,4 @@ -# Grammar rules for tag searching; EBNF. +# Grammar rules for tag searching # The grammar defines expressions in the following forms: # TAG - search blog posts that contain the tag; @@ -11,26 +11,41 @@ # 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)) +# rather stupid expressions, like (TAG) or ((TAG)) or !(!(TAG)). -@@grammar :: Tags +expression = inner_expression:e end -> e -start = expression $ ; +inner_expression = (or_expression | aterm_expression):e -> e -expression = ( - | expression and_op expression - | expression or_op expression - | not_op expression - | expression_parens - | name ) ; +or_expression = aterm_expression:a or_op inner_expression:e -> ('OR', a, e) -expression_parens = '(' expression ')' ; +and_expression = term_expression:t and_op aterm_expression:a -> ('AND', +t, a) -name = /[a-z][a-z0-9_]+/ ; +not_expression = not_op ws (parens_expression | name):n -> ('NOT', n) -and_op = '&' | '&&' | 'AND' | 'and' ; +aterm_expression = (and_expression | term_expression):e -> e -or_op = '|' | '||' | 'OR' | 'or' ; +term_expression = (not_expression:e -> e) | (parens_expression:p -> p) | (name:n space_b4letter -> n) -not_op = '!' | 'NOT' | 'not' ; +parens_expression = '(' ws inner_expression:e ws ')' -> ('PARENS', e) + +and_op = (ws ('&&' | '&') ws) | (ws ('AND' | 'and') space_b4letter) + +or_op = (ws ('||' | '|') ws) | (ws ('OR' | 'or') space_b4letter) + +not_op = (ws '!' ws) | (ws ('NOT' | 'not') space_b4letter) + +name = :n -> ('NAME', n) + +lletter = :l ?(l in 'abcdefghijklmnopqrstuvwxyz') -> l + +digit = :d ?(d in '0123456789') -> d + +lletterOrDigit = (lletter | digit):c -> c + +space_b4letter = (' '+ ~~letter) | ws + +# vim: set ft=text :