Fundamentos de programación con Módula-2 (8)

 

3.5 Sentencia de asignación
 
Una forma de conseguir que una variable guarde un nuevo valor es mediante una sentencia de asignación. Esta sentencia es característica de la programación imperativa, y permite inicializar una variable o modificar el valor que tenía hasta el momento. Mediante asignaciones podremos dar valores iniciales determinados a las variables, o guardar en ellas los resultados intermedios o finales de cualquier programa.
 
La estructura de una sentencia de asignación es la siguiente:
 
Sentencia_de_asignación ::=
       Variable := Expresión
 
Variable ::= Identificador
 
Por el momento la única manera que se ha presentado de hacer referencia a una variable es usando su nombre. Más adelante se indicarán otras formas de hacer referencia a variables, especialmente en el caso de que la variable designada sea parte de una estructura de datos.
 
El símbolo := es el operador de asignación; está formado por esa pareja de caracteres y siempre se debe escribir exactamente en ese orden sin incluir espacios en blanco entre ellos.
 
Este operador indica que el resultado de la expresión de su derecha debe ser asignado a la variable cuyo identificador está a su izquierda. Por ejemplo, la secuencia de asignaciones siguiente:
 
              Area := 56.89;
              Base := 18;
 
sustituye los valores que tuvieran las variables Area y Base hasta ese momento por los nuevos valores 56.89 y 18, respectivamente.
 
Si intervienen variables en la expresión a la derecha de una sentencia de asignación, se usará el valor que tenga la variable en ese momento. Por ejemplo, la siguiente secuencia de asignaciones:
 
              Meses := 2;
              Dias := Meses;
              Meses := 7;
              Saldo := Meses;
 
dejará finalmente almacenados en las variables Meses, Dias y Saldo los valores 7, 2 y 7, respectivamente.
 
Un caso especial, que requiere cierta atención, es aquél en que a una variable se le asigna el valor de una expresión de la que forma parte la propia variable. Por ejemplo:
 
              Dias := Dias + 30;
 
Esta asignación recuerda a una ecuación, pero su significado es completamente diferente. Esta sentencia es una orden de evaluar primero la expresión a la derecha usando el valor que tenía la variable hasta ese momento, y luego modificar el valor de la variable almacenando en ella el resultado de la expresión. En este ejemplo, si la variable Dias tenía el valor 16, esta sentencia almacenará en ella el nuevo valor 46. En general, al ejecutar esta sentencia de asignación, el valor de la variable Dias se incrementará en 30 unidades.
 
3.5.1 Compatibilidad de tipos
Para que una sentencia de asignación sea válida es necesario que el tipo de la variable y el del resultado de la expresión sean compatibles. En caso contrario el compilador indicará que hay error, y será necesario modificar el programa antes de que se pueda ejecutar.
 
La compatibilidad de tipos en la asignación es un poco menos restrictiva que entre los operandos de una misma operación. Hay compatibilidad en asignación entre una variable y un valor de sus mismo tipo, pero además, con los tipos introducidos hasta este momento, es compatible realizar asignaciones de expresiones del tipo CARDINAL a variables INTEGER y viceversa.
 
Sin embargo, si en el momento de ejecutar la asignación se comprueba que el valor obtenido en la expresión no es un valor válido del tipo de la variable asignada, por ejemplo un valor negativo asignado a una variable de tipo CARDINAL, se producirá un error y se detendrá la ejecución del programa. En los temas próximos se indicarán más compatibilidades de tipos según se vayan introduciendo.
 
A continuación se indican algunos ejemplos de sentencias de asignación válidas, utilizando las constantes y variables declaradas en los apartados anteriores:
 
           Modelo := Codigo
           Saldo := Base                (*Compatib. INTEG./CARD. *)
           Dias := Meses * 30
           Volumen := Pi * Radio * Radio * FLOAT( Largo )
           Saldo := Meses * 50000 – TRUNC( Gastos )
           Codigo := "Z"
 
