############################################################################# TextIndexNG The next generation TextIndex for Zope## This software is governed by a license. See# LICENSE.txt for the terms of this license.#################################################################################################################################### a new native Python QueryParser for TextIndexNG# based on the QueryParser by Sidnei da Silva# $Id: PyQueryParser.py,v 1.11.2.4 2002/06/18 20:29:25 ajung Exp $#######################################################import sys, refrom Products.TextIndexNG.BaseParser import BaseParser,QueryParserErrortokens = ( 'STRING' , 'OR', 'AND', 'ANDNOT', 'NEAR', 'QUOTE', 'OPENP', 'CLOSEP', ) t_QUOTE = r'\"' t_OPENP = r'\(' t_CLOSEP = r'\)' t_ignore = '\t'def t_ANDNOT(t): '\s+ANDNOT\s+|\s+andnot\s+' return tdef t_AND(t): r'\s+AND\s+|\s+and\s+' return tdef t_OR(t): '\s+OR\s+|\s+or\s+' return tdef t_NEAR(t): '\s+NEAR\s+|\s+near\s+' return t def t_STRING(t): r'[\w%?*]+' return tdef t_newline(t): r'\n+' t.lineno += t.value.count("\n") def t_error(t): print t if t.value[0] in [' ']: t.skip(1) else: raise QueryParserError,"Illegal character '%s'" % t.value[0]# Build the lexerimport lexlex.lex(debug=0)op_dict = {'AND' : 'txI','OR' : 'txU','NEAR' : 'txN','ANDNOT' : 'txAN'}def p_expr_parens(t): """expr : OPENP expr CLOSEP """ t[0] = '(%s)' % t[2]def p_expr_op(t): """expr : expr AND expr | expr OR expr | expr NEAR expr | expr ANDNOT expr """ t[0] = '%s(%s,%s)' % (op_dict[t[2].strip().upper()], t[1], t[3])def p_expr_noop(t): """expr : expr expr""" t[0] = 'txI(%s,%s)' % (t[1], t[2])def p_expr_expr_factor(t): """expr : factor """ t[0] = t[1]def p_factor_string(t): """factor : string""" t[0] = t[1]def p_factor_quote(t): """factor : QUOTE term QUOTE""" t[0] = "txQ(%s)" % t[2] def p_term_1(t): """ term : string term""" t[0] = "%s,%s" % (t[1],t[2]) def p_term_2(t): """ term : string""" t[0] = t[1]str_regex = re.compile(r'[\w]+$', re.LOCALE|re.UNICODE)sim_regex = re.compile(r'[%][\w]+$', re.LOCALE|re.UNICODE)rt_regex = re.compile(r'[\w]+[*]$', re.LOCALE|re.UNICODE)def p_string(t): """string : STRING""" if str_regex.match(t[1]): t[0] = 'LL("%s")' % t[1] elif sim_regex.match(t[1]): t[0] = 'PL("%s")' % t[1][1:] elif rt_regex.match(t[1]): t[0] = 'RTL("%s")' % t[1][:-1] else: t[0] = 'PML("%s")' % t[1] def p_error(t): raise QueryParserError,"Syntax error at '%s'" % t.valueimport yaccyacc.yacc(debug=0)class Parser(BaseParser): id = 'NewQueryParser' parser_description = 'A TextIndex compatible parser (native Python version)' def parse(self, query, operator): try: return yacc.parse( query ) except QueryParserError: raise except: import traceback traceback.print_exc() raise QueryParserError, 'parser failed for query: %s' % query def test(): import os, sys, re,traceback, atexit histfile = os.path.expanduser('~/.pyhist') try: import readline readline.read_history_file(histfile) atexit.register(readline.write_history_file,histfile) except: pass print "entering interactive query mode:" while 1: s = raw_input('> ') print s try: P = Parser() res = P(s) print 'res:',res except: traceback.print_exc()if __name__ == '__main__': test()