Generación de código
Hay lenguajes que son pseudointerpretados que utilizan un
código intermedio llamado código-P que utiliza lo que se denomina bytecodes
(sentencias de un µP hipotético). Por ejemplo Java utiliza los ficheros .class,
éstos tienen unos bytecodes que se someten a una JavaVirtualMachine, para que
interprete esas sentencias. En este capítulo se muestra cómo se pueden utilizar
los métodos de analizadores dirigidos por la sintaxis para traducir a un código
intermedio, construcciones de lenguajes de programación como declaraciones,
asignaciones y proposiciones de flujo de control. La generación de código
intermedio se puede intercalar en el análisis sintáctico.
Código de tercetos
La elección de operadores permisibles es un aspecto
importante en el diseño de código intermedio. El conjunto de operadores debe
ser lo bastante rico como para implantar las operaciones del lenguaje fuente.
Un conjunto de operadores pequeño es más fácil de implantar en una nueva máquina
objeto. Sin embargo un conjunto de instrucciones limitado puede obligar a la
etapa inicial a generar largas secuencias de proposiciones para algunas
operaciones del lenguaje fuente. En tal caso, el optimizador y el generador de
código tendrán que trabajar más si se desea producir un buen código.
Ejemplo de código de tercetos c = a label etqBucle if b = 0
goto etqFin b = b-1 c = c+1 goto etqBucle label etqFin
Para ilustrar como se utiliza el código de tercetos en una
gramática vamos a suponer que nuestra calculadora en vez de ser una calculadora
interpretada es una calculadora compilada, es decir, en vez de interpretar las
expresiones vamos a generar código intermedio equivalente. Tendremos en cuenta
la posibilidad de utilizar variables.
Las variables temporales sirven para almacenar resultados
intermedios a medida que vamos calculando el resultado final.
Generacion de código de tercetos
o sentencis de control
Cada vez que se reduce a una
condición en base a expresiones, se genera el código
if
arg1 op arg2 goto etq_verdad goto etq_falso
En el momento en que nos encontramos con un operador
lógico, sabemos que a continuación nos vamos a encontrar otra condición, que
también generará un código con la misma estructura, así como otras dos
etiquetas, una de certeza, y otra de falsedad. Ambas condiciones y el operador
lógico, se reducirán a una condición. Ahora bien, dicha condición reducida
deberá tener solo dos etiquetas, ¿qué etiquetas le asignamos?. La solución
depende de la conectiva que se emplee.
Veamos cada uno de los casos:
cond : cond AND cond { }
Ventajas:
Permite abstraer la máquina, separar operaciones de alto nivel de
su implementación a bajo nivel.
Permite la reutilización de los front-ends y backends.
Permite
optimizaciones
generales.
Desventajas:
Implica
una
pasada más para el compilador (no se puede utilizar el modelo de una
pasada, conceptualmente simple).
Dificulta llevar a cabo optimizaciones
específicas de la arquitectura destino.
Suele
ser ortogonal a la máquina destino, la traducción a una arquitectura específica
será más larga e ineficiente.
No hay comentarios.:
Publicar un comentario