Para finalizar este apartado se presenta una declaración de variables y posteriormente una secuencia de sentencias de asignación. En el margen izquierdo se muestran los valores que guardan las variables antes y después de la ejecución de cada sentencia. Nótese que las variables tienen un valor indefinido hasta que son inicializadas asignándoles valor por primera vez.
 
Declaración:
                   VAR Posi : CARDINAL;
                         Dato : INTEGER;
                         EjeX, EjeY : REAL;
 
                                        Valores
      EjeX       EjeY             Dato        Posi          Secuencia de sentencias
        ?           ?                 ?             ?            EjeX := 34.89;
      34.89       ?                 ?             ?            Dato := 67;
      34.89       ?                67            ?            Posi := TRUNC(EjeX) + Dato;
      34.89       ?                67           101          Dato := TRUNC(EjeY) + Posi;
      34.89       ?                 ?            101          EjeY := EjeX + FLOAT(Posi);
      34.89     135.89           ?            101          Dato := Posi DIV 5;
      34.89     135.89           20           101         Posi := Posi MOD 5;
      34.89     135.89           20           1             Posi := Posi * Dato;
      34.89     135.89           20           20           EjeY := EjeY/EjeX;
      34.89     3.8948           20           20           EjeX := EjeX/2.0;
      17.44     3.8948           20           20           Posi := TRUNC(EjeY) – Posi;
                             Fin del Programa. Error de Ejecución *(La variable <Posi> no admite valores negativos)
 
 
3.6 Operaciones de lectura simple
 
Los programas presentados hasta el momento producen siempre el mismo resultado cada vez que se mandan ejecutar. Por ejemplo, con los elementos introducidos hasta ahora se podrían escribir programas para calcular la suma de los números del 4 al 45 o imprimir la nómina de Febrero del Sr. González. Programas que produzcan resultados fijos son poco habituales en la práctica. Bastaría ejecutarlos una sola vez, guardar los resultados impresos y reproducirlos (p.ej., fotocopiándolos) tantas veces como se necesiten.
 
Los programas habituales suelen resolver problemas genéricos. Por ejemplo, obtener la suma de N números desde uno inicial a otro final, o el calcular cada mes la nómina de cada uno de los empleados de una empresa. Un programa que produzca cada vez resultados diferentes deberá operar en cada caso a partir de unos datos distintos, y dichos datos no pueden ser, por tanto, valores constantes que formen parte del programa.
 
Para resolver cada vez el problema concreto que se plantea, el programa debe leer como datos de entrada los valores concretos a partir de los cuales hay que obtener el resultado. Por ejemplo, los valores inicial y final de la serie de números a sumar, o el nombre del empleado cuya nómina se quiere calcular y el mes al que corresponde. Por consiguiente, las operaciones de lectura son fundamentales dentro de cualquier modelo de programación.
 
En Modula-2, los datos leídos han de ser guardados inmediatamente en variables del programa. Por tanto, otra manera de asignar un valor a una variable es almacenar en ella un valor introducido desde el exterior del computador mediante el teclado u otro dispositivo de entrada de datos.
 
Las operaciones de lectura, al igual que las de escritura, pueden presentar grandes diferencias dependiendo del dispositivo utilizado. Pero, también en este caso, existe en Modula-2 un conjunto de procedimientos generales para la lectura de datos, que son invocados siempre de la misma manera, con independencia del dispositivo de entrada utilizado. Por defecto, el dispositivo de entrada suele estar asociado al teclado del terminal por el que se accede al computador. Estos procedimientos están incluidos también en los módulos InOut y RealInOut.
 
Los datos a leer se suministran externamente en forma de texto, es decir, como una serie de caracteres seguidos (o pulsaciones de teclas) que pueden incluir saltos de línea de vez en cuando. El salto de línea corresponde a la tecla marcada ‘INTRO’ o ‘<—|’ (en teclados ingleses, ‘RETURN’ o ‘ENTER’).
 
