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

fparser2: program statement with missing name causes crash #117

Closed arporter closed 5 years ago

arporter commented 5 years ago

According to R1102 the PROGRAM statement must have an associated name. However, if fparser2 encounters e.g.

program
  write(*,*) "Hello"
end program

then it crashes with:

    @staticmethod
    def match(string):
>       return StringBase.match(pattern.abs_name, string.replace(' ', ''))
E       AttributeError: 'NoneType' object has no attribute 'replace'

fparser/src/fparser/two/Fortran2003.py:559: AttributeError

It should of course raise a SyntaxError.

rupertford commented 5 years ago

R1102 simply makes use of BlockBase to do its match. It turns out that blockbase does not check whether the name for the startclass has been supplied before comparing. If we add the following code

            if hasattr(obj, 'get_name'):
                if not obj.get_name():
                    obj.restore_reader(reader)
                    raise FortranSyntaxError("Name is required")

after the existing code

            if match_names:
                start_name = obj.get_start_name()

we raise the exception.

Hwever, why does the name matching return an error?

rupertford commented 5 years ago

Actually it can (and I think should) be intercepted in the Program_Stmt class. This class currently happily returns a null or empty "" name. However we want to raise an exception if this is the case. The following code does this. I think we need #121 to be on master first though.

    def match(string):
        result = WORDClsBase.match('PROGRAM', Program_Name, string,
                                 require_cls=True)
        if not result[1]:
            raise FortranSyntaxError("There be no name my lover")
        return result
    match = staticmethod(match)
rupertford commented 5 years ago

OK, I've changed my mind again. WORDClsBase is used in many situations in fparser2. Whenever its match() method is used with require_cls=True the associated rule expects to have content for the class instance. Therefore an exception should be raised in all of these cases. The reason one is not raised is because the implementation of WORDClsBase returns a match but with None as the return value for the class instance. This is a simple bug, the code that does this test appears after the optional "::" is dealt with so anything without "::" misses the test.

For example

program  xx 
! R521 says the object name list must not be empty
asynchronous
! R537 says the dummy arg name list must not be empty
optional
! R540 says the pointer declaration list must not be empty
pointer
end program
rupert@ubuntu:~/proj/fparser/src/fparser$ ./scripts/fparser2.py test.f90
PROGRAM xx
  ASYNCHRONOUS
  OPTIONAL
  POINTER
END PROGRAM xx
rupert@ubuntu:~/proj/fparser/src/fparser$

Syntax errors should be raised for each of the three lines but are not. All of these examples use WORDClsBase. If we modify the match method appropriately, we get the expected result ...

rupert@ubuntu:~/proj/fparser/src/fparser$ ./scripts/fparser2.py test.f90
Syntax error: at line 3
>>>asynchronous
arporter commented 5 years ago

123 has been merged to master.