Search code examples
fortran

Combining strings and integers to make a variable format: Missing initial left parenthesis in format (Fortran)


I want to make a variable format for my "write" statement. To do so, I wrote a small program (nvari is the variable):

program VariableFormat
  implicit none

  integer              :: x = 1,y = 2, z = 3, i, nvari
  double precision     :: pi = 3.14
  integer, allocatable :: var(:)
  integer              :: A(3) = (/1,2,3/)
  character(100)       :: fmt,fmt2,str1,str2,str3

  print*, size(A)
  allocate(var(size(A)))
  do i = 1, size(A)
     var(i) = A(i)
  end do
  nvari = 2
  !
  ! first part
  !
  fmt = '(a,f4.2)'
  write(*,fmt) "The value of pi is ", pi
  !
  ! second part
  ! 
  write (str1, "(1A2,1I1,1A1,1I2,1A1)") "'(", 3, "I", 15, ","
  print*, str1
  write(str2,'(I10)') nvari
  print*, str2
  write (str3, "(1A1,1I2,1A2)") "I", 15, ")'"
  print*, str3
  fmt2 = trim(adjustl(str1))//trim(adjustl(str2))//trim(adjustl(str3))
  print*, fmt2
  write(*,fmt2) x,y,z,(var(i),i=1,nvari)
  
end program VariableFormat

First question: It can be seen that fmt2 is similar to fmt in the sense that in both we have '(X,Y)'. However, while the first part of the code is executed correctly, for the second part, I have the error:

At line 32 of file VariableFormat.F90 (unit = 6, file = 'stdout')
Fortran runtime error: Missing initial left parenthesis in format
'(3I15,2I15)' 

I don't understand which parenthesis is missing as fmt2 is similar to fmt. To execute my program I use the gfortran compiler: gfortran -o binary_VariableFormat VariableFormat.F90 and then:./binary_VariableFormat

Second question: Is there a way to write fmt2 in a more compact way?


Solution

  • This is perhaps more a misunderstanding about character variables and literal constants than about formats.

    In

    fmt = '(a,f4.2)'
    

    we have the character variable's name (fmt) on the left-hand side of the assignment and the value to assign on the right. '(a,f4.2)' is a literal character constant and its value is given to fmt.

    The two, matching, ''s act as delimiters for the value of the constant: they are not themselves part of the value.1 The value of the literal constant is (a,f4.2). Go on, print the value of fmt to check. (One actually has to do something quite different to get the value of a character variable with delimiters.)

    A character value in a format must be something like (...): the first non-blank value must be a (. Because you've set the value to be like '(...)' the compiler is (quite rightly) complaining.

    Where we have something like

    write(str2,'(I10)') nvari
    

    we are using this literal constant which has value (I10) not '(I10)'. If we instead had

    write(str2,"'(I10)'") nvari
    

    we'd see exactly the same complaint (or perhaps a complaint when compiling instead of running).

    Finally, note that when using a FORMAT statement (many here really don't like such things), we'd not have these delimiters at all:

    format (I10)   ! Correct
    format '(I10)' ! Badly wrong
    

    1 Similarly, if we have literal constants used like

    complex :: a = (1., 2.)
    integer :: i = INT(B'001')
    

    the delimiters for the complex and BOZ literal constants are not part of the value. Equally in an array constructor like [0,1,2,3] the square brackets are a delimiter part of the syntax rather than the value.