3.6.1 Procedimientos ReadInt, ReadCard y ReadReal
Los procedimientos ReadInt y ReadCard pertenecen al módulo InOut. El procedimiento ReadReal pertenece al módulo RealInOut. Para ordenar que se ejecuten estos procedimientos se debe escribir:
 
            ReadInt( Variable_entera )
            ReadCard( Variable_cardinal )
            ReadReal( Variable_real )
 
Cada uno de estos procedimientos lee la representación de un valor numérico, que sea válida según las reglas de Modula-2 (descritas en el tema anterior) para la representación de valores constantes del tipo concreto que corresponda: INTEGER, CARDINAL o REAL, respectivamente. A continuación asigna el valor leído a la variable que se indica.
 
El valor introducido puede ir precedido de todos los espacios en blanco o saltos de línea que se quiera antes del primer carácter válido de la representación del valor: más (+), menos (-) o dígito, según los casos. A continuación se irán leyendo los sucesivos caracteres del dato numérico, hasta leer un espacio en blanco o un salto de línea, que marcarán el final del valor leído.
 
Por ejemplo, la sentencia:
 
             ReadInt( Dias );
 
tomará caracteres del dispositivo de entrada hasta completar la representación de un valor entero, asignará dicho valor a la variable Dias. Si los datos de entra son:
 
        123456
 
se consumirá la parte del texto "123", se asignará el valor 123 a la variable Dias, y quedará disponible para la siguiente lectura el resto de los datos "456".
 
Normalmente una lectura se ejecuta inmediatamente después de una escritura en la que se indica qué dato es el que se solicita en cada momento. Por ejemplo:
 
               WriteString( "¿Cantidad Pendiente ? " );
               ReadInt( Saldo );
 
después de la ejecución del procedimiento de escritura el computador interroga de la siguiente forma:
 
              ¿CantidadPendiente?_
 
y se queda a la espera para ejecutar el procedimiento de lectura. El símbolo (_) se utiliza aquí para indicar la posición del cursor en la pantalla, en espera de la entrada del dato solicitado.
 
Cuando se espera información por el teclado es ventajoso que se pueda corregir el texto que se va tecleando en caso de cometer errores. Para ello la lectura de teclado se suele hacer por líneas completas; mientras se teclea el texto de una línea se pueden hacer correcciones, y al pulsar la tecla de fin de línea el texto se acepta y se procesa como dato de entrada. El texto aparece en la pantalla al mismo tiempo que se va tecleando o corrigiendo. Todo esto es automático, y se hace directamente al invocar los procedimientos de lectura de Modula-2.
 
En el ejemplo anterior, se tecleará el dato acabando con un fin de línea, que representaremos como <INTRO>:
 
             ¿CantidadPendiente?-45768<INTRO>
 
Al pulsar <INTRO> el cursor pasará a la siguiente línea, se procesará el dato de entrada, y a la variable Saldo se le queda asignado el nuevo valor -45768. Si se quiere introducir más de un valor con la misma pregunta y en la misma línea se puede utilizar como separador de datos el espacio en blanco (). Por ejemplo:
 
             WriteString( "¿Cantidad Pendiente y Gastos ? " );
             ReadInt( Saldo );
             ReadReal( Gastos );
 
y después de teclear los datos separados por uno o varios blancos y acabados con un <INTRO>:
 
            ¿Cantidad Pendiente y Gastos?-45768+10456.5<INTRO>
_
 
queda el cursor en la línea siguiente, la variable Saldo con el valor -45768 y la variable Gastos con valor 10456.5. En este caso el espacio en blanco intermedio indica que ha finalizado la introducción del primer valor y se pasa a ejecutar el siguiente procedimiento de lectura desde la última posición del cursor en el espacio en blanco intermedio. La ejecución del segundo procedimiento de lectura acaba con el <INTRO>.
 
Por tanto, los procedimientos de lectura comienzan analizando los datos introducidos desde la posición última del cursor y separan cada valor numérico del siguiente cuando encuentran o espacioes en blanco o finales de línea.
 
3.6.2 Procedimiento Read
El procedimiento Read pertenece al módulo InOut. Para ordenar que se ejecute se debe escribir:
 
               Read( Variable_Carácter )
 
