BBim2BB
Descripción del contenido de esta página
Programa escrito en Vim para convertir al formato estándar de Beta BASIC un código fuente de formato BBim.
Este programa escrito en Vim es el corazón de BBim: a partir del código fuente original en formato BBim crea dos ficheros que podrán ser importados por BBimport:
- Con extensión .bb: Fichero de texto con código fuente en Beta BASIC listo para ser añadido a una imagen de disquete MGT e importado con BBimport 2.
- Con extensión .bb.mgt: Falsa imagen de disquete MGT, para ser leída por BBimport 4.
Listado
" bbim2bb.vim
" BBim2BB
" Copyright (C) 2011,2012 Marcos Cruz (programandala.net)
" License:
" http://programandala.net/license
" This file is part of BBim:
" http://programandala.net/es.programa.bbim
" This program, written in Vim, converts BBim source code
" into an actual Beta BASIC program
" ready to be imported into a ZX Spectrum emulator
" by BBimport.
" Note:
" This file **must** use the Latin1 (ISO-8859 1) encoding.
" ------------------------------
" History
" 2011-08-30: First draft version, based on vim2mb.vim, by the same
" author.
" 2011-08-31: Some improvements, based on sb2sbsasic,vim, by the same
" author.
" 2011-09-01: Renamed to bbim2bb.vim (formerly bb2bbmgt.vim);
" rearranged, based on mbim2mb.vim.
" 2011-09-10: Labels implemented.
" 2011-09-29: Labels checked and finished; renumbering added;
" BBimTokens().
" 2011-09-30: "silent" command used everywhere; custom messages added.
" 2012-01-25: BBimLabels() fixed: lonely labels had to be joined with
" the next line; optional final ":" removed with labels. These fixes
" were first coded for SBim's SBimLabels().
" 2012-01-27: Fixed the greedy subtitution of block comments.
" 2012-01-28: New feature: import-time commands (marked with a
" semicolon at the start of their lines); their line number is removed.
" 2012-01-28: New feature: #firstline command to define the first line
" that will be used to renumber the final program in Beta BASIC.
" 2012-01-28: Improvement: labels are not case sensitive any more.
" 2012-01-28: Improvement: The .BB and .BB.MGT buffers are actually
" closed with "bw" ("wq" kept them on the list).
" 2012-02-16: Fixed?: "c" parameter removed from the search() in
" BBimLabels(). It caused problems in SBim, the parallel project.
" 2012-03-05: New experimental metacommands (not used yet): #define and
" #substitution.
" 2012-03-05: New metacommands: #vim and #include.
" 2012-03-06: Changed all "normal gg" to "call cursor(1,1)".
" 2012-03-06: BBimInclude() fixed: the filename is get from the current
" line with functions instead of normal-mode register commands, because
" normal-mode cursor movement commands depend on the iskeyword
" variable, what depends on the current syntax: the movement is
" different in the .bbim an the .bbim.bb files.
" 2012-03-08 Clearer substitutions with nr2char() instead inline bytes.
" Added the conversion of embedded bytes (in BASin format: \#nnn).
" ------------------------------
" To-do
" Make it possible to write
" several programs in the same BBim source file:
" they would be renumbered apart but exported together
" into one single MGT image, and then imported
" and divided with one single operation.
" ----------------------------------------------
function! BBimClean()
" Clean off all BBim stuff.
silent! %s/^\s*#.*$//e " Remove the metacomments
silent! %s/\s*\/\/.*$//e " Remove the // line comments
silent %s,^\s*\/\*\_.\{-}\*\/,,e " Remove the /* */ block comments
silent! %s/^\s*\d\+\s*$//e " Remove lines with the line number only
" 2012-01-29 Old!!!:
"silent! %s/^\s\+//e " Remove empty lines
"silent! %s/\n\n\+/\r/eg " Remove empty lines
" 2012-01-29 New, untested!!!:
silent! %s/^\n//e " Remove empty lines
silent %s,^\s*\n,,ge " Remove the empty lines
silent! %s/^\s*//eg " Remove main indentation
silent! %s/\s\+$//eg " Remove ending blanks
silent! %s/\\\s*\n//e " Join the splitted lines
silent! %s/^\(\d\+\)\s\+/\1/e " Remove the space after the line number
" Experimental, not implemented yet:
"silent! %s/^\s*endprog\s\+\([a-zA-Z_-]\+\)/save d*"\1"line 10:delete 10 to/e
echo 'Source code cleaned.'
endfunction
" ----------------------------------------------
" Metacommands
function! BBimDefine()
" Experimental!!! Not used yet. BBimVim() can do this and more.
" Execute all #define metacommands.
" Syntax:
" #define regexp new_content
" Empty dictionary to store the substitutions:
let l:substitution={}
call cursor(1,1) " Go to the top of the file.
" Main loop:
while search('^\s*#define\s\+\S\+\>','Wc')
" Store the parameters into register 'p':
normal w"py$
" Copy to a variable:
let l:parameters=getreg('p',1)
let l:new=matchstr(l:parameters,'\S\+$')
" debug!!!
"echo 'parameters='.l:parameters
let l:old=matchstr(l:parameters,'^\S\+')
let l:new=matchstr(l:parameters,'\S\+$')
" debug!!!
"echo 'old='.l:old
let l:new=matchstr(l:parameters,'\S\+$')
" debug!!!
"echo 'new='.l:new
" Store them into the dictionary:
let l:substitution[l:old]=l:new
" Remove the whole line:
normal dd
endwhile
" Do all substitutions:
for l:old in keys(l:substitution)
" debug!!!
"echo 'Searching...'.l:old
call cursor(1,1) " Go to the top of the file.
" Do the subtitution:
while search(l:old,'Wc')
" Debug!!!
'echo l:old 'label reference found'
execute 'silent! substitute/'.l:old.'/'.l:substitution[l:old].'/ei'
endwhile
endfor
endfunction
function! BBimSubstitute()
" Experimental!!! Not used yet. BBimVim() can do this and more.
" Execute all #substitute metacommands.
" The #substitute's syntax is identical to Vim's substitute command,
" but no range or flags can be indicated.
" No syntax check is done.
" If the #substitute command is not recognized,
" it will be part of the Beta BASIC code and will fail at importing-time.
" If the #substitute command's syntax is not fine,
" it will fail at translation-time.
" Examples:
" #substitute/first_element/second_element/
" #substitute,first_element,second_element,
" Empty list to store the substitutions:
let l:substitution=[]
call cursor(1,1) " Go to the top of the file.
" Get all substitutions:
while search('^\s*#substitute[[:punct:]]','Wc')
" Store the parameters into register 's':
normal w"sy$
" Debug!!!:
"echo getreg('s',1)
" Store them into the list:
call add(l:substitution,getreg('s',1))
" Remove the whole line:
normal dd
endwhile
" Debug!!!:
"echo l:substitution
" Do all substitutions:
for l:item in l:substitution
execute 'silent! %substitute'.l:item.'eg'
endfor
endfunction
function! BBimVim()
" Execute all #vim metacommands.
" Syntax:
" #vim Any-Vim-Ex-Command
call cursor(1,1) " Go to the top of the file.
while search('^\s*#vim\s','Wc')
let l:vimCommandLine = line('.')
let l:vimCommand=matchstr(getline(l:vimCommandLine),'\S\+.*',4)
execute 'silent! '.l:vimCommand
call cursor(l:vimCommandLine,1) " Return to the command line.
call setline('.','') " Blank the line.
endwhile
echo 'Vim commands executed.'
endfunction
function! BBimInclude()
" Execute all #include commands in the source.
" Syntax:
" #include file-name
" Warning: nested including is possible, but no recursion check is made!
call cursor(1,1) " Go to the top of the file.
while search('^\s*#include\s','Wc')
let l:fileName=matchstr(getline('.'),'\S\+.*',8)
call setline('.','') " Blank the line.
" ----------- debug!!!
"echo '#include ' l:fileName
"echo 'getcwd()=' getcwd()
"echo 'Modificaciones:'
"echo ':~' fnamemodify(l:fileName,':~')
"echo ':p' fnamemodify(l:fileName,':p')
" -----------
execute "silent! r ".l:fileName
endwhile
echo 'Files included.'
endfunction
" ----------------------------------------------
" Labels
function! BBimGetFirstLine()
" Store into s:firstLine the first line number
" to be used by the final Beta BASIC program
" (old versions of BBimport occupied lines 1-9).
" 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 always at the start of a line
" (with optional indentation).
let s:firstLine=1 " default value
call cursor(1,1) " Go to the top of the file.
if search('^\s*#firstline\s\+[0-9]\+\>','Wc')
" Store the number into register 'l':
normal w"lyw
" And then into the variable:
let s:firstLine=getreg('l',1)
endif
echo 'First line number: '.s:firstLine
endfunction
function! BBimLabels()
" Join lonely labels to the next line:
silent %substitute,^\s*\(\(label\s\+\)\?@[0-9a-zA-Z_]\+\)\s*\n,\1:,ei
" Empty dictionary to store the line numbers of the labels; the labels will be used as keys:
let l:lineNumber={}
call cursor(1,1) " Go to the top of the file.
" Store every label in the l:lineNumber dictionary:
while search('^\s*\(label\s\+\)\?@[0-9a-zA-Z_]\+\>','W')
" Store the label into register 'l':
normal "l2yw
" Debug!!!
"echo 'Raw label found: <' . getreg('l',1) . '>'
" If 'label' is present, go to the next word and repeat:
if tolower(getreg('l',1))=='label @'
normal w"l2yw
" Debug!!!
"echo 'Actual raw label found: <' . getreg('l',1) . '>'
endif
" Remove possible ending spaces:
let l:label=tolower(substitute(getreg('l',1),' ','','g'))
" Debug!!!
"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!!!
"echo l:lineNumber
" Remove all labels:
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)
call cursor(1,1) " Go to the top of the file.
" Do the subtitution:
while search(l:label,'Wc')
" Debug!!!
"echo l:label "label reference found"
execute "silent! substitute/".l:label."\\>/".l:lineNumber[l:label]."/ei"
endwhile
endfor
echo 'Labels translated.'
endfunction
" ----------------------------------------------
" Renum
function! BBimRenum()
" 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 spaces before line numbers
" (nl has no option to remove them):
silent! %substitute/^\s*//e
" Remove line numbers from import-time commands
silent! %substitute/^[0-9]\{1,4}\s://e
echo 'Line numbers added.'
endfunction
" ----------------------------------------------
" Character translation
function! BBimTokens()
" Translate special tokens into its ZX Spectrum code.
silent! %s/<=/\=nr2char(199)/eg
silent! %s/>=/\=nr2char(200)/eg
silent! %s/<>/\=nr2char(201)/eg
endfunction
function! BBimISOchars()
" Translate ISO-8859 1 chars into ZX Spectrum chars.
" (Unfinished).
" The occupied chars must be redefined
" by the final Beta BASIC program,
" so this function must be customized ad hoc.
" silent! %s/¡/\=nr2char(000)/ge
" silent! %s/¿/\=nr2char(000)/ge
" silent! %s/Á/\=nr2char(000)/ge
" silent! %s/É/\=nr2char(000)/ge
" silent! %s/Í/\=nr2char(000)/ge
" silent! %s/Ñ/\=nr2char(000)/ge
" silent! %s/Ó/\=nr2char(000)/ge
" silent! %s/Ú/\=nr2char(000)/ge
" silent! %s/Ü/\=nr2char(000)/ge
" silent! %s/á/\=nr2char(000)/ge
" silent! %s/é/\=nr2char(000)/ge
" silent! %s/í/\=nr2char(000)/ge
" silent! %s/ñ/\=nr2char(000)/ge
" silent! %s/ó/\=nr2char(000)/ge
" silent! %s/ú/\=nr2char(000)/ge
" silent! %s/ü/\=nr2char(000)/ge
endfunction
function! BBimBlockGraphs()
" Translate BASin format ZX Spectrum block graphics notation
" (chars 128-143)
silent! %s/\\ /\=nr2char(128)/ge
silent! %s/\\ '/\=nr2char(129)/ge
silent! %s/\\' /\=nr2char(130)/ge
silent! %s/\\''/\=nr2char(131)/ge
silent! %s/\\ \./\=nr2char(132)/ge
silent! %s/\\ :/\=nr2char(133)/ge
silent! %s/\\'\./\=nr2char(134)/ge
silent! %s/\\':/\=nr2char(135)/ge
silent! %s/\\\. /\=nr2char(136)/ge
silent! %s/\\\.'/\=nr2char(137)/ge
silent! %s/\\: /\=nr2char(138)/ge
silent! %s/\\:'/\=nr2char(139)/ge
silent! %s/\\\.\./\=nr2char(140)/ge
silent! %s/\\\.:/\=nr2char(141)/ge
silent! %s/\\:\./\=nr2char(142)/ge
silent! %s/\\::/\=nr2char(143)/ge
endfunction
function! BBimUDG()
" Translate BASin format ZX Spectrum UDG notation
" (chars 144-164)
silent! %s/\\[Aa]/\=nr2char(144)/ge
silent! %s/\\[Bb]/\=nr2char(145)/ge
silent! %s/\\[Cc]/\=nr2char(146)/ge
silent! %s/\\[Dd]/\=nr2char(147)/ge
silent! %s/\\[Ee]/\=nr2char(148)/ge
silent! %s/\\[Ff]/\=nr2char(149)/ge
silent! %s/\\[Gg]/\=nr2char(150)/ge
silent! %s/\\[Hh]/\=nr2char(151)/ge
silent! %s/\\[Ii]/\=nr2char(152)/ge
silent! %s/\\[Jj]/\=nr2char(153)/ge
silent! %s/\\[Kk]/\=nr2char(154)/ge
silent! %s/\\[Ll]/\=nr2char(155)/ge
silent! %s/\\[Mm]/\=nr2char(156)/ge
silent! %s/\\[Nn]/\=nr2char(157)/ge
silent! %s/\\[Oo]/\=nr2char(158)/ge
silent! %s/\\[Pp]/\=nr2char(159)/ge
silent! %s/\\[Qq]/\=nr2char(160)/ge
silent! %s/\\[Rr]/\=nr2char(161)/ge
silent! %s/\\[Ss]/\=nr2char(162)/ge
silent! %s/\\[Tt]/\=nr2char(163)/ge
silent! %s/\\[Uu]/\=nr2char(164)/ge
endfunction
function! BBimChars()
let l:ignoreCaseBackup=&ignorecase
set noignorecase
call BBimISOchars()
call BBimTokens()
call BBimUDG()
call BBimBlockGraphs()
" Embedded ASCII codes (BASin format):
silent! %s/\\#\(\d\+\)/\=nr2char(submatch(1))/g
echo 'Special chars translated.'
if l:ignoreCaseBackup
set ignorecase
else
set noignorecase
endif
endfunction
" ----------------------------------------------
" Fake MGT disk image
function! BBimMGTfile()
" Create a fake MGT disk image from the current BB file
silent write " Write the current BB file
split " Split the window
silent write! %.mgt " Save a copy with the MGT extension added
silent edit ++bin %.mgt " Open it in binary mode
set noendofline " Don't put an EOL at the end of the file when saving it
set fileencoding=latin1
" Translate line feed chars (decimal 10)
" into carriage returns chars (decimal 13):
silent %!tr "\12" "\15"
" Convert it into a fake MGT disk image,
" just making it 819200 bytes long:
silent %!dd bs=819200 conv=sync 2>> nul
echo 'Fake MGT file created.'
endfunction
" ----------------------------------------------
" BB file
function! BBimBBfile()
" Create a copy of the current BBim file
" with the ".bb" extension added
" and open it for editing.
silent update " Write the current BBim file if needed
split " Split the window
silent write! %.bb " Save a copy with the BB extension added
silent edit %.bb " Open it for editing
set fileencoding=latin1
" fileformat does not work here (it makes the renumbering not to work, because all the code is one line)!!!:
"set fileformat=mac " Force CR (char 13) as end of line
" Force an end of line at the end of the file:
silent! %substitute/\%$/\r/e
silent write
echo 'BB file created.'
endfunction
" ----------------------------------------------
" Main
function! BBim2BB()
set shortmess=at
call BBimGetFirstLine()
let s:ignoreCaseBackup=&ignorecase
set ignorecase
call BBimBBfile()
call BBimInclude()
call BBimVim()
call BBimClean()
call BBimLabels()
call BBimRenum()
call BBimChars()
call BBimMGTfile()
silent w
silent bw
echo 'Fake MGT file saved and closed.'
set fileformat=mac " Force CR (char 13) as end of line
silent w
silent bw
echo 'BB file saved and closed.'
if s:ignoreCaseBackup
set ignorecase
else
set noignorecase
endif
echo 'Done!'
endfunction
" Shortkey ',bb' in normal mode
" to create a Beta BASIC file:
nmap <silent> ,bb :call BBim2BB()<CR>
Descarga
Todos los componentes de BBim pueden descargarse en la sección de descargas de BBim.