2010-07-21 14 views
7

Ciao a tutti Attualmente sto implementando un semplice linguaggio di programmazione per l'esperienza di apprendimento ma ho bisogno di qualche consiglio. Attualmente sto progettando il mio interprete e ho avuto un problema.Implementazione di una macchina virtuale basata su stack per un sottoinsieme di C

La mia lingua è un sottoinsieme di C e sto riscontrando un problema relativo all'implementazione dello stack stack. Nel linguaggio del seguente compilerà:

somefunc() 
{ 
    1 + 2; 
} 

main() 
{ 
    somefunc(); 
} 

Ora, questo va bene, ma quando "1 + 2" viene calcolato il risultato è spinto su una pila e quindi la funzione ritorna, ma c'è ancora un numero sullo stack, e non dovrebbe esserci. Come posso aggirare questo problema?

Ho pensato di salvare uno "stato" dello stack prima di una chiamata di funzione e di ripristinare lo "stato" dopo la chiamata di funzione. Ad esempio, salvando il numero di elementi sullo stack, quindi esegui il codice funzione, restituisci e poi fai un pop dallo stack finché non abbiamo lo stesso numero di elementi di prima (o forse +1 se la funzione ha restituito qualcosa).

Qualche idea? Grazie per eventuali suggerimenti!

risposta

8

Ottima domanda! Uno dei miei hobby è scrivere compilatori per linguaggi giocattolo, quindi complimenti per il tuo eccellente gusto di programmazione.

Una dichiarazione di espressione è quella in cui il codice nell'istruzione è semplicemente un'espressione. Questo significa qualsiasi cosa del formato <expression> ;, che include cose come assegnazioni e chiamate di funzione, ma non if s, while s o return s. Qualsiasi istruzione di espressione avrà un valore residuo in pila alla fine, che dovresti scartare.

1 + 2 è un'istruzione di espressione, ma lo sono anche questi:

  • x = 5;
    L'assegnazione espressione lascia il valore 5 sullo stack in quanto il risultato di una cessione è il valore della sinistra operando a mano. Dopo la dichiarazione è finito si pop off il valore inutilizzato 5.

  • printf("hello world!\n");
    printf() restituisce il numero di caratteri di output. Avrai questo valore rimasto in pila, quindi aprilo quando l'istruzione finisce.

efficacemente ogni affermazione espressione lascerà un valore sullo stack a meno che il tipo di espressione è void. In tal caso, si ottengono le dichiarazioni void per il caso speciale e non si esegue alcun pop-up successivo o si spinge un valore "vuoto" nella pila in modo da poter sempre inserire un valore.

+0

È divertente che tu lo chiami perché nella mia rappresentazione AST ho un nodo chiamato "ASTStmtExpr" solo per questo! Penso che sto iniziando a capire, una specie di ... Ecco di cosa non sono sicuro: A causa delle limitazioni di queste risposte di commento ho incollare uno snipplet: \t vuoto Compiler :: visita (const ASTStmtExpr & expr_stmt, std :: shared_ptr func) \t \t { \t \t \t expr_stmt.expr() -> accettare (* questo, func); \t \t} Stai dicendo che dovrei aggiungere un OP_POP dopo questo, e per cose come i compiti spingerei un oggetto "Nil" fittizio in modo che venisse fatto scoppiare? –

+0

Mi spiace non sapevo che i commenti non sono formattati –

+1

Per gli incarichi no, non si preme un valore fittizio, perché si avrà già il risultato del compito sullo stack. Un assegnamento è solo un'espressione usando l'operatore '=', che non è diverso da '+' o '-', tranne' = 'ha un effetto collaterale di assegnazione a una variabile. Altrimenti si comporta come tutti gli altri operatori. –

2

Avrai bisogno di un parser più intelligente. Quando vedi un'espressione il cui valore non è in uso, devi emettere un POP.

+0

Ciao, grazie per la risposta. Sono ancora nelle fasi iniziali dei compilatori di codice e ho pensato di fare un'ottimizzazione come questa, ma non sono riuscito a trovare una soluzione fattibile :(Forse ci riproverò, ancora grazie !! –

0

Questa è un'importante opportunità per l'ottimizzazione dell'apprendimento. si dispone di una funzione che esegue numeri interi ma matematici, il risultato matematico int non viene nemmeno utilizzato in alcun modo, forma o forma.

Far sì che il compilatore ottimizzi la funzione in modo da ridurre un sacco di bytecode generato ed eseguito per nulla!

Problemi correlati