Sintaxis de Pascal
El propósito de esta página es proporcionar un resumen de
la sintaxis, expresada en BNF (Formas de Backus-Naur), del subconjunto del
lenguaje Pascal contemplado en la asignatura
Programación I,
curso 99/00.
Debe quedar claro que estas definiciones tan sólo incorporan la
sintaxis básica, y por lo tanto el que un elemento cumpla una
definición no significa necesariamente que sea una construcción
correcta en Pascal. Por ejemplo, la definición de sentencia de
asignación, <Variable> := <Expresion> no incorpora
la información de que el resultado de la evaluación de la
expresión debe ser de un tipo de datos compatible con el tipo de la
variable.
Ese tipo de información corresponde a la semántica
del lenguaje, y sólo se incorpora de manera parcial mediante
construcciones del tipo Identificador de funcion, que
restringen los elementos permitidos en una parte de la definición.
Cuando aparezca el símbolo ‡ en la parte derecha
de una definición, significa que existe un enlace a una página
donde se proporciona información adicional sobre ese elemento
(significado, restricciones, etc).
Para facilitar la búsqueda de una definición concreta,
elija el término en la siguiente lista y pulse "Ver Definicion", o
comienze con un elemento de alto nivel como Programa
, Unidad o Tipo de dato.
- Alternativa doble ::= if <Condicion> then <Sentencia> else <Sentencia>
- Alternativa multiple ::= case <Expresion de Tipo ordinal> of <Caso>{; <Caso>} end
Alternativa multiple ::= case <Expresion de Tipo ordinal> of <Caso>{; <Caso>} else <Sentencia> end
‡
- Alternativa simple ::= if <Condicion> then <Sentencia>
- Bucle con numero fijo de iteraciones ::= for <Sentencia de asignacion> to <Expresion de Tipo ordinal> do <Sentencia>
Bucle con numero fijo de iteraciones ::= for <Sentencia de asignacion> downto <Expresion de Tipo ordinal> do <Sentencia>
‡
- Bucle con salida al final ::= repeat <Sentencia>{; <Sentencia>} until <Condicion>
- Bucle con salida al principio ::= while <Condicion> do <Sentencia>
- Cabecera de funcion ::= function <Identificador de funcion> : <Identificador de Tipo elemental> ;
Cabecera de funcion ::= function <Identificador de funcion> ( <Parametros formales por valor>{; <Parametros formales por valor>} ) : <Identificador de Tipo elemental> ;
- Cabecera de procedimiento ::= procedure <Identificador de procedimiento> ;
Cabecera de procedimiento ::= procedure <Identificador de procedimiento> ( <Parametros formales>{; <Parametros formales>} ) ;
- Cabecera de programa ::= program <Identificador de programa> ;
Cabecera de programa ::= program <Identificador de programa> ( <Lista de dispositivos> );
- Cabecera de unidad ::= unit <Identificador de unidad> ;
- Caracter de subrayado ::= _
- Caso ::= <Rango de literales> : <Sentencia>
- Comentario ::= { {<Caracter>} }
Comentario ::= (* {<Caracter>} *)
- Condicion ::= <Expresion de tipo boolean>
- Conversion de tipo ::= <Identificador de Tipo ordinal> ( <Expresion de Tipo ordinal> )
- Cuerpo de funcion ::= <Sentencia compuesta>
- Cuerpo de procedimiento ::= <Sentencia compuesta>
- Cuerpo de programa ::= <Sentencia compuesta>
- Declaracion de campos ::= <Identificador de campo>{, <Identificador de campo>} : <Identificador de Tipo de dato>
- Declaracion de constante ::= <Identificador de constante> = <Literal>
Declaracion de constante ::= <Identificador de constante> : <Identificador de Tipo elemental> = <Literal>
- Declaracion de funcion ::= <Cabecera de funcion><Zona de declaraciones><Cuerpo de funcion>
- Declaracion de interfaz ::= <Cabecera de funcion> | <Cabecera de procedimiento>
- Declaracion de procedimiento ::= <Cabecera de procedimiento><Zona de declaraciones><Cuerpo de procedimiento>
- Declaracion de subprograma ::= <Declaracion de funcion> | <Declaracion de procedimiento>
- Declaracion de variables ::= <Identificador de variable>{, <Identificador de variable>} : <Tipo de dato>
- Definicion de tipo ::= <Identificador de tipo> = <Tipo de dato>
- Digito ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
- Dispositivo ::= input | output | <Identificador de variable tipo fichero>
- Elemento de array ::= <Variable de Tipo array> [ <Expresion de Tipo indice>{, <Expresion de Tipo indice>} ]
- Elemento de estructura ::= <Elemento de array> | <Elemento de registro>
- Elemento de registro ::= <Variable de Tipo registro> . <Identificador de campo>
- Estructura alternativa ::= <Alternativa simple> | <Alternativa doble> | <Alternativa multiple>
- Estructura de control ::= <Estructura alternativa> | <Estructura iterativa> | <Estructura with>
- Estructura iterativa ::= <Bucle con salida al principio> | <Bucle con salida al final> | <Bucle con numero fijo de iteraciones>
- Estructura with ::= with <Variable de tipo registro> do <Sentencia>
- Expresion ::= <Literal> | <Identificador de constante> | <Variable> | <Expresion unaria> | <Expresion binaria> | <Llamada a funcion> | <Conversion de tipo>
Expresion ::= ( <Expresion> )
- Expresion binaria ::= <Expresion><Operador binario><Expresion>
- Expresion unaria ::= <Operador unario><Expresion>
- Identificador ::= <Letra>{<Letra> | <Digito>}
- Letra ::= <Letra mayuscula> | <Letra minuscula> | <Caracter de subrayado>
- Letra mayuscula ::= 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 minuscula ::= 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
- Lista de dispositivos ::= <Dispositivo>{<Dispositivo>}
- Literal ::= <Literal de tipo entero> | <Literal de tipo real> | <Literal de tipo caracter> | <Literal de tipo boolean> | <Literal de tipo string> | <Literal de tipo conjunto> | <Literal de tipo puntero> | <Literal tipo enumerado>
- Literal de tipo boolean ::= true | false
‡
- Literal de tipo caracter ::= ' <Caracter> '
Literal de tipo caracter ::= # <Digito>{<Digito>}
‡
- Literal de tipo conjunto ::= [ ]
Literal de tipo conjunto ::= [ <Rango de valores> ]
- Literal de tipo entero ::= <Signo><Digito>{<Digito>}
- Literal de tipo puntero ::= nil
‡
- Literal de tipo real ::= <Signo><Digito>{<Digito>} . <Digito>{<Digito>}
Literal de tipo real ::= <Signo><Digito>{<Digito>} e <Signo><Digito>{<Digito>}
Literal de tipo real ::= <Signo><Digito>{<Digito>} . <Digito>{<Digito>} e <Signo><Digito>{<Digito>}
- Literal de tipo string ::= ' {<Caracter>} '
- Literal tipo enumerado ::= <Identificador de valor enumerado>
- Llamada a funcion ::= <Identificador de funcion>
Llamada a funcion ::= <Identificador de funcion> ( <Parametros actuales por valor>{; <Parametros actuales por valor>} )
- Llamada a procedimiento ::= <Identificador de procedimiento>
Llamada a procedimiento ::= <Identificador de procedimiento> ( <Parametros actuales>{; <Parametros actuales>} )
- Operador aritmetico entero ::= + | - | * | div | mod
‡
- Operador aritmetico real ::= + | - | * | /
‡
- Operador binario ::= + | - | * | div | mod | / | and | or | = | <> | < | > | <= | >= | in
- Operador de conjunto ::= + | - | * | = | <> | <= | >= | in
‡
- Operador de string ::= +
‡
- Operador logico ::= not | and | or
- Operador relacional ::= = | <> | < | > | <= | >=
- Operador unario ::= - | not
- Parametros actuales ::= <Parametros actuales por valor> | <Parametros actuales por variable>
- Parametros actuales por valor ::= <Expresion>
- Parametros actuales por variable ::= <Variable>
- Parametros formales ::= <Parametros formales por valor> | <Parametros formales por variable>
- Parametros formales por valor ::= <Identificador de variable>{, <Identificador de variable>} : <Identificador de tipo>
- Parametros formales por variable ::= var <Identificador de variable>{, <Identificador de variable>} : <Identificador de tipo>
- Programa ::= <Cabecera de programa><Zona de declaracion de unidades><Zona de declaraciones><Cuerpo de programa> .
- Rango de literales ::= <Literal de Tipo ordinal>
Rango de literales ::= <Literal de Tipo ordinal> .. <Literal de Tipo ordinal>
‡
Rango de literales ::= <Rango de literales>{, <Rango de literales>}
- Rango de valores ::= <Expresion de Tipo ordinal>
Rango de valores ::= <Expresion de Tipo ordinal> .. <Expresion de Tipo ordinal>
‡
Rango de valores ::= <Rango de valores>{, <Rango de valores>}
- Sentencia ::= <Sentencia de asignacion> | <Sentencia compuesta> | <Llamada a procedimiento> | <Estructura de control>
- Sentencia compuesta ::= begin <Sentencia>{; <Sentencia>} end
- Sentencia de asignacion ::= <Variable> := <Expresion>
‡
- Signo ::= | + | -
- Tipo array ::= <Identificador de tipo array>
Tipo array ::= array[ <Tipo indice>{, <Tipo indice>} ] of <Tipo de dato>
- Tipo conjunto ::= <Identificador de tipo conjunto>
Tipo conjunto ::= set of <Tipo ordinal>
‡
- Tipo de dato ::= <Tipo simple> | <Tipo estructurado>
‡
- Tipo elemental ::= <Tipo simple> | <Tipo string>
- Tipo entero ::= integer | longint
‡
- Tipo enumerado ::= <Identificador de tipo enumerado>
Tipo enumerado ::= ( <Literal tipo enumerado>{, <Literal tipo enumerado>} )
- Tipo estructurado ::= <Tipo array> | <Tipo registro> | <Tipo fichero> | <Tipo conjunto> | <Tipo string>
- Tipo fichero ::= <Identificador de tipo fichero>
Tipo fichero ::= text
Tipo fichero ::= file of <Tipo de dato>
‡
- Tipo indice ::= <Tipo ordinal>
- Tipo ordinal ::= <Tipo ordinal predefinido> | <Tipo enumerado> | <Tipo subrango>
- Tipo ordinal predefinido ::= <Tipo entero> | char | boolean
- Tipo puntero ::= <Identificador de tipo puntero>
Tipo puntero ::= ^ <Identificador de Tipo de dato>
‡
- Tipo real ::= real
‡
- Tipo registro ::= <Identificador de tipo registro>
Tipo registro ::= record <Declaracion de campos>{; <Declaracion de campos>} end
- Tipo simple ::= <Tipo ordinal> | <Tipo real> | <Tipo puntero>
- Tipo string ::= <Identificador de tipo string>
Tipo string ::= string[ <Literal de tipo entero> ]
‡
- Tipo subrango ::= <Identificador de tipo subrango>
Tipo subrango ::= <Literal de Tipo ordinal> .. <Literal de Tipo ordinal>
- Unidad ::= <Cabecera de unidad><Zona de interfaz><Zona de implementacion> end.
- Variable ::= <Identificador de variable> | <Elemento de estructura> | <Variable dinamica>
- Variable dinamica ::= <Variable de Tipo puntero> ^
‡
- Zona de declaracion de constantes ::=
Zona de declaracion de constantes ::= const <Declaracion de constante>{; <Declaracion de constante>} ;
- Zona de declaracion de interfaces ::= <Declaracion de interfaz>{; <Declaracion de interfaz>} ;
- Zona de declaracion de subprogramas ::=
Zona de declaracion de subprogramas ::= <Declaracion de subprograma>{; <Declaracion de subprograma>} ;
- Zona de declaracion de unidades ::=
Zona de declaracion de unidades ::= unit <Identificador de unidad>{, <Identificador de unidad>} ;
- Zona de declaracion de variables ::=
Zona de declaracion de variables ::= var <Declaracion de variables>{; <Declaracion de variables>} ;
‡
- Zona de declaraciones ::= <Zona de declaracion de constantes><Zona de definicion de tipos><Zona de declaracion de subprogramas><Zona de declaracion de variables>
‡
- Zona de definicion de tipos ::=
Zona de definicion de tipos ::= type <Definicion de tipo>{; <Definicion de tipo>} ;
- Zona de implementacion ::= implementation <Zona de declaracion de subprogramas>
- Zona de interfaz ::= interface <Zona de declaracion de unidades><Zona de declaracion de constantes><Zona de definicion de tipos><Zona de declaracion de interfaces>
Elementos de semántica de Pascal
case <Expresion de Tipo ordinal> of <Caso>{; <Caso>} else <Sentencia> end
Este tipo de estructura tiene las siguientes características:
- La expresión se evalúa una única vez, antes de
comenzar la estructura
- Los casos deben ser excluyentes entre sí, y por lo tanto no es posible
que un valor pertenezca a más de un caso.
- Cuando se ejecuta la sentencia asociada a un caso, la estructura termina.
- La sentencia asociada a la parte opcional else sólo se
ejecuta si el resultado de la expresión no pertenece a ningún
caso. En esta última situación, si no existiera la parte else,
la estructura terminaría sin ejecutar ninguna sentencia.
for <Variable de control del bucle> := <Expresion 1> to <Expresion 2> do <Sentencia>
Este tipo de estructura tiene las siguientes características:
- La variable de control del bucle no puede ser modificada en la(s)
sentencia(s) que forman parte del bucle.
- Las expresiones 1 y 2 se evaluan una única vez, antes de comenzar
el bucle.
- Los resultados de las expresiones 1 y 2 deben garantizar como mínimo
una ejecución del bucle. En concreto, el valor de la expresión 1
debe ser menor o igual que el de la expresión 2 en un bucle to, y
mayor o igual en un bucle downto.
- La variable de control del bucle toma todos los valores comprendidos
entre entre el valor inicial (el resultado de la evaluacion de la expresion 1)
y el valor final (el resultado de la evaluacion de la expresion 2), ambos
inclusive.
- Tras la ejecución del bucle, el valor almacenado en la variable
de control del bucle es desconocido.
- Si N1 y N2 representan los resultados de la
evaluación de las expresiones 1 y 2, respectivamente, entonces el
bucle se repite (N2 - N1 + 1) veces en el caso de un
bucle to, y (N1 - N2 + 1) veces en el caso de
un bucle downto.
El valor false tiene asociado un valor ordinal de 0, y el valor
true un valor ordinal de 1. Al comparar valores de tipo boolean se
cumple que false < true.
La notación #<Número> representa al carácter
que se encuentra en esa posición de la tabla de caracteres. Es equivalente,
por tanto, a chr(Número).
Comparar caracteres es comparar las posiciones que ocupan en la tabla de
caracteres del sistema. No existe (todavía) una tabla de caracteres
universal, por lo que sólo podemos suponer las siguientes características,
comunes a la mayoria de tablas existentes:
- Los caracteres correspondientes a dígitos se encuentran antes
que los correspondientes a letras mayúsculas, que a su vez son
anteriores a las letras minúsculas. Cuando se habla de letras se
debe entender que nos referimos al alfabeto anglosajón, y por lo
tanto no se incluyen la letra eñe, las vocales acentuadas, ni otros
símbolos particulares de nuestro alfabeto.
- Los grupos de caracteres 0..9, A..Z, a..z ocupan posiciones consecutivas,
y siguen el orden alfabetico normal. Nota: Los grupos generalmente no
son consecutivos, es decir al carácter 9 no le sigue el caráter A.
El literal nil es compatible con todos los tipos puntero. Como la
dirección representada por nil no puede corresponder a la
de ninguna variable dinámica, asignar a un puntero este valor sirve
para indicar que el puntero no almacena una dirección válida.
Los tipos enteros sirven para representar valores numéricos sin
parte decimal. Tienen una limitación de rango, es decir sólo
pueden representar valores dentro de unos límites determinados.
Si alguna operación aritmetica produce un valor fuera de esos limites,
se produce un error de desbordamiento. Los límites, para la
versión de Turbo-Pascal que utilizamos, son:
- Tipo integer: -(Maxint+1) .. Maxint
- Tipo longint: -231 .. (231-1)
Maxint es una constante predefinida que indica el valor máximo
que se puede representar en un valor de tipo integer.
Nota: Maxint = 215-1 = 32.767, 231 = 2.147.483.648. Los
valores se codifican internamente en complemento a dos.
Los operadores aritmeticos enteros operan sobre valores de tipo integer y
longint. Si un operando es de tipo integer y el otro de
tipo longint, el operando de tipo integer se convierte
automáticamente a un valor de tipo longint y se pasa a calcular
el resultado, que será de tipo longint.
En el caso de los operadores cociente (div) y resto (mod),
se cumplen las siguientes relaciones: Dados c := a div b,
r := a mod b, se tiene que:
- (1) a = c*b + r
- (2) |r| < |b|
- (3) |c| = |a| div |b|
- (4) |r| = |a| mod |b|
Las ecuaciones (3) y (4) indican que cuando el dividendo y/o el divisor
son negativos, los valores absolutos del cociente y el resto proporcionados son
iguales a los obtenidos cuando el dividendo y el divisor son positivos, y los
signos del cociente y el resto se eligen de manera que se cumpla la ecuación
(1).
Los tipos reales sirven para representar valores numéricos con
parte decimal. La representación de valores tiene las siguientes
limitaciones:
- El desbordamiento superior sucede cuando el valor a representar
es mayor, en terminos absolutos (sin tener en cuenta el signo), que el valor
máximo representable. En Turbo-Pascal este máximo vale
aproximadamente 1,7*1038. Cualquier operación en la que
se obtenga un resultado absoluto mayor da un error.
- El desbordamiento inferior sucede cuando el valor a representar
esta más cerca de cero que un determinado límite.
En Turbo-Pascal este límite vale aproximadamente 2,9*10-38.
Cualquier operación en la que se obtenga un resultado absoluto menor
da como resultado cero (no se produce error).
- La perdida de precisión sucede cuando se necesita representar
un valor con más dígitos significativos (precisión) de la
que es capaz el método de codificación. En Turbo-Pascal los
valores de tipo real almacenan los 11 dígitos decimales más
significativos (es decir, sin tener en cuenta los ceros iniciales y/o finales).
Esta última limitación indica que, salvo casos especiales,
los valores de tipo real no son una representación exacta del valor
real, sino tan solo una aproximación. Por lo tanto, es necesario
evitar en lo posible comparaciones de igualdad y desigualdad con valores de
tipo real, ya que pueden dar lugar a resultados inesperados. Por ejemplo,
la comparación 3*(1/3) = 1.0 da como resultado false.
Los operadores suma, resta y multiplicación proporcionan un
resultado de tipo real cuando alguno de sus operandos es de ese tipo.
Si un operando es de tipo integer o longint, se convierte
automáticamente a un valor de tipo real y se pasa a calcular
el resultado.
El operador de división (/), sin embargo, proporciona siempre
un resultado de tipo real, incluso cuando ambos operandos son enteros
y la división tiene un resultado exacto.
En la siguiente tabla se muestran los operadores de conjuntos, el
tipo de sus argumentos y de su resultado:
Operador |
Significado |
Operando 1 |
Operando 2 |
Resultado |
+ |
Unión |
Conjunto tipo base T1 |
Conjunto tipo base T2 |
Conjunto tipo base T3 |
* |
Intersección |
Conjunto tipo base T1 |
Conjunto tipo base T2 |
Conjunto tipo base T3 |
- |
Diferencia |
Conjunto tipo base T1 |
Conjunto tipo base T2 |
Conjunto tipo base T3 |
= |
Igualdad |
Conjunto tipo base T1 |
Conjunto tipo base T2 |
Boolean |
<> |
Desigualdad |
Conjunto tipo base T1 |
Conjunto tipo base T2 |
Boolean |
<= |
Subconjunto de |
Conjunto tipo base T1 |
Conjunto tipo base T2 |
Boolean |
in |
Pertenencia |
Valor de tipo T1 |
Conjunto tipo base T2 |
Boolean |
Los tipos de datos T1 y T2 deben cumplir alguna
de las siguientes condiciones:
- Ser el mismo tipo. En este caso el tipo T3 será el mismo
que T1 y T2.
- Que T1 sea un subrango de T2. El tipo resultado
T3 será igual a T2.
- Que T2 sea un subrango de T1. El tipo resultado
T3 será igual a T1.
- Que T1 y T2 sean subrangos del mismo tipo,
posiblemente con límites distintos. En este caso T3 será
el menor subrango cuyos límites incluyen a los de T1 y
T2. Por ejemplo, si T1 = 1..5 y T2 =
4..10, T3 sería 1..10.
El operador de concatenación de cadenas de caracteres (+) tiene la
siguiente sintaxis:
<Expresión de tipo T1> + <Expresión de tipo T2>
Los tipos de datos T1 y T2 pueden ser cualquier tipo
string (independientemente de su número máximo de caracteres) o
char. El resultado es un valor de tipo string[n], donde
n es el tamaño mínimo del string que puede almacenar la
cadena resultante.
En Turbo-Pascal, si la cadena resultante tiene más
de 255 caracteres, no se tienen en cuenta aquellos situados tras la posición
255.
La definición de un rango de valores se utiliza en la sentencia
case (los límites son literales) y en el constructor de
conjuntos (los limites son expresiones). Suponiendo la siguiente
definición común a ambos casos:
<Valor N1>..<Valor N2>
Se deben cumplir las siguientes condiciones:
- N1 debe ser del mismo tipo que N2.
- N1 debe ser menor o igual que N2.
- En Turbo-Pascal, en el caso de construcción de conjuntos, se
tiene la limitación de que los valores no pueden ser negativos.
Nota: Los valores N1 y N2 pertenecen al
rango resultante.
<Variable de tipo T1> := <Expresión de tipo T2>
La ejecución de una sentencia de asignación comprende los
siguientes pasos:
- Se evalua la expresión, obteniendose, si no se producen errores,
un valor de tipo T2. (Para mas detalles, ver
Evaluación de expresiones)
- Se comprueba que es posible asignar a la variable de tipo T1
un valor de tipo T2. Para que sea posible, el valor de tipo
T2 debe estar dentro del rango de valores del tipo T1,
y se debe cumplir alguna de las siguientes condiciones:
- T1 y T2 son el mismo tipo, el cual no es
fichero o un tipo estructurado donde algun elemento sea de tipo fichero.
- T1 es longint y T2 es integer.
- T1 es real y T2 es integer o longint.
- T1 y T2 son cadena de caracteres.
- T1 es cadena de caracteres y T2 es char.
- T1 y T2 son conjuntos cuyos tipos base son compatibles.
- T1 es puntero y el resultado de la expresión es el valor nil.
- Se asigna el valor a la variable.
Para ampliar información, vease Tipos de
datos compatibles.
Todos los tipos de datos son compatibles consigo mismos. Dos tipos
distintos son compatibles entre sí cuando cumplen alguna de
las siguientes condiciones:
- Un tipo es integer y el otro longint.
- Un tipo es un subrango del otro.
- Ambos son subrangos del mismo tipo.
- Ambos son conjuntos cuyos tipos base son compatibles entre sí.
- Ambos son cadenas de caracteres (string).
- Un tipo es cadena de caracteres y el otro es char.
El orden de evaluación de los elementos de una expresión
sigue las siguientes normas:
- Cualquier elemento encerrado entre paréntesis se
evalúa primero.
- Si la expresión es una llamada a función, se evaluan
los parámetros actuales por valor, se asignan esos valores a las
variables parámetros formales de la función, se ejecuta
la funcíon y la expresión se resuelve con el ultimo
valor asignado a la variable asociada a la función.
- Si en la expresión aparecen varios operadores, se ejecuta
primero el operador con mayor precedencia.
En el caso de operadores con la misma precedencia, se ejecuta primero
el operador situado más a la izquierda en la expresión.
Para que una expresión pueda evaluarse se deben dar las siguientes
condiciones:
- En el caso de operadores, los operandos deben ser del tipo requerido y/o
cumplir las reglas de compatibilidad entre tipos.
- En el caso de llamadas a funciones, el tipo de los parametros actuales
(valores que se envián) deben ser compatibles
según las normas de la asignación con el tipo de los
parámetros formales (variables de la función que reciben
los valores).
- No se produzcan problemas de desbordamiento
u operaciones no permitidas (dividir por cero, por ejemplo).
Nota: En el caso de parámetros por variable, el tipo de datos
de la variable parámetro actual y el tipo de datos de la variable
parámetro formal debe ser exactamente el mismo.
Los niveles de precedencia de los operadores de Pascal son los
siguientes:
Nivel |
Tipo de operador |
Operadores |
4 |
Operadores unarios |
not, - |
3 |
Operadores multiplicativos |
*, /, div, mod, and |
2 |
Operadores aditivos |
+, -, or |
1 |
Operadores relacionales |
=, <>, <, >, <=, >=, in |
El tipo de datos conjunto tiene las siguientes características
especiales:
- El tipo base debe ser un ordinal, y en Turbo-Pascal existe la limitación
de que su cardinalidad (número de valores distintos que pertenecen al tipo)
debe ser menor de 256, y en el caso de tipos base numéricos no están
permitidos los valores negativos.
- Existen literales de tipo conjunto (ver
Literal de tipo conjunto).
- Existen operadores que se aplican a conjuntos (ver
Operadores de conjuntos).
- Son compatibles los valores conjunto cuyo tipo base sea compatible,
aunque su definición de tipo sea distinta.
- A diferencia del resto de tipos estructurados, los conjuntos no
almacenan valores del tipo base, sino la información sobre si un
valor, en un momento determinado, pertenece o no al conjunto.
El tipo de datos cadena de caracteres (string) es una especialización
basada en los arrays unidimensionales de caracteres a la que se añade
funcionalidad para facilitar la representación de texto. Entre sus
características especiales destacan:
- Comparte las características de un array de caracteres indexado
desde 1 hasta el tamaño máximo indicado en su definición.
- No todos los elementos (caracteres) de un string se considera
que forman parte de la cadena de caracteres en un momento dado: Sólamente
aquellos cuyo índice esté comprendido entre 1 y la longitud actual del string. La
información referente a la longitud se obtiene mediante la función
predefinida length, y no puede cambiarse directamente, sino que se
adapta automaticamente en las operaciones de asignación entre cadenas
de caracteres y al usar los operadores, funciones y procedimientos predefinidos
que actuan sobre cadenas de caracteres.
- Sólo puede accederse, en un momento dado, a aquellos elementos
(caracteres) de un string cuyo índice se encuentre comprendido entre
1 y la longitud actual del string (es decir, a aquellos caracteres que
forman parte de la cadena). Se debe tener en cuenta, además, que
una cadena de caracteres puede estar vacía (su longitud sea igual a cero).
- Existen literales de tipo cadena de caracteres.
- Se pueden definir funciones que devuelvan un valor de tipo cadena de
caracteres.
- Existen operadores, funciones y procedimientos predefinidos que se aplican
a cadenas de caracteres (ver Operadores de string
y Subprogramas predefinidos que se aplican a string).
- Se pueden leer y escribir directamente en dispositivos de tipo texto.
- En la versión de Turbo-Pascal que estamos usando no se pueden
definir tipos string cuyo tamaño máximo supere los 255
caracteres.
Los ficheros, al representar datos externos al programa y tener
un acceso secuencial, tienen un tratamiento distinto al de los otros
tipos estructurados. Algunas de esas características especiales son:
Definición de ficheros:
- Las variables tipo fichero (denominadas ficheros lógicos,
en contraposición con los ficheros físicos, los
ficheros reales) no almacenan los datos del fichero, sino que sirven de
intermediario para poder acceder a un determinado fichero físico.
- El tipo base de un fichero no puede ser a su vez un tipo fichero,
puesto que no tiene sentido almacenar ficheros lógicos.
- No se puede asignar a una variable tipo fichero el contenido de
otra variable tipo fichero. No tiene sentido el tener dos variables
con la misma información de acceso a un fichero físico.
Consecuentemente, tampoco es posible que varias variables tipo fichero tengan
asignado y abierto, simultaneamente, el mismo fichero físico.
- Debido a lo anterior, al pasar un fichero como parámetro a
un subprograma siempre es necesario hacerlo por variable (un paso
por valor es equivalente a una asignación).
Uso de ficheros:
- El acceso a los datos de un fichero se debe hacer mediante
una serie fija de etapas (asignación de un fichero físico a un
fichero lógico, apertura del fichero para lectura o creación-escritura,
comprobación de fin de fichero-lectura de datos o
escritura de datos, y cierre del fichero) que requieren
la utilizacion de subprogramas predefinidos para
acceso a ficheros.
- Un fichero sólo se puede abrir o bien para lectura
o bien para creación-escritura. No se puede leer y escribir
simultaneamente en un fichero.
- Abrir un fichero para escritura supone crear un fichero físico
nuevo y vacío. Si previamente existía un fichero físico
con el mismo nombre, los datos que contenía se pierden al abrirlo
para escritura. Por lo tanto no es posible añadir datos nuevos
al final de un fichero abriendolo para escritura, es necesario usar otros
medios (usar ficheros auxiliares, por ejemplo).
- No es posible conocer anticipadamente el número de elementos
de un fichero físico. Por lo tanto, antes de cualquier lectura de
un dato es necesario haber comprobado que realmente quedan datos por leer
en el fichero (mediante la fúncion eof).
- Cualquier fichero puede estar vacío, por lo tanto no es posible
aplicar directamente tecnicas de lectura adelantada sobre ficheros.
- Cualquier modificación del contenido de un fichero físico
requiere la utilización de ficheros auxiliares.
La tabla siguiente muestra características de los tipos de datos
predefinidos de Turbo-Pascal:
Tipo de dato |
Simple |
Ordinal |
Elemental |
Imprimible |
Literales |
Acceso |
Entero |
Si |
Si |
Si |
Si |
Si |
- |
Real |
Si |
No |
Si |
Si |
Si |
- |
Carácter |
Si |
Si |
Si |
Si |
Si |
- |
Lógico |
Si |
Si |
Si |
No |
Si |
- |
Enumerado |
Si |
Si |
Si |
No |
Si |
- |
Subrango |
Si |
Si |
Si |
(1) |
Si |
- |
Puntero |
Si |
No |
Si |
No |
No |
- |
Array |
No |
No |
No |
No |
No |
Por índice |
Registro |
No |
No |
No |
No |
No |
Por campo |
Fichero |
No |
No |
No |
No |
No |
Secuencial |
Conjunto |
No |
No |
No |
No |
Si |
(2) |
String |
No |
No |
Si |
Si |
Si |
Por índice |
- Igual que el tipo de datos del que es subrango.
- Un conjunto tan solo permite preguntar si un valor pertenece o no
en un momento dado al conjunto.
Significado de las columnas:
- Elemental: Se pueden definir funciones que devuelvan este
tipo de datos.
- Imprimible: Se puede leer o escribir valores de este
tipo de datos directamente en dispositivos de tipo texto (usando
read, readln, write o writeln).
- Literales: Se pueden especificar directamente valores de
este tipo de datos.
- Acceso: Para tipos estructurados, la estrategia de acceso
a sus elementos.
A la hora de trabajar con variables dinámicas es necesario
asegurarse de que la dirección almacenada en la variable puntero
corresponde realmente a la de una variable dinámica, puesto que
Pascal no verifica que sea así: Si usamos una dirección
incorrecta, podemos inadvertidamente estar cambiando el valor de otras variables
dinámicas, estáticas o incluso el propio código de
nuestro programa o el de cualquier otro que se esté ejecutando en
el ordenador.
Para que esto no ocurra, es necesario asegurarse de que al puntero
usado para acceder a la variable dinámica le ha sido asignado una
dirección válida mediante una llamada al procedimiento new o
por una asignación de un puntero que almacenaba una dirección
válida.
Tras la llamada al procedimiento dispose, la dirección
que almacena el puntero proporcionado deja de ser válida (la memoria
que ocupaba la variable dinámica situada en esa dirección
se libera y pasa a estar disponible para otros usos).
La definición de un tipo puntero tiene dos partes diferenciadas:
Tipo puntero ::= ^ <Tipo de dato asociado>
- El acento circumflejo (^) significa que las variables de este tipo de
datos son punteros, y por lo tanto almacenarán direcciones de memoria.
- El tipo de datos asociado no tiene nada que ver el
tipo puntero que se esta definiendo: Tan sólo sirve para indicar
el tipo de datos que almacenaría una hipotetica variable dinámica
cuya dirección estuviera almacenada en una variable de este tipo puntero.
Las variables de tipo puntero almacenan direcciones de memoria. No
es necesario que conozcamos qué es exactamente una dirección de
memoria, sino tan solo que mediante esos valores es posible hacer referencia
a variables dinámicas.
La dirección almacenada en un puntero puede ser, en un momento dado,
válida o no válida. Es válida cuando
represente la dirección de una variable dinámica existente.
Una variable dinámica existe cuando ha sido creada
mediante una llamada al procedimiento new, y todavia no ha sido
destruida mediante una llamada al procedimiento dispose.
Es necesario tener en cuenta que los valores de tipo puntero son un
mero intermediario para permitir el trabajar con variables dinámicas,
y que no guardan más relación con ellas que las de almacenar
su dirección.
Turbo-Pascal permite que escribamos las zonas de declaraciones en
cualquier orden, e incluso repitamos zonas en sitios distintos. Para los
programas desarrollados en el marco de la asignatura se va a imponer, sin embargo,
la siguiente restricción: Sólo debe existir una zona de
declaración de variables y debe estar situada despues de
cualquier declaración de subprogramas.
De esta forma se garantiza que ningún subprograma puede hacer uso
de variables globales a él, cumpliendo la regla de la programación
modular que establece que los módulos deben ser independientes
(respecto a los datos que manejan) entre sí.
Operaciones matemáticas:
Subprograma |
Tipo |
Parámetros |
Resultado |
abs(x) |
Función |
x de tipo entero o real |
El valor absoluto de x |
odd(x) |
Función |
x de tipo entero |
true si x es impar, false si es par |
random(x) |
Función |
x de tipo entero |
Un entero entre 0 y x - 1, escogido al azar |
sin(x) |
Función |
x de tipo real |
El seno de x (x son radianes) |
cos(x) |
Función |
x de tipo real |
El coseno de x (x son radianes) |
arctan(x) |
Función |
x de tipo real |
El arcotangente de x, expresado en radianes |
ln(x) |
Función |
x de tipo real |
El logaritmo neperiano de x |
exp(x) |
Función |
x de tipo real |
La exponencial de x (ex) |
Operaciones de conversión entre tipos:
Subprograma |
Tipo |
Parámetros |
Resultado |
chr(x) |
Función |
x de tipo entero |
El carácter en la posición x de la tabla de caracteres |
trunc(x) |
Función |
x de tipo real |
La parte entera de x |
round(x) |
Función |
x de tipo real |
El valor entero más cercano a x |
Operaciones ordinales:
Subprograma |
Tipo |
Parámetros |
Resultado |
ord(x) |
Función |
x de tipo ordinal |
La posición del valor x en su tipo de datos (1) |
succ(x) |
Función |
x de tipo ordinal |
El valor siguiente de su mismo tipo |
pred(x) |
Función |
x de tipo ordinal |
El valor anterior de su mismo tipo |
(1) En el caso de argumentos enteros, ord devuelve su mismo valor. En
el resto de casos, devuelve la posición del valor comenzando a contar por
cero. Nota: La función ord no tiene en cuenta si el argumento
proviene o no de una variable de tipo subrango.
Subprograma |
Tipo |
Parámetros |
Resultado |
length(c) |
Función |
c valor de tipo string |
Longitud de la cadena |
copy(c,i,n) |
Función |
c valor de tipo string i,n de tipo entero |
La subcadena de c que comienza a partir de la posición i y tiene longitud n |
insert(s,c,i) |
Procedimiento |
s valor de tipo string c variable de tipo string i de tipo entero |
Inserta la subcadena s en la cadena c a partir de la posición i |
delete(c,i,n) |
Procedimiento |
c variable de tipo string i,n de tipo entero |
Elimina de c la subcadena que comienza a partir de la posición i y tiene longitud n |
pos(s,c) |
Función |
s, c valor de tipo string |
La primera posición de c donde aparece la subcadena s, o cero si no aparece |
Subprograma |
Tipo |
Parámetros |
Resultado |
assign(f,c) |
Procedimiento |
f de tipo fichero c de tipo string |
Asigna un fichero físico a un fichero lógico |
reset(f) |
Procedimiento |
f de tipo fichero |
Abre un fichero para lectura |
rewrite(f) |
Procedimiento |
f de tipo fichero |
Abre un fichero para creación-escritura |
eof(f) |
Función |
f de tipo fichero de datos |
false si quedan datos por leer true si no quedan datos por leer |
eof(f) |
Función |
f de tipo fichero de texto |
false si quedan lineas true si no quedan lineas |
eoln(f) |
Función |
f de tipo fichero de texto |
false si quedan caracteres en la linea actual true si no quedan caracteres en la linea actual |
read(f,v) |
Procedimiento |
f de tipo fichero de datos v variable de tipo base |
Lee un dato del fichero y lo asigna a la variable |
read(f,v) |
Procedimiento |
f de tipo fichero de texto v variable de tipo imprimible |
Lee caracteres, los traduce a un valor del tipo de la variable y se lo asigna |
readln(f,v) |
Procedimiento |
f de tipo fichero de texto v variable de tipo imprimible |
Igual que read, y además pasa a la siguiente linea ignorando los caracteres que quedan en la linea actual |
readln(f) |
Procedimiento |
f de tipo fichero de texto |
Pasa a la siguiente linea ignorando los caracteres que quedan en la linea actual |
write(f,v) |
Procedimiento |
f de tipo fichero de datos v variable de tipo base |
Escribe en el fichero el dato almacenado en la variable |
write(f,e) |
Procedimiento |
f de tipo fichero de texto e expresión de tipo imprimible |
Traduce el valor resultante de la expresión a una secuencia de caracteres y la escribe en el fichero |
writeln(f,e) |
Procedimiento |
f de tipo fichero de texto e expresión de tipo imprimible |
Igual que write, y además escribe los caracteres que indican el final de linea |
writeln(f) |
Procedimiento |
f de tipo fichero de texto |
Escribe los caracteres que indican el final de linea |
close(f) |
Procedimiento |
f de tipo fichero |
Cierra un fichero |