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 puntoflotante 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 CtrlG (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 CtrlG, 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.
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