llist2BBim

Descripción del contenido de la página

Programa escrito en Vim para convertir al formato BBim un listado de un programa escrito en Beta BASIC.

Etiquetas:

llist2BBim es un programa escrito en Vim cuya función es convertir un listado de Beta BASIC en otro en formato BBim. Lo escribí para facilitar la migración al nuevo formato de varios proyectos en desarrollo, como La legionela del pisto e Inebriated Day.

El listado original en Beta BASIC

El listado del código fuente en Beta BASIC puede obtenerse fácilmente desde el propio intérprete de Beta BASIC, con los comandos LIST FORMAT 2 y LLIST, en un emulador de ZX Spectrum que redirija la salida de impresora a un fichero de texto del sistema anfitrión. Fuse y otros muchos emuladores ofrecen esa funcionalidad.

Probablemente, en el listado obtenido de esta manera las líneas que tengan más de ochenta caracteres estarán partidas, debido al controlador de impresora. En teoría es posible evitar esto (hay una variable del sistema en Beta BASIC para esto, pero no he logrado que surta efecto). Por tanto, antes de hacer la conversión, habrá que buscar y volver a juntar las líneas de código que tengan más de ochenta caracteres.

En Vim la búsqueda puede hacerse fácilmente con la expresión ^.\{80}$.

Conversión a BBim

El programa en primer lugar crea una copia del fichero original y le añade la extensión .bbim. Después hace los siguientes cambios en él:

Conversión de palabras clave

Para facilitar la edición posterior del código, el conversor pasa a minúsculas todas las palabras clave de Beta BASIC y si es el caso las une en una sola palabra (por ejemplo, defproc en lugar de DEF PROC). En realidad pasa a minúsculas todas las palabras que estén escritas enteramente en mayúsculas, lo que puede afectar no solo a las palabras clave sino a los textos. Por ello es necesario una revisión manual posterior de los textos que estuvieran escritos en mayúsculas. Esto en la práctica no es un grave inconveniente. Sin embargo es posible que escriba un sistema más seguro para una futura versión del programa, que solo convierta las palabras clave, contenidas en una lista creada previamente.

Conversión de números de línea en etiquetas

El reto más interesante de la programación de llist2BBim fue convertir los números de línea originales en etiquetas, y después eliminar todas las que no se usaran en el programa.

La conversión no puede ser totalmente automática porque, antes de hacer la lista de las etiquetas usadas en el programa, es necesario que el programador marque como tales aquellos números de línea usados de forma no convencional en el código. llist2BBim solo detectará en el código los números de línea usados tras comandos habituales como GO TO, GO SUB, RESTORE... pero lógicamente si usamos números de línea dentro de expresiones o en líneas DATA, el conversor no podrá detectarlos.

Por eso, como el programa advierte cuando termina, es necesario hacer lo siguiente:

  1. Marcar manualmente como etiquetas aquellos números de línea que el conversor no haya detectado como tales. Para marcarlos hay que ponerles el signo «@» delante.
  2. Introducir en Vim el comando :call L2B_clean() para hacer la limpieza final de las etiquetas no utilizadas.

Código fuente

" llist2bbim.vim

" This program is part of the BBim toolkit.

" llist2BBim
" Copyright (C) 2011 Marcos Cruz (programandala.net)
" License: http://programandala.net/license

" This Vim program converts a Beta BASIC listing
" to BBim source code.

" The Beta BASIC listing can be obtained from Beta BASiC
" with LIST FORMAT 2 and LLIST,
" using a ZX Spectrum emulator that can redirect the printer
" output to a text file of the host platform.

" ------------------------------
" History

" 2011-08-31 First version.
" 2011-09-01 Renamed to llist2bbim.vim (formerly llist2bb.vim)
" 2011-09-02 Added the BBim syntax at the end; added "END PROC"
" 2011-09-07 Bug fixed: "END PROC" was converted to "defproc".
" 2011-09-10 Labels implemented. Code divided into functions.
" 2011-09-11 Indentation reformat implemented.
" 2011-09-29 Bug fixed: keywords with a "$" at the end were not changed to lowercase.
" 2011-09-30 "silent" command used everywhere; custom messages added.

" ------------------------------
" To-do

" Some ELSE were not properly joined
" (Search for "   else" to find them at the end).
" It has something to do with line length.
" Already solved?

" ------------------------------

function! L2B_file()

    " Create a copy of the current file,
    " with the extension '.bbim' added,
    " and open it for editing.

    silent update
    split
    silent write! %.bbim
    silent edit %.bbim
    echo 'BBIM file created.'

endfunction

function! L2B_splitted_lines()

    " Mark the splitted lines.

    " Join the lines splitted by the printer driver
    " (not perfect yet; manual check needed).
    " Deprecated. It has to be done manually.
    "%substitute_^\(.\{80}\)\n\s\{6}_\1_g

    " Put the semicolon and the backslash
    " in lines splitted by Beta BASIC:
    silent! %substitute_\n\(\s\{5,}\S\)_:\\\r\1_
    " But remove them when used just to apart REMs:
    "%substitute_^\(.\{5}\):\\\n\s\{5}REM_\1REM_
    silent! %substitute_^\(\s*\d\+\s\+\):\\\n\s\+REM_\r\1//_

    echo 'Splitted lines marked.'

