Использование PLY для разбора операторов SQL - PullRequest
7 голосов
/ 09 сентября 2011

Я знаю, что существуют другие инструменты для анализа операторов SQL, но я использую свои собственные в образовательных целях.Я застреваю с моей грамматикой прямо сейчас .. Если вы можете обнаружить ошибку очень быстро, пожалуйста, дайте мне знать.

SELECT = r'SELECT'
FROM = r'FROM'
COLUMN = TABLE = r'[a-zA-Z]+'
COMMA = r','
STAR = r'\*'
END = r';'
t_ignore = ' ' #ignores spaces

statement : SELECT columns FROM TABLE END

columns : STAR
        | rec_columns

rec_columns : COLUMN
            | rec_columns COMMA COLUMN

Когда я пытаюсь разобрать оператор типа «ВЫБРАТЬ ИЗ Б;»Я получаю синтаксическую ошибку на токене ОТ ... Любая помощь очень ценится!

(Правка) Код:

#!/usr/bin/python
import ply.lex as lex
import ply.yacc as yacc

tokens = (
    'SELECT',
    'FROM',
    'WHERE',
    'TABLE',
    'COLUMN',
    'STAR',
    'COMMA',
    'END',
)

t_SELECT    = r'select|SELECT'
t_FROM      = r'from|FROM'
t_WHERE     = r'where|WHERE'
t_TABLE     = r'[a-zA-Z]+'
t_COLUMN    = r'[a-zA-Z]+'
t_STAR      = r'\*'
t_COMMA     = r','
t_END       = r';'

t_ignore    = ' \t'

def t_error(t):
    print 'Illegal character "%s"' % t.value[0]
    t.lexer.skip(1)

lex.lex()

NONE, SELECT, INSERT, DELETE, UPDATE = range(5)
states = ['NONE', 'SELECT', 'INSERT', 'DELETE', 'UPDATE']
current_state = NONE

def p_statement_expr(t):
    'statement : expression'
    print states[current_state], t[1]

def p_expr_select(t):
    'expression : SELECT columns FROM TABLE END'
    global current_state
    current_state = SELECT
    print t[3]


def p_recursive_columns(t):
    '''recursive_columns : recursive_columns COMMA COLUMN'''
    t[0] = ', '.join([t[1], t[3]])

def p_recursive_columns_base(t):
    '''recursive_columns : COLUMN'''
    t[0] = t[1]

def p_columns(t):
    '''columns : STAR
               | recursive_columns''' 
    t[0] = t[1]

def p_error(t):
    print 'Syntax error at "%s"' % t.value if t else 'NULL'
    global current_state
    current_state = NONE

yacc.yacc()


while True:
    try:
        input = raw_input('sql> ')
    except EOFError:
        break
    yacc.parse(input)

1 Ответ

4 голосов
/ 09 сентября 2011

Я думаю, что ваша проблема в том, что ваши регулярные выражения для t_TABLE и t_COLUMN также соответствуют вашим зарезервированным словам (SELECT и FROM).Другими словами, SELECT a FROM b; токенизируется до чего-то вроде COLUMN COLUMN COLUMN COLUMN END (или некоторой другой неоднозначной токенизации), и это не соответствует ни одному из ваших произведений, поэтому вы получаете синтаксическую ошибку.

В качестве быстрой проверки работоспособности,измените эти регулярные выражения так, чтобы они точно совпадали с тем, что вы печатаете:

t_TABLE = r'b'
t_COLUMN = r'a'

Вы увидите, что синтаксис SELECT a FROM b; проходит, потому что регулярные выражения 'a' и 'b' не совпадаютВаши зарезервированные слова.

И есть еще одна проблема, заключающаяся в том, что регулярные выражения для TABLE и COLUMN также перекрываются, поэтому лексер не может токенизироваться без неоднозначности в отношении этих токенов.

Есть тонкий, но соответствующий раздел в документации PLY относительно этого.Не уверен, что это лучший способ объяснить это, но дело в том, что сначала проходит этап токенизации, поэтому он не может использовать контекст из ваших производственных правил, чтобы узнать, встречался ли он с токеном TABLE или COLUMN.Вам нужно обобщить их в какой-то токен ID, а затем отсеять их во время разбора.

Если бы у меня было больше энергии, я бы попытался еще немного проработать ваш код и найти реальное решение.в коде, но я думаю, что, поскольку вы уже выразили, что это учебное упражнение, возможно, вы будете довольны мной, указывая в правильном направлении.

...