Академический Документы
Профессиональный Документы
Культура Документы
Siguiendo estn los diseos primarios de los problemas para las expresiones
aritmticas, las cuales todas se discute en esta seccin:
Qu son las reglas de precedencia de operador?
Qu son las reglas de asociatividad de operador?
Qu es el orden de evaluacin del operando?
Hay restricciones en el efecto colateral de la evaluacin de operandos?
El lenguaje permite que el usuario defina una sobrecarga del operador?
Qu modo mezclado es permitido en expresiones?
7.2.1 Orden de Evaluacin del Operador
Nosotros investigamos las reglas del lenguaje que especifican el orden de
evaluacin de los operadores primero.
7.2.1.2 Precedencia
El valor de una expresin depende, por lo menos en parte, del orden de
evaluacin de los operadores en la expresin. Considere la expresin siguiente:
a+b*c
Suponga las variables a, b, y c que tienen los valores 3, 4, y 5,respectivamente.
Evaluado de izquierda a derecha (la suma primero y luego la multiplicacin), el
resultado es 35. Evaluado de derecha a izquierda, el resultado es 23..
En lugar de evaluar el orden simplemente de izquierda a derecha o de derecha
a izquierda, los matemticos han desarrollado el concepto de colocar
operadores en una jerarqua de evaluacin de prioridades y basando el orden
de evaluacin de expresiones en parte en esta jerarqua. Por ejemplo, en
matemtica, se considera que la multiplicacin es de prioridad ms alta que la
suma. Si nosotros seguimos esa convencin en nuestra expresin del ejemplo,
la multiplicacin se evaluara primero.
La regla de precedencia del operador para la evaluacin de la expresin define
el orden en que se evalan los operadores de niveles de precedencia
diferentes. La reglas de precedencia del operador para las expresiones estn
basadas en la jerarqua de prioridades del operador, como son visto por el
diseador del lenguaje. La regla de precedencia del operador de los lenguajes
imperativos comunes son casi todos los mismos, porque ellos estn todos
basados en aquellos de matemtica. En estos lenguajes, la exponenciacin
tiene la precedencia ms alta (cuando es proporcionado por el lenguaje),
siguiendo por la multiplicacin y divisin en el mismo nivel, seguido por la
suma binaria y substraccin en el mismo nivel.
Muchos lenguajes tambin incluyen versiones unarias de suma y substraccin.
La suma unaria es llamada el operador de identidad porque usualmente no
tiene operacin asociada y as no tiene el efecto en su operando. Ellis
yStroustrup, hablando sobre C++, llama e esto un accidente histrico y
correctamente lo etiqueta intil (Ellis y Stroustrup, 1990, pg. 56). En Java, el
unario actualmente tiene un efecto cuando el operando es char, sort, o byteesto causa una conversin implcita de ese operando al tipo del int. El menos
del Unario, claro, siempre cambia el signo de su operando.
En todos los lenguajes imperativos comunes, los operadores menos del unario
Derecha: **
Pascal Izquierda: todos
C Izquierda: postfija ++, postfija - -, *, /, %, binario +, binario
Derecha: prefija ++, prefija - -, unario +, unario
C++ Izquierda: *, /, %, binario +, binario
Derecha: ++, - -, unario -, unario +
Ada Izquierda: todos excepto **
No asociativo: **
Como lo declarado en la seccin 7.2.1.1, en APL, todos los operadores tienen el
mismo nivel de precedencia. As el orden de evaluacin de operadores en las
expresiones de APL es completamente determinado por la regla de
asociatividad, la cual es de derecha a izquierda para todos los operadores. Por
ejemplo, en la expresin
AxB+C
el operador de suma se evala primero, siguiendo por el operador de la
multiplicacin (x es en APL el operador de multiplicacin). Si A era 3, B era 4, y
C era 5, el valor de esta expresin de APL sera 27.
Muchos compiladoreshacen uso del hecho que algunos operadores aritmticos
son matemticamente asociativos, significando que las reglas de asociatividad
no tienen el impacto en el valor de una expresin que contiene slo esos
operadores. Por ejemplo, la suma es matemticamente asociativa, como en la
matemtica el valor de la expresin
A+B+C
no dependa del orden de evaluacin del operador. Si las operaciones de puntoflotante para operaciones matemticamente asociativas tambin fueran
asociativas, el compilador podra usar este hecho para realizar algunas simples
optimizaciones. Especficamente, si el compilador es permitido para reordenar
la evaluacin de operadores, puede poder producir el cdigo ligeramente ms
rpido para la evaluacin de la expresin. Los compiladores actualmente hacen
estos tipos de optimizaciones.
Desdichadamente, los dos, las representaciones del punto-flotante y las
operaciones aritmticas de punto-flotante son slo aproximaciones de
matemtica (debido a las limitaciones del tamao). El hecho que un operador
matemtico es asociativo necesariamente no implica que la correspondiente
operacin de punto-flotante es asociativa. De hecho, slo si todos los
operadores y resultados intermedios pueden representarse exactamente en
notacin de punto-flotante ser el proceso precisamente asociativo. Por
ejemplo, hay situaciones patolgicas en las cuales la suma de entero en una
computadora no es asociativa. Por ejemplo, suponga que un programa debe
evaluar la expresin
A+B+C+D
y que A y C son muy largos nmeros positivos, y B y D son nmeros negativos
con muy largos valoresabsolutos. En esta situacin, agregando B a A no causa
un sobre fluido, pero agregando C a A, si. Igualmente, agregando C a B no
causa el sobre fluido, pero agregando D a B, si. Debido a las limitaciones de
aritmtica de la computadora, la suma es catastrficamente el no asociativo en
este caso. Por consiguiente, si el compilador reordena estas operaciones de
suma, afecta al valor de la expresin. Esto es, claro, un problema que puede
ser evitado por el programador, asumiendo que los valores aproximados de las
variables son conocidos. El programador puede simplificar parentizando la
expresin (vea seccin 7.2.1.3) para asegurar que slo el orden seguro de la
evaluacin es posible. Sin embargo, esta situacin puede levantarse de
maneras ms sutiles, en las que el programador probablemente notar menos
el orden de dependencia.
7.2.1.3 Parntesis
Los Programadores pueden alterar las reglas de precedencia y la asociatividad
colocando parntesis en las expresiones. Una parte de la parentizacin de una
expresin tiene la precedencia sobre sus partes no parentizadas adyacentes.
Por ejemplo, aunque la multiplicacin tiene la precedencia sobre la suma, en la
expresin
(A + B) * C
la suma se evaluar primero. Matemticamente, esto es perfectamente
natural. En esta expresin, el primer operando del operador de la
multiplicacin no est disponible hasta que la suma en la parentizacin de la
subexpresin es evaluada.
Lenguajes que permiten los parntesis en las expresiones aritmticas podran
distribuirse con todas las reglas de precedencia y simples asociatividad; todos
los operadores deizquierda a derecha o de derecha a izquierda. El programador
especificara el orden deseado de evaluacin con los parntesis. Esto sera
simple porque ni el autor ni los lectores de programas necesitaran recordar
cualquier regla de precedencia o asociatividad. La desventaja de este esquema
es que hace las expresiones escritas ms tediosas, y tambin compromete
seriamente la legibilidad del cdigo. Todava esta era la opcin hecha por Ken
Iverson, el diseador de APL.
7.2.1.4 Expresiones Condicionales
Ahora miremos al operador ternario ?: el cual es parte de C, C++, y Java. Este
operador es utilizado para formar las expresiones condicionales.
A veces se utilizan las sentencias if-then-else para realizar una asignacin de la
expresin condicional. Por ejemplo, considere
if (count = =0)
average = 0
else
average = sum / count;
a = b * d;
}
Asuma que el segundo operando del operador de la multiplicacin era
supuestamente c, pero debido a un error del tecleo se tecle como d. Porque
las expresiones del modo-mixto son legales en Java, el compilador no
descubrira esto como un error. Insertara el cdigo simplemente para
coaccionar el valor del otro operando, b, a float. Si las expresiones del modomixto no fueran legales en Java, este error del tecleo se habra descubierto por
el compilador como un error de tipo.
Como un ejemplo ms extremo de los peligros y costos de demasiada coaccin,
considere los esfuerzos de PL/I para lograr la flexibilidad en las expresiones. En
PL/I, unavariable de cadena de caracteres puede combinarse con un entero en
una expresin. En tiempo de ejecucin, la cadena se examina para un valor
a= b + c;
Los valores de b y c son coaccionados a int y una suma int es representada.
Luego la suma es convertida a byte y colocada en a.
7.4.2 Conversin del Tipo Explcito
La mayora de los lenguajes proveen un poco de capacidad haciendo las
conversiones explcitas, ambas reduciendo y ampliando. En algunos casos, los
mensajes de advertencia son producidos cuando el resultado de una
conversin reducida explcita cambia el significado para el valor del objeto al
inicio de la conversin
Ada proporciona operaciones de conversin explcitas que tienen la sintaxis de
llamadas de la funcin. Por ejemplo, nosotros podemos tener
AVG := FLOAT(SUM) / FLOAT(COUNT)
donde AVG es del tipo punto flotante, y SUM y COUNT pueden ser cualquier
tipo numrico.
En el lenguaje basado en C, la conversin del tipo explcito es llamada cast
(lanzar). Las sintaxis de un cast no es de una llamada a funcin; ms bien, el
tipo deseado es colocado en parntesis slo antes de ser convertida la
list [count] := 0
for count := 1 step 1 until 10 do
list [count] := 0
for count := 1, count + 1 while (count 0 goto out
[loop body]
for_var = for_var + step
goto loop
out:
abajo est una descripcin semntica operacional de ejemplos ms complejos
de sentencia for:
for count := 10 step 2 * count until init * init, 3 * count while sum 0 goto loop2
sum = sum + count
count = count + step
goto loop1
loop2:
count = 3 * count
if sum > 1000 goto out
sum =sum + count
goto loop2
out:
8.4.1.4 La sentencia for del Pascal
La sentencia for de Pascal es el modelo de simplicidad. Su forma es
for variable := valor_inicial (to | downto) valor_final do sentencia
La opcin to | downto permite que el valor de la variable crezca o disminuya en
los pasos de a 1. Las opciones del diseo for de Pascal son como sigue: La
variable ciclo debe ser un tipo ordinal, y este tiene el mbito de su declaracin.
En el fin del ciclo normal, la variable ciclo es indefinida. Si el ciclo es terminado
prematuramente, tiene su ltimo valor. La variable ciclo no puede ser
cambiada en el cuerpo del ciclo. Los valores inicial y final, los cuales pueden
ser expresiones de cualquier tipo que son compatibles con la variable del ciclo,
puede ser cambiados en el ciclo, pero porque ellos son evaluados solo una vez,
esto no puede afectar el control del ciclo.
8.4.1.5 La sentencia for de Ada
La sentencia for de Ada es similar a la versin de Pascal. Este es un pre
examinado ciclo con la forma:
for variable in [reserve] rango_discreto loop
end loop;
Un rango discreto es un subrangos de enteros o un tipo enumerado, tal como
1..10.
La nueva caracterstica ms interesante de la sentencia for de Ada el mbito de
la variable ciclo, la cual es el rango del ciclo. La variable es implcitamente
declarada en la sentencia for e implcitamente no declarada despus del fin del
ciclo. Por ejemplo, en:
loop:
if expresin_2 = 0 goto out
[loop body]
expression_3
goto loop`
out:
Un tpico contador del ciclo de C es
for (index = 0; index > indat;
while (indat >= 0) {
sum += indat;
cin >> indat;
}
cin >> valor;
do {
valor /= 10;
dgitos ++;
} while (valor > 0);
Note que todas la variables en estos ejemplos son de tipo entero. cin es el flujo
de entrada estndar (el teclado), y >> es el operador de entrada.
En la versin pre examinada (while) la sentencia es ejecutada tan largo como
la expresin evala verdadero. En C, C++ y Java las sentencias post
examinadas (do), del cuerpo del ciclo es ejecutada hasta la que la expresin
evala falso. La sola diferencia real entre el do y el while es que el do siempre
causa que el cuerpo del ciclo sea ejecutado por lo menos una vez. En ambos
casos, la sentencia puede ser compuesta. Las descripciones semnticas
operacionales de estas dos sentencias son obtenidas abajo:
while do-while
loop: loop:
if expresin = 0goto out [cuerpo del ciclo]
[cuerpo del ciclo] if expresin = 0 goto loop
goto loop
out: ...
Es legal en ambos C y C++ bifurcar dentro de ambos cuerpos de ciclos while y
do.
Las sentencias while y do de Java son similares a las de C y C++, excepto la
expresin de control debe ser del tipo boolean, y porque Java no tiene un goto,
los cuerpo del ciclo no pueden ser introducidos por cualquier parte sino por su
origen.
FORTRAN 90 no tiene ni un pre examinador ni un post examinador de ciclo
lgico. Ada tiene un pre examinador de ciclo lgico pero no una versin de post
examinador de ciclo lgico.
Perl tiene dos pre examinadores de ciclos lgicos, while y until, pero no post
examinador de ciclo. El until es similar a while pero usa el valor inverso de la
expresin de control.
end loop;
end loop;
Cualquier ciclo puede ser nombrado, y cuando un ciclo nombrado es incluido
en el exit, el control es transferido a la sentencia inmediatamente siguiendo lo
referenciado por el ciclo. Por ejemplo, considere el siguiente segmento de
cdigo:
OUTER_LOOP:
for ROW in 1..MAX_ROWS loop
INNER_LOOP:
for COL in 1..MAX_COLS loop
SUM := SUM + MET(ROW, COL);
exit OUTER_LOOP when SUM > 1000.0;
end loop INNER_LOOP;
end loop OUTER_LOOP;
En este ejemplo, el exit es una bifurcacin condicional de la primera sentencia
despus del ciclo externo. Si el exit estaba en cambio
exit when SUM > 1000.0;
esto sera una bifurcacin condicional de la primera sentencia despus del ciclo
interno. Note que las sentencias exit son frecuentemente usados para
manipulacin inusual o condiciones de error.
C, C++, y Pascal tienen innombradas incondicionales (break en C y C++; y last
en Perl); FORTRAN 90 y Java tienen salidas nombradas incondicionalmente
(EXIT en FORTRAN 90 y break en Java), como Ada, excepto que en la versin de
Java el indicador puede estar en cualquier sentencia compuesta encerrada.
C y C++ incluyen un mecanismo de control, continue, que transfiere el control
del mecanismo de control del ms pequeo ciclo encerrado. Esta no esuna
salida sino ms bien una manera para saltar del resto de las sentencias del
ciclo en la actual iteracin sin terminar la estructura del ciclo. Por ejemplo,
considerar lo siguiente:
while (sum < 1000) {
getnext (valor);
if (valor < 0) continue;
sum += valor;
}
Un valor negativo causa la sentencia de asignacin para ser saltado, y el
control se transfiere en cambio al condicional en la cima del ciclo. Por otro lado,
en:
}
En esta sentencia, traverse es el iterador.
Las sentencias de iteracin definidas por el usuario son ms importantes en la
programacin orientada a objetos porque sus paradigmas fueron ms fciles de
desarrollar en software. Este resultado del hecho que el usuario ahora
rutinariamente construya tipos de datos abstractos para las estructuras de
datos. En tales casos, una sentencia de iteracin definida por el usuario y su
iterador deben ser provistos por el autor de la abstraccin de datos porque la
representacin de objetos en los tipos no son conocidas por el usuario. En C+
+, el iterador para el tipo definido por el usuario, o clases, son frecuentemente
implementadas como funciones amigas a las clases o como clases separadas
por el iterador.
8.5 Bifurcacin Incondicional
Una sentencias de bifurcacin incondicional transfiere el control de la ejecucin
a un lugar especficoen el programa.
8.5.1 Problemas con la Bifurcacin Incondicional
El ms acalorado debate en los diseos de los lenguajes de los ltimos 1960
fue sobre problema de si la bifurcacin incondicional debera ser parte de
cualquier lenguaje de alto nivel, y si as es, si su uso debera ser restringido.
La bifurcacin incondicional, o goto, es la sentencia ms poderosa para
controlar l flujo de la ejecucin de las sentencias de un programa. Sin embargo,
usando el goto descuidadamente puede dejar problemas. El goto tiene un
estupendo poder y gran flexibilidad (todas las otras estructuras de control
pueden ser construidas con goto y un seleccionador), pero su mucha fuerza
hace su uso peligroso. Sin restricciones en su uso, impuestos por los diseos
del lenguaje o los estndares de la programacin, las sentencias goto pueden
hacer programas virtualmente ilegibles, y como resultado, sumamente ilegibles
y difciles de mantener.
Estos problemas siguen directamente de la capacidad de un goto de forzar
cualquier sentencia del programa a seguir a cualquier otra en la secuencia de
ejecucin, sin tener en cuenta que si la sentencia precede o sigue el primer
tiempo de ejecucin ocurre que causa el termino del programa. Esto forza al
programador a considerar y listar todas las posibilidades, como con la
sentencia case de Ada. Considerar el siguiente ejemplo:
if i = 0 -> sum := sum +i
[] i > j -> sum := sum + j
[] j > I -> sum := sum + I
fi
Si i =0 y j > i, esta construccin escoge no indeterminadamente entre las
primera y tercera sentencias de asignacin. Si i es igual a j y no es cero, un
error en tiempo de ejecucin ocurre porque ninguna de las condiciones es
verdadera.
Esta construccin puede ser una manera elegante de permitir al programador
condicionar el orden de ejecucin, en algunos casos, es irrelevante. Por
ejemplo, hallar el ms largo de dos nmeros, podemos usar
if x >= y -> max := x
[] y >= x -> max := y
fi
Este cmputo deseado resulta sin sobre especificando la solucin. En
particular, si x y y son iguales, no importa que asignamos a max. Es una forma
de abstraccin proporcionada por la no determinada semntica de la sentencia.
Otra situacin en la cual la construccin de seleccin de Dijsktra es valiosa es
la siguiente: Supongamos que estamos escribiendo un programa que
interrumpe servicios, y el interruptor tiene la misma prioridad. Por esto,
necesitamos una construccin que elija entre interruptores actuales en algunos
maneras aleatorias.
La semntica de los comandos protegidos sondifciles de describir
precisamente. Aunque los diagramas de flujo no son buenas herramientas para
el diseo de programas, son algunas veces poderosas descripciones para las
semntica. La figura 8.1 es un diagrama de flujo describiendo la aproximacin
usada por la sentencia de seleccin de Dijkstra. Note que este diagrama de
flujo es relativamente impreciso, reflejando la dificultad en la captura de la
semntica de los comandos protegidos.
La estructura de ciclo proporcionada por Dijkstra tiene la forma
do ->
[] ->
[]
[] ->
od
La semntica de esta construccin es que todas las expresiones Boolean son
evaluadas en cada iteracin. Si ms de una es verdadera, una de las
sentencias asociadas es no determinadamente escogida por la ejecucin,
despus del cual la expresiones son evaluadas otra vez. Cuando todas las
expresiones son simultneamente falsa, el ciclo termina.
Considerar el siguiente cdigo, el cual aparece en forma ligeramente diferente
en Dijkstra (1975). Las cuatro variables q1, q2, q3, y q4 son para tener su valor
reorganizados para que q1 q3 -> temp := q2; q2 := q3; q3 := temp;
[] q3 > q4 -> temp := q3; q3 := q4; q4 := temp;
od
Un diagrama de flujo describiendo la aproximacin es usada las sentencias de
ciclo de Dijkstra es mostrada en la figura 8.2. Una vez ms, note que la
semntica del flujo de control de esta construccin no puede ser
completamente descripta en un diagrama de flujo.
Figura 8.1
Diagrama de Flujo
aproximado usado con
el seleccionador de
sentencias de Dijkstra
T
FT
Los comandos protegidos por Dijkstra, como estas dos construcciones son
conocidas, son interesante en parte porque ellas ilustran como la sintaxis y la
semntica de las sentencias puede tener un impacto en le verificacin del
programa, y viceversa. La verificacin del programa es virtualmente imposible
cuando las sentencias goto son usadas. La verificacin es muy simplificada si
solo los ciclos lgicos ciclos de seleccin, como los de Pascal, son usados, o los
comandos protegidos son usados. La semntica axiomtica de los comandos
protegidos es convenientemente especificada (Gries, 1981). Debera ser obvio,
sin embargo, aqu es considerablemente incrementada la complejidad en la
implementacin de los comandos protegidos sobre su complemento
determinado convencional.
8.6 Conclusiones
Figura 8.1
Diagrama de Flujo
aproximado usado con
sentencias de ciclo de
Dijkstra
todava que tomar este paso; adems, dudamos que todas manden debido al
efecto en la escritura y la legibilidad. Los programas escritos con una sola
seleccin y ciclos pre examinados lgicos son generalmente menos naturales
en estructura, ms complejos, y por lo tanto difciles de escribir y ms difciles
de leer. Por ejemplo, la estructura de seleccin mltiple de Ada es una gran
ganancia para la escritura de Ada, con claros negativos. Otro ejemplo es la
estructura de ciclo contadora de muchos lenguajes, especialmente cuando la
sentencia es simple, como en Pascal y Ada.
No es claro para qu la utilidad de muchas de las otras estructuras de control
que han sido propuestas es mrito de su inclusin en lenguajes (Ledgard y
Marcotty, 1975). Esta cuestin apoya a un largo grado en la cuestin
fundamental de si el tamao de los lenguajes debe ser minimizado. Ambos,
Wirth (1975) y Hoare (1973), fuertemente avalaron la simplicidad en el diseo
del lenguaje. En el caso de las estructuras de control, la simplicidad significa
que solo algunas sentencias de control deberan estar en el lenguaje, y todas
ellas deberan ser simples.
La rica variedad de niveles de sentencias deestructuras de control que han sido
inventadas muestran la diversidad de opiniones entre los diseadores del
lenguaje. Despus de todo el invento, la discusin, y la evaluacin, no hay
todava unanimidad de opinin en el preciso conjunto de sentencias de control
que deberan estar en un lenguaje. Muchos lenguajes contemporneos, por
supuesto, tienen sentencias de control similar, pero hay todava algunas
variaciones en los detalles de su sintaxis y semntica. Adems, hay todava
desacuerdo en si un lenguaje debera incluir un goto; C++ y Ada 95 lo hacen,
pero Java no.
Una nota final: Las estructuras de control de lenguajes de programacin
funcional y lgica y Smalltalk son todas bastante diferentes de estas descriptas
en este captulo. Estos mecanismos son discutidos en algunos detalles en el
Captulo 15, 16, y 12, respectivamente.
Resumen
Las sentencias de control de los lenguajes imperativos suceden en varias
categoras: seleccin, seleccin mltiple, iterativa, y bifurcacin incondicional.
FORTRAN introdujo un seleccionador de sentencia de una manera, el lgico IF.
El seleccionador de ALGOL 60 es ms avanzado, permitiendo la seleccin de
sentencias compuestas e incluyendo un clusula opcional else. Muchas
estructuras de control se beneficiaron de las sentencias compuestas que
ALGOL 60 introdujo.
El IF aritmtico de FORTRAN es seleccionador de tres maneras que usualmente
requiere otra bifurcacin incondicional.
FORTRAN introdujo dos formas de sentencias de seleccin mltiple: el calculado
GO TO y el asignado GO TO . Cierto a sus nombres, ambos son
actualmenteramificaciones de manera mltiple. El case de Pascal es
representativo de modernas sentencias de seleccin mltiple; incluye ambos,
encapsulacin de segmentos seleccionables y ramificaciones implcitas en el