endfunction

function! L2B_comments()

    " Convert comments.

    " Move the REM at the top of the commented line
    " (unfinished; doesn't work yet):
    ":%s_^\(\s*\d\+\s\+\)\(.\+\)\(^\s\+REM\)\(.\+$\)_\r\s\{5}//\3\r\1\2_

    " Simpler alternative;
    " the comment stays at the end of the line:
    silent! %substitute_:\\\n\(\s\+\)REM \(.\+\)$_\r\1// \2\r_

    " Change all remaining REMs:
    silent! %substitute_REM _// _

    echo 'Comments converted.'

endfunction

function! L2B_keywords()

    " Make keywords compact and lowercase.

    " Make some keywords compact and lowercase:
    silent! %substitute.\<DEF FN\>.deffn.g
    silent! %substitute.\<DEF PROC\>.defproc.g
    silent! %substitute.\<END PROC\>.endproc.g
    silent! %substitute.\<DEF KEY\>.defkey.g
    silent! %substitute.\<GO TO\>.goto.g
    silent! %substitute.\<GO SUB\>.gosub.g

    " Make the rest of keywords lowercase
    :silent! %substitute.\<\([A-Z]\+\$?\)\>.\L\1\E.g

    " Note: Of course any uppercase word will be modified,
    " not only  keywords. A safer method may be
    " programmed in the future, with a list of keywords.

    echo 'Keywords converted.'

endfunction

function! L2B_labels()

    " Convert line numbers into labels.

    " Line numbers before a comment remain on the same text line:
    silent! %substitute_^\s*\(\d\{1,4}\s\//\)_@\1_
    " The rest is splitted and marked as such:
    silent! %substitute_^\s*\(\d\{1,4}\s\)_@\1\\\r_

    " Change the most common line number references:
    silent! %substitute_\<\(goto\|gosub\|restore\|line\|renum\|renum to\)\s\+\(\d\+\)_\1 @\2_g
    " Note: There are other cases where line numbers are used,
    " e.g. "on x gosub". Those have to be changed by hand.

    echo 'Line numbers converted to labels.'

endfunction

function! L2B_clean()

    " Remove all unused labels.
    " Check and test!!!

    " Note: This function has to be called 
    " after having manually searched the code
    " for the line numbers not detected by the program
    " and having added the '@' prefix to them.

    " Make a list for the used line numbers:
    let l:usedLineNumbers=[]
    " Go to the end of line:
    normal gg
    " Search and store every line number used in the code:
    while search('^\@![,=]\?\s*@\d\{1,4}',"We")
        " Copy the line number into the 'l' register:
        normal b"lyww
        " Debug!!!
        "echo 'Found' getline('.')
        " Remove possible duplicated matchs in the list:
        call filter(l:usedLineNumbers,'v:val !='.getreg('l',1))
        " Store the line number into the list:
        call add(l:usedLineNumbers,getreg('l',1))
    endwhile

    " Debug!!!
    "echo 'used line numbers:' l:usedLineNumbers

    " Hide the used labels:
    for l:usedLineNumber in l:usedLineNumbers
        execute 'silent! %substitute_^@' . l:usedLineNumber . '\>_!' .  l:usedLineNumber . '_'
    endfor
    " Remove the unused labels:
    silent! %substitute.^@\d\{1,4} //.//. " Those before a comment
    silent! %substitute.^@\d\{1,4} \\\n.. " The rest
    " Unhide the used labels:
    silent! %substitute.^!.@.

    echo 'Useless labels removed.'

endfunction

function! L2B_indentation()

    " Change indentation to tabs.

    silent! %substitute.^\s\{5}..
    " Go to the start of the file:
    normal gg
    " Search and substitute doubles spaces
    " at the start of the line
    " (maybe located after optional tabs)
    " with a tab:
    while search('^\(\t\+\)\?  ','Wc')
        silent! substitute_^\(\t\+\)\?  _\1\t_g
        " Go to the very start of the line:
        normal 0
    endwhile

    echo 'Indentation converted to tabs.'

endfunction

" ------------------------------
" Main

function! L2B()

    " Create a BBim format source code
    " from a Beta BASIC LLISTing (in LLIST FORMAT 2).

    call L2B_file()
    call L2B_splitted_lines()
    call L2B_comments()
    call L2B_keywords()
    call L2B_labels()
    "call L2B_clean()
    call L2B_indentation()
    silent! write
    set syntax=bbim
    echo 'Done!'

endfunction

echo '--------------------------------------------------'
call L2B()
echo '--------------------------------------------------'
echo 'Now search the code for undetected line numbers,'
echo 'add the "@" prefix to them and finally give the'
echo 'command ":call L2B_clean()".'
echo '--------------------------------------------------'

Descargas

Todos los componentes de BBim pueden descargarse en la sección de descargas de BBim.