1 of 34

Lenguajes de Programación I

Parcial 2022

Ejercicio 3 – Semántica Lenguaje Color

2 of 34

Dado el siguiente programa en el lenguaje Color del ejercicio anterior, sin errores de compilación, que se ejecuta correctamente:

  • Las variables de tipo entero ocupan más espacio que los punteros.
  • Los RA de las funciones RO, VI y AM tienen el mismo tamaño, y son más grandes que los RA de las funciones AZ y VE.
  • El RA de la función AZ tiene el tamaño de sus cadenas solamente, mientras que el de VE ocupa además el tamaño de un puntero.
  • El lenguaje implementa el PP por nombre usando reemplazo textual y el PP por referencia usando punteros.

3 of 34

1

2

3

4

5

6

7

8

9

1011

12

13

14

15

16

17

18

19

20

21

22

23

negro int a=0;

negro int i_loop=0;

negro double c= 2.5;

int RO(rojo int ro){

print (“La dirección de ro es: %d y su valor es %d“,&ro, ro);

ro<-1000;

}

int AZ(azul int az){

print (“La dirección de az es: %d y su valor es %d“,&az, az);

az<-2000;

}

int VI(violeta int vi){

print (“La dirección de vi es: %d y su valor es %d“,&vi, vi);

vi<-3000;

}

int VE(verde int ve){

print (“La dirección de ve es: %d y su valor es %d“,&ve, ve);

ve<-4000;

}

int AM(amarillo int am){

print (“La dirección de am es: %d y su valor es %d“,&am, am);

am<-5000;

}

4 of 34

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

int primera(){

int a=25;

blanco int[] numeros= [1, 2, 3, 4, 5];

print (“La dirección de numeros[0] es %d“,&numeros[0]);

numeros <- [10, 25, 40, 55, 75, 100, 112, 126, 128];

print (“La dirección de numeros[0] es %d“,&numeros[0]);

print (“La dirección de a es %d“,&a);

RO(a);

print (“El valor de a es %d“,a);

AZ(a);

print (“El valor de a es %d“,a);

VI(a);

print (“El valor de a es %d“,a);

VE(a);

print (“El valor de a es %d“,a);

AM(a);

print (“El valor de a es %d“,a);

}

42

43

44

45

46

47

48

49

50

float recursiva(amarillo int b5){

negro double x=b5;

x<-b5+c;

print (“La dirección de x es: %d“,&x);

while(i_loop<3){

i_loop<-i_loop+1;

recursiva(b5);

}

}

5 of 34

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

int main (){

int b=10;

double d;

print(“Direcciones: a=%d b=%d c=%d d=%d”, &a, &b, &c, &d);

primera();

recursiva(b);

b:=a;

a<-8;

if (b==a) { print(“a y b son iguales”); }

else { print(“a y b son distintas”); }

d<-c;

c<-7.9;

if (c==d) { print(“c y d son iguales”); }

else { print(“c y d son distintas”); }

}

6 of 34

SALIDA

Direcciones: a=-5000 b=300 c=-5004 d=304

La dirección de numeros[0] es 1284300

La dirección de numeros[0] es 1284314

La dirección de a es 318

La dirección de ro es: 330 y su valor es 25

El valor de a es 25

La dirección de az es: -5000 y su valor es 0

El valor de a es 25

La dirección de vi es: 330 y su valor es 4941284

El valor de a es 3000

La dirección de ve es: 318 y su valor es 3000

El valor de a es 4000

La dirección de am es: 330 y su valor es 4000

El valor de a es 5000

La dirección de x es: -5008

La dirección de x es: -5008

La dirección de x es: -5008

La dirección de x es: -5008

a y b son iguales

c y d son distintas

7 of 34

  1. Completar en el cuadro, la semántica para cada elemento de la gramática según corresponda de: pasaje de parámetros | tipo de almacenamiento | tipo de asignaciones. Fundamentar brevemente las respuestas

Elemento de la gramática

Semántica

negro

blanco

rojo

azul

