2010-11-03 17 views
28

Quali vantaggi hanno i parser LL su parser LR per garantire la relativa popolarità in today's parser generator tools?Quali vantaggi hanno i parser LL rispetto ai parser LR?

Secondo Wikipedia, LR analisi sembra avere vantaggi rispetto LL:

LR analisi in grado di gestire una gamma più ampia di lingue diverse LL analisi, ed è anche meglio a segnalazione degli errori, vale a dire che rileva gli errori sintattici quando l'input non è conforme alla grammatica il prima possibile. Questo è in contrasto con un LL (k) (o anche peggio, un parser LL (*)) che può differire il rilevamento degli errori in un ramo diverso della grammatica a causa del backtracking, spesso rendendo gli errori più difficili da localizzare attraverso disgiunzioni con lunghi prefissi comuni .

Nota: questo non è compito. Sono stato sorpreso quando ho scoperto che Antlr è un generatore di parser LL (nonostante abbia "LR" nel suo nome!).

+0

Parlando * parser * (e non grammatiche): LL (*) può essere scritta in modo semplice ricorsiva -approccio decente. Questo è un +1 nel mio libro. –

+0

@pst: true, stavo solo sperando che "perché sono più facili da implementare" non era il vantaggio principale. :) –

+3

Nota che "LR" in ANTLR sta semplicemente per "Language Recognition", non qualcosa sulla classe di grammatica che accetta. –

risposta

26

GLR è ottimo se si desidera un albero/foresta di analisi e non si preoccupa delle scatole nere. Ti consente di digitare qualsiasi cosa CFG a costo di verificare le ambiguità in fase di analisi tramite test approfonditi, invece di risolvere i conflitti LR/LALR in modo statico. Alcuni dicono che è un buon compromesso. Lo strumento DMS di Ira Baxter o Elkhound, che ha una grammatica C++ libera, è utile per questa classe di problemi. ANTLR è utile anche per un'ampia classe di applicazioni linguistiche, ma utilizza un approccio top-down, generando parser di discesa ricorsivi chiamati LL (*) che consentono i predicati semantici. Qui dichiarerò senza prove che i predicati consentono di analizzare i linguaggi sensibili al contesto oltre i CFG. Ai programmatori piace inserire azioni in grammatiche, come una buona gestione degli errori, e come il debug in un unico passaggio.LL è buono a tutti e tre. LL è ciò che facciamo a mano, quindi è più facile da capire. Non credere allo wikipedia nonsense about LR being better at handling errors. Detto questo, se si esegue un backtrack molto con ANTLR, gli errori sono effettivamente peggiori con LL (*) (i PEG hanno questo problema).

Re backtracking. GLR specula (vale a dire backtrack) anche, proprio come PEG, ANTLR e qualsiasi altra strategia non deterministica. In qualsiasi stato LR non deterministico, i sotto-parser GL "forks" consentono di provare qualsiasi percorso percorribile. Ad ogni modo, LL ha un buon contesto per la gestione degli errori. Dove LR sa che corrisponde ad un'espressione, LL sa che è un'espressione in un compito o IF -conditional; LR sa che potrebbe essere in entrambi ma non è sicuro - e che l'incertezza è dove ottiene il suo potere.

GLR è O(n^3) caso peggiore. packrat/PEG è il peggior caso O(n). Le ANTLR sono O(n^2) a causa del DFA lookahead ciclico ma in pratica O(n). Non importa davvero GLR è abbastanza veloce.

ANTLR è AN altro T ool per L ang R eCognition non anti-LR, ma mi piace anche quello;)

Francamente, come un sacco di giovani programmatori negli anni '80, non capivo LALR e non mi piacevano le scatole nere (ora scavo la bellezza del motore GLR ma preferisco comunque LL). Ho costruito un compilatore commerciale basato su LL (k) e ho deciso di creare uno strumento per generare ciò che avevo costruito a mano. ANTLR non è per tutti e casi limite come C++ potrebbero essere meglio gestiti con GLR ma molte persone trovano ANTLR adatto alla loro zona di comfort. Dal gennaio 2008, ci sono stati 134.000 download del barattolo binario di ANTLR, all'interno di ANTLRWorks, e il totale delle zips di origine (secondo Google Analytics). Vedi our paper su LL (*) con molti dati empirici.

+1

Posso certamente apprezzare la possibilità di eseguire il debug line-by-line! Posso anche apprezzare l'idea di "contesto" (cioè, sapendo che l'espressione analizzata è contenuta in un'istruzione 'if'). Grazie per la risposta, certamente illustra alcuni punti di forza dei parser LL! –

+0

