fromZXtoSAM
Descripción del contenido de la página
Utilidad para intentar pasar programas en BASIC desde una ZX Spectrum a una SAM Coupé.
La idea inicial
El objetivo de este programa es facilitar la conversión de programas en BASIC de ZX Spectrum a SAM Coupé. El programa original puede estar escrito en Sinclair BASIC o en Beta BASIC; la conversión final, por supuesto, hay que hacerla manualmente (a SAM BASIC o a MasterBASIC).
La idea que se me ocurrió es muy sencilla y consta de dos partes que hay que ejecutar en orden:
- Un programa exportador en Beta BASIC, (toSAM), que se mezcla con el programa que queremos exportar y mediante
LIST
ySHIFT$()
crea, en dos pasos, un listado en forma de texto en un fichero de datos en el disquete. - Un programa importador en MasterBASIC, (fromZX), que lee el fichero de datos por líneas y evalúa cada una con
KEYIN
. Los errores sintácticos los intercepta conON ERROR
y los soluciona añadiendoREM
al principio de las líneas erróneas y una marca convencional («MISTAKE», idea tomada del SuperBASIC de la QL) que permita localizarlos después.
Sobre el papel el procedimiento era tan sencillo que no podía tener fallos...
El problema en la importación
En la práctica descubrí que fromZX no funcionaba bien; dio problemas desde el primer momento. De vez en cuando KEYIN
daba errores injustificados que además en ocasiones no se gestionaban bien con ON ERROR
. Tras diversas pruebas no encontré un patrón para los fallos y concluí que era el comando KEYIN
de SAM BASIC el que fallaba, o bien su combinación con ON ERROR
.
En la guía A-to-Z of Hints'n'Tips, publicada en disquete por su autor en 1993, ya había leído algo que me había puesto sobre aviso: El comando
:
KEYIN
está lleno de fallos y no es fiable para hacer programas que se modifiquen a sí mismos
Although this command is bug-ridden and so can't reliably be used to make self-modifying programs, it can be useful for having SAMBASIC command-line input within programs.
Malevolent '93
Con ayuda de toda la documentación disponible intenté sin éxito todas las combinaciones que se me ocurrieron entre KEYIN
y ON ERROR
(procedimientos, saltos directos, saltos a subrutinas...). Llegué a sospechar que si KEYIN
estaba solo en su propia línea de programa los fallos no se producían, pero no era así. El programa fromZX no era fiable; lo dejé a un lado con el nombre de fromZX (system 0) y pensé de qué otra manera podría lograr el objetivo.
Segundo intento
Pensé una idea original: para poder prescindir de la interceptación de errores, bastaba añadir un REM
al principio de cada línea importada (seguido de alguna marca) y al final del proceso quitarlos todos con el comando ALTER
. Aparentemente funcionó bien. Incluso probé a situar el programa tanto al principio (entre las líneas 1 y 9) como al final (a partir de la línea 10000), y en ambos casos funcionó bien, por lo que lo dejé en la línea 10000, que es más práctico y cómodo.
Mi duda era qué pasaría al quitar los REM
de líneas sintácticamente erróneas, pero no pasó nada: como era de esperar, no eran reinterpretadas. Las líneas erroneas darían error en tiempo de ejecución. Pero no me di cuenta de que había un problema oculto: precisamente porque el REM
inicial había impedido la interpretación de las líneas con KEYIN
, las palabras clave de MasterBASIC habían sido almacenadas como texto, no traducidas a sus códigos propios en el juego de caracteres de la SAM Coupé... y eso por supuesto no cambiaba al quitar el REM
. El resultado era que todas las líneas daban error de ejecución porque para el intérprete eran incomprensibles. Había que «reinterpretar» una por una a mano, bajándolas a la línea de comandos y subiéndolas de nuevo, lo cual es viable pero no es práctico (incluso con ayuda del sistema de redefinición de teclas de SAM BASIC, que ayudaría un poco).
Pero en cualquier caso, seguían produciéndose errores ocasionales durante la importación, al parecer en líneas muy largas (porque tenían GDU que el programa toSAM había interpretado inevitablemente como comandos de Beta BASIC).
Llamé a este segundo intento fromZX (system 1).
Tercer intento
Lo siguiente que pensé fue compactar el código de fromZX (system 0) y moverlo a las primeras nueve líneas de programa. Colocar el programa en la línea 10000 era cómodo porque así no pisaba ninguna posible línea importada (la ZX Spectrum usa el rango 1-9999). Colocando el programa fromZX en las líneas de la 1 a la 9 obligaba a que el programa importado empezara en la línea 10 o posterior, lo que era una pequeña e incómoda limitación. Pero a cambio las líneas de fromZX no cambiarían su posición en la memoria durante la importación, lo que pensé que podría estar relacionado con los desajustes de KEYIN
y ON ERROR
. Pronto me desegañé: Seguían ocurriendo fallos inexplicables.
A este nuevo intento lo llamé fromZX (system 2).
Últimos intentos
Había que probar una última cosa: simplificar al máximo la interceptación de errores (hacerla con GO TO
en lugar de con un procedimiento), y desactivarla explícitamente cada vez que se produjera un error. Para probarlo escribí fromZX (system 3) y fromZX (system 4). Funcionaron mejor; la rutina de error dejó de actuar recursivamente; pero siguieron produciéndose errores, aunque más tardíos, que detenían el proceso de importación.
Exportación de programas grandes
Independientemente de los fallos de importación en la SAM Coupé, hay una limitación en la exportación: Beta BASIC solo deja libres unos 19 KiB de memoria. Si el programa que queremos exportar está escrito en Sinclair BASIC y es mayor, el programa toSAM no sirve de nada porque no hay suficiente memoria libre para hacer MERGE
.
Para solucionar este problema, en primer lugar dividí el código de toSAM en dos procedimientos:
- TOr lee con
MERGE
el programa a exportar y crea un fichero con extensión «.r» (de raw) que contiene el listado en bruto, sin traducir a texto. - rTOl abre el fichero «.r», traduce cada línea con
SHIFT$()
y la guarda en el fichero definitivo, que usa la extensión «.l» (de listing).
En segundo lugar escribí Sinclair BASIC un programa equivalente al procedimiento limitante, que es el primero, y lo llamé también TOr. Este programa hace pues la misma función que el procedimiento original sin tener que cargar Beta BASIC. Después de usarlo hay que cargar toSAM y ejecutar el procedimiento rTOl con el nombre base del programa a exportar, lo que creará el fichero final «.l» a partir del «.r».
Conclusión
Sobre el papel la idea es perfecta pero ciertos fallos en el intérprete de SAM BASIC (y que MasterBASIC no arregla) impiden que funcione de forma práctica.
Posiblemente la versión menos inútil del programa de importación sea fromZX (system 3); quizá pueda servir, sin garantías, para importar programas pequeños (o divididos en partes), y mejor que hayan sido editados en la ZX Spectrum para eliminar incompatibilidades con MasterBASIC.
No creo que haya más soluciones posibles, salvo escribir el proceso de importación en Z80, algo que decididamente no merece la pena; más interesante aunque no menos laborioso sería depurar la ROM de la SAM Coupé, cuyo desensamblado está disponible.
Pantallazos
El directorio del disquete durante el desarrollo del programa, visto de forma diferente por ambos sistemas operativos:
Primer ejemplo de importación fallida con fromZX (system 0)
El siguiente pantallazo muestra la salida en pantalla de fromZX (system 0) leyendo un módulo de mi proyecto La legionela del pisto. En verde se muestran las líneas importadas con éxito y en rojo las que han dado error sintáctico y el programa ha anulado con un REM
. En este caso la línea 530 ha dado error porque hace referencia a una matriz del disco RAM (!word$()
), característica de Beta BASIC 4.0 que MasterBASIC no comprende:
En el siguiente pantallazo se muestra un nuevo error de importación del mismo código. Las líneas blancas son un recurso de depuración y muestran la línea leída del fichero antes de ser evaluada con KEYIN
. La línea 980 causa un error sintáctico por el mismo motivo citado (una matriz del disco RAM), que sin embargo no es interceptado por ON ERROR
y provoca un error incontrolado. ¿Qué diferencia ese error sintáctico de otros interceptados previamente? Nada. Algo no funciona bien en el intérprete.
Segundo ejemplo de importación fallida con fromZX (system 0)
Error final de la prueba de importación del código de Dictador:
El sistema quedó inestable y se reinició solo. La línea donde se produjo el error es la siguiente a la 796, la 798:
796 POKE gr,VAL "104": POKE gr+on,VAL "94"
798 PRINT AT VAL "3",on; PAPER VAL "4";"ABCABCABCABCABCABCABCABCABCABC";AT VAL "4",on;"DEFDEFDEFDEFDEFDEFDEFDEFDEFDEF";AT VAL "5",on;"GHIGHIGHIGHIGHIGHIGHIGHIGHIGHI
"
Como se ve, el error sintáctico lo causa una variable que se llama on. La línea tiene la peculiaridad de tener muchos GDU, que durante la exportación son interpretados como palabras claves de Beta BASIC y por tanto en el fichero a importar figuran como tales, como texto. Pero eso no explica por qué el proceso de importación se detiene y corrompe el sistema.
Tercer ejemplo de importación fallida con fromZX (system 0)
Error final de la prueba de importación del código de Colegio Erevest 3:
Esta vez el sistema no se bloqueó y pude imprimir la línea causante del error, como muestro a continuación. La línea no había sido aceptada porque la variable ON coincide con la palabra reservada ON
de SAM BASIC. Hasta ahí todo normal. Lo inexplicable es que, como se ve, la línea ya había sido procesada muchas veces por la rutina de interceptación de errores, hasta provocar el error final:
Ejemplo de importación fallida con fromZX (system 2)
Error final de la prueba de importación del código de Colegio Erevest 3, e impresión de la línea causante (la 233):
Ejemplos de importaciones fallidas con fromZX (system 3) y fromZX (system 4)
Fallos en los últimos intentos de importación del código de Dictador:
Código fuente
toSAM
En Beta BASIC y Beta DOS para ZX Spectrum:
1 REM toSAM
Part of the tool 'fromZXtoSAM'.
Copyright (C) 2011 Marcos Cruz (programandala.net)
License
programandala.net/license
2 REM Changelog
2011-03-02 First version.
2011-03-25 Improved. f$ saved in memory. All streams closed at the start.
2011-03-27 Improved. Better look. Split into two steps (TOr and rTOl). BetaDOS functions. FN W$().
3 LET BBon=VAL "58419"
LET EOFLET=VAL "4481"
LET SPKLET=VAL "4482"
POKE @EOFLET,CODE "Z"
POKE @SPKLET,CODE "B"
RANDOMIZE USR BBon
DEF FN B(x)=USR 8
DEF FN Z(x)=USR 8
DEF FN G(x)=FN B(x+VAL "8192")
DEF FN W$(f$)=f$( TO LEN f$-VAL "2"*(LEN f$>VAL "8"))
REM Beta DOS functions=
B()=peek of shadow ROM and RAM
G()=relative peek of shadow RAM
Z()=End Of File
4 DEF PROC toSAM f$
TOr f$
rTOl f$
END PROC
5 DEF PROC TOr f$
LOCAL r$
CLS #
PRINT INK VAL "7";STRING$(VAL "32"," ")
PRINT "toSAM"''"Merging the program '";f$;"'"
6 POKE VAL "16384",LEN f$
POKE VAL "16385",f$
MERGE d*;f$
LET f$=MEMORY$()(VAL "16385" TO VAL "16385"+PEEK VAL "16384"-SGN PI)
LET r$=FN w$(f$)+".r"
PRINT "Creating the file '";r$;"'"
CLOSE #*
OPEN #5;d*;r$ OUT
LIST FORMAT NOT PI
LIST #5;1e1 TO
LIST FORMAT VAL "2"
CLOSE #*
7 DELETE 1e1 TO
END PROC
8 DEF PROC rTOl f$
LOCAL l$
LET f$=FN w$(f$)
CLOSE #*
OPEN #5;d*;f$+".r"RND
OPEN #6;d*;f$+".l"RND
DO UNTIL FN z(5)
INPUT #5; LINE l$
LET l$=SHIFT$(7,l$)
PRINT l$
PRINT #6;l$
LOOP
CLOSE #*
END PROC
9 DEF PROC toSAMsave
DELETE 1e1 TO
CLEAR
SAVE OVER d*"toSAM" LINE 1
STOP
END PROC
REM THIS LAST LINE MUST BE LOWER THAN 10
fromZX (system 0)
En MasterBASIC y Master DOS para SAM Coupé:
10000 REM fromZX (system 0)
Part of the tool 'fromZXtoSAM'.
10010 REM Copyright (C) 2011 Marcos Cruz (programandala.net)
10020 REM License
programandala.net/license
10030 REM Changelog
10040 REM 2011-03-02 First version.
10050 REM 2011-03-25 Bug fixed in fromZXmistake. FSTAT was added to check the file.
10060 DEF PROC fromZX file$
10070 LOCAL line$,red,green,lineInk
10080 DEFAULT file$="test.l"
REM debug!!!
10090 LET red=2,green=4,lineInk=green
10100 CLS #
PRINT "fromZX"''
10110 IF NOT FSTAT(file$,1) THEN PRINT "File not found"
STOP
10120 IF FSTAT(file$,3)<>10 THEN PRINT "Wrong file type"
STOP
10130 CLOSE #4
OPEN #4;file$IN
10140 DO UNTIL EOF 4
10150 INPUT #4; LINE line$
10160 ON ERROR fromZXmistake
KEYIN line$
ON ERROR STOP
10170 PRINT PEN lineInk;line$
LET lineInk=green
10180 LOOP
10190 CLOSE #4
10200 END PROC
10210 DEF PROC fromZXmistake
LET line$=line$( TO 4)+" REM MISTAKE "+line$(6 TO )
KEYIN line$
LET lineInk=red
END PROC
10220 DEF PROC d
DELETE TO VAL "9999"
END PROC
10230 DEF PROC r
RENUM 1e4 TO LINE 1e4
END PROC
10240 DEF PROC s
d
r
SAVE OVER "fromZX_0"
END PROC
fromZX (system 1)
En MasterBASIC y Master DOS para SAM Coupé:
10000 REM fromZX (system 1)
Part of the tool 'fromZXtoSAM'.
Copyright (C) 2011 Marcos Cruz (programandala.net)
License
programandala.net/license
10010 REM Changelog
2011-03-25 First version, based on fromZX (system 0).
2011-03-27 Tested on line 10000. Moved from lines 1-9 to line 10000.
10020 DEF PROC fromZX file$
LOCAL line$
CLS #
PRINT "fromZX (system 1)"''
10030 IF NOT FSTAT(file$,1)
PRINT "File not found"
STOP
ELSE
IF FSTAT(file$,3)<>10
PRINT "Wrong file type"
STOP
END IF
END IF
CLOSE #4
OPEN #4;file$IN
10040 SCROLL CLEAR
DO UNTIL EOF 4
INPUT #4; LINE line$
PRINT line$
LET line$=line$( TO 4)+" REM"+" ZX"+line$(6 TO )
10050 KEYIN line$
10060 LOOP
SCROLL RESTORE
CLOSE #4
10070 ALTER (CHR$ 183+"ZX") TO ""
REM remove all fake "REM"
10080 END PROC
10090 DEF PROC d
DELETE TO VAL "9999"
END PROC
10100 DEF PROC r
RENUM 1e4 TO LINE 1e4
END PROC
10110 DEF PROC s
d
r
SAVE OVER "fromZX_1"
END PROC
fromZX (system 2)
En MasterBASIC y Master DOS para SAM Coupé:
1>REM fromZX (system 2)
Part of the tool 'fromZXtoSAM'.
Copyright (C) 2011 Marcos Cruz (programandala.net)
License
programandala.net/license
Changelog
2011-03-25 First version, based on fromZX (system 0).
2 DEF PROC fromZX file$
LOCAL line$,red,green,lineInk
LET red=2,green=4,lineInk=green
CLS #
PRINT "fromZX (system 2)"''
IF NOT FSTAT(file$,1)
PRINT "File not found"
ELSE
IF FSTAT(file$,3)<>10
PRINT "Wrong file type"
END IF
END IF
CLOSE #4
OPEN #4;file$IN
3 DO UNTIL EOF 4
INPUT #4; LINE line$
ON ERROR fromZXmistake
4 KEYIN line$
5 ON ERROR STOP
PRINT PEN lineInk;line$
LET lineInk=green
LOOP
CLOSE #4
END PROC
6 DEF PROC fromZXmistake
LET line$=line$( TO 4)+" REM MISTAKE "+line$(6 TO )
7 KEYIN line$
8 LET lineInk=red
END PROC
9 DEF PROC s
DELETE 1e1 TO
RENUM LINE 1 STEP 1
SAVE OVER "fromZX_2"
END PROC
fromZX (system 3)
En MasterBASIC y Master DOS para SAM Coupé:
10000 REM fromZX (system 3)
Part of the tool 'fromZXtoSAM'.
10010 REM Copyright (C) 2011 Marcos Cruz (programandala.net)
10020 REM License
programandala.net/license
10030 REM Changelog
10040 REM 2011-03-29 First version, based on fromZX (system 0)
10050 DEF PROC fromZX file$
10060 LOCAL line$,red,green,lineInk
10070 DEFAULT file$="test.l"
REM debug!!!
10080 LET red=2,green=4,lineInk=green
10090 CLS #
PRINT "fromZX"''
10100 IF NOT FSTAT(file$,1) THEN PRINT "File not found"
STOP
10110 IF FSTAT(file$,3)<>10 THEN PRINT "Wrong file type"
STOP
10120 CLOSE #4
OPEN #4;file$IN
10130 DO UNTIL EOF 4
10140 INPUT #4; LINE line$
10150 ON ERROR GO TO 10160
KEYIN line$
ON ERROR STOP
GO TO 10170
10160 ON ERROR STOP
LET line$=line$( TO 4)+" REM MISTAKE "+line$(6 TO )
KEYIN line$
LET lineInk=red
10170 PRINT PEN lineInk;line$
LET lineInk=green
10180 LOOP
10190 CLOSE #4
10200 END PROC
10210 DEF PROC d
DELETE TO VAL "9999"
END PROC
10220 DEF PROC r
RENUM 1e4 TO LINE 1e4
END PROC
10230 DEF PROC s
d
r
SAVE OVER "fromZX_3"
END PROC
fromZX (system 4)
En MasterBASIC y Master DOS para SAM Coupé:
1>REM fromZX (system 4)
Part of the tool 'fromZXtoSAM'.
Copyright (C) 2011 Marcos Cruz (programandala.net)
License
programandala.net/license
Changelog
2011-03-29 First version, based on fromZX (system 2).
2 DEF PROC fromZX file$
LOCAL line$,red,green,lineInk
LET red=2,green=4,lineInk=green
CLS #
PRINT "fromZX (system 4)"''
IF NOT FSTAT(file$,1)
PRINT "File not found"
ELSE
IF FSTAT(file$,3)<>10
PRINT "Wrong file type"
END IF
END IF
CLOSE #4
OPEN #4;file$IN
3 DO UNTIL EOF 4
INPUT #4; LINE line$
ON ERROR GO TO 5
4 KEYIN line$
ON ERROR STOP
GO TO 6
5 ON ERROR STOP
LET line$=line$( TO 4)+" REM MISTAKE "+line$(6 TO )
KEYIN line$
LET lineInk=red
6 PRINT PEN lineInk;line$
LET lineInk=green
LOOP
CLOSE #4
END PROC
7 DEF PROC s
DELETE 1e1 TO
RENUM LINE 1 STEP 1
SAVE OVER "fromZX_4"
END PROC
TOr
En Sinclair BASIC y Beta DOS para ZX Spectrum:
1 REM TOr:Part of the tool 'fromZXtoSAM':Copyright (C) 2011 Marcos Cruz (programandala.net):License http://programandala.net/license
2 REM Changelog: 2011-03-27 First version.
3 DEF FN w$(f$)=f$( TO LEN f$-VAL "2"*(LEN f$>8)): CLS #: PRINT INK 7;" ": PRINT "TOr"'': INPUT "Program to export"'f$: LET l=LEN f$: LET f$=f$(1 TO l*(11 > l)+10*(l > 10)): LET l=LEN f$: POKE VAL "16384",l: FOR n=SGN PI TO l: POKE VAL "16384
"+n,CODE f$(n): NEXT n: PRINT "Merging '";f$;"'...": MERGE d*;f$: LET l=PEEK VAL "16384": LET f$="**********"( TO l): FOR n=1 TO l: LET f$(n)=CHR$ PEEK (VAL "16384"+n): NEXT n
4 LET r$=FN w$(f$)+".r": PRINT "Creating '";r$;"'...": CLOSE #*: OPEN #4;d*;r$ OUT : LIST #4,10: CLOSE #*
5 PRINT "Done!"''"Now load the Beta BASIC"'"program 'toSAM' and execute"'"the following command:"''" rTOl """;f$;"""": STOP
6 CLEAR : SAVE OVER d*"TOr": STOP : REM THIS LAST LINE MUST BE LOWER THAN 10
Descargas
La imagen de disquete en formato MGT es válida tanto para Beta DOS como para Master DOS. Lo único a tener en cuenta es:
- El fichero MDOS+MBAS contiene MasterBASIC y Master DOS para SAM Coupé; debe ser siempre el primer fichero del disco, para que la SAM Coupé lo encuentre.
- Ambos sistemas operativos tras arrancar intentan cargar el primer fichero cuyo nombre empiece por «auto» (sin distinguir mayúsculas de minúsculas). Para distinguirlos, he llamado a uno AutoZX y al otro AutoSAM. El primero en el directorio es AutoZX, para que la ZX Spectrum, más incómoda de arrancar a mano, ponga en marcha ella sola el entorno Beta BASIC tras cargarse el sistema operativo de disco. Pero la SAM Coupé intentará cargarlo también y lógicamente dará error; por tanto el programa AutoSAM hay que cargarlo manualmente (no es imprescindible, solo ajusta algunas variables del sistema y carga el programa principal).
- En cuanto a la descripción de los ficheros al listar el contenido del disquete: Beta DOS mostrará los ficheros de SAM Coupé como de tipo desconocido (con «WHAT?»), lo que es normal. Master DOS sin embargo sí listará correctamente el tipo de los ficheros creados en la ZX Spectrum.
Para ZX Spectrum, el disquete contiene:
- Beta DOS 1.3 (1990), corregido con los programas Betafix publicados en las publicaciones Format (número 9/9, de 1996-05) y Outlet (número 132, de 1998).
- Beta BASIC 4.0+D (1987), para ZX Spectrum 128 con interfaz +D.
- Fichero de inicio AutoZX, que carga el cargador de Beta BASIC, que a su vez carga el programa toSAM.
- Programa toSAM.
- Programa TOr.
Para SAM Coupé, el disquete contiene:
- MasterBASIC 1.7 (>1990) combinado con Master DOS 2.3 (1990).
- Fichero de inicio AutoSAM (y su auxiliar Init que configura algunas variables del sistema).
- Programas fromZX_0, fromZX_1, fromZX_2, fromZX_3 y fromZX_4, correspondientes a las variantes susodichas.
- Cargador fromZX, que carga fromZX_3.
También incluyo algunos de los programas usados para hacer las pruebas de importación, tanto en su formato original como en forma de listado en un fichero «.l» de tipo OPENTYPE.
Disquete:
- fromzxtosam.mgt.zip (183.15 KiB) Imagen de disquete comprimida con zip.
- fromzxtosam.mgt.gz (183.50 KiB) Imagen de disquete comprimida con gzip.