Domanda

Perché LL (k) e LL (8) sono incompatibili con ricorsione sinistra? Capisco che un LL (k) la lingua in grado di supportare a sinistra ricorsività a condizione che a gettoni k-overahead possono essere risolti ogni ambiguità. Ma, con una grammatica LL (8), quale tipo di ambiguità non può essere risolto?

È stato utile?

Soluzione

Il problema che $ LL $ varianti hanno con la ricorsione sinistra è inerente al modo $ LL $ lavori:. Si tratta di un tipo top-down parser, il che significa che sostituisce nonterminals dai loro produzioni

Un $ LL $ -style parser funziona come segue. Si attraversa l'input da sinistra a destra in un colpo solo. Se siamo a un certo punto l'ingresso, allora sappiamo che tutto ciò che a sinistra di questo punto è OK. Per tutto alla destra di questo punto, il parser ha costruito un 'approssimazione' di quello che si aspetta di vedere il prossimo. Consideriamo per esempio questa grammatica:

1: $ E \ a E + E $
2: $ E \ a $ x

Si noti che la grammatica non LL $ $ è, ma siamo in grado di ingressi ancora parse a $ LL $ in stile. Su Ingresso $ x + x + x $, un parser in stile $ LL $ può finire alla posizione $ x + \ bullet x + x $. Supponiamo che si è deciso che la parte sinistra, $ x + $, va bene, e per il resto dell'ingresso si aspetta di vedere $ x + E $. Sarà poi scoprire che $ x + x + $ va bene, con $ E $ rimanenti. Può quindi sostituire questo $ E $ da una produzione, in particolare la produzione 2 di cui sopra. Con $ x $ rimanente, il parser accetterà l'input.

Il trucco è quindi di decidere correttamente la produzione di sostituzione per un dato non terminale. Una grammatica è $ LL (k) $ se siamo in grado di farlo da solo guardando al prossimo simboli $ k $ di ingresso, e altre tecniche sono note che sono più potenti.

Consideriamo ora la seguente grammatica:

1: $ A \ ad A a $
2: $ A \ a \ varepsilon $

Se un $ LL $ parser tenta di sostituire $ A $ da una produzione, si deve decidere tra la produzione 1 e 2.

Consideriamo ciò che la corretta linea di condotta sarebbe se il nostro parser era onnisciente. Ogni volta che si sostituisce il $ A $ per la produzione di 1, e 'aggiunto' un $ A $ per quello che si aspetta per l'ingresso rimanente (il resto previsto va da $ A $ a $ Aa $ a $ Aaa $ ...), ma il $ a $ alla partenza non va via. Alla fine, esso deve raccogliere la produzione 2, dopo di che il $ A $ scompare e non può più aggiungere $ a $ s per l'aspettativa.

Poiché non v'è alcuna possibilità di abbinare un paio di simboli di input, il parser deve decidere esattamente quella posizione di ingresso quante volte la produzione di 1 deve essere abbinato. Questo significa che deve sapere esattamente quante volte nel nostro caso appare il $ a $ nel resto dell'ingresso in questo momento.

Tuttavia, $ LL (k) $ può vedere solo $ k $ simboli avanti. Ciò significa che se la produzione di 1 deve essere scelto più di $ k $ volte, il parser non può 'vedere' questo e così è destinato a fallire. $ LL (*) $ è migliore a parsing di $ LL (k) $, perché può vedere arbitrariamente molto più avanti in entrata, ma il dettaglio fondamentale (che non è sempre menzionato) è che questo lookahead è normale .

Per immaginare quello che succede, è possibile visualizzare l'algoritmo come segue: quando si deve decidere che la produzione a prendere, si avvia una macchina a stati finiti (un DFA, che equivale al potere per le espressioni regolari) e permette di questa macchina guardare il resto dell'ingresso. Questa macchina può poi riferire 'usare questa produzione'. Tuttavia, questa macchina è fortemente limitata in ciò che può fare. Anche se è strettamente meglio che guardare solo il prossimo $ k $ simboli, non può per esempio 'count', il che significa che essa non può fare nella situazione di cui sopra.

Anche se si dovesse 'incidere' in qualche funzione di conteggio in questo automa a stati finiti, quindi ci sono ancora grammatiche per il quale si ha realmente bisogno di più potenza ricorsive a sinistra. Per esempio, per questa grammatica:

$ A \ B ad A $
$ A \ a \ varepsilon $
$ B \ a (B) $
$ B \ a \ varepsilon $

si sarebbe dovuto corrispondere 'torri' di parentesi graffe di corrispondenza, che è qualcosa di un automa a stati finiti non può fare. Peggio ancora:

$ A \ B a C A D E $
$ A \ A '$
$ A '\ A' D E $
$ A' \ a \ varepsilon $
$ B \ ad un B un \ metà b B b \ metà a a \ metà bb $
$ C \ C C c \ metà d C d \ metà c c \ metà d d $
$ D \ a e D e \ metà f D f \ mid e e\ Metà f f $
$ E \ to g E g \ metà h E h \ metà g g \ metà h h $

è una grammatica completamente terribile, per cui sono abbastanza sicuro che non sono noti in tempo lineare opere algoritmo di analisi e di tutti gli algoritmi di analisi generale noti richiedono tempo quadratico. Peggio ancora, qualsiasi grammatica che descrive questo linguaggio è necessariamente sinistro ricorsivo. La grammatica è ancora ambigua comunque. Avete bisogno di un parser a mano artigianale per analizzare questi mostri in tempo lineare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a cs.stackexchange
scroll top