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