Introduction to the Macro SPITBOL MINIMAL Reference Manual

The source code for MACRO SPITBOL contains extensive documentation. I have extracted the specification of the MINIMAL (Machine Independent Macro Assembly Language) and the specification of the OSINT (Operatint System INterface) and converted the plain text to HTML, resulting in what is now the “MINIMAL Reference Manual.

As part of this effort I wrote an introduction in order to give a sense of the flavor of the code. Here is that introduction:

Introduction

The implementation of MACRO SPITBOL is written in three languages: MINIMAL, C, and assembler.

The SPITBOL compiler and runtime is written in MINIMAL, a machine-independent portable assembly language.

The runtime is augmented by procedures written in C that collectively comprise OSINT (Operating System INTerface). These procedures provides such functions as input and output, system initialization and termination, management of UNIX pipes, the loading of external functions, the writing and reading of save files and load modules, and so forth.

The implementation also includes assembly code. This size of this code varies according to the target machine. About 1500 lines are needed for the x86 architecture running UNIX.

This code provides such functions as macros that define the translation of MINIMAL instructions that take more than a few machine-level instructions, support for calling C procedures from MINIMAL, for calling MINIMAL procedures from C, for creating save files and load modules, and for resuming execution from save files or load modules.

To give some idea of the flavor of the code, consider the following simple SPITBOL program that copies standard input to standard output.

loop output = input :s(loop)
end

By default, the variable input is input-associated to standard input, so each attempt to get its value results in reading in a line from standard input and returning the line as a string. The read fails if there are no more lines, and succeeds otherwise.

Similarly, the variable output is output-associated with standard output, so each assignment to output causes the assigned value to be written to the standard output file.

The osint procedure for writing a line is SYSOU. It is called from within SPITBOL as part of assignment, as shown in the follwing excerpt from the MINIMAL source:

*      here for output association

asg10  bze  kvoup,asg07      ignore output assoc if output off
asg1b  mov  xl,xr            copy trblk pointer
       mov  xr,trnxt(xr)     point to next trblk
       beq  (xr),=b_trt,asg1b loop back if another trblk
       mov  xr,xl            else point back to last trblk
.if    .cnbf
       mov  -(xs),trval(xr)  stack value to output
.else
       mov  xr,trval(xr)     get value to output
       beq  (xr),=b_bct,asg11 branch if buffer
       mov  -(xs),xr         stack value to output
.fi
       jsr  gtstg            convert to string
       ppm  asg12            get datatype name if unconvertible

*      merge with string or buffer to output in xr

asg11  mov  wa,trfpt(xl)     fcblk ptr
       bze  wa,asg13         jump if standard output file

*      here for output to file

asg1a  jsr  sysou            call system output routine
       err  206,output caused file overflow
       err  207,output caused non-recoverable error
       exi                   else all done, return to caller

From the OSINT C code (the C procedure name starts with ‘z’ since there is intermediate code (shown below) to call from MINIMAL to C at runtime):

zysou()
{
    REGISTER struct fcblk *fcb = WA(struct fcblk *);
    REGISTER union block *blk = XR(union block *);
    int result;

    if (blk->scb.typ == type_scl) {
	/* called with string, get length from SCBLK */
	SET_WA(blk->scb.len);
    } else {
	/* called with buffer, get length from BCBLK, and treat BSBLK
	 * like an SCBLK
	 */
	SET_WA(blk->bcb.len);
	SET_XR(blk->bcb.bcbuf);
    }

    if (fcb == (struct fcblk *) 0 || fcb == (struct fcblk *) 1) {
	if (!fcb)
	    result = zyspi();
	else
	    result = zyspr();
	if (result == EXI_0) 
	    return EXI_0;
	else 
	    return EXI_2;
    }

    /* ensure iob is open, fail if unsuccessful */
    if (!(MK_MP(fcb->iob, struct ioblk *)->flg1 & IO_OPN)) {
	 return EXI_1;
    }

    /* write the data, fail if unsuccessful */
    if (oswrite
	(fcb->mode, fcb->rsz, WA(word), MK_MP(fcb->iob, struct ioblk *),
	 XR(struct scblk *)) != 0)
	 return EXI_2;

    /* normal return */
    return EXI_0;
}

