miércoles, 2 de noviembre de 2016

Programación del Sinclair QL (II): Formas estructuradas de intrucciones básicas

Añadido el 30/06/24 ampliaciones y mejoras

Añadido el 19/07/24 ampliación del On Select


Arreglos, mas conocidos como arrays, vectores o matrices

Como ingeniero informático llamaré a las cosas por su nombre. Array es una palabra inglesa que no existe en Español, en su lugar hay que usar la palabra arreglo. Se llama vector a un arreglo de una dimensión, y matriz a un arreglo de dos dimensiones, estos nombres se usan por similitud con las estructuras matemáticas del mismo nombre, pero el nombre que debemos usar debe ser arreglo unidimensional o arreglo bidimensional.


SuperBASIC admite arreglos de una y de dos dimensiones, pero con varias diferencia sobre los del  BASIC estándar.

En superBASIC es posible usar mas de dos dimensiones, no hay más límite que la memoria total disponible, pero en mi larga vida de programador muy pocas veces he usado arreglos de 3 dimensiones (solo recuerdo un caso), podemos pensar que esto se refiere a una colección de matrices, como sería por ejemplo una hoja de cálculo con un conjunto de hojas con sus filas y columnas. Usar mas de 3 es muy complicado de imaginar siquiera su uso, y personalmente nunca lo he necesitado, aunque yo me dedico profesionalmente a la gestión empresarial, quizá en la rama científica sea más factible usarlo.

En un arreglo numérico se incluye siempre el elemento cero, pero por compatibilidad se mantiene que el número sea el máximo elemento del arreglo, de forma que cuando se define un arreglo de 10 elementos estos van del 0 al 10, y no del 1 al 10 como en BASIC estándar, o del 0 al 9 como en C.


Los arreglos de caracteres son siempre de elementos de un solo carácter con la longitud máxima indicada, y guardando en el elemento cero la longitud real de la cadena, de forma que si creamos un arreglo con DIM a$(10), b$(10,5) lo que hacemos es crear en a$ una variable de cadena de diez posiciones máximo, y en b$ creamos ONCE cadenas (recordar que el elemento cero existe) de cinco posiciones máximo. En SuperBASIC el nombre del arreglo es una referencia a su contenido, de esta manera si hacemos a$="Hola" o b$(3)="Otras cadenas", lo que hacemos es usar cadenas de longitud máxima predefinida. 

  • Si hacemos PRINT a$;".";b$(3) en pantalla aparece Hola.Otras sin incluir espacios.
  • Si hacemos PRINT a$(0), en pantalla aparece 4 
  • Si hacemos PRINT a$(1), en pantalla aparece H 

Las cadenas se puede tratar como arreglos unidimensionales, pero en este caso no existe el elemento 0 con su longitud, así podemos hacer LET c$="Hola", si hacemos PRINT c$(1) aparece en pantalla H, si hacemos PRINT c$(0) o si hacemos PRINT c$(5) dará un error en ambos casos.

Podemos usar esto para imprimir todos los elementos de un arreglo numérico o de cadena en un PRINT, o para igualar entre si elementos de arreglos de cadena y usar por ejemplo b$(1)=a$, pero esta asignación no funciona con arreglos numéricos. Podemos dar valor a un arreglo de cadena usando por ejemplo INPUT a$ pero esto no funciona con numéricos.

 

Formas corta y larga de las instrucciones, uso del IF

En el superBASIC hay dos formas de escribir una instrucción, la que denominan forma corta abarca hasta el final de la línea en curso y no necesita cerrarse por tanto, mientras que la forma larga abarca varias líneas. Un ejemplo típico será un pequeño IF que podemos escribir de dos maneras

Forma LARGA     Forma CORTA
130 IF columna > 10 THEN 
140   columna=1
150   linea=linea+1
160 END IF 
   
130 IF columna > 10 THEN columna=1 : linea=linea+1

La forma corta no necesita cierre pues siempre termina en la misma línea en la que está, mientras que la forma larga si necesita siempre cierre. Esto es válido para cualquier instrucción.

En superBASIC existe la forma IF ... THEN ... ELSE ... END IF normal en los BASIC, con la parte ELSE opcional, pero con la particularidad de que el THEN es opcional, por lo que para la forma corta debe reemplazarse por dos puntos, pudiendo escribirse por ejemplo cualquiera de estas dos líneas

IF linea=23 THEN linea=1 : ELSE linea=linea+1
IF linea=23 : linea=1 : ELSE linea=linea+1

Bucle FOR

Los bucles FOR del QL mantienen la compatibilidad con el BASIC estándar pero añaden características adicionales. Veamos un bucle muy básico, presentaremos en pantalla una lista de números del 1 al 20:

BASIC     SuperBASIC
10 FOR i=1 TO 20 
20   PRINT i 
30 NEXT i
   
