Использование PLY для разбора операторов SQL

Я знаю, что существуют другие инструменты для анализа операторов 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 ответ

Решение

Я думаю, что ваша проблема в том, что ваши регулярные выражения для 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 токен, а затем отсеять вещи во время разбора.

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

Другие вопросы по тегам