@Terence: qual è il problema di una "scatola nera"? Tutti i generatori di parser e le macchine di supporto sono praticamente dei misteri per gli utenti e giustamente; la maggior parte degli utenti non vuole conoscere la teoria o gli ingranaggi. Compro la tua "prova assente" di ANTLR andando oltre i CFG; ma questo è vero per qualsiasi motore basato sulla grammatica che permetta anche i predicati semantici. In pratica, lo fanno tutti (almeno tutti quelli che ho incontrato o costruito :) compresi i DMS. Il passaggio singolo è una questione di strumenti, non la tecnologia del generatore di parser. La qualità del recupero degli errori ha la stessa proprietà. –

+3

Tutti: Sono d'accordo sul fatto che ANTLR e la maggior parte dei generatori di parser sono utili per la costruzione di parser per grammatiche "modeste". La distinzione inizia a verificarsi quando le grammatiche diventano "difficili". Se hai il controllo della grammatica e puoi cambiarla per far sparire i casi difficili, allora qualsiasi generatore di parser lo farà. Se non lo sei, la forza del generatore di parser conta davvero. In entrambi i casi, l'ingegneria a supporto dello strumento aiuta davvero. Nonostante il mio pregiudizio verso GLR (sono anche O (n) in pratica!), Sarò il primo ad ammettere che Terence ha fatto un lavoro abbastanza decente rendendo l'ANTLR efficace. –

-1

Una ragione che viene in mente è che è molto più facile fare un linguaggio che ha bisogno backtracking arbitraria (tosse C++) in un paradigma LL.

+0

* Cough * C++ NON necessita di backtracking arbitrario. Un parser GLR lo fa bene. Vedi la mia risposta. –

+0

Voglio dire, C++ non è LL (k) o LR (k) per ogni k finito, a causa della ambiguità dichiarazione/espressione. – zwol

+1

Bene, l'analisi del C++ in un senso puro (non GCC-resolves-types-during-parsing hack) richiede che il parser raccolga anche le analisi ambigue. Le analisi LL/LR semplicemente non lo fanno. I parser GLR fanno. Risolvi l'ambiguità in seguito con le informazioni sulla tabella dei simboli, permettendoti di separare l'analisi dal nome e dalla risoluzione del tipo, il che ti dà un parser molto più pulito. –

1

Dalla mia esperienza personale (l'ho usato sia per varie situazioni), la differenza più pratica è che, con un LL (k), è possibile definire la grammatica in un modo più semplice (poiché è dall'alto verso il basso) senza preoccuparsi molti possibili conflitti di riduzione-riduzione o riduzione-spostamento che si verificano spesso con parser LR. L'unica cosa di cui ti devi preoccupare è la ricorsione a sinistra che deve essere trasformata in quella giusta.

Un'altra cosa è che l'approccio top-down di solito implica una complessità più alta (rispetto allo spazio o al tempo), perché deve memorizzare l'intero albero durante l'analisi e può crescere molto finché non si risolvono le ambiguità.

+0

Solo così capisco ... Stai dicendo che la differenza più pratica è che i parser LL evitano i conflitti tipici dei parser LR. Ciò si applica solo ai parser LR che limitano il loro lookahead a un numero piccolo (ad esempio LR (1) o LALR (1))? Ho pensato che i parser LR (k) non avessero tanti conflitti ... –

10

Se si ha a portata di mano il codice uno, la discesa ricorsiva (LL) è qualcosa che si può fare realisticamente; le persone non possono costruire manualmente parser L (AL) R praticamente a mano.

Dato che i moderni generatori di parser gestiranno tutta la struttura del parser per te, e che lo spazio non è un gran problema, preferisco i parser LR perché non devi combattere con le grammatiche tanto per renderle valide per il tuo particolare generatore di parser (nessuna "rimozione di tutte le sciocchezze di sinistra").

In effetti, preferisco lo GLR parsers, che analizzerà praticamente qualsiasi cosa con una grammatica senza contesto. Nessun problema di ricorsione a sinistra. Nessuno spostamento/riduzione delle preoccupazioni sui conflitti. Nessun limite di lookahead.

Se volete vedere la gamma di lingue che uno GLR motore di parsing in grado di gestire (tra cui il famoso hard-to-parse-con-LL/lingua LALR, C++), si può guardare here.

+0

non devi combattere contro grammatiche solo perché puoi definire le predizioni direttamente da specifici comandi all'interno della definizione del parser, non perché LR approccio ha meno requisiti sulla grammatica stessa .. – Jack

+0

@Ira: post molto interessante! Non avevo mai sentito parlare di parser GLR prima. –

+0

@Jack: concordo con il punto su come le direttive di precedenza non siano un vantaggio specifico per LR. Tuttavia, sei d'accordo con il punto di Ira riguardo l'eliminazione della ricorsione a sinistra? –

0

L'unico vantaggio che ho mai avuto è che puoi facilmente codificare i parser LL a mano. I parser LR sono MOLTO più difficili da codificare a mano (di solito si usa un generatore di parser).

+1

E quando si dispone di un tale genarator, la loro produzione è * veramente * facile. –