Compiladores
Enviado por johncastro • 19 de Diciembre de 2012 • 5.042 Palabras (21 Páginas) • 377 Visitas
2. Análisis Semántico:
El analizador semántico verificara que cada operador tenga los operandos permitidos
=
/ \
id1 +
/ \
id2 *
/ \
id3 tipo_ent
|
500
Este árbol es diferente al anterior, no interesa la estructura gramatical, ni las clases de tokens. Se expresan los tipos de datos relacionados con los tokens.
Generación de código intermedio: En esta etapa se lleva la expresión a una representación intermedia como un programa para una maquina abstracta.
temp1= tipo_ent(500)
temp2= id3 * temp1
temp3= id2 + tem2
id1= temp3
Optimización de código El código intermedio obtenido es representado de una forma mas optima y eficiente de la siguiente forma :
temp1= id3 * 500
id1= id2 + temp1
Generación de código Finalmente se lleva el código intermedio a un código objeto que ensamblador.
MOVF id3, [R2]
MULF #500, [R2]
MOVF id2, [R1]
ADDF [R2], [R1]
MOVF [R1], id1
Código Intermedio:
El del ejemplo es un lenguaje ensamblador genérico, un código intermedio entre el código fuente y el lenguaje binario de bajo nivel. Hay algunos aspectos a tener en cuenta:
1) R1, R2 son registros del procesador. Son compartimientos físicos con una longitud determinada de bits. Se llaman variables del hardware porque hacen referencia a la parte física de la máquina. Pueden existir registros de 8, 16, 32, 64, 128 bits. Cada modelo de procesador ( 8086, 80286, 80386, 80486, pentium ll ) tienen su propia familia de registros y de instrucciones.
2) MOVF
MULT
ADDF
SUBF
DIVF
Son instrucciones del código ensamblador (código intermedio). Son nemotécnicos para las operaciones de asignación (MOVF), multiplicación (MULT), suma (ADDF), resta (SUBF) y división (DIVF ).
3) El código mas utilizado es el código en tres direcciones, en le que sus instrucciones constan de tres direcciones o registros, dos para dos operandos y uno para el resultado. En general la forma representativa para este código es :
res= oper1 op oper2
OP quiere decir operador, oper1 operando 1 y oper2 operando 2.
4) MOVF id3, [R2]
MULF #500, [R2]
MOVF id2, [R1]
ADDF [R2], [R1]
MOVF [R1], id1
Este código esta escrito en dos direcciones. Cada instrucción tiene al máximo dos operandos.
El formato general de las mismas es:
A su vez es el almacenamiento para el resultado
Por ejemplo:
MOVF id3, [R2] se interpreta as: Lleve al registro R2 el valor almacenado en la variable de memoria id3.
MULF #500, [R2] se interpreta as: Lleve al registro R2 el resultado del producto entre el número 500 y el valor almacenado en el registro R2..
MOVF id2, [R1] se interpreta así : Lleve al registro R1 el valor almacenado en la variable de memoria id2..
ADDF [R2], [R1] se interpreta así : Lleve al registro R1 el resultado de la suma entre el registro R2 y el registro R1. .
MOVF [R1], id1 se interpreta así : Lleve a la variable de memoria id1 el valor almacenado en el registro R!..
5) MOVF id3, [R2]
MULF #500, [R2]
En estas dos instrucciones se observan dos detalles : Cuando un operando es un número, en la instrucción se le antepone el símbolo #. Los registros ( variables del software deben escribirse entre corchetes ( [ ] ).
6) Puede decirse que es un código intermedio en dos sentidos : Esta entre el código fuente de alto nivel y el código binario, y utiliza variables del código de alto nivel (variables de memoria) y variables del hardware. (registros del procesador).
3. Proceso general de traducción
La estructura interna del proceso general de traducción desde un código fuente de alto nivel, hasta un código de máquina ( binario de 1s y 0s ), esta dividida en cuatro grandes módulos, cada uno independiente del otro. En la siguiente gráfica se muestran los mismos:
El preprocesador, es el encargado de transformar el código fuente de entrada original en el código fuente puro. Es decir en expandir las macros, incluir las librerías, realizar un preprocesado racional (capacidad de enriquecer a un lenguaje antiguo con recursos más modernos), extender el lenguaje y todo aquello que en el código de entrada sea representativo de una abreviatura para facilitar la escritura del mismo.
El compilador recibe el código fuente puro ( un único código fuente, sin macros ni procedimientos), este es él modulo principal de un compilador, pues si ocurriera algún error en esta etapa el compilador no podría avanzar. En esta etapa se somete al código fuente puro de entrada a un análisis léxico gráfico, a un análisis sintáctico, a un análisis semántico, que construyen la tabla de símbolos, se genera un código intermedio al cual se optimiza para así poder producir un código de salida generalmente en algún lenguaje ensamblador
El ensamblador. Este modulo no es ni más mi menos que otro compilador pues recibe un código fuente de entrada escrito en ensamblador, y produce otro código de salida, llamado código binario no enlazado. Si por un momento viéramos a este modulo como un programa independiente, veríamos que en este caso los términos programa compilador y proceso de compilación son los mismos. Pues este modulo no es mas que un compilador, que en su interior realiza como su antecesor un análisis léxico gráfico, un análisis sintáctico, un análisis semántico, crea una tabla de símbolos, genera un código intermedio lo optimiza y produce un código de salida llamado código binario no enlazado, y a todo este conjunto de tares se los denomina proceso de compilación. Como se puede ver este compilador (llamado ensamblador) a diferencia de los demás compiladores no realiza una expansión del código fuente original(código fuente de entrada), tiene solamente un proceso de compilación y por supuesto no enlaza el código fuente. Es un compilador
...