Skip to content

Especificación

Extracción de Requisitos

Dado que en esta fase se va a crear un árbol, los requisitos que la corresponden son aquellos que dicten qué elementos (nodos) debe tener un árbol y con qué otros deben conectarse. Pero, a diferencia de otras fases, éstos requisitos no se extraerán de la descripción del Lenguaje. Dado que la misión de esta fase es crear un árbol que va a ser procesado por las demás fases, son éstas las que determinarán los requisitos del AST.

Los requisitos del AST de cualquier lenguaje son:

  • Ser completo. Habrá que incluir toda información que necesiten el resto de las fases para realizar su tarea; debe preservarse la semántica del programa.
  • Ser mínimo. Deberá incluir sólo la información anterior, eliminando toda información redundante (a diferencian del árbol concreto).

El diseño de los nodos de un AST no deja de ser un ejercicio de diseño orientado a objetos en el que habrá que identificar las clases (nodos) y las relaciones (hijos) que permitan un recorrido del mismo más simple y eficaz por parte del resto de las fases del compilador. Por tanto, es normal que, a medida que se vayan implementado las fases posteriores del compilador, el AST se vaya afinando para facilitar la implementación de dichas fases. No debe pretenderse realizar en este momento un diseño de nodos que vaya a ser definitivo .

Especificación con Gramática Abstracta

Dado que el objetivo de esta fase es determinar cómo serán los AST que generará el compilador, se necesita un metalenguaje que permita definir símbolos y las relaciones entre ellos. El metalenguaje que se usará para esto será las gramática abstractas. Una gramática abstracta, descrita de manera informal, es una forma de enumerar todos los nodos que pueden usarse en la construcción de un árbol.

Los nodos mínimos para representar cualquier programa en MLang son los que se describen mediante la siguiente gramática abstracta:

java
program ⟶ varDefinition* statement*

varDefinition ⟶ type string

intType:type ⟶ ε
floatType:type ⟶ ε

print:statement ⟶ expression
assignment:statement ⟶ expression expression

arithmetic:expression ⟶ expression string expression
variable:expression ⟶ string
intLiteral:expression ⟶ int
floatLiteral:expression ⟶ float

Como puede observarse, una gramática abstracta es un conjunto de reglas, cada una de las cuales describe uno de los nodos. Cada regla tiene la forma:

bnf
<nodo>: <categorias> -> <tipo hijo1> ... <tipo hijo2>;

Es decir, cada regla, además del nombre del nodo, indica si pertenece a alguna categoría (expresión, sentencia, etc.), cuántos hijos tiene y de qué tipo es cada uno. Los tipos de los hijos deberán ser símbolos de la propia gramática abstracta (nodos o categorías) o bien tipos primitivos (principalmente string).