El compilador FreePascal existe para plataformas Ms-Dos, Windows de 32-bits, Linux, OS/2, AmigaOs , FreeBSD , etc. Está limitado a las arquitecturas Intel y Motorola. Como característica interesante hay que decir que soporta muchas de las características del Pascal de Borland y de ObjectPascal de Delphi y además incluye nuevas posibilidades inexistentes en estos compiladores, como es la sobrecarga de operadores, por poner un ejemplo. También aporta una librería estándar que funciona en todas las plataformas que da soporte el compilador. En este manual se explicará como programar en Pascal y como aprovechar al máximo todas las posibilidades que el compilador FreePascal brinda al usuario, sin olvidar las que tratan del entorno Win32.
Antes de compilar ningún programa
Preparación del compilador
A diferencia de los productos comerciales, FreePascal no es un sistema diseñado para que los usuarios inexpertos lo empleen sin tener algún que otro problema antes de conseguir compilar su primer programa. En este apartado daremos algunas recomendaciones de forma que la tarea de instalación y preparación del entorno sea lo más fácil para los usuarios inexpertos.
Descarga e instalación del compilador
El compilador se puede descargar gratuitamente desde el área de descarga del web principal de FreePascal o desde alguno de los mirrors más cercanos. Para la mayoría de usuarios descargando el archivo completo sin fuentes, llamadas sources, es más que suficiente. El archivo en cuestión para la plataforma Win32 ocupa algo más de 8 Mb y viene comprimido en formato Zip. Para descomprimirlo podemos emplear WinZip o cualquier otro programa que de soporte a este formato.
Una vez descomprimido en una carpeta temporal, habrá que ejecutar el programa INSTALL.EXE. Este programa se encarga de descomprimir el resto de archivos Zip que incorpora el archivo de distribución. En la primera ventana que aparece, veremos tres páginas tabuladas . La primera, General, es donde tenemos que especificar el directorio donde se instalará FreePascal (Base Path) . Recomendamos que active la opción de crear el archivo de configuración del compilador (Create ppc386.cfg). En la siguiente página tabulada, Win32, se pueden escoger los elementos que queremos instalar, en nuestro caso una instalación mínima exige los componentes Required que son los 2 primeros, aunque una instalación completa sólo ocupa 20 Mb.
Finalmente, en la página Common podemos escoger instalar los elementos comunes a todas las distribuciones. Recomendamos que active la instalación de la documentación en formato PDF.
Al pulsar Continue, empieza la instalación. Finalmente, el programa nos avisará que es recomendable ampliar la variable PATH para poder trabajar con el compilador sin problemas.
Para hacerlo, ejecute la aplicación SysEdit que viene con Windows (escoja Ejecutar del Menú Inicio y escriba sysedit y pulse Intro). De las ventanas que aparecerán escoja la ventana con el nombre AUTOEXEC.BAT (puede cerrar todas las otras) y al final del archivo añada la línea SET PATH=%PATH%;C:PPBINWIN32 suponiendo que ha instalado el compilador al directorio C:PP (que es el directorio por defecto). En todo el manual se supondrá que el directorio de instalación es este . Guarde el archivo y reinicie el ordenador (no se limite a reiniciar el Windows).
Compilación del primer programa
Para emplear el compilador FreePascal tendrá que abrir una sesión de Ms-Dos en Windows. En este ejemplo compilaremos uno de los programas de ejemplo que lleva FreePascal (siempre que los haya instalado, claro). Este ejemplo es el típico Hola mundo, y se encuentra al directorio C:PPSOURCEDEMOTEXT en el archivo HELLO.PP.
Para compilar el archivo escriba :
PPC386 HELLO.PP
En unos instantes, si todo ha ido bien durante la compilación y el enlazado, obtendrá un archivo ejecutable con el nombre HELLO.EXE. Si lo ejecuta obtendrá la salida :
Hello world
En caso que hubiera obtenido el error de "Comando o nombre de archivo incorrecto" revise que el directorio C:PPBINWIN32 se encuentra en la variable PATH.
Buscando un IDE para FreePascal
FreePascal incorpora un entorno de desarrollo integrado (IDE) en modo texto, también se pueden emplear por ejemplo el Programmers Notepad para Windows (http://www.alternate.demon.co.uk/pn/), de Echo Software. También está muy bien el IDE totalmente integrado BloodShed's Dev-Pascal (http://www.bloodshed.net) bajo licencia GNU (hay que indicar que ya lleva su propia distribución del compilador FreePascal).
En cualquier caso es muy recomendable que el IDE o editor permita :
- Resaltar la sintaxis de Pascal.
- Ejecutar el compilador directamente desde el editor. Consulte la documentación del editor sobre como aprovecharse de esta característica.
Primeros pasos con Pascal
Programas y units
Pascal define dos tipos básicos de archivos que se pueden compilar : los programas y las units. En estos primeros capítulos nos limitaremos a trabajar con programas y dejaremos el tema de creación de units para más adelante.
Los archivos de código fuente que se escriben con un editor (o IDE) conviene que tengan extensión .PP o bien .PAS. Al compilar programas a Win32 obtendremos archivos .EXE mientras que si compilamos units obtendremos archivos .PPW que no son ejecutables.
Estructura básica de un programa
Cabecera
Todos los programas tienen la misma estructura. Para indicar al compilador que se trata de un programa tenemos que escribir la palabra program seguida de un espacio y de un nombre (que puede tener letras y números) y que tiene que terminar en un punto y coma. Por ejemplo:
program EjemploNumero6;
Es importante indicar que el nombre que demos al programa tiene que seguir unas reglas ya que sino en caso contrario no será válido para el compilador :
- El primer carácter tiene que ser una letra y no una cifra ya que en caso contrario el compilador se pensaría que es un número. Por ejemplo, no es valido el nombre siguiente :
program 6Ejemplo;
- El único carácter no alfanumérico válido es el guión bajo. No se admiten caracteres como exclamaciones o signos de interrogación, etc.
- Tampoco se admiten vocales acentuadas o letras que no pertenezcan al alfabeto inglés. Por ejemplo la ÿ y la ñ no se admiten.
- Finalmente, el nombre del programa no tiene que coincidir con otras variables o constantes del programa. …éstas las veremos más adelante.
Utilización de units
En algunos casos nos puede interesar emplear diferentes funciones y procedimientos que están definidos en otros archivos. Esta especie de almacenes de rutinas se llaman units y hay que explicitarlas cuando queremos emplear alguna de sus rutinas en nuestro programa.
Las units estándar que incorpora FreePascal son las siguientes :
PARA TODAS LAS PLATAFORMAS | |
GETOPTS | Permite recuperar los parámetros pasados en la línea de órdenes de un programa. |
MMX | Aporta funcionalidad básica para el uso de las extensiones multimedia de los procesadores INTEL. |
OBJECTS | Incorpora rutinas para gestionar objetos. |
OBJPAS | Se emplea automáticamente cuando se activa el soporte Delphi. |
PORTS | Da acceso a los puertos I/O del PC. No se recomienda su uso en Win32. |
STRINGS | Permite emplear el tipo de cadena PCHAR. |
SYSUTILS | Implementación alternativa de la unit del mismo nombre en Delphi. |
TYPINFO | Permite acceder a la información de tipo en tiempo de ejecución, como en Delphi. |
PARA WINDOWS 32-BIT | |
DOS | Lleva rutinas de emulación de acceso al sistema DOS mediante funciones del sistema de Windows. |
CRT | Rutinas básicas de gestión de la pantalla en modo texto. |
GRAPH | Gestión básica de gráficos. |
WINDOWS | Esta unit permite acceder a las funciones de la API de 32-BIT de Windows. |
OPENGL | Accede a les funciones de bajo nivel OpenGL de Windows 32-BIT. |
WINMOUSE | Funciones para emplear el ratón en Windows 32-BIT. |
OLE2 | Implementa las posibilidades OLE de Windows 32-BIT. |
WINSOCK | Interfaz a la API winsock de Windows 32-BIT. |
SOCKETS | Encapsulación de WINSOCK de forma que sea compatible en Windows 32-BIT y en Linux. |
En la mayoría de ejemplos sólo emplearemos la unit CRT para mostrar datos en modo texto. Para incluir una unit en nuestro programa emplearemos la palabra reservada uses. Por ejemplo, si queremos incluir las units CRT y GRAPH sólo habrá que añadir la siguiente cláusula debajo de program :
uses CRT, GRAPH;
Cuando se emplee más de una unit se tendrá que separarlas en comas. La línea siempre hay que finalizarla en punto y coma.
[]
3.2.3.Declaración de constantes
Muchas veces puede ser útil emplear un valor numérico o un texto determinado varias veces en un programa. Para evitar tener que definirlo en cada punto que lo necesitemos emplearemos una referencia única en todo el programa al que llamaremos constante.
Las constantes no varían en todo el programa y se declaran seguidas de la palabra reservada const, un signo igual y el valor que representan. Por ejemplo :
const
maximo = 1000;
e = 2.71828;
nombre = 'Roger Ferrer';
letra = 'a';
Lo que va después del signo igual recibe el nombre de literal. Un literal es un valor incluido directamente en el código. En el primer caso es el numero entero 1000, la constante maximo vale 1000. En el caso de la constante e, es el número real 2.71828. Finalmente nombre representa una cadena de caracteres con el texto Roger Ferrer.
La declaración de literales se rige por unas normas sencillas :
- Las cifras que no lleven decimales son automáticamente entendidas por el compilador como un entero.
- Las cifras con notación decimal inglesa, o sea, un punto decimal en vez de una coma decimal, son siempre cifras reales.
- Las cadenas de caracteres siempre empiezan y terminan con un apóstrofe o comilla simple ('). Para escribir el signo apóstrofe dentro de una cadena de caracteres hay que duplicar el apóstrofe. Eje : 'Tira palante'
- Si una cadena de caracteres tiene un sólo carácter, el compilador lo entiende también como un tipo carácter. Los caracteres son compatibles con las cadenas de caracteres pero no a la inversa.
- Podemos escribir caracteres con su código ASCII en decimal añadiendo el símbolo # delante del número. Por ejemplo #7 es el carácter BEEP que al escribirse emite un ruido por el altavoz, #65 es la letra A mayúscula. Podemos combinar caracteres escritos así y literales normales, por ejemplo 'L'#65 equivale a 'LA'.
- Los tipos enteros que empiecen con un signo de dólar $ se interpretarán como cifras hexadecimales. Las cifras que empiecen con un signo de porcentaje % se interpretarán como nombres binarios. En el caso de los hexadecimales se permite el uso de todas las cifras en base 16 (0..9, A..F) y en el caso de los binarios sólo son validas la cifras 0 y 1.
const
NumeroBase10 = 1522;
NumeroBase16 = $5F2;
NumeroBase2 = %10111110010;
En este caso las tres constantes NumeroBase10, NumeroBase16 y NumeroBase2 representan el mismo número, aunque escrito en bases distintas.
En Pascal, los nombres de constantes es indiferente de que estén en mayúsculas o minúsculas. Por tanto, en el ejemplo anterior maximo, MAXIMO y maXIMo representan lo mismo para el compilador. Hay que ir con cuidado para no duplicar nombres. Por ejemplo, esto es incorrecto.
const
maximo = 1000;
MAXIMO = 5000;
Ya que MAXIMO y maximo son lo mismo y se está redeclarando una constante ya declarada. Esta independencia sintáctica a las mayúsculas está presente en todos los aspectos de Pascal excepto , claro está, en las cadenas de caracteres. Es usual, debido a la notación de C, que las constantes se declaren totalmente en mayúsculas y en los programas se empleen en mayúsculas para distinguirlas de las variables, como veremos más adelante, aunque no sea necesario hacerlo.
Declaración de variables. Tipos de datos fundamentales
Si pensamos en muchas fórmulas matemáticas veremos que emplean variables en su expresión. Por ejemplo el área del triángulo es AT = b * h . Cuando queremos calcular el area de un triángulo dado nos limitamos a sustituir estas variables. En Pascal, y programación ocurre algo parecido.
Pascal exige que se declaren las variables que se emplearán. Las variables pueden modificar su valor a lo largo del programa. Cada variable tiene que ser de un tipo determinado. Los tipos de variables, llamados tipos de datos, se dividen en cuatro grandes grupos fundamentales :
- Numéricos. Enteros o reales.
- Alfanuméricos. Un carácter o una cadena de caracteres.
- Booleanos. Sólo pueden valer cierto o falso.
Los tipos numéricos enteros que incorpora FreePascal son los siguientes :
Tipos | Rango numérico | Bytes (Bits) |
Byte | 0..255 | 1 (8) |
Shortint | -128..127 | 1 (8) |
Integer | -32768..32767 En modo compatibilidad Delphi este tipo es igual a Longint. | 2 (16) |
Word | 0..65535 | 2 (16) |
Longint | -2147483648..2147483647 | 4 (32) |
Cardinal | 0..4294967296 | 4 (32) |
Int64 | -9223372036854775808..9223372036854775807 | 8 (64) |
También tenemos tipos reales
Tipos | Rango real | Decimales significativos | Bytes (Bits) |
Single | 1.5^-45 .. 3.4^38 | 7-8 | 4 (32) |
Real | 5.0^-324 .. 1.7^308 | 15-16 | 8 (64) |
Double | 5.0^-324 .. 1.7^308 | 15-16 | 8 (64) |
Extended | 1.9^-4951 .. 1.1^4932 | 19-20 | 10 (80) |
Comp | -2^64 +1 .. 2^63 -1 | 19-20 | 8 (64) |
El tipo Comp es un tipo especial de entero con propiedades de real. Los decimales significativos indican cuantos decimales se tienen en cuenta a la hora de hacer cálculos.
Los tipos alfanuméricos que implementa FreePascal son los siguientes :
Tipos | Contenido | Bytes |
Char | Un solo carácter | 1 |
ShortString | Una cadena de 255 caracteres | 256 |
String[n] | Una cadena de n caracteres 1<=n<=255 | n+1 |
AnsiString | Nombre ilimitado de caracteres | Concepto no aplicable en este caso |
Pchar | Cadena finalizada en NULL | Concepto no aplicable en este caso |
Los tipos AnsiString y PChar permiten almacenar datos alfanuméricos pero su funcionamiento y uso es más especial.
El tipo String puede representar un ShortString o un AnsiString en función del modo en qué se encuentre el compilador.
Finalmente, los tipos booleanos implementados son Boolean, ByteBool, WordBool y LongBool. Los tres últimos sólo tienen sentido en programación de la API de Windows y el tipo Boolean es el que se emplea más habitualmente.
Para declarar variables emplearemos la palabra reservada var, los nombres de las variables seguidas de dos puntos y del tipo de variable. Por ejemplo :
var
Base : Integer;
Altura : Integer;
NombreUsuario : ShortString;
Todo lo que era aplicable a los nombres de las constantes también lo es para los nombre de variable. Por tanto altura, ALTURA y altura serian equivalentes. La declaración anterior se podía haber simplificado de la forma siguiente :
var
Base, Altura : Integer;
NombreUsuario : ShortString;
Podemos declarar dos o más variables del mismo tipo a la vez separándolas entre comas.
Hay que tener en cuenta de que no se pueden emplear las siguientes palabras para nombres de variables o constantes ya que son palabras reservadas para Pascal.
absolute | const | export | implementation |
abstract | constructor | exports | in |
alias | continue | external | index |
and | default | false | inherited |
array | destructor | far | initialization |
as | dispose | file | inline |
asm | div | finalization | interface |
assembler | do | finally | is |
begin | downto | for | label |
break | else | forward | library |
case | end | function | mod |
cdecl | except | goto | name |
class | exit | if | near |
new | private | repeat | try |
nil | procedure | saveregisters | type |
not | program | self | unit |
object | property | set | until |
of | protected | shl | uses |
on | public | shr | var |
operator | published | stdcall | virtual |
or | raise | string | while |
override | read | then | with |
packed | record | to | write |
pascal | register | true | xor |
popstack |
En esta lista se incluyen todas las palabras reservadas de FreePascal, Turbo Pascal y Delphi. Aunque la lista parece muy grande, no es nada complicado encontrar nuevos nombres para constantes y variables.
El bloque principal del programa
Una vez hemos declarado la etiqueta program, la clausula uses y las declaraciones de constantes y variables sólo falta el bloque principal de código del programa. El bloque donde se ejecutarán las ordenes. Este bloque, a diferencia de los anteriores, no se puede dejar de poner en un programa Pascal. El bloque principal del programa se define entre las palabras begin y end. Por ejemplo estas dos líneas ya son un programa válido para el compilador aunque no haga nada :
begin
end.
Nótese que el end _tiene que llevar un punto final indicando que termina el programa_. Es entre estas dos palabras que incluiremos nuestro código. Todas las órdenes que se incluyen en este bloque reciben el nombre de sentencias.
Los primeros programas
Vamos a hacer un programa que calcule el área de un triángulo dadas la base y la altura. El código podría ser el siguiente :
program Calcular_Area_del_triangulo;
var
base, altura, area : real;
begin
base := 2.4;
altura := 5.3;
area := 0.5*base*altura;
Writeln(area);
end.
Antes de comentar nada obsérvese que todas las líneas de Pascal suelen terminar en un punto y coma. Como excepciones notables tenemos en nuestro caso a var y begin.
Declaramos las variables base, altura y area de tipo real. Dentro del bloque de código asignamos el valor 2.4 a la variable base mediante el operador de asignación. Este operador := permite asignar valores a las variables. En la siguiente línea se hace lo mismo con la variable altura.
En la variable area se almacena el valor del producto de por la base por la altura. Finalmente esta variable la mostramos en la pantalla mediante la función Writeln.
Las funciones que necesitan parámetros se especifican entre paréntesis. Si tuviéramos que añadir más de un parámetro lo separaríamos entre comas.
El resultado que obtenemos en pantalla no es muy profesional, pero más adelante ya veremos como especificar los decimales que queremos obtener.
6.359999999999999E+000
Ya que el resultado de la operación 0.5*base*altura; es un real y Writeln puede mostrar reales podíamos haber simplificado el programa de la forma siguiente :
program Calcular_Area_del_triangulo;
var
base, altura : real;
begin
base := 2.4;
altura := 5.3;
Writeln(0.5*base*altura);
end.
Hemos empleado el asterisco * para indicar producto. Pero FreePascal incorpora más operadores aritméticos. Los operadores se distinguen por unarios, que sólo trabajan con un sólo elemento, o binarios, que trabajan con dos elementos.
Operadores unarios | Operación |
+ | Identidad de signo. |
– | Inversión del signo. |
Operadores binarios | Operación | Tipo de dato resultante |
+ | Suma aritmética | Admite operandos reales y enteros. Si los dos operandos son enteros el resultado es un entero. En caso contrario es un real. |
– | Resta aritmética | |
* | Producto aritmético. | |
** | Potencia. Ex 2**3 = 2^3 | Sólo admite operandos enteros y el resultado es un entero. |
div | División entera | |
mod | Residuo de la división entera | |
/ | División real | Admite operandos enteros y reales. El resultado siempre es un real. |
Los operadores tienen las mismas prioridades que en las operaciones matemáticas habituales. Si deseamos calcular 3+4 y multiplicarlo por 5 tendremos que hacer (3+4)*5 = 35 ya que si hacemos 3+4*5 = 23. Los paréntesis se pueden colocar en medio de la operación para modificar el orden de prioridad de los operadores.
begin
Writeln(3+4*5);
Writeln((3+4)*5);
Writeln((3+4)*5+6);
Writeln((3+4)*(5+6));
end.
En este aspecto hay que remarcar que los operadores con mayor prioridad son **, *, /, div y mod. Mientras que la suma y la resta son los que menos tienen. En el caso que todos tengan la misma prioridad la operación se lleva a cabo de izquierda a derecha.
Writeln(4*20 div 5);
Writeln(4*(20 div 5));
Writeln((4*20) div 5);
En este caso los tres resultados son idénticos y los paréntesis sólo tienen una finalidad esclarecedora. En los dos últimos casos la operación empezará siempre por el elemento que tenga paréntesis o que tenga más que los otros.
Introducción de datos
El programa de cálculo de áreas que hemos hecho antes funciona correctamente pero siempre devuelve el mismo resultado. Por ejemplo, vamos a hacer un programa que calcule la suma de n potencias de r > 1. O sea que nos diga el resultado de r^0 +r^1 +r^2 …+ r^n-1 = (r^n -1)/ (r-1).
program Calcular_n_potencias;
var
r, n : Integer;
begin
Writeln('R :');
Readln(r);
Writeln('N :');
Readln(n);
Writeln('Resultado :');
Writeln((r**n-1) div (r-1));
end.
En el anterior ejemplo hemos empleado la orden Readln para leer una entrada del teclado y almacenarla en la variable especificada en los parámetros de Readln. El usuario tiene que introducir un par de números. Por ejemplo si ejecutamos el programa e introducimos los datos siguientes obtendremos :
R : 5
N : 4
Resultado :
156
Comentarios en el código
Los programadores pueden situar comentarios en el código que no se compilará. Para indicar al compilador que un elemento es un comentario es necesario rodearlo de llaves { } o de los conjuntos siguientes (* y *). Finalmente si el comentario va desde un punto cualquiera hasta el final de la linea podemos emplear dos barras oblicuas //. No mezcle los caracteres { y } con (* y *) ni tampoco escriba un espacio entre el paréntesis y el asterisco porque entonces no se entiende como un comentario.
program Calcular_Area_del_triangulo;
{ Este comentario está hecho con llaves }
var
r, n : Integer;
(* Este, en cambio, emplea la notación antigua de Pascal *)
begin
Writeln('R :'); // Desde las 2 barras hasta el final de linea es un comentario
Readln(r);
Writeln('N :');
Readln(n);
Writeln('Resultado :');
Writeln((r**n-1) div (r-1));
end.
Profundizando aspectos
Trabajando con variables y tipos de datos
Hemos visto en ejemplos anteriores que trabajar con variables es tan sencillo como declararlas y después referirse en el código, por ejemplo, en una asignación o en una operación. Aún así, hay otras cuestiones que debemos conocer cuando trabajemos con variables.
Gestión de las variables
Los tipos de variables que estamos empleando no precisan de ningún tipo de operación de inicialización o de finalización. El compilador se encarga de todos estos aspectos reservando la memoria necesaria para las variables.
Compatibilidad y tipos de variables
Pascal es un lenguaje fuertemente tipificado. Esto quiere decir que las comprobaciones de tipos de datos son bastante estrictas. Por este motivo no podemos asignar cualquier valor a las variables sino variables o literales que sean compatibles. El programa siguiente es incorrecto sintácticamente :
var
cadena : string;
numero : Integer;
begin
cadena := 10; // No podemos asignar un numero a un string
numero := '10'; // No se puede asignar un string a un numero
cadena := numero; // Tipos incompatibles por asignación
end.
Para resolver algunos de los problemas de tipos que se presentan en Pascal tenemos dos formas.
Escoger una u otra dependerá de la situación en la que nos encontremos :
- Si los dos datos incompatibles representan una misma estructura de datos podemos probar un typecasting. Por ejemplo, los diferentes tipos de cadenas o de nombres enteros.
- Si los dos datos son de naturaleza distinta podemos recurrir a alguna función que transforme los datos. Por ejemplo, pasar un entero a cadena o un real a entero.
Algunas veces no será necesario realizar ninguna transformación. Es el caso de los enteros. Los enteros son compatibles "de abajo arriba". O sea, podemos emplear enteros pequeños como el Byte en asignaciones de enteros mayores como Integer o Cardinal. Habrá que tener en cuenta también si el entero es con signo o sin signo. Hay que observar también que el proceso contrario, "de arriba abajo", no siempre es posible.
var
pequeno : Byte;
grande : Longint;
begin
pequeno := 200;
grande := pequeno;
Writeln(grande); // 200
grande := 500;
pequeno := grande;
Writeln(pequeno); // 244 !
end.
La causa por la cual obtenemos 244 en el último caso es debido al rango del Byte 0..255 que no llega a 500. Los enteros, los caracteres y los booleanos, son tipos de datos llamados ordinales. Esto quiere decir que sus valores tienen un orden cíclico (en los reales, por ejemplo, no tiene sentido hablar de ordinalidad) y por tanto en un Byte después de 255 viene un 0. Por tanto 255 + 1 = 0. Cuando asignamos 500 mediante el Longint resulta que 500 = 256 + 224 = 0 + 224 = 224. O Expresado de otra forma 500 mod 256 = 224. Es importante tener en cuenta este hecho ya que es un error bastante habitual asignar tipos enteros demasiado pequeños que suelen dar comportamientos erráticos y difíciles de detectar. A menos que sea imprescindible (que podría ser), es recomendable emplear Integer o Longint en vez de Byte o Shortint.
[editar]
Typecasting
En muchos casos trabajar con un tipo u otro de entero no reviste ninguna importancia excepto por el rango en el que trabajemos. Algunas veces es necesario que nuestro entero tenga el tamaño adecuado. Para "amoldar" el tamaño de las variables podemos emplear el typecasting.
Para realizar un typecasting sólo hay que rodear la variable a amoldar con el nombre del tipo de dato al cual queremos ajustar. Los typecasting son habituales cuando se trabaja con clases y objetos. He aquí un ejemplo de typecasting con booleanos :
var
var_bool : Boolean;
begin
var_bool := Boolean(0);
Writeln(var_bool); // Escribe FALSE
var_bool := Boolean(1);
Writeln(var_bool); // Escribe TRUE
var_bool := Boolean(12);
Writeln(var_bool); // Escribe TRUE
end.
Esto es sintácticamente correcto ya que un booleano es nada más que un Byte que se interpreta cierto cuando tiene un valor distinto a cero. Otro typecasting muy usual es el de la conversión de caracteres a su valor ASCII. Por ejemplo :
var
caracter : Char;
begin
Write('Introduzca un carácter : ');
Readln(caracter);
Writeln('Su código ASCII es ', Integer(caracter));
end.
La instrucción Write es idéntica a Writeln pero no hace saltar el cursor a la línea siguiente. Write y Writeln permiten concatenar más de un parámetro separados por comas, en este caso un string y un Integer. Esta característica es única de Write, Writeln, Read y Readln aunque sólo se suele emplear en Write y Writeln.
En el caso anterior, si introducimos una A mayúscula obtendremos el valor 65 del código ASCII. Esto también es correcto ya que un carácter no es nada más que un Byte. Escribiendo Integer hacemos que Writeln lo interprete como si de una variable Integer se tratara.
[editar]
Funciones de conversión de tipo
Qué tenemos que hacer cuando necesitamos convertir una cadena de texto que tiene un numero a un entero o convertir un real a string ?
Para esto tendremos que emplear las funciones que incorpora la unit SysUtils. Las funciones que nos interesarán más son IntToStr, StrToInt, FloatToStr, FloatToStrF y FloatToText.
Convertir de entero a string
Nos puede interesar convertir un entero a string ya que muchas funciones sólo permiten strings como parámetros. Además, los strings se pueden concatenar con el operador +.
begin
Writeln('Hola '+'qué tal?');
end.
En el caso de Writeln no sería necesario pero muchas funciones sólo admiten un string y esta es una forma sencilla de añadir más de una o como veremos añadir enteros.
La función IntToStr toma como parámetro un entero y devuelve un String. Veamos el caso siguiente.
uses SysUtils; // IntToStr está definida en SysUtils
var
cadena : string;
anyos : Integer;
begin
Write('Cuantos años tienes ? '); Readln(anyos);
cadena := 'Tienes ' + IntToStr(anyos) + ' años';
Writeln(cadena);
end.
El punto y coma del final de cada sentencia nos permite agruparlas en una sola línea aunque no es recomendable, generalmente. Obsérvese la enorme diferencia entre anyos y 'años' pues la primera es una variable y la segunda una cadena de texto..
Ya que IntToStr devuelve un string lo puedo operar como si de un string se tratara, por ejemplo concatenándolo con el operador +.
Convertir de string a entero
En este caso la conversión no es tan simple pues corremos el riesgo de que la cadena de texto no pueda ser convertida a un entero. En este caso la función StrToInt lanzará una excepción. La gestión de excepciones la veremos más adelante, a pesar de esto veamos un ejemplo sencillo :
uses SysUtils;
var
sum_a, sum_b, total : string;
begin
sum_a := '100';
sum_b := '400';
total := IntToStr( StrToInt(sum_a) + StrToInt(sum_a) );
Writeln(total);
end.
Obsérvese la tercera sentencia que tiene una estructura muy interesante. Primero convertimos los string sum_a, sum_b a enteros mediante StrToInt. Ahora la suma es aritmética ya que los dos valores son enteros. Una vez hecha la suma transformamos de nuevo el entero en un string y lo almacenamos en una variable de tipo string. En este ejemplo, los enteros contienen números válidos que pueden ser convertidos a enteros sin problemas.
Convertir un real a string
Para convertir un real a string tenemos tres funciones : FloatToStr, FloatToStrF i FloatToText. Las dos últimas son más complejas ante la simplicidad de FloatToStr.
uses SysUtils;
var
prueba : real;
cadena : string;
begin
prueba := 10.5;
cadena := 'El valor es '+FloatToStr(prueba);
Writeln(cadena);
end.
Trabajar con constantes
A las constantes se les puede aplicar muchas de las cuestiones expuestas para las variables. Mientras la función de conversión no modifique el parámetro, se verá más adelante cómo, es posible sustituir una variable por una constante.
uses SysUtils;
const
NUMERO = 1000;
begin
Writeln('El numero es '+ IntToStr(NUMERO));
end.
Asignaciones aritméticas de variables
Antes hemos visto el operador := que es el operador de asignación por excelencia. Habitualmente, se emplean construcciones parecidas que se han simplificado en otros operadores de asignación. La tabla siguiente muestra la lista de operadores de asignación aritméticos de FreePascal. Estos operadores están disponibles sólo cuando añadimos el parámetro -Sc al compilador.
Expresión | Operación | Equivalencia |
x += y; | Suma "y" a "x" y lo guarda en "x". | x := x + y; |
x -= y; | Resta "y" a "x" y lo guarda en "x". | x := x – y; |
x *= y; | Multiplica "x" por "y" y lo almacena en "x". | x := x * y; |
x /= y; | Divide "x" entre "y" y lo almacena en "x". | x := x / y; |
Veamos un ejemplo :
var
a : Integer;
begin
a := 10;
a+=1;
Writeln(a); // 11
a := a + 1;
Writeln(b); // 12
end.
Expresiones e instrucciones
Hasta ahora hemos visto muchos ejemplos de expresiones (por ejemplo a*b + c*d) combinadas con instrucciones (por ejemplo a:= 10;). Una expresión es siempre algo que tiene un valor, ya sea una operación matemática simple como las que hemos visto antes. El valor de la expresión viene determinado por los elementos que intervienen en la operación que suelen ser variables, literales, constantes y operadores. Así el producto de dos enteros es un entero mientras que un entero por un real es una expresión real.
Las instrucciones son acciones que se realizan en el programa. Las instrucciones en Pascal reciben el nombre de sentencias. Hasta ahora hemos visto dos sentencias muy habituales : las sentencias de asignación y la sentencia de llamada de funciones y procedimientos. Pascal, afortunadamente, dispone de un conjunto de sentencias más elaborado que veremos en el siguiente capítulo.
Sentencias estructuradas
Introducción
Las sentencias estructuradas, basadas en más de una sentencia, son de hecho sentencias con construcciones especiales que permiten, básicamente, alterar la ejecución secuencial de las sentencias de un programa.
La estructura condicional if
Antes hemos visto por ejemplo calcular r^0 +r^1 +r^2 …+r^n-1 =(r^n -1) / (r-1) cuando r > 1. En en código anterior no hemos comprobado en ningún momento que r fuera mayor que 1. Si r = 1 el programa fallaba ya que se produce una división entre cero. Para evitar que el usuario introduzca un valor menor o igual que 1 tendremos que comprobar es mayor que 1. Con la finalidad de comprobar la certeza o falsedad de una condición Pascal (y muchos lenguajes de programación) dispone de la sentencia if.
La estructura de if es la siguiente :
if expresionBooleana then sentencias;
Es importante que la expresión entre if y then sea una expresión booleana. Vamos a ver el código del programa una vez modificado :
program Calcular_n_potencias;
var
r, n : Integer;
begin
Writeln('R :');
Readln(r);
if r > 1 then
begin
Writeln('N :');
Readln(n);
Writeln('Resultado :');
Writeln((r**n-1) div (r-1));
end;
end.
Obsérvese que en este caso la expresión booleana r > 1 sólo es cierta cuando r es mayor que 1. Si es cierta se ejecuta lo que se encuentra después del then. En este caso es un bloque de sentencias. En Pascal los bloques de sentencias, aparte del principal, van entre un begin y un end con punto y coma. Si r > 1 no es cierto entonces no se ejecutará nada más.
Habitualmente, precisaremos de código que se ejecutará cuando la condición no se cumpla. Para hacerlo hay que emplear la estructura siguiente :
if expresionBooleana then sentencias else sentencias;
Por ejemplo modificando el programa anterior tendríamos :
program Calcular_n_potencias;
var
r, n : Integer;
begin
Writeln('R :');
Readln(r);
if r > 1 then
begin
Writeln('N :');
Readln(n);
Writeln('Resultado :');
Writeln((r**n-1) div (r-1));
end
else
begin
Writeln('R tiene que ser un valor superior a 1');
end;
end.
Si el usuario introduce un valor menor o igual a 1 entonces obtiene el mensaje que "R tiene que ser un valor superior a 1". Obsérvese también que sólo en este caso end tiene que ir sin ningún punto y coma pues va seguido de else.
Si el número de sentencias de then o else es sólo una es posible omitir begin y end. Pero sólo en este caso. Si deseamos que se ejecute más de una sentencia no tendremos más remedio que emplear begin y end. En cualquier caso, el uso de begin y end es mejor pues evita muchos errores típicos.
var
numero : Integer;
begin
Write('Introduzca un número : '); Readln(numero);
if numero mod 5 = 0 then Writeln('Es divisible por 5')
else Writeln('No es divisible por 5');
end.
Observe que tampoco la sentencia anterior a else tiene que llevar un punto y coma. Un número es divisible por otro si su residuo (operación mod) es cero.
De las estructuras condicionales anteriores hemos visto unos pocos operadores llamados relacionales que permiten construir expresiones booleanas más o menos complicadas.
Operadores lógicos booleanos
Pascal incorpora un conjunto de operadores booleanos lógicos que permiten modificar las expresiones booleanas. Las tres operaciones booleanas que se pueden aplicar a expresiones booleanas son las clásicas de la lógica : not (negación), and (conjunción) y or (disyunción).
Not es un operador unario (con un solo operando) y devuelve el valor contrario a la expresión booleana.
not | |
true (verdadero) | false (falso) |
false (falso) | true (verdadero) |
Los operadores and y or son operadores binarios, trabajan sobre dos operandos. And devuelve true si los dos operandos son true y or retorna true si alguno de los operandos lo es.
and | or | ||
false | false | false | false |
false | true | false | true |
true | false | false | true |
true | true | true | true |
Finalmente disponemos de un tercer operador binario xor, disyunción exclusiva, este devuelve cierto cuando los dos elementos tienen valores diferentes.
xor | ||
false | false | false |
false | true | true |
true | false | true |
true | true | false |
Los operadores booleanos combinados con los operadores relacionales, de los cuales hemos visto antes el operador > y el =, permiten construir expresiones booleanas muy eficientes. Los operadores relacionales relacionan dos elementos y devuelven una expresión booleana.
Operador | Tipos de datos | Resultado |
= | Todos los ordinales, reales y string. | Enteros y Reales. Cierto si los dos operandos son idénticos. |
Caracteres. Si el valor ASCII de los dos caracteres es el mismo. | ||
Booleanos. Si las dos expresiones booleanas tienen el mismo valor. | ||
String. Si las dos cadenas comparadas son idénticas incluso en las mayúsculas. | ||
Devuelve true cuando = ha devuelto false y viceversa. | ||
< | Todos los ordinales, reales y string. | Enteros y reales. Devuelve cierto si el primer operando es menor que el segundo. |
Devuelve cierto si el valor ASCII del primer carácter es menor al valor del segundo. | ||
String. Devuelve cierto si la primera cadena es alfabéticamente anterior a la segunda. El alfabeto de referencia es el ASCII^1 <#sdfootnote1sym>. | ||
Booleanos. Si el primer operador es false y el segundo true entonces el resultado es cierto. Téngase en cuenta de que false es menor que true y true es mayor que false ya que los booleanos son ordinales. | ||
> | Todos los ordinales, reales y strings. | Enteros y reales. Devuelve cierto si el primer operando es mayor al segundo. |
Caracteres. Devuelve cierto si el valor ASCII del primer operando es mayor al segundo. | ||
String. Devuelve cierto si la primera cadena es alfabéticamente posterior a la segunda. El alfabeto de referencia es el ASCII. | ||
Booleanos. Si el primer operador es true y el segundo false entonces el resultado es cierto. | ||
<= | Todos los ordinales, reales y string. | Enteros y reales. Devuelve cierto si el primer operando es menor o igual al segundo. |
Caracteres. Devuelve cierto si el valor ASCII del primer operando es menor o igual al segundo. | ||
String. Devuelve cierto si la primera cadena es alfabéticamente anterior o idéntica a la segunda. El alfabeto de referencia es el ASCII. | ||
Booleanos. Sólo devuelve falso si el primer operador es true y el segundo false. En otros casos devuelve cierto. | ||
>= | Todos los ordinales, reales y string. | Enteros y reales. Devuelve cierto si el primer operando es mayor o igual al segundo. |
String. Devuelve cierto si la primera cadena es alfabéticamente posterior o idéntica a la segunda. El alfabeto de referencia es el ASCII. | ||
Booleanos. Sólo devuelve false si el primer operando es false y el segundo es true. En otros casos es siempre cierto. |
Vamos a ver ejemplos de combinación de operadores relacionales. Por ejemplo, para determinar si un numero es 0 ? x ? 10 (mayor o igual que cero y menor o igual que diez). Podríamos hacerlo de la forma siguiente :
Este ejemplo funcionaría perfectamente pero es mucho mejor combinar
if numero >= 0 then
begin
if numero <= 10 then
begin
…
end;
end;
operadores booleanos y relacionales para obtener un código más eficiente :
if (numero >= 0) and (numero <= 10) then
begin
…
end;
En este caso hemos empleado el operador booleano and ya que nuestro número es "mayor o igual que cero y menor o igual que 10". Obsérvese que en este caso se necesitan paréntesis para separar las diferentes operaciones ya que los operadores relacionales tienen la misma prioridad que los booleanos y es necesario que los relacionales sean primeros pues se intentaría hacer un and con un numero y no es un booleano.
Supongamos que disponemos de una variable de tipo carácter. Queremos comprobar que la variable contiene una 'a' minúscula o una 'A' mayúscula, entonces una forma de hacerlo es :
if (Caracter = 'a') or (Caracter = 'A') then
begin
…
end;
Finalmente, como ejemplo, vamos a definir la operación xor con and y or. En este caso las dos estructuras siguientes son equivalentes :
var
a, b : Boolean;
begin
if a xor b then
begin
…
end;
if ((not a) or b) or (a or (not b)) then
begin
…
end;
end;
La estructura iteractiva for
Muchas veces nos interesará realizar una misma o parecida operación dentro de un conjunto limitado de valores. Con esta finalidad Pascal posee la estructura for.
Para poder realizar la estructura for es necesario emplear una variable contadora que variará en 1 y que tiene que ser de tipo entero necesariamente. Veamos un ejemplo simple :
var
numero : Integer;
begin
for numero := 1 to 4 do
begin
Writeln('Repetición número ', numero);
end;
end.
La salida del programa es la que sigue :
Repetición número 1
Repetición número 2
Repetición número 3
Repetición número 4
Como se ve, el código de dentro del bucle se ha ejecutado empezando desde el valor 1 de la variable numero hasta el valor 4, momento en el cual el bucle termina.
En el caso anterior podíamos haber escrito este código equivalente pues el bloque begin y end sólo tiene una sentencia, pero sólo en este caso :
for numero := 1 to 4 do Writeln('Repetición número ', numero);
Obsérvese que si hace for numero := 1 to 4 do; con punto y coma después de do, el compilador entenderá que es una sentencia vacía y no hará nada más que incrementar la variable, pero nada más.
Si en vez de incrementar la variable queremos decrementarla hay que cambiar to por downto a la vez que cambiar el origen y el final.
for numero := 4 downto 1 do Writeln('Repetición número ', numero);
Si los parámetros origen y final del contador son incorrectos, es decir que el origen es superior al final y tenemos un to, el for ya ni empezará y continuará con la sentencia siguiente después del for.
var
contador : Integer;
Página anterior | Volver al principio del trabajo | Página siguiente |