gramatica: Refactor parseo y tests
Refactorizo el parseo de gramáticas para que sea igual al de Grammophone. Esto a futuro nos va a permitir tener símbolos con más de un caracter, pero por la implementación actual no podemos. Se agregan tests para el parseo que chequean que todas las gramáticas que estaban en el directorio de ejemplos se parseen correctamente, y se actualiza su formato.
Revisé y los ejemplos de gramáticas siguen funcionando igual.
Este nuevo formato tiene varias ventajas,
- En el 99% de los casos no vamos a querer tener símbolos que no aparezcan en las producciones, entonces va a ser más cómodo que se infieran a partir de ellas.
- Soporte para comentarios.
- El formato en el que se especifican las producciones es más legible a primera vista sin conocer el formato de antemano.
- Permite agrupar producciones con la misma cabeza.
- Es práctico poder copiar y pegar a grammophone sin cambiar nada.
- Resolved by Manuel Panichelli
- Last updated by Nicolas Pironio
286 return res 287 288 def __eq__(self, other) -> bool: 289 if not isinstance(other, Gramatica): 290 return False 291 292 return ( 293 self.terminales == other.terminales and 294 self.no_terminales == other.no_terminales and 295 self.prods == other.prods and 296 self.simbolo_start == other.simbolo_start 297 ) 298 299 class GramaticaParser(object): Creo que
GramaticaParser
podría estar en un archivo separadoNo me parece mal que los nombres de los métodos estén en ingles, pero a lo mejor intentaría que queden en español para que todo el código quede lo más parecido posible. Aunque justo en este caso no es que es parte de la API del módulo, así que no diría que es crucial renombrarlos
Edited by Nicolas PironioOriginalmente lo implementé en otro archivo, pero el problema es que como en
Gramatica.from_str
se usaGramaticaParser
, y enGramaticaParser.p_grammar
(la regla de la que se inicia) se crea una gramática, hay una dependencia circular.# Gramatica def from_str(cls, gramatica: str): """Parsea una gramática de un string""" return GramaticaParser().parse(gramatica) # GramaticaParser def p_grammar(self, p): 'grammar : rules' prods = p[1] # El símbolo start es la cabeza de la primera producción start = prods[0][0] p[0] = Gramatica( start=start, terminales=self.terminales, no_terminales=self.no_terminales, producciones=prods, verbose=False, )
lo más sencillo para resolverlo me pareció moverlo al mismo archivo, porque las otras soluciones que se me ocurrieron fueron
- hacer que el parser en vez de devolver una gramática devuelva algo intermedio, como por ej. solo las producciones, y que en
Gramatica.from_str
se construya la gramática. Pero me parece que tiene sentido que el parser devuelva la gramática entera. - que el parser siga devolviendo la gramática entera, pero no tener el wrapper en
Gramatica
que genera un parser y le pide que parsee. Esto no me gusta tanto porque me parece que tiene sentido que todas las formas de inicialización estén en la misma claseGramatica
.
Si bien no me gusta tanto como queda el código en castellano, me parece que tiene sentido porque los conceptos en la materia los vemos en castellano y podría ser confuso ponerlo en inglés (por ej. producción vs production y cosas así). Lo que me parece más importante es que seamos consistentes, así que ahí lo cambié!
- hacer que el parser en vez de devolver una gramática devuelva algo intermedio, como por ej. solo las producciones, y que en
added 2 commits
mentioned in commit d4dc19e0