El procedimiento Read lee el primer carácter introducido desde la última posición del cursor anteriormente analizada y lo guarda en la variable indicada. En este caso cualquier carácter es válido, incluyendo los signos de puntuación, los espacios en blanco, o el carácter de salto de línea.
 
Por ejemplo la ejecución de la secuencia de sentencias:
 
              ReadReal(Volumen);
              Read(Modelo);
              Read(Codigo);
              ReadCard(Base);
              ReadInt(Dias);
 
con los siguientes datos:
 
              23456.85E-3<INTRO>
              -5678<INTRO>
              27<INTRO>
              _
asigna a cada variable los valores siguientes:
 
              Variable                               Valor
              Volumen                              23.45685
              Modelo                                ""
              Codigo                                 "-"
              Base                                  5678
              Dias                                    27
 
 
3.7 Estructura de un programa con constantes y variables
 
Antes de realizar nuevos programas es necesario saber dónde se sitúan dentro del programa los nuevos elementos introducidos en este tema. Las declaraciones de valores constantes y de las variables forman parte del bloque del programa. Por tanto, ahora la estructura del bloque es la siguiente:
 
             Bloque ::= Parte_declarativa Parte_ejecutiva END
             Parte_declarativa ::= { Declaración }
             Declaración ::=
                    Declaración_de_constantes | Declaración_de_variables
             Parte_ejecutiva ::= BEGIN Secuencia_de_sentencias
             Secuencia_de_sentencias ::= Sentencia { Sentencia ; }
 
La parte declarativa es opcional y siempre está delante de la parte ejecutiva. Hasta este momento sólo forman parte de la parte declarativa la declaración de constantes y variables, que pueden ser declaradas en cualquier orden.
 
Las sentencias de asignación y los procedimientos de lectura siempre forman parte de la secuencia de sentencias.
 
 
3.8. Ejemplos de programas
 
A continuación se realizan varios programas con los nuevos conceptos introducidos.
 
3.8.1 Ejemplo: Conversión a horas, minutos y segundos
 
En este ejemplo se trata de convertir a horas, minutos y segundos una cierta cantidad de tiempo expresada en segundos. La variable Segundos se utilizará para leer la cantidad total de segundos y posteriormente para ir guardando los segundos restantes al quitar los segundos ya convertidos a horas y minutos. El listado del programa es el siguiente:
 
MODULE HoraMinutoSeg;
   FROM InOut IMPORT
      WriteString, WriteLn, WriteInt, ReadInt;
 
   VAR Hora, Minutos, Segundos : INTEGER;
 
(* Conversión a Hora, Minutos y Segundos de los segundos introducidos como dato *)
 
