使用PLY解析SQL语句

时间:2011-09-08 22:57:08

标签: python sql parsing context-free-grammar ply

我知道还有其他工具来解析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

当我尝试解析像'SELECT a FROM b;'这样的语句时我在FROM令牌上遇到语法错误...非常感谢任何帮助!

(编辑)代码:

#!/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 个答案:

答案 0 :(得分:4)

我认为您的问题是t_TABLEt_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的正则表达式也会重叠,因此词法分析器无法在没有歧义的情况下进行标记化。

对此有一个subtle, but relevant section in the PLY documentation。不确定解释这个的最好方法,但诀窍是令牌化传递首先发生,因此它不能真正使用生产规则中的上下文来知道它是否遇到了TABLE令牌或COLUMN令牌。你需要将它们概括为某种ID令牌,然后在解析过程中解决这些问题。

如果我有更多的精力,我会尝试更多地处理您的代码,并提供代码中的实际解决方案,但我想,因为您已经表示这是一个学习练习,也许您会满意我指着正确的方向。