Tema IV Conceptos Elementales de Programación

Versión PostScript Versión PDF

Codificación: elementos

Una vez diseñado el algoritmo sobre estructuras de datos adecuadas, se realiza la co-di-ficación en el lenguaje elegido. En este tema se comenzará a estudiar la codificación en Pascal.

 

Léxico y sintaxis

El alfabeto sobre el que se construyen los programas Pascal está constituído por letras, dígitos y algunos otros signos, que se organizan según una forma estricta. Con objeto de describirla se emplean métodos específicos, como la notación Backus-Naur o los gráficos de Conway. En el primer caso, lo que se define aparece a la izquierda de los símbolos ::= y a la derecha la descripción o las descripciones posibles separadas por un símbolo |. Los términos que tengan que ser utilizados literalmente aparecerán en letra normal, y los que se usen para describir, en itálica o entre <>. Por ejemplo:

 

<dígito> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 
<letra mayúscula> ::= A | B | C | D | E | F | G | H | I | J | K | L | M | N 
                  | O | P | Q | R | S | T | U | V | W | X | Y | Z
<letra minúscula> ::= a | b | c | d | e | f | g | h | i | j | k | l | m | n 
                  | o | p | q | r | s | t | u | v | w | x | y | z

En la descripción pueden usarse términos ya descritos:

 

<letra> ::= <letra mayúscula> | <letra minúscula>

Los símbolos de llave { y } encierran en la parte de descripción elementos que pueden aparecer una serie de veces o ninguna:

<entero positivo> ::= <dígito>{<dígito>}

Los gráficos de Conway realizan la descripción mediante el recorrido de un grafo:

\includegraphics[width=8cm]{ConwayNumero}

Con los símbolos del alfabeto se construyen palabras (también llamadas componentes léxicos o ``token''). El conjunto de palabras constituye el léxico del lenguaje.

El léxico del Pascal está constituído por:

Salvo para el caso de las cadenas literales, no se distingue entre mayúsculas y minúsculas.

Con estos elementos se contruyen las frases (sentencias o intrucciones), constituyendo la sintaxis. El símbolo ; separa una sentencia de la siguiente. Normalmente, para facilitar la legibilidad, se escribe cada sentencia en una línea, pero esto no es obligatorio.

La sintaxis completa del Pascal puede encontrarse en varias referencias (por ejemplo en la página web de la asignatura).

El Pascal que se definió inicialmente se conoce como Pascal estándar, y puede encontrarse en el documento ``PASCAL. Manual del usuario e informe'' de Jensen y Wirth (1975). Las implantaciones prácticas (compiladores) pueden ampliar el léxico y la sintaxis pero deben respetar las especificaciones de dicho estándar.

 

Definición y uso

Los lenguajes imperativos se basan en un proceso de definición de elementos y uso posterior. En el caso concreto del Pascal, este proceso es sistemático. La definición consta de declaración de nombre y tipo y asignación de valor. De esta forma, todos los elementos empleados deben tener nombre, tipo y valor para poder ser usados. Para dar nombre a los elementos se emplean identificadores, como se han definido en el apartado anterior.

Por ejemplo: un programa se define cuando se codifica, y se usa cuando se ejecuta.

 

Estructura de un programa

Consta de una cabecera en la que se declara, una descripción (declaración o definición, según los casos) de los datos que se emplean y la sentencia que describe las acciones que se realizarán con dichos datos. Por ejemplo:

 

