MBim2MB
Descripción del contenido de la página
Programa escrito en Vim para convertir al formato estándar de MasterBASIC un código fuente en formato MBim.
Etiquetas:
Este programa escrito en Vim es el corazón de MBim: a partir del código fuente original en formato MBim crea dos nuevos ficheros que podrán ser importados en el emulador SimCoupe de SAM Coupé:
- Con extensión .mb: Fichero de texto con código fuente en MasterBASIC listo para ser añadido a una imagen de disquete MGT e importado con MBimport 3 (o, alternativamente, trasferido a la memoria de la SAM Coupé con la opción correspondiente del emulador SimCoupe e importado con MBimport 1).
- Con extensión .mb.mgt: Falsa imagen de disquete MGT, para ser leída por MBimport 2).
Debido a que el proceso final de importación no puede funcionar, este programa quedó con detalles sin «rematar». La versión análoga para Beta BASIC, BBim2BB, es un ejemplo de lo que MBim2MB debería haber sido.
Código fuente
" mbim2mb.vim
" MBim2MB (version A-02-201406260020)
" This file is part of the MBim tools.
" Copyright (C) 2011,2012,2013,2014 Marcos Cruz (programandala.net)
" This Vim program provides some functions needed to
" convert MBim source code into an actual MasterBASIC
" program ready to be imported into the
" SimCoupe emulator using the MBimport utility.
" ------------------------------
" History
" 2011-08-07: First version, called "vim2mb.vim".
" 2011-08-10: Added: "set noignorecase" and lowercase UDG chars.
" 2011-08-12: Fixed: "set fileencoding=latin1" was needed to make sure the
" source file is not UTF-8.
" 2011-09-01: Many changes: Renamed to "mbim2mb.vim". Improved: Two files are
" created from the original "myprogram.mbim": "myprogram.mbim.mb" and
" "myprogram.mbim.mb.mgt". Formerly, the MGT was created right from the
" original code, ready to be imported by "MBimport 2". Now the intermediate MB
" file can be added into a real MGT disk image with the "SAM Diskimage
" manager" by Edwin Blink, and then imported by "MBimport 3".
" 2012-11-16: "silent!" added to the substitutions.
" 2012-11-17: Messages during the process. Usage message at the start. UDG and
" block chars are translated with nr2char() insted of hardcoded char codes.
" Support for embedded ASCII codes (in BASin format). "silent" added to the
" file operations. Fixed: "nul" to "/dev/null"
" 2012-11-18: The fake MGT image is compressed with zip or gzip.
"
" 2012-11-19: The lines can be numbered. This way the new versions of MBimport
" can work faster. The MB file can be deleted; is not needed in the last
" versions of MBimport. Line comments now need a trailing space (this avoids
" the '//' in 'http://' to be considered the start of a comment, and in other
" cases as well).
"
" 2012-11-20: Implemented: '#firstline'.
"
" 2012-12-05: Improved: now '#firstline 0' means no line number (MBimport 5
" imports source with line numbers, what is faster; the previous versions add
" the line numbers during the import proccess). The minimum line number is
" 100, to protect MBimport 5.
" 2012-12-06: Improved: in MBimChars(), the status of 'ignorecase' is
" preserved. Fixed: 'normal w"lyw' had to be 'normal ww"lyw'. New: '#vim' and
" '#include' (copied from BBim2BB). New: '#keep_mb_file' and '#compression'.
" 2012-12-08: The minimum line number now is 10, because MBimport 5 has only
" seven lines.
" 2012-12-25: '#firstline' changed to '#first_line_number'.
" 2013-01-20: Block comments regexp improved.
" 2014-06-19: Revision. New to-do.
" 2014-06-26: Version A-02. No ISO chars translated anymore. The
" 'delete_MB_file' variable is renamed to 'remove_MB_file', and its default
" value is changed: now the file is keep unless '#remove_mb_file' is used;
" '#keep_mb_file' doesn't work any more. The default first line is 1, not 0
" (what caused the lines were not numbered by default).
" Fix: tow 'silent wq' are changed to 'silent w' and 'silent bw'; previously
" the buffers of the .mb and .mb.mgt files were not actually closed, and
" the next run failed.
" ------------------------------
" XXX TODO
" 2014-07-03: Fix:
" The following deffn with splitted lines removes some lines above it:
" deffn f$(e)\
" // comment
" ="x"
" But this way it is properly rendered:
" deffn f$(e)=\
" // comment
" "x"
" Fix?: This line removes al the following splitted lines:
" // print i:\ // comment
" Change: #fake_mgt to force the creation of the mgt file. The default
" behaviour will be not to create it, because it will be unnecessary with the
" next version of SimCoupe.
" Improve: Option to translate labels to line numbers? This may prevent
" problems with KEYIN during the import process, and also would make the code
" faster.
" Fix: remove empty lines at the top of the source (after removing the
" comments); test this with the program 'mkusage5'.
" New: #remove_labels, #udg_off, #blocks_1_off, #blocks_2_off
" ----------------------------------------------
" Source cleaning
function! MBimClean()
" Clean off all MBim stuff.
" Remove comments:
silent! %s@^\s*#.*$@@ " metacomments
silent! %s@^\s*\/\/\s\+.*$@@ " line comments at the start
silent! %s@\s\+\/\/\s\+.*$@@ " line comments at the end
silent! %s@^\s*\/\*\_.\{-}\*\/@@ " block comments
" Remove the empty lines:
silent! %s/^\s\+//
silent! %s/\n\n\+/\r/g
silent! %s.^\s*..g " Remove indentation
silent! %s/\s\+$//g " Remove ending blanks
silent! %s.\\\n.. " Join the splitted lines
echo 'Source code cleaned.'
endfunction
" ----------------------------------------------
" Metacommands
function! MBimGetConfig()
" Search the source for '#keep_mb_file', '#compression zip' and
" '#compression gzip'. They can be anywhere in the source but always at the
" start of a line (with optional indentation). The values of
" 's:remove_MB_file' and 's:zip_compression' are set accordingly.
" Delete the MB file?
" The MB file is needed only by old versions of MBimport.
let s:remove_MB_file=0 " Default
call cursor(1,1) " Go to the top of the file.
let s:remove_MB_file=search('^\s*#remove_mb_file\>','Wc')
if s:remove_MB_file
echo 'The MB file will be removed.'
else
echo 'The MB file will be kept.'
endif
" Compress the fake MGT file with zip instead of gzip?
let s:zip_compression=0 " Default
call cursor(1,1) " Go to the top of the file.
if search('^\s*#compression\s\+g\?zip\>','Wc')
" Store the compression format into register 'l':
normal ww"lyw
" And then into the config variable:
let s:zip_compression=(getreg('l',1)=='zip')
endif
if s:zip_compression
echo 'The MGT file will be zipped.'
else
echo 'The MGT file will be gzipped.'
endif
endfunction
function! MBimVim()
" Execute all #vim metacommands.
" Syntax:
" #vim Any-Vim-Ex-Command
call cursor(1,1) " Go to the top of the file.
let l:vimCommands=0 " Counter
while search('^\s*#vim\s','Wc')
let l:vimCommands += 1
let l:vimCommandLine = line('.')
let l:vimCommand=matchstr(getline(l:vimCommandLine),'\S\+.*',4)
" echo l:vimCommand
execute 'silent! '.l:vimCommand
call cursor(l:vimCommandLine,1) " Return to the command line.
call setline('.','') " Blank the line.
endwhile
if l:vimCommands==0
echo 'No Vim command found.'
elseif l:vimCommands==1
echo 'One Vim command executed.'
else
echo l:vimCommands 'Vim commands executed.'
endif
endfunction
function! MBimInclude()
" 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.
let l:includedFiles=0 " Counter
while search('^\s*#include\s','Wc')
let l:includedFiles += 1
let l:fileName=matchstr(getline('.'),'\S\+.*',8)
call setline('.','') " Blank the line.
" ----------- xxx debug check
"echo '#include ' l:fileName
"echo 'getcwd()=' getcwd()
"echo 'Modifications:'
"echo ':~' fnamemodify(l:fileName,':~')
"echo ':p' fnamemodify(l:fileName,':p')
" -----------
execute "silent! r ".l:fileName
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
" ----------------------------------------------
" Renum
function! MBimGetFirstLine()
" Store into s:firstLine the first line number
" to be used by the final MasterBASIC program.
" The command #first_line_number can be used to set
" the desired line number. Only the first occurence
" of #first_line_number will be used; it can be anywhere
" in the source but always at the start of a line
" (with optional indentation).
" Default value of the first line number
" (if it's 0, the lines will not be renumbered):
let s:firstLine=1 " Default
call cursor(1,1) " Go to the top of the file.
if search('^\s*#first_line_number\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
if s:firstLine
" Make sure the first line does not clash with MBimport 5:
let s:firstLine=max([s:firstLine,10])
echo 'First line number: '.s:firstLine
else
echo 'No line numbers'
endif
endfunction
function! MBimRenum()
" Call the the nl program (part of the Debian coreutils package):
execute "silent! %!nl --body-numbering=t --number-format=rn --number-width=6 --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,5}\s://e
echo 'Line numbers added.'
endfunction
" ----------------------------------------------
" Character translation
" Translations are provided for block graphs and ZX Spectrum UDGs, using the
" BASin notation.
"
" Other ad hoc translations must be done in the program source, using the #vim
" command. Example:
"
" // Convert every A acute char in the source to SAM Coupé's char 133:
" #vim %s/Á/\=nr2char(133)/g
function! MBimBlockGraphs()
" Translate BASin format ZX Spectrum block graphics notation
" (SAM Coupé 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! MBimUDG()
" Translate BASin format ZX Spectrum UDG notation
" (SAM Coupé 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! MBimChars()
set fileencoding=latin1
set fileformat=mac " Force CR (char 13) as end of line
let l:ignoreCaseBackup=&ignorecase
set noignorecase
call MBimUDG()
call MBimBlockGraphs()
" 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! MBimMGTfile()
" Create a fake MGT disk image from the
" current MB file.
silent write " Write the current MB file
split " Split the window
silent write! %.mgt " Save a copy with the MGT extension added
echo 'Fake MGT file created.'
silent edit ++bin %.mgt " Open it in binary mode
set noendofline " Don't put an EOL at the end of the file whew saving it
set fileencoding=latin1
" Convert it to a fake MGT disk image,
" just making it 819200 bytes long:
silent %!dd bs=819200 conv=sync 2>> /dev/null
" Somehow, 'dd' changes all
" carriage returns (decimal 13) to
" line feeds (decimal 10), what makes useless
" the command 'set fileformat=mac' used to
" force the carriage return needed by the SAM Coupé
" as end of line. That's why "tr" is needed now:
" Translate line feed chars (decimal 10)
" into carriage returns chars (decimal 13):
silent! %!tr "\12" "\15"
let mgtfile=expand("%")
silent w " Write the MGT file
silent bw " Close the MGT file
echo 'Fake MGT file saved and closed.'
" Make a compressed copy of the fake disk image
" (no check is made; the compression program must be installed):
if s:zip_compression
" silent execute '!zip -9' shellescape(mgtfile.'.zip') shellescape(mgtfile)
silent execute '!zip -9' shellescape(mgtfile.'.zip') shellescape(mgtfile)
silent call delete(mgtfile)
echo 'Fake MGT file compressed with zip.' mgtfile
else
silent call delete(mgtfile.'.gz')
silent execute '!gzip' shellescape(mgtfile)
echo 'Fake MGT file compressed with gzip.'
endif
endfunction
" ----------------------------------------------
" MB file
function! MBimMBfile()
" Create a copy of the current MBim file
" with the ".mb" extension added
" and open it for editing.
silent write " Write the current MBim file
split " Split the window
silent write! %.mb " Save a copy with the MB extension added
silent edit %.mb " Open it for editing
set fileencoding=latin1
echo 'MB file created.'
endfunction
" ----------------------------------------------
" Main
function! MBim2MB()
call MBimGetFirstLine()
call MBimGetConfig()
call MBimMBfile()
call MBimInclude()
call MBimVim()
call MBimClean()
if s:firstLine
call MBimRenum()
endif
call MBimChars()
call MBimMGTfile()
let mbfile=expand("%")
silent w " Save the MB file
silent bw " Close the MB file
echo 'MB file saved and closed.'
if s:remove_MB_file
silent echo delete(mbfile)
echo 'MB file removed.'
endif
echo 'Done!'
endfunction
" Shortkey ',mb' in normal mode:
nmap <silent> ,mb :call MBim2MB()<CR>
echo "MBim2MB loaded."
echo "Activate it with the keys ',mb' (comma, M and B), in normal mode, on your MBim source."
Descargas
Todos los componentes de MBim pueden descargarse en la sección de descargas de MBim.