Descriverò un algoritmo che funziona. Il tempo di esecuzione non dovrebbe essere così male. Puoi anche pre-calcolarne un po '.
Presumo che non contenga non terminali (anche se probabilmente è facile adattarsi a quel caso) e che non si conosce x , y o la derivazione di a . Presumo anche che la tua grammatica non contenga produzioni che non sono mai utilizzate in alcuna derivazione ( A → A per esempio).un'Xyun'A → A
Il problema principale è davvero analizzare , poiché vuoi sapere in che tipo di stati finisci, quindi sai cosa può seguire un . Non è così facile perché non conosci x .un'un'X
Usiamo un adattamento dell'algoritmo di Earley . Ti consigliamo di capire prima quell'algoritmo. Il nostro algoritmo funziona quasi allo stesso modo, tranne che le fasi di inizializzazione e completamento sono diverse.
Per l'inizializzazione, seminiamo il nostro primo set con un elemento Earley per ogni occorrenza di (il primo carattere in una ) in qualsiasi produzione del vostro grammatica. Impostiamo il puntatore indietro di questo elemento su -1, un valore non valido. Questo è importante nel nostro completamento modificato. In sostanza, -1 significa "Non ho idea di dove sia iniziata questa produzione".un'1un'
Ora eseguiamo l'algoritmo Earley separatamente per ogni possibile articolo Earley iniziale. Non possiamo semplicemente eseguirle tutte contemporaneamente, poiché le analisi potrebbero interferire tra loro. Non riesco a vedere facilmente un metodo più veloce del backtracking qui.
Per la fase di completamento, dobbiamo solo apportare una modifica per gestire -1 puntatori posteriori. Dato che abbiamo completato una produzione di cui non conosciamo l'origine, siamo nei guai. Tuttavia, il metodo utilizzato per calcolare i set di lookahead L A L R ( 1 ) di Pennello e DeRemer ci salva: ciò di cui abbiamo bisogno qui è esattamente il set di lookahead . Ogni articolo in questi set di lookahead ha una posizione corrispondente nella grammatica, che a sua volta corrisponde a una possibile continuazione della produzione completata.L A L R ( 1 )
Sfortunatamente, non vedo davvero altra scelta che tornare indietro di nuovo qui. Per ogni posizione nel set di lookahead, esegui il passaggio di completamento con questa posizione e continua l'analisi da lì. Lo fai separatamente per ogni analisi. Nota che se la tua grammatica è , il tuo lookahead determinerà in modo univoco in quale posizione devi andare, quindi non devi tornare indietro.L A L R ( 1 )
un'
Modifica: penso di aver trovato il metodo che rimuove la maggior parte delle spese generali introdotte dal backtracking. Associamo ad ogni articolo Earley un insieme di identificatori, che sono stringhe, poiché dovremo utilizzare i prefissi di questi identificatori. All'inizializzazione, aggiungiamo tutti gli elementi iniziali al set Earley e associamo un identificatore univoco a ogni set.
Sulle fasi dello scanner e del predittore, gli identificatori vengono riportati a nuovi elementi. Gli articoli Earley nello stesso set Earley che differiscono solo nei loro identificatori vengono uniti unendo i loro identificatori insieme. È possibile eseguire passaggi dello scanner e dei predittori su questi nuovi elementi con identificatori, senza dover eseguire questo passaggio per ogni identificatore separatamente.
L A L R ( 1 )
In sostanza, eseguiamo il backtracking utilizzando questi identificatori, in modo da non fare doppio lavoro nei passaggi dello scanner e dei predittori.