Fortran one-line toy interpreter

On Linux you can run a Python one-liner from the command line and get the output:

python -c 'print(2**5)' gives 32

I wrote a program that reads a Fortran program from the command line (multiple lines are separated by semicolons), writes it to a source file, adds an end statement, compiles it, and runs the executable. It uses execute_command_line for the last two operations. Running the executable frun.exe on Windows,

frun i=2;j=5;print*,i**j gives 32.

frun do i=2,5;print*,i,sqrt(real(i));end do

gives

           2   1.41421354    
           3   1.73205078    
           4   2.00000000    
           5   2.23606801

Implicit typing is sometimes convenient :slight_smile:. The program could be useful to remind oneself how intrinsic functions work:

frun print*,mod(3,-2),mod(-3,2),modulo(3,-2),modulo(-3,2) gives 1 -1 -1 1

One problem is that quotes on the command line are stripped, so

frun print*,"hi"

creates code

print*,hi
end

Another problem is that on Linux using semicolons to provide multiple lines of code does not work. It would be convenient if p x were expanded to print*,x, which could be done if p is not followed by an =. Here is the code, which assumes gfortran is installed. The variable
unix would be set to .true. on Linux.

program run_fortran
implicit none
integer, parameter   :: nlen = 10**4, iu = 10
character (len=nlen) :: text
integer              :: ispace
logical, parameter   :: print_command = .false., unix = .true.
character (len=:), allocatable :: src, executable
logical                        :: exec_exists
src = "temp.f90" ! source code file to create and compile
call get_command(text)
! command line starts with executable name, so strip it off
ispace = index(text," ") 
text = text(ispace+1:nlen)
if (print_command) print "(a)",trim(text)
open (unit=iu,file=src,action="write",status="replace")
write (iu,"(a)") trim(text)
write (iu,"('end')") ! save the user the trouble of supplying 'end' on the last line
close (iu)
call execute_command_line("gfortran " // trim(src)) ! compile source
! run program
executable = merge("a.out","a.exe",unix)
inquire (file=executable,exist=exec_exists)
if (exec_exists) then
   if (unix) then
      call execute_command_line("./" // executable)
   else
      call execute_command_line(executable)
   end if
end if
end program run_fortran

I am of course aware of the interactive Fortran compiler LFortran, which is a serious project.

Edit: I see that single quotes work, so

frun print*,'Hello, world';i=2;j=5;print '(a,*(1x,i0))','i,j,i**j=',i,j,i**j

gives

 Hello, world
i,j,i**j= 2 5 32
6 Likes

I uploaded to GitHub an interactive console program FortranShell that runs on Windows and Linux, where you enter code and then enter run, which causes the code to be saved to a file, compiled with gfortran, and run, with output appearing within the program. You can enter more code and then run again. I think it is fun for experimenting with Fortran, and it could be enhanced to link to compiled libraries such as Lapack and stdlib and become more useful.

A sample session is

c:\fortran\test>fedit.exe
> print*,2**5;
          32
> del
> imp
> integer :: i
> do i=1,4
> print*,i,i**2
> end do
> list
1: implicit none
2: integer :: i
3: do i=1,4
4: print*,i,i**2
5: end do
> run
           1           1
           2           4
           3           9
           4          16
> q
STOP done -- code saved in temp.f90

The help lists some features:

 enter a line of Fortran code. Otherwise, ...
 quit or q to quit
 run or r to compile and run executable
 a line of code terminated by ; causes the program to be compiled and run
 runold or ro to run executable again without recompiling
 compile to compile without running executable
 list or l for a program listing with line numbers
 barelist or bl for a program listing without line numbers
 del to delete all code; del i to delete line i ; del i j to delete lines i to j
 line n <code> to replace the current line n with <code>
 insert n <code> to move lines n on down by 1 and put <code> on line n
 imp is expanded to implicit none

Running fedit.exe main.f90 would import main.f90 instead of starting from scratch.

1 Like