¡Hola a todos!, hay problemas con la web que espero poder arreglar lo antes posible, ¡mil perdones!

Ver índice de webs/blogs

QBlog : Carga dinámica de programas en SuperBASIC Leer


¿Te imaginas que tu programa SuperBASIC pueda mostrar una barra de progreso mientras se va cargando con LOAD o LRUN, o que muestre al usuario en cuánto tiempo se ha cargado este programa usando sólo SuperBASIC, sin necesitar ninguna extensión? Estas son algunas de las cosas que podemos conseguir con el método que explico aquí.

Es posible que esto ya sea conocido por los expertos en SuperBASIC, o que se haya documentado antes, pero para mi ha sido todo un descubrimiento recientemente, y así lo comparto.

Fuente imagen: https://www.flickr.com/photos/193030246@N04/51238171803

Cargando programas en SuperBASIC

Cuando ejecutamos una instrucción LOAD o LRUN, el sistema abre el fichero _bas que le indiquemos, y va leyendo y cargando cada línea. Al hacerlo, completa los comandos reducidos que pudiera haber, como REM, por poner un ejemplo, que traduce en el listado como REMark, y revisa si hay algún error de sintaxis para avisar al usuario mediante la inserción de un «MISTake» en esa línea.

Nunca me había parado a pensar cómo funciona la carga de programas SuperBASIC hasta que, hace unos días, hablando con Zerover, recordamos el juego «Nuclear Invaders» que el usuario dancresp había publicado en el foro español RetroWiki, y su peculiar forma de incluir comentarios en el listado que había compartido. Ver el enlace: https://retrowiki.es/viewtopic.php?f=98&t=200040396

En su listado hay lineas vacías y comandos REM sin número de línea, algo que a Zerover le pareció una buena idea para hacer el programa más corto, ya que, al parecer, dichas líneas no aparecerán en el listado una vez cargado el programa, por lo que ocupará menos memoria, y además esto ayuda a que el código sea más legible cuando se muestra en, por ejemplo, un foro.

Preguntando a dancresp sobre esta peculiaridad, me comentó lo siguiente:

«…de tanto en tanto los imprimo (los listados) para ojearlos, y aprovecho antes para separar los bloques con un REM al inicio del bloque y una línea en blanco al final. Lo curioso es que después los cargaba en el QL y no daba error

REM y lineas en blanco

Entonces, ¿qué ocurre con las líneas en blanco y los REM? Pues, sencillamente que, durante la carga, las líneas que no tienen número de líneas son ejecutadas tan pronto como se cargan, como si las introdujésemos directamente por la ventana de comandos.

Esto me sorprendió, y comencé a hacer pruebas. Los REM y las líneas en blanco, por supuesto, no tienen ningún efecto en el ordenador. También podemos incluir el símbolo «:» que se usa como separador de comandos en una línea, y todo funcionará bien. Así pues, podemos tener un programa similar a este que el sistema cargará sin errores:

REM start

:
100 PRINT "Hi!"
:

REM end

Y al hacer LIST, sólo se mostrará la línea numerada

100 PRINT "Hi!"

ejecutando el resto de líneas no numeradas en el momento de la carga.

Comandos sin número de línea intercalados

Y si este método funciona con REM, ¿funcionará con otras instrucciones SuperBASIC? La respuesta es sí.

Podemos usar instrucciones SuperBASIC intercaladas en el programa si las incluimos sin número de línea.

Algo como esto es posible:

PRINT #0,"Loading..."
100 REM The code here
110 REM ...

El caso es que podemos usar incluso variables, bucles, etc… Para estructuras que requieran de cierre, como en el caso del uso de FOR, IF… los END deben estar en la misma línea, separados por «:», como si empleásemos el comando DO de Toolkit 2.

Lo que al parecer no funciona es la definición de funciones y procedimientos. Si definimos un procedimiento, y lo llamamos más adelante, en otra línea del fichero sin número de línea, recibiremos el error «No encontrado», y se parará la carga.

Este método permite tener dos programas en uno; el programa compuesto de instrucciones intercaladas en el listado almacenado sin número de líneas que se ejecutan durante la carga, y el listado del programa con números de línea que se ejecuta con RUN cuando se termine de cargar.

Porcentaje de carga

Como las líneas se cargan consecutivamente, podemos intercalar instrucciones allá donde queramos que se ejecuten a medida que el listado se cargue. Esto nos permitiría, por ejemplo, mostrar el porcentaje de carga del programa de esta forma:

CLS #0
AT #0,0,0:PRINT #0, "Loading 0%"
100 REM code
AT #0,0,0:PRINT #0, "Loading 25%"
250 REM more code
AT #0,0,0:PRINT #0, "Loading 50%"
500 REM more and more code
AT #0,0,0:PRINT #0, "Loading 75%"
750 REM more code again
AT #0,0,0:PRINT #0, "100% loaded"
999 REM program loaded

Durante la carga, se ejecutará, cuando corresponda:

CLS #0
AT #0,0,0:PRINT #0, "Loading 0%"
AT #0,0,0:PRINT #0, "Loading 25%"
AT #0,0,0:PRINT #0, "Loading 50%"
AT #0,0,0:PRINT #0, "Loading 75%"
AT #0,0,0:PRINT #0, "100% loaded"

y el listado resultante que se mostrará con LIST será:

100 REM code
250 REM more code
500 REM more and more code
750 REM more code again
999 REM program loaded