violeta

verde

amarillo

:=

<-

8 of 34

4. ?declaracionvar: almacenamiento tipo id | almacenamiento tipo id "=" expresion | tipo id | tipo id "=" expresion

5. ?almacenamiento : "negro" | "blanco"

1

2

3

negro int a=0;

negro int i_loop=0;

negro double c= 2.5;

24

25

26

27

28

29

30

int primera(){

int a=25;

blanco int[] numeros= [1, 2, 3, 4, 5];

print (“La dirección de numeros[0] es %d“,&numeros[0]);

numeros <- [10, 25, 40, 55, 75, 100, 112, 126, 128];

print (“La dirección de numeros[0] es %d“,&numeros[0]);

}

42

43

44

45

46

47

48

49

50

float recursiva(amarillo int b5){

negro double x=b5;

x<-b5+c;

print (“La dirección de x es: %d“,&x);

while(i_loop<3){

i_loop<-i_loop+1;

recursiva(b5);

}

}

9 of 34

main->primera-> COLORES -> recursiva->recursiva->recursiva->recursiva

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

int main (){

int b=10;

double d;

print(“Direcciones: a=%d b=%d c=%d d=%d”, &a, &b, &c, &d);

primera();

recursiva(b);

b:=a;

a<-8;

if (b==a) { print(“a y b son iguales”); }

else { print(“a y b son distintas”); }

d<-c;

c<-7.9;

if (c==d) { print(“c y d son iguales”); }

else { print(“c y d son distintas”); }

}

main

b,d

recursiva

negro x

global

negro: a, i_loop, c

primera

a, blanco numeros

10 of 34

SALIDA

Direcciones: a=-5000 b=300 c=-5004 d=304

La dirección de numeros[0] es 1284300

La dirección de numeros[0] es 1284314

La dirección de a es 318

La dirección de ro es: 330 y su valor es 25

El valor de a es 25

La dirección de az es: -5000 y su valor es 0

El valor de a es 25

La dirección de vi es: 330 y su valor es 4941284

El valor de a es 3000

La dirección de ve es: 318 y su valor es 3000

El valor de a es 4000

La dirección de am es: 330 y su valor es 4000

El valor de a es 5000

La dirección de x es: -5008

La dirección de x es: -5008

La dirección de x es: -5008

La dirección de x es: -5008

a y b son iguales

c y d son distintas

11 of 34

a(global) -5000

c(global) -5004

x(recursiva) -5008

main

b,d

recursiva

negro x

global

negro: a, i_loop, c

primera

a, blanco numeros

numeros[0] (primera)

1284300

numeros[0] (primera)

1284314

b(main)

300

d(main)

304

a(primera)

318

param. formal(RO, VI, AM)

330

12 of 34

a(global) -5000

c(global) -5004

x(recursiva) -5008

main

b,d

recursiva

negro x

global

negro: a, i_loop, c

primera

a, blanco numeros

numeros[0] (primera)

1284300

numeros[0] (primera)

1284314

b(main)

300

d(main)

304

a(primera)

318

param. formal(RO, VI, AM)

330

negro: están en la misma sección a pesar de haber sido declaradas en ámbitos distintos

13 of 34

SALIDA

La dirección de x es: -5008

La dirección de x es: -5008

La dirección de x es: -5008

La dirección de x es: -5008

42

43

44

45

46

47

48

49

50

float recursiva(amarillo int b5){

negro double x=b5;

x<-b5+c;

print (“La dirección de x es: %d“,&x);

while(i_loop<3){

i_loop<-i_loop+1;

recursiva(b5);

}

}

2

negro int i_loop=0;

main

recursiva

recursiva

recursiva

recursiva

Si existiese una x por cada invocación de recursiva, no tendría siempre la misma dirección

14 of 34

Elemento de la gramática

Semántica

negro

almacenamiento estático:

-a, c y x se encuentran en la misma sección de memoria a pesar de haber sido declaradas en ámbitos distintos