program PrimerEjemplo (output);
(* Área de un círculo de radio 2'5 *)
const PI = 3.141592;
var radio, area : real ;
BEGIN
    writeln ('Considerando el valor de PI como ', PI);
    radio = 2.5 ;
    area := PI * radio * radio; 
    writeln ('el área de un círculo de radio', radio, ' es ', area)
END.

En la primera línea se declara el programa, dando su nombre (PrimerEjemplo) y su tipo (program (output): programa que tiene salidas pero no entradas). A continuación, se describen los datos y las acciones, constituyendo el contenido (o valor) del programa (Algoritmos + estructuras de datos = programas).

Esta primera línea consta de una frase de 7 palabras separadas entre sí por espacios, y el punto y coma que separa la frase de la siguiente, que está en la siguiente línea. Las 7 palabras son la palabra reservada program, el identificador que le da nombre, los identificadores predefinidos input y output, los paréntesis y la coma.

 

<declaración de programa> ::= program <identificador> |
                              program <identificador> (<lista de dispositivos>)
La segunda línea es un comentario que el compilador ignorará, pero que el lector del programa agradecerá.

La tercera línea define una constante de nombre PI, valor 3.141592 y tipo real (lo determina el valor en este caso).

La cuarta línea declara dos variables de nombres respectivos radio y area y tipo real.

Las acciones a realizar se encuadran en una única sentencia compuesta enmarcada entre las palabras reservadas BEGIN y END, siendo el punto la marca de fin de programa. Como PI ya está definida, puede usarse para mostrar su valor (en la línea 6). La definición de la variable radio se realiza mediante asignación (a 2'5, en la línea 7), y entonces puede usarse para asignar valor a la variable area (línea 8). Finalmente ambas se usan en una nueva sentencia de escritura (línea 9).

 

Variables, constantes y expresiones

Una variable es un lugar de almacenamiento, que debe tener nombre, (para poder referirse a ella), tipo y valor para poder ser usada. La declaración se realiza mediante una sentencia var con la sintaxis:
<declaración de variables> ::= var <lista de identificadores> : <tipo>
                              { ;  <lista de identificadores> : <tipo>}
La asignación se realiza bien mediante una sentencia de asignación:
<sentencia de asignación> ::= <identificador> := <expresión>
bien mediante una lectura del valor que proporcione en ese momento el usuario:
<sentencia de lectura> ::= readln (<lista de identificadores de variable>)
(hay algunos otros modos, que se verán más adelante).

En el primer caso, la expresión está compuesta por constantes y variables previamente definidas, ligadas por operadores adecuados. En el segundo, el usuario debe proporcionar valores de los tipos de las variables a las que se asignarán. El valor de una variable puede cambiar a lo largo de la ejecución (de ahí el nombre de variable).

Una variable se usa en general para formar parte de una expresión (cuyo valor pro-ba-blemente se asignará a otra variable). Cuando se usa, significa el valor que tiene en ese momento. Una expresión tiene un tipo (determinado por sus operadores y operandos) y un valor (es una excepción de la necesidad de nombre, tipo y valor).

Una constante es un valor, que también se almacena en algún lugar. Puede tener nombre (como el caso de PI en el ejemplo) o no tenerlo (como el caso del 2.5 del ejemplo, otra excepción de la necesidad de nombre, tipo y valor). Pero tal valor no cambia en la ejecución (de ahí el llamarla constante).

Las constantes sin nombre pueden usarse sin declarar, puesto que el valor es lo que se usa directamente, y el tipo está determinado por dicho valor.

La definición de constantes con nombre se realiza mediante una sentencia

<definición de constantes> ::= const <identificador> = <valor constante>
                               { , <identificador> = <valor constante>}

En el uso, al igual que en el de las variables, significan su valor. Existen a veces constantes predefinidas. En Pascal, por ejemplo, MAXINT es una constante entera cuyo valor depende de la implantación y es el del mayor número entero positivo representable (al menos $32767 = 2^{15}-1$).

En este segundo ejemplo, el programa es algo más útil: se le pide al usuario el valor del radio.

 

program SegundoEjemplo (input, output);
(* Área de un círculo de radio dado por el usuario*)
const PI = 3.141592;
var radio, area : real ;
BEGIN
    writeln ('Escriba un valor para el radio de un círculo');
    readln (radio);
    writeln ('Considerando el valor de PI como ', PI);
    area := PI * radio * radio; 
    writeln ('el área de un círculo de radio', radio, ' es ', area)
END.

 

Tipo de datos

Tanto las variables como las constantes y las expresiones tienen un tipo. Un tipo viene caracterizado por

De algún modo, un tipo es una forma del lugar de almacenamiento, que determina las operaciones realizables con los datos que pueda contener. Por ejemplo, se pueden sumar enteros, pero no se pueden sumar caracteres.

En los lenguajes existe una serie de tipos predefinidos, y normalmente una forma de permitir que el programador defina los suyos propios. Entre los tipos predefinidos habrá números enteros, reales, caracteres, cadenas de caracteres, etc.

Por ejemplo, en Pascal, el tipo entero está predefinido, caracterizado por su nombre: integer, el conjunto de valores posibles: los números enteros de un intervalo dado, normalmente [-(MAXINT+1), MAXINT], y un conjunto de operaciones que incluyen la suma (+), la diferencia y cambio de signo (-), el producto (*), la división entera (DIV) y el resto de dicha división (MOD).

 

Entrada y salida

La entrada y la salida de datos se realizan mediante procedimientos predefinidos. En el caso del Pascal, llamados read y readln para lectura y write y writeln para escritura.

 

Lectura

Es una asignación en tiempo de ejecución, a una serie de variables que se indican, de unos valores que proporciona el usuario en ese momento, por la vía que se le especifique. La vía más sencilla es el dispositivo (fichero) input, que suele estar asignado al teclado. Si un programa utiliza esta vía, se debe especificar en la cabecera del programa entre la lista de dispositivos.
<sentencia de lectura> ::= 
         read   (<fichero>, <lista de identificadores de variable>) |
         readln (<fichero>, <lista de identificadores de variable>) |
         readln (<fichero>)

Si la vía de entrada es el fichero input, éste puede omitirse, y la sintaxis se reduce a:

 

<sentencia de lectura> ::= read   (<lista de identificadores de variable>) |
                           readln (<lista de identificadores de variable>) |
                           readln

El programa esperará a que el usuario escriba valores suficientes para asignarlos a las variables según el orden. La separación entre los valores se hace mediante espacios en blanco o avances de línea (return). El control de la ejecución está en manos del usuario hasta que éste pulse la tecla de avance de línea.

Si hay más valores en la entrada de los requeridos, quedarán almacenados en una zona de memoria intermedia para posteriores lecturas.

Es responsabilidad del usuario proporcionar datos de los tipos que se esperan. En caso contrario, no está especificado en el estándar qué se hará. Por ello es siempre recomendable que antes de las lecturas, se informe al usuario claramente de lo que se espera.

En el caso de la instrucción readln, una vez satisfechas las asignaciones, se omiten todos los datos que aparezcan en la línea de entrada, de forma que los siguientes accesos para lectura se harán en la línea siguiente.

La instrucción readln sin lista de variables esperará hasta que el usuario pulse un avance de línea (si es que no estaba almacenada tal pulsación en la zona de memoria intermedia de entrada). Suele usarse para forzar una pausa controlada por el usuario.

 

Escritura

Es una acción (procedimiento) que evalúa una serie de expresiones y las muestra por el dispositivo especificado. El más sencillo es el llamado output que suele estar asignado a la pantalla. Nuevamente si éste es el caso, debe especificarse en la declaración del programa, y puede omitirse en la sintaxis:
<sentencia de escritura> ::= 
         write   (<fichero>, <lista de expresiones>) |
         writeln (<fichero>, <lista de expresiones>) |
         writeln (<fichero>)
<sentencia de escritura> ::= 
         write   (<lista de expresiones>) |
         writeln (<lista de expresiones>) |
         writeln

La forma en la que se imprimen los valores calculados depende del tipo de la expresión, según lo predefine el sistema. Por ejemplo, los enteros se mostrarán siempre en una cantidad fija de posiciones; los reales también, lo que forzará en algunos casos a utilizar la notación de punto flotante, formada por un coeficiente y un factor de escala (notación ``científica''). Este comportamiento puede modificarse especificando después de la expresión uno o dos parámetros de ancho de campo, que son expresiones de tipo entero, en la forma:

<expresión para imprimir>::= <expresión>        |
                             <expresión>:<m>    |
                             <expresión>:<m>:<n>

Si aparece el primer parámetro (m), y la representación del dato a escribir ocupa menos de m posiciones, se añaden espacios hasta llegar a m. El segundo, n, se emplea para especificar el número de cifras decimales de los números reales. Si no se especifica, se elegirá una representación de punto flotante o no, según el valor a representar. Las implantaciones concretas de Pascal pueden ampliar el significado de estos parámetros.

 

Documentación

Un programa debe ir acompañado de documentación externa e interna. La documentación interna, contenida en el propio texto del programa, está constituída por los comentarios que estén insertados en el mismo. Debe ser suficientemente significativa y en la cantidad justa: como el objeto de la documentación es facilitar la lectura, un exceso de comentarios puede ser contraproducente. Se debe incluir una descripción de la función que realiza el programa, de los elementos de entrada y salida, y de la fecha de realización. También una breve explicación del significado de los elementos del entorno local. Respecto al algoritmo en sí, una buena técnica es dejar algunos rastros del diseño descendente en forma de comentarios, señalando más el qué se hace que el cómo se hace.

Aunque no sea documentación propiamente dicha, es importante mantener una disposición de código clara, con indentaciones que respeten la estructura de acciones y líneas en blanco que faciliten la visión global, así como elegir nombres significativos para nombrar elementos. Esta adecuada elección de nombres en muchas ocasiones hará innecesaria la explicación del significado de dichos elementos (por ejemplo: si una variable se llama VelocidadInicial no habrá que explicar para qué se usa, y siempre que se use en el código se recordará su significado; pero la situación cambia si se llama x).