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 28 forks source link

No difference between function call and array reference #370

Open antoine-morvan opened 1 year ago

antoine-morvan commented 1 year ago

Hi,

In the AST, I did not find a way to differenciate function calls and array references.

My sample program is the following:

function mytestfunc(i) result(x)
  integer, intent(in) :: i
  integer :: x
  x = 1337 * i
end function mytestfunc

program test
    integer :: myvar
    integer, dimension(1:10) :: myArray
    myArray = (/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /)
    !! function call
    myvar = mytestfunc(3)
    write(*,*) myvar
    !! array reference
    myvar = myArray(3)
    write(*,*) myvar
end program test

and my script is the following:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

ARG_FORTRAN_FILE_INPUT_PATH = "input.f90"
ARG_FORTRAN_STANDARD = 'f2008'

from fparser.common.readfortran import FortranFileReader
from fparser.two.parser import ParserFactory
from fparser.common.readfortran import FortranFileReader
from fparser.two.utils import walk
from fparser.two.Fortran2003 import Main_Program, Assignment_Stmt

print("## Parsing input")
reader = FortranFileReader("{0}".format(ARG_FORTRAN_FILE_INPUT_PATH), ignore_comments=True)
f_parser = ParserFactory().create(std=ARG_FORTRAN_STANDARD)
parse_tree = f_parser(reader)
print("## Visiting AST")
programs = walk(parse_tree,Main_Program)
for program in programs:
    execParts = walk(program,Assignment_Stmt)
    for execPart in execParts[1:3]:
        walk(execPart, debug=True)

The debug print for the 2 assignments to myvar is the following:

child type =  <class 'fparser.two.Fortran2003.Assignment_Stmt'>
  child type =  <class 'fparser.two.Fortran2003.Name'>
  child type =  <class 'str'> '='
  child type =  <class 'fparser.two.Fortran2003.Part_Ref'>
    child type =  <class 'fparser.two.Fortran2003.Name'>
    child type =  <class 'fparser.two.Fortran2003.Section_Subscript_List'>
      child type =  <class 'fparser.two.Fortran2003.Int_Literal_Constant'>
        child type =  <class 'str'> '3'
        child type =  <class 'NoneType'>
child type =  <class 'fparser.two.Fortran2003.Assignment_Stmt'>
  child type =  <class 'fparser.two.Fortran2003.Name'>
  child type =  <class 'str'> '='
  child type =  <class 'fparser.two.Fortran2003.Part_Ref'>
    child type =  <class 'fparser.two.Fortran2003.Name'>
    child type =  <class 'fparser.two.Fortran2003.Section_Subscript_List'>
      child type =  <class 'fparser.two.Fortran2003.Int_Literal_Constant'>
        child type =  <class 'str'> '3'
        child type =  <class 'NoneType'>

We can observe that woth assignements RHS are a Part_Ref / Name / Subscript / Const.

Is there any way to differenciate the two cases ?

Best.

rupertford commented 1 year ago

In general there is a problem in distinguishing between arrays and functions in Fortran unless you are able to fully link the program and in general we are only parsing part of a full program. What fparser2 currently does is match with the first thing it can which I guess is an assignment here. I think in your particular case we could determine that it is a function as we could add mytestfunc to the symbol table. However, we don't do that at the moment.