SBim

Descripción del contenido de la página

Utilidad para escribir programas para QL en SBim (formato mejorado de S*BASIC) con el editor Vim.

Etiquetas:

«SBim» significa «SuperBASIC improved», esto es, «SuperBASIC mejorado», Por una parte es un formato mejorado para escribir código en S*BASIC; por otra, es una utilería para Vim que facilita escribir en dicho formato y lo traduce a S*BASIC estándar, listo para ser interpretado.

El formato SBim

Aparte de la comodidad de trabajar con un editor tan potente y versátil como Vim, las mejoras que aporta el formato SBim en sí respecto al S*BASIC original son las siguientes:

Comentarios

El formato SBim proporciona tres nuevas opciones para comentarios:

Los comentarios originales (con el comando REMark) pueden seguir usándose, y se mantendrán en el programa final. Son útiles para indicar el autor del código fuente, la versión, la licencia de uso y poco más.

Comentarios de línea

La marca // puede estar en cualquier lugar de la línea (incluso dentro de cadenas o expresiones).

La marca, los espacios o tabuladores que la precedan y el resto de la línea a su derecha serán eliminados.

Comentarios de bloque

La marca de inicio /* debe estar al comienzo de una línea (opcionalmente con espacios o tabuladores previos). La marca de final */ puede estar en cualquier posición.

Todo lo que haya de una a otra marca será eliminado, y también los espacios o tabuladores que precedan a la marca de inicio.

Los comentarios de bloque no son anidables.

Metacomentarios de línea

Este es el tipo de comentario de mayor prioridad, el que primero se elimina del código.

El signo «#» debe ser el primero de la línea (opcionalmente con espacios o tabuladores previos).

La función de este tipo de comentarios es poder hacer anotaciones que se refieran al propio desarrollo del código, no a su funcionamiento, así como anular temporalmente de forma clara zonas de código que puedan contener los otros tipos de comentarios.

Líneas partidas

Una línea de código fuente puede ser dividida en más de una línea de texto. Habitualmente en los lenguajes de programación, para indicar que una línea de código fuente continúa en la siguiente línea de texto se emplea el signo de la barra inclinada hacia la izquierda («\»). Dado que en S*BASIC este signo es un separador de impresión, en las primeras versiones del código se optó por usar la barra vertical («|»). No obstante, como la barra inclinada hacia la izquierda es mucho más habitual y en la práctica los casos de ambigüedad son muy excepcionales y pueden resolverse fácilmente añadiendo dos puntos («:»), se decidió hacer el cambio.

La indentación de las líneas de texto segunda y siguientes de una línea de código dividida no es tenida en cuenta, será eliminada en la línea de código resultante. Pero los espacios antes del signo «\» sí se conservarán, y a menudo son imprescindibles, como muestra el siguiente ejemplo, en que también se ilustra el uso original de «\» como operador de impresión:

let \
  d=18871215
print\
  "Saluton, \
  mondo!":\
list
print\ \
  "Bonan matenon"
print\:
clear

El código anterior en formato SBim será convertido en el siguiente código en S*BASIC:

1 let d=18871215
2 print "Saluton, mondo!":list
3 print\"Bonan matenon"
4 print\:
5 clear

Etiquetas

SBim no usa números de línea; para hacer referencia a líneas del código se usan etiquetas.

Los nombres de las etiquetas deben empezar siempre por el signo de la arroba, tanto al definirlas como al referenciarlas. El resto de caracteres pueden ser letras del alfabeto inglés, dígitos o el signo de subrayado («_»), en cualquier orden o combinación. No se hace distinción entre minúsculas y mayúsculas. No hay longitud máxima para el nombre de una etiqueta (salvo la impuesta por el lenguaje de programación de Vim, cualquiera que sea).

Para definir una etiqueta basta que su nombre esté al comienzo de una línea de código (puede haber espacios o tabuladores antes):

gosub @rutina1
stop

@rutina1
  print "Rutina 1"
  @espera
  if not rnd then goto @espera
  return

Opcionalmente, para mayor claridad, si se prefiere puede usarse el comando label para definir las etiquetas:

gosub @rutina1
stop

label @rutina1
  print "Rutina 1"
  label @espera
  if not rnd then goto @espera
  return

Cualquier palabra que en el código fuente cumpla las condiciones para ser una etiqueta será tomada como tal, independientemente de su posición en el código. Esto permite incluir etiquetas dentro de cadenas o en cálculos, como haríamos con los propios números de línea:

print @rutina2+100*valor

Sin embargo eso puede tener efectos indeseados. Por ejemplo, dado el siguiente código:

label @blabla
print "Hola"
print "Mi correo-e es: superbasic@blablabla.info"
print "Y mi otro correo-e es: superbasic@blabla.info"

El resultado final en S*BASIC sería el siguiente, con una sustitución indeseada en la última línea:

2 print "Hola"
3 print "Mi correo-e es: superbasic@blablabla.info"
4 print "Y mi otro correo-e es: superbasic1.info"

Para evitar esas posibles coincidencias debe usarse algún medio de camuflar la falsa etiqueta, como en los ejemplos siguientes:

rem Arroba camuflada:
print "Y mi otro correo-e es: superbasic";chr$(64);"blabla.info"
rem Arroba separada:
print "Y mi otro correo-e es: superbasic@";"blabla.info"

Primer número de línea

Puede definirse el primer número de línea que se usará para renumerar el programa final, con el comando #firstline, que debe estar al inicio de cualquier línea del programa (los espacios o tabuladores previos no serán tenidos en cuenta):

#firstline 9000

Si hay más de un comando #firstline solo el primero será tenido en cuenta. Si no se usa este comando, el primer número de línea será el uno.

Inclusión de otros ficheros fuente

Es posible incluir otros ficheros fuente dentro del principal con la directiva #include:

#include dev1_inc_routine_sbim

Posibles mejoras

Entre las ideas consideradas para futuras versiones del formato SBim están las siguientes:

Instalación

En primer lugar, edítese CONFIG.sh, descomentando solo las opciones deseadas: directorio de instalación y método. Las instalación predeterminada se hace en el directorio del usuario mediante enlaces simbólicos.

A continuación, ejecútese INSTALL.sh.

Uso

Al editar ficheros con extensión «.sbim» o «_sbim» estará disponible el atajo de teclado ,sb (una coma seguida de una S y una B) para convertir el código en formato estándar de S*BASIC.

El resultado de ambos comandos será un fichero con el mismo nombre que el actual y en su mismo directorio, pero con la extensión _bas añadida. El uso recomendado es emplear la extensión _sbim para el código original. Así, el fichero resultante terminará en _sbim_bas. Cualquier configuración es posible modificando el código fuente o usando enlaces en el sistema anfitrión.

Código fuente

El fichero principal de SBim es el conversor de código:

" sbim.converter.vim
" (~/.vim/sbim.vim)

" This file is part of SBim
" http://programandala.net/es.programa.sbim.html

" ==============================================================
" Description

" This VimL program converts S*BASIC source code written in the
" SBim format to an ordinary S*BASIC file ready to be loaded by
" a S*BASIC interpreter.

" ==============================================================
" Author and license

" Author: Marcos Cruz (programandala.net), 2011,2012,2015,2016 

" You may do whatever you want with this work, so long as you
" retain the copyright/authorship/acknowledgment/credit
" notice(s) and this license in all redistributed copies and
" derived works.  There is no warranty.

" ==============================================================
" History

" See at the end of the file.

" ==============================================================
" Code

function! SBimRenum()

  " Put line numbers;
  " remove spaces from blank lines;
  " save the file.

  " Call the the nl program (part of the Debian coreutils package):
  execute ":silent %!nl --body-numbering=t --number-format=rn --number-width=5 --number-separator=' ' --starting-line-number=".s:firstLine." --line-increment=1"

  " In older versions of coreutils,
  " -v sets the first line number, and -i sets the line increment.
  " (the long option for -v doesn't work, though the manual mentions it).
  " Modern versions of nl uses the clearer options
  " --first-line and --line-increment, see:
  " http://www.gnu.org/software/coreutils/manual/coreutils.html#nl-invocation

  " Remove all spaces from lines that only contain spaces:
  ":%s/^\s\+$//

  " Remove spaces before line numbers
  "(nl has no option to remove them):
  silent %substitute/^\s*//e

  echo 'Line numbers added.'

endfunction

