stfc / fparser

This project maintains and develops a Fortran parser called fparser2 written purely in Python which supports Fortran 2003 and some Fortran 2008. A legacy parser fparser1 is also available but is not supported. The parsers were originally part of the f2py project by Pearu Peterson.
https://fparser.readthedocs.io
Other
61 stars 29 forks source link

Parentheses around implied-do break reader #252

Closed reuterbal closed 3 years ago

reuterbal commented 4 years ago

Hi,

I have found a situation where parentheses in an implied-do break the reader. Consider the following boiled-down example:

>>> from fparser.common.readfortran import FortranStringReader
>>> from fparser.two.parser import ParserFactory                                                                                                                                                                    
>>> fcode = """
... SUBROUTINE FOO(ARR1)
... REAL, INTENT(INOUT) :: ARR1(10)
... INTEGER :: JBODY
... WHERE((/(JBODY,JBODY=1,SIZE(ARR1(:)))/)/=1) ARR1(:)=1.0
... END SUBROUTINE FOO
... """
>>> reader = FortranStringReader(fcode)
>>> parser = ParserFactory().create(std='f2008')
>>> ast = parser(reader)
Traceback (most recent call last):
...
  File "/.../src/fparser/two/utils.py", line 376, in __new__
    obj = subcls(string, parent_cls=parent_cls)
  [Previous line repeated 10 more times]
  File "/.../src/fparser/two/utils.py", line 352, in __new__
    result = cls.match(string)
  File "/.../src/fparser/two/Fortran2003.py", line 9735, in match
    Intrinsic_Name, Actual_Arg_Spec_List, string)
  File "/.../src/fparser/two/utils.py", line 1232, in match
    rhs = repmap(rhs)
  File "/.../src/fparser/common/splitline.py", line 105, in __call__
    line = line.replace(k, self[k])
KeyError: 'F2PY_EXPR_TUPLE_41'

Replacing the statement by

WHERE((/JBODY,JBODY=1,SIZE(ARR1(:))/)/=1) ARR1(:)=1.0

(i.e., removing the obsolete parentheses) or by

WHERE((/(JBODY,JBODY=1,10)/)/=1) ARR1(:)=1.0

(i.e., hard-coding the size but keeping the parentheses) works fine.

arporter commented 4 years ago

I can reproduce (thanks for providing the example) and will take a look.

arporter commented 4 years ago

I think I've fixed it. 'Just' need to do the tidying and testing to bring this part of the code into line with the coding standards.

reuterbal commented 4 years ago

Thanks a ton! This looks like it was a nasty thing to find...

arporter commented 4 years ago

It wasn't too hard - once you see F2PY_EXPR_TUPLE_xxx in the output you know you're missing a remap() somewhere :-)

arporter commented 4 years ago

It turns out that the "obsolete parentheses" are required by the standard but not, unfortunately, by fparser2 :-(

arporter commented 4 years ago

Without the parentheses, fparser2 matches an Ac_Value_List rather than an implicit loop:

-> assert "array = (/ival, ival = 1, nval, istep/)" in str(ast)
(Pdb) ast
Assignment_Stmt(Name('array'), '=', Array_Constructor('(/', Ac_Value_List(',', (Name('ival'), Structure_Constructor_2(Name('ival'), Int_Literal_Constant('1', None)), Name('nval'), Name('istep'))), '/)'))

All valid Expr are valid members of this list but we can see that in this case the parser has matched a Structure_Constructor_2 for the assignment ival = 1. This does not seem to follow the standard:

R457 structure-constructor is derived-type-spec ( [ component-spec-list ] )
arporter commented 4 years ago

fparser2 has instead: https://github.com/stfc/fparser/blob/ae8f92b3ba0fd2e8cb58bd8aa186b6c2acb914e7/src/fparser/two/Fortran2003.py#L2289-L2292

where:

https://github.com/stfc/fparser/blob/ae8f92b3ba0fd2e8cb58bd8aa186b6c2acb914e7/src/fparser/two/Fortran2003.py#L2277-L2286

and it's the structure-constructor-2 that is causing the problem. I can find no mention of R457.b (with which structure-constructor-2 is labelled in the code) in the 2003 standard.

arporter commented 4 years ago

This appeared to be opening a can of worms so I've closed it again by opening issue #255 :-)

reuterbal commented 4 years ago

Thanks - and sorry for the trouble...

reuterbal commented 4 years ago

I can confirm that #256 fixes the issue for us. Many thanks!

rupertford commented 3 years ago

PR #256 is now on master. Closing this issue.