Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the point of BLOCK in Fortran?

Tags:

fortran

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 google it, but all I found was something about BLOCK DATA and COMMON blocks. I'm not sure whether they are related.

like image 974
Andrej Avatar asked Jul 23 '18 09:07

Andrej


3 Answers

From the Fortran 2008 standard:

The BLOCK construct is an executable construct that may contain declarations.

It is not related to common blocks or to block data program units.

So, the main use is this "containing declarations".

As scoping units we have things like

integer i
block
  integer j ! A local integer
  integer i ! Another i
  save i    ! ... which can even be SAVEd
end block

which affords locality of declarations:

! ... lots of code
block
  integer something
  read *, something
end block
! ... lots more code

These scoping blocks allow automatic objects:

integer i
i = 5
block
  real x(i)
end block

As executable constructs, they also have useful flow control:

this_block: block
  if (something) exit this_block
  ! ... lots of code
end block

They also have finalization control:

type(t) x
block
  type(t) y
end block ! y is finalized
end  ! x is not finalized

for x and y of finalizable type.

Oh, and let's not forget how you can confuse people with implicit typing.

like image 71
francescalus Avatar answered Nov 11 '22 13:11

francescalus


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
like image 10
user5713492 Avatar answered Nov 11 '22 12:11

user5713492


The block construct allows you to declare entities such as variables, types, external procedures, etc which are locally known to the block but have no effect to any variables outside of the block.

Example 1:

IF (swapxy) THEN
  BLOCK
    REAL (KIND (x)) tmp
    tmp = x
    x = y
    y = tmp
  END BLOCK
END IF

Here the variable tmp is locally defined to help out with the swap of two variables. Outside of the block, the variable tmp is unknown or back its original form if it was defined outside of the block (see next example).

Example 2:

F = 254E-2
BLOCK
  REAL F
  F = 39.37
END BLOCK
! F is still equal to 254E-2.

The variable F is redefined locally to the block but has no effect outside of it.

These kinds of blocks are used to make the code more readable and easier to understand as you don't need to look to the entire subprogram to understand what the locally defined entities are. Furthermore, the compiler knows that these entities are locally defined, so it might do some more optimization.

like image 6
kvantour Avatar answered Nov 11 '22 12:11

kvantour