2016-09-21 47 views
0

使用PLY(http://www.dabeaz.com/ply/)时我注意到了什么似乎是一个非常奇怪的问题:当我使用像&这样的标记进行连接时,下面的程序工作正常,但是当我在同一地方使用AND时,PLY声明语法错误。做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

问题大概是在第一个“p_qwordseq”制作中字符串“'AND'”将与't_qword = r'\ w +'匹配,即您需要消除语法歧义。 –

回答

0

Ply对排序令牌正则表达式有一些偏心的方法,部分原因是它依赖于基础Python正则表达式库。使用功能(例如number令牌)定义的令牌按其出现顺序进行识别,与许多词汇扫描程序生成器不同,Ply不会尝试执行最长匹配。通过赋值定义的标记 - 所有其他标记类型 - 具有比函数更低的优先级,并通过减少长度(正则表达式)来按顺序排列。

帘布层手册(第4.3节)强烈表明不使用关键字令牌如AND变量赋值的风格,因为该模式r'AND',例如,将认识到的前三个字符,例如,ANDROGYNOUS,你大概会期望成为一个变量。相反,它建议使用具有简单模式的函数首先将所有关键字和变量识别为简单单词,然后使用字典识别特定关键字。示例代码和较少的电报解释在Ply手册中(在上面引用的部分中)。

相关问题