2016-09-21 6 views
0

При использовании PLY (http://www.dabeaz.com/ply/) Я заметил, что это очень странная проблема: когда я использую токены типа & для соединения, нижеприведенная программа работает, но когда я использую AND там же, синтаксис PLY требует синтаксиса ошибка.Do AND, OR строки имеют особое значение в PLY?

Программа:

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

import sys 
import os 

from ply import lex 

import ply.yacc as yacc 

parser = None 
lexer = None 


def flatten_list(lst): 
    flat = [] 
    for x in lst: 
     if isinstance(x, list): 
      flat.extend(flatten_list(x)) 
     else: 
      flat.append(x) 
    return flat 


############## Tokenization ############## 

tokens = (
    'number', 
    'lparen', 
    'rparen', 
    'textw', 
    'titlew', 
    'qword', 
    'AND' 
) 

t_lparen = r'\(' 
t_rparen = r'\)' 
t_textw = r'TEXTW:' 
t_titlew = r'TITLEW:' 
t_qword = r'\w+' 
t_AND = r'AND' 


def t_number(t): 
    r'\d+' 
    t.value = int(t.value) 
    return t 


t_ignore = ' \t' 


def t_error(t): 
    raise ValueError(
     'Illegal character "{}" at position {}, query text: {}'.format(t.value[0], t.lexpos, t.lexer.lexdata)) 


lexer = lex.lex() 



################# Parsing ################# 


def p_querylist_boolop(p): 
    """querylist : subquery AND subquery""" 
    print >> sys.stderr, 'p_querylist', list(p) 
    p[0] = [] 
    p[0].append(p[1]) 
    p[0].append(p[3]) 


def p_subquery(p): 
    """subquery : lparen querykw qwordseq rparen""" 
    print >> sys.stderr, 'p_subquery', list(p) 
    p[0] = flatten_list(p[3]) 


def p_querykw(p): 
    """querykw : textw 
       | titlew""" 
    print >> sys.stderr, 'p_querykw', list(p) 
    p[0] = p[1] 


def p_qwordseq(p): 
    """qwordseq : qwordseq qword 
        | qwordseq number 
        | qword 
        | number""" 
    print >> sys.stderr, 'p_qwordseq', list(p) 
    if p[0]: 
     p[0].extend(p[1:]) 
    else: 
     p[0] = p[1:] 



def p_error(p): 
    global parser 
    if p: 
     tok = parser.token() 
     if tok: 
      msg = 'Syntax error in input, token "{}" at position {}, query text: {}'.format(tok.value, tok.lexpos, 
                          lexer.lexdata) 
      raise ValueError(msg) 
    msg = 'Syntax error at the end of input, query text: {}'.format(lexer.lexdata) 
    raise ValueError(msg) 


parser = yacc.yacc() 
# parser = yacc.yacc(debug=0, write_tables=0) 


def parse_query(q): 
    return parser.parse(q) 


if __name__ == '__main__': 
    query_texts = ["""(TEXTW: one article) AND (TEXTW: two books)"""] 
    for qt in query_texts: 
     res = parse_query(qt) 
     print '***', res 

Это дает:

ValueError: Syntax error in input, token "(" at position 19, query text: (TEXTW: abc) AND (TEXTW: aaa) 

Однако, когда я изменяю следующее:

t_AND = r'&' 
query_texts = ["""(TEXTW: one article) & (TEXTW: two books)"""] 

..Это работает просто отлично:

*** [['one', 'article'], ['two', 'books']] 
+2

Проблема заключается в том, что строка «' AND' »будет сопоставляться с' t_qword = r '\ w +' 'в первом произведении' p_qwordseq', т. Е. Вам необходимо устранить неоднозначность вашей грамматики. –

ответ

0

Ply имеет слегка эксцентричный подход к упорядочению регулярных выражений токена, отчасти потому, что он зависит от базовой библиотеки регулярных выражений python. Токены, определенные с помощью функций, таких как токен number, распознаются в том порядке, в котором они появляются, и, в отличие от многих генераторов лексических сканеров, Ply не пытается выполнить самое длинное совпадение. Токены, определенные назначением - все ваши другие типы токенов - имеют более низкий приоритет, чем функции, и упорядочиваются по уменьшению длины (регулярного выражения).

полотнище руководство (раздел 4.3) настоятельно советует не использовать переменный стиль назначения для токенов ключевых слов, таких как AND, так как шаблон r'AND', например, распознает первые три символа, например, ANDROGYNOUS, который вы, вероятно, ожидайте переменную. Вместо этого он рекомендует использовать функцию с простым шаблоном, чтобы сначала распознать все ключевые слова и переменные как простые слова, а затем использовать словарь для распознавания конкретных ключевых слов. Образец кода и менее телеграфное объяснение содержатся в руководстве Ply (в приведенном выше разделе).