-x se encuentra una única vez en memoria a pesar de existir cuatro invocaciones recursivas de la función que la contiene

Respuesta completa:

Justificaciones incompletas:

“se encuentran en direcciones -500X”

“se encuentran muy abajo en la pila”

15 of 34

24

25

26

27

28

29

30

int primera(){

int a=25;

blanco int[] numeros= [1, 2, 3, 4, 5];

print (“La dirección de numeros[0] es %d“,&numeros[0]);

numeros <- [10, 25, 40, 55, 75, 100, 112, 126, 128];

print (“La dirección de numeros[0] es %d“,&numeros[0]);

}

numeros[0] (primera)

1284300

numeros[0] (primera)

1284314

números cambia de tamaño en la misma ejecución de primera

-El RA no puede cambiar de tamaño, por lo que no se encuentra dentro del RA.

-Las direcciones muestran que los datos de números se encuentran en una sección distinta de memoria

-El cambio de dirección del elemento 0 del arreglo indica que el arreglo se alojó en otro espacio de memoria al cambiar de tamaño.

Es el comportamiento de una variable con almacenamiento dinámico (con nombre)

16 of 34

Elemento de la gramática

Semántica

blanco

almacenamiento dinámico (con nombre):

-la variable numeros cambió de tamaño en la misma ejecución de primera

-la variable numeros se movió en memoria (en el heap) en la misma ejecución de primera

Respuesta completa:

Justificaciones incompletas:

“se encuentran en direcciones 1284XXX”

“se encuentran muy arriba en la pila (heap)”

17 of 34

4

5

6

7

8

9

1011

12

13

14

15

16

17

18

19

20

21

22

23

int RO(rojo int ro){

print (“La dirección de ro es: %d y su valor es %d“,&ro, ro);

ro<-1000;

}

int AZ(azul int az){

print (“La dirección de az es: %d y su valor es %d“,&az, az);

az<-2000;

}

int VI(violeta int vi){

print (“La dirección de vi es: %d y su valor es %d“,&vi, vi);

vi<-3000;

}

int VE(verde int ve){

print (“La dirección de ve es: %d y su valor es %d“,&ve, ve);

ve<-4000;

}

int AM(amarillo int am){

print (“La dirección de am es: %d y su valor es %d“,&am, am);

am<-5000;

}

Cada función imprime dirección y valor de parámetro formal y le cambia el valor

18 of 34

24

25

30

31

32

33

34

35

36

37

38

39

40

41

