Atributos y definiciones dirigidas por la sintaxis

Document Sample
Atributos y definiciones dirigidas por la sintaxis Powered By Docstoc
					Atributos y definiciones
dirigidas por la sintaxis
         Clase 15
               Introducción
• El ejemplo del verificador de tipos anterior,
  calcula los atributos de los símbolos de la
  gramática realizando un recorrido en
  profundidad del árbol.
   – Por lo tanto, puede ser realizado, durante la fase
     sintáctica.
   – Sin tener que construir el árbol primero
   – O en una pasada en un recorrido del AST
• La clase de definiciones dirigidas por la
  sintaxis para las cuales esto puede hacerse
  se llaman: definiciones de L-atributos
   – (No todas pueden realizarse de esa forma … )
         Tipos de atributos
• Tenemos producciones de la forma:
  A X1X2X3 … Xn
• Con reglas semánticas de la forma:
  b:=f(c1,c2,c3, …, cn)
• Donde b y las c´s son atributos de los
  símbolos gramaticales
• b se conoce como un atributo sintetizado si:
  – b es un atributo de A (i.e. de la parte izquierda)
  – Las c´s son todos atributos de las X´s (símbolos
    de la derecha).
         Atributos Sintetizados
b:=f(c1,c2,c3)




             La información para calcular b
             Se pasa a la parte superior del árbol
      Atributos heredados
  A X1X2X3 … Xn
  b:=f(c1,c2,c3, …, cn)
• b es un atributo heredado si
  – b es un atributo de uno de los X´s (i.e. de la parte
    derecha)
  – Y los c´s son atributos de A y/o uno o más de los
    otros X´s
  – Lo que significa que están al lado o arriba de
    donde se necesita b.
           Atributos heredados
b:=f(c1,c2,c3)




            La información para calcular b debe pasarse
            hacía la parte de abajo del árbol de derivación

 Note que X2 solo se asocia con X1 y X3 vía sus apariciones
 en la parte derecha de una producción para A
   La información debe fluir a través de A en el árbol.
   Definición de S-atributos
• Una definición definida por la sintaxis es de S-
  atributos si
   – Solo utiliza atributos sintetizados
• Lo que implica que la definición puede ser anotada
  evaluando reglas semánticas para los nodos de
  forma ascendente
   – Los cuales encajan naturalmente con un árbol ascendente
   – Y pueden ser evaluados con analizadores descendentes.
   – Ya que ambos tipos realizan un recorrido primero en
     profundidad
• Pero la presencia de atributos heredados tiene un
  problema.
      Ejemplo de atributos
          heredados
• Una definición para declaraciones al estilo de
  C
Atributos heredados en
  declaraciones de C
     Cálculo de atributos
   heredados y sintetizados
• Atributos sintetizados
   – Encajan naturalmente con el análisis ascendente
      • Yacc $$ = $1 + $3
   – Puede utilizar valores de regreso de las funciones del
     análisis sintáctico.
• Atributos heredados
   – Naturales para análisis descendente
      • Recursivo descendente: parámetros en el análisis
        sintáctico de llamadas a funciones
   – Problemático para analizadores ascendentes.
       • Especialmente al tratar de obtener el atributo de la parte
         izquierda.
       • Algunas veces se puede realizar con acciones adicionales.
       • Pero usualmente se maneja con un recorrido posterior del
         árbol.
    Definición de L-atributos
• Una definición dirigida por la sintaxis tiene L-
  atributos si cada atributo heredado de algún
  símbolo Xi en la parte derecha de alguna
  producción A X1Xi-1Xi … Xn
    – Depende solo de los atributos de A (la parte
      izquierda) y
    – de los atributos de los símbolos X1…Xi-1 a la
      izquierda del símbolo Xi en la producción
•    Esto implica que la definición se puede
    anotar evaluando reglas semánticas para
    recorrer los nodos primero en profundidad y
    de izquierda a derecha.
 Evaluación de definiciones
       de L-atributos
• Una definición de L-atributos se puede
  evaluar mediante un recorrido del árbol
  primero en profundidad.
  procedure dfvisit(n:node)
  begin
   for cada hijo m de n, de izquierda a derecha do
  begin
     evaluar atributos heredado de m;
     dfvisit(m)
  end
  evaluar atributos sintetizados de n
  end
 Evaluación de definiciones
       de L-atributos
• Lo cual significa que puede ser
  evaluado mientras se realiza el análisis
  sintáctico.

• Note que cada definición de S-atributos
  es también un L-atributo.
  Esquema de traslación
• Una GLC con atributos asociada con
    símbolos gramaticales y acciones
 semánticas encerradas en corchetes { }
  incrustada dentro de la parte derecha
    para indicar el momento en que la
 acción debe ser ejecutado para evaluar
              sus atributos.
    Esquema de traslación
• Una acción puede ser ejecutada solo si todos
  los atributos a los que se refiere hayan sido
  ya evaluados.
• Para un atributo sintetizado
  – La acción puede ponerse al final de la producción
• Para un atributo heredado:
  – Un atributo heredado para un símbolo en la parte
    derecha debe ser evaluado en la acción antes que
    el símbolo (y entonces pasado hacía abajo), y
  – Una acción no se puede referir a un atributo
    sintetizado a la derecha de la acción.
Declaraciones estilo Pascal
• El ejemplo de declaraciones en ¨C¨ fue de L-
  atributos … pero la siguiente gramática no lo
  es:
  D        var id IDLIST : T
  IDLIST   , id IDLIST
            
  T  integer  real
