fromZXtoSAM

Descripción del contenido de la página

Utilidad para intentar pasar programas en BASIC desde una ZX Spectrum a una SAM Coupé.

Etiquetas:

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:

  1. Un programa exportador en Beta BASIC, (toSAM), que se mezcla con el programa que queremos exportar y mediante LIST y SHIFT$() crea, en dos pasos, un listado en forma de texto en un fichero de datos en el disquete.
  2. 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 con ON ERROR y los soluciona añadiendo REM 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:

  1. 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.
  2. 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:

Directorio en ZX SpectrumDirectorio en SAM Coupé

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:

fromZX

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.

Error en fromZX

Segundo ejemplo de importación fallida con fromZX (system 0)

Error final de la prueba de importación del código de Dictador:

Error en fromZX (system 0)

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:

fromZX (system 0)

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:

Error en fromZX (system 0)

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):

fromZX (system 2)fromZX (system 2)

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:

fromZX (system 3)fromZX (system 4)

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:

Para ZX Spectrum, el disquete contiene:

Para SAM Coupé, el disquete contiene:

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:

Páginas relacionadas

MBim
Utilería para desarrollo cruzado en MasterBASIC con SimCoupe.