Scheme in a Fortran module

David Duffy.

After reading Chapter 5 of SICP, I too started writing my own Scheme interpreter, but to be implemented in Fortran. Shortly after starting, I found the 1980s style C code for Minischeme (written by Atsushi Moriwaki and Akira Kida, following Matsuda and Saigo's article Programming of LISP, archive No 5 1987, 6-42). Minischeme (or miniscm) is also the basis for Dimitrios Souflis's Tinyscheme. I settled for porting the C code from both these projects (but mainly miniscm) across into Fortran so I could use it as an embedded language for my other Fortran projects.

The resulting interpreter passes most tests from R4RS and R5RS test suites, but lacks vectors and bignums. The types of numbers are long integers and reals. An internal peculiarity is that characters are implemented as single character Fortran strings. A memory cell is:

  type mcell
    integer :: iflag
    integer (kind=8) :: value
    integer :: slength
    character, dimension(:), allocatable :: svalue
    integer :: keynum 
    integer :: car 
    integer :: cdr 
  end type mcell

The file fscheme_mod.f95 contains the module scheme_lang, along with a few other dependencies, extracted from my sib-pair.f95 code by a simple awk script. This has been then hand edited to remove the extra commands used to access Sib-pair data structures. The last few lines (which you will have to revise) is a minimal main program demonstrating how to call up the Scheme read-eval-print loop:

program stub
  use scheme_lang
  integer :: plevel = 0, typ = 1 ! 1=interactive 2,3=batch
  call init_scheme()
  call repl_scheme(typ, plevel)
end program stub

Therefore:

gfortran -cpp fscheme_mod.f95

will give you a runnable interpreter, from whose command line "(help)" will list the available commands.

Compile with -DEGGX to add the commands calling the EGGX/ProCALL graphical library ( http://www.ir.isas.jaxa.jp/~cyamauch/eggx_procall/), which allows plotting and building simple GUIs etc under X Windows. You will need to compile the library and add -leggx -lX11 to your compile command.

Compile with -DJAPI to add the commands calling the JAPI (java application programming interface) library (http://www.japi.de). JAPI allows Fortran code to interface the Java AWT (Abstract Windowing Toolkit), so one can build GUIs etc.

Adding a new Scheme function to call your Fortran code is straightforward enough.

  1. Add a new opcode in the variable list at the beginning of the scheme_lang module. For example, "OP_NEWFUN=905".
  2. In init_procs() add the appropriate call to mk_proc, eg
    call mk_proc(OP_NEWFUN, 'my-new-fun')
    
  3. In the Fortran subroutine opexe18(), add in the appropriate call to your matching Fortran code:
    else if (op == OP_NEWFUN) then
      call your_fortran_code(i)
      s_return(mk_number(i))
    
  4. Compile, and the REPL should allow:
    %% (my-new-fun)
    42
    

Look at the code for examples of passing lists to and from Fortran. For example,

   else if (op == OP_DIR) then
      call list_files(get_string(car(scm_args)), files)
      n=size(files)
      res=nil
      if (n > 0) then
        do i=1, n
          res=append_one_string(trim(files(i)), res)
        end do
        deallocate(files)
      end if
      call s_return(res)

calls the Fortran code list_files(), which uses C interoperability to call POSIX readdir, and then converts the resulting Fortran character array into a Scheme list.

read_scheme_image() and save_scheme_image() are used by Fortran code to read and save images of the interpreter.