10 FOR i=1 TO 20
20   PRINT i 
30 END FOR i

Vemos que la única diferencia es como terminamos el bucle, y ya que la instrucción NEXT sigue funcionando en SuperBASIC, aunque añade otro sentido, podemos escribir ambos programas en el QL obteniendo el mismo resultado.

Los bucles en SuperBASIC disponen de dos instrucciones que podemos usar en su interior, la primera es NEXT, que hace que el bucle pase directamente al siguiente ciclo sin pasar por el resto de instrucciones. Si deseamos por ejemplo que el bucle se salte los elementos que sean múltiplos de 3, podemos escribir el código así:

BASIC     SuperBASIC
10 FOR i=1 TO 20 
20   IF (i MOD 3) = 0 THEN GOTO 40
30   PRINT i 
40 NEXT i
   
10 FOR i=1 TO 20
20   IF (i MOD 3) = 0 THEN NEXT i
30   PRINT i 
40 END FOR i

Como vemos ahora se imprimen solo los números 1,2,4,5,7,8,10,11,13,14,16,17,19,20 en ambos casos, pero nos hemos ahorrado el GOTO, y sobre todo, podemos incluir todas las líneas que deseemos en el bucle, sin importarnos cual es la línea que lo termina. Nuevamente podemos teclear ambas variantes del programa en SuperBASIC y funcionan ambas.

La otra instrucción que se puede usar en los bucles es EXIT, que como podemos imaginar hace que nos salgamos del bucle en el lugar en que nos encontremos. Supongamos que deseamos hacer que el bucle termine aleatoriamente, para lo que podemos escribir esto:
BASIC     SuperBASIC
100 CLS
110 FOR i=1 TO 20
120   IF (i MOD 3) = 0 THEN GOTO 160
130   LET a = INT(RND*11)
140   PRINT i, a
150   IF a = 10 THEN GOTO 170
160 NEXT i
170 REM Fin
   
100 CLS
110 FOR i=1 TO 20
120   IF (i MOD 3) = 0 THEN NEXT i
130   a = RND(0 TO 10)
140   PRINT i, a
150   IF a = 10 THEN EXIT i
160 END FOR i

Nuevamente, podemos escribir ambos programas en SuperBASIC con el mismo resultado, pero la segunda forma tiene la ventaja de que no necesitamos conocer donde acaba el bucle para salir de el, ni debe existir siquiera una sentencia posterior. Podemos ver otra característica del lenguaje interesante, la instrucción LET es opcional. Y por último, la instrucción RND es mas completa, si no decimos nada genera un número real entre 0 y 1, pero podemos darle un rango y generará números en ese rango, evitando calcular la parte entera de la multiplicación.

Además el bucle FOR también admite la forma corta en una sola línea, que no requiere añadir al final el End For:

                                FOR i=1 to 10 : PRINT i, : LET j=i*4 : PRINT j


Como característica adicional muy interesante, un bucle FOR puede contener dos formas de marcar los límites, la tradicional del TO-STEP o la posibilidad de indicarle una lista de valores sobre los que iterar, así podemos escribir:


10 FOR i = 1 TO 20 STEP 3
20 FOR i = 1 TO 3, 11 TO 13, 21 TO 23
30 FOR i = 1,3,7,10,20 TO 25,40,50
 

Y el bucle iterará por los valores 1, 4, 7, 10, 13, 16 y 19 en el primer caso, por 1, 2, 3, 11, 12, 13, 21, 22, 23 en sel segundo, y por 1, 3, 7, 10, 20, 21, 22, 23, 24, 25, 40, 50 en el tercero.

Bucle REPeat

En otros lenguajes hay dos construcciones estructuradas para el manejo de los bucles llamadas normalmente:
 
 
                            
WHILE (condición)                 
   ....
   ....
WEND
REPEAT
   .....
   .....
UNTIL (condición)

 
que se diferencian en cuando se verifica que se cumpla la condición, antes de empezar o tras la primera iteración. En SuperBASIC se dispone del REPeat como la otra forma estructurada de iterar en un bucle, que no verifica las condiciones nunca, debemos añadir un EXIT para poder salir del mismo siempre. Cuando tecleamos el programa, solo es necesario escribir la parte en mayúsculas de comando para que el sistema la complete. Este es un bucle básico que cuenta del 1 al 20:

BASIC     SuperBASIC
100 CLS
110 LET I=0
120   LET I=I+1
130   PRINT I
140 IF (I < 20) THEN GOTO 120
   
100 CLS
110 i=0
120 REPeat bucle
130   i = i + 1
140   PRINT i
150   IF i = 20 THEN EXIT bucle
160 END REPeat bucle