Por supuesto podemos incluir tantas instrucciones PRINT como deseemos, y afinar el porcentaje de carga. Si tenemos 100 líneas de código, y queremos mostrar el porcentaje de carga cada vez que se cargue un 10% del código, entonces deberemos intercalar los PRINT sin número de línea, con el mensaje correspondiente, cada 10 líneas.

Aquí otro ejemplo usando una barra de progreso creada a partir de caracteres:

CLS #0
AT #0,0,0:PRINT #0, "Loading 0%"

100 REM Program here

PAUSE 50 : REM Simulates the loading time
AT #0,0,0:PRINT #0, "Loading 25% "; FILL$(CHR$(226), 3)

110 REM Program here

PAUSE 50
AT #0,0,0:PRINT #0, "Loading 50% "; FILL$(CHR$(226), 6)

120 REM Program here

PAUSE 50
AT #0,0,0:PRINT #0, "Loading 75% "; FILL$(CHR$(226), 9)

130 REM Program here

PAUSE 50
AT #0,0,0:PRINT #0, "100% loaded "; FILL$(CHR$(226), 12)

Podemos echar a volar la imaginación haciendo uso de instrucciones gráficas como WINDOW, LINE, BLOCK o incluso SCROLL o PAN para dibujar y mostrar visualmente el avance de las barras de procentaje de carga… o todo aquello que se te ocurra.

Creando los listados

Obviamente, con el editor del QL, ya sea con EDIT o con ED, no vamos a poder crear los listados con las líneas intercaladas sin número de línea. Para ello vamos a necesitar un editor de texto como por ejemplo QED o similar.

Lo recomendado es crear el programa completo por los medios habituales y probarlo hasta que todo funcione. Sólo después de esto sería recomendable incorporar el segundo programa, el que se ejecutará durante la carga, con las instrucciones sin números de línea que deseemos.

Calculando el tiempo de carga

Para concluir, veamos otro ejemplo en el que se resume todo lo expuesto aquí en un pequeño programa que muestra el tiempo que tardó en realizarse la carga del programa.

t=DATE

100 PRINT "PROGRAM CODE" : REM Only this numbered line will be shown in the listing
:
PAUSE 100 : REM Simulates the loading time of the rest of the lines of code

PRINT "Loaded in ";DATE-t;" seconds."

En la primera línea, en la variable «t» se guarda la fecha y hora actual como un valor en coma flotante.

Saltando la línea de espacio en blanco, la línea 100 es cargada y será la única que se mostrará en el listado al hacer LIST.

Tras la línea de los dos puntos que no tiene efecto en el programa, con el PAUSE se simula en este ejemplo el tiempo de carga del resto de líneas de un programa. El valor 100 supone una demora de 2 segundos.

Y tras una nueva línea en blanco, la instrucción PRINT mostrará el tiempo transcurrido desde que empezó la carga del programa en segundos.

Consideraciones

Este método da para mucho si se le echa imaginación, y permite mostrar, de forma dinámica, información que el usuario de nuestros programas en SuperBASIC agradecerá, sobre todo si el tiempo de carga es elevado, como cuando cargamos programas desde microdrive.

Mostrar avances en la carga, información sobre requisitos, o incluso trucos de uso, ayudará a mantener al usuario interesado en el programa y hará más llevadera la carga, pero no sólo sirve para eso.

Este método puede ser útil también para ejecutar instrucciones durante la carga que luego no es necesario que vuelvan a ser usadas cada vez que se ejecuta el programa en SuperBASIC, por ejemplo, cargar extensiones, ejecutar TK2_EXT, ejecutar un POKE o reservar memoria.

Otra forma de usarlo es eliminando del listado que será cargado en memoria aquellas líneas que no son de utilidad para la ejecución y que ocupan memoria, como los REM.

Dicho todo esto, es importante mencionar que el método sólo funcionará con listados de programas en SuperBASIC, ya que los programas compilados no nos dan esta posibilidad. y recordar también que, como ya dije, esto no permite el uso de procedimientos y funciones durante la carga.

Una cosa más. Si cargas el programa con LRUN y este no se ejecuta, añade un RUN sin número de línea al final del listado de tu programa.

Advertencia

Dilwyn Jones, en el foro inglés, hace ver la siguiente información:

En el manual del Toolkit 2 hay una nota sobre lo que puede suceder con líneas no numeradas en un archivo BASIC en algunas ROM QDOS, que también se menciona en los artículos de errores de ROM de Simon Goodwin en QL. World.

Un archivo DO es un archivo de comandos directos que se ejecutarán mediante el comando DO del Toolkit 2. El manual dice:

«Si hay un comando RUN en un fichero DO, el fichero no será cerrado, una vez leído su contenido. Tampoco será cerrado, si es cargado con MERGE en lugar de con DO.»

Quizás sea por eso que esta técnica nunca se implementó realmente, que la gente estaba consciente de problemas potenciales como este al cargar archivos con comandos directos si alguien fusionara el programa. Los artículos de Simon afirman que este problema de MERGE se solucionó en Minerva y, hasta cierto punto, en Toolkit 2.

En cualquier caso, es fácil verificar si LRUN / LOAD funciona bien simplemente cargándolo desde un disco y verificando si el archivo permanece abierto después usando algo como el menú de canales de QPAC2, o incluso cambiando los discos; el sistema pronto se quejará. si intenta cambiar los discos con un archivo aún abierto.

Siguel a discusión de la comunidad aqui: https://retrowiki.es/viewtopic.php?f=98&t=200040477