int primera(){

int a=25;

print (“La dirección de a es

RO(a);

print (“El valor de a es %d“,a);

AZ(a);

print (“El valor de a es %d“,a);

VI(a);

print (“El valor de a es %d“,a);

VE(a);

print (“El valor de a es %d“,a);

AM(a);

print (“El valor de a es %d“,a);

}

Se llama a cada función con a como parámetro real.

Al volver, se imprime el valor de a local. Esto nos va a servir para ver si fue modificada

a(primera)

318

19 of 34

  • Las variables de tipo entero ocupan más espacio que los punteros.
  • Los RA de las funciones RO, VI y AM tienen el mismo tamaño, y son más grandes que los RA de las funciones AZ y VE.
  • El RA de la función AZ tiene el tamaño de sus cadenas solamente, mientras que el de VE ocupa además el tamaño de un puntero.
  • El lenguaje implementa el PP por nombre usando reemplazo textual y el PP por referencia usando punteros.

RO VI y AM almacenan el parámetro formal (alguna variante de copia)

AZ no almacena parámetro formal (nombre usando reemplazo textual)

VE tiene un puntero (referencia usando punteros)

20 of 34

4

5

6

7

int RO(rojo int ro){

print (“La dirección de ro es: %d y su valor es %d“,&ro, ro);

ro<-1000;

}

a(primera)

318 (valor 25)

SALIDA

La dirección de ro es: 330 y su valor es 25

El valor de a es 25

Se copió el valor al llamar a la función

El parámetro formal existe en memoria

No se copió el valor al finalizar la ejecución de la función

COPIA VALOR

21 of 34

8

9

10

11

int AZ(azul int az){

print (“La dirección de az es: %d y su valor es %d“,&az, az);

az<-2000;

}

a(primera)

318 (valor 25)

SALIDA

La dirección de az es: -5000 y su valor es 0

El valor de a es 25

El parámetro formal no existe en memoria (se está usando a global)

NOMBRE

1

negro int a=0;

a(global) -5000

Al finalizar la ejecución, la a local de primera() no se modificó

22 of 34

12

13

14

15

int VI(violeta int vi){

print (“La dirección de vi es: %d y su valor es %d“,&vi, vi);

vi<-3000;

}

a(primera)

318 (valor 25)

SALIDA

La dirección de vi es: 330 y su valor es 4941284

El valor de a es 3000

No se copió el valor al llamar a la función (se lee un valor basura)

El parámetro formal existe en memoria

Se copió el valor al finalizar la ejecución de la función

COPIA RESULTADO

23 of 34

16

17

18

19

int VE(verde int ve){

print (“La dirección de ve es: %d y su valor es %d“,&ve, ve);

ve<-4000;

}

a(primera)

318 (valor 3000)

SALIDA

La dirección de ve es: 318 y su valor es 3000

El valor de a es 4000

Se lee el valor del parámetro real

El parámetro formal está referenciando al real

Se modificó directamente el valor del parámetro real

REFERENCIA

24 of 34

20

21

22

23

int AM(amarillo int am){

print (“La dirección de am es: %d y su valor es %d“,&am, am);

am<-5000;

}

a(primera)

318 (valor 4000)

SALIDA

La dirección de am es: 330 y su valor es 4000

El valor de a es 5000

Se copió el valor al llamar a la función

El parámetro formal existe en memoria

Se copió el valor al finalizar la ejecución de la función

COPIA VALOR RESULTADO

25 of 34

51

52

53

57

58

59

60

61

62

63

64

65

int main (){

int b=10;

double d;

b:=a;

a<-8;

if (b==a) { print(“a y b son iguales”); }

else { print(“a y b son distintas”); }

d<-c;

c<-7.9;

if (c==d) { print(“c y d son iguales”); }

else { print(“c y d son distintas”); }

}

1

3

negro int a=0;

negro double c= 2.5;

Al cambiar el valor de a, se cambia también el de b. Ambos nombres de variable quedaron ligados a la misma celda de memoria -> Asignación por referencia

Al cambiar el valor de c, no se modifica el de d. Ambos nombres de variable son independientes -> Asignación por copia

26 of 34

b) Indique si cada afirmación es verdadera o falsa, justificando todas sus respuestas. En caso de ser verdadera, justificar indicando en qué líneas del programa se denotan las características indicadas:

  1. El lenguaje posee binding de ámbito dinámico.

27 of 34

negro int a=0;

int AZ(azul int az){

print (“La dirección de az es: %d y su valor es %d“,&a, a);

az<-2000;

}

int primera(){

int a=25;

print (“La dirección de a es %d“,&a);

RO(a);

print (“El valor de a es %d“,a);

AZ(a);

print (“El valor de a es %d“,a);

VI(a);

print (“El valor de a es %d“,a);

VE(a);

print (“El valor de a es %d“,a);

AM(a);

print (“El valor de a es %d“,a);

}

Si se usara esta var. a (última que se declaró), el alcance sería dinánico

Como se usa esta var. a (al alcance léxico/sintáctico), el alcance es estático

28 of 34

b) Indique si cada afirmación es verdadera o falsa, justificando todas sus respuestas. En caso de ser verdadera, justificar indicando en qué líneas del programa se denotan las características indicadas:

  • El lenguaje posee binding de ámbito dinámico.

Falso. El lenguaje posee binding de ámbito (alcance) estático, debido a que la función AZ, cuando es llamada con el parámetro a, utiliza la var. a global (que está a su alcance léxico), y no la var. a declarada en primero, que fue la última declarada. (Esta última sería la situación si el binding de alcance fuese dinámico)

