X-Git-Url: https://git.phdru.name/?a=blobdiff_plain;f=parser%2Fparser.py;h=dbd054964820852fd530b4cfab0f1da2c8e79e30;hb=240857e1b474ca2d8d3e97f0ac234ca3e4b3ad3a;hp=38c4cd236084d9bfb050214193503d64ced96c4c;hpb=2167fc0e09f4343c0fe67c8c754e29a41769e684;p=phdru.name%2Fcgi-bin%2Fblog-ru%2Fsearch-tags.git diff --git a/parser/parser.py b/parser/parser.py old mode 100644 new mode 100755 index 38c4cd2..dbd0549 --- a/parser/parser.py +++ b/parser/parser.py @@ -1,58 +1,66 @@ -# Parse query - -from ply import lex, yacc - -literals = '()' - -tokens = ('NAME', 'AND_OP', 'OR_OP', 'NOT_OP') - -t_NAME = '[a-z][a-z0-9_]*' - -t_AND_OP = '&' - -t_OR_OP = r'\|' - -t_NOT_OP = '!' - -t_ignore = '[ \t]+' - -def t_error(t): - """Avoid warnings on stderr""" - -lexer = lex.lex() - -def p_expression_name(p): - """expression : NAME""" - 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]) - -def p_expression_and(p): - """expression : expression AND_OP expression""" - p[0] = ('AND', p[1], p[3]) - -def p_expression_not(p): - """expression : NOT_OP expression""" - p[0] = ('NOT', p[2]) - -def p_expression_or(p): - """expression : expression OR_OP expression""" - p[0] = ('OR', p[1], p[3]) - -def p_expression_parens(p): - """expression : '(' expression ')'""" - p[0] = ('PARENS', p[2]) - -def p_error(p): - """Avoid warnings on stderr""" - yacc.restart() - -precedence = ( - ('left', 'OR_OP'), - ('left', 'AND_OP'), - ('right', 'NOT_OP'), -) - -parser = yacc.yacc() +#! /usr/bin/env python + +import os +from lark import Lark, Transformer + + +class TagsTransformer(Transformer): + def and_expression(self, items): + left = items[0] + right = items[2] + if len(items) > 3: + right = self.and_expression(items[2:]) + return ('AND', left, right) + + def or_expression(self, items): + left = items[0] + right = items[2] + if len(items) > 3: + right = self.or_expression(items[2:]) + return ('OR', left, right) + + def not_expression(self, items): + return ('NOT', items[1]) + + def expression_parens(self, items): + return ('PARENS', items[0]) + + def name(self, name): + return ('NAME', name[0].value) + + +# cache +_grammar = None + + +def load_grammar(): + global _grammar + parser_dir = os.path.dirname(__file__) + with open(os.path.join(parser_dir, 'grammar.ebnf'), 'rt') as grammar_file: + grammar_text = grammar_file.read() + grammar_lines = [line for line in grammar_text.splitlines() + if not line.startswith('#')] + grammar_text = '\n'.join(grammar_lines) + _grammar = Lark(grammar_text) + + +def parse(input): + if _grammar is None: + load_grammar() + tree = _grammar.parse(input) + return TagsTransformer().transform(tree) + + +if __name__ == '__main__': + print '----------' + print parse('test') + print parse('!test') + print parse('not test') + print parse('foo or bar') + print parse('foo && bar') + print parse('foo && bar && baz') + print parse('!foo && bar && baz') + print parse('(test)') + print parse('(foo || bar)') + print parse('(foo and !bar)') + print '----------'