Domanda

Nella mia lingua posso utilizzare una variabile di classe nel mio metodo quando la definizione appare sotto il metodo.Può anche chiamare metodi sotto il mio metodo e così via.Non ci sono "intestazioni".Prendi questo esempio in C#.

class A
{
    public void callMethods() { print(); B b; b.notYetSeen();
    public void print() { Console.Write("v = {0}", v); }
    int v=9;
}

class B
{
    public void notYetSeen() { Console.Write("notYetSeen()\n"); }
}

Come dovrei compilarlo?quello che stavo pensando è:

  • passaggio1:convertire tutto in un AST
  • passaggio2:passare attraverso tutte le classi e creare un elenco di classi/variabili/ecc. definite
  • passaggio3:esamina il codice e controlla se sono presenti errori come variabile non definita, uso errato ecc. e crea il mio output

Ma sembra che affinché funzioni devo eseguire i passaggi 1 e 2 per TUTTI i file prima di eseguire il passaggio 3.Inoltre mi sembra molto lavoro da fare finché non trovo un errore di sintassi (a parte l'ovvio che può essere fatto in fase di analisi, come dimenticare di chiudere una graffa o scrivere 0xLETTERS invece di un valore esadecimale).Il mio istinto dice che c'è un altro modo.

Nota:Sto usando bison/flex per generare il mio compilatore.

È stato utile?

Soluzione

La mia comprensione dei linguaggi che gestiscono i riferimenti futuri è che in genere usano solo il primo passaggio per creare un elenco di nomi validi.Qualcosa sulla falsariga di inserire semplicemente una voce in una tabella (senza compilare la definizione) in modo da avere qualcosa a cui puntare in seguito quando si esegue il passaggio reale per generare le definizioni.

Se provi a creare effettivamente definizioni complete mentre procedi, finirai per dover ripetere la scansione ripetutamente, salvando ogni volta qualsiasi riferimento a cose non definite fino al passaggio successivo.Anche questo fallirebbe se ci fossero riferimenti circolari.

Altri suggerimenti

Vorrei eseguire il primo passaggio e raccogliere tutti i nomi e i tipi di classe/metodo/campo, ignorando i corpi del metodo.Quindi nel passaggio due controlla solo i corpi del metodo.

Non so se ci possa essere altro modo che attraversare tutti i file nell'origine.

Penso che tu possa ridurlo a due passaggi: al primo passaggio, crea l'AST e ogni volta che trovi un nome di variabile, aggiungilo a un elenco che contiene i simboli di quel blocco (probabilmente sarebbe utile aggiungere quell'elenco a l'ambito corrispondente nell'albero).Il secondo passaggio consiste nell'attraversare linearmente l'albero e assicurarsi che ogni simbolo utilizzato faccia riferimento a un simbolo in quell'ambito o a un ambito sopra di esso.

La mia descrizione è eccessivamente semplificata, ma la risposta di base è: lookahead richiede almeno due passaggi.

L'approccio abituale è quello di risparmiare B come "sconosciuto".Probabilmente è una specie di tipo (a causa del luogo in cui l'hai incontrato).Quindi puoi semplicemente riservargli la memoria (un puntatore) anche se non hai idea di cosa sia realmente.

Per la chiamata al metodo, non puoi fare molto.In un linguaggio dinamico, dovresti semplicemente salvare il nome del metodo da qualche parte e verificare se esiste in fase di esecuzione.In un linguaggio statico, puoi salvarlo in "metodi sconosciuti" da qualche parte nel compilatore insieme al tipo sconosciuto B.Poiché le chiamate ai metodi alla fine si traducono in un indirizzo di memoria, è possibile riservare nuovamente la memoria.

Poi, quando incontri B e il metodo, puoi chiarire le tue incognite.Poiché li conosci un po', puoi dire se si comportano come dovrebbero o se il primo utilizzo ora è un errore di sintassi.

Quindi non devi leggere tutti i file due volte ma sicuramente rende le cose più semplici.

In alternativa, puoi generare questi file di intestazione quando incontri le fonti e salvarli da qualche parte dove puoi ritrovarli.In questo modo puoi velocizzare la compilazione (poiché non dovrai considerare i file non modificati nella successiva compilazione).

Infine, se scrivi una nuova lingua, non dovresti più usare bison e flex.Ormai ci sono strumenti molto migliori. ANTLR, ad esempio, può produrre un parser in grado di ripristinarsi dopo un errore, in modo da poter ancora analizzare l'intero file.Oppure controlla questo articolo di Wikipedia per ulteriori opzioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top