Informática
Lenguajes de Programación
ADA
HISTORIA, CARACTERÍSTICAS generales
El lenguaje de programación Ada fue diseñado en un esfuerzo de colaboración, patrocinado por el Departamento de Defensa con la participación de la industria, mundo académico y comunidad internacional. Su propósito principal fue proporcionar un lenguaje de alto nivel en el que pudieran expresarse, desarrollarse y mantenerse los problemas de programación de sistemas. Ada contiene mecanismos especiales para la gestión de sucesos concurrentes en un entorno de tiempo real, desarrollando paquetes específicos de la aplicación y definiendo operadores y procedimientos genéricos.
Fue a principios de los 70s cuando el Departamento de Defensa de los EE.UU., identificó un grave problema en el crecimiento del coste del software en los sistemas de computadoras "empotradas", es decir, sistemas que están incluidos en distintos vehículos militares.
La principal causa de este problema era la ausencia de un lenguaje de programación adecuado y de un entorno de programación para desarrollar y mantener este software. Las aplicaciones caían en el área general de la "programación de sistemas" y la mayoría de estos programas estaban repletos de líneas de código escritas en ensamblador, obviamente variaba según la máquina. Por lo tanto afectaba a su transportabilidad.
En 1975 el Departamento de Defensa de los EE.UU formó un grupo de trabajo en un lenguaje de alto orden cuya misión era:
1) Identificar el conjunto completo de requerimientos para los lenguajes del Departamento de Defensa (DD).
2) Evaluar la adecuación de los lenguajes existentes seleccionados sobre la base de éstos requerimientos.
3) Hacer una recomendación sobre el DD debía adoptar uno o más lenguajes existentes.
Durante el período 1976-1977, se realizó una extensa evaluación de los veintitrés lenguajes existentes (incluyendo SIMULA, ALGOL, JOVIAL, PASCAL FORTRAN, COBOL, y PL/I, (pero excluyendo sorprendentemente al C) sobre la base de los requerimientos TINMAN. El informe final concluyó con que ninguno de los veintitrés lenguajes evaluados eran candidatos y que debía desarrollarse un nuevo lenguaje sobre un lenguaje que sirviera como base apropiada. Los candidatos fueron Pascal, Algol, y PL/I.
En 1977 se inició el diseño de un nuevo lenguaje como un proyecto competitivo, y mas adelante se seleccionaron cuatro de los competidores para desarrollar diseños del lenguaje. Estos cuatro diseños, llamados, Azul, Rojo, Amarillo, y Verde, (para preservar el anonimato), fueron evaluados extensamente en 1978 y se seleccionaron dos para el final. Al final el diseño Verde, propuesto por Honeywell-Bull, fue seleccionado como el nuevo lenguaje de alto nivel de Departamento de Defensa de EE.UU. El lenguaje se llamó Ada en reconocimiento a Augusta Ada Byron, hija del poeta Lord Byron. Ella es considerada por algunos como la primera programadora del mundo, puesto que trabajó con Charles Babbage, a principios del siglo XIX.
Desde 1979, los esfuerzos se han dirigido a desarrollar un documento e implementaciones estándar para Ada. El primero de tales documentos se publicó en 1980 y la versión final, llamada Reference Manual for the Ada Programming Languaje, fué aprobada a principios de 1983 como el estándar militar.
Esa fue la historia de Ada, un lenguaje que a nivel mundial costó muchos miles de dólares. Hoy en día tenemos la versión de GNAT Ada95 que es muy parecida al Pascal for Windows.
descripción general
-
Clasificar a Ada como un lenguaje Pascal-like,sería un engaño. Sólo la mitad de Ada es directamente comparable con Pascal (sin embargo, esta mitad corrige la mayoría de las fallas de diseño de Pascal y es motoriamente más rico). La otra mitad soporta conceptos importantes como encapsulamiento, genéricos, excepciones y concurrencias; y en este aspecto Ada extiende grandemente lo brindado por Pascal.
-
Es un lenguaje imperativo descendiente del Pascal, el cual posee:
-
Una estructura en bloques: destinado a controlar mecanismos en “tiempo real” (o sea una velocidad compatible con las necesidades reales) pero de gran complejidad.
-
Es fuertemente tipado: este hecho se hace cumplir a través de unidades por separado compiladas del programa, que es una necesidad para la integración de un sistema grande.
-
El ADA es un lenguaje grande que es relativamente difícil de compilar porque hace muchas comprobaciones en tiempo de compilación. Se ha estimado que un compilador de Ada completamente validado requiere cerca de 50 años de horas hombre para escribirlo y ponerlo a punto.
-
Dicho lenguaje presenta dos versiones normalizadas:
-
Ada 83 (ISO 8652:1987)
-
Ada 95 (ISO 8652:1995), orientado a objetos.
-
Se ha utilizado en el desarrollo de programas muy grandes, llegando hasta el millón de líneas de código.
-
Plataforma: Todos los procesadores modernos y sistemas operativos tienen una buena opción de compiladores y de herramientas (aunque el Apple Macintosh no lo implementa bien).
-
La interconexión a otros sistemas ha demostrado ser en ocasiones difícil. Por ejemplo, el lenguaje no permite procedimientos como parámetros a los procedimientos, una técnica a veces llamada " llamada hacia atrás " que es utilizado por la mayoría de las ventanas y de los GUIs. El SQL se puede embutir en programa Ada .
-
Una parte no es compilador-dependiente, pero la conexión es limitada al nivel ensamblador o al código de C se proporciona a menudo.
-
Los programas en el Ada son altamente portables como el proceso de la validación del compilador se detalla y prohíben los compiladores que validan solamente un subconjunto de Ada.
-
Usado por el departamento de defensa de E.E.U.U.
-
Programadores expertos: Muchos " Programadores de Ada " se emplean en los proyectos existentes, pero hay una escasez del personal experto en Ada y disponibles para los nuevos proyectos. Relativamente pocas universidades (media docena en el Reino Unido) enseñan Ada en sus cursos del grado de la informática.
-
El Ada 83 es conveniente para el desarrollo del sistema grande donde será crucial la confiabilidad.
-
Diseño de software robusto y fiable.
-
Énfasis en la reutilización del sofware.
-
Lenguaje standard.
-
Pensado para realizar sistemas empotrados de gran dimensión.
-
Ada 83(basado en objetos):
- Legibilidad
-
Fuertemente tipado
-
Construcción de grandes programas
-
Manejo de excepciones
-
Abstracción de datos
-
Procesamiento paralelo
-
Unidades genéricas
-
Ada 95 (orientado a objetos)
-
Herencia
-
Interface con otros lenguajes
Características generales
-
Legibilidad: programas fáciles de leer (libertad de formatos de escritura).
-
Tipado fuerte: todo objeto tiene componentes de valor definido (es mucho mas fuerte que Pascal).
-
Capaz de construir grandes programas: compilación separada de los distintos paquetes (módulos).
-
programación estructurada
-
programación concurrente
-
Manejo de excepciones: ideal para la programación en tiempo real.
-
Abstracción de datos.
-
Unidades genéricas: que se pueden agrandar todo lo que queramos con nuevas funciones.
-
Alta transportabilidad de los programas entre distintas plataformas: UNIX, OS/2, Win32.
-
Criticalidad: razonablemente bueno.
Ventajas y desventajas de ADA
Ventajas: Legibilidad; Es fuertemente tipado (para la seguridad máxima); corrección de errores; Abstracción de los datos; Asignación (dentro del lenguaje para mejorar portabilidad y confiabilidad); y unidades genéricas (utiliza la creación de bibliotecas de componentes reutilizables). El Ada es utilizado en aplicaciones militares pero también en aplicaciones civiles similares (por ej., en el sector de la aviación).
Desventajas: Tiene ciertas características bajas, por ejemplo, no tiene conversión chequeada. La dirección de anomalía puede producir los sistemas que son duros de razonar alrededor. La orden de la elaboración de las unidades de la biblioteca es un problema. El lenguaje tiene relativamente pocas inseguridades considerando su gran tamaño; de hecho el tamaño y la complejidad es probablemente la preocupación principal.
El Ada es un lenguaje de programación diseñado para utilizar la construcción de los sistemas de software duraderos, altamente confiables. El lenguaje incluye recursos para definir los conjuntos de tipos, de objetos, y de operaciones relacionados. Los conjuntos pueden ser dados parámetros y los tipos se pueden extender para utilizar la construcción de las bibliotecas de los componentes de software reutilizables, adaptables. Las operaciones se pueden poner en ejecución como subprogramas usando las estructuras convencionales del control secuencial, o como entradas que incluyan la sincronización de cuerdas de rosca simultáneas del control como parte de su llamada. El lenguaje trata modularidad en el sentido físico también, con un recurso de utilizar la compilación separada.
El lenguaje incluye un recurso completo para la ayuda del tiempo real, programación simultánea. Los errores se pueden señalar como anomalías y manejar explícitamente. El lenguaje también cubre la programación de sistemas; esto requiere control exacto concluido la representación de datos y del acceso a las características sistema-dependiente. Finalmente, un ambiente predefinido de los conjuntos de estándar se proporciona, incluyendo los recursos para, entre otros, entrada-exit, manipulación de cadena, las funciones elementales numéricas, y generación del número al azar.
tipos de datos simples
-
Un tipo es un conjunto de objetos (variables) que se caracteriza por:
*Un conjunto de valores que pueden tomar los objetos de ese tipo.
*Un conjunto de atributos (por ejemplo LAST ).
*Un conjunto de operaciones realizables con los objetos de ese tipo.
-
Tipado fuerte: no se pueden usar valores de un tipo en operaciones de otro tipo sin efectuar una conversión de tipo explícita.
-
Un objeto (variable) se introduce en un programa mediante una declaración, dándole un nombre e indicando, el tipo al que pertenece:
*I: INTEGER; -- objeto sin inicializar.
*Dato: INTEGER := 12; -- objeto con valor inicial.
*J, K : INTEGER := Dato; -- elaboración lineal de declaraciones.
*Pi: constant := 3.14159 ; -- objeto declarado como constante.
-
Cuando se refina un tipo, se puede elegir el obtener el resultado de un subtipo (sbutype) o un tipo derivado (derived type). Los subtipos son convenientes ya que heredan todas las propiedades del tipo original. Los tipos derivados tienen la ventaja de poder proporcionar protección contra un mal uso, accidental o intencionado, de los objetos.
-
Pueden crearse subtipos de subtipos.
elementales
escalares
discretos
enumeration
character
boolean
other enumeration
integer
signed integer
modular integer
real
floating point (punto flotante)
fixed point (punto fijo)
ordinary fixed point
decimal fixed point
ELEMENTALES
- Escalares: los tipos escalares abarcan tipos de ENUMERACIÓN, ENTERO, y REALES. Los tipos enumeración y entero se llaman tipos discretos; cada valor de un tipo discreto tiene un número de posición que es un valor del número entero. Los tipos del número entero y los tipos reales se llaman tipos numéricos.
Rangos: un rango tiene un límite inferior y un límite superior y especifica un subconjunto de los valores de un cierto tipo escalar (el tipo del rango). Un rango con un límite más bajo L y el límite superior R es descrito por ``l.. R ' '. Si R es menos que L, entonces el rango es un rango nulo, y especifica un conjunto vacío de valores. Si no, el rango especifica los valores del tipo del límite más bajo al límite superior, inclusivos.
El rango base de un tipo escalar es el rango de los valores finitos del tipo que se puede representar en cada objeto de tipo libre.
-
Tipo entero: el rango base de un tipo del entero con signo incluye por lo menos los valores del rango especificado. Un tipo modular es un tipo de número entero cuyo modulo aritmético es un módulo positivo especificado.
El conjunto de los valores para un tipo del entero con signo es el (infinito) set de los números enteros matemáticos, aunque solamente valores del rango base del tipo se utiliza completamente para las operaciones run-time. El conjunto de los valores para un tipo modular del número entero es los valores a partir de la 0 a uno menos que el módulo, inclusive.
-
Enteros predefinidos:
integer, long_integer, short_integer
-
Subtipos de enteros predefinidos:
natural, positive
-
Definición de tipos enteros:
type DigitosOctales is range 0..7;
-
Enteros modulares:
type IndiceBuffer is mod 200;
-
Tipo enumerado: una definición de tipo enumeración define un tipo enumeración. La elaboración de una definición de tipo enumeración crea el tipo de la enumeración y su primer subtipo, que se obliga al rango base del tipo. En un tipo enumerado se pueden combinar identificadores, caracteres y cadenas.
Además:
- Sobrecarga de constantes enumeradas:
type mineral is (ambar, cuarzo, pirita);--mineral'(ambar)
- Constantes enumeradas caracter o literal
type cifraromana is (`I','V','X','D','C','L','M');
- Posiblilidad de conversión en cadena.
put(color'image(rojo))
Tipo Booleano: hay una enumeración predefinida llamada Boolean, declarado en la parte visible del conjunto estándar. Tiene los dos literales de la enumeración TRUE y FALSE ordenado con la relación FALSE < TRUE. Cualquier descendiente del tipo predefinido booleano es llamado un tipo booleano.
-
Integer: es un verdadero tipo de Ada, el Flota está declarado en algún lugar a partir de un tipo como flotante predefinido. A este tipo se le pueden imponer restricciones y atributos.
- Tipo Real: el tipo real provee de aproximaciones a los números reales, con los límites relativos debido a los errores para los tipos de punto flotante, y los límites absolutos para los tipos de punto fijo.
Dentro de éste se puede encontrar:
-
Real predefinido
-
Tipos de punto flotante (o coma flotante): el límite del error es especificado como precisión relativa dando el número mínimo requerido de dígitos decimales significativos. El conjunto de valores para un tipo de punto flotante es el (infinito) set de números racionales. El rango bajo de un tipo de punto flotante es simétrico alrededor del cero, a menos que en él pueda incluir algunos valores negativos adicionales en algunas puestas en práctica.
-
Tipo fixed point: un tipo de punto fijo es un tipo ordinario de punto fijo, o un tipo decimal de punto fijo. El límite del error de un tipo de punto fijo se especifica como valor absoluto, llamado el delta de tipo de punto fijo.
- Tipo Puntero: solamente se puede apuntar a una variable con nombre (puntero a la memoria de pila) si esta ha sido declarada como aliased. Esto atenúa el problema de alias. La asignación de memoria dinámica se realiza mediante el procedimiento new.
Hay dos formas de dale valor al objeto:
Al declararlo:
l:new nodo'(ant=>nil,sig=>nil,info=>0);
Al asignarlo:
l.info:=0;
También existen diferentes tipos de punteros:
-
Punteros a objetos declarados (no anónimas):
-
Punteros a subprogramas
Estructuras de datos principales
compuestos
access
access-to-object
access-to-subprogram
array
string
other array
untagged record
tagged
task
protected
Un tipo compuesto (o tipo de estructura de datos) es un tipo cuyos valores están compuestos o estructurados por valores simples; los lenguajes de programación soportan una gran variedad de estructuras de datos : tuplas, registros, variables, uniones, arreglos, conjuntos, cadenas, listas, árboles, archivos secuenciales, archivos de acceso directo, relaciones, los tipos de tareas, los tipos protegidos, etc. Todos estos tipos, en realidad pueden ser entendidos en términos de pequeños números de conceptos de estructura. Estos conceptos son:
* Producto cartesiano (tuplas y registros)
* Uniones disjuntas (variables y uniones)
* Mapping (arreglos y funciones)
* Powersets (conjuntos)
* Tipos recursivos (estructuras de datos dinamicas)
Los tipos de acceso me indican que valores proporcionan al acceso los objetos o los subprogramas.
Una de las características importantes de los tipos registro y array de Ada es que pueden variar en ciertos aspectos. En esto Ada ha tenido en cuenta las deficiencias de Pascal y ha proporcionado flexibilidad, manteniendo una estricta seguridad.
-
Tipo Array: un objeto array es un objeto compuesto que contiene componentes del mismo subtipo. El nombre para un componente de un array utiliza uno o más valores de índices que pertenecen a los tipos discretos especificados. El valor de un objeto array es un valor compuesto que consiste en los valores de los componentes. Un tipo array incorpora el tipo de sus límites de índice pero no sus valores actuales. Ada permite tipo anónimos, es decir, sin nombre; lo que permite la implementacion de arrays dinamicos. Los arrays dinamicos posibilitan tener objetos array de tamaños a especificar en la fase de ejecución; los arrays sin condicionantes facultan el tener tipos array que acepten objetos array de cualquier tamaño. El ejemplo clásico de un tipo array sin condicionantes es el tipo conferido string que se define por cualquier numero entero de subscriptores desde 1 en adelante.
Ejemplo: type Vector is array (Integer range <>)of Real; (ARRAY NO RESTRINGIDO)
type PaletaDeColores is array (colores) of Boolean;
-
Tipo Registro: un objeto de registro es un objeto compuesto que consiste en components nombrados. El valor de un objeto de registro es un valor compuesto que consiste en los valores de los componentes.
Definición de un tipo registro:
type fecha is record
dia,mes,anio:integer;
end record;
Cumpleanios:fecha:=(dia=>27,mes=>10,anio=>96);
Registros discriminados: la inicialización de un registro discriminado puede ser restringida (el valor del discriminante no varia en la ejecución) o no.
type TipoBuffer (tamanio: TamaniBuffer:=100) is
record
posicion:TamanioBuffer:=0;
valor:string(1..tamanio);
end record;
teclado:buffer (256);
Los objetos tipo registro pueden tambien variar en dos formas:
-
Seleccionando una de las opciones de la lista de campos dada en el tipo
-
Proporcionando un valor para un limite de un array dinamico
Estructuras de control | ||||
Repetitivas | selectivas | |||
loop <...> end loop ; | while <BOOLEAN expression> loop <...> end loop ; | for <loop index> in <range> loop <...> end loop ; | if <condition>
then <...> end if ; | case <selector>
is <...> end case ; |
Estructuras de control secuenciales
-
Asignación:
*Valor := 1;
*Dato := Valor +3;
-
Nula:
*null;
-
Llamada a procedure:
*Text_IO.Put_Line(“Hola a todos”);
*Put(“Introducir variable”);
*Stacks.Push(23.56,Pila);
-
Return:
*return;
*return PI*2.0;
-
Bloque :
declare -- variables locales al bloque
local1 : INTEGER;
begin -- código del bloque
local1 := 2 ;
valor := valor /local1;
end;
Estructuras de control condicionales
Los comandos condicionales no determinístico tienden a estar disponible sólo en los lenguajes de programación concurrentes (tal como Ada), donde el no determinismo está presente de cualquier manera, pero sus ventajas no se restringen a tales lenguajes.
- Estructura IF-ELSE
<Condición> IF <lista_de_sentencias> else <lista_de_sentencias2>
Una declaración if se selecciona para la ejecución en la mayoría una de las secuencias de declaraciones incluidas, dependiendo del valor (de la verdad) de unas o más condiciones correspondientes.
Para la ejecución de una declaración if, se evalúa la condición especificada, y algunas condiciones especificadas después de endif, se evalúan en sucesión, hasta que evalúa para TRUE o todas las condiciones se evalúan FALSE. Si una condición evalúa para TRUE, después se ejecutan las secuencias de declaraciones correspondientes; si no se ejecuta ninguna de ellas.
La sentencia else es Opcional.
if Condición then
-- hacer algo
else - hacer algo
end if;
- Estructura CASE
Una declaración CASE selecciona para la ejecución una de un número de secuencias de declaraciones alternativas; la alternativa elegida es definido por el valor de una expresión.
Se espera que la expresión sea de tipo discreto. El tipo previsto para cada selección discreta es el tipo de la expresión. Deben cubrirse todos los valores posibles. Solo es aplicable a tipos discretos. Las opciones son siempre valores estáticos.
case Dia is
when LU | MA | MI | JU | VI => trabajar;
when others => Descansar;
end case;
case Dia is
when LU | MA | JU | VI => Real_Time;
when MI => null;
when others => Descansar;
end case
case Dia is
when LU .. VI => Trabajar;
when otrhers => Descansar;
end case;
Estructuras de control cíclicas
- Estructura del tipo DO -LOOP
Una declaración LOOP incluye las secuencias de declaraciones que debe ser ejecutado en varias ocasiones, cero o más veces.
Si una declaración LOOP tiene más de un identificador de declaración LOOP, después el identificador será relanzado después del bucle del extremo; si no, no habrá un identificador después del bucle del extremo.
Para la ejecución de una declaración LOOP, las secuencias de declaraciones se ejecutan en varias ocasiones, cero o más veces, hasta que la declaración LOOP es completo. La declaración LOOP se completa cuando una transferencia del control ocurre o, en el caso de un esquema de iteración, según lo especificado abajo.
Un parámetro del bucle es una constante; no puede ser actualizado dentro de las secuencias de declaraciones del bucle
limit start DO ... I ... LOOP .
I es optional. I devuelve start start+1 ... start+n-1.
start debería ser más chico que limit.
- Estructura EXIT
Una declaración EXIT se utiliza para terminar la ejecución de una declaración LOOP que incluye; la terminación es condicional si la declaración EXIT incluye una condición.
El nombre de LOOP, si lo hay, en una declaración EXIT resuelven denotar una declaración LOOP.
Cada declaración EXIT se aplica a una declaración LOOP; de ésta es la declaración LOOP del que sale. Una declaración EXIT con un nombre se permite solamente dentro de una declaración LOOP denotado por el nombre, y se aplica a esa declaración LOOP. Una declaración EXIT sin un nombre se permite solamente dentro de una declaración LOOP, y se aplica que incluye el íntimo.
exit; -- incondicional
exit when A=0; -- condicional
Bucle_externo:
loop
loop
….
exit Bucle_Externo when Condicion;
end loop;
end loop;
- Estructura del tipo while-repeat
Mientras condición sea distinta de cero repite una serie de instrucciones, hasta que su valor sea cero.
BEGIN <Lista_de_sentencias1> <condición> WHILE <Lista_de_sentencias2> REPEAT
- Estructura de tipo FOR
Para la realización de ciclos de este tipo, se apela a un estructura do...loop, y el uso de una instrucción especial i que incrementa en 1 cada vez que se cumple un ciclo.
Ejemplo:
-
for I in 5 .. 9 loop
-- hacer algo
end loop;
-
Los bucles loop pueden manejar expresiones dinámicas.
-
Las variables índice se crean en el momento de ejecutar el bucle.
-
El índice debe ser de un tipo discreto.
-
Los incrementos son unitarios.
Estructuras de control: Procedimientos, Funciones, Subrutinas.
-
Dichas estructuras de control en general pueden sobrecargarse. Es distinto la sobrecarga que la ocultación:
ocultación: el nombre es el mismo, el número de parámetros y su tipo también.
sobrecarga: el nombre es el mismo, los parámetros o tipos no.
En caso de que se presente ambigüedad se puede especificar el tipo mediante calificación.
-
Pueden declararse procedures y functions dentro de otras.
-
Si una function o procedure no requiere de parámetros en la llamada no se ponen ().
-
Es posible asignar valores por defecto a los parámetros de una subrutina (aunque no con los operadores).
-
Procedimientos: subprograma que se puede llamar como parte de una expresión, a diferencia de las funciones, no devuelven un resultado, aunque puede haber return. Relacionados con la abstracción de acción.
-
Esta permitido hacer llamadas recursivas dentro de los procedimientos.
-
Los parámetros pueden ser de tres modos:
-
in: el parámetro formal es una constante, se lee pero no se escribe.
-
out: el parámetro formal es una variable, se escribe pero no se lee.
-
in out: el parámetro formal es una variable, se escribe y se lee.
-
Pueden emplearse arrays irrestringidos como parámetros.
-
Puede emplearse la notación nombrada al llamar a un procedure o una function aunque no con operadores.
-
Se pueden descomponer en especificación:
procedure ordenar (t: in out tabla);
y cuerpo
procedure ordenar (t: in out tabla) is
-- declaraciones
begin
-- sentencias
end ordenar;
-
Funciones: es un subprograma que se puede llamar como parte de una expresión, el cual devuelve un dato. Relacionadas con la abstracción de valor.
-
El cuerpo de una función puede tener varias sentencias return.
-
Es posible redeclarar operadores, aun sin cambiar su sintaxis de llamada.
-
Un parámetro formal puede ser cualquiera, pero ha de tener un nombre de tipo, puede ser también un tipo array irrestringido, los límites se determinan en la llamada.
-
Solo admiten parámetros in.
-
También tienen especificación:
function cuadrado (x: float) return float;
y cuerpo
function cuadrado (x: float) return float;
begin
return x**2;
end cuadrado;
-
Esta permitido hacer llamadas recursivas dentro de las funciones.
Ejemplo:
function Sin(X:FLOAT ) return FLOAT is -- el parámetro actúa como una constante
R: FLOAT; -- variable local a la función, parte declarativa
begin
-- calcular el seno de un ángulo y ponerlo en R
return R; -- la elaboración de return puede ser de una complejidad arbitraria
end Sqrt; Y:= Sin(X) +3.0; --ejemplo de llamada a la función
-
Sobrecarga de operadores:
Function “+” (m1,m2: matriz) return matriz;
Entrada y Salida de Datos
Entrada de datos X: Normalmente se va a ejecutar a través de instrucciones de lectura, y en lo que se le pide al usuario la información que el programa va a necesitar para ejecutarse y se hace a través de lecturas.
En Ada no existen sentencias de entrada y salida que formen parte integrante de una estructura. Para los tipos conferidos (entero, flota, bolean, character, string) se puede llamar al package text_io de la siguiente forma:
whit text_io; use text_io
al comienzo de un programa. El efecto real de esto es realizar procedimientos tales como get y put disponibles solo para caracteres y cadenas. Para los restantes tipos, se deben especificar las características proporcionadas por text_io como sigue:
package int_io is new integer_io (integer); use int_io;
package flo_io is new float_io (float); use flo_io;
package boo_io is new enumeration_io (boolean); use boo_io;
package dec_io is new decimal_io (decimal); use dec_io; (Reales de coma fija decimales)
package mod_io is new modular_io (modular); use mod_io; (Enteros sin signo)
package fix_io is new fixed_io (fixed); use fix_io; (reales con coma fija)
-
get(X).- Lee character string, float o integer
-
get_line(S,L).-Lee un string de longitud L y cambia de línea
-
skip_line.- Desestima el resto de linea.
Salida Y: Mostrar en un dispositivo de salida los resultados de las acciones anteriormente realizadas. Son acciones de escritura.
-
put(X).- Escribe character string, float o integer
-
put_line(S).- Escribe un string y salta de linea
-
new_line.- Cambia de linea
Ada provee medios para la creación o eliminación de archivos, con llamadas a procedimientos en un paquete estándar de entrada-salida. Esto permite a un programa crear un archivo en cualquier momento, y también permite el archivo puede borrarse en cualquier momento, aún durante la misma activación del programa o durante una futura activación de dicho programa.
Estructura general de un programa. Unidades o módulos
-
Formado por las siguientes unidades
-
Subprogramas.- Procedimientos y funciones
-
Paquetes. Colecciones de entidades (tipos, subprogramas, etc).
-
Tareas. Acciones en paralelo
-
Unidades protegidas. Coordinación de datos.
-
Unidades genéricas. Componentes reusables.
-
Distribuidas en uno o varios ficheros
-
La estructura general de un programa esta dada por:
Declaración de librerías usadas
Declaración de procedimiento principal
Subprogramas auxiliares
Declaración de variables
Desarrollo del procedimiento principal
end Nombre del procedimiento principal;
Ejemplo: Programa que da el doble de un número.
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;
procedure Compute is
procedure Double(Item : in out Integer) is
begin -- procedure Double.
Item := Item * 2;
end Double;
X : Integer := 1; -- Local variable X of type Integer.
begin -- procedure Compute
loop
Put(X);
New_Line;
Double(X);
end loop;
end Compute;
El compilador de Ada se asegura de que los módulos sean compilados en un orden correcto. Tambien realiza un completo chequeos de tipos a traves de los límites de los módulos.
La segura compilación separada de Ada contrasta a la compilación independiente de Fortran y C. En estos lenguajes las llamadas a procedimientos y funciones no son tipos chequeados del todo. Si una abstracción es llamada con un número incorrecto, o tipos de argumentos, el programa probablemente corra mal. Tampoco hay ninguna restricción en el orden de compilación.
Un procedimiento puede ser dividido en la declaración del procedimiento y el cuerpo de éste (tal como se realiza en los paquetes). En cada caso, el módulo tiene una declaración que especifica su interface,y el cuerpo que contiene los detalles de la implementación. Está división soporta la compilación separada de módulos
Funciones, procedimientos y operadores predefinidos principales (aritméticos, relacionales, lógicos, etc.)
operador | operacion | operandos | resultado |
and | conjunción lógica | boolean | boolean |
or | o lógico | boolean | boolean |
xor | o exclusivo lógico | boolean | boolean |
= | igualdad | cualquiera | boolean |
/= | desigualdad | cualquiera | boolean |
< | menor que | escalar | boolean |
<= | menor o igual que | escalar | boolean |
> | mayor que | escalar | boolean |
>= | mayor o igual que | escalar | boolean |
+ | suma | numérico | el mismo |
- | resta | numérico | el mismo |
+ | identidad | numérico | el mismo |
- | negación | numérico | el mismo |
* | multiplicación | integer --- real | integer --- real |
/ | división | integer --- real | integer --- real |
mod | módulo | integer | integer |
rem | resto | integer | integer |
** | exponenciación | integer - integer>=0 real -- integer | integer real |
not | negación | boolean | boolean |
abs | valor absoluto | numérico | el mismo |
and then | cortocircuitos | boolean | boolean |
or else | cortocircuitos | boolean | boolean |
in | operador de pertenencia | expresión escalar -- rango | boolean |
not in | operador de no pertenencia | expresión escalar - rango | boolean |
& | añadir strings (concatenación) | strings | strings |
paquetes
Los paquetes son usados en Ada para declarar tipos abstractos y objetos, y para perfeccionar el encapsulamiento en general. El concepto clave es la division de un paquete en la declaración del paquete y cuerpo del paquete. El propósito esencial de la declaración del paquete es declarar solo aquellos componenetes que serán exportados, y así específicar la interface entre el paquete y otros módulos. El propósito del cuerpo del paquete es contener los detalles de la implementación. Estos detalles incluyen cuerpos y cualquier otra abstracción exportada, y declaraciones de cualquier componente oculto.
Un paquete (package) comienza con la especificación de sus datos y, operaciones. Va seguida de una seccion opcional que indica que partes de los datos se conoceran en el mundo exterior mediante un nombre aunque no se examinen con detalle. El cuerpo del paquete repite las especificaciones, cumplimentando cada una con las implementaciones requeridas.
Los paquetes de Ada ayudan a la abstracción de datos en tres niveles:
Denominando conjuntos de declaraciones.
Agrupando subprogramas relacionados lógicamente y que comparten declaraciones internas. Esta es una de las facilidades que los lenguajes estructurados en bloques tradicionales no pueden suministrar.
Encapsulacion de datos con implementacion oculta de operaciones. Esto es la abstraccion de datos en su mas completo sentido, que proporciona ahorro de esfuerzos, facilidad de mantenimiento y tanta protección como se necesite.
La estructura de un paquete Ada se muestra seguidamente:
Especificación, fichero ads
package nombre is
-- tipos, variables, procedimientos y
-- funciones del package
private
-- detalle de los tipos que necesitan ocultarse (declaraciones privadas)
end nombre;
package body nombre is
-- declaraciones de tipos y variables locales, etc.;
-- implementaciones de funciones y procedimientos
-- mencionados en la especificacion
end nombre;
La parte private es opcional. La parte anterior a private es la interfaz.
Subunidades
La mayoría de las unidades de la biblioteca Ada son especificaciones y cuerpos de paquetes. A estos últimos nos referimos ahora. En la implementación de un paquete pueden aparecer, de nuevo, elementos como procedimientos, objetos protegidos, tareas o paquetes, todos ellos con su respectiva especificación en su caso y, siempre, el cuerpo. Pues bien, el cuerpo de cualquiera de estos elementos puede ser extraído de la unidad de compilación y compilado como una unidad de compilación separada. A esta unidad segregada se le llama subunidad. Sólo un paquete puede tener subunidades.
Información anexa
Concurrencia
Muchos problemas se expresan de forma natural mediante varias actividades concurrentes:
• sistemas de control atendiendo a múltiples subsistemas y eventos
• sistemas multicomputadores o distribuidos
• para el uso concurrente de múltiples recursos
La concurrencia implica prever la sincronización:
• para la utilización de recursos y datos compartidos
• y para el intercambio de eventos e información
Tradicionalmente, existen tres entornos de aplicación en los que se utilizan programas concurrentes:
• En aplicaciones que interaccionan con o controlan entornos físicos, en los que múltiples eventos y subsistemas deben de ser controlados a la vez. En estos sistemas una solución concurrente lleva a un mayor grado de modularidad y a un diseño más claro.
• En sistemas multicomputadores o distribuidos, donde el paralelismo físico se puede aprovechar al máximo ejecutando diferentes tareas en diferentes procesadores.
• En sistemas de cálculo convencional, si se desea utilizar múltiples recursos a la vez. Por ejemplo, en un sistema de ventanas, puede ser útil asociar tareas a determinadas clases de ventanas, de forma que puedan ejecutar diferentes actividades concurrentemente.
Los programas concurrentes representan el modelo más natural para resolver muchos problemas del mundo real que son de naturaleza concurrente.
También se pueden usar (a veces) aproximaciones no concurrentes para la programación de problemas de naturaleza concurrente.
Concurrencia en Ada
El Ada soporta la programación de procesos concurrentes mediante las tareas (“tasks”).
Las tareas constan de especificación y cuerpo:
• la especificación de una tarea declara sus puntos de entrada (si los hay)
• el cuerpo define una actividad que se ejecuta independientemente; tiene declaraciones e instrucciones
Las tareas van en la parte de declaraciones de un módulo
• se arrancan nada más ser visibles
• el módulo que las declara no termina si no han terminado todas sus tareas
Sincronización de espera
La sincronización de espera entre tareas en Ada se realiza mediante el mecanismo del “ rendezvous”, o punto de entrada, o punto de encuentro entre dos tareas
• Hay una tarea que llama, y otra que acepta el encuentro
• En la llamada se pueden pasar parámetros, como en un procedimiento
• La tarea que “llama” se queda esperando hasta que la tarea que acepta la llamada termine de ejecutarla
Los puntos de entrada se declaran en la especificación.
Sincronización de datos
La sincronización de datos, para compartir información de manera mutuamente exclusiva, se realiza mediante objetos protegidos.
El objeto protegido tiene una especificación con:
• parte visible: tiene funciones, procedimientos y puntos de entrada
• parte privada: contiene los datos protegidos
Con las funciones y procedimientos se garantiza un acceso mutuamente exclusivo a la información protegida.
Puntos de entrada en objetos protegidos
Los puntos de entrada proporcionan la misma protección que los procedimientos protegidos, pero además:
• permiten a una tarea esperar, hasta que se cumpla una determinada condición
• la evaluación de esta condición también está protegida
La sincronización de datos es necesaria para garantizar que la modificación o lectura de datos compuestos es consistente. Si por ejemplo una tarea está modificando un dato compuesto, y cuando sólo ha modificado una parte es interurmpida por otra tarea, esta segunda puede leer un dato inconsistente.
La solución es la sincronización para acceso mutuamente exclusivo. En Ada esto se logra con los objetos protegidos. Los objetos protegidos proporcionan acceso mutuamente exclusivo mediante funciones, procedimientos o puntos de entrada protegidos. Los procedimientos protegidos funcionan de modo que no pueden ser interrumpidos por otro procedimiento o función protegido del mismo objeto.
Los puntos de entrada, además de la protección equivalente a la de un procedimiento protegido, permiten que la tarea que los llama espere a que se cumpla una determinada condición. Esta condición se evalúa de forma protegida, es decir mutuamente exclusiva. Mientras la tarea espera, otras tareas pueden ejecutarse.
Programación en tiempo real
El Ada soporta la programación de sistemas empotrados y de sistemas de tiempo real, mediante los siguientes mecanismos:
• Representación del hardware
• Interrupciones
• Gestión del tiempo
• Prioridades
• Sincronización libre de inversión de prioridad
Estos mecanismos están descritos en anexos opcionales:
• Anexo de programación de sistemas
• Anexo de sistemas de tiempo real
Un computador empotrado es aquel que forma parte de un sistema más grande. Por ejemplo, el computador que controla un robot o un avión. Generalmente son computadores con un hardware restringido en algunos aspectos (por ejemplo sin disco duro) y ampliado en otros aspectos de relación con el entorno (convertidores A/D y D/A, entrada/salida digital, etc.). Las necesidades especiales de programación se derivan precisamente de la necesidad de acceder directamente al hardware y de responder a interrupciones externas.
Los sistemas de tiempo real son aquellos en los que no sólo importa la realización de unos determinados cálculos, sino el instante en el que se produce la salida de los resultados de estos cálculos. Ello se debe a que el sistema de tiempo real interacciona con un entorno cambiante con el tiempo.
Normalmente, un sistema de tiempo real debe realizar diversas actividades de forma concurrente, y cada una de estas actividades presenta unos requerimientos de tiempo de respuesta que es preciso cumplir. Ello implica la necesidad de disponer de facilidades de programación tales como gestión del tiempo, poder dar más prioridad a aquellas tareas más urgentes, etc.
Muchas de las facilidades que presenta el lenguaje Ada para sistemas empotrados y de tiempo real son opcionales, ya que se hallan contenidas en Anexos del lenguaje.
Representación del hardware
En muchos sistemas los programas deben interaccionar directamente con el hardware
Muchas veces se utiliza para ello lenguaje ensamblador.
El Ada proporciona mecanismos para establecer la correspondencia entre estructuras lógicas y representaciones físicas del hardware. Por ejemplo:
• asociación entre campos de registros y posiciones de bits
• posicionamiento de datos en direcciones de memoria
concretas
Se permiten también las operaciones de I/O de bajo nivel.
En general, si se programa en Ada no es necesario el uso del lenguaje ensamblador para acceder al hardware. El Ada permite:
• Expresar la correspondencia entre los campos de un registro y las posiciones de determinados bits en una palabra de la memoria. Está especialmente indicado para acceder a los registros de control y estado de dispositivos hardware.
• Es posible expresar la posición de memoria concreta en la que se pueden colocar una o más variables del programa. Esto permite acceder directamente a dispositivos hardware que están mapeados en memoria.
• Cuando los dispositivos hardware no están mapeados en memoria, el Ada permite expresar operaciones de entrada/salida de bajo nivel, para poder acceder a estos dispositivos a través del bus de entrada/salida.
c
Historia, CARACTERÍSTICAS generales
La historia del C corre paralela a la del desarrollo del sistema operativo Unix. El nacimiento de éste último tuvo lugar por la necesidad de disponer de un sistema operativo con unas posibilidades similares a las de los grandes sistemas de la época (1970) y que pudiese funcionar en pequeños ordenadores de propósito general. Con esta finalidad, Ken Thompson desarrollo la primera versión escrita originalmente en lenguaje ensamblador; posteriormente la rescribió en un nuevo lenguaje de programación denominado “lenguaje B” (similar en algunos aspectos al Pascal de Niklaus Wirth).
El lenguaje B fue revisado por Dennis Ritchie, ampliándolo y obteniendo una nueva versión a la que denominó “lenguaje C”.
El lenguaje C inicialmente fue creado para la programación de
-Sistemas operativos
-Intérpretes
-Editores
-Ensambladores
-Compiladores
-Administradores de bases de datos.
Con la popularidad de las microcomputadoras muchas compañías comenzaron a implementar su propio C por lo cual surgieron discrepancias entre sí. Por esta razón ANSI estableció un comité en 1983 para crear una definición no ambigua del lenguaje C e independiente de la máquina que pudiera utilizarse en todos los tipos de C.
Algunos de los C existentes son:
-Quick C
-C++
-Turbo C
-Turbo C ++
-Borland C
-Borland C++
-Microsoft C
-etc.
Este lenguaje ha sido estrechamente ligado al sistema operativo UNIX, puesto que fueron desarrollados conjuntamente. Sin embargo, no está ligado a ningún sistema operativo ni a ninguna máquina concreta. Se le suele llamar lenguaje de programación de sistemas (debido a su utilidad para escribir compiladores y sistemas operativos); actualmente se puede desarrollar cualquier tipo de aplicación.
Sus características más importantes son:
-
El C estándar puede utilizarse en todos los tipos de C.
-
El C es un lenguaje de propósito general. Puede ser utilizado para una gran variedad de tareas que incluyen sistemas de bases de datos, científicos, financieros, de pasatiempo y programas de educación.
-
Se puede utilizar en todas las máquinas: superordenadores, ordenadores de tarea específica (mainframe), miniordenadores y microordenadores.
-
Es portable, es decir, es posible adaptar los programas escritos para un tipo de computadora en otra.
-
Es un lenguaje de programación de nivel medio ya que combina los elementos del lenguaje de alto nivel con la funcionalidad del ensamblador.
-
No lleva a cabo comprobaciones de errores en tiempo de ejecución, un claro ejemplo esta en que se sobrepasen los límites de un arreglo; en una ocasión como esta, el programa no se detiene y sigue escribiendo o leyendo en memoria, posiblemente hasta en el mismo código del programa.
-
Es estructurado. Los programas pueden escribirse en módulos (funciones) o fuentes independientes entre sí.
-
Ofrece una enorme librería de rutinas en tiempo de ejecución.
-
Es conciso. Lo compacto del código fuente del C ahorra espacio en el disco, reduce el tiempo de compilación y también la cantidad de escritura que ha de realizar el programador.
-
Posee un alto nivel de abstracción.
-
Además de poseer expresiones y flujo de control explicito, y la asignación y el acceso a memoria se realizan mediante operadores (New); ofrece economía sintáctica, estructuras sencillas y un buen conjunto de operadores.
-
Todos los argumentos son pasados 'por valor'. No existe el concepto de paso de parámetros 'por variable' o 'por referencia'.
-
Algunas de sus limitaciones son: por su libertad de expresión, requiere mayor responsabilidad por parte del programador ; el uso de punteros puede producir errores de programación difíciles de localizar; y, la abundancia de operadores y eliminación de palabras superfluas hacen que el código llegue a ser difícil de rastrear.
Tipos de datos y descripción
Soporta los siguientes tipos de datos:
-
Caracteres, ya sean ASCII o EBCDIC
-
Enteros, con o sin signo
-
Números en coma flotante, en simple o doble precisión
-
Funciones
-
Arrays, de cualquier tipo de variables
-
Punteros, a cualquier tipo de variables
-
Estructuras
Cuando usamos un programa es muy importante manejar datos. En C podemos almacenar los datos en variables. El contenido de las variables se puede ver o cambiar en cualquier momento. Estas variables pueden ser de distintos tipos dependiendo del tipo de dato que queramos guardar en ellas. No es lo mismo guardar un nombre que un número. Hay que recordar también que la memoria del ordenador es limitada, así que cuando guardamos un dato, debemos usar sólo la memoria necesaria.
Identificadores
Son nombres dados a constantes, variables y funciones. El identificador esta formado por una secuencia de una o más letras, dígitos y el caracter de subrayado. El primer caracter de un identificador siempre debe ser una letra o el caracter de subrayado, en estos identificadores se debe tener gran cuidado, ya que el C hace diferencia entre mayúsculas y minúsculas.
Por ejemplo, Max, max y MAX son tres identificadores diferentes.
Constantes
Las constantes son un valor que una vez fijado por el compilador, no cambia durante la ejecución del programa. El C indica al programa que se trata de una constante usando la directiva #define.
Por ejemplo:
#define pi 3.1416
Esta línea define a la variable pi como una constante con el valor 3.1416, este valor de las constantes puede ser un numero o bien una cadena de caracteres.
Tipos de Datos Simples
Tipo Int
En una variable de este tipo se almacenan números enteros (sin decimales) y con signo (puede ser positivo o negativo o cero); el rango de valores que admite es -32767 a 32767. Cuando definimos una variable lo que estamos haciendo es decirle al compilador que nos reserve una zona de la memoria para almacenar datos de tipo int. Hay que decirle al compilador que queremos crear una variable y hay que indicarle de qué tipo. Si esta declaración se hace antes del main(), indica que la variable será una variable global, o sea que se usará en todo el main() y en el resto de funciones; mientras que si se declara dentro del main(), indica que será una variable local, o sea, sólo para la función main().
Por ejemplo:
int valor;
main()...
Esta expresión declara una variable global de nombre "valor" y de tipo entero.
main()
{
float valor;
}
Esta expresión declara una variable local de nombre "valor" y de tipo float (coma flotante)
C dispone de tres palabras claves que se aplican como “adjetivos” para modificar el entero básico :
-
Short: es la abreviatura de short int, puede usar menor espacio de almacenamiento que int, lo que permite ahorrar memoria cuando se necesitan usar solamente números de pequeño tamaño.
-
Long: abreviatura de long int, puede usar mayor espacio de almacenamiento que int, permitiendo el uso de enteros de mayor rango.
-
Unsigned (Unsigned int): desplaza el rango de números que esta permitido almacenar. El bit que se utiliza para indicar el signo en los números con signo, se transforma en una nueva cifra binaria que permite alojar el numero mayor.
Ejemplo: unsigned int de 2 bytes permite un rango desde 0 a 65535, en lugar del rango -32768 a +34767.
Muchos compiladores reconocen también como tipos válidos: unsigned long int o unsigned long y unsigned short int o unsigned short.
Tipo Char
Las variables de tipo char sirven para almacenar caracteres como letras o signos de puntuación, el almacenamiento es en forma de números del 0 al 255. Los 128 primeros (0 a 127) son el ASCII estándar. El resto es el ASCII extendido y depende del idioma y del ordenador.
Para declarar una variable char solo escribimos: "char nombre;"
Los distintos tipos de int se pueden utilizar para la mayor parte de los proyectos para el desarrollo del software. Sin embargo, los programas que implican un mayor número de cálculos matemáticos, a menudo utilizan números de “punto flotante”, llamados en C, tipo flota.
Tipo Float
En este tipo de variable podemos almacenar números decimales, no sólo enteros como en los anteriores. El rango de posibles valores es del 3.4 E-38 al 3.4 E+38.
Para declarar un float, de forma similar, escribimos: "float prom;" y con esto hemos declarado una variable de nombre "prom" que tendrá un dato de tipo float o coma flotante.
Corresponde a los reales de FORTRAN y Pascal.
Dispone también de un tipo double, para doble precisión en punto flotante; y el tipo long double, con una precisión aún mayor que double.
Tipo double
En las variables tipo double se almacenan números reales, estos tiene el rango de 1.79769 E-308 a 1.79769 E+308.
Al igual que las anteriores para declararla escribimos: "double num;" y tenemos una variable de nombre "num" que aceptará datos tipo double.
Tipo | Bytes | Descripción | Rango |
Char | 1 | caracter | -127 a 127 |
Unsigned char | 1 | caracter | 0 a 255 |
Int | 2 | entero | -32.767 a 32.767 |
unsigned int | 2 | entero positivo | 0 a 65.535 |
Long int | 4 | entero largo | -2.147.793.467 a 2.147.793.467 |
unsigned long int | 4 | entero largo positivo | 0 a 4.294.967.925 |
float | 4 | real | seis dígitos de precisión |
double | 8 | real | diez dígitos de precisión |
void | 0 | nada | - |
Cabe resaltar que, el lenguaje 'C', dispone de una declaración llamada typedef que permite la creación de nuevos tipos de datos.
Ejemplo:
typedef int entero; /* acabamos de crear un tipo de dato llamado entero */
entero a, b=3; /* declaramos dos variables de este tipo */
Su empleo con estructuras está especialmente indicado. Se puede hacer de varias formas:
Una forma de hacerlo:
struct trabajador
{
char nombre[20];
char apellidos[40];
int edad;
};
typedef struct trabajador datos;
datos fijo, temporal;
Estructuras de datos principales
Para definir una estructura usamos el siguiente formato:
struct nombre_de_la_estructura {
campos de estructura;
};
Por ejemplo.
struct cliente {
char nombre[30];
char apellido[40];
char teléfono[10];
char edad;
};
Arreglos de Estructuras
Para manejar los datos de más personas necesitamos declarar array de estructuras.
Esto se hace de la siguiente manera:
struct cliente cliente1[NUMERO_ELEMENTOS];
Ahora para acceder a un elemento determinado simplemente hacemos cliente1[0].nombre.
Inicialización de una estructura
A las estructuras se les pueden dar valores iniciales de manera análoga a como hacíamos con los arrays. Primero tenemos que definir la estructura y luego cuando declaramos una variable como estructura le damos el valor inicial que queramos.
Ejemplo.
struct cliente cliente1 = {
"Andrés",
"Pascal",
"260-0483",
30
};
De forma análoga se puede inicializar un arreglo de estructuras. Siempre teniendo en cuenta el orden de las mismas.
Punteros a estructuras
Se define la estructura normalmente, la diferencia está en que al declarar la variable de tipo estructura debemos ponerle el operador '*' para indicarle que es un puntero, dándole una dirección válida donde apuntar.
De la misma forma se puede usar punteros para arreglos de estructuras.
Es posible crear estructuras que tengan como miembros otras estructuras; son llamadas estructuras anidadas. Esto tiene diversas utilidades, por ejemplo tener la estructura de datos más ordenada.
Archivos
Lectura
Todas las funciones de entrada / salida estándar usan el puntero *FILE para acceder a la información sobre el archivo abierto. Este puntero no apunta al archivo sino a una estructura que contiene información sobre él.
Esta estructura incluye entre otras cosas información sobre el nombre del archivo, la dirección de la zona de memoria donde se almacena el fichero, tamaño del buffer. Para poder utilizar este puntero se debe incluir el archivo de cabecera stdio.h.
Para abrir el archivo utilizamos la función fopen, su sintaxis es:
FILE *fopen(const char *nombre_fichero, const char *modo);
El nombre del archivo se puede indicar directamente o usando una variable.
El archivo se puede abrir de distintas formas, como se muestran en la tabla:
Parámetro | Modo |
r | Abre un archivo existente para lectura |
w | Crea un archivo nuevo y lo abre para escritura |
a | Abre un archivo (si no existe lo crea) para escritura |
Para leer un archivo podemos utilizar la función getc, que lee los caracteres uno a uno. Además existen otras funciones como fgetc, fgets, fread que leen más de un carácter.
La sintaxis de la función getc y fgetc es:
int getc(FILE *archivo);
Para detectar el final del fichero se pueden usar dos formas:
-
con la función feof()
-
comprobando si el valor de letra es EOF.
Esta función comprueba si se ha llegado al final de fichero en cuyo caso devuelve un valor distinto de 0. Si no se ha llegado al final de fichero devuelve un cero.
Un archivo se cierra mediante la función fclose(fichero). Si todo va bien fclose devuelve un cero, si hay problemas devuelve otro valor.
Para la escritura en un archivo usamos la función putc, la cual tiene la siguiente sintaxis:
int putc(int c, FILE *fichero);
Estructuras de control condicionales
Sentencia “If”
Permite tanto la ejecución si es cierta la condición, como la alternativa else para el caso de que no se verifique la condición.
Su sintaxis es:
If (expresión)
Sentencia;
O también:
If (expresión)
Sentencia1;
Else
Sentencia2;
Como expresión se puede utilizar cualquiera cuyo valor sea distinto de cero.
La sentencia Switch
Verifica una elección múltiple, comparando una expresión con cierto número de constantes de los tipos int o char. Posee mas similitud con el goto de Fortran que con el case de Pascal.
La sintaxis utilizada es:
Switch (expresión)
Sentencia;
Donde “expresión” debe ser cualquier expresión que de por resultado un entero, y sentencia es normalmente una sentencia compuesta (bloque) que puede estar precedida por una o mas etiquetas de “case” y/o “default”, de la forma:
Case constante-expresión: <sentencias>
y
default: <sentencias>
donde constante-expresión es una expresión constante y donde el flujo del programa se transfiere a la etiqueta case si la expresión de la sentencia switch es igual a la constante-expresión, o a la etiqueta opcional default si ninguna de las etiquetas de case se aplica; sentencias es una lista opcional de una o más sentencias de expresión (no una sentencia de bloque).
Estructuras de control cíclicas
El bucle for
El bucle for en C cumple la misma función que en el resto de los lenguajes de programación procedimentales pero se le añade una potencia y flexibilidad únicos; otra de las diferencias es que permite que se realicen modificaciones en las variables interiores pertenecientes a su cuerpo, ya que no necesariamente son constantes.
Su forma es la siguiente:
for(inicialización; condición; incremento)
sentencia;
Donde inicialización es una sentencia de asignación para inicializar la variable de control del bucle, condición es una expresión relacional que determina el final del bucle e incremento define cómo cambia la variable de control cada vez que se ejecute una iteración del bucle.
Ej.:
#include "stdio.h"
/* imprime los números del 1 al 100 */
main()
{
int x;
for (x=1; x<=100; x++) printf("%d ", x);
}
En este ejemplo, x se inicializa a 1 y se compara con 100, ya que la condición es cierta, se ejecuta la función printf() y x se incrementa en 1, este bucle se repite hasta que x es mayor que 100.
El bucle while
Tiene como sintaxis:
While (expresión)
Sentencia;
Donde es obligatorio el uso de paréntesis para separar expresión de la siguiente sentencia (Pascal utiliza la palabra clave “do” para el mismo fin)
Una variación de la sentencia while es: do-while . En ella la sentencia se ejecuta al menos una vez, antes de que se evalúe la expresión condicional.
Su forma es:
Do
Sentencia
While (expresión);
{sentencia;
while (expresión)
sentencia;
}
La equivalencia entre las construcciones for y while no es exacta, la única diferencia es que while admite el empleo de la sentencia “continue”.
Saltos y Etiquetas
Hay casos en los que es necesario salir de una estructura de bucles de varios niveles, en estas ocasiones se justifica la utilización del goto. Su sintaxis es:
goto etiqueta;
y produce que la ejecución del programa continúe en la instrucción que sigue a “etiqueta”; una etiqueta consiste en un nombre de variable seguida por “:”. El goto mas eficiente es mediante la utilización de las instrucciones especiales “break” (fuerza la salida inmediata de un bucle for, do o while, así como la sentencia switch ) y “continue”(produce el salto a la siguiente iteración en un bucle do, for o while).
Return
La sintaxis general de la sentencia return es
return <expresión>
donde expresión sólo es obligatoria si devuelve valor. La expresión va normalmente entre paréntesis, pero esto sólo es necesario en ciertas expresiones complejas.
Estructuras de control: Procedimientos, Funciones y Subrutinas.
Funciones.
Las funciones se emplean para dividir un programa grande en otros mas pequeños y manejables. Cada función consiste en una parte del programa, con sus propias variables, definiciones e incluso llamadas a otras funciones (lo que no esta permitido es declarar funciones dentro de otras).
Una propiedad importante de las funciones es la posibilidad de trabajar con argumentos de llamada y devolver valores, pudiendo ser utilizadas en otros programas similares con solo cambiar los datos que figuran en la llamada de la función.
La definición de una función posee la siguiente forma:
tipo_de_variable nombre_de_la_función( argumentos )
{
definición de variables;
cuerpo de la función;
return 0;
}
El nombre de la función debe ser un nombre de identificador válido. Este se utiliza para llamar la función dentro del programa.
El tipo_de_variable:
Cuando una función se ejecuta y termina debe devolver un valor. Este valor puede ser cualquiera de los tipos de variables definidos en Tipos de datos (int, char, float, double), o un tipo de dato definido por el usuario. El valor que devuelve la función suele ser el resultado de las operaciones que se realizan en la función.
Las funciones deben declararse con un tipo: las que posean valores de retorno deberán declararse con el mismo tipo que tiene dicho valor, las funciones que carecen de valor de retorno deben declararse de tipo void, y las que no indican el tipo el lenguaje supone que es tipo int.
Definición de variables:
Cuando definimos una variable dentro de una función, esa variable sólo es válida dentro de la función. Si definimos una variable dentro de main sólo podremos usarla dentro de main. Si por el contrario la definimos como variable global, antes de las funciones, se puede usar en todas las funciones.
Podemos crear una variable global y en una función una variable local con el mismo nombre. Dentro de la función cuando llamamos a esa variable llamamos a la local, no a la global. Esto no da error pero puede crear confusión al programar y al analizar el código.
Return:
la función devuelve un valor. El dato que se pone después de return es el dato que se devuelve. Puede ser una constante o una variable. Debe ser del mismo tipo que “tipo_de_variable”.
Argumentos:
Estos son variables que se pasan como datos a una función. Deben ir separados por una coma. Cada variable debe ir con su tipo de variable. Las funciones deben definirse antes de ser llamadas.
Entrada y Salida de datos
El lenguaje C no incorpora directamente instrucciones para la realización de las operaciones de Entrada / salida, implementándola a través de librerías y funciones, como la Librería de E/S estándar.
E/S simple
Las operaciones mas sencillas que se pueden realizar sobre un fichero que ya esté abierto son la función getchar() que lee el siguiente carácter presente en la entrada (el fichero estándar de entrada es el teclado) y, análogamente, putchar(c) que escribe el carácter a la salida (la pantalla) .
Es usual que en un programa el usuario introduzca datos por el teclado. Para ello contamos con varias posibilidades, la más usual de éstas es usar las funciones de la biblioteca estándar .
scanf
El uso de scanf es de la siguiente manera: "scanf("%i", &num);" esta última expresión indica al programa que se debe solicitar un número entero (%i, es una especificación de formato y esto lo puedes ver en la sección de operadores y manipuladores), luego se indica el nombre de la variable en la que se va a guardar el dato, éste (el nombre) precedido por el signo &, que indica al programa la dirección de ésta variable.
printf
El uso de printf, es similar al de scanf, lo que scanf hace para leer una variable, printf lo hace para imprimirla. De esta manera podemos imprimir en pantalla, ya sea un mensaje o el valor contenido en una variable. La sintaxis de printf es así: "printf("%d", num);" esta sentencia lo que hace es imprimir el valor de la variable num en el lugar donde aparece el "%d".
Para hacer uso de estas funciones, es necesario incluir la directiva o archivo de cabecera stdio.h, esto se hace de la siguiente manera: "#include ", así queda incluida éste archivo y se podrá proceder con el programa.
Esquema general de un programa
El C es un lenguaje modular. Los programas pueden escribirse en módulos (funciones) o fuentes independientes entre sí; cada módulo queda en un fichero aparte y cada fichero se compila separadamente. Luego, cada una de estas unidades compiladas por separado puede ser combinada (enlazada) en un programa entero. Las rutinas utilizadas más comúnmente pueden colocarse en una librería, dicha librería podrá ser enlazada en los nuevos programas cuando ello sea necesario.
Es conveniente mantener los fuentes de un tamaño no muy grande, para que la compilación sea rápida. También puede facilitar la legibilidad del programa y su estructuración.
Funciones, procedimientos y operadores predefinidos principales
Funciones predefinidas
La biblioteca general de utilidades contiene un conjunto bastante heterogéneo de funciones, incluyendo un generador de números aleatorios, y funciones de búsqueda y ordenación, de conversión y gestión de memoria, etc.
bsearch: realiza la búsqueda binaria.
clock: devuelve el tiempo de CPU utilizado.
fread y fwrite
Estas funciones nos permiten tratar con datos de cualquier tipo, incluso con estructuras dentro de un archivo, al contrario de las pasadas en las que solo sirven para manejar caracteres y cadenas.
fwrite
Fwrite nos permite escribir en un fichero. Esta función tiene la siguiente sintaxis:
size_t fwrite(void *buffer, size_t tamano, size_t numero, FILE *pfichero);
buffer: variable que contiene los datos que vamos a escribir en el fichero.
tamano: el tamaño del tipo de dato a escribir. Puede ser un int, un float, una estructura, ... Para conocer su tamaño usamos el operador sizeof.
numero: el número de datos a escribir.
pfichero: El puntero al fichero sobre el que trabajamos.
fread
La función fread se utiliza para sacar información de un Archivo, su sintaxis es:
size_t fread(void *buffer, size_t tamano, size_t numero, FILE *pfichero);
Siendo buffer la variable donde se van a escribir los datos leídos del fichero archivo.
El valor que devuelve la función indica el número de elementos de tamaño 'tamano' que ha conseguido leer.
fseek y ftell: La función fseek nos permite situarnos en la posición que queramos de un fichero abierto. . La sintaxis de fseek es asi:
int fseek(FILE *pfichero, long desplazamiento, int modo);
La función ftell es complementaria a fseek, devuelve la posición actual dentro del fichero.
Su sintaxis es la siguiente:
long ftell(FILE *pfichero);
El valor que nos da ftell puede ser usado por fseek para volver a la posición actual.
fprintf y fscanf: Estas dos funciones trabajan igual que sus equivalentes printf y scanf. La única diferencia es que podemos especificar el fichero sobre el que se desea operar.
Las sintaxis de estas dos funciones son:
int fprintf(FILE *pfichero, const char *formato, ...);
int fscanf(FILE *pfichero, const char *formato, ...);
Main() indica el comienzo de la función principal del programa la cual se delimita con llaves. Esta función acepta dos argumentos:
int main( int argc, char *argv[] )
El primer argumento es argc (argument count). Es de tipo int e indica el número de argumentos que se le han pasado al programa.
El segundo es argv (argument values). Es un array de strings (o puntero a puntero a char). En el se almacenan los parámetros. Normalmente (como siempre depende del compilador) el primer elemento (argv[0]) es el nombre del programa con su ruta. El segundo (argv[1]) es el primer parámetro, el tercero (argv[2]) el segundo parámetro y así hasta el final.
A los argumentos de main se les suele llamar siempre así.
sleep: suspende la ejecución de un proceso durante un intervalo de tiempo especificado.
También podemos usar las funciones matemáticas que se encuentran dentro de la biblioteca matemática, cuyo archivo de encabezamiento es math.h. Las mas usuales son:
atan(): acepta un argumento double y devuelve el ángulo cuya tangente tiene ese valor. Ésta función puede dar resultados ambiguos, es decir, no distingue entre una línea que forme un ángulo concreto y otra que esté inclinada 180° en la dirección opuesta. Trabaja en radianes.
atan2(): acepta los valores de x e y, y analizando sus signos calcular el ángulo correcto.
ceil: ante un valor numérico con decimales, conserva la parte entera, despreciando los decimales.
log: logaritmo natural. Devuelve el logaritmo en base e del número al que hay que elevar e para que resulte el valor que se le indique. Si intenta hallar el logaritmo de un número negativo o cero, devolverá error.
floor: realiza la misma conversión que ceil, pero redondea hacia abajo.
pow: eleva un numero al exponente que se le indique..
sqrt() : acepta un argumento double y devuelve la raíz cuadrada del mismo, en un valor que también es de tipo double.
Operadores (manipuladores)
Los operadores son símbolos que indican como son manipulados los datos. Estos operadores se pueden clasificar en: aritméticos, lógicos, relacionales, de asignación, de manejo de bits y otros.
Operadores de Asignación
Operador | Operación |
+ | Suma dos números, pueden ser enteros o reales |
- | Resta dos números, pueden ser enteros o reales |
* | Multiplica dos números, pueden ser enteros o reales |
/ | División, el resultado depende de los tipos de datos |
% | Módulo o resto de una división entera, los operandos tienen que ser enteros |
++ | Incrementa en uno la variable |
-- | Decrementa en uno la variable |
Operadores Lógicos
Operador | Operación |
&& | AND, en español Y. Da como resultado el valor lógico 1, si ambos operadores son distintos de cero |
|| | OR, en español O. El resultado es cero, si ambos operandos son cero |
! | NOT, en español NO. El resultado es cero si el operando tiene un valor distinto de cero |
Operadores de relación
Operador | Operación |
< | Primer operando menor que el segundo |
> | Primer operando mayor que el segundo |
<= | Primer operando menor o igual que el segundo |
>= | Primer operando mayor o igual que el segundo |
== | Primer operando igual que el segundo |
!= | Primer operando distinto del segundo |
Operadores Binarios
Operador | Operación |
& | AND, compara los bits dos a dos, si ambos son 1 el resultado es 1 |
! | OR, compara los bits dos a dos, si alguno de ellos es 1, se obtiene 1 |
^ | XOR, compara los bits dos a dos, si son distintos el resultado es 1 |
~ | Complemento, convierte los ceros a uno y los unos a cero |
>> | Desplazamiento a la derecha, esto equivale a dividir por 2 |
<< | Desplazamiento a la izquierda, esto equivale a multiplicar por 2 |
Operadores de Asignación
Operador | Operación |
= | Asignación simple |
*= | Multiplicación más asignación |
/= | División más asignación |
%= | Módulo más asignación |
+= | Suma más asignación |
-= | Resta más asignación |
<<= | Desplazamiento a la izquierda más asignación |
>>= | Desplazamiento a la derecha más asignación |
&= | Operación AND sobre bits más asignación |
!= | Operación OR sobre bits más asignación |
^= | Operación XOR sobre bits más asignación |
?: Operador condicional: el C ofrece una forma abreviada de expresar la sentencia if else. Se denomina “expresión condicional” y emplea el operador condicional ?. es éste un operador en dos partes que contiene tres operandos. Su forma general es:
expresiín1 ? expresión2 : expresión3
Si expresión1 es cierta (distinta de cero), la expresión condicional total toma el valor de expresión2; si expresión1 es falsa (0), toma el valor de expresión3.
DBASE
Historia, CARACTERÍSTICAS generales
A principio de los años ochenta, DBASE II hizo su aparición esta nueva herramienta se presentaba en el emergente mundo de los microordenadores con la intención de facilitar la gestión de las bases de datos.
También, a principio de los ochenta se comienza a utilizar entre los usuarios de micros una nueva terminología informática de bases de datos, ésta era más familiar en otros ambientes informáticos y definía con precisión los conceptos más básicos
DBASE III PLUS es una versión mejorada del dBASE III. El dBASE III es una versión mejorada del dBASE II, el primer gestor de base de datos popular para microcomputadoras. Los comienzos del programa se sitúan mucho antes de que la computadora personal se hiciera popular. El DBASE II fue creado por Waine Ratliff (diseñador del software del JPL). Los científicos del Jet Propulsión Laboratory (JPL) de California, usaban un sistema de gestión de base de datos en grandes computadoras con el fin de seguir la pista a la información recibida en los satélites del JPL.
Ratliff, impresionado por la capacidad y las posibilidades del gestor de base de datos de la computadora central, se puso a redactar un sistema de base de datos para su micro (denominado Vulcan), usando el sistema del JPL como modelo. Este sistema constituyó un atisbo del DBASE II.
Un seguidor del Vulcan fue Tate, un distribuidor de software. Tate probó el programa y quedó suficientemente impresionado como para contactar con Ratliff esperando poder distribuir el programa. Ratliff cedió los derechos de comercialización del Vulcan a Tate.
Con Tate el vulcan paso a denominarse DBASE II -no hubo DBASE I, a pesar de que el II daba a entender que se trataba de una versión mas reciente-.
(LA PRIMERA DE LAS VERSIONES DE DBASE II SE UTILIZÓ CON EL SISTEMA OPERATIVO CP/M)
Tate hizo anuncio del DBASE II para comercializarlo, el público se fijó en los anuncios y en el producto. Tate formó un equipo con Hal Lashlee y creó una compañía, Ashton-Tate, para distribuir el DBASE II.
Tras años de éxito del dBASE II, la competencia empezó a sacar productos con mayores posibilidades que el dBASE II. Como respuesta, Ratliff y un equipo de diseñadores de Ashton-Tate pasaron dos años trabajando en un nuevo programa, el dBASE III. A diferencia de su predecesor, el dBASE III fue diseñado para obtener un pleno rendimiento de las microcomputadoras de 16 bits y estaba escrito en el lenguaje de programación C. Luego, debido al auge de las redes de computadoras personales y al deseo de los compradores de aumentar la cooperación entre usuarios, se desarrolló el dBASE III PLUS. El programa ofrece un número significativo de mejoras respecto del dBASE II y del dBASE III.
El lenguaje de programación dBASE III PLUS es un conjunto de órdenes que permiten acceder a la base de datos mediante el teclado. Las órdenes son palabras que le indican a la computadora la operación que se desea realizar. Cualquier cosa que se desee hacer con la base de datos ha de ser comunicada a la computadora escribiendo la orden correspondiente mediante el teclado.
Las numerosas órdenes del lenguaje de programación del dBASE III PLUS ofrecen multitud de posibilidades de manipulación de la información.
El éxito obtenido entre los usuarios de micros, principalmente atraídos por su versatilidad y potencia, y los grandes beneficios producidos en su comercialización, hizo que muchas empresas de software se adhirieran a la idea de desarrollar nuevos productos análogos, una gama de dialectos que hoy se les agrupa con el sobrenombre de entorno XBase (Clipper, Quicksilver, Foxbase, etc.).
Caracteristicas
El Dbase puede usarse con órdenes de acción directa o con series de instrucciones diferidas. En este caso presenta todas las características estructurales de un auténtico lenguaje, que se une a los lenguajes de alto nivel tipo cobol, pascal, etc., y que ha sido proyectado para elaborar la base de datos que constituye el núcleo central de Dbase.
Dbase es un lenguaje débilmente tipado, estructurado.
Estructuras de datos simples
-
Character: Comúnmente llamado string, con largo máximo de 256 caracteres.
-
Date: Contienen fechas de la forma mm/dd/aa (SET DATE AMERICAN) o dd-mm-aa (SET DATE ITALIAN)
-
Logical: Contienen un valor lógico:
-
.t. Verdadero
-
.f. Falso
-
Memo: Es un string que acepta 4096 caracteres de largo.
-
Numeric: Corresponde a valores numéricos (reales o enteros) donde se usa el punto para la coma decimal y el guión - para indicar valores negativos.
-
Constantes: una constante es un tipo de datos que no cambia. Existen constantes numéricas, de caracteres y lógicas. Todas las constantes de caracteres deben estar escritas entre comillas.
Estructuras de datos principales
El Dbase es un sistema de manejo de base de datos de tipo relacional, cuya estructura está constituida por archivos compuestos por registros del mismo formato que, a su vez, se dividen en campos.
archivos
El Dbase se compone de dos grupos de archivos: los que contienen las órdenes ejecutables y los que están destinados a recoger los datos de usuario. Estos están especificados por una sigla compuesta por tres letras, llamada extensión.
-
Los archivos para la elaboración y programación son:
-
keyword file: contiene las claves para elaborar el sistema entero.
-
command file: sirve para contener una secuencia de sentencias para ejecutar funciones frecuentemente usadas.
-
format file: sirve para formatear datos en la pantalla; solo puede contener sentencias del tipo: @ ... say
-
text output file: permite la adición de los textos en caracteres ascii.
-
report form file: contiene las instrucciones de los formatos de informes dispuestos por el usuario.
-
label form file: sirve para contener las instrucciones de los formatos de tablas dispuestas por el usuario.
-
Los archivos para la memorización de los datos son:
-
data base file: sirve para contener los datos estructurados en registros y campos.
-
index file: sirve para contener los datos de un archivo catalogado; son creados automáticamente por el comando index.
-
data base text file: sirve para conservar en la memoria el contenido de los campos.
-
memory file: son creados automáticamente cuando se da la orden save de los resultados de la computación, constantes o variables que se requerirán posteriormente.
Los nombres de los archivos no pueden superar los 8 caracteres de longitud y 3 caracteres para la extensión, después del punto. Deben empezar siempre con una letra, y el resto de los caracteres pueden ser cifras, pero no espacios en blanco.
Registros
Los registros que puede contener cada archivo en el Dbase II son hasta 65.535 y en Dbase III hasta 1 billón.
Campos
Cada campo en el registro puede contener hasta 254 caracteres. A cada campo se le asigna un nombre, que no puede superar los 10 caracteres, que debe empezar siempre con una letra y que puede contener en su interior cifras pero no espacios.
Estructuras de control secuenciales
Estructuras de control condicionales
-
if - else
IF <condición>
<Instrucciones>
-ELSE
<Instrucciones>]
ENDIF
La orden permite seguir recorridos alternativos según se verifique o no la condición especificada. Funciona como sigue: apenas la orden if abre el ciclo, se valora la condición y si es verdadera se ejecutan las instrucciones especificadas hasta la orden endif, para proseguir después con las instrucciones puestas a continuación de la última orden; de lo contrario no se ejecutan las instrucciones que siguen al if y saltan a las que están puestas después del endif.
-
while
DO WHILE <condición>
<Instrucciones>
[LOOP]
[EXIT]
ENDDO
-
Do case
DO CASE
CASE <condicion1>
==================
CASE <condicion2>
==================
.......
.......
[OTHERWISE]
.......
ENDCASE
Esta orden se utiliza bastante para los menús, ya que el usuario tiene posibilidades de actuar de varias maneras. Apenas la orden abre el ciclo, se valora la condición y si esta se satisface, se ejecutan todas las instrucciones establecidas hasta el siguiente case, y así sucesivamente hasta el endcase; de lo contrario salta a las instrucciones que siguen a la estructura case.
Estructuras de control cíclicas
do while condición
instrucciones
enddo
En cuanto se llega al ciclo se valora la condición y si resulta verdadera se ejecuta las condiciones indicadas en las líneas siguientes hasta llegar a la orden enddo, la cual envía la ejecución del programa a la orden inicial de do while; en caso contrario las instrucciones especificadas no se ejecutan. Y el programa continua con la ejecución de las instrucciones que siguen a la orden enddo.
Estructuras de control: procedimientos, funciones, subrutinas
Entrada y salida de datos
@ i, j [SAY "mensaje"] [GET <variable>]
El cursor se posiciona en el punto (i,j) y puede desplegar un mensaje a partir de esa posición, obtener una variable, o ambas cosas. Lo ultimo puede realizarse previa inicialización de la variable, que incluso puede ser un campo de la tabla.
Otras alternativas:
?? "mensaje" + <variable> + "Otro mensaje" + ...
? "idem" + <variable>
SET PRINT ON
SET TALK ON
Esquema general de un programa
MODIFY COMMAND <nombre del programa>
A continuación se dan una serie de comandos de interés:
&& y * : indican comentarios
Contorno de un programa:
SET TALK OFF
SET STATUS OFF
SET DATE ITALIAN
CLEAR ALL
Para ejecutar un programa se debe ingresar:
DO <Nombre del programa>
Como lógica del proceso de programación estructurada podemos definir los siguientes pasos a seguir:
Definición del problema
División del problema en módulos
Definición de los módulos
División de los módulos en otros módulos constituyentes
Codificación de estos submódulos
Ejecución y depuración según la necesidad
Codificación
Ejecución y depuración de módulos
Codificación del problema
Enlazamiento, encadenamiento de módulos
Funcionamiento y depuración del programa integro
Funciones, procedimientos y operadores predefinidos principales
operadores lógicos | descripción |
not | Negación lógica |
and | Conjunción lógica |
or | Disyunción lógica |
operadores de cadena | descripción |
+ | Concatenación de cadenas |
$ | Búsqueda de subcadenas |
operadores matemáticos | descripción |
+ | Suma |
- | Resta |
* | Multiplicación |
/ | División |
**, ^ | Exponenciación |
() | Paréntesis de reagrupamiento |
operadores relacionales | descripción |
< | Menor que |
> | Mayor que |
= | Igualdad |
<>,# | Distinto que |
<= | Menor igual |
>= | Mayor igual |
funciones predefinidas
Las funciones casi son como ordenes, cada una comenzando con una palabra clave.
Entre las funciones más usuales están las de tiempo y fecha, las funciones que convierten caracteres en mayúscula a minúscula y viceversa, funciones de archivos y registros, y funciones matemáticas.
fecha y hora
-
date (fecha)
Función que proporciona la fecha actual.
-
time (tiempo)
Función que proporciona la hora actual.
-
ctod y dtoc
Son las funciones de carácter a fecha y de fecha a carácter.
funciones para caracteres y cadenas
-
trim
Es la función que elimina los espacios finales, los espacios en blanco que siguen a caracteres, de una cadena.
-
len
Medida de la longitud de la cadena.
-
upper (condición)
Función que convierte las letras minúsculas en letras mayúsculas.
funciones para la conversión de caracteres
-
srt
Es la función que se utiliza para convertir un valor numérico en una cadena de caracteres.
-
lower (condición)
Es la función inversa de UPPER y convierte letras mayúsculas a minúsculas.
funciones para archivos y registros
-
recno (condición)
Es la función que da dos formas de conocer exactamente donde está situado el puntero en la base de datos.
-
eof
(end of file) función que permite determinar que el puntero está al final del archivo.
funciones matemáticas
-
exp
Exponenciación
-
int
Muestra la parte entera.
-
log
Logaritmo natural
-
round
Redondeo de los decimales
-
sqrt
Raíz cuadrada
programas específicos
-
help: facilita la utilización de distintas órdenes. Se activa tecleando help y la órden de la que se piden explicaciones.
Durante el trabajo de elaboración de la base de datos, el usuario puede interrumpirlo y activar la órden help, que hace aparecer una explicación exhaustiva en la parte superior de la pantalla.
-
assist: funciona como un auténtico piloto automático. Se activa tecleando assist y <return> y durante el trabajo de elaboración de la base de datos se activa y desactiva apretando F2.
Además de las explicaciones de cada orden está provisto de líneas en negativo donde, a continuación de las elecciones sugeridas por los modelos, los usuarios pueden construirse las órdenes trozo por trozo.
PASCAL
Historia, características generales
El lenguaje Pascal se creó en la década de los 70 con el objetivo de disponer de un lenguaje de programación de alto nivel y propósito general (se utiliza para gran diversidad de aplicaciones) orientado hacia los nuevos conceptos de programación, desarrollado por el profesor suizo Niklaus Wirth, como un lenguaje para la enseñar la programación de modo disciplinado, fácil de aprender y con la complejidad suficiente para permitir una correcta preparación de los programadores futuros.
Una versión preliminar del lenguaje apareció en 1968 y el primer compilador totalmente completo apareció a finales de 1970 (compilador: programa que hace posible la traducción de un lenguaje de programación al medio que solo entiende el ordenador). Cuando Pascal fue diseñado, ya existían muchos lenguajes de programación, pero pocos eran de uso generalizado: FORTRAN, C, Assambler, COBOL. La idea clave del nuevo lenguaje fue el orden, administrado mediante un concepto sólido de tipo de dato, y requiriendo declaraciones de tipo y controles de programa estructurados.
El lenguaje fue diseñado también para ser un instrumento de enseñanza a estudiantes que aprendían a programar. Desde entonces muchos compiladores han sido construidos y están disponibles para diferentes máquinas. De entre todas ellas Turbo Pascal es sin duda la versión más importante entre los compiladores desarrollados, ofreciéndonos un entorno operativo de programación en la que se integran el mismo editor de programa, el compilador y un interprete, perfectamente desarrollado para desarrollar programas en Pascal.
Características
El lenguaje estándar presenta una serie de características que lo hacen el lenguaje perfecto para aquellas personas iniciadas en la programación:
Excelente para el aprendizaje de la programación.
Lenguaje de propósito general, es decir, se puede aplicar a gran diversidad de aplicaciones.
Utilización de procedimiento (programación modular).
Lenguaje estructurado, se utilizan secuencias de control de bifurcación y bucles(if, for, while, repeat) sin necesidad de la famosa instrucción GOTO tan utilizada en muchos lenguajes como BASIC.
Soporta la recursividad, es decir, propiedad que tienen los procedimientos para llamarse a sí mismo.
Tipo de datos simples y estructurado, así como definidos por el usuario.
Posibilidad de trabajar con punteros (variables dinámicas), de este modo permite definir nuestras propias estructuras de datos dinámicas (lista, pilas, colas, etc).
Es un lenguaje fuertemente tipado.
Clasificación
El lenguaje Pascal es clasificado como lenguaje de programación Procedimental o Procedural, y por esto las funciones en estos lenguajes tienen una importancia mayor que los datos. Estos lenguajes se construyen a partir de diagramas de flujo de datos, que muestran el flujo de datos a través de un sistema, dentro y fuera de las funciones y/o procedimientos.
Tipos de datos simples
ordinales
-
Integer: Incluye valores positivos y negativos. El rango de valores es de -32.768 a 32.767. El valor entero más grande que puede obtenerse esta contenido en el identificador.
Dentro de los tipos enteros hay cinco tipos predefinidos diferentes: byte (entre 0 y 255), shortint, word (2 byte) y longint.
-
Boolean: Sólo tiene dos valores posibles: Verdadero (TRUE) y Falso (FALSE).
-
Char: Se representan entre comillas, incluyen todas las letras mayúsculas, minúsculas, números y caracteres especiales.
-
Enumerado:
-
Subrango se compone de un conjunto de valores referenciados por identificadores. Estos valores constituyen una lista de identificadores de constantes que ele programador debe indicar en la parte del programa reservada a las declaraciones.
Su orden se indica por la disposición de los valores en la definición.
Los únicos que pueden acompañar a los tipos ordinales son los operadores de relación y asignación.
-
Cadena (string): Es una secuencia de caracteres de cero o más caracteres correspondientes al código ascii. La longitud de una cadena es el número de caracteres encerrados entre los apóstrofes. Una variable tipo STRING puede identificarse como un arreglo de caracteres.
no ordinales
-
Real: Incluye valores positivos y negativos con parte fraccionaria. Es permitida la notación científica con exponentes enteros. El rango de valores sin tomar en cuenta el signo del número es de 2.9 x 10-39 a 1.7 x 1038.
Se pueden representar de dos formas: en notación científica o de coma flotante (el área ocupada se divide en dos zonas: mantisa y exponente) y en notación en coma fija (expresa el número real con un punto decimal).
No o
Símbolos y caracteres
Pascal acepta cualquier carácter del código ASCII de datos.
ESTRUCTURAS DE DATOS PRINCIPALES
1. LA ESTRUCTURA ARRAY
Un array (también llamado matriz, vector, arreglo, etc) es una estructura homogénea de datos, de tamaño constante, y con acceso a cada uno de sus elementos mediante un identificador común y uno o varios índices. De esta definición se sacan las siguientes características que tiene un array:
Todos los elementos del array son del mismo tipo.
El número de ellos no varía durante la ejecución del programa.
Accedemos a un elemento de la estructura mediante un identificador común (el nombre del array), y con el valor que toman uno o varios índices. Al número de índices necesarios para designar un elemento del array se le denomina dimensión del array.
El número máximo de valores posibles que puede tomar cada índice se denomina rango de esa dimensión o índice. Los valores han de ser consecutivos, por lo que el índice ha de ser de un tipo ordinal.
1.1 - DECLARACIÓN DE TIPOS Y VARIABLES ARRAY
La declaración más general de un array es la siguiente:
Type Rango1 = TipoOrdinal1; Rango2 = TipoOrdinal2; ... Rango1N= TipoOrdinalN; TipoBase = (*cualquiera definido por el usuario*) TipoArray = Array[Rango, Rango2, ... , RangoN) of TipoBase;
que también puede declararse así: TipoArray = Array[Rango1] of [Rango2] of ... of [RangoN] of TipoBase; |
1.2- OPERACIONES CON ARRAYS
Con los elementos que componen la estructura podemos realizar las mismas operaciones que el tipo base al que pertenecen.
Acceso a los elementos de un array
Se debe utilizar el nombre o identificador del array, seguido por tantos valores de tipo ordinal compatibles con el tipo de los índices, como dimensiones tenga el array. Este conjunto de valores, que incluso pueden ser expresiones de tipo ordinal, deben ir encerrados entre corchetes y separados por comas unos de otros.
-
Operaciones con la estructura
Las dos únicas operaciones posibles con la estructura son:
Asignación: Podemos asignar un array a otro siempre que tengan tipos compatibles.
Paso como parámetros a un subprograma: Se pueden pasar arrays como parámetros a procedimientos y funciones teniendo la precaución de que el tipo al que pertenecen esté definido globalmente.
-
Constantes variables array
Esta forma de declarar constantes tiene el inconveniente que no hace transportable el código a otro compilador de Pascal, por lo que tendríamos que modificar su código fuente.
1.3ARRAYS ESPECIALES: CADENAS DE CARACTERES
Una cadena de caracteres (string) es un tipo de datos consistente en una serie o secuencia de caracteres cuyo número (longitud) puede variar de 0 a 255. Turbo Pascal soporta datos de tipo cadena, no así Pascal estándar, que carece de instrucciones específicas de tratamiento de este tipo de datos, y debe implementarlas mediante arrays de caracteres.
El tipo string tiene una longitud de 255 caracteres, pero se pueden definir cadenas más cortas, especificando la longitud máxima requerida entre corchetes.
La longitud física corresponde al máximo número de caracteres que puede almacenar, mientras que la longitud lógica corresponde al número de caracteres que tiene en un instante determinado.
1.4 OPERACIONES CON CADENAS
Todas estas operaciones hacen distinción entre mayúsculas y minúsculas.
Comparación de cadenas
Se hacen según el orden del código ASCII. Los operadores relacionales =, <, >, >=, <=, <>, permiten realizar comparaciones lógicas. Las cadenas empiezan a compararse por el primer carácter de la izquierda. Si los dos son iguales continúa la comparación hasta encontrar dos distintos. Se considera que una cadena es "menor" que otra cuando el primer carácter que es distinto es anterior alfabéticamente.
-
Concatenación de cadenas
Esta operación combina dos o más cadenas en una sola. Existen dos métodos:
Mediante el operador de concatenación `+'.
La función predefinida Concat. Acepta cualquier número de variables y constantes de cadena como parámetros, separados por comas.
-
La cadena vacía o nula
Es una cadena que tiene longitud cero. Se representa con dos apóstrofes seguidos (`').
-
Acceso a los elementos de una cadena
Se hace de igual forma que los arrays.
1.5 DEFINICIÓN DE CADENAS EN PASCAL ESTÁNDAR
Una cadena se define en Pascal estándar como un array empaquetado de caracteres.
Una cadena de caracteres constante se construye con cualquier sentencia de caracteres encerrados entre apóstrofes. Cada una de estas cadenas constantes representa un array cuyo límite inferior es 1 y el límite superior es el número de caracteres.
Pueden definirse tipos de cadena de caracteres de forma explícita, indicando la longitud:
Type Cadena = Packed Array[1..MAXLONG] of char; Var Cad: Cadena; o bien directamente en la declaración de la variable: Var Cad: Packed Array[1..MAXLONG] of char; |
1.6OPERACIONES CON CADENAS EN PASCAL ESTÁNDAR
Pascal estándar permite las siguientes operaciones:
-
Asignación y comparación
Las asignaciones que se hagan a variables cadena han de coincidir exactamente en número de caracteres entre el dato asignado y la variable.
De igual forma que ocurre con los arrays sin empaquetar, las variables cadena del mismo tipo pueden asignarse unas a otras.
Las comparaciones se hacen según el orden del código ASCII. Los operadores relacionales =, <, >, >=, <=, <>, permiten realizar comparaciones lógicas. Las cadenas empiezan a compararse por el primer carácter de la izquierda. Si los dos son iguales continúa la comparación hasta encontrar dos distintos. Se considera que una cadena es "menor" que otra cuando el primer carácter que es distinto es anterior alfabéticamente. Así, `ANA' es "mayor" que "ALBERTO".
-
Entrada y salida de cadenas de caracteres
Las cadenas de caracteres pueden ser pasadas como argumentos a los procedimientos Write y WriteLn aplicados a ficheros de texto. Sin embargo, los arrays de caracteres no pueden escribirse de una sola llamada, hay que hacerlo carácter a carácter.
En cuanto a la entrada de datos, con Read y ReadLn, hay que hacerla elemento a elemento.
1.7 PACK Y UNPACK
La librería de Pascal estándar tiene estos procedimientos que permiten empaquetar o desempaquetar al mismo tiempo un array.
PACK(U, i, P) copia los elementos del array no empaquetado U a partir de la posición i en el array empaquetado P
UNPACK(P, U, i) copia los elementos del array empaquetado P desde la primera posición del array en el array no empaquetado U comenzando en la posición i. |
2. CONJUNTOS
A)CONCEPTO DE CONJUNTO
Si bien la notación matemática de conjunto no implica limitaciones en cuanto a la naturaleza ni número de componentes de un conjunto, por razones de implementación, Pascal limita los elementos o componentes de un conjunto a un mismo tipo base ordinal y el número máximo de elementos que puede tener una variable conjunto en un momento determinado a 256.
Un conjunto (Set) es, por tanto, un grupo de cero o más elementos de un tipo de base ordinal, es decir, carácter, booleanos y definidos por el usuario (enumerado y subrango).
Para definir una variable de tipo conjunto se pueden seguir los pasos acostumbrados: o bien se definen previamente en la sección TYPE el tipo base y luego el tipo conjunto, o se realiza la declaración correspondiente en la sección VAR. La declaración de un tipo de datos Set comienza con las palabras reservadas set of seguido del tipo base al que pertenecen sus elementos.
Type Tipo_base = (* cualquier tipo ordinal *) Tipo_conjunto = set of Tipo_base; |
3. REGISTROS
3.1 LA ESTRUCTURA DE DATOS REGISTRO
Un registro es una estructura homogénea de datos, denominados campos, y a los que a diferencia de un array accedemos por nombre y no por medio de un índice, como en el caso de los arrays.
Type TRegistro = Record Campo1:...; (*De cualquier tipo*) Campo2:...; ... CampoN:...; End; Var Registro: TRegistro; |
2.2 ACCESO A LOS CAMPOS
El acceso a la variable registro se realiza mediante su identificador, y el acceso a un campo del registro, a través de un selector o identificador de campo, compuesto por el nombre de la variable registro, y el nombre del campo separados por un punto.
Se hace pesado poner el nombre del registro cada vez que se necesite acceder a un campo. Para esto se utiliza la palabra reservada WITH, que indica al compilador Pascal que asocie los identificadores de los campos con el nombre de la variable registro de la sentencia WITH.
2.3REGISTROS COMO OPERANDOS Y PARÁMETROS
La única operación que se puede hacer con una variable tipo registro como tal es la asignación, es decir, copiar todos los campos de una variable registro a otra variable registro del mismo tipo.
Un registro puede ser pasado como parámetro a una función o procedimiento como parámetro actual, siempre y cuando el correspondiente parámetro formal sea del mismo tipo.
La variable registro se pasa por variable y sólo se necesita un parámetro, en lugar de cuatro (una para cada campo).
2.4REGISTROS JERÁRQUICOS
Los campos de los registros pueden ser de cualquier tipo definido por el usuario, incluso también registros. Un registro con uno o más campos de tipo registro se denomina registro jerárquico.
2.5REGISTROS VARIABLES
En Pascal es posible definir tipos registro, que tengan algunos campos que son iguales para todas las variables de ese tipo (parte fija), y algunos campos que pueden ser diferentes o variables (parte variable). La parte variable se especifica con las palabras reservadas CASE..OF y debe declararse inmediatamente después de la parte fija. Sólo se admite una parte variable y sus campos, pueden ser a su vez, variables. Si alguna de las opciones o valores de la parte variable carece de definición de campos se indicaría con un par de paréntesis vacíos.
No debe confundirse el CASE OF de la definición de la parte variable con una estructura o sentencia CASE OF, pues debe observarse la falta del END que la cierra.
3 CONCEPTOS GENERALES DE ARCHIVOS
Un archivo es una estructura de datos consistente en una secuencia de elementos o componentes llamados registros, todos del mismo tipo. Un archivo puede almacenarse en un dispositivo auxiliar (discos, cintas...), de forma que los datos obtenidos antes, durante y después del procesamiento de los datos no se pierden.
3.1DECLARACIÓN Y APERTURA DE ARCHIVOS
Para declarar una variable archivo es necesario indicar el tipo de elementos que lo compone, es decir, definir la naturaleza de sus registros.
Esta declaración puede hacerse directamente en la sección de declaración de variables, o declarar previamente el tipo de archivo en la sección de tipos y posteriormente la variable o variables correspondientes en la sección de variables, procedimiento éste más aconsejado.
3.2El procedimiento ASSIGN
Se utiliza con objeto de asociar un archivo lógico con su archivo físico correspondiente.
Después de la asignación, cualquier operación sobre la variable archivo afectará al archivo correspondiente. El formato del procedimiento es:
Assign(VarArch, NomArch); |
Donde VarArch es una variable de tipo archivo, y NomArch una variable tipo cadena o una cadena de caracteres que contiene el nombre del archivo físico asociado, con expresión de unidad de disco, camino y nombre y extensión.
Los archivos son procesados, registro a registro, con el fin de realizar operaciones de lectura (entrada) o escritura (salida) sobre sus componentes. Los procedimientos RESET y REWRITE permiten abrir los archivos para cada una de las operaciones anteriores.
3.3El procedimiento RESET
Abre un archivo para lectura posicionando el puntero de lectura del archivo en el primer elemento del archivo, y poniendo la variable booleana EOF asociada al archivo a false, o en la marca de fin de archivo si el archivo está vacío, en cuyo caso EOF toma true. Puede utilizarse el procedimiento RESET sobre archivos que ya estén abiertos para lectura, siendo el resultado de la operación reposicionar el puntero de lectura en el primer registro. RESET abre el fichero sólo para lectura, por lo que no permite la modificación del contenido de ningún registro.
El formato de este procedimiento es:
Reset(VarArch); |
3.4El procedimiento REWRITE
Abre el archivo para escritura destruyendo el contenido del archivo si éste ya existía. Su formato es:
Rewrite(VarArch); |
3.5El procedimiento CLOSE
Una de las diferencias más acusadas en el tratamiento de archivos entre Turbo Pascal y Pascal estándar es la necesidad de indicar con el procedimiento CLOSE el proceso de cierre de archivos. En Pascal estándar los archivos se cierran cuando finaliza el programa, mientras que en Turbo Pascal y otros compiladores es necesario el empleo explícito de CLOSE, porque de lo contrario, los últimos datos se perderán. La sintaxis de este procedimiento es:
Close(VarArch) |
El empleo de CLOSE es necesario tanto en procesos de lectura como en procesos de escritura sobre archivos.
3.6PROCEDIMIENTOS DE ENTRADA Y SALIDA
Constituyen dos operaciones básicas que tienen por objeto introducir datos dentro de la computadora y poder extraerlos después de su procesamiento. Los dos procedimientos básicos de E/S son READ (entrada) y WRITE (salida).
En ambas operaciones es muy importante la marca de fin de fichero (EOF).
A)El procedimiento READ
Se usa para introducir el contenido de un registro del archivo en una variable de memoria definida del mismo tipo de dato que el registro leído. El formato es:
Read(VarFich, NomReg) |
B)Fin de archivo: EOF
El tratamiento de una estructura repetitiva, como es el caso de un archivo secuencial, requiere detectar la marca de fin de archivo, con objeto de leer datos que no existen. En cada iteración del bucle se lee un registro del archivo avanzando el puntero de lectura del fichero una posición hacia el fin del mismo. En la lectura del último registro, el avance del puntero posiciona éste sobre la marca de fin de fichero, colocando la función lógica EOF (End of File) asociada a cada archivo a true. EOF tiene el siguiente formato:
EOF(VarArch) |
C)El procedimiento WRITE
Escribe en un registro del fichero el contenido de una variable de memoria definida del mismo tipo. El formato de este procedimiento es:
WRITE(VarFich, NomReg) |
3.7ARCHIVOS DE TEXTO
Están constituidos por secuencias de caracteres de longitud variable, separadas unas de otras por los códigos retorno de carro/ avance de línea (CR/LF, o bien 13/10 en ASCII). Constituyen un tipo predefinido en Pascal, que se designa por TEXT, tipo que no tiene que ser declarado de forma explícita en la sección Type. Un archivo de texto se termina con una marca de fin de fichero EOF (^Z o en el código ASCII 26).
A)Declaración de archivos de texto
El formato general es:
Var VarArch: text; |
B)Escritura en un archivo de texto
WRITE y WRITELN escriben el valor de una o varias variables en un archivo de texto de la misma forma que lo hacen sobre pantalla. Los formatos son:
Write(VarArch,v1,v2,...,vN); Writeln(VarArch,v1,v2,...,vN); |
Si no se especifica una variable de archivo en las sentencias, la salida es sobre la pantalla. La sentencia WRITELN, que sólo puede utilizarse con archivos de texto, inserta una marca de fin de línea después de la última variable escrita.
C)Lectura de un archivo de texto
Las sentencias READ y READLN leen caracteres de un archivo igual que lo hacen desde teclado. Los formatos de las sentencias son:
Read(VarArch,v1,v2,...,vN); Readln(VarArch,v1,v2,...,vN); |
El procedimiento READLN sólo puede utilizarse con archivos de texto. Sirve para detectar los caracteres de control (CR/LF) que sirven para separar las distintas líneas de un archivo de texto.
D)La función EOLN
EOLN(VarAch) es una función lógica que se asocia a cada archivo de texto para su procesamiento. Toma el valor true bajo dos condiciones: cuando el puntero de lectura del archivo alcanza un fin de línea o el final del archivo.
El siguiente programa muestra el funcionamiento de los procedimientos READLN y WRITELN y las funciones boolenas EOLN y EOF, realizando una copia de un archivo de texto en otro.
4. LA VARIABLE 'BUFFER' DE FICHERO
Pascal estándar suministra una variable especial, denominada variable "buffer" de archivo y que se representa con f^, donde f es el nombre de la variable archivo, que es una variable del mismo tipo que las componentes del archivo. Esta variable se puede considerar como una especie de ventana a través de la cual podemos acceder, tanto en lectura como en escritura, aunque no de forma simultánea, a los componentes del archivo (registros).
Esta declaración implica la existencia de la variable f^ que almacena números enteros.
A)PUT, GET, RESET Y REWRITE
Para operar con la variable buffer de archivo, Pascal estándar proporciona dos procedimientos especiales, PUT y GET, que no están definidos en Turbo Pascal, y que permiten escribir el contenido de la variable f^ y moverla durante el procesamiento de archivos. Estas variables también están relacionadas con los procedimientos de apertura de archivos RESET y REWRITE.
Los procedimientos que utiliza Pascal estándar para el procesamiento de archivos secuenciales y su relación con la variable buffer de archivo f^ son los siguientes:
-
Reset(f)
Posiciona la variable f^ sobre el primer elemento del archivo. Si el archivo está vacío, el contenido de la variable f^ es indefinido y eof(f) toma el valor true. Si el archivo contiene elementos, el contenido de f^ es el del primer registro del archivo y eof(f) toma el valor false.
-
Rewrite(f)
Operación que reescribe el archivo, de modo que si existiera previamente, se perderían los datos, es decir, sea cual sea el contenido de f, lo sustituye por el archivo vacío, eof(f) toma true y se pueden grabar registros en el archivo.
-
Get(f)
Hace avanzar f^ al próximo componente del mismo, es decir, asigna a la variable buffer de archivo el contenido del siguiente registro al actual. De no existir tal componente, el valor de f^ es indefinido y eof(f) toma true.
-
Put(f)
Permite añadir el contenido de la variable f^ al archivo abierto para escritura. Sólo se puede utilizar si eof(f) es true, es decir, estamos en el final del fichero.
Relación de GET y PUT con READ y WRITE
Los procedimientos READ y WRITE están íntimamente relacionados con la variable buffer de archivo y con las variables registro que reciben los valores correspondientes. Las relaciones son las que se indican a continuación:
Read(f, registro); equivale a: registro:= f^; get(f); |
Write(f, registro); equivale a: f^:= registro; put(f); |
El empleo de READ y WRITE es más sencillo que el de PUT y GET, ya que gracias a ellos nos evitamos considerar el valor de la variable f^, indefinido en algunas ocasiones, si bien, el empleo de esta variable se puede emplear como lectura anticipada de los registros del fichero.
-
El procedimiento page
Pascal estándar proporciona este procedimiento especial, y no contemplado en Turbo Pascal, cuando el contenido de un archivo se lista por impresora y se quiere obtener un salto de página.
5. PUNTERO
5.1 EL TIPO DE DATO PUNTERO
Pascal proporciona un tipo especial de variable denominada puntero, que es una variable cuyo valor o contenido es la dirección de una posición de memoria, donde se establece una variable asociada al mismo.
Al definir un tipo puntero, se debe indicar el tipo de valores que se almacenarán en las posiciones designadas o referenciadas por los mismos. La razón es que los diferentes tipos de datos requieren diferentes cantidades de memoria para almacenar sus valores.
Una variable de tipo puntero contiene la dirección de la posición de otra variable.
Para declarar una variable puntero en Pascal, se debe especificar el nombre de la variable puntero y el valor que se almacenará en la posición de memoria referenciada.
Type Tdato=...; Tpuntero=^Tdato; Var Apuntador: Tpuntero; |
Una variable de tipo Tpuntero es un puntero hacia un dato de tipo Tdato.
5.2 OPERACIONES CON PUNTEROS
-
Procedimiento NEW(P)
Este procedimiento aplicado a un puntero P es el que crea una nueva variable dinámica denominada P^ y establece que la variable puntero P apunte a ella.
La llamada a NEW exige que exista suficiente espacio de memoria, ya que en caso contrario se producirá un error en tiempo de ejecución.
-
Procedimiento DISPOSE(P)
Libera la posición de memoria ocupada por una variable dinámica, y deja el valor de la variable puntero indefinido, por lo que cualquier intento de referenciar a P^ producirá un error. Dicho de otra forma, destruye la asociación de la variable puntero con la dirección de memoria asociada a la variable dinámica que referenciaba.
-
Inicialización y asignación de punteros
La asignación de variables puntero sólo está permitida si las dos variables puntero están definidas como punteros al mismo tipo de datos. Esta operación sirva para referenciar con dos variables puntero distintas una misma variable dinámica.
-
Constante NIL
Pascal proporciona una constante predefinida, NIL, que se utiliza para indicar que una variable puntero no apunta a ninguna posición. Esta constante puede ser asignada a un puntero de cualquier tipo:
P:=NIL; |
Como NIL no apunta a ninguna posición de memoria, una referencia a P^ generará un error en tiempo de ejecución.
-
Operadores relacionales entre variables puntero
Los punteros pueden ser comparados sólo en expresiones de igualdad, y siempre que referencien al mismo tipo de variable. Esto indica que los únicos operadores relaciones entre punteros son los operadores `=' y `<>'.
6. LAS LISTAS ENLAZADAS
6.1Estructuras de datos estáticas y dinámicas
En capítulos anteriores se han estudiado estructuras de datos estáticas (conjuntos, arrays, registros...), cuya característica esencial es que su almacenamiento en memoria (número de elementos) se determina a priori en el momento de escribir el programa y se fija durante la compilación. Durante la ejecución del programa sus valores se pueden modificar, pero no se puede cambiar el número de elementos de la estructura, que es fijo.
Para paliar este inconveniente, se utilizan las estructuras dinámicas de datos, que son aquellas en las que podemos aumentar o reducir su número de elementos (nodos) de acuerdo con las necesidades del programa. Las estructuras dinámicas de datos se dividen en dos grandes grupos: lineales (listas, pilas, colas...) y no lineales (árboles, grafos...).
6.2DEFINICIÓN DE LISTA ENLAZADA
Son estructuras dinámicas lineales de elementos llamados nodos, que se encuentran enlazados o relacionados cada uno con el siguiente mediante un enlace o puntero. Cada nodo debe tener dos campos: un campo (info) que contiene el valor de ese elemento y un campo (enlace o puntero) que indica la posición del siguiente elemento.
Existe una marca para fin de lista, que es la constante NIL, representada por una barra inclinada en el último nodo.
-
Declaración de un nodo
Seguidamente indicamos cómo se declara un puntero para referenciar un nodo correspondiente a una estructura dinámica de datos:
Type Tptro = ^Tnodo; Tnodo = Record Info: TipoDato; (* cualquier tipo de datos definido por el usuario *) Enlace: Tptro End; |
Observe que la definición de Tptro precede a la definición del registro tipo Tnodo. Esta es una de las pocas situaciones en las que está permitido utilizar un identificador (Tnodo) antes de ser definido.
Para las operaciones que a continuación se describen (inicialización, insertar al principio, insertar al final, recorrido y eliminación de un nodo de una lista).
-
Inicialización de una lista enlazada
Construye una lista vacía, es decir, que no contiene elementos.
-
Insertar al principio de la lista
Crea un nodo y lo pone en el primer lugar de la lista:
-
Insertar al final de la lista
Crea un nodo y lo pone en el último lugar de la lista.
-
Recorrido de una lista
La operación de imprimir los datos de una lista se conoce como recorrido. Se debe comenzar por la cabecera de la lista y seguir con todos los punteros de la lista, imprimiendo todos los campos info (datos).
-
Eliminar un nodo
Borrar o eliminar el nodo al que se está apuntando, exige conectar el nodo precedente al nodo después del que se desea borrar:
6.3INSTRUCCIONES DE ENTRADA Y SALIDA
La instrucción de entrada de datos que usaremos por el momento será READLN. Esta instrucción admite un número variable de parámetros. Los parámetros pueden ser variables de los tipos estándares antes mencionados. El uso principal de esta instrucción es la captura de valores desde el teclado para asignarlos a las correspondientes variables. Podemos leer un valor a la vez utilizando varias instrucciones READLN, una por cada variable; o podemos utilizar una sola instrucción READLN y utilizar una lista de variable separadas por comas. De la primera forma, cada valor asignado deberá seguirse de la pulsación de la tecla de <ENTER>(o <CR>). Para la segunda forma tenemos dos opciones: la primera opción es idéntica al primer caso, o podemos escribir en línea los valores separados por uno o más espacios en blanco.
La instrucción de salida de datos es WRITELN. Esta instrucción admite como parámetros, variables y cadenas de caracteres, permitiendo dar un formato a la salida, entendiéndose por formato, la impresión de caracteres y valores a voluntad y en una forma particular deseada. Imprime sobre una línea, las cadenas y valores de las variables listadas. Su uso principal es para dirigir la salida de datos y formatos hacia la pantalla.
Pascal utiliza por omisión el formato de notación exponencial; esto puede ser modificado definiendo el ancho e campo y número de decimales, si son requeridos. Esto será tratado en un tema posterior.
6.4COMENTARIOS
Los Comentarios son pequeñas cadenas de caracteres que se insertan dentro del listado de un programa (Programa Fuente) y que no forman parte de las instrucciones del mismo, por tanto no generan código ejecutable, i.e., no son traducidas a lenguaje de máquina por el compilador. Su uso principal es descriptivo, pues permite dejar pequeñas notas, lo que hará más claro el programa tanto para la gente ajena a su realización, como para el mismo programador, como recordatorio, algún tiempo después de la creación del mismo.
En Pascal, los comentarios están limitados por un paréntesis, "(", seguido de un asterisco, "*", y cerrando el comentario con los mismos símbolos pero invirtiendo su orden de aparición (asterisco y paréntesis). En medio de los cuales podrán existir cualquier combinación de caracteres imprimibles, generados desde el teclado.
Estructuras DE CONTROL Condicionales
-
Sentencia IF-THEN / IF-THEN-ELSE
El formato es:
IF <expresión lógica> THEN <Sentencia1> (*IMPORTANTE: no poner punto y coma*) ELSE <Sentencia2>; |
Si el resultado de la expresión lógica es verdadero, entonces se ejecuta la sentencia siguiente a la palabra reservada THEN, en caso contrario, se ejecuta la sentencia a continuación de ELSE.
La cláusula ELSE es opcional, no así la cláusula THEN.
No puede existir un punto y coma inmediatamente antes de un ELSE, ya que se interpretaría como final de la estructura IF y el compilador generaría un error de sintaxis ya que la cláusula ELSE debe ir siempre precedida por la cláusula THEN.
-
Sentencia CASE
Se usa cuando para los distintos valores de una variable o expresión, existen distintos conjuntos de sentencias a ejecutar. Tiene el siguiente formato:
CASE <expresión o variable> OF <lista de constantes 1> : <sentencia1>; <lista de constantes 2> : <sentencia2>; <lista de constantes 3> : <sentencia2>; 2... <lista de constantes N> : <sentenciaN>; ELSE <sentencia> ... END; |
La expresión o variable debe ser de tipo ordinal (entero, carácter, lógico, subrango o enumerado). Cada una de las listas de constantes, que reciben el nombre de etiquetas o selectores, deben ser del mismo tipo que la variable o la expresión.
Si el valor de una de las constantes coincide con el de la expresión, se ejecuta la sentencia asociada a esa etiqueta; si el valor de la expresión no está contenido en ninguna 2de las listas de constantes, entonces se ejecuta la sentencia correspondiente a la cláusula ELSE.
Cuando termina la ejecución de la sentencia, el control salta al final de la estructura (sentencia END;).
Las reglas para utilizar CASE son:
-
Una constante no puede aparecer en dos listas de constantes distintas.
-
Una etiqueta puede estar formada por un tipo subrango si para todos los valores de este tipo la sentencia a ejecutar es la misma, con lo que se ahorra esfuerzo en la codificación.
La cláusula ELSE, no contemplada en Pascal estándar, se reserva para cuando hay que ejecutar sentencias si el selector de la sentencia CASE no toma ninguno de los valores de las etiquetas. Si no hay que ejecutar ninguna sentencia, la cláusula ELSE no se utiliza.
-
sentencia INCONDICIONAL GOTO
Transfiere el2 control del programa a la siguiente a la etiqueta marcada en GOTO. La sentencia GOTO requiere una declaración de etiquetas LABEL. Cada etiqueta sólo puede marcar una sentencia dentro de un programa.
GOTO debe ser evitado y su uso restringido, por no decir prohibido.
Estructuras de control repetitivas
-
Sentencia WHILE
Indica que se ejecute una sentencia mientras se cumpla una determinada condición, determinada por una expresión lógica:
WHILE condición DO <sentencia>; |
La sentencia WHILE comprueba inicialmente si la condición es verdadera. Si lo es, se ejecutan las sentencias mientras la condición se siga cumpliendo. El bucle finaliza, cuando la expresión lógica tome valor false.
Características del bucle WHILE: 2
La expresión se verifica antes que las sentencias del interior del bucle se ejecuten, por tanto, deben ser inicializadas antes de la ejecución del bucle.
El bucle WHILE se ejecuta mientras la condición sea verdadera.
Dentro del bucle debe existir una sentencia que modifique el valor de la expresión, pues de lo contrario, el valor inicial verdadero nunca se modifica, y se ejecutará el bucle infinitamente.
Si la expresión lógica es falsa al comenzar el bucle, éste no se realizará.
-
Sentencia REPEAT-UNTIL
Repite las sentencias comprendidas entre las palabras reservadas REPEAT y UNTIL hasta que la expresión sea verdadera. Tiene el siguiente formato:
REPEAT <sentencia>; <sentencia>; ... UNTIL condición; |
-
Características del bucle REPEAT:
La expresión se verifica al final del bucle, por tanto, se ejecuta al menos una vez.
El bucle REPEAT se ejecuta hasta que la condición sea verdadera.
Dentro del bucle debe existir una sentencia que modifique el valor de la expresión, pues de lo contrario, el valor inicial falso nunca se modifica, y se ejecutará el bucle infinitamente.
-
Sentencia FOR
Repite la ejecución de una o varias2 sentencias un número fijo de veces. El bucle se ejecuta mientras una variable de control de tipo ordinal toma una serie consecutiva de valores de tipo ordinal. La sentencia FOR tiene dos formatos:
FOR VariableControl:=ValorInicial TO ValorFinal DO <sentencia>; y FOR VariableControl:=ValorInicial DOWNTO ValorFinal DO <sentencia>; |
El primer formato se denomina FOR ascendente y el segundo, descendente.
La variable de control de bucle y los valores iniciales y finales que lo determinan deben ser ordinales y del mismo tipo y no deben ser alterados por ninguna de las sentencias que componen el bucle.
Existe una limitación en el uso de FOR, y es que la variable de control siempre se incrementa o decrementa en una unidad.
Procedimientos, funciones y subrutinas
Los procedimientos y funciones son grupos de sentencias que realizan tareas específicas, o bien que se ejecutan a lo largo del programa principal varias veces. Su estructura es similar a la del programa, con la diferencia de que los procedimientos y funciones comienzan su declaración en su cabecera con las palabras reservadas procedure y function y que en vez de terminar con un punto, terminan con punto y coma.
Los procedimientos y funciones pueden tener sus propias declaraciones de etiquetas, constantes, tipos, variables y sus propios procedimientos y funciones; pero no pueden tener una sentencia USES y se declaran después de las variables y antes del programa principal.A partir de ahora nos referiremos a los procedimientos y funciones, con el término genérico de subprogramas.
A)- LOS PARÁMETROS
Son canales de comunicación para pasar datos entre programas y subprogramas en ambos sentidos. Los parámetros van asociados a variables, constantes, expresiones..., y por tanto, se indican mediante los correspondientes identificadores o expresiones. Los parámetros que se utilizan en la llamada o invocación al subprograma se denominan parámetros actuales, reales o argumentos, y son los que entregan la información al subprograma. Los parámetros que la reciben en el subprograma se denominan parámetros formales o ficticios y se declaran en la cabecera del subprograma. Algunos subprogramas carecen de parámetros, ya que no requieren información del programa principal.
En una llamada a un subprograma debe verificarse que:
El número de parámetros formales debe ser igual al de actuales y que ocupen el mismo orden en cada una de las listas deben ser compatibles en tipo.
Los parámetros actuales se pueden ser:
-
Parámetros por valor
Cuando un parámetro actual se pasa por valor, el subprograma hace una copia del valor de éste en una posición de memoria idéntica en tamaño, pero distinta en ubicación a la del parámetro actual y la asigna al parámetro formal correspondiente. Por lo tanto, se puede modificar el valor del argumento formal dentro del subprograma, pero el valor del argumento actual en el punto de llamada no cambiará.
-
Parámetros por variable o referencia
El parámetro formal queda asociado a la misma posición de memoria que su correspondiente parámetro actual, por lo que cualquier modificación que el subprograma realice sobre el contenido del parámetro formal, se efectúa sobre el parámetro actual correspondiente.
B) DECLARACIONES LOCALES Y GLOBALES
Todos los objetos (constantes, tipos, variables...) declarados en el programa principal son reconocidos y, por tanto, pueden ser utilizados por cualquiera de los subprogramas llamados por el programa principal. Se dice que su ámbito o dominio de visibilidad es global.
Todos los objetos que un subprograma necesite para su uso exclusivo se definirán en la sección de declaraciones correspondiente a cada subprograma, serán propios de éste y, por tanto, inaccesibles para el programa principal o llamador.
C)- ESTRUCTURA, DECLARACIÓN Y EMPLEO DE UN SUBPROGRAMA
Los subprogramas (procedimientos y funciones) se declaran inmediatamente después de las variables del programa principal, teniendo la precaución de que si un subprograma llama a otro, el llamado debe declararse primero.
Declaración de procedimientos
Cabecera Procedure NombreProcedimiento(lista de parámetros); Declaraciones Const... Locales Type... Var... <declaración de otros procedimientos y funciones> Cuerpo Begin ... End; |
Los parámetros formales se declaran, encerrados entre paréntesis, indicando el identificador y el tipo correspondiente asociado a cada uno, separados por ":", y terminando en ";". La palabra reservada VAR precediendo a un identificador de parámetro formal indica al compilador de Pascal que el paso 6del parámetro es por variable. Su ausencia indica que el paso de parámetro se hace por valor.Si dos parámetros son del mismo tipo se pueden declarar separados por comas y seguidos por el tipo al que pertenecen. Si dos o más parámetros son del mismo tipo, y además son todos pasados por variable, se pueden englobar en la misma declaración VAR.
La llamada o invocación a un procedimiento se realiza desde el programa llamador o principal, indicando el identificador del procedimiento seguido de la lista de parámetros actuales encerrados entre paréntesis y separados por comas.
-
Declaración de funciones
Una función es idéntica a un procedimiento, con la diferencia de que la función devuelve un valor de tipo simple . La estructura de una función es la siguiente:
Cabecera Function NomFuncion(lista de parámetros): TipoDato; Declaraciones Const... Locales Type... Var... <declaración de otros procedimientos y funciones> Cuerpo Begin ... NomFuncion:=Valor; ... End; |
Dado que la función devuelve un valor de tipo simple, en la cabecera y separado por dos puntos (:) del cierre del paréntesis, se debe indicar el tipo de datos que devuelve la función.
En el cuerpo del programa, el identificador de la función debe estar situado a la izquierda de por lo menos una sentencia de asignación. Este valor que recibe el identificador de la función es el que se envía al programa o subprograma que realizó la llamada.
Pascal trata a la función como un valor, por lo que puede aparecer en los mismos sitios en los que pueda aparecer un valor: asignación a una variable, componente de una expresión, sentencia de salida WRITE...
El paso de parámetros a funciones se hace de idéntica forma que en procedimientos. Dado que una función devuelve un único valor de tipo simple, no se tendrá la necesidad de cambiar los argumentos, por tanto, el paso de parámetros a funciones se hará siempre por valor, menos cuando se pasen grandes estructuras de datos como parámetros.
INPUT Y OUTPUT
Pascal estándar define dos archivos de texto (TEXT) por defecto que son los archivos INPUT y OUTPUT, que se corresponden con los periféricos estándar de entrada y salida en la instalación, normalmente el teclado y la pantalla o impresora. Los procedimientos READ y WRITE cuando omiten el archivo empleado, se sobreentiende que se emplea estos dos archivos por defecto, por ello es obligatorio su utilización como parámetros en el encabezamiento del programa, no así en Turbo Pascal, donde se pueden omitir.
Los archivos de texto se dividen en líneas formadas por conjuntos de caracteres, separadas unas de otras por caracteres de control especiales. En el código ASCII, la marca separadora de líneas está constituida por la combinación de caracteres CR/LF (retorno de carro/avance de línea).
En este tipo de archivos también se utiliza la variable booleana Eoln(f) para indicar si f^ se encuentra o no sobre la marca separadora de líneas. En caso afirmativo, toma el valor true. En algunas implementaciones e Pascal, el contenido de f^ cuando se encuentra en la marca de fin de línea es un carácter en blanco (#32), por lo que debe tenerse esto en cuenta, por ejemplo, si hacemos una estadística de caracteres de un archivo de texto.
Esquema general de un programa
FUNCIONES PREDEFINIDAS
Algunas de ellas son:
Funciones matemática:
Abs(x) valor a2bsoluto de x ArcTan(x) arco cuya tangente es x Chr(x) devuelve el carácter ASCII de un entero (x) entre 0 y 255 Cos(x) coseno de x Exp(x) ex Frac(x) parte decimal de x Int(x) parte entera de x Ln(x) logaritmo neperiano de x Odd(x) devuelve true si x es impar, y false si es par Ord(x) devuelve el ordinal de una variable de tipo ordinal x Pred(x) ordinal anterior a la variable ordinal x Round(x) entero más próximo a x Sin(x) seno de x Sqr(x) x2 Sqrt(x) raíz cuadrada de x (x>=0); Succ(x) ordinal siguiente a la variable ordinal x Trunc(x) parte entera de x |
Funciones de cadenas.
-
Length
Esta función predefinida proporciona la longitud lógica de una cadena de caracteres.
Longitud:= Lenght(Cadena) |
-
Copy
Extrae una subcadena de caracteres de otra cadena.
Copy(Cad1, Pos, Num) |
La primera posición del carácter a extraer es Pos, y el número de caracteres a extraer se indica en Num. Ambos parámetros deben ser enteros.
Si se solicitan en la subcadena más caracteres de los disponibles, Copy devuelve sólo tantos caracteres como puede hasta el final de la cadena. Si se usa un índice Pos más alto que la longitud de la cadena, devuelve la cadena nula.
-
Pos
Tiene dos parámetros Cad1 y Cad2, y permite determinar si el primero es una subcadena del segundo. En caso afirmativo devuelve la posición en donde comienza Cad1 en el interior de Cad2, en caso negativo, devuelve 0.
Pos(Cad1, Cad2) |
-
Delete
Este procedimiento suprime Num caracteres de la cadena Cad a partir de la posición Pos.
Delete(Cad, Pos, Num) |
-
Insert
Inserta una cadena (Subcadena) en otra (Destino) a partir de una posición (Pos) dada.
Insert(Subcadena, Destino, Pos); |
Todos los caracteres de la variable Destino situados a partir de Pos se desplazarán a la derecha. Si la longitud física de Destino no es suficiente, los caracteres a la derecha se perderán.
-
Str
Convierte un valor numérico a la correspondiente cadena de caracteres que lo representa.
Str(Valor, Cad); |
Donde Valor es el número a convertir y Cad su cadena equivalente.
-
Val
Es el inverso a Str. Permite convertir una cadena de caracteres en un valor numérico. El contenido de la cadena debe corresponder a las reglas de escritura de los números y además, ningún espacio se debe encontrar en primera y última posición. Val devuelve un código de error en el caso de que la cadena de entrada Cad no se pueda convertir a número. Si la conversión se ha podido llevar a cabo, devuelve 0, en caso contrario, Código contiene la posición del primer carácter de la cadena Cad que impide la conversión. En este caso el valor de Variable no está definido.
Val(Cad, Variable, Código) |
Operadores lógicos:
Las expresiones logicas pueden combinarse para formar expresiones mas complejas utilizando los operadores logicos: and, or y not. Estos operadores se utilizan con constantes logicas de forma similar al modo en que los operadores aritmeticos se utilizan con las constantes numericas. Estos operadores trabajan con operandos que son expresiones logicas.
Operador | Sintaxis | Significado |
+ | NOT expresion | Complemento |
AND | Expresion1 AND Expresion2 | And |
OR | Expresion1 OR Expresion2 | OR Inclusiva |
XOR | Expresion1 XOR Expresion2 | OR Exclusiva |
Operadores Aritmeticos
Operador | Sintaxis | Significado |
+ | + expresión | Positivo(unitario) |
+ | Expresion1+ Expresion2 | Suma (Binaria) |
- | -expresion | Negativo(unitario) |
- | Expesion1-expresion2 | Resta(Binario) |
* | Expresion1 *Expresion2 | Multipicacion |
/ | Expresion1 /Expresion2 | Division(Real) |
DIV | Expresion1 DIV Expresion2 | Division Entera |
MOD | Expresion1 MOD Expresion2 | Resto(Modulo) |
Operadores relacionales:
Se utilizan para expresar condiciones y describen una relación entre dos valores.
Operador | Sintaxis | Significado |
= | expresion1 = expresion2 | Expresiones iguales |
<> | expresion1 <> expresion2 | Expresiones diferentes |
< | expresion1 < expresion2 | Expresion1 menor que expresión2 |
<= | expresion1 <= expresion2 | Expresion1 menor o igual que expresión2 |
> | expresion1 > expresion2 | Expresion1 mayor que expresión2 |
>= | expresion1 >= expresion2 | Expresion1 mayor o igual que expresión2 |
PERL
Historia, Características Generales
Perl (Practical Extraction and Report Languaje) es un lenguaje de programación creado por Larry Wall, surgido a inicios de los noventas, que busca antes que nada el facilitar la elaboración de tareas comunes en sistemas tipo UNIX, donde tradicionalmente las tareas de administración y proceso de datos se realiza con herramientas muy rudimentarias y por demás hostiles al usuario o administrador. Pero que se aplican sobre grandes cantidades de información (por lo regular texto) por lo que se requiere que sean de alto rendimiento.
Perl surgió como una opción para una gran cantidad de herramientas de UNIX en las cuales basa su propia sintaxis, buscando el mínimo sacrificio de su desempeño por una máxima facilidad de programación e integración, sigue la filosofía de mantener un ambiente que sea capaz de detectar y corregir pequeñas omisiones del programador, y de proporcionarle una forma abreviada de realizar múltiples tareas. En una palabra, es una herramienta que pretende facilitar el proceso de grandes volúmenes de información sin sacrificar el rendimiento.
Las plataformas donde Perl más se ha desarrollado son los servidores UNIX, por sus necesidades de administración y lo robusto de su manejo de memoria y de procesos (requisitos de PERL hacia el S. O.) además de la facilidad de Perl para realizar los así llamados CGI, interfaces para comunicar recursos del servidor con un servicio de Internet particular (como podría ser WWW o Gopher), En otras plataformas, PC en particular, se han desarrollado versiones que mantienen un razonable grado de funcionalidad, pero en realidad, el sistema DOS no tiene un manejo lo bastante bueno de los procesos o de la memoria para permitir a PERL dar un buen desempeño, además de que no es común ver en PC necesidades de administración de la magnitud de un servidor institucional. Sin embargo, puede practicarse la programación en PERL de PC, o incluso elaborar programas de reporteo en él, sin embargo, es algo que no se ha popularizado hasta hoy.
Perl no establece ninguna filosofía de programación (de hecho, no se puede decir que sea orientado a objetos, modular o estructurado aun cuando soporta directamente todos estos paradigmas), los objetivos que se tuvieron en cuenta al diseñar la sintaxis de Perl fueron la facilidad de aprendizaje y de uso y la claridad de código, las cuales son necesarias (aunque pueden escribirse programas en Perl complejos e inteligibles si así se desea).
Por si fuese poco, Perl no es ni un compilador ni un interprete, esta en un punto intermedio, cuando mandamos a ejecutar un programa en Perl, se compila el código fuente a un código intermedio en memoria, se le optimiza (como si fuésemos a elaborar un programa ejecutable) pero es ejecutado por un motor, como si se tratase de un interprete. El resultado final, es que se utiliza algo que se comporta como un intérprete pero que tiene un rendimiento comparativo al de programas compilados. Sin embargo, ya existen compiladores de Perl con la versión 5.
TIPOS DE DATOS
Los tipos de datos básicos son :
-
Escalares.
-
Arreglos indexados de Escalares.
-
Arreglos Asociativos de Escalares.
Los escalares pueden ser strings, numéricos o booleanos dependiendo del contexto. Valores de 0 (cero) y '' (null string) son falsos; cualquier otro valor es verdadero.
Los tipos de variables son determinados por la anteposición de un carácter especial.
CARÁCTER VARIABLE
$ Escalar
@ Arreglo Indexado
% Arreglo Asociativo
& Función
Todos los tipos de datos tienen su propio nombre, así como las etiquetas, funciones, archivos y manejadores de directorios.
El tipo de dato escalar es denotado mediante un nombre de variable precedido del símbolo $, y puede contener un número, una cadena de caracteres, y una cadena de caracteres en la que alguno de los caracteres puede ser un carácter especial.
Por ejemplo, para definir una variable de tipo escalar llamada numero y que contenga un el número 15 haríamos:
$numero = 15;
Para almacenar una cadena de caracteres se pueden hacer dos cosas:
-
Definir el contenido entre comillas simples, no interpretándose ningún carácter especial contenido entre ellas, un ejemplo podría ser:
$palabra = 'perros';
-
Definir el contenido entre comillas dobles, interpretándose cualquier carácter especial contenido entre ellas a la hora de la impresión de la cadena, un ejemplo podría ser:
$palabra = " perros \n";
Por último, se puede definir varias variables al mismo tiempo utilizando los paréntesis. Por ejemplo:
($palabra1,$palabra2,$palabra3) = ("ALVAREZ","TURIN","PASCAL");
Reglas a seguir para asignarle nombres a variables escalares |
$[a-zA-Z]+[a-zA-Z0-9_]* |
El tipo de dato array de escalares es denotado mediante un nombre de variable precedido del símbolo @. Un ejemplo de inicialización de una variable de este tipo podría ser:
@frutas = ("manzana","pera","naranja","fresa");
El número de elementos menos uno de un array de escalares se puede obtener mediante el nombre de la variable precedido de los símbolos $#, por ejemplo si se quiere obtener el número de elementos de @frutas haríamos:
$numero_de_elementos = $#frutas+1;
Para ser más exactos $# devuelve el último índice del array, así, si el valor para el primer índice es 0 el número de elementos - 1 será el último valor permitido para indexar el array.
El acceso a un elemento de un array se hace mediante un índice numérico de la forma $nom_variable [ índice ] ; así, si se quiere acceder al tercer elemento de @frutas haríamos:
$2_elemento = $frutas[2];
También se puede acceder a varios elementos de un array de la forma @nom_variable[indice1,...,índice n], por ejemplo:
print @frutas[1,2];
imprimiría el elemento segundo y tercero del array @frutas.
Otra forma de indexar un array es usando el operador rango .. , si se quisiera imprimir todos los valores desde un índice i hasta un índice j se debe utilizar el siguiente formato @nom_variable[i..j], por ejemplo:
print @frutas[0..2];
imprimiría todos los elementos del array @frutas.
Por último tenemos también el tipo de dato array asociativo de escalares, mediante este tipo de datos se puede acceder a un determinado elemento de un array a través de una clave anteriormente definida, para denotar este tipo de dato se debe preceder al nombre de la variable con el símbolo % . Un ejemplo de definición de claves y valores de un determinado array asociativo puede ser:
%precio = ( "manzana",100,"pera",20,"naranja",30,"fresa",200 );
Si se quiere acceder a un elemento de un array asociativo, se debe seguir el siguiente formato @nom_variable { clave }, un ejemplo podría ser:
$numero_de_manzanas=10;
$gasto = @precio {"manzana"} * $numero_de_manzanas;
ESTRUCTURAS DE CONTROL cONDICIONALES
Al igual que en la mayoría de los lenguajes de programación , en Perl existen estructuras como if, for, while.
-
if, elseif, else
La estructura de un if es la siguiente :
if ( .... ) {
......;
......;
}
elsif ( .... ) {
......;
......;
}
elsif ( .... ) {
......;
......;
}
else ( .... ) {
......;
......;
}
Nótese que los elsif y el else van solo si el usuario desea varias preguntas. Aunque sea una instrucción por if debe ir entre llaves.
If y unless:
Todas las estructuras de control necesitan de llaves, aunque solo fuera una instrucción; pero esto es incomodo por ejemplo para los if, es por eso que el if se puede usar de otra forma, poniéndolo al final de lo que queremos ejecutar.
También existe el unless, que hace todo lo contrario del if, es decir, ejecuta la acción si no se cumple la condición del final.
ESTRUCTURAS DE CONTROL CICLICAS
-
While y until
La forma del while es :
while ( condición ) {
....;
....;
}
Lo que esta entre llaves se ejecuta mientras sea verdadera la condición.
La forma del until es :
until ( condición ) {
...;
...;
}
A diferencia del while el until se ejecuta al menos una vez , y se sigue mientras la condición sea falsa , es decir es similar al Repeat/Until de Pascal.
-
For
La forma general del for es :
for ( exp_inicial; exp_testeo; exp_increm){
...;
...;
}
-
Foreach
El foreach de Perl es muy similar al de C-shell, recibe una lista de valores y asigna cada uno de los valores de la lista a una variable de lectura. La estructura del foreach es:
foreach $a ( @alguna_lista ) {
...;
...;
...;
}
ESTRUCTURAS DE CONTROL
SUBRUTINAS:
Al igual que la mayoría de los lenguajes de Programación, Perl soporta subrutinas, también conocidas como procedimientos o funciones.
El formato de declaración de una subrutina es:
sub NOMBRE BLOQUE
La llamada a la subrutina se realiza usando:
do nombre_de_la_subrutina();
&nombre_de_la_subrutina;
Las dos formas producen el mismo resultado con la excepción de que en el caso de do hay siempre que poner los paréntesis, si se quiere pasar argumentos se debe pasar los argumentos entre estos paréntesis, y estos serán almacenados en el array de escalares @_, es decir para saber el numero y el valor de los argumentos pasados a una subrutina hay que leer de este array predefinido.
El valor retornado por la subrutina es el de la última expresión evaluada, y puede ser tanto un array como un escalar. También se puede devolver explícitamente un valor usando return, como en C.
También resulta interesante la declaración y uso de formatos o reports. Con la definición de un report, se esta alterando el formato de salida de los registros cuando utilizamos la función write.
VARIABLES PREDEFINIDAS:
Las siguientes palabras tienen un significado especial en PERL:
$_ : contiene el contenido del último registro leído de un fichero.
$. : contiene el número de la última línea leída de un fichero.
$/ : separador de campo para la entrada.
$, : separador de campo para la salida, aplicable a print.
$\ : separador de registro para la salida, aplicable a print.
$~ : contiene el nombre del formato o report definido para la salida actual.
$^ : contiene el nombre de la cabecera de formato o report definido para la salida actual.
$$ : número de proceso perl scripts que se esta ejecutando actualmente.
$& : representa el valor de la último cadena de caracteres comparada exitosamente.
$` y $': estos dos terminos se utilizan conjuntamente para separar cadenas de caracteres comparadas exitosamente.
$!: contiene el valor actual de ERRNO, es decir, el último error acontecido.
$0: contiene el nombre del fichero que hemos dado a nuestro perl script.
$[: contiene el valor del primer índice de una array de escalares, por defecto es 0.
$<: uid real del proceso actual.
$>: uid efectivo del proceso actual.
$(: gid real del proceso actual.
$): gid efectivo del proceso actual.
@ARGV: contiene los parámetros pasados a nuestro perl script.
%ENV: array asociativo que contiene las variables de entorno bajo el que se ejecuta nuestro perl script.
ENTRADA / SALIDA
Es el modo de capturar / mostrar valores a través del teclado / pantalla. La instrucción básica para mostrar el valor de las variables en pantalla es print. Ejemplo: print "Hola"; Su salida en pantalla sería: Hola
Existen muchos modificadores para la salida de los valores de las variables. A continuación vamos a estudiar algunas de ellos.
"\n" Nueva línea.
"\t" Tabulacíon.
"\r" Retorno de carro.
"\f" Nueva hoja (formfeed).
"\b" Espacio atrás (backspace).
"\e" Secuencia de ESCape.
"\u" Pasa a mayúscula el primer caracter de texto siguiente".
"\U" Pasa a mayúscula todo el texto siguiente".
"\l" Pasa a minúscula el primer caracter de texto siguiente".
"\L" Pasa a minúscula todo el texto siguiente.
"\E" Fin del efecto de los modificadores \U,\L.
"\a" Emite un pitido.
"\cC" Combinación de Control+Letra. En este caso Control-C .
xN El signo por(x) seguido de un número N repite un caracter o texto anterior N veces.
El efecto de estos modificadores serían estos:
print "Hola PERL \n"; Su salida es: Hola PERL seguido de nueva línea.
print "\UHola Perl"; Su salida es: HOLA PERL.
print "\lHola \LPERL \n"; Su salida es: hola perl seguido de nueva línea.
print3x4; Muestra: 3333. NO CONFUNDIR x con el operador * (multiplicar).
print "Hola "x3. Muestra:Hola Hola Hola Hola.
Funciones, OPERADORES PREDEFINIDOS PRINCIPALES
FUNCIONES:
A continuación se describen algunas de las funciones más utilizadas en la programación de un perl script:
abs: devuelve el valor absoluto de la expresión pasada.
chmod: cambia los permisos de los ficheros dados.
chop: recorta y retorna el último carácter de una cadena.
chown: cambia el propietario de los ficheros dados.
close : cierra un fichero.
cos: devuelve el coseno del ángulo dado en radianes.
defined: sirve para comprobar si existe una variable, formato, subrutina, etc..
delete: borra un valor de un array asociativo a través de su clave.
die: imprime en la salida del error estándar un mensaje pasado como parámetro cuando ocurre un error en la ejecución de una sentencia.
eof: retorna verdadero si el final del fichero dado.
eval: evalúa la expresión pasada como si se tratase de un pequeño programa perl.
exec: ejecuta lo que se pasa como parámetro y sale del programa.
exit: hace que salgamos del perl script devolviendo al sistema operativo el valor pasado como argumento.
exp: retorna el numero e elevado a la potencia pasada como parámetro.
fileno: devuelve el descriptor del manejador del fichero pasado como parámetro.
fork: realiza una llamada fork.
getc: lee el siguiente carácter del fichero especificado.
hex: devuelve el valor decimal del numero hexadecimal pasado como parámetro.
index: devuelve la posición de la primera ocurrencia de una cadena en otra.
int: devuelve la parte entera del parámetro pasado.
join: une las cadenas pasadas como argumento con un separador también pasado como argumento.
keys: devuelve todas las claves de un array asociativo.
length: devuelve la longitud en caracteres del parámetro pasado.
local: declara como locales las variables pasadas como argumentos.
log: devuelve el logaritmo del numero dado.
mkdir: crea un directorio en el camino dado.
oct: devuelve el valor decimal del numero octal pasado como parámetro.
open: abre el fichero dado asociándole un manejador de fichero especificado también como parámetro.
pop: retorna y borra el ultimo elemento del array dado.
print: muestra en la salida standar o en el fichero especificado la expresión dada.
push: añade el valor dado al final del array pasado como parámetro.
rand: devuelve un numero aleatorio entre 0 y el valor pasado como argumento.
read: lee un determinado numero de caracteres desde el fichero pasado como argumento.
rename: sirve para renombrar un fichero.
require: sirve para incluir código externo en nuestro guión.
return: devuelve un valor desde una subrutina.
rmdir: borra un directorio.
seek: sitúa un puntero a fichero en un lugar determinado.
select: sirve para seleccionar el manejador de fichero que será utilizado por defecto para la salida de los comandos o funciones que no especifiquen un determinado manejador de fichero como parámetro.
shift: devuelve el primer valor del array dado borrándolo posteriormente.
sin: devuelve el seno del ángulo pasado en radianes.
sleep: causa que el perl script o guion se detenga el numero de segundos especificados.
sort: ordena el array dado.
split: divide una cadena en subcadenas según el separador especificado.
sqrt: devuelve la raíz cuadrada del numero pasado.
system: igual que exec pero no se sale del perl script.
tell: devuelve la posición actual del puntero a fichero del manejador de fichero especificado.
values: devuelve todos los valores del array asociativo dado.
write: escribe un registro con formato en el fichero asociado a ese formato.
OPERADORES
PERL soporta una gran cantidad de operadores, la mayoría de ellos heredados del lenguaje C. En PERL los operadores conservan el mismo uso que en el resto de lenguajes, y se utilizan para realizar operaciones aritméticas, operaciones lógicas, etc., entre las variables del programa. Los operadores pueden clasificarse en los siguientes tipos:
-
Operadores relacionales: mediante estos operadores se pueden enfrentar dos expresiones, de manera que dependiendo de su valor se generará un resultado que puede ser lógico o numérico. PERL tiene los siguientes operadores:
Símbolo == : Este operador sirve para comparar dos valores iguales, de manera que cuando las expresiones a su izquierda y su derecha son iguales, devuelve un valor lógico verdadero y cuando no lo son devuelve falso.
eq : Es empleado para comparar expresiones no numéricas, se utiliza de igual manera que == pero para cadenas.
Símbolo != : Con este operador se comparan cantidades numéricas diferentes.
ne : Se utiliza para comparar cantidades no numéricas diferentes. Su funcionamiento es similar que el de != .
Símbolo < : Verifica el valor de una cantidad numérica con respecto del valor de la expresión de la derecha, de modo que si el valor de esta expresión es mayor que el de la cantidad numérica se devuelve verdadero, en caso contrario se devuelve falso.
Símbolo > : Verifica el valor de una cantidad numérica con respecto del valor de la expresión de la derecha, de modo que si el valor de esta expresión es menor que el de la cantidad numérica se devuelve cierto, en caso contrario se devuelve falso.
Los operadores para los términos menor o igual y mayor o igual son <= y >= respectivamente, y en ambos casos además de el significado de cada término explicado anteriormente, se devuelve cierto si las expresiones son iguales.
-
Operadores sobre cadenas
Como en el caso de las operaciones anteriores, existen equivalentes que se utilizan con las cadenas no numéricas para los términos < y > . Estos operadores son: lt que devuelve cierto si el orden de la cadena de la izquierda es menor que el de la cadena de la derecha, y gt que devuelve cierto si la cadena de la izquierda es mayor que el orden de la cadena de la derecha.
cmp Este término es utilizado para comparar caracteres, de manera que, retorna 0 si los caracteres comparados son iguales, 1 si la cadena de la derecha se encuentra al comienzo de la de la izquierda, y -1 en el caso contrario.
Símbolo <=> : Este término se utiliza para comparar valores numéricos, retornando 0 cuando son iguales, 1 cuando el termino de la derecha es menor que el de la izquierda y -1 en el caso contrario.
Símbolo =~ : Este termino es usado en las expresiones regulares para indicar la presencia de un patrón de comparación dentro de una variable que contiene una cadena de caracteres.
Símbolo !~ : Meditante este operador se verifica la no existencia del patrón de búsqueda en una cadena.
-
Operadores de comparación
Números | Strings |
== | eq |
!= | ne |
< | lt |
> | gt |
<= | le |
>= | ge |
-
Operadores de asignación: los terminos de asignación se utilizan en PERL para dar valores a cualquiera de las variables validas en PERL. Existen en Perl los siguientes operadores de asignación:
Símbolo = : Con este término se asigna a la variable que se encuentra a la izquierda del operador el valor de la expresión de la derecha. Así mediante este valor se pueden dar valores iniciales a cualquier variable.
Símbolo =~ : Aparte de la función de verificación de existencia de un patrón dentro de una cadena, este operador dentro de una expresión regular de sustitución se utiliza para sustituir un patrón de comparación por otra cadena.
-
Operadores aritméticos: Mediante estos términos se realizan las operaciones aritméticas necesarias para el manejo de las expresiones. A parte de los operadores aritméticos comunes; + (suma), - (resta), * (multiplicación) y / (división), PERL también incluye los siguientes operadores:
Símbolo **: Este término se emplea para obtener la potencia de un valor numérico.
Símbolo .: Este término se emplea para concatenar dos cadenas de caracteres.
Símbolo x: Este término multiplica n veces la cadena de caracteres especificada.
Símbolo %: Permite obtener el módulo de la división entre dos números.
Símbolo | : Este término cuando se emplea entre 2 valores numéricos, permite realizar una operación binaria 'o' entre ellos.
Símbolo & : Este término cuando se emplea entre 2 valores numéricos, permite realizar una operación binaria 'y' entre ellos.
El operador de asignación = está muy relacionado con los operadores aritméticos de modo que PERL permite que se combinen ambos siguiendo este formato general:
$variable (operador aritmético)= expresión;
En general lo que se consigue con este formato es realizar la operación aritmética, y posteriormente asignar el valor a la variable.
-
Operadores lógicos: permiten relacionar dos o más expresiones condicionales para determinar si el resultado lógico es falso o cierto. Estos son los diferentes operadores lógicos que emplea PERL:
Símbolo |: Este operador se utiliza en las expresiones regulares como operador lógico 'o', de modo que retorna cierto siempre que cualquiera de los patrones de búsqueda que componen la expresión sea cierto y falso cuando los dos son falsos
Además de utilizarse dentro de las expresiones regulares, también se utiliza para unir mediante la operación 'o' dos expresiones condicionales.
Símbolo ||: También representa la operación lógica 'o' pero en este caso se utiliza sobre instrucciones no sobre expresiones.
Símbolo &: Este operador trabaja como un operador lógico 'y' en expresiones regulares, permite confrontar 2 patrones, de modo que para que se produzca un valor cierto se tiene que cumplir la existencia de ambos en la cadena donde se realiza la comparación, en el caso contrario el valor devuelto es falso.
Como en el caso del operador | también se utiliza para relacionar expresiones condicionales.
Símbolo &&: Al igual que el operador anterior trabaja como un operador lógico 'y', pero con la diferencia de que este operador se emplea sobre instrucciones y no sobre expresiones regulares.
Símbolo !: Con este operador realizamos una evaluación negativa de la expresión.
-
Operadores de Archivo: estos operadores se emplean para verificar en el sistema operativo los permisos de un archivo, o su naturaleza de ejecución, etc. A continuación se muestra los diferentes operadores:
-r : indica si el archivo tiene permiso de lectura.
-W : indica si el archivo tiene permiso de escritura.
-T : indica si el archivo es de tipo texto.
-e : indica si el archivo existe.
-z : indica si el archivo tiene tamaño 0.
-s : indica si el archivo es mayor que 0.
-f : indica si el archivo es plano.
-d : indica si se trata de un directorio.
-M : indica el número días después de la última modificación
-B : indica si el archivo es binario.
-t : indica si el archivo esta abierto en un terminal.
RECONOCEDOR:
sub $es_identificador (`cad'){
$q = 0_2;
@sigma = (letra,digito,otro);
@tipo_delta($q,sigma);
$q0 = 0;
$f = 1;
sub $1do(símbolo){
if {símbolo = `a'..'z','a'..'z'} {$1do = “letra”;}
if {símbolo = `0'..'9'} {$1do = “digito”;}
else {$ido = otro;}
}
}
$delta = tipo_delta;
$estado = q;
{
$delta (0,letra) = 1;
$delta (0,digito) = 2;
$delta (0,otro) = 2;
$delta (1,letra) = 1;
$delta (1,digito) = 1;
$delta (1,otro) = 2;
$delta (2,letra) = 2;
$delta (2,digito) = 2;
$delta (2,otro) = 2;
$estado = q0;
for ($i=0;length(cadena);i++){
$estado = delta(estado, do 1d0(cadena(i))}
$es_identificador = estado in f;
{
print “escriba la cadena: \n”;
$'cad' = <stdin>;
if {do es_identificador (cad)} {print “es identificador”};
else [print “no es identificador”}
}
http://www.lpis.com/ayudas/perl.html
http://www.geocities.com/SunsetStrip/Backstage/6023/CGI_perl_01.html
http://www.geocities.com/SunsetStrip/Backstage/6023/CGI_perl_02.html#Tipos de datos en PERL
http://www.geocities.com/SunsetStrip/Backstage/6023/CGI_perl_03.html#Variables predefinidas
http://geneura.ugr.es/~jmerelo/tutoperl/tutoperl5.html
http://geneura.ugr.es/~jmerelo/tutoperl/tutoperl4.html
http://geneura.ugr.es/~jmerelo/tutoperl/tutoperl6.html
http://geneura.ugr.es/~jmerelo/tutoperl/tutoperl7.html
http://geneura.ugr.es/~jmerelo/tutoperl/tutoperl10.html
http://geneura.ugr.es/~jmerelo/tutoperl/tutoperl11.html
http://geneura.ugr.es/~jmerelo/tutoperl/tutoperl0.html
http://geneura.ugr.es/~jmerelo/tutoperl/tutorial-print.html
American National Standars Institute
Conjunto de funciones de E/S que es portable a un gran número de sistemas operativos (UNIX, VMS, MS-DOS, CP/M,...)
program ejemplo;
uses crt;
const
a=10;
type
formato = string[12];
var
respuesta: formato;
procedure EjemploUno;
begin
{cuerpo del procedimiento}
end;
………
begin
{cuerpo principal del programa}
end.
Descargar
Enviado por: | Elen |
Idioma: | castellano |
País: | Argentina |