Want to make creations as awesome as this one?

Transcript

Start

1.3.-Presentacion interactiva

Alumno: José Giovany Gómez CruzProfesor: Alberto Romo Moreno

Consideraremos algunas comprobaciones estáticas simples que pueden realizarse durante la construcción de un árbol sintáctico para un programa fuente. Hay una diferencia entre el significado de los identificadores a la izquierda y a la derecha de una asignación. En las siguientes asignaciones: i = 5; i = i + 1; el lado derecho especifica un valor entero, mientras que el lado izquierdo indica dónde se almacenará el valor. Los términos l-value y r-value se refieren a los valores apropiados en los lados izquierdo y derecho de una asignación, respectivamente. Los r-value son lo que consideramos como "valores", mientras que los l-value son las ubicaciones. La comprobación estática debe asegurar que el lado izquierdo de una asignación denote un l-value. Un identificador como i tiene un l-value.

L-value y R-value

La comprobación de tipos asegura que el tipo de una construcción coincida con lo que espera su contexto. Por ejemplo, en la siguiente instrucción if: if (expr) instr se espera que la expresión expr tenga el tipo boolean. Las reglas de comprobación de tipos siguen la estructura operador/operando de la sintaxis abstracta. Suponga que el operador rel representa a los operadores relacionales como <=. La regla de tipos para el grupo de operadores rel es que sus dos operandos deben tener el mismo tipo, y el resultado tiene el tipo booleano. Utilizando el atributo tipo para el tipo de una ex- presión, dejemos que E consista de rel aplicado a E1 y E2. El tipo de E puede comprobarse al momento de construir su nodo, mediante la ejecución de código como el siguiente:

Comprobación de tipos

La idea de relacionar los tipos actuales con los esperados sigue aplicándose en las siguientes situaciones: • Coerciones. Una coerción ocurre cuando el tipo de un operando se convierte automáticamente al tipo esperado por el operador. En una expresión como 2 + 3.14, la transformación habitual es convertir el entero 2 en un número de punto flotante equivalente, 2.0, y luego realizar una operación de punto flotante con el par resultante de operandos. La definición del lenguaje especifica las coerciones disponibles. Por ejemplo, la regla actual para rel que vimos antes podría ser que E.tipo y E2.tipo puedan convertirse al mismo tipo. En tal caso, sería legal comparar, por ejemplo, un entero con un valor de punto flotante. • Sobrecarga. El operador + en Java representa la suma cuando se aplica a enteros y la concatenación cuando se aplica a cadenas. Se dice que un símbolo está sobrecargado si tiene distintos significados dependiendo de su contexto. Por lo tanto, + está sobrecargado en Java. Para determinar el significado de un operador sobrecargado, hay que considerar los tipos conocidos de sus operandos y resultados. Por ejemplo, sabemos que el + en z = x + y es concatenación si alguna de las variables x, y o z es de tipo cadena. Sin embargo, si también sabemos que alguna de estas es de tipo entero, entonces hay un error de tipos y no hay significado para este uso de +.

Código de tres direcciones

Una vez que se construyen los árboles de sintaxis, se puede realizar un proceso más detallado de análisis y síntesis mediante la evaluación de los atributos, y la ejecución de fragmentos de código en los nodos del árbol. Para ilustrar las posibilidades, vamos a recorrer árboles sin- tácticos para generar código de tres direcciones. En específico, le mostraremos cómo escribir funciones para procesar el árbol sintáctico y, como efecto colateral, emitir el código de tres direcciones necesario. Instrucciones de tres direcciones El código de tres direcciones es una secuencia de instrucciones de la forma x = y op z en donde x, y y z son nombres, constantes o valores temporales generados por el compilador; y op representa a un operador. Manejaremos los arreglos usando las siguientes dos variantes de instrucciones: x [y]=z x = y [z]