2013-08-12 11 views
14

Ho già l'interfaccia tokenizer che crea un elenco di token. Ho il meccanismo di lavoro per il parser. È davvero unico e funziona come un fascino. L'unica cosa che mi manca è la struttura di base dell'AST. Come l'albero, i nodi e le dichiarazioni dovrebbero essere rappresentati a livello di astrazione. Non ho bisogno di alcuna implementazione solo una veloce idea di come dovrebbe essere nella gerarchia delle classi? Sto lavorando su un linguaggio orientato agli oggetti. Sì, ho già capito che avrò bisogno di due tipi di dichiarazioni. Alcuni valori che restituiscono l'istruzione di tipo "espressione" e un'istruzione di tipo di controllo del flusso di istruzioni non di ritorno. Grazie mille.Rappresentazione astratta della struttura della sintassi in C++

+0

Consiglio di esaminare il progetto CLANG/LLVM. Compilatore opensource molto solido, con molto da fare. Ti aiuterà a iniziare, e scavare attraverso il loro forum/codice fornirà una risposta migliore di chiunque altro in un post di overflow dello stack. http://clang.llvm.org/docs/InternalsManual.html – ChrisCM

+2

@ChrisCM: un problema con Clang, ciò che chiamano 'AST' è in effetti un' ABT', ovvero i * binding * (questo identificatore è stato dichiarato qui , il tipo di questa variabile è X) sono già risolti. È più semplice farlo in un algoritmo a due fasi 1/generare AST 2/risolvere i collegamenti. –

+1

Un chiarimento corretto, ma che ritengo non necessario nell'ambito del suo utilizzo come punto di partenza per la comprensione degli alberi di sintassi. I tipi di nodi di cui hai bisogno, struttura, dichiarazioni, ecc ... sono simili in entrambi gli schemi, ed è questo che l'OP è curioso. – ChrisCM

risposta

15

Se la lingua è imperativo/c-like, lo scenario comune inizia con top-gerarchia essendo diviso in 2 supertipi:

  • Espressione
  • Dichiarazione

Il programma è una lista di affermazione, che è un'affermazione stessa.

Probabilmente vorrete avere una classe per tipo di istruzione che estenda la classe base dell'istruzione.

Uno scenario tipico assomiglia:

  • blocco di istruzioni (un elenco di istruzioni)
  • ite (se poi il resto)
  • per (un'espressione per il ciclo con la sua lista dichiarazioni di inizializzazione, controllare, incrementare le istruzioni e bloccare
  • mentre (simile, ma solo controllare espressione
  • dichiarazione variabile
  • assegnazione (Compresi i + = - = ++ -, si può avvolgere tutto in una classe con un campo operatore, un lval e un rval)
  • chiamata di funzione (void uno)

Per le espressioni:

  • Bop (operazione binaria, qualsiasi cosa che abbia 2 operandi e 1 operatore cioè + - * /% | & & & || == <
  • Uop (operazione unaria, tutto ciò che ha 1 operando e 1 operatore cioè ~!)
  • chiamata di funzione (quelli non-nulli)
  • espressione condizionale (exp vero val:? Falsa val)

La cosa buona di avere queste 2 astrazioni (espressioni e dichiarazioni) è che all'interno di tutte le classi, si avranno tipi astratti e sarà possibile visitare l'AST con il modello di visitatore, ad esempio.

Per esempio, alcune classi avrebbero simile a questo (pseudocodice):

class Ite extends Statement { 
    Expression condition; 
    Statement ifBranch; 
    Statement elseBranch; 
} 


class Bop extends Expression { 
    BOperator operator; // +, -. * or whatever 
    Expression left;  // Left operand 
    Expression right; // Right operand 
} 


class StatementBlock extends Statement { 
    List<Statement> statements; 
} 


class Assignment extends Statement { 
    AOperator assignOp; // = += -= etc. 
    LVal lvalue;   // The lvalue cannot be an arbitrary expression, you will usually have a specific type for it 
    Expression rvalue; // Right value 
} 

Inoltre, avrete bisogno di qualche modo per rappresentare tipi (per l'AST, a soli tipi statici sono sufficienti, se si proietti per implementare anche alcuni back-end, avrete bisogno anche di alcuni tipi dinamici).

I tipi statici possono in genere essere specificati con alcune enumerazioni, se non si prevede di supportare matrici di dimensioni fisse che necessitano di informazioni sulle dimensioni. Se si desidera che le matrici di dimensione fissa con, dimensione, è possibile implementare una classe per tipo e il tipo di matrice contenere informazioni di dimensioni aggiuntive.

enum Type { 
    CHAR, 
    SHORT, 
    INT, 
    LONG, 
    FLOAT, 
    DOUBLE, 
    ARRAY 
} 

class Float extends StaticType { 
    final Type type = Type.FLOAT; 
} 

class Array extends StaticArray { 
    final Type type = Type.ARRAY; 

    int size; 
} 

Sarà quindi istanziare un'istanza StaticType per ogni tipo nella AST, ad esempio quando l'utente dichiara una variabile. Sarai in grado di utilizzare la stessa gerarchia anche se prevedi di eseguire controlli di tipo statici in futuro.

Per quanto riguarda l'esecuzione/interpretazione del codice nel modulo AST, sarà necessaria una memoria che contenga uno stack/heap contenente informazioni sulla memoria di runtime. A quel punto sarà necessario memorizzare i valori insieme alle informazioni sul tipo.

+0

E come dovrei sistemarli in una gerarchia ad albero? Ho bisogno di qualche tipo di classi 'AST' e 'ASTNode' per camminare attraverso l'intero albero. –

+0

Nella mia soluzione, in realtà non è necessario che tutti i nodi siano dello stesso tipo. Avrai una root che è un StatementBlock e conterrà un elenco di Statement s. Queste affermazioni conterranno la sottostruttura che la loro classe definisce. Come puoi vedere ho definito la gerarchia AST in modo ricorsivo, in modo che tu possa esplorare l'albero intero con il visitatore del modello molto semplicemente. È un approccio molto orientato agli oggetti, se preferisci non utilizzare l'ereditarietà, puoi avere tutti i nodi ASTNode con il loro tipo rappresentato da un'enumerazione invece di avere una classe diversa per ogni tipo di nodo. – Lake

+0

Il problema è che non conoscerò il tipo di derivato se ho bisogno di un tipo di Statement, per esempio. Saprò solo che non è una dichiarazione più. –

Problemi correlati