2012-03-07 9 views
5

Estoy escribiendo un intérprete C# desde cero para la experiencia de aprendizaje, y hasta ahora todo ha ido bien. Tengo un lector de C# completamente funcional que genera todo tipo de tokens para el analizador. Sé cómo voy a analizar los tokens, pero no estoy seguro de cómo debería estructurar mi AST (árbol de sintaxis abstracta).¿Cómo diseñar partes de un árbol de sintaxis abstracto?

Por ejemplo, si tengo un fragmento de código simple:

using System.Xml; 

lo que sería el árbol verá como cuando analizado?

como esta?

UsingDirective 
    Identifier(System) 
     Identifier(Xml) 

o ¿como?

UsingDirective 
    Identifier(System) 
    Identifier(Xml) 

Si pudiera conseguir algunas sugerencias y/o ejemplos en cuanto a cómo podría estructurar cosas como identificadores con los puntos en ellos, si/else if/else, declaración de variables/asignación combinados en una declaración (int i = 0;), definiciones de funciones, etc. que serían útiles. Solo necesito tener una mejor idea de cómo estructurar el árbol y puedo descubrir el resto yo mismo. Gracias.

+0

Esa va a ser una larga experiencia de aprendizaje, si quieres implementar todo C# :-) – svick

+0

Bueno, estoy dejando de lado la mayoría de la biblioteca de clases. Básicamente estoy implementando lo que necesita implementarse para definiciones básicas de clase/función, creación/uso de variables y llamadas a funciones. –

Respuesta

2

He escrito un par de analizadores en el pasado, y por lo general me quedo con algo como esto:

UsingDirective 
    IdentifierList 
    Identifier (LeftNode) (System) 
    Identifier (RightNode) (Xml) 

En el caso de esta using System.Collections.Generic

UsingDirective 
    IdentifierList 
     IdentifierList (LeftNode) 
      Identifier (LeftNode) (System) 
      Identifier (RightNode) (Collections) 
     Identifier (RightNode) (Generic) 

A diferencia de Roslyn, prefiero manteniendo mis ASTs livianos al no incluir tokens como el punto y coma, la palabra clave using, etc. ya que el compilador no los necesita.

Los analizadores escritos específicamente para IDE tienen un aspecto diferente: llevan todo este material adicional junto con más información, como los números de línea y columna.

+0

¿Por qué hiciste que tu 'IdentifierList' tenga solo dos hijos? ¿Por qué no tener una sola 'IdentifierList' con tantos hijos como sea necesario? – svick

+0

Sí, creo que una sola IdentifierList con hijos ilimitados sería mejor. En cualquier caso, gracias por tu respuesta xbonez. –

+0

Estoy seguro de que funcionaría también. Personalmente, me resulta más fácil recorrerlo de esta manera (recursivamente) que si fuera solo una lista de identificadores. Configuraría una función 'traverIdentList':' if (identlist.leftnode es identlistnode) {traverseIdentList (leftnode); } else {traverseident (leftnode); } traverseident (rightnode); ' – xbonez

2

Puede ver cómo Microsoft está haciendo esto con Roslyn. Podrías ver cómo declararon los árboles de sintaxis para C# (y VB.NET) y tal vez incluso podrías usarlo en lugar de partes de tu intérprete antes de escribirlas.

Específicamente, Roslyn árbol de sintaxis para su directiva using se ve así:

UsingDirective 
    UsingKeyword 
    QualifiedName 
     IdentifierName (System) 
     DotToken 
     IdentifierName (Xml) 
    SemicolonToken 

Por lo tanto, similar a su segunda versión, pero más detallada.

Creo que su primera versión no tiene mucho sentido. Xml no es un hijo de System en el nivel sintáctico (aunque es posible que tenga un concepto de "espacio de nombres padre" más adelante en el nivel semántico).

+0

Pero eso no es un árbol de sintaxis abstracta, es un árbol de sintaxis concreto, ya que incluye partes del código fuente como el punto y el punto y coma. –

+0

Sí, tienes razón. Pero creo que podrías basar tu AST en esto. – svick

+0

¡Sip, gracias por su respuesta! Eso ayudo. –

Cuestiones relacionadas