Ambas versiones funcionan en SuperBasic nuevamente. Estos bucles son útiles, pero se echa de menos una condición de entrada o de salida que nos ayude un poco mas, aunque podemos poner el EXIT como la primera instrucción del bucle para simular el WHILE, o como la última para el REPEAT. En estos bucles, la instrucción NEXT funciona pero no sirve para seguir iterando sino que es un sinónimo del EXIT para salir de bucle.  

Podemos escribir estas instrucciones en Super-BASIC de la siguiente manera, pero hay que tener en cuenta que el Repeat de otros lenguajes se repite MIENTRAS se cumpla la condición, por tanto para salir en Super-BASIC hay que verificar que NO se cumpla la condición. En caso del Repeat de otros lenguajes, se repite HASTA que se cumpla la condición, por tanto es lo mismo en Super-BASIC.


WHILE (condición)
  ....
  ....
WEND
Repeat bucle
  IF NO_Condición : EXIT bucle
  ....
END REPeat bucle
REPEAT
  ....
  ....
UNTIL (condición)
Repeat bucle
  ....
   IF condición : EXIT bucle
END REPeat bucle

SELect ON

Mientras en BASIC clásico se debe usar ON...GOTO / ON...GOSUB o instrucciones IF, en SuperBASIC se dispone del comando SELect como la forma estructurada de ejecutarlo, con la limitación de que solo se admite para valores numéricos y no de cadena. Veamos un ejemplo en el que decidimos que hace según el valor de una variable

BASIC     SuperBASIC
100 INPUT "Valor: ";VAR
110 ON VAR GOTO 140,160,180
120 PRINT "Valor no válido ";VAR
130 GOTO 200
140 PRINT "Valor 1"
150 GOTO 200
160 PRINT "Valor 2"
170 GOTO 200
180 PRINT "Valor 3"
190 GOTO 200
200 REM fin
   
100 INPUT "Valor: ";valor
110 SELect ON valor
120   ON valor=1
130     PRINT "Valor 1"
140   ON valor=2
150     PRINT "Valor 2"
160   ON valor=3
170     PRINT "Valor 3"
180   ON valor=REMAINDER 
190     PRINT "Valor no válido: ";valor
200 END SELect 

Ambas versiones funcionan en SuperBasic nuevamente, aunque la primera dará un error si el valor introducido no es 1, 2 o 3 dependiendo de la versión del BASIC que usemos, y lo dará en SuperBASIC. El uso de ON en la primera línea es opcional, y el de REMAINDER nos posibilita tratar cualquier caso no contemplado entre los seleccionados. Además, el sistema puede tratar con listas de valores, por tanto podemos poner por ejemplo:

110 SELect valor
120   ON valor=1,3,5
130     PRINT "Valor impar"
140   ON valor=2,4,6
150     PRINT "Valor par"
180   ON valor=REMAINDER 
190     PRINT "Valor fuera de rango"
200 END SELect 


Es posible compactar mas todavía las líneas, eliminando el ON (aunque por costumbre de otros lenguajes lo seguiré usando) y usar la forma corta de las instrucciones:

110 SELect valor
120   =1,3,5     : PRINT "Valor impar"
130   =2,4,6     : PRINT "Valor par"
140   =REMAINDER : PRINT "Valor fuera de rango"
150 END SELect 

Se puede usar la forma corta en una sola línea, lo que usando rangos nos permite reemplazar un IF por un SELect

110 SELect valor=1 TO 5, 11 TO 15 : PRINT "Valor fuera de rango"
Importante el que en el select el valor de control debe ser numérico, NO ES POSIBLE USAR VALORES DE CADENA, así NO podemos hacer un select de esta manera, da un error:

110 SELect valor$
120   ON valor$="1" : PRINT "UNO"
130   ON valor$="2" : PRINT "DOS"
140   ON valor$=REMAINDER : PRINT "OTRO"
150 END SELect 

3 comentarios:

  1. Y además de vectores y matrices, los arreglos (DIM) pueden tener más dimensiones, 3, 4, etc... tantas como de la memoria. Aunque la verdad, más de tres dimensiones es raro que se usen.

    ResponderEliminar
    Respuestas
    1. Efectivamente, SuperBASIC no tiene limitación del número de dimensiones de un arreglo, mas de 3 es muy raro e incluso 3 se usan muy poco.

      Eliminar
  2. Interesante artículo. La verdad es que el SuperBasic tiene muchas curiosidades.

    Otro detalle curioso es que se puede eliminar el ON variable de los bloques interiores de cada selección. Por ejemplo:

    110 SELect valor
    120 =1,3,5
    130 PRINT "Valor impar"
    140 =2,4,6
    150 PRINT "Valor par"
    180 =REMAINDER
    190 PRINT "Valor fuera de rango"
    200 END SELect

    ResponderEliminar