• (El símbolo T esta a la derecha de IDLIST en
  la primera producción, así que el tipo no
  puede pasarse hacía abajo del árbol durante
  el recorrido de izquierda a derecha)
Reescribir la gramática para
   facilitar su traslación
• La gramática de declaraciones de Pascal
  puede reescribirse para permitir el uso de
  sólo atributos sintetizados:

D  var id LIS    {settype(id.entry, LIS.type)}
LIS  , id LIS1   {settype(id.entry, LIS1.type)
                  LIS.type =T.type}
          :T     {Lis.type=T.type}
T    integer     {T.type=INTEGER}
       real      {T.type=FLOAT}
Evaluación de atributos con
    la nueva gramática
Tabla de símbolos y árbol
  sintáctico abstracto
        Tabla de símbolos
• Las tablas de símbolos pueden tener varias
  formas.
• Ya hemos visto como se usa en forma de una
  lista ligada con el verificador de tipos.
• Para un lenguaje como Java se tienen varias
  tablas como:
  – Una lista ligada de descriptores de CLASS
  – Para cada CLASS, una lista ligada de
    descriptores de Métodos y Campos.
  – Para cada método, una lista de parámetros
    formales, variables locales y un apuntador a una
    estructura del AST para el código actual.
  Estructura del árbol como
  representación de código
         intermedio
• Los compiladores de producción construyen alguna
  forma de código intermedio durante el análisis
  sintáctico, posponiendo la generación del código
  objetivo hasta que se realice la fase de optimización.
   – El lenguaje intermedio generalmente es independiente del
     lenguaje de las máquinas reales.
   – Una forma común de código intermedio es una estructura de
     árbol.
• Esto separa de manera clara el front end (análisis del
  lenguaje fuente) del back end (generación de código
  para una máquina específica)
     Árbol Sintáctico y AST
• El árbol sintáctico
  pudiera ser una
  forma intermedia,
  pero es incómodo




                        • Sólo 3 operaciones
                          para 7 nodos interiores!
  Árbol sintáctico abstracto
• El AST elimina los
  nodos irrelevantes y
  captura el
  significado en una
  forma mínima


                         • Sólo 3 nodos
                           interiores
 Esquema de traslación para
           AST




El AST es una representación conveniente
para optimización en máquinas
independientes.
Genera código objetivo posteriormente vía
un recorrido post orden del árbol
  Árbol sintáctico abstracto
• El AST es una simplificación del árbol de análisis
  sintáctico, que contiene únicamente información
  relevante.
• La tabla de símbolos es otra forma de AST, ya que
  contiene la información relevante acerca de clases,
  atributos y métodos, ignorando los detalles
  sintácticos de cómo se declaran.
   – Usualmente contiene otros campos que no necesariamente
     se llenan en la fase sintáctica.
• Los AST se construyen de forma directa.
  Expresión de árbol (AST)
• (Los ejemplos se basan en un AST para un
  verificador de tipos )

  – Caso de operadores binarios
  struct AST {    int opr;
                  struct AST *left;
                  struct AST *right;
                  }
  – Un operador y apuntadores a los nodos del AST
    para los operandos de la izquierda y derecha
 Creación de un nodo en el
           AST
exp: exp ´+´ exp {$$=make_binary(´+´, $1,
  $3)}

• … con acciones semánticas similares para
  diferentes estructuras.
• Se pasa el apuntador hacía arriba del árbol
  vía $$, así que cuando la reducción final al
  símbolo inicial ocurra, se obtiene un
  apuntador a la raíz del árbol completo.
 Tipos de nodos del AST (1)
• Se tienen diferentes operadores
  (binarios, unarios …) y diferentes
  estructuras en el lenguaje (if, while …)
  así que se necesitan diferentes clases
  de nodos.
• Podemos crear una estructura de datos
  única para cada tipo de nodo.
  – Esto conduciría a un gran número de
    estructuras de datos únicas
 Tipos de nodos del AST (1)
• Así que utilizamos una estructura de
  propósito general con variantes.
  – Si se tienen un lenguaje orientado a
    objetos, podemos utilizar subclases de un
    nodo genérico llamado class
  – En C, tenemos que usar una estructura de
    propósito general, tal vez utilizando una
    unión para tratar con casos especiales.
Nodos del AST de propósito
         general
             • Ejemplo:
             Si tenemos un apuntador
                a para un AST y
                conocemos que el
                nodekind es
                binary_exp, podemos
                referirnos al operando
                de la izquierda como
                a->[0] y al de la derecha
                como a->[1] y el
                operador sería
                    a->attr.op
  Creación de un nodo




Uno de estos para cada subtipo del AST
        Verificación de tipos
         recorriendo el AST
•    Este verificador es de dos pasadas
    1. Primero construye el árbol sintáctico y construye
       un AST y la tabla de símbolos en esta pasada
    2. Posteriormente, recorre el AST recursivamente
       calculando los tipos de las expresiones y
       verificando las reglas semánticas.
–    El AST es un nodo ¨prog¨ con un ¨block¨
     (lista ligada con nodeos sentencias de
     asignación) como un hijo del nodo.
–    (Ver el capítulo de análisis semántico para
     un método alternativo)
Código de ejemplo para el
   nuevo verificador




Note el uso de dos variables globales ast_root y Symtab
Producciones de
  expresiones
Recorrido del árbol para las
  reglas de verificación
La función main …
Demo del verificador

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:30
posted:6/14/2012
language:Spanish
pages:37