2009-12-01 16 views
16

Estoy construyendo un analizador sintáctico para un lenguaje de programación imaginario llamado C-- (no el lenguaje C-- real). Llegué al punto en el que necesito traducir la gramática del idioma a algo que Pyparsing puede aceptar. Desafortunadamente, cuando procedo a analizar mi cadena de entrada (que es correcta y no debe causar errores de Pyrarsing), no está analizando correctamente. Me temo que esto se debe a errores en mi gramática, pero como estoy empezando a Pyparsing por primera vez, parece que no puedo ver dónde me estoy equivocando.Depurando Pyparsing Grammar

He subido la gramática que estoy traduciendo de here para que las personas la lean.

EDIT: Actualizado con el asesoramiento de Paul.

Ésta es la gramática Tengo actualmente (las dos líneas superiores de Sintaxis definición son terriblemente mal de mí lo sé):

# Lexical structure definition 
ifS = Keyword('if') 
elseS = Keyword('else') 
whileS = Keyword('while') 
returnS = Keyword('return') 
intVar = Keyword('int') 
voidKeyword = Keyword('void') 
sumdiff = Literal('+') | Literal('-') 
prodquot = Literal('*') | Literal('/') 
relation = Literal('<=') | Literal('<') | Literal('==') | \ 
      Literal('!=') | Literal('>') | Literal('=>') 
lbrace = Literal('{') 
rbrace = Literal('}') 
lparn = Literal('(') 
rparn = Literal(')') 
semi = Literal(';') 
comma = Literal(',') 
number = Word(nums) 
identifier = Word(alphas, alphanums) 

# Syntax definition 
term = '' 
statement = '' 
variable = intVar + identifier + semi 
locals  = ZeroOrMore(variable) 
expr  = term | OneOrMore(Group(sumdiff + term)) 
args  = ZeroOrMore(OneOrMore(Group(expr + comma)) | expr) 
funccall = Group(identifier + lparn + args + rparn) 
factor  = Group(lparn + expr + rparn) | identifier | funccall | number 
term  = factor | OneOrMore(prodquot + factor) 
cond  = Group(lparn + expr + relation + expr + rparn) 
returnState = Group(returnS + semi) | Combine(returnS + expr + semi) 
assignment = Group(identifier + '=' + expr + semi) 
proccall = Group(identifier + lparn + args + rparn + semi) 
block  = Group(lbrace + locals + statement + rbrace) 
iteration = Group(whileS + cond + block) 
selection = Group(ifS + cond + block) | Group(ifS + cond + block + elseS + block) 
statement = OneOrMore(proccall | assignment | selection | iteration | returnState) 
param  = Group(intVar + identifier) 
paramlist = OneOrMore(Combine(param + comma)) | param 
params  = paramlist | voidKeyword 
procedure = Group(voidKeyword + identifier + lparn + params + rparn + block) 
function = Group(intVar + identifier + lparn + params + rparn + block) 
declaration = variable | function | procedure 
program  = OneOrMore(declaration) 

Me gustaría saber si hay algún error I' he hecho la traducción de la gramática y las mejoras que podría hacer para simplificarla mientras sigo la gramática que se me ha dado.

EDIT 2: Se ha actualizado para incluir el nuevo error.

Aquí es la cadena de entrada estoy de análisis: se

int larger (int first , int second) { 
if (first > second) { 
return first ; 
} else { 
return second ; 
} 
} 

void main (void) { 
int count ; 
int sum ; 
int max ; 
int x ; 

x = input () ; 
max = x ; 
sum = 0 ; 
count = 0 ; 

while (x != 0) { 
count = count + 1 ; 
sum = sum + x ; 
max = larger (max , x) ; 
x = input () ; 
} 

output (count) ; 
output (sum) ; 
output (max) ; 
} 

Y este es el mensaje de error que consigo cuando se ejecuta mi programa de la Terminal:

/Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1156: SyntaxWarning: null string passed to Literal; use Empty() instead 
other = Literal(other) 
/Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1258: SyntaxWarning: null string passed to Literal; use Empty() instead 
other = Literal(other) 
Expected ")" (at char 30), (line:6, col:26) 
None 
+0

¿Tiene alguna pista para nosotros, como qué mensaje de error está recibiendo (si corresponde)? Usted dice "no está analizando correctamente", pero ¿cómo lo sabe? Hay un error? ¿Está generando un AST incorrecto? Se necesita más información. –

+0

Perdón por eso. He actualizado mi pregunta con la cadena de entrada que estoy intentando analizar y los mensajes de error que recibo en la Terminal. – greenie

Respuesta

31

1) Cambiar Literal("if")-Keyword("if") (y así sucesivamente, hasta Literal("void")), para evitar que coincida con el "si" de una variable llamada "ifactor".

2) nums, alphas y alphanums no son expresiones, que son cadenas, que se pueden utilizar con la clase de palabra para definir algunos conjuntos típicos de caracteres en la definición de "palabras" como "un número es una palabra compuesta de nums ", o" un identificador es una palabra que comienza con un alfa, seguido de cero o más alfanuméricos ". Así que en lugar de:

number = nums 
identifier = alphas + OneOrMore(alphanums) 

que quieren

number = Word(nums) 
identifier = Word(alphas, alphanums) 

3) En lugar de Combine, creo que quieres Group. Use Combine cuando desee que los tokens coincidentes sean contiguos sin espacios en blanco intermedios, y concatenará los tokens y los devolverá como una sola cadena. Combine se utiliza a menudo en casos como éste:

realnum = Combine(Word(nums) + "." + Word(nums)) 

Sin Combine, analizar "3.14" devolvería la lista de cadenas ['3', '.', '14'], así que agregamos Combine de modo que el resultado del análisis de realnum es '3.14' (que luego se podría pasar a una acción de análisis para convertir al valor flotante real 3.14). La aplicación Combine de espacios en blanco intermedios también evita que analicemos accidentalmente 'The answer is 3. 10 is too much.' y pensemos que el "3. 10" representa un número real.

4) Esto no debería causar su error, pero su cadena de entrada tiene lotes de espacios adicionales. Si logras que tu gramática funcione, deberías poder analizar "int x;" tan bien como "int x ;".

Espero que algunos de estos consejos te ayuden. ¿Has leído algún tutorial o artículos de pyparsing en línea? Y mira los ejemplos en línea. Necesitará obtener una buena idea de cómo Word, Literal, Combine, etc. realizan sus tareas de análisis individual.

5) No ha implementado correctamente las definiciones recursivas para el término y el enunciado. En lugar de asignar '' a ellos, escribir:

term = Forward() 
statement = Forward() 

A continuación, cuando se va a definir la realidad con sus definiciones recursivas, utilice el operador << (y asegúrese de incluir la RHS en () 's).

term << (... term definition ...) 
statement << (... statement definition ...) 

puede encontrar un ejemplo de un programa de análisis recursivo here, y una presentación sobre el uso pyparsing básica here - consulte la sección titulada "Analizar listas" para más paso a paso de cómo se maneja la recursividad.

+0

Gracias Paul. He reemplazado todas las instancias de Combine with Group y ahora recibo algunos errores diferentes que creo que están relacionados con la forma en que se escriben mis reglas en lugar de la sintaxis que he usado. Actualicé mi publicación original para reflejar los cambios que sugirió y el nuevo error que tengo. – greenie

+0

Excelente Paul, muchas gracias. Ojalá pudiera +1 más :) – greenie