Gfortran list directed read error question

I get the following error when I try to use an implied do loop in a list directed read from an internal file (string) with gfortran 13. ifx 2024.1 and ifort along with Nvidia 24.3 don’t give an error. Who’s correct. Is this another gfortran bug or just a feature.

 1649 |           Read(string,*) dum, dum, dum, ZT, ((X(i),Y(i)), i=1,N)
      |                                            1
Error: Expecting variable in READ statement at (1)
1 Like

Is there a purpose for the outer pair of parentheses in

? Take them out, and the compilation may succeed.

program rwtst
real x(10),y(10)
character(100) string
N = 3
Read(string,*) dum, dum, dum, ZT, (X(i),Y(i), i=1,N)
end

P.S.:
Given the fixed-form version of this program, G77 (FSF-g77 version 0.5.25 19990728) says:

rwmsu.f:5:
         Read(string,*) dum, dum, dum, ZT, ((X(i),Y(i)), i=1,N)
                                            1         2
Unexpected token at (2) in implied-DO construct at (1) -- form of implied-DO is `(item-list,do-var=start,end[,incr])'

Check parenthesis.

The following is more for new Fortranners trying out list-directed IO in Fortran:

   integer, allocatable :: x(:), y(:)
   integer dum
   character(len=200) s
   dum = -99
   x = [ 1, 2, 3 ] ; y = [ 42, 43, 44 ]
   write( s, fmt=* ) dum, dum, dum, ( x(i), y(i), i = 1, 3 )
   print *, trim(s)
   x(:) = 0 ; y(:) = 0
   read( s, fmt=* ) dum, dum, dum, ( x(i), y(i), i = 1, 3 )
   print *, "x = ", x
   print *, "y = ", y
end
C:\temp>gfortran -ffree-form p.f -o p.exe

C:\temp>p.exe
          -99         -99         -99           1          42           2          43           3          44
 x =            1           2           3
 y =           42          43          44

C:\temp>
1 Like

Yes the extra parens are probably not needed. I was using them for a visual clue to make sure that it is understood that the data is stored in pairs ie.

x(1)
y(1)
x(2)
y(2)

I really don’t see why the extra parens should be problem. It is apparently not for Intel and Nvidia but is for gfortran. Removing them does allow gfortran to compile. Thanks to @mecej4 and @FortranFan for spotting this.

In an i/o list, parentheses can be used around expressions. If it had been written, for example, as ((x(i)+y(i)), i = 1, 3 ), or as (((x(i)+y(i))), i = 1, 3 ), or as ((((x(i))+y(i))), i = 1, 3 ), and so on, then the extra parentheses would be allowed. But in the comma separated list, the parentheses do not enclose expressions. I don’t know why some compilers allow them in this case, but I do remember having code even back in the 1970s and 1980s that had extra parentheses in i/o lists that some compilers would take but others wouldn’t. I’ve always assumed that it was an extension, possibly even documented somewhere, because it is a common programmer error to add them. The intel compilers try to accommodate many legacy fortran extensions, so this may be one of them.

There is also the related issue of the syntax (1.0,2.0) to denote a complex literal constant. This would be allowed in an output list in a write statement, but the seemingly equivalent (x,2.0), (1.0,y), or (x,y) with variables is not. Those are not complex variables.

I’m not so much annoyed by the error itself as I am that compilers are not consistent about catching these kinds of errors (or maybe they are just “features”). I’m not sure who if anyone is at fault here, the standard for not being more specific or the compiler developers for having different interpertations of the standard.

Don’t forget the effective “SLA” with gfortran and the GNU ecosystem is that the user is also the compiler developer and the one who can submit patches.

Anyone and everyone who relies on gfortran may want to think over this seriously and feel empowered and consider learning how to fix bugs and submit patches in what’s their own compiler!

1 Like

My understanding is similar, i.e., a comma-separated sequence (w/o parens) does not represent an expression in Fortran, and if so, the extra parens seem to be allowed only as an extension. I’ve tried several other patterns also (using Compiler Explorer), and it seems whether extra parentheses are allowed or not seems rather ad-hoc (context-dependent and not systematic).

program main
implicit none
integer x(3),y(3), dum1, dum2, dum3, N, i
character(100) string
N = 3
string = "-1 -2 -3 10 11 20 21 30 31"
read(string,*)   ( (dum1, dum2), dum3 ), (X(i),Y(i), i=1,N)      !! pass(ifx), error(gf,fln)
read(string,*)   ( (dum1, dum2), dum3 ), ( (X(i),Y(i)), i=1,N)   !! pass(ifx), error(gf,fln)
!! read(string,*) ( ( (dum1, dum2), dum3 ), ( (X(i),Y(i)), i=1,N) ) !! error(ifx), error(gf,fln)
print *, x(:)
print *, y(:)

print *, (dum1, dum2), (dum3, 200), (100, 200)  !! pass(ifx), error(gf,fln)
!! print *, [(dum1, dum2), (dum3, 200)], (100, 200)  !! error(ifx), error(gf,fln)
end

Compiler extensions (features) are often enabled by default, and a compiler option is required to get standard behavior. Back in the f77 the older days, vendors promoted and encouraged the use of their extensions in order to lock in customers for their hardware upgrades. In general, a compiler can claim to be standard conforming if it compiles correctly standard-conforming code, and it is free to add extensions that also compile nonconforming code (warnings are not required).

BTW, it looks like in this case that gfortran is standard and the other compilers have the extension that allows the nonstandard syntax.

This question is about list-directed i/o, but format statements are also rich with compiler extensions. DEC compilers, just for an example, had the Q and $ format descriptors and the <n> repeat count, and also many legacy compilers do not enforce the use of commas to separate some format descriptors.

Some compilers also have quirky nonstandard behavior regarding ENDFILE and BACKSPACE statements.

All of this makes it difficult for the programmer to write portable code, or to even know when an extension is being used.

Yeah, I understand about non-standard extensions but most of those have been replaced by something in the standard. I’ve always wondered about how much trying to satisfy a few users requirements for old DEC, IBM, and Cray extensions have cluttered up the code of a lot of compilers. I’ve been programming Fortran for about 50 years now and I still see an extension I didn’t know existed. The latest is the following option on an OPEN statement that I think was a DEC VAX thing.

, carriagecontrol = 'LIST'

Again, my issue is why there can’t be more commonality at least in the terms of error detection in the compiler development community. I also wonder why gfortran decided to make this particular error a hard fail instead of just a warning in light of the other compilers letting it slide.

Yes, I remember using that option on VAX computers – if I remember correctly, it effectively turned off the ASA formatting conventions, which were the default. Gfortran does support many VAX extensions, and extensions from other compilers too, but apparently not the extra parentheses one. If this were my code, then it would not matter if it were a warning or a fatal error, I would just fix the code in either case. If it is someone else’s code, then of course it is more complicated than that.

I always fix errors and usually warnings when I know they are errors. Since the first three compilers I tried (ifx, ifort, and nvfortran) didn’t give an error, my first assumption was that gfortran was wrong. Usually a score of 3-1 wins. I only use gfortran to see if my code will compile with gfortran because if I release something into the wild I’m sure someone will want to use it and I have a responsibility to at least see if it works. I rarely use gfortran for development.

Note with IFX and IFORT, you may try -stand to get the following:

warning #8089: Parentheses around an I/O list is an extension to Standard F2018.   [X]
1 Like

What if you use an array constructor instead of a comma separated list? I’m on my phone so I couldn’t test it, but that seems like what you are trying to do.

Read(string,*) dum, dum, dum, ZT, ([X(i),Y(i)], i=1,N)

I think that works in this case because the list elements within the redundant parentheses are of the same type and kind. If the list elements are of mixed types, then that would not work. However, even when that works, it seems like a hack to work around the error rather than a fix, right?

1 Like