Otra posible justificación: Porque utiliza registros de activación

29 of 34

ii. La variable x sólo existe en memoria en los momentos en que está al alcance.

Falso. Por tener almacenamiento estático (negro), la variable x existe en memoria durante toda la ejecución del programa.

Por estar declarada dentro de recursiva(), sólo está al alcance durante la ejecución de recursiva().

42

43

44

45

46

47

48

49

50

float recursiva(amarillo int b5){

negro double x=b5;

x<-b5+c;

print (“La dirección de x es: %d“,&x);

while(i_loop<3){

i_loop<-i_loop+1;

recursiva(b5);

}

}

30 of 34

iv. Durante la ejecución del programa, existen en memoria tres copias de la variable x declarada en recursiva().

Falso. Por tener almacenamiento estático (negro), existe una única copia de la variable x en memoria en la ejecución del programa. Esto se puede ver en la impresión de la dirección de x

42

43

44

45

46

47

48

49

50

float recursiva(amarillo int b5){

negro double x=b5;

x<-b5+c;

print (“La dirección de x es: %d“,&x);

while(i_loop<3){

i_loop<-i_loop+1;

recursiva(b5);

}

}

SALIDA

La dirección de x es: -5008

La dirección de x es: -5008

La dirección de x es: -5008

La dirección de x es: -5008

31 of 34

iii. El lenguaje no necesita variables auxiliares para calcular la expresión b5+c (línea 44).

Falso. Para resolver una expresión va a ser necesaria sí o sí una variable auxiliar. Además, como b5 y c tienen tipos distintos, alguna se debe convertir al otro tipo (usando una variable auxiliar).

42

43

44

45

46

47

48

49

50

float recursiva(amarillo int b5){

negro double x=b5;

x<-b5+c;

print (“La dirección de x es: %d“,&x);

while(i_loop<3){

i_loop<-i_loop+1;

recursiva(b5);

}

}

3

negro double c= 2.5;

32 of 34

v. El lenguaje realiza conversiones implícitas entre los tipos numéricos.

Verdadero. En las líneas 43 y 44 se realizan asignaciones entre tipos distintos sin ninguna conversión explícita. Como el programa compila y ejecuta correctamente, esa conversión la está realizando el lenguaje implícitamente

42

43

44

45

46

47

48

49

50

float recursiva(amarillo int b5){

negro double x=b5;

x<-b5+c;

print (“La dirección de x es: %d“,&x);

while(i_loop<3){

i_loop<-i_loop+1;

recursiva(b5);

}

}

3

negro double c= 2.5;

33 of 34

vi. En la expresión b5+c;(línea 44) se accede al valor de todas las variables por la cadena dinámica.

Falso. NUNCA se accede a las variables por la cadena dinámica.

En este caso, al ser “c” una var. estática, se accede directo a través de su dirección, y al ser “b5” una variable local, se accede con el offset dentro del RA.

42

43

44

45

46

47

48

49

50

float recursiva(amarillo int b5){

negro double x=b5;

x<-b5+c;

print (“La dirección de x es: %d“,&x);

while(i_loop<3){

i_loop<-i_loop+1;

recursiva(b5);

}

}

3

negro double c= 2.5;

34 of 34

vi. El RA de primera() cambia de tamaño durante la ejecución de la función ya que contiene un arreglo que cambia de tamaño.

Falso. Los RA no pueden cambiar de tamaño.

Al ser “números” una variable dinámica con nombre, en el RA sólo está su descriptor. Los datos están almacenados en el heap, y es ahí donde la variable crece o cambia de lugar, no en el RA.

24

25

26

27

28

29

int primera(){

int a=25;

blanco int[] numeros= [1, 2, 3, 4, 5];

print (“La dirección de numeros[0] es %d“,&numeros[0]);

numeros <- [10, 25, 40, 55, 75, 100, 112, 126, 128];

print (“La dirección de numeros[0] es %d“,&numeros[0]);