Here is the assembly code that is used to call a C procedure from MINIMAL. The code is for 32-bit X86
and is written using NASM (Netwide Assembler) syntax.

	%macro	mtoc	1
	extern	%1
	; save minimal registers to make their values available to called procedure
	mov     dword [reg_wa],ecx     
        mov     dword [reg_wb],ebx
        mov     dword [reg_wc],edx	; (also reg_ia)
        mov     dword [reg_xr],edi
        mov     dword [reg_xl],esi
        mov     dword [reg_cp],ebp	; Needed in image saved by sysxi
        call    %1			; call c interface function
;       restore minimal registers since called procedure  may have changed them
        mov     ecx, dword [reg_wa]	; restore registers
        mov     ebx, dword [reg_wb]
        mov     edx, dword [reg_wc]	; (also reg_ia)
        mov     edi, dword [reg_xr]
        mov     esi, dword [reg_xl]
        mov     ebp, dword [reg_cp]
;	restore direction flag in (the unlikely) case that it was changed
        cld
;	note that the called procedure must return exi action in eax
	ret
	%endmacro

  ...

	global	sysou			; output record
sysou:
	mtoc	zysou
Advertisements

9 Comments

  1. paul
    Posted October 3, 2012 at 15:59 | Permalink | Reply

    I don’t understand why NASM? I’d have thought the idea was to convert MINIMAL into the target machine’s native assembler, using a Spitbol program.

    I also wonder if there could be a “portable” version made by having C as a translation target. It would look like a lot of calls to macros or inline functions, with a suitable set of #define’s.

    The program is small enough that a manual translation to C or C++ is probably still of reasonable scope for a recreational project.

    • Posted October 5, 2012 at 15:43 | Permalink | Reply

      Paul,

      Indeed, the goal is to convert MINIMAL source to native assembler, whatever ‘native’ means. In the present case, NASM is far superior to GAS, notably in its use of uniform notation for memory references, all of which must be enclosed in square brackets.

      Also, the NASM macro processor is far superior to the one in GAS.

      Though assembly languages are indeed “low level,” I have found that in the ten or so assemblers I have used over the years, macro processing in assembler is quite powerful. Usually an assembler processor is much more powerful than that provided by the C preprocessor.

      • paul
        Posted October 5, 2012 at 17:19 | Permalink

        By native assembler I just meant the one that comes on the target OS, e.g. GAS. I would have thought all asm-level macro expansion would be handled by the MINIMAL-to-asm Spitbol program. I’d have thought the Spitbol program could handle all issues like square brackets.

        I wonder if you know about Parsec, the Haskell parser combinator library. It reminds me in some ways of Spitbol pattern matching:

        * http://legacy.cs.uu.nl/daan/parsec.html

        * http://www.haskell.org/haskellwiki/Parsec

      • Posted October 11, 2012 at 09:35 | Permalink

        Paul,

        Re Haskell parser library, I still put my faith in Philippe’s JikesPG, arguably the best parser generator around.

        thanks,dae

  2. Posted October 10, 2012 at 22:07 | Permalink | Reply

    I live your energy! I hope you have a blast!!

  3. Posted October 10, 2012 at 22:07 | Permalink | Reply

    Great post. I loved this: “Knowing that I am starting from zero, any progress will be great news, and it will be fun to see how far I can get. I had a similar experience working with Philippe Charles on Jikes. We started from nothing, and were able to build something that achieved some success. I hope to repeat that, and I know I will have fun trying to do so, even if I don’t succeed.”

  4. Jack Black
    Posted December 27, 2012 at 05:12 | Permalink | Reply

    Hi Dave, is there a link to the doc somewhere? Thank you.

    • Posted January 4, 2013 at 15:53 | Permalink | Reply

      What doc?

      • Posted January 4, 2013 at 16:10 | Permalink

        Jack,

        Ah, I see you want the MINIMAL Reference Manual.

        To get it, do

        $ git clone http://github.com/hardbol/spitbol

        and use your browser to open the file

        minimal-reference-manual.html

        The SPITBOL manual as well as “The Green Book” can be found in subdirectory spitbol/docs.

        thanks,dave

        thanks.dave

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

  • Pages

  • October 2012
    M T W T F S S
    « Sep   Dec »
    1234567
    891011121314
    15161718192021
    22232425262728
    293031  
  • RSS The Wayward Word Press

  • Recent Comments

    mrrdev on On being the maintainer, sole…
    daveshields on On being the maintainer, sole…
    James Murray on On being the maintainer, sole…
    russurquhart1 on SPITBOL for OSX is now av…
    dave porter on On being the maintainer, sole…
  • Archives

  • Blog Stats

  • Top Posts

  • Top Rated

  • Recent Posts

  • Archives

  • Top Rated

  • %d bloggers like this: