Ho letto diversi articoli, articoli e la sezione 4.1.4, capitolo 4 di Compilatori: Principi, tecniche e strumenti (2a edizione) (alias "The Dragon Book") che discutono tutti dell'argomento del recupero sintattico degli errori del compilatore. Tuttavia, dopo aver sperimentato diversi compilatori moderni, ho visto che si riprendono anche da errori semantici e da errori sintattici.
Comprendo abbastanza bene gli algoritmi e le tecniche alla base dei compilatori che si stanno riprendendo da errori sintatticamente correlati, tuttavia non capisco esattamente come un compilatore possa recuperare da un errore semantico.
Attualmente sto usando una leggera variazione del modello visitatore per generare codice dal mio albero di sintassi astratto. Considera il mio compilatore compilando le seguenti espressioni:
1 / (2 * (3 + "4"))
Il compilatore genererebbe il seguente albero di sintassi astratto:
op(/)
|
-------
/ \
int(1) op(*)
|
-------
/ \
int(2) op(+)
|
-------
/ \
int(3) str(4)
La fase di generazione del codice utilizza quindi il modello visitatore per attraversare ricorsivamente l'albero di sintassi astratto ed eseguire il controllo del tipo. L'albero di sintassi astratto verrebbe attraversato fino a quando il compilatore non arrivasse alla parte più interna dell'espressione; (3 + "4")
. Il compilatore quindi controlla ogni lato delle espressioni e vede che non sono semanticamente equivalenti. Il compilatore genera un errore di tipo. Qui è dove si trova il problema. Cosa dovrebbe fare ora il compilatore ?
Affinché il compilatore si riprenda da questo errore e continui il controllo del tipo controllando le parti esterne delle espressioni, dovrebbe restituire un tipo ( int
o str
) dalla valutazione della parte più interna dell'espressione alla successiva parte più interna dell'espressione. Ma semplicemente non ha un tipo da restituire . Poiché si è verificato un errore di tipo, non è stato dedotto alcun tipo.
Una possibile soluzione che ho postulato è che se si verifica un errore di tipo, dovrebbe essere generato un errore e un valore speciale che indica che si è verificato un errore di tipo dovrebbe essere restituito alle precedenti chiamate di attraversamento dell'albero di sintassi astratte. Se le chiamate di attraversamento precedenti incontrano questo valore, sanno che si è verificato un errore di tipo più profondo nella struttura della sintassi astratta e dovrebbero evitare di provare a dedurne un tipo. Mentre questo metodo sembra funzionare, sembra essere molto inefficiente. Se la parte più interna di un'espressione è in profondità nell'albero della sintassi astratta, il compilatore dovrà effettuare molte chiamate ricorsive solo per rendersi conto che non è possibile eseguire alcun lavoro reale e tornare semplicemente da ognuna.
È usato il metodo che ho descritto sopra (ne dubito). In tal caso, non è efficace? In caso contrario, quali sono esattamente i metodi utilizzati quando i compilatori si riprendono da errori semantici?