2011-09-08 30 views
6

Sé que hay otras herramientas para analizar sentencias de SQL, pero estoy implementando las mías con fines educativos. Me estoy quedando atrapado con mi gramática en este momento ... Si puede detectar un error muy rápido, por favor hágamelo saber.Uso de PLY para analizar sentencias de 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 

Cuando intento analizar una afirmación como 'SELECCIONE FROM FROM;' Obtengo un error de sintaxis en el token FROM ... ¡Cualquier ayuda es muy apreciada!

(Edición) Código:

#!/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

¿Qué pasa si coloca un espacio entre 'b' y'; '? – zerkms

+0

Todavía el mismo resultado, se me olvidó agregar que ignora los espacios ... Lo editaré en. – sampwing

+1

Por lo que sé, la mayoría de las bases de datos admitirán al menos '[a-zA-Z_0-9]' como tabla nombres. – NullUserException

Respuesta

4

creo que tu problema es que sus expresiones regulares para t_TABLE y t_COLUMN también son coincidentes con sus palabras reservadas (SELECT y FROM). En otras palabras, SELECT a FROM b; tokenizes a algo como COLUMN COLUMN COLUMN COLUMN END (u otra tokenización ambigua) y esto no coincide con ninguna de sus producciones, por lo que se obtiene un error de sintaxis.

Como una comprobación de validez rápida, cambiar esas expresiones regulares para que coincida exactamente lo que se está escribiendo en este aspecto:

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

verá que la sintaxis SELECT a FROM b; pases porque las expresiones regulares 'a' y ' b 'no coinciden con sus palabras reservadas.

Y, hay otro problema que las expresiones regulares para TABLE y COLUMN también se superponen, por lo que el lexer tampoco puede tokenizar sin ambigüedad con respecto a esos tokens.

Hay un subtle, but relevant section in the PLY documentation con respecto a esto. No estoy seguro de la mejor manera de explicar esto, pero el truco es que el pase de tokenización ocurre primero, por lo que no puede usar el contexto de las reglas de producción para saber si se ha topado con un token TABLE o un token COLUMN. Debe generalizarlos en algún tipo de token ID y eliminar las cosas durante el análisis.

Si tuviera un poco más de energía, trataría de trabajar con su código un poco más y proporcionar una solución real en código, pero creo que ya ha expresado que este es un ejercicio de aprendizaje que tal vez estará contento conmigo apuntando en la dirección correcta.

+1

No revisé su respuesta completamente con mi código todavía ... Pero cuando hizo referencia a la documentación, me dio una idea ... ¡Cuánto apreciaba a Joe! – sampwing

+1

Lea el documento cuando estaba más despierto ... La solución era obvia, gracias de nuevo Joe. – sampwing

Cuestiones relacionadas