BEGIN
   WriteString( "¿Segundos Totales ?" );
   ReadInt( Segundos );
   WriteLn;
   Hora := Segundos DIV 3600;
   Segundos := Segundos MOD 3600;
   Minutos := Segundos DIV 60;
   Segundos := Segundos MOD 60;
   WriteString("Equivalen a ");
   WriteInt(Hora, 2);
   WriteString( horas, ");
   WriteInt(Minutos, 2);
   WriteString( min. y ");
   WriteInt(Segundos, 2);
   WriteString(" seg.");
   WriteLn;
END HoraMinutoSeg.
 
La ejecución del programa introduciendo como dato 23459 segundos es la siguiente:
 
¿Segundos Totales ?23459
Equivalen a 6 horas, 30 min. y 59 seg.
 
3.8.2 Ejemplo: Área y volumen de un cilindro
En este ejemplo se desarrolla un programa para el cálculo del área y el volumen de un cilindro genérico. Esto es posible gracias a los procedimientos de entrada de datos y al empleo de variables. Además se declara como constante el valor de (pi) lo que evita tenerlo que escribir dos veces y los posibles errores de escritura. El programa así realizado es más general y más fácil de comprender y modificar. El listado del programa es el siguiente:
 
MODULE AreaVolumenCilindro;
   FROM InOut IMPORT WriteString, WriteLn;
   FROM RealInOut IMPORT ReadReal, WriteReal;
 
   CONST PI = 3.141592;
   VAR Radio, Altura, Area, Volumen : REAL;
 
(* Calculo del área y el volumen de un cilindro *)
 
BEGIN
   WriteString("¿Radio del Cilindro ?");
   ReadReal(Radio);
   WriteLn;
   WriteString("¿Altura del Cilindro ?");
   ReadReal(Altura);
   WriteLn;
   Area := 2.0*PI*Radio*(Radio+Altura);
   Volumen := PI*Radio*Radio*Altura;
   WriteString("El Area es igual a: ");
   WriteReal(Area, 15);
   WriteLn;
   WriteString("y su Volumen es igual a: ");
   WriteReal(Volumen, 15);
   WriteLn;
END AreaVolumenCilindro.
 
La ejecución del programa introduciendo como valor del radio 12.5 y como altura 72.65 produce el siguiente resultado:
 
¿Radio del Cilindro ?12.5
¿Altura del Cilindro ?72.65
El Area es igual a: 0.668766259E+04
y su Volumen es igual a: 0.356619687E+05
 
3.8.3 Ejemplo: Realización de un recibo
En este ejemplo se trata de realizar un recibo sencillo, correspondiente a la compra de unos equipos. Como datos habrá que introducir el tipo de equipo, indicando mediante un código de un carácter; la cantidad de equipos; el precio unitario, y el tipo de IVA aplicado.
 
Los subtotales y totales siempre se darán en Pts enteras sin céntimos. Para no perder precisión, el cálculo de las Pts de IVA se realizará como un valor REAL. Este valor se truncará antes de imprimir el recibo.
 
El listado del programa completo esta recogido a continuación de la ejecución del mismo.
 
A continuación se muestra un ejemplo de la ejecución del programa, presentando los resultados escritos junto a los datos leídos.
 
¿Tipo de Equipos ?A
¿Cantidad ?12
¿Precio Unitario ?2345
¿% IVA Aplicado ?15
 
              RECIBO de COMPRA
 
Cantidad    Concepto       Pts/unidad    Total
 
    12        Equipos: A        2345          28140
                                 15 % IVA          4221
 
                                 TOTAL            32361
 
 
MODULE Recibo;
   FROM InOut IMPORT
      Write, WriteString, WriteLn, WriteInt, Read, ReadInt;
   VAR
      Cantidad, Precio, IVA, SubTotal : INTEGER;
      Total, PtsIva : REAL; Tipo : CHAR;
 
   (* Cálculo e impresión de un Recibo *)
 
BEGIN
   WriteString("¿Tipo de Equipos ?");
   Read(Tipo); Write(Tipo);
   WriteLn;
   WriteString("¿Cantidad ?");
   ReadInt(Cantidad);
   WriteLn;
   WriteString("¿Precio Unitario ?");
   ReadInt(Precio);
   WriteLn;
   WriteString("¿% IVA Aplicado ?");
   ReadInt(IVA);
   WriteLn; WriteLn;
   SubTotal := Cantidad * Precio;
   PtsIva := FLOAT(SubTotal) * FLOAT(IVA) / 100.0;
   Total := FLOAT(SubTotal) + PtsIva;
   WriteString("       RECIBO de COMPRA");
   WriteLn; WriteLn;
   WriteString("Cantida    Concepto      Pts/unidad    Total");
   WriteLn; WriteLn;
   WriteInt(Cantidad, 5);
   WriteString("       Equipos:");
   Write(Tipo);
   WriteInt(Precio, 10);
   WriteInt(SubTotal, 12);
   WriteLn;
   WriteInt(IVA, 26);
   WriteString(" % IVA ");
   WriteInt(TRUNC(PtsIva), 10);
   WriteLn; WriteLn;
   WriteString("                               TOTAL");
   WriteInt(TRUNC(Total), 14);
   WriteLn; WriteLn;
END Recibo.
Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s