CAPITULO 2

 

FUNDAMENTOS DEL LENGUAJE
OBJECT PASCAL

 

 

TIPOS DE DATOS

 

Cuando se escribe un programa, se trabaja con información que generalmente pertenece a uno de cinco tipos básicos: enteros, números reales, caracteres y cadenas, booleanos (lógicos) y apuntadores.

 

 

Tipos de datos enteros

 

A continuación se listan los tipos de datos enteros implementados por el compilador de Delphi :

 

 

Tipo                            Rango                 Formato

Tipos Genericos :

Integer       –2147483648..2147483647           signed 32-bit

Cardinal                0..4294967295         unsigned 32-bit

 

Tipos Basicos :

Shortint                    –128..127            signed 8-bit

Smallint                –32768..32767           signed 16-bit

Longint       –2147483648..2147483647           signed 32-bit

Int64                   –2^63..2^63–1           signed 64-bit

Byte                           0..255          unsigned 8-bit

Word                         0..65535         unsigned 16-bit

Longword                0..4294967295         unsigned 32-bit

 

 

Los tipos genericos Integer y Cardinal corresponden a los tipos basicos LongInt y Longword respectivamente.

 

La función High retorna el maximo valor permitido en el rango del tipo del argumento. Asi High(Word) retorna 65535.

 

Object Pascal permite usar notación hexadecimal (base 16) para valores enteros. Para especificar una constante en formato hexadecimal, anteponga un signo de pesos ($). Por ejemplo, $A7 representa el valor 167 en Haxadecimal.

 

 

Tipos de datos reales

 

Un tipo de dato real es una representación en punto­flotante consistente de un valor significativo (porción fraccional) multiplicada por un exponente (potencia de 10).

 

 

Tipo         Rango                           Dígitos  Tamaño en

                                      Significativos      bytes

Real         5.0 x 10^–324 .. 1.7 x 10^308     15–16          8

 

Real48       2.9 x 10^–39 .. 1.7 x 10^38       11–12          6

Single       1.5 x 10^–45 .. 3.4 x 10^38         7–8          4

Double       5.0 x 10^–324 .. 1.7 x 10^308     15–16          8

Extended     3.6 x 10^–4951 .. 1.1 x 10^4932   19–20         10

Comp         –2^63+1 .. 2^63 –1                19–20          8

Currency     –922337203685477.5808 ..          19–20          8

             922337203685477.5807

 

 

El tipo generico Real se corresponde con el tipo Double.

Los tipos Real48 y Comp son mantenidos por compatibilidad con anteriores versiones del compilador.

 

Currency es una representacion de punto fijo que minimiza los problemas de redondeo al operar sobre valores monetarios.

 

 

Tipos de datos caracteres y cadenas

 

Ya se ha visto cómo almacenar valores númericos en Pascal, ahora veamos cómo almacenar caracteres y cadenas (conjuntos de caracteres). Pascal ofrece el tipo predefinido char (carácter) que tiene por tamaño un byte y contiene exactamente un carácter. Caracteres constantes se representan encerrándolos entre comillas simples (apóstrofes), por ejemplo 'A', 'e', '&', '2'. Note que '2' representa el carácter "2", mientras que 2 representa el entero 2 (y 2.0 representa el número real 2). Note además que 'E' no es lo mismo que 'e'. Esto debido a que en el código ASCII tienen un valor diferente.

 

Tipo        Bytes   Contenido              Objeto

Char        1       Un carácter ANSI.      Tipo carácter por defecto.

AnsiChar    1       Un carácter ANSI.      Carácter Ansi de 8-bit.

WideChar    2       Un caracter Unicode.   Carácter Unicode de 16-bit.

 

 

Los caracteres se representan por su equivalente en el código ASCII: Cada carácter es un número binario de 8 bits, que es lo mismo que un byte (8 bits = 1 byte). Los tipos WideChar se utilizan para representar caracteres Unicode. Unicode es un superconjunto de los caracteres ASCII que utiliza dos bytes por cada carácter, esto le permite manejar 65536 caracteres y asi contener los caracteres de la mayoria de los lenguajes del mundo.

 

