Procesadores de Lenguajes Ingeniería Técnica superior de Ingeniería Informática Departamento de Lenguajes y Sistemas inf
Views 79 Downloads 0 File size 517KB
Procesadores de Lenguajes Ingeniería Técnica superior de Ingeniería Informática Departamento de Lenguajes y Sistemas informáticos
Generación de código intermedio I Sentencias y expresiones Javier Vélez Reyes [email protected] Departamento de Lenguajes Y Sistemas Informáticos UNED
Generación de código intermedio. Sentencias y expresiones Objetivos
Objetivos › Aprender en qué consiste la generación de código intermedio › Aprender qué es el código intermedio › Conocer los distintos tipos de lenguajes intermedios › Valorar la importaría de realizar una buena elección del lenguaje intermedio › Conocer cómo son los lenguajes intermedios lineales › Entender el significado de las variables temporales en el código intermedio lineal › Entender el significado de las etiquetas en el código intermedio lineal › Aprender a construir esquemas de traducción para generar código intermedio › Conocer los artefactos computacionales que son necesarios para darles soporte › Aprender a generar código intermedio para expresiones › Aprender a generar código intermedio para sentencias de control
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Índice
Índice › Introducción › Qué es el código intermedio › La fase de generación de código intermedio › El código intermedio como punto de desacoplamiento › Lenguajes intermedios › Representaciones jerárquicas de código intermedio › Representaciones lineales de código intermedio › Generación de código intermedio en la práctica › Artefactos para la generación de código intermedio › Generación de código intermedio para expresiones › Generación de código intermedio para sentencias › Desarrollo paso a paso › Bibliografía
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Introducción
¿Qué es el código intermedio? Una vez superadas todas las fases de análisis del código fuente, el compilador debe ser capaz de generar una representación simbólica del programa lo más aproximada a los potenciales lenguajes objetivos al que se va a traducir el mismo pero lo suficientemente distante de éstos como para garantizar su aplicabilidad en distintas arquitecturas físicas finales El código intermedio es una representación abstracta del programa cercana a los lenguajes objetivos potenciales pero independiente de cualquier consideración específica de una arquitectura física concreta
I. Independencia del entorno de ejecución La independencia del entorno de ejecución se refiere al hecho de que el código intermedio debe ser agnóstico del modelo de organización de memoria, el número, tipo y propósito de registros, etc. Esto implica que todas las referencias a datos en código intermedio siguen haciéndose a través de símbolos registrados o generados durante el proceso de compilación
II. Independencia del juego de instrucciones El código intermedio de un programa es una abstracción establecida a través de un compromiso de consenso entre los equipos dedicados al análisis de lenguajes y los dedicados a la síntesis. Esto significa que la colección de operadores disponibles en un código intermedio se debe mantener independiente y equidistante de cualquier lenguaje y juego de instrucciones propio de una arquitectura física real para garantizar la traducción a distintos códigos finales
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Introducción
La fase de generación de código intermedio La fase de generación de código intermedio se encarga de traducir el programa a una representación de código intermedio para que luego ésta pueda ser transformada en las fases subsiguientes a un código ejecutable en una determinada arquitectura física
S WHILE
E
DO
E > E
S
√
S
WHILE
E
DO
E > E
S
LD a t1 LD b t2 GRT t3 t1 t2 BRZ t3 L1 …
Código final
Código intermedio
e·l·i· h·w
Analizador léxico
While ( a > b ) do a := a + 1;
Analizador semántico
Etapa de síntesis
Analizador sintáctico
Etapa de análisis
0000 0011 0000 0011 0100 0001 0100 0000 0001 0010 …
› Expertos en lenguajes
› Expertos en arquitecturas
› Independencia de arquitectura
› Dependencia de arquitectura
› Dependencia de lenguaje
› Independencia de lenguaje
› Optimización de lenguajes
› Optimización de ejecución Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Introducción
El código intermedio como punto de desacoplamiento El código intermedio permite multiplexar los esfuerzos de desarrollo de los equipos de análisis de lenguajes y de síntesis de manera que se pueden crear M x N compiladores distintos a partir de M especificaciones y N traducciones a arquitecturas físicas reales While ( a > b ) do a := a + 1;
while ( a > b ) a++;
Equipo de Lenguaje
Pascal
M
C
Analizador léxico
Analizador léxico
Analizador sintáctico
Analizador sintáctico
Analizador semántico
…
Código intermedio
arquitectura
Equipo de
N
Código intermedio LD a t1 LD b t2 GRT t3 t1 t2 BRZ t3 L1 …
Código intermedio
Analizador semántico
Intel
Optimización Código intermedio Código final
…
Solaris
Optimización Código intermedio Código final
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Lenguajes intermedios
Lenguajes intermedios El primer paro para la generación de código intermedio consiste en el diseño de un lenguaje intermedio que permita representar de forma fiel y suficientemente abstracta los programas de un compilador. Existen distintas alternativas que describiremos a continuación
Lenguajes intermedios
Las representaciones jerárquicas de código intermedio reflejan los programas de un lenguaje como una estructura relacional de nodos y arcos entre nodos. Estas representaciones son aconsejables para tareas de análisis y transformación pero no para sintetizar ejecutables en una arquitectura física real
II. Representaciones lineales Las representaciones lineales de código intermedio codifican un programa como una secuencia de instrucciones de bajo nivel abstractas próximas al lenguaje ensamblador. Este tipo de lenguajes resultan más apropiados para la etapa de síntesis puesto que se encuentran más cercanas a la estructura típica los lenguajes objetivos más comunes
I.I Arboles sintácticos abstractos Son una representación similar a los árboles de análisis sintácticos donde los artefactos semánticamente superfluos se omiten y los no terminales se sustituyen por operadores
I.I Grafos dirigidos acíclicos Cuando los nodos de un árbol sintáctico abstracto son referenciados por más de un padre surgen los grafos dirigidos acíclicos
II.I Lenguajes de tercetos o tripletas En los lenguajes de tercetos cada operación tiene hasta dos operandos de entrada y uno de salida que se sobrescribe sobre alguno de los de entrada
I. Representaciones jerárquicas
Foco de atención
II.II Lenguajes de cuartetos o cuádruplas En los lenguajes de cuartetos cada operación tiene hasta 2 operandos de entrada y uno independiente de salida para el resultado
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Lenguajes intermedios
Representaciones jerárquicas Las representaciones jerárquicas describen el código fuente de un programa como una colección de nodos relacionados entre sí a través de arcos con el mismo nivel de abstracción que lo hacen los árboles de análisis sintáctico
Árboles sintácticos abstractos Los arboles sintácticos abstractos representan el código fuente de un programa de acuerdo a una estructura jerárquica de forma similar a como lo haces los árboles de análisis sintáctico. En estas representaciones no obstante se omiten todos tipo de símbolos semánticamente superfluos y se eliden los no terminales que dan información sobre el proceso de derivación gramatical Árbol de análisis sintáctico
(
E
)
E
>
E
while (a>b) do a++
› Apto para procesos de transformación › Inadecuado para la etapa de síntesis › Representación excesivamente abstracta
Código intermedio
SWhile WHILE
› Apto para análisis semántico
transformación
DO
WHILE
S
> ID
++ ID
ID
while (a>b) do a++
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Lenguajes intermedios
Representaciones jerárquicas Las representaciones jerárquicas describen el código fuente de un programa como una colección de nodos relacionados entre sí a través de arcos con el mismo nivel de abstracción que lo hacen los árboles de análisis sintáctico
Grafos dirigidos acíclicos Los arboles dirigidos acíclicos realizan una representación del código fuente en forma de grafo. El método constructivo es similar al de los árboles sintácticos con la diferencia de que aquí se reutilizan los nodos que reflejen la misma estructura én aras a resultar más eficiente su representación en memoria Árbol de análisis sintáctico
› Apto para análisis semántico › Apto para procesos de transformación › Inadecuado para la etapa de síntesis › Representación excesivamente abstracta
Código intermedio
Asignación :=
ID
E
E E
:=
*
transformación
+ E
a := b * c + b * c
ID
+
E E
*
* E
ID
ID
a := b * c + b * c
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Lenguajes intermedios
Representaciones lineales Las representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. Para articular el proceso de secuenciamiento se utilizan varios elementos como operandos de dichas instrucciones que serán utilizados en lo venidero a lo largo del tema
I. Valores literales
II. Variables
En numerosas ocasiones las operaciones de código intermedio utilizan operandos que representan valores literales enteros con o sin signo. La fase de traducción a código final se encarga posteriormente de traducir esos valores a la representación numérica correspondiente utilizada por la arquitectura
Muchos de los símbolos declarados por el programador, tales como constantes, variables globales o locales y parámetros, son referidos de forma general dentro del código intermedio como operandos de tipo ‘variable’
Los
valores
literales
utilizados
operandos en las operaciones
como de los
Las
variables
representan
las
de
código
constantes,
intermedio variables
lenguajes de código intermedio lineales
globales o locales y parámetros declarados
representan valores enteros con signo
por el programador a lo largo del código fuente
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Lenguajes intermedios
Representaciones lineales Las representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. Para articular el proceso de secuenciamiento se utilizan varios elementos como operandos de dichas instrucciones que serán utilizados en lo venidero a lo largo del tema
III. Variables temporales
IV. Etiquetas de código
El secuenciamiento de expresiones complejas requiere del almacenamiento temporal de los resultados parciales de las subexpresiones en espacios de memoria específicamente reservados para ello. Los elementos de código intermedio que se utilizan para referencias esas direcciones se llaman variables temporales
Muchas de las sentencias de un lenguaje de alto nivel (control de flujo, invocación de subprogramas, etc.) requieren insertar etiquetas en el código final para luego realizar saltos a ellas. La forma de referirse a estas etiquetas en código intermedio es mediante las etiquetas de código
Una variable temporal es la representación
Una etiqueta de código es una referencia de
simbólica en código intermedio de un
código intermedio a una zona de memoria
espacio de memoria destinado a almacenar
donde comienza cierta porción de código
un resultado parcial de alguna expresión
final
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Lenguajes intermedios
Representaciones lineales Las representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. A continuación describimos los 2 tipos de representaciones lineales
Lenguajes de tercetos Las representaciones de código intermedio basadas en tercetos están formados por una secuencia de instrucciones constituida por 3 elementos: un código de operación, un operando de entrada y otro de entrada y salida para almacenar el resultado
ADD Código de operación El código de operación es un acrónimo que representa el tipo de operación que se aplican entre los operandos del terceto
x
y
› Apto para la etapa de síntesis › Representación cercana al lenguaje objetivo › Complejidad en la traducción de construcciones Resultado En los lenguajes de tercetos uno de los operandos hace de almacén para el resultado de la operación lo que supone que el operando de entrada se pierde tras su ejecución Operandos Los operandos identifican los elementos sobre los que se efectúa la operación referida por el código de operación. Pueden ser valores literales, variables, variables temporales o etiquetas
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Lenguajes intermedios
Representaciones lineales Las representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. A continuación describimos los 2 tipos de representaciones lineales
Lenguajes de tercetos Las representaciones de código intermedio basadas en tercetos están formados por una secuencia de instrucciones constituida por 3 elementos: un código de operación, un operando de entrada y otro de entrada y salida para almacenar el resultado
› Apto para la etapa de síntesis › Representación cercana al lenguaje objetivo › Complejidad en la traducción de construcciones
Árbol de análisis sintáctico Asignación :=
ID (a) E ID (b)
a := b * c
Código intermedio E *
transformación
E ID (c)
LOAD t0 b LOAD t1 c MUL t1 t0 STORE t1 a
t0 t1 t1 t1
b c t1 * t0 a
a := b * c
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Lenguajes intermedios
Representaciones lineales Las representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. A continuación describimos los 2 tipos de representaciones lineales
Lenguajes de cuartetos Las representaciones de código intermedio basadas en cuartetos están formados por una secuencia de instrucciones constituida por 4 elementos: un código de operación, dos operando de entrada y otro de salida para almacenar el resultado
ADD Código de operación El código de operación es un acrónimo que representa el tipo de operación que se aplican entre los operandos del terceto
x
y
z
› Apto para la etapa de síntesis › Representación cercana al lenguaje objetivo › Mayor sencillez en la traducción de construcciones Resultado En los lenguajes de cuartetos el almacén para el resultado de la operación es un operando de salida independiente lo que supone que no hay perdida de información tras la ejecución de la operación Operandos Los operandos identifican los elementos sobre los que se efectúa la operación referida por el código de operación. Pueden ser valores literales, variables, variables temporales o etiquetas
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Lenguajes intermedios
Representaciones lineales Las representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. A continuación describimos los 2 tipos de representaciones lineales
Lenguajes de cuartetos Las representaciones de código intermedio basadas en cuartetos están formados por una secuencia de instrucciones constituida por 4 elementos: un código de operación, dos operando de entrada y otro de salida para almacenar el resultado
› Apto para la etapa de síntesis › Representación cercana al lenguaje objetivo › Mayor sencillez en la traducción de construcciones
Árbol de análisis sintáctico Asignación :=
ID (a) E ID (b)
a := b * c
Código intermedio E *
transformación
E ID (c)
LOAD t0 b LOAD t1 c MUL t2 t1 t0 STORE t2 a
t0 t1 t2 t2
b c t1 * t0 a
a := b * c
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Artefactos para la generación de código intermedio La generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer ScopeManager TypeTable TemporalTable
< uses
IntermediateCodeBuilder
Scope
Create >
SymbolTable
TypeIF
SymbolIF
Quadruple
OperandIF
LabelFactory TemporalFactory
Create > Create >
Label
Variable
Temporal
Value
Reference to >
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Artefactos para la generación de código intermedio La generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer
Cuádruplas Las cuádruplas son el elemento central de la arquitectura. Representan cada una de las operaciones atómicas que pueden ser referenciadas dentro del código intermedio para que surtan cierto efecto o realicen cierto cálculo a partir de los operandos
+ String getOperation () + void setOperation () + OperandIF getFirstOperand () + void setFirstOperand (OperandIF o) + OperandIF getSecondOperand () + void setSecondOperand (OperandIF o) + OperandIF getResult () + void setResult (OperandIF o)
Quadruple
Los objetos de tipo Quadruple se utilizan para representar operaciones atómicas del código intermedio. Una cuadrupla está formado por un código de operación, un operando opcional resultado y a lo sumo dos operandos de entrada también opcionales. En efecto, en función del tipo de operación el numero de operandos puede variar. Puede haber instrucciones con ningún operando ni resultado, como HALT. Puede haber otras con un sólo operando como los saltos del tipo BR L. O puede haber instrucciones con un resultado y dos operandos como en la suma ADD t3 t1 t2.
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Artefactos para la generación de código intermedio La generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer
Variables, temporales, valores y etiquetas Los operandos sobre los que operan las cuádruplas son de uno de cuatro tipos: variables, variables temporales, valores literales enteros y etiquetas. Dentro de la arquitectura existe una clase abierta para representar cada uno de estos tipos que el alumno debe carácter con atributos Variable
Label
-String name
-String name
-ScopeIF scope
-ScopeIF scope
-Boolean isGlobal
Temporal -String name
Value -Integer value
-ScopeIF scope -Integer address
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Artefactos para la generación de código intermedio La generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer
Tabla de temporales Los temporales que se van generando a medida que el compilador procesa las expresiones del lenguaje deben almacenarse en una tabla de temporales asociada a cada ámbito. Este es un aspecto importante para las fases posteriores. El artefacto TemporalTable gestiona los temporales de un ámbito
-ScopeIF scope -List temporals + ScopeIF getScope () + TemporalTable (ScopeIF scope) + List getTemporals () + void addTemporal (TemporalIF temporal) + boolean containsTemporal (TemporalIF temporal)
TemporalTable
Cada tabla de temporales se crea de forma automática asociada a un ámbito cuando este es abierto a través del gestor de ámbitos. Por tanto existe una tabla de temporales para cada ámbito. La responsabilidad de este artefacto es gestionar la colección de temporales generados durante el proceso de compilación del bloque sintáctico asociado al ámbito. Los métodos addTemporal y getTemporals sirven para registrar y tener acceso a los temporales respectivamente y son de utilidad en ésta y en las fases posteriores de generación de código final
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Artefactos para la generación de código intermedio La generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer
Factorías de etiquetas y temporales Aunque la construcción de temporales y etiquetas puede realizarse haciendo uso directo de los constructores en sendas clases, el framework proporciona dos tipos de factorías cuyo uso para construir objetos de estas clases resulta recomendable por las ventajas que ello supone
La factoría de temporales es un artefacto asociado a un ámbito pasado como argumento en el constructor que se utiliza para crear temporales. El primer método create construye un temporal con nombre propio y lo registra automáticamente en la tabla de temporales. La diferencia del segundo create, es que éste método construye el temporal con un nombre autogenerado que garantiza la unicidad dentro del ámbito
TemporalFactory
La factoría de etiquetas es un que se utiliza para crear etiquetas. El primer método create construye una etiqueta con nombre propio. La diferencia del segundo create, es que éste método construye la etiqueta con un nombre autogenerado que garantiza la unicidad
+ TemporalFactory (ScopeIF scope) + TemporalIF create (String name) + TemporalIF create ()
LabelFactory + LabelFactory (ScopeIF scope) + LabelIF create (String name) + LabelIF create ()
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Artefactos para la generación de código intermedio La generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer
IntermediateCodeBuilder La construcción de las cuádruplas que componen el código intermedio puede realizarse por invocación de sus constructores de clase. No obstante, resulta más sencillo y económico utilizar instancias de IntermediateCodeBuilder para realizar esta labor
+ void addQuadruple (String op, r) + void addQuadruple (String op, r, o1) + void addQuadruple (String op, r, o1, o2) + void addQuadruple (QuadrupleIF q) + void addQuadruples (List code) + List create ()
IntermediateCodeBuilder
Las operaciones addQuadruple se encargan de insertar un nuevo cuarteto dentro de la lista interna de código intermedio. Sin embargo su semántica depende del tipo y formato de los operandos › Si es de tipo OperandIF se inserta tal cual › Si es de tipo int se crea un Value y se inserta
› Si es de tipo String Primero se instancia el code builder pasándole como argumento de constructo el ámbito. Después se utilizan los métodos addQuadruple para ir acumulando cuartetos internamente. Al finalizar la acción semántica el código se obtiene invocando el método create ()
› Si comienza por “L_” se crea Label y se inserta › Si comienza por “T_” se crea Temporal y se inserta › Sino se busca en TS’s, se crea Variable y se inserta
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Diseño del lenguaje intermedio Antes de proceder con la generación de código intermedio es necesario determinar el juego de instrucciones (cuartetos) que será empleado. Estudie para ello el/los lenguajes objetivos finales Cuarteto
Descripción
NOP
Cuarteto
Nada
NOT
x
y
Descripción x := !y
ADD
x
y
z
x := y + z
BR
L
SUB
x
y
z
x := y – z
BRT
x
L
Si x, salto a L
MUL
x
y
z
x := y * z
BRF
x
L
Si !x, salto a L
DIV
x
y
z
x := y / z
INL
L
MOD
x
y
z
x := y % z
MV
x
y
x
:= y
INC
x
y
x := y + 1
MVP
x
y
x
:= *y
DEC
x
y
x := y – 1
MVA
x
y
x
:= &y
NEG
x
y
x := – y
STP
x
y
*x := y
GR
x
y
z
x := (y > z)
STA
x
y
&x := y
EQ
x
y
z
x := (y == z) ? 1 : 0
PUSH
x
*SP := x ; SP++
LS
x
y
z
x := (y < z)
POP
x
x := *SP ; SP --
AND
x
y
z
x := y && z
CALL f
Llamada a función f
OR
x
y
z
x := y || z
RET x
Retorno de f con valor x
XOR
x
y
z
x := y ^ z
HALT
Stop
? 1 : 0 ? 1 : 0
Salto a L
Insertar L:
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Generación de código intermedio en Cup Una vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup
Expresiones
exp ::= exp:e1 MENOS exp:e2
{: ... :}
Exp e = new Exp();
exp ::= exp:e1 POR exp:e2
{: ... :}
...
ScopeIF scope = scopeManager.getCurrentScope();
exp ::= exp:e1 AND exp:e2
{: ... :}
TemporalFactory tF = new TemporalFactory (scope);
exp ::= exp:e1 OR
{: ... :}
IntermediateCodeBuilder cb = new …Builder (scope)
exp ::= NOT exp:e1 {: ...
exp ::= exp:e1 MAS exp:e2 {:
:}
Expresiones
exp:e2
TemporalIF temp1 = e1.getTemporal ();
ScopeIF scope = scopeManager.getCurrentScope();
TemporalIF temp2 = e2.getTemporal ();
TemporalFactory tF = new TemporalFactory (scope);
TemporalIF temp = tF.create ();
IntermediateCodeBuilder cb = new …Builder (scope)
cb.addQuadruples (e1.getCode ());
TemporalIF temp1 = e1.getTemporal ();
cb.addQuadruples (e2.getCode ());
TemporalIF temp = tF.create ();
cb.addQuadruple (“ADD”, temp, temp1, temp2);
cb.addQuadruples (e1.getCode ());
e.setTemporal (temp);
cb.addQuadruple (“NOT”, temp, temp1);
e.setCode (cb.create());
e.setTemporal (temp);
RESULT = e
e.setCode (cb.create()); RESULT = e :}
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Generación de código intermedio en Cup Una vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup
Expresiones exp ::= MENOS exp:e1 {:
Expresiones exp ::= PI exp:e1 PD {: RESULT = e1;
Exp e = new Exp();
:}
ScopeIF scope = scopeManager.getCurrentScope();
exp ::= rNumero:rn {:
TemporalFactory tF = new TemporalFactory (scope);
Exp e = new Exp ();
IntermediateCodeBuilder cb = new …Builder (scope)
Integer value = rn.getValue ();
TemporalIF temp1 = e1.getTemporal ();
TemporalIF temp = tF.create ();
ScopeIF scope = scopeManager.getCurrentScope();
cb.addQuadruples (e1.getCode ());
TemporalFactory tF = new TemporalFactory (scope);
cb.addQuadruple (“NEG”, temp, temp1);
IntermediateCodeBuilder cb = new …Builder (scope);
e.setTemporal (temp);
TemporalIF temp = tF.create ();
e.setCode (cb.create());
cb.addQuadruple (“MV”, temp, value);
RESULT = e;
e.setTemp (temp); e.setCode (cb.create ()):
:}
RESULT = e; :}
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Generación de código intermedio en Cup Una vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup
Expresiones exp ::= referencia:r {:
Referencias referencia ::= ID:id {:
Exp e = new Exp ();
Referencia r = new Referencia ();
e.setType (r.getType ());
String name = id.getLexema ();
ScopeIF scope = scopeManager.getCurrentScope();
TemporalFactory tF = new TemporalFactory (scope);
ScopeIF scope = scopeManager.getCurrentScope();
IntermediateCodeBuilder cb = new …Builder (scope);
TemporalFactory tF = new TemporalFactory (scope);
TemporalIF rTemp = r.getTemporal ();
IntermediateCodeBuilder cb = new …Builder (scope);
TemporalIF temp = tF.create ();
TemporalIF temp = tF.create ();
cb.addQuadruples (r.getCode ());
SymbolVariable sV = scopeManager.searchSymbol (name);
cb.addQuadruple (“MVP”, temp, rTemp);
Variable var = new Variable (name, sV.getScope ());
e.setTemp (temp);
cb.addQuadruple (“MVA”, temp, var);
e.setCode (cb.create ()):
referencia.setTemporal (temp);
RESULT = e;
referencia.setCode (cb.create ()); RESULT = referencia;
:} :}
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Generación de código intermedio en Cup Una vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup
referencia ::= ID:id {: Referencia r = new Referencia (); String name = id.getLexema ();
D3
V
Referencias a elementos de Arrays i
j
D2
ScopeIF scope = scopeManager.getCurrentScope();
k
TemporalFactory tF = new TemporalFactory (scope); IntermediateCodeBuilder cb = new …Builder (scope); TemporalIF temp = tF.create ();
D1
TemporalIF tempI = tF.create (); cb.addQuadruple (“MVA”, temp, name); cb.addQuadruple (“MV”, tempI, 0); referencia.setTemporal (temp);
V [i][j][k] t1 := 0
&v + i x (D2 x D3 x size)
referencia.setTemporalIndex (tempI);
+ j x (D3 x size)
referencia.setCode (cb.create ());
+ k x size
RESULT = referencia; :}
size
=
t2 := t1 x D1 + i t3 := t2 x D2 + j t4 := t3 x D3 + k t5 := &v + t4 x size
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Generación de código intermedio en Cup Una vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup
referencia ::= referencia:r CI exp:e CD {:
i
Referencia rn = new Referencia ();
j
TypeIF
D3
V
Referencias a elementos de Arrays
D2
rType = r.getType();
int rDim = rType.getMax () – rType.getMin () + 1;
k
TemporalFactoryIF tF = new TemporalFactory (scope); TemporalIF rTemp = r.getTemporal (); TemporalIF rTempI = r.getTemporalIndex ();
D1
TemporalIF eTemp = e.getTemporal (); TemporalIF rnTempI = tF.create (); IntermadiateCodeBuilder cb = new …Builder (scope); cb.addQuadruples (e.getCode ());
size
V [i][j][k] t1 := 0
&v + i x (D2 x D3 x size)
cb.addQuadruples (r.getCode ());
+ j x (D3 x size)
cb.addQuadruple (“MUL”, rnTempI, rTempI, rDim);
+ k x size
cb.addQuadruple (“ADD”, rnTempI, rnTempI, eTemp); rn.setType (rType.getBaseType());
=
t2 := t1 x D1 + i t3 := t2 x D2 + j t4 := t3 x D3 + k t5 := &v + t4 x size
rn.setTemporal (rTemp); rn.setTemporalIndex (rnTempI); r.setCode (cb.create()); RESULT = rn; :}
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Generación de código intermedio en Cup Una vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup
exp ::= referencia:r {: Exp e = new Exp ();
D3
V
Referencias a elementos de Arrays i
j
D2
ScopeIF scope = scopeManager.getCurrentScope (); TemporalFactoryIF tF = new TemporalFactory (scope);
k
TemporalIF rTemp = r.getTemporal (); TemporalIF rTempI = r.getTemporalIndex (); TemporalIF eTemp = tF.create (); TypeIF
D1
rType = r.getType();
int rSize = rType.getSize (); IntermadiateCodeBuilder cb = new …Builder (scope); cb.addQuadruples (r.getCode ());
size
V [i][j][k]
cb.addQuadruple (“MUL”, eTemp, rTempI, rSize);
+ j x (D3 x size)
cb.addQuadruple (“ADD”, eTemp, eTemp, rTemp);
+ k x size
cb.addQuadruple (“MVP”, eTemp, eTemp); e.setTemporal (eTemp);
t1 := 0
&v + i x (D2 x D3 x size)
=
t2 := t1 x D1 + i t3 := t2 x D2 + j t4 := t3 x D3 + k t5 := &v + t4 x size
e.setCode (cb.create()); RESULT = e; :}
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Generación de código intermedio en Cup Una vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup
Referencia a campos de registro referencia ::= referencia:r PUNTO ID:id {:
Referencia a campos de registro expr ::= referencia:r {:
Referencia rn = new Referencia ();
Exp e = new Exp ();
String name = id.getLexema ();
ScopeIF scope = scopeManager.getCurrentScope ();
ScopeIF scope = scopeManager.getCurrentScope();
TemporalFactoryIF tF = new TemporalFactory (scope);
TemporalFactory tF = new TemporalFactory (scope);
TemporalIF rTemp = r.getTemporal ();
TemporalIF rTemp = r.getTemporal ();
TemporalIF rTempI = r.getTemporalIndex ();
TemporalIF rTempI = r.getTemporalIndex ();
TemporalIF rTempO = r.getTemporalOffset ();
TemporalIF rTempO = tF.create ();
TemporalIF eTemp = tF.create ();
IntermediateCodeBuilder cb = new …Builder (scope);
TypeIF
cb.addQuadruples (r.getCode ());
int rSize = rType.getSize ();
TypeRecord rType = r.getType ();
IntermadiateCodeBuilder cb = new …Builder (scope);
int idOffset = rType.getOffset
(name);
rType = r.getType();
cb.addQuadruples (r.getCode ());
cb.addQuadruple (“MV”, rTempO, idOffset);
cb.addQuadruple (“MUL”, eTemp, rTempI, rSize);
rn.setTemporal (rTemp);
cb.addQuadruple (“ADD”, eTemp, eTemp, rTemp);
rn.setTemporalIndex (rTempI);
cb.addQuadruple (“ADD”, eTemp, eTemp, rTempO);
rn.setTemporalOffset (rTempO) ;
cb.addQuadruple (“MVP”, eTemp, eTemp);
rn.serCode (cb.create()); RESULT = rn; :}
e.setTemporal (eTemp); e.setCode (cb.create());
RESULT = e; :}
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Generación de código intermedio en Cup Una vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup
Sentencia asignación sentenciaAsignacion ::= referencia:r IGUAL exp:e {:
Sentencia If sentenciaIF ::= IF PI exp:e PD s:s1 ELSE s:s2 {:
SentenciaAsignacion sa = new SAsignacion ();
SentenciaIf sIf = new SIf ();
ScopeIF scope = scopeManager.getCurrentScope();
ScopeIF scope = scopeManager.getCurrentScope ();
TemporalFactoryIF tF = new TemporalFactory (scope);
LabelFactoryIF lF = new LabelFactory (scope);
TemporalIF eTemp = e.getTemporal ();
LabelIF l1 = lF.create ();
TemporalIF rTemp = r.getTemporal ();
LabelIF l2 = lF.create ();
TemporalIF rTempI = r.getTemporalIndex ();
TemporalIF eTemp = e.getTemporal ();
TemporalIF rTempO = r.getTemporalOffset ();
IntermadiateCodeBuilder cb = new …Builder (scope);
TemporalIF temp = tF.create ();
cb.addQuadruples (e.getCode ());
IntermediateCodeBuilder cb = new …Builder (scope);
cb.addQuadruple (“BRF”, eTemp, l1);
cb.addQuadruples (e.getCode ());
cb.addQuadruples (s1.getCode ());
cb.addQuadruples (r.getCode ());
cb.addQuadruple (“BR”, l2);
cb.addQuadruple (“MUL”, temp, rTempI, rSize);
cb.addQuadruple (“INL”, l1);
cb.addQuadruple (“ADD”, temp, temp, rTemp);
cb.addQuadruples (s2.getCode ());
cb.addQuadruple (“ADD”, temp, temp, rTempO);
cb.addQuadruple (“INL”, l2);
cb.addQuadruple (“STP”, temp, eTemp);
sIF.setCode (cb.create ());
sa.setCode (cb.create()); RESULT = sa; :}
RESULT = sIF; :}
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Generación de código intermedio en Cup Una vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup
Sentencia While sentenciaWhile ::= WHILE PI exp:e PD s:s1 {:
Sentencia For sentenciaFor ::= FOR sAsignacion:sa TO exp:e DO s:s1 {:
SentenciaWhile sWhile = new SWhile ();
SentenciaFor sFor = new SFor ();
ScopeIF scope = scopeManager.getCurrentScope ();
ScopeIF scope = scopeManager.getCurrentScope ();
LabelFactoryIF lF = new LabelFactory (scope);
LabelFactoryIF lF = new LabelFactory (scope);
LabelIF l1 = lF.create ();
LabelIF l1 = lF.create ();
LabelIF l2 = lF.create ();
LabelIF l2 = lF.create ();
TemporalIF eTemp = e.getTemporal ();
TemporalIF eTemp = e.getTemporal ();
IntermadiateCodeBuilder cb = new …Builder (scope);
IntermadiateCodeBuilder cb = new …Builder (scope);
cb.addQuadruple (“INL”, l1);
cb.addQuadruples (sa.getCode ());
cb.addQuadruples (e.getCode ());
cb.addQuadruple (“INL”, l1);
cb.addQuadruple (“BRF”, eTemp, l2);
cb.addQuadruples (e.getCode ());
cb.addQuadruples (s1.getCode ());
cb.addQuadruple (“BRF”, eTemp, l2);
cb.addQuadruple (“BR”, l1);
cb.addQuadruples (s1.getCode ());
cb.addQuadruple (“INL”, l2);
cb.addQuadruple (“BR”, l1);
sWhile.setCode (cb.create ());
cb.addQuadruple (“INL”, l2);
RESULT = sWhile; :}
sFor.setCode (cb.create ()); RESULT = sFor; :}
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Generación de código intermedio en la práctica
Desarrollo paso a paso La fase de generación de código intermedio requiere de la implementación de acciones semánticas en el esquema de traducción dirigidas a producir un código lineal cercano al código objeto pero independiente de una arquitectura física real. A continuación se resumen los pasos recomendados para esta fase 1. Diseñar un lenguaje intermedio -
Identificar todas las operaciones necesarias y asignarles un acrónimo y semántica
-
Tomar como referencia el lenguaje objeto de la arquitectura real
-
Comenzar por un juego sencillo e ir refinándolo bajo demanda
2. Implementar las clases necesarias del framework -
Caracterizar mediante atributos los operandos: Variable, Temporal, Label, Value
-
Incluir atributos necesarios a cada no terminal (Expresión, Sentencias, Referencias, …)
-
Considerar revisar la definición de otros artefactos: TypeIF, …
3. Implementar las acciones semánticas que generan código intermedio -
Código intermedio para expresiones, referencias, sentencias…
-
Incorporar este código al del comprobador de tipos implementado en la fase anterior
4. Probar el código intermedio -
Ejecutar el finalTestCase
-
semanticErrorManager.debug en reglas para que imprima el código intermedio generado Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Bibliografía
Material de estudio Bibliografía básica Construcción de compiladores: principios y práctica Kenneth C. Louden International Thomson Editores, 2004 ISBN 970-686-299-4
Javier Vélez Reyes [email protected]
Generación de código intermedio. Sentencias y expresiones Bibliografía
Material de estudio Bibliografía complementaria Compiladores: Principios, técnicas y herramientas. Segunda Edición Aho, Lam, Sethi, Ullman Addison – Wesley, Pearson Educación, México 2008
Diseño de compiladores. A. Garrido, J. Iñesta, F. Moreno y J. Pérez. 2002. Edita Universidad de Alicante
Javier Vélez Reyes [email protected]