I am looking at some code and there is this:
BLOCK
...lines of code...
END BLOCK
What is the purpose of BLOCK? I tried to go
I have composed a few more fun examples. What if you want to invoke an assumed length function with different lengths in the same instance of a subprogram? You need a specification statement to tell the compiler the length you want, so a BLOCK construct can do this for you
function F(x)
implicit none
character(*) F
character x(:)
integer i
do i = 1, len(F)
F(i:i) = x(1)
end do
end function F
program blox1
implicit none
integer i
character c
do i = 1, 7
c = achar(65+modulo(i**4+6*i**2+1,26))
block
character(2*i+1), external :: F
call blox1a(F)
end block
end do
contains
subroutine blox1a(F)
interface
function F(x)
import
implicit none
character(2*i+1) F
character x(:)
end function F
end interface
write(*,'(a)') F([c])
end subroutine blox1a
end program blox1
Output with gfortran:
III
PPPPP
GGGGGGG
PPPPPPPPP
WWWWWWWWWWW
FFFFFFFFFFFFF
SSSSSSSSSSSSSSS
Or how about when you need the appropriate KIND for a REAL literal? This requires a named constant and the KIND might be given in the specification statements of another MODULE and may even be given as an expression. In that case you might try defining a named constant with the value of that expression, but if an unlucky choice is made that name might override another host associated name. A BLOCK construct makes it all OK:
module mytypes
use ISO_FORTRAN_ENV
implicit none
type T(KIND)
integer, kind :: KIND
real(KIND) x
end type T
interface assignment(=)
module procedure assign8, assign4
end interface assignment(=)
contains
subroutine assign8(x,y)
real(REAL64), intent(in) :: y
type(T(kind(y))), intent(out) :: x
x%x = y
end subroutine assign8
subroutine assign4(x,y)
real(REAL32), intent(in) :: y
type(T(kind(y))), intent(out) :: x
x%x = y
end subroutine assign4
end module mytypes
program blox2
use mytypes
implicit none
type(T(REAL32)) x
BLOCK
! integer, parameter :: rk = x%KIND ! Not allowed
integer, parameter :: rk = kind(x%x)
x = 0.0072973525664_rk
write(*,'(g0)') x%x
END BLOCK -1 is too small
12! = 479001600
13 is too big
BLOCK
type(T(REAL64)) x
BLOCK
! integer, parameter :: rk = x%KIND ! Not allowed
integer, parameter :: rk = kind(x%x)
x = 0.0072973525664_rk
write(*,'(g0)') x%x
END BLOCK
END BLOCK
end program blox2
Output with gfortran:
0.729735242E-02
0.72973525663999998E-002
It can be tricky to get a Fortran pointer to a C string because there is no syntax to tell C_F_POINTER what the length of the target of a deferred length pointer should be. BLOCK to the rescue!
program blox3
use ISO_C_BINDING
implicit none
character(len=:,kind=C_CHAR), allocatable, target :: x
type(C_PTR) c_hello
integer(C_INTPTR_T) address
character(kind=C_CHAR), pointer :: nul_address
character(len=:,kind=C_CHAR), pointer :: f_hello
integer i
x = 'Hello, world'//achar(0)
c_hello = C_LOC(x(1:1))
address = transfer(c_hello,address)
i = 0
do
call C_F_POINTER(transfer(address+i,C_NULL_PTR),nul_address)
if(nul_address == C_NULL_CHAR) exit
i = i+1
end do
BLOCK
character(len=i,kind=C_CHAR), pointer :: temp
call C_F_POINTER(c_hello,temp)
f_hello => temp
END BLOCK
write(*,'(i0,1x,a)') len(f_hello), f_hello
end program blox3
Output with gfortran:
12 Hello, world
Not to mention that a named BLOCK construct gives us a label to hang our spaghetti code on:
program blox4
implicit none
integer i
integer j(3)
integer k
j = [-1,12,13]
do i = 1, size(j)
factorial: BLOCK
if(j(i) < 0) then
write(*,'(*(g0))') j(i),' is too small'
EXIT factorial
end if
if(j(i) > 12) then
write(*,'(*(g0))') j(i),' is too big'
EXIT factorial
end if
write(*,'(*(g0))') j(i),'! = ',product([(k,k=1,j(i))])
END BLOCK factorial
end do
end program blox4
Output with gfortran:
-1 is too small
12! = 479001600
13 is too big