Encontrar rápidamente cadenas vacías que producen no terminales en un CFG

8

Para un lenguaje libre de contexto determinado G, que llamamos un no terminal nullable si , es decir, podemos derivar la cadena vacía de después de aplicar un número finito de producciones.Ai AiϵAi

Hay un algoritmo simple para determinar qué no terminales de una gramática son anulables, como se puede encontrar aquí :

Comenzamos considerando todos los no terminales como no anulables. todos los como anulables si hay una producción . Luego hacemos un bucle sobre todas las demás producciones excluyendo las producciones con un terminal en ellas, y marcamos como anulable si todos son anulables. Seguimos haciendo este bucle hasta que terminemos un bucle sin marcar ningún no terminal como anulable.A iϵ A iB 1 B 2B k A i B iAiAiϵAiB1B2BkAiBi

Mi problema con este algoritmo es que tiene un tiempo de ejecución: un peor de los casos es por ejemplo , , , ..., , .A 1A 2 A 2A 3 A 3A 4 A n - 1A n A nϵO(n2)A1A2A2A3A3A4An1AnAnϵ

¿Existe un algoritmo para este problema con un mejor tiempo de ejecución que ?O(n2)

Alex ten Brink
fuente
2
¿No es elemental implementar ese algoritmo en tiempo lineal? ¿Podría ser esto un problema de tarea?
Warren Schudy
¿Está interesado en una determinada clase de gramáticas o quiere abordar las gramáticas arbitrarias?
Raphael
1
Estoy interesado en abordar las gramáticas arbitrarias: estoy implementando un analizador Earley, para el cual es útil saber si un no terminal puede derivar la cadena vacía. Mi reacción inicial fue que esto debería ser trivialmente solucionable en tiempo lineal, pero las gramáticas como , complican las cosas. B AABBA
Alex ten Brink
¿Tiene alguna razón para mantener tales reglas en alguna situación práctica?
Raphael
1
Estoy implementando un analizador Earley de la manera descrita aquí: webhome.cs.uvic.ca/~nigelh/Publications/… . En el enfoque adoptado en ese documento, en algún momento uno necesita encontrar los no terminales anulables para una gramática: una vez que se conocen, es muy fácil adaptar el algoritmo de Earley para manejar las producciones de épsilon.
Alex ten Brink

Respuestas:

8

¿No se puede implementar ese algoritmo en tiempo lineal de la siguiente manera? (Advertencia: no he revisado esto con demasiada atención, por lo que es probable que haya errores).

En lo que sigue cada vez que digo "producción" me refiero a incluir solo aquellos que no incluyen terminales. Construir una lista, para cada no terminal, de las producciones que aparece. Para cada producción dejo c i contar cuántas no terminales distintos en el lado derecho están marcados como no anulable. Supongamos que Q denota una cola de no terminales que se han marcado como nulos pero aún no procesados. Inicialice todo c i al número de no terminales distintos en el lado derecho de producción i . Inicialice todos los no terminales a no anulables. Para cada Z no terminal generada por la producción i con c i =iciQciiZi agregue Z a Q y marque Z como anulable.ci=0ZQZ

Mientras no está vacío, elimine una X arbitraria no terminal de Q y procese de la siguiente manera. Por cada producción j en la que X está, decremente c j . Si a c j se convierte en cero, verifique si el Y no terminal correspondiente ya se ha marcado como nulo. Si no es así, marque Y anulable y añadir Y a Q .QXQjXcjcjYYYQ

Warren Schudy
fuente
A menos que me falte algo, creo que su algoritmo debería funcionar. Me parece muy extraño que si busco en Internet un algoritmo para este problema, obtengo más de media docena de visitas en la primera página que describen alguna variación del algoritmo que describí en mi primera publicación: ¿por qué dar un algoritmo n cuadrado? si existe un algoritmo lineal simple?
Alex ten Brink
Una razón probable para dar el algoritmo cuadrático es que es aún más simple. Si solo quiere dar a las personas una comprensión de la nulabilidad, ocultar los detalles de implementación tiene sentido.
Warren Schudy