Loro - Un Sistema de Programación Didáctico
Especificación del lenguaje
Versión 0.9.2 – noviembre
25 de 2002
Carlos A. Rueda
Loro es un
lenguaje de programación de carácter didáctico con revisión estricta de tipos y
reciclaje automático de memoria. Su soporte central es el diseño por contrato
aplicado a la programación tanto imperativa como orientada a objetos. Este
documento ofrece una definición descriptiva del lenguaje. Se asumen conocimientos
previos de algún lenguaje de programación como Java o C++. Aunque no se utiliza
un estilo estrictamente formal,
tampoco se trata de un documento dirigido al lector principiante en
programación.
Siendo parte
integral de un proyecto abierto y en desarrollo, esta especificación no debe
tomarse como definitiva. De hecho, el
lenguaje está abierto a los ajustes que sean pertinentes para atender, hasta
donde sea posible, las diferentes propuestas y revisiones que vayan surgiendo. Para
obtener información actualizada al respecto, favor visitar la página del
proyecto.
El apéndice (7.13) explica la notación utilizada e incluye la gramática
concreta del lenguaje.
En general, el
conjunto de caracteres de Loro es el conjunto Unicode. Las letras mayúsculas y
minúsculas se toman como distintas en el lenguaje.
El espacio
simple, tabulador, y el cambio de línea corresponden a los espacios en
blanco (espacios, para abreviar) cuya función es la de decidir la
separación de los componentes léxicos (1.1.3) del lenguaje. Por lo menos un espacio es necesario
para separar dos palabras clave o identificadores adyacentes, o entre una
palabra clave o identificador y un número, pero no se requiere entre un número
y una palabra clave dado que esto no representa ninguna ambigüedad. Los
delimitadores y operadores no requieren espacios para separarlos de sus
elementos adyacentes a ambos lados. Excepto en literales cadena, ningún
componente léxico contiene espacios en blanco.
Un comentario es
cualquier texto (secuencia de caracteres) delimitado según dos posibilidades:
Los comentarios
pueden aparecer en cualquier punto en donde pueda venir un componente léxico y
no requieren espacios en blanco a ningún lado para delimitarse. Estos comentarios
son ignorados completamente durante compilación.
Los componentes
léxicos son las palabras clave, constantes literales, identificadores,
operadores y delimitadores.
Las palabras claves del lenguaje se muestran a continuación (nótese que las versiones sin tilde también están reservadas):
|
booleano |
cadena |
caracter |
entero |
|
real |
algoritmo |
bajando |
caso |
|
ciclo |
cierto |
clase |
constante |
|
constructor |
continúe |
crear |
desde |
|
descripción |
en (*) |
entonces |
entrada |
|
es_instancia_de |
especificación |
éste
(*) |
estrategia |
|
existe |
extiende |
falso |
fin |
|
global
(*) |
haga |
hasta |
implementación |
|
inicio |
implementa
(*) |
interface
(*) |
mientras |
|
nada |
nulo |
paquete |
para |
|
para_todo |
paso |
pos |
pre |
|
repita |
retorne |
salida |
según |
|
si |
si_no |
si_no_si |
súper
(*) |
|
termine |
utiliza |
como |
operación
(*) |
|
método
(*) |
objeto |
implementa |
lance |
|
intente |
atrape |
siempre |
|
(*) No usados aún.
Las constantes
literales pueden ser números enteros, números reales, constantes booleanas,
caracteres, cadenas y el literal nulo.
·
Un texto
de documentación es similar a una cadena literal excepto que se encierra en
pares de comillas sencillas (’’).
Como su nombre lo indica, estas cadenas son utilizadas para documentar diversos
elementos en un programa.
·
Un texto
de implementación es similar a una cadena literal excepto que se encierra
entre los símbolos {% y %}.
Estas cadenas se utilizan para indicar lenguajes diferentes a Loro en la
codificación de algoritmos. (8)
Las siguientes
secuencias de escape permiten indicar caracteres especiales dentro de los
literales caracter y cadena:
|
Secuencia |
Descripción |
|
\n |
cambio de línea |
|
\r |
retroceso a
inicio de línea |
|
\t |
Tabulador |
|
\b |
Retroceso |
|
\f |
cambio de
página |
|
\\ |
diagonal
invertida |
|
\’ |
comilla
sencilla |
|
\” |
comilla doble |
|
\ddd |
caracter octal
(cada d es un dígito octal) |
|
\udddd |
caracter
Unicode (cada d es un dígito hexadecimal) |
Un identificador es
una secuencia de letras y posiblemente dígitos comenzando con una letra,
excluyendo las palabras clave (1.1.3.1). Por letra se entiende cualquiera de los caracteres
Unicode correspondientes a letra, y también los caracteres $ y _ (“subguión”).
No hay una longitud límite preestablecida para los identificadores. Un
identificador también puede finalizarse con una o más comillas simples, en cuyo
caso se interpreta como una variable semántica (3.2.1).
Los operadores
denotados con símbolos (no palabras clave) son los siguientes:
|
:= |
?: |
<=> |
=> |
|
|| |
&& |
| |
^ |
|
& |
= |
!= |
< |
|
> |
<= |
>= |
<< |
|
>> |
>>> |
+ |
- |
|
* |
/ |
% |
! |
|
~ |
# |
@ |
|
Los siguientes son componentes léxicos (no palabras clave) utilizados como delimitadores.
|
: |
; |
, |
. |
|
( |
) |
[ |
] |
|
{ |
} |
-> |
|
Un documento fuente (fuente,
para abreviar) se refiere al conjunto de elementos (especificaciones,
algoritmos, clases) (5) que pueden aparecer dentro de un programa fuente
sometido a compilación. En este documento se utiliza el término unidad de
compilación para cada uno de tales elementos.[1]
Un documento fuente tiene el siguiente esquema:
[ paquete ]
( utiliza )*
( especificación | algoritmo | clase )+
Las unidades
quedarán asociadas al paquete indicado si aparece, o bien al paquete anónimo
si no se indica explícitamente un paquete (2.1). La sintaxis para indicar el paquete correspondiente
es:
paquete id ( :: id )*
;
Todas las
unidades del mismo paquete tienen accesibilidad inmediata entre sí. Unidades en
otros paquetes deben referenciarse incluyendo el
nombre de sus paquetes correspondientes. Los elementos utiliza dan una facilidad para abreviar la referencia a unidades ubicadas
en otros paquetes. La sintaxis general es:
utiliza ( especificación | algoritmo | clase ) id ( :: id
)* ;
En Loro, como en
otros lenguajes, se utiliza un mecanismo de paquetes para establecer espacios de nombres para las unidades
compiladas. En este sentido, cada unidad “reside” lógicamente en un cierto
paquete. Salvo por el paquete anónimo (que
no tiene un nombre explícito), todo paquete se identifica con un nombre
particular. La sintaxis para un nombre de paquete es:
id ( :: id )*
es decir, una lista de identificadores
simples separados por “::”. El nombre completo de una cierta unidad
se establece indicando el nombre del paquete en que reside, el separador (“::”) y el nombre de
la unidad como tal. Cada tipo de unidad establece un espacio de nombres
diferente. Por esta razón, los elementos utiliza, dentro de un documento fuente, incluyen la indicación del tipo
de unidad correspondiente.
Todos los
identificadores que aparezcan en una unidad de compilación (5) tienen que introducirse mediante declaraciones
correspondientes. Una declaración puede ser explícita o implícita.
En esta categoría están las definiciones de
unidades, las declaraciones de
variables y las etiquetas.
La definición de
una unidad (5) establece una declaración explícita para el nombre
correspondiente. En el caso de clases y algoritmos, la vigencia de este nombre
comienza justo a continuación del encabezado principal correspondiente con el
fin de permitir la recursión. Esto no aplica para las especificaciones.
Para permitir la
recursión mutua (y también por conveniencia), es posible utilizar un
identificador para referir a una unidad (es decir, especificación, algoritmo o
clase) que se define más adelante dentro de un mismo fuente. (Una
implementación podría extender esta facilidad para abarcar múltiples fuentes.)
Una variable
siempre tiene que declararse explícitamente y antes de cualquier uso. Toda declaración
de variable involucra una asociación de un tipo de dato (4) para el identificador de la variable, y también una
descripción verbal. Las declaraciones de variables siempre tienen una vigencia
local dentro del ámbito en que se hace la declaración. Esta vigencia
comienza justo a continuación de la declaración y va hasta el final del ámbito
en que se hace la declaración. El ámbito está determinado por cada construcción
que permita declaraciones de variables como se explica en otras partes de este
documento. Dentro de este ámbito no puede declararse otra variable con el mismo
nombre.
Una etiqueta es un
identificador para una acción de iteración (6.3). Se declaran a través de la sintaxis correspondiente
a cada caso de iteración con la forma básica:
/ id
/
Las acciones termine (6.5) y continúe (6.6), que operan sobre iteraciones, pueden cualificarse
agregando el identificador de la iteración sobre la que deben actuar. Por
defecto, estas acciones actúan sobre la iteración más inmediata. A través del
mecanismo de las etiquetas se hace posible que actúen sobre una iteración no
inmediata en un anidamiento de iteraciones.
No se permite que dos iteraciones
anidadas (una dentro del cuerpo de acciones de la otra) tengan la misma
etiqueta.
Ciertos identificadores son introducidos a través de declaraciones implícitas. En este caso se encuentran las variables semánticas y ciertos atributos para arreglos y cadenas.
Una variable semántica (o lógica) representa un
cierto valor fijo en un momento dado dentro de la ejecución de un programa.
Este mecanismo, que permite capturar el valor que tiene una
expresión en un momento dado, puede utilizarse para relacionar valores antes
y después de un cierto fragmento de código, lo que es particularmente
útil en la escritura de pre y poscondiciones.
Este valor fijo puede corresponder también a una función
matemática que, o bien no se quiere expresar, o bien no se puede expresar
utilizando la semántica del mismo lenguaje. Por ejemplo, la función matemática
que toma un argumento entero positivo n y produce el n-ésimo número primo podría representarse con una variable semántica.
Una variable semántica sólo puede aparecer dentro del contexto de
las afirmaciones (6.7) y no requiere declaración explícita previa como las
otras variables regulares del lenguaje. Para dar soporte adecuado a esto, la primera
aparición de una variable lógica debe ser en una expresión de igualdad: expresión = x’. Para efectos de
compilación, el tipo de x’ se deduce de manera
automática puesto que toma exactamente el tipo de la expresión. En ejecución,
el valor de x’ será el que resulte de
la evaluación de la expresión. En consecuencia, la expresión no puede contener
variables semánticas que no hayan sido definidas previamente (en particular, si
tanto x' como y' son variables sin definir previamente,
entonces la expresión x' = y' será
inválida).
Nótese que la expresión booleana exp1 = x’,
para introducir la variable semántica x’, captura la noción de que existe un valor
x’ tal que la expresión
dada exp1 es igual a x’; por lo tanto, siempre se evaluará con
resultado cierto. Complementariamente, si x’
ya se encuentra definida previamente, entonces exp2 = x’
podrá resultar en cierto o en falso dependiendo de si los valores
correspondientes son iguales en el momento de la evaluación.
En el caso de arreglos y cadenas,
los siguientes identificadores se declaran implícitamente para denotar
atributos:
|
Identificador |
Tipo |
Descripción |
|
inf |
entero |
Límite inferior en rango de indización |
|
sup |
entero |
Límite superior en rango de indización |
|
longitud |
entero |
Tamaño total del arreglo o cadena |
Si x es un arreglo o cadena,
siempre se cumple que x.longitud = x.sup – x.inf
+ 1. Ver 7.6 y 7.10.
Loro ofrece los
siguientes tipos de datos: