270 likes | 461 Views
CAP. 3 ANALISI SINTATTICA. 3.1 Il ruolo dell'analizzatore sintattico 3.2 Le grammatiche 3.3 L’analisi discendente 3.4 L’analisi ascendante. 3.1 Il ruolo dell'analizzatore sintattico. unità lessicale. analizzatore lessicale. analizzatore sintattico. programma iniziale.
E N D
CAP. 3 ANALISI SINTATTICA • 3.1 Il ruolo dell'analizzatore sintattico • 3.2 Le grammatiche • 3.3 L’analisi discendente • 3.4 L’analisi ascendante
3.1 Il ruolo dell'analizzatore sintattico unità lessicale analizzatore lessicale analizzatore sintattico programma iniziale albero di analisi (sintattico) richiesta tabella dei simboli Ruolo centrale della parte frontale: attiva l'analizzatore lessicale con richieste verifica la correzzione sintattica costruisce l'albero di analisi prepara e anticipa la traduzione gestisce gli errori comuni di sintassi.
Tipi di analizzatori sintattici: • metodi universali (Cocke-Younger-Kasami), permettono un'analisi di qualsiasi grammatica algebrica, ma complessità in O(n3); • metodi lineari in O(n), su certe grammatiche: analisi discendente, più intuitiva, ben adatta a grammatiche simplici; analisi ascendente, più sofisticata, più utilizzata dai generatori automatici di analizzatori sintattici, poichè necessita poche adattazioni della grammatica. Trattamento degli errori: • diagnosi (messagi); • continuazione dell'analisi: "modo panico", fino a risincronizzazione; correzione (difficile se l’errore è avvenuta molto prima della detezione; regole di errori, integrate alla sintassi (grammatica).
3.2 Le grammatiche Sintassi specificata da regole grammaticali. • Simboli terminali (= unità lessicali) alfabeto A; • Simboli intermedi o variabili (= categorie grammaticali) alfabeto X; • Regole grammaticali xw , dove xX e w (AX)* w è una parole, anche vuota. Esempi : instrifexprtheninstrelseinstr frasesoggetto verbo complemento • Assioma (= programma) Linguaggio generato = parole terminali derivate dall'assioma.
Esempio: Espressioni aritmetiche Enumber E ( E ) EE + E EE – E EE * E EE / E Albero d'analisi di 3*(6+2) E E * E 3 number ( E ) E + E 6 number 2 number I valori espliciti sono attributi delle unità lessicali. L’associazione alle unità lessicali è realizzata dall’analizzatore lessicale.
Grammatica precedente ambigua Grammatica non ambigua per espressioni aritmetiche (operatori suffissi): EEE + | EE – | EE * | EE / | number Grammatica non ambigua per expressioni aritmetiche: EE +T | E –T | T TT *F | T /F | F F ( E ) | number Scelta: associatività a sinistra precedenza di * e / su + et –
Analisi sintattica: Data una parola terminale, determinare se è, sì o no, generata dalla grammatica; in caso di sì, produrre un albero d'analisi. • Metodo universale: provare tutte le derivazioni partendo dall’assioma, fino a trovare la parola. Regole di lunghezza (dopo modificazioni) permettono di eliminare le derivazioni che non possono convenire. • Metodo discendente (descesa recursiva): una procedura per variabile, i terminali servono a scegliere la regola (previsione) e alla validazione. • Metodo ascendante: la parola è letta (spostamento) fino ad identificare regole, che vengono ridotte (riduzione).
3.3 L’analisi discendente Una procedura per variabile. Problema: ricorsività diretta a sinistra; necessità di una trasformazione per eliminarla. Grammatica iniziale Grammatica modificata EE +T | T TT *F | F F (E ) | number A E$(produzione aumentata) E TG G +TG | TFU U *FU | F (E ) | number Procedure corrispondenti: supponiamo che due procedure sono già scritte: • prevision ritorna l’unità lessicale seguente senza rimuoverla; • match(x) legge l’unità lessicale seguente, la rimuove e segnala un errore se non vale x.
procedure expression ; begin writeln(‘E->TG’) ; term ; moreterm end ; procedure moreterm ; begin if prevision = plus then begin writeln(‘G->+TG’) ; match(plus) ; term ; moreterm end else writeln(‘G->epsilon’) end ; procedure expression ; begin writeln(‘E->TG’) ; term ; while prevision = plus do begin writeln(‘G->+TG’) ; match(plus) ; term end ; writeln(‘G->epsilon’) end ; Raggruppando e eliminando la ricorsività terminale
procedure term ; begin writeln(‘T->FU’); factor ; while prevision = mult do begin writeln(‘U->*FU’) ; match(mult) ; factor end ; writeln(‘U->epsilon’) end ; procedure factor ; begin if prevision = open then begin writeln(‘F->(E)’) ; match(open) ; expression ; match(close) end else if prevision = number then begin writeln(‘F->number’); match(number) end else writeln(‘error’) end ; procedure analysis ; begin writeln(‘A->E$’) ; expression ; match(dollar) ; writeln(‘success’) end ; Il fallimento dell’analisi è trattato da match(x).
Funzioni FIRST e NEXT x FIRST(x) NEXT(x) FIRST(x) = insieme dei terminali che possono cominciare una derivazione da x. NEXT(x) = insieme dei terminali che possono seguire x in una derivazione
Calcolo di FIRST: Un grafo è costruito fra tutti i simboli grammaticali. Freccia da x verso y ssi xy , e è annullabile. Qui, contiene solo variabili, senza restrizione (anche ). FIRST(x) = { a terminale | esiste un cammino da x fino a a } ; se x è annulabile, si aggiunge a FIRST(x). Esempio con la grammatica precedente: Annulabili: G e U Grafo: A E T F ( G + U * number FIRST(A) = FIRST(E) = FIRST(T) = FIRST(F) = { (, number } FIRST(G) = {+, } FIRST(U) = { *, } La funzione FIRST è estesa a tutte le parole: FIRST(xu) = FIRST(x) se x non è annullabile {}FIRST(x) \ } FIRST(u) se x è annullabile
Calcolo di NEXT: Un grafo è costruito fra tutti i simboli grammaticali. Freccia da x verso y sse • esiste zx , y è terminale e y FIRST() ; • esiste yx e è annullabile. Qui, e sono parole qualsiasi (anche ). NEXT(x) = { a terminale | esiste un cammino da x fino a a }. Esempio con la grammatica precedente: F * Grafo: NEXT non è definito per l'assioma della produzione aumentata (qui A). NEXT(G) = NEXT(E) = { $, ) } NEXT(U) = NEXT(T) = { +, $, ) } NEXT(F) = { *, +, $, ) } U T + G E $ )
Con FIRST e NEXT si possono caratterizzare le grammatiche analizzabili in modo discendente, usando un solo simbolo di previsione a: a parte già analizzata simbolo di previsione parte ancora da analizzare Grammatiche LL(1). Siaa il simbolo di previsione e x la variabile da riscrivere. Utilizzare la regola x se a FIRST(); Se è annullabile, utilizzare la regola x se a NEXT(x). La grammatica è LL(1) quando, per ogni x, una sola regola soddisfa una delle condizioni sopraddette.
Tabella di analisi LL(1): 0 A E$ 1 E TG 2 G +TG 3 G 4 TFU 5 U *FU 6 U 7 F ( E ) 8 F number ( ) n $ + * E 1 1 G 2 3 3 T 4 4 U 6 5 6 6 F 7 8 I vuoti nella tabella corrispondono a errori sintattici. La tabella specifica i collegamenti nelle procedure del programma di analisi per discesa ricorsiva. Può anche essere usato come il dato di un programma universale di analisi discendente non ricorsiva.
3.4 L’analisi ascendante Si utilizza uno pila e un automa. Le transizioni di esso dipendono dal simbolo seguente: oppure • si mette uno stato sulla pila (push) e si rimuove il simbolo di previsione (spostamento); o • si rimuove dalla pila un numero di stati uguale alla lunghezza della regola riconosciuta (pop) e si mette sulla pila un nuovo stato (riduzione). pila parte analizzata parte non analizzata
Esempio: espressioni aritmetiche 0 AE$ 1 EE +T 2 ET 3 TT *F 4 TF 5 F (E ) 6 F n FIRST: A E T F ( n NEXT: F T E $ + * ) Calcolo degli stati: regole marcate (items); Lo stato iniziale contiene la produzione aumentata con il marchio in posizione iniziale; Se uno stato contiene l'item xu •yv, contiene anche tutti gli items y •w (chiusura di un item) ; Se uno stato contiene l'item xu •yv, c'è una transizione con il simbolo y sullo stato che contiene xuy •v.
stato 0 stato 1 $ ACCETTATA A •E$ E •E +T E •T T •T *F T •F F •(E ) F •n E AE •$ EE • +T stato 9 stato 6 T + EE +T • TT • *F EE +•T T •T *F T •F F •( E ) F •n stato 2 F 3 7 T ET • TT • *F * ( 4 n * 5 F stato 3 stato 10 stato 7 F n TF • TT *F • TT * •F F •(E ) F •n ( ( stato 5 stato 4 4 n F n • F (•E ) E •E +T E •T T •T *F T •F F •(E ) F •n 5 stato 11 stato 8 ) E F (E )• n F (E •) EE • +T + 6 T 2 ( F 3 Automa costruito dalla grammatica precedente
Fonzionamento del automa: All'inizio, la pila contiene lo stato 0. Si legge il simbolo seguente del testo da analizzare; l'ultimo stato sulla pila e questo simbolo indicano al automa il numero dello stato da mettere sulla pila (spostamento). Quando uno stato contiene un item di tipo xu •, si possono rimuovere dalla pila gli ultimi |u| stati; si legge il nuovo stato sulla pila; questo, con x, indica al automa un nuovo stato, che si sostituisce sulla pila a quelli rimossi (riduzione). In certi casi, più di una possibilità esiste: si dice che c'è un conflitto spostamento-riduzione o riduzione–riduzione; Il caso più generale è quando lo stesso stato contiene xu •, yv •, z r •st, dove s è un simbolo terminale. Il conflitto può essere tolto se NEXT(x), NEXT(y) e {s} sono disgiunti. Se è il caso, si dice che la grammatica è SLR(1).
La sequenza delle reduzioni costituisce una derivazione della parola da analizzare, a partire dalla fine, dalla destra verso la sinistra. Esempio: L'unico conflitto si trova nello stato 9. È tolto dal esame di NEXT(E). Tabella di analisi SLR(1) delle espressioni aritmetiche
pila 0 2 7 0 2 7 5 0 2 7 10 0 2 0 1 parte non analizzata 4 $ $ $ $ $ regola F n TT *F ET ACCET. Esempio: (3 + 2) * 4 $ pila 0 0 4 0 4 5 0 4 3 0 4 2 0 4 8 0 4 8 6 0 4 8 6 5 0 4 8 6 3 0 4 8 6 9 0 4 8 0 4 8 11 0 3 0 2 parte non analizzata (3 + 2) * 4 $ 3 + 2) * 4 $ + 2) * 4 $ + 2) * 4 $ + 2) * 4 $ + 2) * 4 $ 2) * 4 $ ) * 4 $ ) * 4 $ ) * 4 $ ) * 4 $ * 4 $ * 4 $ * 4 $ regola F n TF ET F n TF EE +T F (E ) TF Derivazione ottenuta: ET T *F T * 4 F * 4 (E) * 4 (E + T) * 4 (E + F) * 4 (E + 2) * 4 (T + 2) * 4 (F + 2) * 4 (3+ 2) * 4
Certe volte, i conflitti non possono essere tolti dall'esame degli insiemi NEXT. Si può allora tenere conto dei caratteri che possono seguire una variabile durante la costruzione. Se l’automa costruito così non ha più conflitti, si dice che la grammatica è LR(1). Maggiore problema: il numero degli stati può diventare troppo grande. Compromesso: sull'automa simplice costruito precedentemente, si può definire dinamicamente l'insieme dei caratteri che possono seguire una variabile. Nei casi di reduzioni, questi insiemi si sostituiscono agli insiemi NEXT del caso SLR(1). Se allora i conflitti sono tolti, si dice che la grammatica è LALR(1). Questo metodo è usato da YACC. LR(1) LALR(1) SLR(1)
Regola di propagazione della previsione: item x u •yv (z) da per chiusura y •w (FIRST(vz)) per transizione x uy •v (z) Si costruisce il grafo di dipendenza degli items. I caratteri di previsione ammissibili sono calcolati seguendo quel grafo. stato 0 A •E$ () E •E +T ($, +) E •T ($, +) T •T *F ($, +, *) T •F ($, +, *) F •(E ) ($, +, *) F •n ($, +, *) stato 2 T ET • ($, +) TT • *F ($, +, *) conflitto tolto Per questa grammatica, stesso risultato con LALR(1) o con SLR(1).
Uso dell'ambiguità: 0 AE$ 1 EE +E 2 EE *E 3 E (E ) 4 E n Grammatica ambigua per espressioni aritmetiche NEXT(E ) = {$, +, *, )} L'ambiguità impedisce un'analisi sia discendente che ascendente. Le tecniche precedenti non possono togliere i conflitti.
stato 0 stato 1 stato 6 $ ACCETTATA + A •E$ E •E +E E •E *E E •(E ) E •n E AE •$ EE •+E EE •*E EE +E • EE •+E EE •*E 3 stato 3 + E * 4 EE + •E E •E +E E •E *E E •(E ) E •n ( stato 2 ( 2 * n E (•E ) E •E +E E •E *E E •(E ) E •n 9 n ( stato 7 stato 4 E stato 9 EE *E • EE •+E EE •*E + EE * •E E •E +E E •E *E E •(E ) E •n 3 E n • * n 4 E ( 2 n 9 stato 8 stato 5 ) E (E ) • E (E •) EE •+E EE •*E + 3 * 4
Conflitti spostamento-riduzione stato 6 Con $, ), niente conflitto, si riduce Con +, si riduce poichè + associativo a sinistra Con *, si sposta poichè * ha precedenza su + EE +E • EE •+E EE •*E stato 7 Con $, ), niente conflitto, si riduce Con +, si riduce poichè * ha precedenza su + Con *, si riduce poichè * associativo a sinistra EE *E • EE •+E EE •*E Regole di precedenza per togliere i conflitti spostamento-riduzione Se conflitto tra xu op1y • e xu •op2y 1) op1 ha precedenza su op2, si riduce; 2) op2 ha precedenza su op1, si sposta; 3) op1 e op2 hanno stessa precedenza: 3.1) associatività a sinistra, si riduce; 3.2) associatività a destra, si sposta; 3.3) niente associatività, segnalare un errore.
Gestione degli errori: Grammatica ambigua precedente Esempi di correzione possibile. Correzioni in corsivo Azioni correttrici: 1 Inserire un n fittivo (e dunque porre 9 sulla pila) e segnalare "missing number" 2 Togliere ) dal testo e segnalare "extra closing parenthesis" 3 Inserire un +fittivo (e dunque porre 3 sulla pila) e segnalare "missing operator" 4 Inserire un )fittivo (e dunque porre 8 sulla pila) e segnalare "missing closing parenthesis".