Una grammatica viene generalmente definita come grammatica senza contesto : una definizione precisa viene fornita nella pagina di Wikipedia, ma funziona come in PLY, che si basa su Bison , che a sua volta si basa su yacc .
Qui dice che PLY usa un parser LALR . Questo è essenzialmente un parser LR in cui le tabelle di ricerca sono condensate, introducendo possibilmente conflitti di analisi, riducendo parte dell'espressività di una grammatica LR (ovvero una grammatica libera dal contesto che un parser LR può analizzare). Se vuoi sapere sulle limitazioni di questa particolare branca della parser e quelle di altri parser, una panoramica di tutti i tipi di tecniche di parsing (LL, LR e altri) è dato qui .
Per rispondere alla tua domanda: esistono algoritmi di analisi in grado di analizzare qualsiasi linguaggio privo di contesto, anche se il linguaggio è ambiguo (ovvero, esiste più di un modo per interpretare l'input):
Il primo algoritmo di questo tipo era l' algoritmo CYK , che purtroppo ha un tempo di esecuzione di , dove n è la lunghezza della stringa di input e | G | è la dimensione della grammatica ed è quindi poco pratico per l'analisi delle lingue.O ( n3| G | )n| G |
Il secondo algoritmo è l' algoritmo Earley . Questo algoritmo è anche in grado di analizzare qualsiasi grammatica libera dal contesto. Sebbene l'algoritmo abbia bisogno di tempo per analizzare un linguaggio ambiguo, richiede solo tempo O ( n 2 ) per analizzare un linguaggio non ambiguo. Inoltre, sembra funzionare in tempo lineare per la maggior parte delle grammatiche LR e funziona particolarmente bene su grammatiche ricorsive a sinistra.O ( n3)O ( n2)
Qui puoi trovare un documento che discute un'implementazione pratica dell'algoritmo Earley (un adattamento). Concludono: "Data la generalità dell'analisi di Earley rispetto all'analisi LALR (1) ((che è approssimativamente ciò che fa PLY)), e considerando che anche il peggio dei PEP ((la loro implementazione dell'algoritmo di Earley)) non sarebbe evidente da un utente, questo è un risultato eccellente ".
L'ultimo tipo di parser è il parser GLR . Questa è una versione generalizzata dell'analisi LR, in grado di analizzare qualsiasi linguaggio privo di contesto.
Un'implementazione matura di GLR è ASF + SDF . Bison può anche generare un parser GLR, sebbene le sue implementazioni siano leggermente diverse dall'algoritmo GLR "standard". L' algoritmo Elkhound è un algoritmo ibrido GLR / LALR. Usa LALR quando possibile e GLR quando necessario, per essere veloce e capace di analizzare qualsiasi grammatica.
Oltre alle grammatiche libere dal contesto ci sono grammatiche sensibili al contesto , ma queste sono generalmente difficili da analizzare e non aggiungono molta espressività: puoi fare di più con loro, ma per la maggior parte delle applicazioni gli usi extra non sono rilevanti, a meno che tu non stia analizzando un linguaggio naturale.
Come ultimo passo ci sono grammatiche senza restrizioni . A questo punto la grammatica è completa di Turing, quindi non c'è alcun limite che uno possa dedicare da quanto tempo ci vorrà per analizzare una determinata lingua, il che è indesiderabile per la maggior parte delle applicazioni di analisi. La potenza extra non è quasi mai necessaria. Se vuoi usare tutta quella potenza, c'è la macchina della lingua disponibile.
Infine, implementare il proprio generatore di parser non è una faccenda banale, in particolare per renderlo veloce. Personalmente ho appena finito di creare la mia versione di flex (il generatore di lexer), e mentre questo sembrava un esercizio in problemi algoritmici relativamente semplici, è diventato abbastanza complesso da ottenere, in particolare quando ho provato a supportare Unicode. Prendi in considerazione l'utilizzo di un'implementazione già esistente invece di scriverne una tua.