function! SBimClean()

  silent %s,\t\+, ,ge " Remove tabs
  echo 'Tabs removed.'

  silent %s,^\s*#.*$,,e " Remove the # line metacomments
  silent %s,\s*\/\/.*$,,e " Remove the // line comments
  silent %s,^\s*\/\*\_.\{-}\*\/,,e " Remove the /* */ block comments

  echo 'Comments removed.'

  silent %s,^\s*\n,,ge " Remove the empty lines

  echo 'Empty lines removed.'

  "silent %s,^\s*,,e " Remove indentation
  "silent %s,\s\+$,,e " Remove ending blanks
  silent %s,^\s*\(.\+\)\s*$,\1,e " Remove blanks

  echo 'Indentation and blanks removed.'

  " old format (vertical bar to split the lines):
  " silent %s,|\n,,e
  " Join the splitted lines (the vertical bar is used, because
  " the backslash is a printing separator in S*BASIC)

  " new format (backslash to split the lines):
  silent %s,\\\s*\n,,e " Join the splitted lines 

  echo 'Splitted lines joined.'

endfunction

function! SBimConfig()

  call SBimGetFirstLine()

endfunction

function! SBimGetFirstLine()

  " Store into s:firstLine the first line number
  " to be used by the final S*BASIC program
  " The command #firstline can be used to set
  " the desired line number. Only the first occurence
  " of #firstline will be used; it can be anywhere
  " in the source but alwayl at the start of a line
  " (with optional indentation).

  let s:firstLine=1 " default value

  " Go to the top of the file:
  normal gg
  if search('^\s*#firstline\s\+[0-9]\+\>','Wc')
    " Store the number into register 'l':
    normal ww"lyw
    " And then into the variable:
    let s:firstLine=getreg('l',1)
  endif
  echo 'First line number: '.s:firstLine

endfunction

function! SBimInclude()

  " Execute all '#include' directives.

  " Syntax:
  " #include filename

  " Warning: nested including is possible, but no recursion check is made!

  call cursor(1,1) " Go to the top of the file.
  let l:includedFiles=0 " Counter
  while search('^\s*#include\s\+','Wc')
    let l:includedFiles += 1
    let l:filename=matchstr(getline('.'),'\S\+.*',8)
    call setline('.','// <<< start of included file '.l:filename)
    call append('.','// >>> end of included file '.l:filename)
    let l:filecontent=readfile(s:sourceFileDir.'/'.l:filename)
    call append('.',l:filecontent)
  endwhile

  if l:includedFiles==0
    echo 'No file included'
  elseif l:includedFiles==1
    echo 'One file included'
  else
    echo l:includedFiles 'files included'
  endif

endfunction

function! SBimLabels()

  " Translate the line labels.

  " Join lonely labels to the next line:
  silent! %substitute,^\s*\(\(label\s\+\)\?@[0-9a-zA-Z_]\+\)\s*\n,\1:,ei

  " Create an empty dictionary to store the line numbers of the
  " labels; the labels will be used as keys:
  let l:lineNumber={}
  " Go to the top of the file:
  normal gg
  " Store every label into the dictionary:
  while search('\(^\|:\)\s*\(label\s\+\)\?@[0-9a-zA-Z_]\+\>','Wc')
    " Store the label in the 'l' register:
    normal "l2yw
    " Debug message:
    " echo 'Raw label found: <' . getreg('l',1) . '>'
    " If the label is the second one in a line, remove the semicolon:
"     if stridx(getreg('l',1),':')==0
"      call setreg('l',strpart(getreg('l',1),1))
"    endif
    " If 'label' is present, go to the next word and repeat:
    if tolower(getreg('l',1))=='label @'
      normal w"l2yw
      " Debug message:
      " echo 'Actual raw label found: <' . getreg('l',1) . '>'
    endif
    " Remove possible ending spaces:
    let l:label=tolower(substitute(getreg('l',1),' ','','g'))
    " Debug message:
    "echo 'Clean label: <' . l:label . '>'
    " Use the label as the key to store the line number:
    let l:lineNumber[l:label]=line('.')+s:firstLine-1
    " Go to the next word:
    normal w
  endwhile

  " Debug message:
  "echo l:lineNumber

  " Remove the label definitions:
  silent! %substitute/^\s*\(label\s\+\)\?@[0-9a-zA-Z_]\+\s*:\?\s*//ei

  " Substitute every label reference with its line number:
  for l:label in keys(l:lineNumber)
    " Go to the top of the file:
    normal gg
    " Debug message:
    "echo 'About to translate label '.l:label
    " Do the subtitution:
    while search(l:label,'W')
      " Debug message:
      "echo 'Label '.l:label.' found'
      "execute "silent! substitute,".l:label."\\>,".l:lineNumber[l:label].","
      silent! execute "substitute,".l:label."\\>,".l:lineNumber[l:label].","
      " Debug message:
      "echo l:label.' --> '.l:lineNumber[l:label]
    endwhile
  endfor

  echo 'Labels translated.'

