2011-02-16 20 views
6

Estoy usando ply como mi analizador de lex. Mis especificaciones son las siguientes:Ply Lex problema de análisis

t_WHILE = r'while' 
t_THEN = r'then' 
t_ID = r'[a-zA-Z_][a-zA-Z0-9_]*' 
t_NUMBER = r'\d+' 
t_LESSEQUAL = r'<=' 
t_ASSIGN = r'=' 
t_ignore = r' \t' 

Cuando trato de analizar la cadena siguiente:

"while n <= 0 then h = 1" 

Se da salida siguiente:

LexToken(ID,'while',1,0) 
LexToken(ID,'n',1,6) 
LexToken(LESSEQUAL,'<=',1,8) 
LexToken(NUMBER,'0',1,11) 
LexToken(ID,'hen',1,14)  ------> PROBLEM! 
LexToken(ID,'h',1,18) 
LexToken(ASSIGN,'=',1,20) 
LexToken(NUMBER,'1',1,22) 

No reconoce el token ENTONCES, en cambio, toma "gallina" como identificador.

¿Alguna idea?

+0

Ok, descubrí el problema. – Karan

+0

En realidad, descubrí que debido a t_ignore = r "\ t", estaba ignorando la letra "t" (¡no preguntes mi por qué!). Así que lo eliminé, y ahora comienza a tomar "entonces" como símbolo. – Karan

+1

@Karan: 'r '\ t'' es una cadena * raw *. Supongo que no se pudo escapar el '\ t' y hubiera funcionado si hubieras eliminado la' r' inicial = 't_ignore = '\ t'' – ereOn

Respuesta

7

La razón por la que esto no funcionó está relacionado con la forma en que ply prioriza las coincidencias de tokens, la más larga toge regex se prueba primero.

La manera más fácil de evitar este problema es hacer coincidir los identificadores y las palabras reservadas del mismo tipo, y seleccionar un tipo de token apropiado según la coincidencia. El siguiente código es similar a un ejemplo en la capa ply documentation

import ply.lex 

tokens = [ 'ID', 'NUMBER', 'LESSEQUAL', 'ASSIGN' ] 
reserved = { 
    'while' : 'WHILE', 
    'then' : 'THEN' 
} 
tokens += reserved.values() 

t_ignore = ' \t' 
t_NUMBER = '\d+' 
t_LESSEQUAL = '\<\=' 
t_ASSIGN = '\=' 

def t_ID(t): 
    r'[a-zA-Z_][a-zA-Z0-9_]*' 
    if t.value in reserved: 
     t.type = reserved[ t.value ] 
    return t 

def t_error(t): 
    print 'Illegal character' 
    t.lexer.skip(1) 

lexer = ply.lex.lex() 
lexer.input("while n <= 0 then h = 1") 
while True: 
    tok = lexer.token() 
    if not tok: 
     break 
    print tok 
4

prioriza las fichas declaradas como cadenas simples de acuerdo con la expresión regular más larga, pero los tokens declarados como funciones tienen su orden de prioridad.

A partir de los documentos:

Cuando la construcción de la expresión regular maestro, se añaden reglas en el siguiente orden:

  1. Todos los tokens definidos por funciones se añaden en el mismo orden en que aparecen en el archivo lexer.
  2. Los tokens definidos por cadenas se agregan a continuación clasificándolos en orden de disminución de la longitud de expresión regular (primero se agregan expresiones más largas ).

Por lo tanto, una solución alternativa sería simplemente para especificar las fichas que desea priorizados como funciones, en lugar de cuerdas, así:

def t_WHILE(t): r'while'; return t 
def t_THEN(t): r'then'; return t 
t_ID = r'[a-zA-Z_][a-zA-Z0-9_]*' 
t_NUMBER = r'\d+' 
t_LESSEQUAL = r'<=' 
t_ASSIGN = r'=' 
t_ignore = ' \t' 

De esta manera tiempo y luego serán las primeras reglas para ser agregado, y obtienes el comportamiento que esperabas.

Como nota al margen, usaba r' \t' (cadena sin procesar) para tignorar, por lo que Python estaba tratando el \ como una barra invertida. Debería ser una cadena simple en su lugar, como en el ejemplo anterior.