Object Pascal implementa dos vias adicionales para representar un carácter constante: con el signo (^) o con el signo de número (#). Primero, los caracteres con códigos entre 0 y 31 se denominan caracteres de control. A ellos se hace referencia mediante abreviaciones (CR para retorno de carro, LF por avance de línea, ESC por escape y así sucesivamente) ó, por la palabra Ctrl seguida de la correspondiente letra resultante de agregar 64 al código de control: Por ejemplo el carácter con código ASCII 7 es conocido como BEL (campana) o Ctrl­G (el carácter 'G' equivale al código ASCII número 71). Object Pascal permite representar este carácter usando el signo (^), seguido de la letra correspondiente. Así, en un programa, ^G es una representación válida de Ctrl­G, pudiéndose escribir una sentencia tal como Writeln(^G), la cual hace que su computador emita un pitido. Este método sólo trabaja para los caracteres de control y puede ser usado en aplicaciones de consola.

 

También se puede representar cualquier carácter usando el signo de número (#), seguido por el código ASCII del carácter. Así #7 es equivalente a ^G, #65 es equivalente a 'A', y #97 representa a 'a'.

 

 

Definiendo una cadena

 

Para trabajar una secuencia o arreglo de caracteres Pascal implementa los tipos cadena ilustrados en la siguiente tabla :

 

Tipo           Longitud Máxima    Memoria Reque.   Uso

ShortString    255 caracteres     2 a 256 bytes    Compatibilidad

AnsiString     ~2^31 caracteres   4 bytes a 2GB    Caracteres ANSI

WideString     ~2^30 caracteres   4 bytes a 2GB    Caracters Unicode 

 

 

La palabra reservada String, funciona como un identificador de tipo generico, el cual se procesa por defecto como AnsiString  o como ShortString cuando se incluyen subindices en la declaración, tal como se ilustra en el siguiente programa :

 

 

program Ejemplo_Cadena;

{$APPTYPE CONSOLE}

uses SysUtils;

 

var

   nombre : string[30];

   oficio : string[10];

 

begin

   // Insert user code here

   Write('Nombre de la persona ');

   Readln(nombre);

   Write('Cual es su oficio ');

   Readln(oficio);

   Writeln(nombre,' trabaja como ',oficio);

   readln;

end.

 

 

 

Aquí la variables nombre y oficio se declaran de tipo ShortString, con una asignación de 30 y 10 caracteres respectivamente. Pascal requiere un byte adicional para almacenar la longitud actual de cada cadena. Lo que se proporcione como entrada será exactamente lo que se imprime a la salida con la sentencia Writeln. Si se registra una entrada más larga que el espacio preasignado a cada cadena sólo se usa el número de caracteres determinados en la declaración de la cadena; los demás se ignoran. Cuando se declara una variable de cadena ShortString, se puede especificar cuántos caracteres (hasta 255) podrá contener.

 

Si se omite la longitud de la cadena, se asume por defecto una cadena del tipo AnsiString.

 

Delphi ofrece un amplio número de funciones y procedimientos para manipular cadenas; éstas se verán más adelante.

 

 

Tipos de datos lógicos (Booleanos)

 

Pascal predefine un tipo de dato lógico que almacena un valor de verdad: TRUE (verdadero) o FALSE (falso). Estas variables de tipo logico se declaran de la siguiente manera:

 

      var

            correcto :Boolean;

 

pudiéndose entonces asignar a la variable correcto el valor de las constantes TRUE o FALSE, o de cualquier expresion cuyo resultado sea un valor Booleano.

 

Una expresión Booleana es simplemente una expresión que puede ser falsa o verdadera, ésta puede ser una expresión relacional, un operador de logica booleana, una variable booleana o cualquier otra expresion lógica. Por ejemplo la siguiente sentencia  while (hacer mientras que..) contiene una expresión Booleana:

 

      while (asistentes <= cupo) and (not correcto) do ...

 

la expresión Booleana es todo lo que está entre las palabras reservadas while y do, y presupone que Correcto es una variable (o posiblemente una función) de tipo Booleana.

 

 

Tipos de datos apuntadores (Pointer)

 

Todos los tipos de datos mostrados hasta ahora son éso justamente: datos. Un pointer (apuntador) contiene un tipo de información diferente: direcciones. Un puntero es una variable que contiene la dirección en memoria (RAM) donde hay algún dato almacenado, en vez de datos propiamente dichos. Un apuntador señala a los datos, a manera de índice.

 

Un apuntador se declara como cualquier otro tipo de datos. Considere las siguientes declaraciones:

 

var

  Valor     : Integer;

  DirValor  : ^Integer;

 

 

La variable DirValor define un apuntador a un dato Integer. La variable Valor permite almacenar un valor entero (4 bytes) mientras que la variable DirValor permite almacenar la direccion en memoria de una variable de tipo entero y ocupa ...La variable Buf1 es del tipo Buffer; y ocupa hasta 256 bytes de memoria. La variable Buf2 es del tipo BufPtr; y contiene una dirección de 32 bits ocupando sólamente 4 bytes de memoria.

 

Donde apunta Buf2 ? Hasta ahora, a ninguna parte. Antes de poder usar BufPtr, se necesita apartar un bloque de memoria y almacenar su dirección en Buf2. Esto se hace usando el procedimiento New así:

 

  New(Buf2);

 

Despues de ésto, Buf2 apunta a un tipo Buffer. Esta sentencia crea un espacio de 256 bytes en algún lugar de la memoria y coloca su dirección en Buf2.

 

Para accesar el dato apuntado por Buf2 se emplea el operador de indirección ^. Por ejemplo suponga que se desea almacenar una cadena dentro de Buf1 y del espacio apuntado por Buf2. Estas dos sentencias muestran como hacerlo:

 

Buf1  := 'Esta cadena esta almacenada en Buf1.'

Buf2^ := 'Esta cadena esta almacenada donde apunta Buf2.'

 

Note la diferencia entre Buf2 y Buf2^. Buf2 se refiere a la variable apuntador de 4 bytes; Buf2^ se refiere a la cadena de 256 bytes cuya dirección está almacenada en Buf2.

 

Ahora, para liberar la memoria apuntada por Buff2 se usa el procedimiento Dispose. Dispose hace que el bloque de memoria que se asignó a Buf2 quede disponible para otros usos. Después de usar Dispose con un apuntador es buena práctica asignar el valor (predefinido) nil al apuntador. Esto permite conocer cuántos apuntadores ya no señalan a cualquier cosa.

 

  Dispose(Buf2);

Buf2 := nil;

 

Notese que nil se asigna a Buf2, y no a Buf2^.

 

Los apuntadores son muy versátiles para trabajar con estructuras dinámicas de datos, lo cual está fuera del contexto de esta guía. Un buen texto de Pascal le explicará cómo y cuándo usarlos.

 

 

 

 

IDENTIFICADORES

 

Hasta ahora se han dado nombres a las variables sin saber qué restricciones existen al respecto. Los nombres que se dan a las constantes, tipos de datos, variables y funciones se conocen como identificadores.

 

Algunos de los identificadores usados hasta aquí incluyen:

 

integer, real, string            Tipos de datos predefinidos

Ejemplo_Cadena                          Función principal de programa

Nombre, A, B, oficio              Variables definidas por el  usuario

Write,Readln                              Procedimientos predefinidos

 

 

Object Pascal sigue unas cuantas reglas acerca de los identificadores:

 

- Todo identificador contiene letras ('a'..'z' o 'A'..'Z'), el carácter subrayado ('_') o dígitos ('0'..'9'), ningún otro carácter es permitido, no puede contener espacios.

- Todo identificador debe comenzar con una letra o carácter subrayado.

- Los identificadores no establecen diferencias entre mayúsculas y minúsculas. Por ejemplo, los identificadores: indice, Indice o INDICE son idénticos.

- Los identificadores pueden tener cualquier longitud, pero sólo son significativos los primeros 255 caracteres.

- Las palabras reservadas no pueden ser usadas como identificadores.

 

 

 

OPERADORES

 

Una vez que un programa ha almacenado datos (dentro de sus variables), probablemente éstos deberán ser manipulados de alguna manera, usando los operadores viables. Estos son de ocho tipos: asignación, unarios/binarios, bit a bit, relacionales, lógicos, direcciones, conjuntos y cadenas.

 

La mayoría de los operadores en Object Pascal son binarios, es decir, requieren de dos operandos; el resto son unarios (sólo requieren de un operando). Los operadores binarios se usan de la forma algebráica usual, por ejemplo :  a + b. Un operador unario siempre precede al operando, por ejemplo : -b.

 

 

                                   Precedencia de los operadores

 

Operadores              Precedencia       Categorias

 

@, not                  Primera (alta)    Operadores unarios

*,/,div,mod,and,shl,shr Segunda           Operadores de multiplicación

+,-,or,xor              Tercera           Operadores de adición

=,<>,<,>,<=,>=,in       Cuarta (baja)     Operadores relacionales

 

 

Operaciones con igual precedencia normalmente se desarrollan de izquierda a derecha, aunque el compilador algunas veces las reorganiza para optimizar el código. Secuencias de operadores de la misma precedencia se evalúan de izquierda a derecha. El uso de parentesis permite alterar la precedencia de los operadores, las expresiones entre paréntesis se evaluan primero independientemente de los operadores circundantes.

 

Se debe tener cuidado al escribir ciertas expresiones, por ejemplo :

 

    8      

2+3X

 

no puede escribirse como   8/2+3*X ; lo correcto es escribirlo así:   8/(2+3*X)

 

 

Operadores de asignación

 

La operación básica es la asignación de valores a una variable, tal como en: Cociente := a / b. En Pascal el símbolo de asignación es dos puntos seguido por un signo igual (:=). En el ejemplo anterior, el valor de la expresion a/b a la derecha del símbolo de asignación se asigna a la variable Cociente.

 

 

Operadores unarios y binarios

 

Pascal soporta el conjunto usual de operadores para aritmética binaria, éstos trabajan con tipos de valor entero y real:

 

            *     Multiplicación

            div   División entera

            /     División real

            mod   Módulo (residuo de la división entera)

            +     Adición

            -     Substracción

 

Object Pascal también soporta el menos como operador unario (p.e. : a+(-b)), que realiza dos evaluaciones complementarias y el más unario (a+(+b)) que no afecta la expresion pero se puede incluir explicitamente.

 

 

Operadores bit a bit.

 

Para operar a nivel de bits, Pascal posee los siguientes operadores:

 

shl      Desplazamiento a la izquierda. Corre los bits a la izquierda el número indicado de veces, llenando a la derecha con ceros.

shr      Desplazamiento a la derecha. Corre un número dado de bits a la derecha, llenando a la izquierda con ceros.

and      Efectúa la operación lógica and, la cual para cada correspondiente par de bits retorna un 1 si los dos bits a operar son 1 y 0 en cualquier otro caso.

or        Efectúa la operación lógica or para cada par de bits, retornando 0 si ambos son cero y 1 en cualquier otro caso.

xor      Efectúa la operación lógica or exclusiva a pares de bits, retornando 1 si los bits son diferentes y cero en los demás casos.

not      Retorna el complemento lógico de cada bit, cambiando cada 0 a 1 y viceversa.

 

Estos operadores permiten desempeñar operaciones a bajo nivel con valores de tipo entero.

 

 

Operadores relacionales

 

Los operadores relacionales permiten comparar dos valores, retornando un resultado Booleano de falso o verdadero - TRUE o FALSE. He aquí los operadores relacionales en Pascal:

 

>         Mayor que

>=       Mayor o igual que

<         Menor que

<=       Menor o igual que

=         Igual a

<>       No igual (diferente) a

in       Es elemento de

 

Para ver cómo se procesan resultados Booleanos, introduzca el siguiente programa:

 

program PruebaMayorque;

{$APPTYPE CONSOLE}

uses SysUtils;

var

   A, B    : integer;

   Prueba  : boolean;

begin

   // Insert user code here

   Write ('Entre dos números: ');

   ReadLn(A,B);

   Prueba := A > B;

   WriteLn('A es mayor que B: ',Prueba);

   ReadLn;

end.

 

Este programa escribe TRUE si A es mayor que B, o FALSE si A es menor o igual que B.

 

 

Operadores lógicos

 

Hay cuatro operadores lógicos - and, xor, or y not -que son similares mas no idénticos a los operadores bit a bit. Estos operadores lógicos trabajan con valores lógicos (TRUE y FALSE), permitiendo combinar expresiones relacionales, variables Booleanas y expresiones Booleanas.

Las diferencias con los correspondientes operadores bit a bit son:

 

- Los operadores lógicos producen un resultado Booleano, mientras que los operadores bit a bit devuelven valores de tipo entero.

- No se pueden combinar expresiones Booleanas y expresiones de tipo entero con estos operadores.

- Los operadores lógicos and y or son por defecto de "corto-circuito" ; xor y not no lo son. Es decir, suponga que se tiene la expresión:

 

            exp1  and  exp2

 

Si exp1 es falsa, entonces la expresión entera es falsa y exp2 nunca será evaluada. De igual modo, si se tiene la expresión 

 

            exp1  or  exp2

 

si exp1 es verdadera, exp2 nunca será evaluada. Se puede forzar una evaluación completa de expresiones Booleanas usando la directiva de compilación {$B+} o la opción correspondiente en el menú.

 

 

 

Operadores de dirección

 

Pascal soporta dos operadores especiales para direcciones: el operador "dirección de" (@) y el operador de "indirección" (^).

 

El operador @ retorna la dirección en memoria de una variable. Por ejemplo, si Sum es una variable de tipo entero, entonces @Sum es la dirección (localidad de memoria) de dicha variable. Así mismo, si ChrPtr es un apuntador de tipo char, entonces ChrPtr^ es el carácter al que ChrPtr apunta.

 

 

Operadores de conjuntos

 

Los operadores de conjuntos trabajan de acuerdo a las reglas de la lógica de conjuntos. El juego de operadores y operaciones incluye:

 

+         unión

-         diferencia

*         multiplicación

 

 

 

Operadores de cadenas

 

La única operación viable con cadenas es la desarrollada con el operador +, que se emplea para concatenar dos o más cadenas.

 

 

 

SALIDA

 

Puede parecer extraño hablar primero de la salida antes que de la entrada, pero son muy comunes los programas que no toman información. La salida usualmente coloca la información escrita en la pantalla (palabras y dibujos), o la almacena en algún medio (floppy o disco duro), o hace I/O a un puerto de comunicaciones (serial o puerto de impresión).

 

 

El procedimiento WRITELN

 

La rutina writeln es la función de salida más común en Pascal. Para escribir información en la pantalla se usa writeln . Su formato es a la vez simple y flexible:

 

      Writeln (item,item,...);

 

donde cada ítem es cualquier cosa que se desea escribir en la pantalla. item puede ser un valor literal, un entero o un número real (3, 42, -1732.3), un carácter ('a','Z'), una cadena ('Hola, Mundo'), o un valor Booleano (TRUE). Pueden ser también nombres de constantes, variables, una referencia a un apuntador, o el llamado a una función (mientras ésta produzca un valor de tipo entero, real, carácter, cadena o Booleano). Todos los items seran impresos en una línea en el orden dado. El cursor es entonces posicionado al comienzo de la siguiente línea. Si se desea dejar el cursor despues del último ítem en la misma línea, entonces use la sentencia  write así:

 

      write (item,item,...);

 

Cuando en una sentencia Writeln o Write se imprimen los items, no se insertan blancos automáticamente ; si se desean espacios entre items, se deben colocar explícitamente, de la siguiente  manera:

 

      Writeln (item,'  ',item,'  ',...);

 

Por ejemplo, las siguientes sentencias producen la salida que se indica:

 

      A := 1; B := 2; C := 3;

      Nombre := 'Adriana';

      Writeln(A,B,C);                    123

      Writeln(A,' ',B,' ',C);            1 2 3

      Writeln('Nombre',Nombre);          NombreAdriana

      Writeln('Nombre  ',Nombre);        Nombre  Adriana

 

Note que 'Nombre' es un literal, mientras que Nombre es una variable que puede contener cualquier cadena.

 

También se puede especificar una "longitud de campo" para definir el espacio que se asignará a cada item. La forma es

 

      Writeln(item:ancho,..);

 

donde ancho es una expresión entera (literal, constante, variable, llamado a función, o combinación de éstas) especificando la longitud total del campo donde se escribe ítem. Por ejemplo, considere el siguiente código y su resultado de salida

 

A := 10; B := 2; C := 100;

Writeln(A, B, C);                   102100

Writeln(A:2, B:2, C:2);             10 2100

Writeln(A:3, B:3, C:3);             10  2100

Writeln(A, B:2, C:4);               10 2 100

 

Note que el ítem se imprime colocando blancos a la izquierda, para hacer que el espacio ocupado sea igual al campo especificado. El valor actual es justificado a la derecha. Si el ancho  especificado es menor que el espacio necesario para la salida, entonces Pascal expande el ancho al mínimo espacio requerido.

 

Este método trabaja para todos los items permitidos: enteros, reales, caracteres, cadenas, y lógicos. Sin embargo, los números reales impresos con longitud de campo especificada (o sin ella) dan una salida en notación científica:

 

x := 421.53;

Writeln(x);                         4.2153000000E+02

Writeln(x:8);                       4.2E+02

 

A causa de ésto, Pascal permite añadir un segundo especificador de amplitud de campo: item:ancho:dígitos. Este segundo valor forza la impresión del número real en un formato de punto decimal fijo y permite determinar el número de dígitos despues del punto decimal:

 

x := 421.53;

Writeln(x:6:2);                     421.53

Writeln(x:8:2);                       421.53

Writeln(x:8:4);                     421.5300

 

 

 

 

ENTRADA

 

El Pascal estándar tiene dos funcones básicas para entrada, Read y Readln, que se emplean para leer datos desde el teclado. La sintaxis general es

 

      Read (item,item,...);

 

o

 

      Readln (item,item,...);

 

donde ítem es una variable de tipo entero, real, carácter o cadena. Los números deben  separarse entre sí por espacios o presionando Enter.  Al igual que con la sentencia write, read se diferencia de readln en que el cursor se mantiene en la misma línea, en tanto que readln, cambia de línea una vez se ha presionado Enter al hacer la entrada correspondiente.

 

Se debe tener cuidado con el uso de una u otra sentencia, ya que usar sentencias read antes de leer variables de tipo char o string, hace que su lectura no se lleve a cabo; retornando cadenas vacías o variables de tipo carácter con un ASCII 13 (Enter) como contenido.  Al tomar entradas por teclado, es recomendable usar siempre Readln.

 

 

NOTA : Las rutinas Write, WriteLn, Read y ReadLn solo estan disponibles para aplicaciones de consola.

 

 

 

SENTENCIAS CONDICIONALES

 

En algunas ocasiones se desea ejecutar una porción de un programa cuando una condición toma o no el valor de TRUE, o cuando se alcance un valor dado en una expresión.

 

 

La sentencia IF

 

Observando las sentencias if en los ejemplos previos, note que puede tomar la siguiente forma genérica :

 

      if  expr

            then  sentencia1

            else  sentencia2

 

Donde expr es una expresión Booleana (que se resuelve en TRUE o FALSE), y sentencia1, sentencia2 son sentencias válidas en Pascal. Si expr es TRUE, entonces (then) se ejecuta la sentencia1, en cualquier otro caso (else) se ejecuta la sentencia2.

 

Se deben tener en cuenta dos puntos importantes acerca de la instrucción  if/then/else:

 

Primero, la sentencia:

 

            else sentencia2

 

  es opcional; en otras palabras, también es válida la siguiente sentencia If:

 

      if  expr

            then sentencia1

 

En este caso, sentencia1 sólamente se ejecuta si expr es TRUE. Si expr es FALSE, entonces se salta sentencia1 y el programa continúa.

 

Segundo, si se desea ejecutar más de una instrucción en el caso que una expresión particular sea verdadera o falsa, entonces se puede usar una sentencia compuesta. Una sentencia compuesta consiste en un bloque de sentencias delimitadas entre las palabras clave begin y end.

 

El siguiente programa ejemplo muestra cómo usar IF. Cree una nueva aplicación y escriba el siguiente código para el evento OnResize de la forma :

 

 

 

procedure TForm1.FormResize(Sender: TObject);

var

   maxX, maxY,

   i, maxpuntos,

   x, y, m, n    : integer;

 

begin

    Refresh;       // "Borra" el contenido actual de la forma

 

    x := 0;

    y := 0;

    m := 1;        // Magnitud del avance

    n := 1;

 

    maxX := ClientWidth;

    maxY := ClientHeight;

 

    maxpuntos := maxX * maxY div 3; // El 33% del area

 

    for i := 1 to maxpuntos do

    begin

        // Dibuja un punto en la coordenada (x,y), con un color

        // determinado por los valores x, y

        Canvas.Pixels[x,y] := RGB(x * y, x + y, x - y);

 

        x := x + m;

        y := y + n;

 

        if x >= maxX

           then m := -1;    // Tope derecho

 

        if y >= maxY

           then n := -1;    // Tope inferior

 

        if x <= 0

           then m := 1;     // Tope izquierdo

 

        if y <= 0

           then n := 1;     // Tope superior

 

        // Hace una pausa de 1 milisegundo cada 10 puntos :

 

        // if i mod 10 = 0

        //    then Sleep(1);

    end;

 

end;

 

 

 

NOTA: Las lineas colocadas entre llaves ({..}) y los textos precedidos por doble slash (//) son comentarios. Los comentarios se pueden colocar en cualquier lugar del codigo, la escritura de éstos no tienen ningun efecto sobre el programa pues son ignorados por el compilador, su única función es dar claridad al código fuente.

 

 

Este programa traza puntos continuamente a través de la pantalla, desplazándose en x y en y, hasta encontrar un borde cualquiera de ésta (sentencias If), entonces cambia el sentido del desplazamiento para no salirse del área de la forma. Se dibujara un nuevo diseño cada vez que cambie el tamaño de la forma. Si desea seguir el proceso de dibujo habilite la ultima condicion (la que esta puesta como comentario), la cual habilita un pequeño retardo cada 10 puntos dibujados.

 

 

La sentencia CASE

 

Esta sentencia brinda al programa la posibilidad de elegir entre varias alternativas sin tener que especificar sentencias if para cada una.

 

La sentencia case consiste de una expresión (el selector) y de una lista de sentencias, cada una precedida por una etiqueta de caso del mismo tipo del selector. La sentencia que se ejecuta es la de la etiqueta que se corresponda al valor actual del selector. Si ninguna de las etiquetas de caso contiene el valor del selector, ninguna de las sentencias será ejecutada y se ejecutará la sentencia que siga a la palabra reservada else si esta existe (el uso de else es opcional).

 

Una etiqueta de caso consiste de cualquier número de constantes o subrangos, separados por comas y seguidos por dos puntos (:).

 

Un subrango se escribe como dos constantes separadas por el delimitador de subrangos '..'. El tipo de la constante y el selector debe ser el mismo. La sentencia que sigue a la etiqueta case se ejecuta si el valor del selector es diferente a las constantes o si no está dentro de los subrangos.

 

Esta es la estructura general de la sentencia case:

 

            case expresion of

           caso: sentencia;

           ...

           caso: sentencia;

      end

 

o también:

 

            case expresion of

           caso: sentencia;

           ...

           caso: sentencia;

           else

               sentencia

      end

 

Observe que la parte else es opcional. Esta ejecuta la sentencia asignada, si ningún otro de los casos se da.

 

El siguiente ejemplo muestra cómo usar case y su gran versatilidad. Cree una nueva aplicación, añada a la forma un control Memo y un Button, enlace el siguiente código al evento OnClick del botón:

 

 

 

procedure TForm1.Button1Click(Sender: TObject);

const

     CR_LF = #13 + #10;   // Salto de línea

var

   i     : integer;

   texto : String;

   car   : char;

 

   mayus, minus, vocales,

   espacios, digitos, otros : Integer;

   otrosstr : string;

 

begin

   texto := memFrase.text;

 

   // Inicializa variables

   mayus := 0;

   minus := 0;

   vocales := 0;

   espacios := 0;

   digitos := 0;

   otros := 0;

   otrosstr := '';

 

   for i := 1 to length(texto) do

   begin

      car := texto[i];

 

      case car of

         'A'..'Z' :

             begin

                mayus := mayus + 1;

                if car in ['A', 'E', 'I', 'O', 'U']

                   then vocales := vocales + 1;

             end;

 

         'a'..'z' :

             begin

                minus := minus + 1;

                if car in ['a', 'e', 'i', 'o', 'u']

                   then vocales := vocales + 1;

             end;

 

         #32 : // Espacio

             espacios := espacios + 1;

 

         '0'..'9' :

             digitos := digitos + 1;

         else

             otros := otros + 1;

             otrosstr := otrosstr + car;

      end; // case

 

   end;

 

   label1.WordWrap := True;  // Etiquetas de multiples lineas

   label1.Width := Width - label1.left; // Extiende la etiqueta hasta

                                        // el borde derecho de la forma

 

   label1.Caption := IntToStr(mayus) + ' - Letras Mayusculas' + CR_LF +

                     IntToStr(minus) + ' - Letras Minusculas' + CR_LF +

                     IntToStr(vocales) + ' - Letras Vocales' + CR_LF +

                     IntToStr(espacios) + ' - Espacios' + CR_LF +

                     IntToStr(digitos) + ' - Digitos 0 .. 9' + CR_LF +

                     IntToStr(otros) + ' - Otros caracteres : ' +

                     OtrosStr;

 

end;

 

 

Este código toma el texto escrito en el memo y lo procesa para contar el número de mayúsculas, minúsculas, vocales, números, etc. que contiene. La sentencia case permite definir de manera muy clara los rangos de valores que se desean comprobar para cada carácter. La opción else de la instrucción case sirve para contar todos aquellos caracteres que no están incluidos en los "filtros" básicos. Que pasa con los acentos (p.e. 'ü', 'á', 'é' ...) y con letras como la 'ñ' ?.

 

 

 


 

CICLOS

 

Así mismo como algunas sentencias pueden ejecutarse condicionalmente, existen otras que se deben ejecutar repetitivamente, una construcción de este tipo se denomina un ciclo.

 

Los tres tipos de ciclos son: el ciclo while (hacer mientras que), el ciclo repeat (hacer hasta que) y el ciclo for.

 

 

El ciclo WHILE

 

La instrucción while se usa cuando se desea probar la condición de ejecución al comienzo del ciclo.

 

Cree una nueva aplicación y escriba el siguiente código para el evento OnResize de la forma :

 

 

 

 

procedure TForm1.FormResize(Sender: TObject);

var

   maxX, maxY, mitad,

x, y                : integer;

 

begin

    Refresh;

   

    maxX := ClientWidth;   // Alto y ancho del area

    maxY := ClientHeight;  // disponible de la forma

 

    mitad := maxX div 2;

 

    y := maxY;

    x := mitad;

 

    while  y >= 0 do

    begin

        Canvas.MoveTo(mitad + x, maxY);

        Canvas.LineTo(mitad, y);         // Linea derecha

        Canvas.LineTo(mitad - x, maxY);  // Linea simetrica

        y := y - 10;   //   5

        x := x - 9;    //  10

    end;

end;

 

 

Este programa realiza un sencillo diseño gráfico repitiendo el trazo de una línea que se desplaza al restar una cantidad determinada, hasta alcanzar el tope superior de la pantalla (coordenada horizontal 0); de ahí que la condición de repetibilidad del ciclo sea:  y >= 0; más alla de ese punto (valores negativos), la línea estaría fuera del area de la forma, siendo inútil dibujarla.

 

Para lograr diferentes efectos en el dibujo, los valores colocados como comentarios pueden reemplazar a los valores fijados.

 

La forma de la instrucción While es

 

      While  expr  do  sentencia

 

donde expr es una expresión Booleana, y sentencia es cualquier sentencia simple o compuesta.

 

El ciclo while evalúa expr. Si ésta es TRUE, se ejecuta sentencia, y expr se evalua de nuevo. Si expr es FALSE, se finaliza el ciclo while y el programa continúa.

 

 

El ciclo REPEAT

 

El segundo tipo de ciclo es  repeat ... until. Para el siguiente programa requiere una nueva aplicación y añadir un boton a la forma, asocie el siguiente codigo al evento OnClick del boton :

 

 

procedure TForm1.Button1Click(Sender: TObject);

const

    CR_LF = #13 + #10;   // Secuencia de caracteres para salto de línea

var

    numero,

    opcion,

    intentos        : Integer;

    acierto         : Boolean;

 

begin

    Randomize;              // Regenera la secuencia de números al azar

 

    acierto := FALSE;

    intentos := 0;

    numero := random(100);  // Genera un numero al azar

 

    ShowMessage('Adivina el número escogido' + CR_LF +

                'por el computador (0..99)');

 

    repeat

        opcion := StrToInt(InputBox('Adivina', 'Tu opción :', ''));

 

        intentos := intentos + 1;

 

        if opcion = numero

           then acierto := TRUE

           else begin

               if numero < opcion

                  then ShowMessage('El número a adivinar es MENOR')

                  else ShowMessage('El número a adivinar es MAYOR')

           end;

 

    until acierto;     // Al acertar se termina el ciclo

 

    ShowMessage('ACERTASTE' + CR_LF +

                'A los ' + IntToStr(intentos) + ' intentos');

 

end;

 

 

 

La secuencia principal se repite hasta que se acierte el número generado por el computador. En otras palabras, todo lo que hay entre  repeat  y  until  se repite hasta tanto la variable Booleana "acierto" tome el valor de TRUE.

 

Más código : Puede añadir el siguiente trozo de codigo, despues de terminar el ciclo repeat, para "clasificar" el nivel de juego de un jugador. Observe que se requiere definir una variable de tipo String llamaga msg y modificar el mensaje en la ultima sentencia ShowMessage() :

 

 

    // Clasificación

    if intentos < 5

       then msg := 'Estas Suertudo !'

       else if intentos < 9

               then msg := 'Eres Inteligente !'

               else if intentos < 15

                       then msg := 'Necesitas Practicar'

                       else if intentos < 20

                               then msg := 'Piensa un poco ...'

                               else msg := 'Juega otra cosa ...';

 

    ShowMessage('ACERTASTE' + CR_LF +

                'A los ' + IntToStr(intentos) + ' intentos' +

                CR_LF + Msg);

 

 

 

Nota : La construccion de sentencias if sucesivas que se ilustra en esta porcion de codigo se conoce como un "escalonador if", permite probar rangos de valores sin tener que escribir complejas expresiones logicas para sentencias if sueltas.

 

 

 

La forma genérica para el uso del ciclo  repeat ... until es:

 

      repeat

            sentencia;

            sentencia;

            ...

            sentencia

      until expr

 

 

Existen tres diferencias claves entre el ciclo while y el ciclo repeat. Primero, las sentencias en el ciclo repeat siempre se ejecutan por lo menos una vez, puesto que la verificación de expr no se hace sino hasta que el ciclo ha ocurrido una vez. En contraste, la estructura del ciclo while se omite si la expresión es inicialmente falsa.

 

Además, el ciclo repeat se ejecuta hasta que la expresión sea verdadera, mientras que el ciclo while se ejecuta mientras la expresión es verdadera. Esto significa que los ciclos pueden modificarse para ser usados dentro de una u otra estructura, while o repeat.

 

Finalmente, el ciclo repeat puede contener múltiples sentencias sin usar una sentencia compuesta. Note que no es necesario usar  begin .. end para delimitar el cuerpo del ciclo, como cuando se usa el ciclo while.

 

Recuerde que el ciclo repeat siempre se ejecuta por lo menos una vez. En cambio un ciclo While podría no ser ejecutado ni siquiera una vez dependiendo del valor de la expresión.

 

 

El ciclo FOR

 

El ciclo for es una instrucción común en muchos lenguajes de computación. Su versión en Pascal es simultáneamente limitada y poderosa.

 

Básicamente, permite ejecutar un conjunto de sentencias un número fijo de veces; una variable (conocida como variable índice o de control) "camina" a través de un rango de valores.

 

Por ejemplo, estudie el siguiente programa:

 

 

 

program Factorial_For_Demo;

{$APPTYPE CONSOLE}

uses

  SysUtils;

 

var

   cont, numero    : Integer;

   fac             : Extended;

 

begin

    // Insert user code here

    Write('Numero a calcular el factorial: ');

    ReadLn(numero);

    fac := 1;

 

    for cont := 1 to numero do

    begin

       write('.'); // Escribe un punto por cada multiplicación

       fac := fac * cont;

    end;

 

    WriteLn;

    WriteLn('El factorial de ',numero,' es ',fac:16:0);

    WriteLn('Presione Enter para terminar');

    ReadLn;

 

end.

 

 

 

En este programa la variable de control (cont), recorre un rango de valores entre 1 y el número dado, para ir acumulando productos sucesivos en fac, obteniéndose el factorial del número entrado.

 

La sintaxis para un ciclo for es:

 

      for  index := expr1 to expr2  do  sentencia

 

donde  index es una variable de algún tipo escalar (cualquier tipo entero, carácter, booleano y cualquier tipo enumerado), expr1 y expr2 son expresiones de algún tipo compatible con index, y sentencia una sentencia simple o compuesta. A través de cada ejecución del ciclo, Index se incrementa automáticamente en uno.

 

También se puede disminuír (incrementar negativamente) el valor de la variable de control reemplazando la palabra clave  to  por  downto.

 

El ciclo for sólo permite incrementos/decrementos en uno. Esto es consistente y ventajoso en el trabajo con tipos enumerados y rangos de valores.

 

Es también muy común el uso de instrucciones for anidadas (una dentro de otra); veamos este sencillo ejemplo de programa que simula un reloj -aunque camina algo rápido !.

 

Cree una nueva aplicación, añada una etiqueta llamada lblreloj y un boton al cual asociar el siguiente codigo para el evento OnClick

 

 

procedure TForm1.Button1Click(Sender: TObject);

var

   hora, min, seg   : integer;

 

begin

    // Propiedades de la etiqueta del reloj

    lblReloj.Font.Name := 'Courier New';

    lblReloj.Font.Size := 24;

    lblReloj.Font.Color := clRed;

    lblReloj.Font.Style := [fsBold];

 

    for hora := 0 to 23 do

       for min := 0 to 59 do

          for seg := 0 to 59 do

          begin

             lblReloj.Caption := format('%2d:%2d:%2d',

                                        [hora, min, seg]);

             sleep(10);   // Espera en milisegundos,

             Application.ProcessMessages;

          end

 

end;

 

 

Si se desea hacer más real el avance del reloj, basta con colocar 1000 como parámetro dado a la instrucción sleep (1000 milisegundos = 1 segundo).

 

Nota : La sentencia Application.ProcessMessages permite a Windows procesar los mensajes que se encuentran en su cola de mensajes. Esto hace que se actualice el rotulo que despliega la etiqueta y que eventualmente se termine la ejecucion de la aplicación si se incluye el siguiente codigo para el evento OnClose de la forma :

 

 

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

   Halt;   // Fuerza la terminación del programa

end;

 

 

En caso contrario el usuario tendra que esperar a que se ejecute la totalidad de los ciclos for !. Si la aplicación esta ejecutandose desde el entorno de Delphi es posible deternerla con la opcion de menú : Run\Program Reset

 

 

 

PROCEDIMIENTOS Y FUNCIONES

 

Ya se ha visto cómo ejecutar código condicional e interactivamente. Ahora se verá cómo ejecutar el mismo conjunto de instrucciones con diferentes conjuntos de datos y en diferentes posiciones de un programa. Esto se hace colocando las sentencias a repetir dentro de una subrutina, que se puede invocar cuando sea necesario.

 

En Pascal, existen dos tipos de subrutinas: procedimientos y funciones. La principal diferencia entre las dos es que una función retorna un valor y puede usarse en expresiones como ésta:

 

      x := Sin(x);

 

mientras que un procedimiento es invocado para desempeñar una o más labores, sin retornar valor alguno:

 

      Writeln ('Este es un test');

 

Antes de detallar el manejo de procedimientos y funciones es conveniente comprender la estructura de un programa Pascal.

 

 

Estructura de un programa

 

Los programas Pascal poseen la siguiente estructura:

 

            program  NombreProg;

            label

                        etiquetas;

            const

                        declaración de constantes;

            type

                        definiciones de tipos de datos;

            var

                        declaraciones de variables;

 

            procedimientos y funciones;

 

            begin

                        cuerpo principal del programa;

            end.

 

 

Las cinco secciones de declaración -etiquetas, constantes, tipos, variables, procedimientos y funciones- no son todas necesarias en cada programa. La sección de declaraciones va seguida de los procedimientos y funciones definidos por el usuario, finalmente va el cuerpo principal del programa, consistente de cualquier número de sentencias.

 

Object Pascal permite gran flexibilidad en el orden de la estructura mencionada, pero se debe tener en cuenta que las cosas deben estar definidas antes de poder usarlas.

 

 

Estructura de los procedimientos y funciones

 

Los procedimientos y funciones -conocidos generalmente como subprogramas- aparecen en cualquier lugar antes del cuerpo principal del programa.

 

Los procedimientos tienen el siguiente formato:

 

            procedure NombreProc (parametros);

            label

                        etiquetas;

            const

                        declaraciones de constantes;

            type

                        definiciones de tipos de datos;

            var

                        declaraciones de variables;

 

            procedimientos y funciones;

 

            begin

                        cuerpo principal del procedimiento;

            end;

 

 

Las funciones se declaran igual que los procedimientos, excepto que comienzan con el encabezamiento  function y terminan con el tipo de dato del valor que retorna la función:

 

      function  NombreFunc (parametros) : tipo de dato;

 

Como puede ver, sólo existen dos diferencias entre un programa regular con los procedimientos y las funciones: éstos comienzan con el encabezado de procedure o function en lugar de program, y terminan con punto y coma (;) en lugar de punto (.). Un procedimiento o una función puede contener constantes, tipos de datos, y variables exclusivas para sí, e incluso sus procedimientos y funciones propios. Aún más, todos estos items sólo pueden emplearse dentro del procedimiento o función en que fueron declarados.

 

He aquí un ejemplo:

 

 

 

program ProcFuncDemo;

{$APPTYPE CONSOLE}

uses

  SysUtils;

 

var

   a, b     : integer;

   total    : real;

 

procedure LeerEntrada(var x, y : integer);

var

   prueba : char;

begin

   repeat

      Write('Entre dos números ');

      ReadLn(a, b);

      Write('Datos correctos S/N ');

      ReadLn(prueba);

   until upcase(prueba) = 'S'

end;

 

function suma (c, d : integer) : integer;

begin

   result := c + d;

end;

 

function cociente (x, y : integer) : real;

begin

   if y = 0

      then writeln ('Division por cero. Indeterminado')

      else result := x / y;

end;

 

begin

   LeerEntrada(a, b);

   total := suma(a, b);

   WriteLn (a, ' + ', b, ' = ', total:10:0);

   WriteLn (a, ' / ', b, ' = ', cociente(a, b):10:2);

   ReadLn;

end.

 

 

 

Aqui se ilustra someramente el uso de procedimientos y funciones, éstos se explicarán en detalle más adelante.

 

Cuando se compila y corre este programa, la ejecución comienza con la primera sentencia en el cuerpo principal del programa: LeerEntrada(a,b). Esta sentencia es lo que se conoce como una llamada al procedimiento. El programa manipula este llamado ejecutando las sentencias en LeerEntrada, reemplazando X y Y (conocidos como los parámetros formales) con A, B (los parámetros actuales). La palabra clave var al comienzo de la declaración de parámetros indica que los parametros actuales deben ser variables y que sus valores pueden ser modificados y pasados de vuelta al "llamador" del procedimiento. También se pueden pasar literales, constantes, expresiones y así sucesivamente. Una vez que LeerEntrada ha finalizado, la ejecución retorna al cuerpo principal del programa y continúa con la sentencia siguiente a la llamada a LeerEntrada.

 

La siguiente sentencia es una llamada a la funcion suma. Note que hay algunas diferencias clave. Primero, suma retorna un valor, el cual puede usarse como se desee, en este caso es asignado a la variable total. Segundo, un valor es asignado a result en el cuerpo mismo de la función, result es una variable implicitamente declarada dentro de cada funcion y determina el valor que retornará la función. Tercero, la función no tiene la palabra clave var al frente de los parámetros formales C y D. Esto permite pasar parámetros actuales que pueden ser dos expresiones enteras cualesquiera, como:  total := Suma (A + B , 300), si los parámetros formales se modifican en el cuerpo de la función, los nuevos valores no son devueltos al llamador (los cambios hechos a los parámetros en la función no se reflejan en el programa que la invoca). Esta no es una distinción entre los procedimientos y las funciones; en cualquier tipo de subprograma se puede usar cualquiera de los dos tipos de parámetros.

 

 

 

LA INSTRUCCION GOTO.

 

Esta instrucción produce un salto incondicional en la ejecución del programa al lugar marcado con la etiqueta especificada.

 

Su sintaxis es:

           

      goto etiqueta;

 

Donde etiqueta es un identificador previamente declarado en la sección label del programa.

 

El salto a un "label" se hará dentro del bloque donde ha sido definida la etiqueta, o sea que no será posible saltar a o desde una función o procedimiento diferente.

 

Puesto que Pascal es un lenguaje de programación estructurado, el uso de decisiones estructuradas permite eliminar de plano el uso de esta instrucción. Se recomienda NO usar esta orden, ya que disminuye considerablemente la calidad del programa en cuanto a legibilidad. Un programa resulta mucho más claro si se conservan y cumplen las reglas de la programación estructurada, usando la instrucción GoTo únicamente cuando sea ABSOLUTAMENTE necesario.

 

 

 

COMENTARIOS

 

En algunas ocasiones se desean insertar notas en un programa para indicar o simplemente informar la función de alguna variable, o de cierto procedimiento o sentencia y así sucesivamente. Estas notas se denominan comentarios. Pascal permite colocar todos los comentarios que usted desee dentro de su programa.

 

Se puede comenzar un comentario con el corchete izquierdo ({), que indica al compilador que ignore cualquier cosa hasta encontrar un corchete derecho (}).

 

Los comentarios pueden extenderse a través de múltiples líneas, así:

           

      { Este es un largo

        comentario, que se extiende

        a lo largo de varias lineas }

 

 

Tambien se pueden añadir comentarios de una sola línea usando dos caracteres backslash (//), cualquier texto despues de dichos caracteres es considerado un comentario. Ejemplo:

 

numero := random(100);  // Genera un número al azar