endfunction

function! SBimBASfile()

  " Create a copy of the current SBim file
  " with the "_bas" extension added
  " and open it for editing.


  " Filename of the source file, without path
  "let s:sourceFilename=fnamemodify(expand('%'),':t')

  " Absolute directory of the source file
  let s:sourceFileDir=fnamemodify(expand('%'),':p:h')

  silent update " Write the current SBim file if needed
  split " Split the window
  silent write! %_bas " Save a copy with the _bas extension added
  silent edit %_bas " Open it for editing
  set fileencoding=latin1
  set fileformat=unix " Force NL (char 10) as end of line

  echo 'S*BASIC file created.'

endfunction

function! SBim2SB()

  let s:ignoreCaseBackup=&ignorecase
  set ignorecase

  call SBimBASfile()
  call SBimInclude()
  call SBimConfig()
  call SBimClean()
  call SBimLabels()
  call SBimRenum()

  silent w
  silent bw
  echo 'S*BASIC file saved and closed.'

  if s:ignoreCaseBackup
    set ignorecase
  else
    set noignorecase
  endif

  echo 'Done!'

endfunction

" Shortkey ',sb' in normal mode
" to create an S*BASIC file:
nmap <silent> ,sb :call SBim2SB()<CR>

" ==============================================================
" History

" 2011-08-13: First version, named sb2sbasic.vim, based on
" vim2mb.vim ("Vim to MasterBASIC"), by the same author. [vim2mb
" was the origin of MBim].
"
" 2011-08-16: Added removing of blanks (tabs or spaces) at the
" end of lines; added start line parameter for renumbering;
" created alternative shortcut key to create boot files.
"
" 2011-08-25: Added C style comments, block and inline.
"
" 2011-09-01: Renamed to sbim2bas.vim; own renum function
" instead of using that of line_numbers.vim; all functions
" renamed with the "SBim" prefix.
"
" 2011-09-26: Renamed to sbim2sb.vim; some functions renamed;
" some comments improved.
"
" 2011-10-04: Block comments fixed with '\{-}'; 'silent' added
" to many commands; 'e' flag added to substitutions; custom
" messages added.
"
" 2012-01-25: New function SBimLabels(), based on BBimLabels()
" from BBim.  Fixed: lonely labels had to be joined with the
" next line; optional final ":" removed with labels.
"
" 2012-01-26: The character to split lines now is backslash
" instead of the vertical bar.
"
" 2012-01-28: Improvement: labels are not case sensitive any
" more.
"
" 2012-01-28: New feature: #firstline command to define the
" first line that will be used to renumber the final program in
" S*BASIC.
"
" 2012-01-28: Improvement: The S*BASIC buffer is actually closed
" with "bw" ("wq" kept it on the list).
"
" 2012-01-29: Improvement: Only one regex, simpler and fixed, to
" remove empty lines (the old three regex left the first line of
" the file blank).
"
" 2012-01-29: Fixed: Spaces or tabs at the end of line, after
" the split bar, are ignored.
"
" 2012-02-01: Bug found. The label translation loop doesn't end
" in some cases.
"
" 2012-02-15: Fixed? The 'c' parameter was removed from search()
" in the label translation loop.
"
" 2015-12-26: Changed the layout of the source. Renamed the
" program to "SBim".  Changed the license. 
"
" 2016-01-13: Fixed `SBimGetFirstLine()`: the directive was
" yanked instead of the line number.
"
" 2016-01-19: Typo. Updated header.
"
" 2016-01-25: Added `#include` directive.

" vim: textwidth=64:ts=2:sw=2:sts=2:et

Descargas

También puedes descargar SBim en GitHub.

Páginas relacionadas

SuperBASIC Vim syntax file
Fichero de Vim para colorear código en SuperBASIC o SBASIC.
MBim
Utilería para desarrollo cruzado en MasterBASIC con SimCoupe.
BBim
Utilería para escribir programas para ZX Spectrum en BBim (formato mejorado de Beta BASIC) con el editor Vim.