Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Lenguajes de Programación Expresiones Ma. Laura Cobo Universidad Nacional del Sur Departamento de Ciencias e Ingeniería de la Computación 2016 Prof. Ma. Laura Cobo Página 1 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Introducción Las expresiones son una forma fundamental de especificar computación en un lenguaje de programación. Además de la forma de las mismas (sintaxis: BNF), su significado (semántica) es crucial. La semántica, esta gobernada por su forma de evaluación Es necesario estar conscientes de los ordenes de evaluación de operandos y operadores La esencia de los lenguajes de programación imperativos es dominada por el rol de las sentencias de asignación 2 Prof. Ma. Laura Cobo Página 2 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Expresiones Aritméticas Las expresiones constan de: • Operadores • Operandos • Paréntesis • Llamadas a función Los operadores pueden ser: • Unarios: tienen sólo un operando • Binarios: tienen dos operandos 3 Prof. Ma. Laura Cobo Página 3 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Expresiones Aritméticas La mayoría de los lenguajes imperativos adoptan una notación infija para los operadores, pero hay otras opciones: • Prefija Común *(+(A,B),-(C,A)) Polaca (*(+ A B) (- C A)) Polaca Cambridge * + A B – C A • Posfija Sufija ((A,B)+,(C,A)-)* Inversa AB+CA-* • Infija (A + B) * (C – A) 4 Prof. Ma. Laura Cobo Página 4 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Expresiones Aritméticas Aspectos de diseño: • Reglas de precedencia de operadores Control • Reglas de asociatividad de operadores • Orden de evaluación de los operandos • Evaluación de efectos colaterales de un operador • Sobrecarga de un operador • Modo mixto de expresiones • Errores en las expresiones 5 Prof. Ma. Laura Cobo Página 5 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Reglas de precedencia - Asociatividad Define el orden en el cual operadores adyacentes (con diferente precedencia) son evaluados. Los niveles de precedencia típicos son: • • • • • Paréntesis Operadores unarios ** (potenciación) *, / +, - Define como se resuelve el orden de evaluación frente a operadores del mismo nivel de precedencia. Regla típica: evaluación de izquierda a derecha Las reglas de precedencia y asociatividad pueden modificarse con el uso de paréntesis Prof. Ma. Laura Cobo 6 Página 6 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Evaluación de operandos 1. Variables: cargar el valor desde memoria 2. Constantes: algunas veces son cargas desde la memoria, otras veces la constante puede ser parte de las instrucciones del lenguaje máquina 3. Expresiones parentizadas: se evalúan las expresiones de acuerdo al modo de evaluación elegido Si ninguno de los operandos u operadores tiene efectos colaterales, entonces el orden de evaluación es irrelevante 7 Prof. Ma. Laura Cobo Página 7 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Efectos colatelares potenciales Efectos colaterales funcionales: cuando una función cambia un parámetro de entrada-salida o una variable global. a + fun(a) Si fun es una función que no tiene efectos colaterales sobre la variable a entonces el orden de evaluación los operandos no afecta el valor de la expresión. Caso contrario el orden de evaluación determina el valor de la misma Ejemplo en C: int a =5; int fun1() { a = 17; return 3; void fun2 () { a = a + fun1(); void main() { fun2(); Prof. Ma. Laura Cobo } } } 8 Página 8 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Soluciones a el problema de efectos colaterales 1. El diseñador del lenguaje de programación deshabilita los efectos colaterales de las funciones a. No hay parámetros de entrada-salida en las funciones b. No hay referencias a variables globales en las funciones • Ventaja: funciona como solución • Desventaja: muy inflexible 2. Escribir la definición del lenguaje de manera que fije la evaluación de los operandos • Desventaja: limita las posibilidades de optimizar el código 9 Prof. Ma. Laura Cobo Página 9 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Operadores sobrecargados Tiene lugar, cuando se utiliza el mismo operador para más de un propósito. Características: 1. Pérdida de detección de errores por parte del compilador 2. Pérdida en la facilidad de lectura (readability) 3. Puede ser evitada con la introducción de nuevos símbolos 4. Lenguajes como C++ y Ada permiten al usuario declarar operadores sobrecargados • El usuario puede declarar operadores sin sentido • La facilidad de lectura se ve lesionada aún cuando el operador tenga sentido 10 Prof. Ma. Laura Cobo Página 10 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Conversión de tipos La conversión o bien limita el tipo o lo expande. Una conversión limitante sucede cuando se convierte el tipo de un objeto a un tipo que no puede incluir todos los valores del tipo original. Por ejemplo transformar el tipo de un objeto float en int Un conversión expansora sucede cuando se convierte el tipo de un objeto a un tipo que puede incluir al menos aproximaciones al tipo original. Por ejemplo transformar int a float 11 Prof. Ma. Laura Cobo Página 11 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Conversión de tipos Las conversiones de tipo pueden ser: • Explicitas o implícitas Un decisión de diseño de las expresiones es determinar si se van a Expresiones que admiten permitir expresiones mixtas operadores de tipos diferentes Las conversiones implícitas o coerciones es generalmente iniciada por el compilador. La mayoría de los lenguajes de programación provee coerciones expansoras para sus expresiones 12 Prof. Ma. Laura Cobo Página 12 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Conversión de tipos Las conversiones de tipo explicitas pueden ser de tanto limitantes como expansoras. En lenguajes como C se realizan a través del cast. (int) temperatura En cambio en lenguajes como Ada la sintaxis es parecida a la de las llamadas a función: AVG := FLOAT(SUMA) / FLOAT (CONTADOR) • • Errores en las expresiones Causadas por limitaciones inherentes a la aritmética (por ejemplo división por cero) Causadas por limitaciones en la forma de computar la aritmética (overflow-underflow de la representación) 13 Prof. Ma. Laura Cobo Página 13 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Expresiones relacionales y booleanas Expresiones relacionales Usan operadores relacionales sobre operadores de diferentes tipos. El valor obtenido de cualquier expresión relacional es booleano Los lenguajes utilizan diferentes símbolos para representar a los operadores relacionales Expresiones booleanas En este caso tanto los operadores como los operandos son de tipo booleano Nuevamente los lenguajes utilizan símbolos diferentes para representar los operadores booleanos tradicionales 14 Prof. Ma. Laura Cobo Página 14 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Expresiones relacionales y booleanas Curiosidades C no provee el tipo booleano en forma explicita (utiliza en tipo int) Además tiene permite escribir expresiones que no se computan de la forma que se esperaría a<b<c La precedencia de los operados booleanos y relaciones en general es la habitual (cómo en el caso aritmético) 15 Prof. Ma. Laura Cobo Página 15 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Evaluación de expresiones Nos resta ver las posibles forma de evaluar las expresiones Los tipos fundamentales son: 1. Evaluación Estricta 2. Evaluación No Estricta Evaluación Estricta: los argumentos de una función o los operandos de la expresión son siempre completamente evaluados antes de la aplicación de la función u operador. Evaluación No Estricta: los argumentos de una función o los operandos de la expresión no son evaluados a menos que sean utilizados en el cuerpo de la función o sean necesarios para determinar el valor de la expresión. 16 Prof. Ma. Laura Cobo Página 16 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Evaluación estricta La evaluación estricta es la tradicionalmente utilizada por los lenguajes de programación. Es también conocida como: Evaluación de orden aplicativo (evalúa de izq. a der.) Evaluación ansiosa En este tipo de evaluación una expresión se evalúa al momento de establecer la ligadura con una variable. Los lenguajes imperativos la utilizan casi siempre (debido a que el orden de ejecución esta definido implícitamente por la organización del código) 17 Prof. Ma. Laura Cobo Página 17 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Evaluación estricta Ventajas: Elimina la necesidad de planificar El programador puede determinar el orden de ejecución Desventajas: Fuerza la evaluación de expresiones que pueden no ser necesarias en tiempo de ejecución. Puede demorar la evaluación de expresiones cuyo valor se requiere en forma mas inmediata. Fuerza al programador a organizar el código fuente para garantizar una ejecución óptima. 18 Prof. Ma. Laura Cobo Página 18 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Evaluación no estricta Cuando se implementa se denomina evaluación de orden normal. Características: La evaluación se reduce por la izquierda Las funciones se aplican antes de evaluar sus argumentos. Se puede especializar en distintas versiones: Evaluación perezosa: agrega la memorización de los argumentos evaluados. Evaluación corto-circuito (expresiones booleanas): se retorna el valor de la expresión tan pronto como se pueda determinar el valor de verdad sin ambigüedad 19 Prof. Ma. Laura Cobo Página 19 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Evaluación de orden normal: Ejemplo Ejemplo: Considere la siguiente llamada sumar(2+3) sumar(x): sumar(x): yy==2+3 x * 2* 2 zz==2+3 + 10 x + 10 El resultado, se obtiene sustituyendo x con la expresión 2+3. La expresión 2+3 y no el valor 5, es pasado como el de valor de x en la función. 20 Prof. Ma. Laura Cobo Página 20 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Evaluación perezosa: Ejemplo Ejemplo: Considere la siguiente llamada sumar(2+3) sumar(x): y = 2+3 x * 2* 2 z = x5 + 10 El resultado, se obtiene sustituyendo x con la expresión 2+3, en la primera aparición de x dentro del cuerpo de sumar y por el valor de la expresión, 5, en las futuras apariciones de x en el cuerpo de la función. 21 Prof. Ma. Laura Cobo Página 21 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Evaluación perezosa: Ejemplo Ejemplo en ML fun g(x,y,z) = if x<2 then y+3 else z+6 a=0: 0 ? b/a Ejemplo en C Es interesante notar que solo el valor de y o el valor de z son requeridos para el cálculo del resultado, pero no ambos. Ejemplo en Haskell fibs = 0 : 1 : zipWith (+) fibs(tail fibs) “:” agrega un elemento a la lista Tail: retorna una lista sin su primer elemento zipWith crea una nueva lista tomando el elemento a la cabeza de cada lista, aplicando una función, + en este caso Esta función calcula una lista con todos los números Fibonacci. 22 Prof. Ma. Laura Cobo Página 22 Lenguajes de Programación Departamento de Cs. e Ingeniería de la Computación Universidad Nacional del Sur Primer Cuatrimestre de 2016 Evaluación corto-circuito: Ejemplo Ejemplo en C int a = 0; int b = 4 if (a != b && myfun(b) ) { do_something(); } En este ejemplo, debido a la evaluación en corto-circuito, se garantiza que la llamada a myfun(b) nunca suceda. Esto es porque a se evalúa como falso Otro ejemplo en C int TieneTresCaracteresDeLongitud(const char *p) { return (p != NULL) && (strken(p) ==3); } Prof. Ma. Laura Cobo 23 Página 23