Localizando rapidamente não-terminais de produção de cadeia vazia em um CFG

8

Para uma dada linguagem livre de contexto G, chamamos um não-terminal anulável se , ou seja, podemos derivar a string vazia de depois de aplicar um número finito de produções.UMAEu UMAEuϵUMAEu

Existe um algoritmo simples para determinar quais não-terminais de uma gramática são anuláveis, como pode ser encontrado aqui :

Começamos considerando todos os não-terminais como não anuláveis. todos os como anuláveis ​​se houver uma produção . Em seguida, passamos por todas as outras produções excluindo produções com um terminal nelas e marcamos como nulo se todos os forem nulos. Continuamos fazendo esse loop até terminar um loop sem marcar nenhum termo-terminal como nulo.UMAEuUMAEuϵUMAEuB1B2BkUMAEuBEu

Meu problema com esse algoritmo é que ele tem um tempo de execução : o pior caso é, por exemplo, , , , ..., , .O(n2)UMA1UMA2UMA2UMA3UMA3UMA4A nϵUMAn-1UMAnUMAnϵ

Existe um algoritmo para esse problema com um tempo de execução melhor que ?O(n2)

Alex ten Brink
fonte
2
Não é fundamental implementar esse algoritmo em tempo linear? Isso pode ser um problema de lição de casa?
22710 Warren Schudy
Você está interessado em uma determinada classe de gramáticas ou deseja lidar com gramáticas arbitrárias?
Raphael
1
Estou interessado em abordar gramáticas arbitrárias: estou implementando um analisador Earley, para o qual é útil saber se um não-terminal pode derivar a sequência vazia. Minha reação inicial foi que isso deveria ser trivialmente solucionável em tempo linear, mas gramáticas como , B A complicam as coisas. UMABBUMA
Alex10 Brink #
Você tem um motivo para manter essas regras em qualquer situação prática?
Raphael
1
Estou implementando um analisador Earley da maneira descrita aqui: webhome.cs.uvic.ca/~nigelh/Publications/… . Na abordagem adotada nesse artigo, em algum momento é necessário encontrar os não terminais para nulidade de uma gramática: uma vez conhecidos, é muito fácil adaptar o algoritmo de Earley para lidar com as produções epsilon.
Alex10 Brink #

Respostas:

8

Não se pode implementar esse algoritmo em tempo linear da seguinte maneira? (Aviso: eu não li isso com muito cuidado, é provável que haja erros.)

No que se segue, sempre que digo "produção", quero incluir apenas aqueles que não incluem terminais. Construir uma lista, para cada não-terminal, das produções em que aparece. Para cada produção deixar c i contar quantos não-terminais distintos no lado direito estão atualmente marcados não anulável. Deixe Q denotar uma fila de não terminais que foram marcados como nulos, mas ainda não processados. Inicialize todos c i para o número de não terminais distintos no lado direito da produção i . Inicialize todos os não terminais para não anuláveis. Para cada Z não terminal gerado pela produção i com c i =EucEuQcEuEuZEu adicione Z a Q e marque Z como nulo.cEu=0 0ZQZ

Enquanto não estiver vazio, remova um X não terminal arbitrário de Q e processe-o da seguinte maneira. Para cada produção jQXQj que está, diminua c j . Se um c J torna-se zero, verificar para ver se o correspondente não terminal Y tenha sido marcado nulo já. Se não, marcar Y anulável e adicionar Y para Q .XcjcjYYYQ

Warren Schudy
fonte
A menos que esteja faltando alguma coisa, acho que seu algoritmo deve funcionar. Eu acho muito estranho que, se eu procurar na Internet um algoritmo para esse problema, recebo mais de meia dúzia de hits na primeira página, descrevendo algumas variações do algoritmo que descrevi no meu primeiro post - por que dar um algoritmo n-quadrado se existe um algoritmo linear simples?
Alex10 Brink
Uma razão provável para fornecer o algoritmo quadrático é que ele é ainda mais simples. Se você deseja apenas dar às pessoas uma compreensão da nulidade, ocultar os detalhes da implementação faz sentido.
Warren Schudy