Todo sobre: GO TO en el Spectrum Ya antes habiá empezado tratando exclusivamente sobre el ON GOTO y cómo definirlo mediante una función de usuario. Ahora he dicidido expandirlo. Este texto reune todas mis notas sobre la sentencia GOTO y las instrucciones relacionadas con la misma, ya sea existentes en otros BASICs o en el Basic Sinclair, asi como sus equivalentes y diferencias en el ZX SPECTRUM. GOTO en Fortran Empezamos la comparativa con el FORTRAN, uno de los lenguajes más antiguos en usar GOTO. GO TO incondicional Sintaxis: GO TO num donde num = un número de línea de preograma al cual saltar Ejemplo: C - SUMA DE NUMEROS POSITIVOS INTEGER X, SUMA SUMA=0 58 READ, X IF(X.EQ.0)GO TO 23 IF(X.GT.0)SUMA=SUMA+X GO TO 58 23 PRINT, SUMA STOP END GO TO computado o calculado Sintaxis: GO TO (lista),var donde var = una posición dentro de la lista de números de línea a la cual saltar Ejemplo: C - ALTURA PROMEDIO INTEGER SEXO, VARON, MUJER REAL H VARON, H MUJER H VARON= H MUJER= MUJER= VARON= 0 3 READ, ALTURA, SEXO GO TO(14,29,17),SEXO 14 H VARON= H VARON+ ALTURA VARON= VARON+ 1 GOTO 3 29 H MUJER= H MUJER+ ALTURA MUJER= MUJER+ 1 GOTO 3 17 PRINT, H VARON/VARON, H MUJER/MUJER STOP END GO TO asignado Sintaxis: GO TO var, (lista) donde var = un número de línea que debe de existir dentro de la lista asignada var requiere de la sentencia ASSIGN para su definición. Ejemplo: C - ASIGNADO ASSIGN 3 TO ISALTO 5 GO TO ISALTO,(7,3,6) 6 PRINT, 99999 7 STOP 3 PRINT, 88888 ASSIGN 6 TO ISALTO GO TO 5 END Fortran tiene además otro medio de salto utilizando el IF aritmético. GOTO-less (no al GOTO) Mientras que FORTRAN solamente requiere de números de línea para asignar el salto de GOTO, cosa que es hecha de modo tan arbitrario que es realmente dificil de seguir, tal como se puede ver en los ejemplos anteriores; el BASIC desde sus orígenes requiere que todas las sentencias de un programa tengan números de línea a su inicio. Fue en respuesta a esto que surgieron lenguajes de programación como el COMAL. El goto era criticado por llevar a lo que se llamó "código espagueti", al punto que Dijkstra, el autor del PASCAL escribió un artículo llamdo "La sentencia Go To considerada dañina." Es decir, se acusa al programa escrito usando GOTOs de ser, no solamente dificil de seguir por los saltos e interrupciones que se hacen, sino dificil de modificar a futuro para su adaptación a nuevos problemas. Así como de corregir en caso de errores o renumeración. GOTO en Pascal A pesar de la regla GOTO-less, tanto Algol, Pascal, C y algunas versiones de LOGO, tienen la sentencia GOTO implementada en uno u otro modo. Solo que al no haber números de línea, se usan etiquetas a las cuales se hacen los saltos. Incluso PL/1 y MS-DOS la usan. sintaxis: goto donde e (etiqueta) = un número entero sin signo no mayor de 4 dígitos. requiere de la declaración 'label'. Ejemplo: program ex(input,output); label 15; var t, x, s :real; n :integer; begin read(x); t:=1; s:=1; n:=0; 15: n:=n+1; t:=t*x/n; if t>0.0001 ^ n<19 then begin s:=s+t; goto 15 end; write('suma de la serie',s) end. En general, el Pascal o el C, prefieren usar otras estructuras de control como while o repeat, incluso bucles for, antes que un goto. Sin embargo se la mantiene debido a la posibilidad de que el diseño del programa no deje otra alternativa que su uso, como por ejemplo, salir de una estructura de bucles a varios niveles. GOTO en los primeros BASICs GO TO incondicional sintaxis: GOTO const donde const = un número de línea del programa al cual saltar Esta versión de GOTO no acepta variables ni expresiones numéricas de ningún tipo sólo números. Es el GOTO que existe en los BASICS de APPLE, Commodore, TRS80 y similares. GOTO condicionado sintaxis: IF cond GOTO xx donde sólo se salta a la línea xx si cond es igual a verdadero. IF cond THEN xx - es la forma más admitida por la mayoría de BASICs. Tomemos el primer ejemplo del GOTO de Fortran y convirtámoslo a BASIC estandar. 10 REM - SUMA DE NUMEROS POSITIVOS 20 SUMA=0 30 INPUT X 40 IF X =0 GO TO 70 50 IF X >0 THEN SUMA=SUMA+X 60 GO TO 30 70 PRINT SUMA 80 END Nota: A diferencia de FORTRAN que admitía sentencias luego de un IF, el Basic no admitió la forma más completa de "IF ... THEN sentencias" hasta 1972. El único uso y objetivo de IF era hacer saltos condicionados nada más. ON GOTO sintaxis: ON nn GOTO lista donde nn = una posición dentro de la lista de números de línea a la cual saltará Inexistente en el Basic Darmouth original hasta su cuarta edición en el 68. Otras variantes son: GOTO OF - usado por algunas antiguas versiones de BASIC. ON THEN - aceptado sintácticamente como válido en el Basic de Darmouth a partir de 1968. Pasamos ahora a converitr el segundo ejemplo de Fortran a ON GOTO 10 REM - ALTURA PROMEDIO 20 INPUT ALTURA, SEXO 30 ON SEXO GO TO 40,70,100 40 HVARON= HVARON+ ALTURA 50 VARON= VARON+ 1 60 GOTO 20 70 HMUJER= HMUJER+ ALTURA 80 MUJER= MUJER+ 1 90 GOTO 20 100 PRINT HVARON/VARON, HMUJER/MUJER Otro uso de GOTO es asociado a ON ERROR para la captura de errores. En BASICs estructurados Tanto el Basic BBC, el Super Basic de QL o el Quick Basic de Microsoft, retienen la sentencia GOTO y ON GOTO, pero solamente por motivos de compatibilidad, ya que estos BASICs poseen estructuras de control del tipo pascaliano y suelen aconsejar más el uso de esto último. Quick Basic puede reemplazar los numeros de línea por etiquetas de un modo similar a como lo hacen Pascal y LOGO. En el ZX Spectrum Finalmente pasamos a ver el potencial de la sentencia GOTO del Spectrum. GO TO sintaxis: GO TO xx donde xx = un número de línea del programa al cual saltar xx puede ser también una variable numérica o expresión aritmética Es la sintaxis que comparten también los Basics de Atari y Oric. xx por otro lado, puede ser una variable o constante alfanumérica asociada a VAL. Vamos a convertir el ejemplo de PASCAL a Spectrum: 10 REM program ex(input,output) 20 LET label= 70 30 INPUT x 40 LET t =1 50 LET s =1 60 LET n =0 70 REM label 71 LET n =n+1 80 LET t =t*x/n 90 IF t>0.0001 AND n<19 THEN LET s =s+t: GOTO label 100 PRINT "suma de la serie ";s ON GO TO inexistente en el Basic Sinclair del ZX80, ZX81 y Spectrum. Existe en cambio, en la versión Super Basic del QL. Algunas extensiones al BASIC, como el de Manuel Arana publicado en la revista española TodoSpectrum también lo incluye tal cual. BetaBasic tiene en cambio la variante GOTO ON var; lista. En cuanto a cómo el Spectrum sin extensión alguna lo replica, ver el artículo previamente publicado llamado "ON GOTO en el Spectrum". GOTO a instrucciones dentro de una línea del listado En BetaBasic 3.xx existe una forma de ON cuya sintaxis es: ON : sentencia1: sentencia2: ... En el Spectrum sin expansión es posible de hacer lo mismo mediante: NEWPPC (23618-9) donde se almacena el número de línea NSPPC (23620) donde se pone la posición de la sentencia en esa línea a la cual saltar. Ejemplo: 10 PRINT "Ingrese un número": INPUT n: PRINT "ingrese otro numero": INPUT m: STOP Ahora quiero ejecutar solamente a partir del segundo PRINT. Tipeo entonces: 20 POKE 23618,10: POKE 23619,0: POKE 23620,3 de este modo ya no tengo que dividir la línea 10 en dos. De hecho, NEWPPC almacena el último GOTO ejecutado. Sabiendo esto, podemos usar goto con poke NSPPC, x. De este modo podemos hacer algo como: 30 INPUT n 40 GOTO 100 100 POKE 23620,n*2: PRINT "PRUEBA 1": STOP: PRINT "SEGUNDA PRUEBA": STOP: PRINT "PRUEBA 3" Definitivamente con algo de ingenio y mucho experimentar, se puede encontrar el mejor modo de aprovechar esta curiosa técnica. Bucles en el Spectrum Un bucle es un método para repetir varias veces o infinitamente una serie de instrucciones seguidas unas de otras. GO TO es la única instrucción de salto por excelencia y de facto, la única usada para crear y manejar bucles en los BASICs más clásicos, de los cuales el Basic Sinclair es heredero. Eso es aparte de los bucvles FOR - NEXT. Bucles sin salida El también llamado bucle sin fin. Una vez se entra en esta clase de bucles sólo se sale pulsando BREAK. Ejemplo: 10 PRINT "Hola mundo" 20 GOTO 10 Bucles con salida al medio Una vez dentro del bucle, es posible salir en cualquier punto, siempre que se cumpla la condición escogida para salir de ello. Ejemplo: 10 LET init=100: LET exit=400 100 REM inicia el bucle ... ... 200 IF cond THEN GOTO EXIT ... ... 300 GOTO INIT 400 REM fin del bucle Bucles tipo while o repeat En esta clase de bucles, el primero es seguir en el bucle mientras no se cumpla la condición y el segundo es repetir el bucle hasta que se cumpla la condición dada. Ejemplo: 10 LET init=100 100 REM inicia el bucle ... ... 200 IF cond THEN GOTO init 210 REM fin del bucle ON GOTO en el ZX81 A continuación vamos a ver no el único modo de simular ON GOTO en ZX81, ya que este admite los modos de salto condicial y computado, pero sí uno que usa las cadenas para replicarlo: Ejemplo - mediante cadenas: 10 LET A$="010002000300040005000600" 20 INPUT N 30 GOTO VAL A$((N*4-3 TO N*4) ON GOTO mediante DIM y DATA 10 DIM o(10) 20 DATA 1000.2000.3000.4000.5000.6000 30 FOR n=1 TO 6 40 READ o(n): NEXT n 50 INPUT n 60 GOTO o(n) Y para cerrar... RESTORE y ON RESTORE Si hay ON GOTO y ON GOSUB, debe o debería de haber entonces ON RESTORE también. De hecho existe en GW-Basic. Obviamente no existe en el Spectrum, pero para definirlo basta con decir que lo que es valido para GOTO y GOSUB es igualmente válido para RESTORE. RUN y ON RUN ON RUN sería para casos muy espEciales ya que RUN normalmente es como un GOTO más CLEAR. Normalmente, uno hace RUN para ejecutar el programa desde su inicio, y raras veces a partir de algún otro número de línea distinto al comienzo. Pero, ¿qué tal si en vez de un solo programa, juntamos varios programas cortos como un solo listado y compartiendo todos las mismas subrutinas? En este caso, el primer módulo podría estar desde las líneas 100 a 400, el segundo del 500 a 980 y el tercero desde la 600 hasta 990 con todas las subrutinas empezando a partir de 1000, siendo del 10 al 90 el menú de selección. Ahí si sería óptimo un ON RUN. CONTINUE Este es un caso muy especial en el Basic Sinclair. Normalmente continúa un programa interrumpido (con BREAK) a partir del punto donde se quedó. Sin embargo incluido en un listado hace lo mismo que GOTO 10, devolviendo error si la línea 10 no existiese. Ejemplo: 10 PRINT "Hola mundo" 20 CONTINUE El bucle de tipo while-repeat se puede ahora retipear del modo sigte.: 1 LET exit=400 10 REM inicia el bucle ... ... 200 IF cond THEN GOTO EXIT ... ... 300 CONTINUE 400 REM fin del bucle Esto es debido a las sigtes variables del sistema: OLDPPC (23662-3) donde se almacena el número de línea, aparentemente tiene el valor 10 por defecto. OSPPC (23664) donde se pone la posición de la sentencia en esa línea a la cual saltar. Ejemplo: 20 POKE 23662,100: POKE 23619,0: POKE 23620,3 hará que el primer CONTINUE con el que se tope el programa, salte a la línea 100 y a la tercera instrucción de la misma. Si no existiese ninguna, el programa se detendrá reportando que hubo un error. Practicamente hace un GOTO sin GOTO y como en el caso del salto a una sentencia dentro de una línea, es cuestión de práctica e ingenio que se le pueda sacar provecho a CONTINUE dentro de un programa. (c)2020 zx_if1@hotmail.com