fparser
fparser is a Python implementation of a Fortran parser that provides the ability to parse Fortran code (F77, Fortran 2003, 2008, 2018 standards) and represent it as an Abstract Syntax Tree (AST). This allows for static analysis, refactoring, or code generation. The current stable version is 0.2.2, with active development and regular releases.
Common errors
-
ModuleNotFoundError: No module named 'fparser.one'
cause Attempting to import from the deprecated 'fparser.one' module after installing `fparser` version 0.2.x or later.fixThe 'fparser.one' API is completely different and no longer maintained. Update your code to use the 'fparser.two' API, starting with `from fparser.two import Fortran2003` (or Fortran2008/2018). -
fparser.two.parser.ParseError: Failed to parse input at line X, column Y
cause The Fortran code provided is either syntactically incorrect, or the chosen Fortran standard parser (e.g., Fortran2003) cannot handle the features used in the code.fixVerify the Fortran code for syntax errors. If the code is valid, try using a newer Fortran standard parser, e.g., `from fparser.two import Fortran2018`, as your code might be using modern Fortran features. -
FileNotFoundError: [Errno 2] No such file or directory: 'your_fortran_file.f90'
cause The `read_file` function could not locate the specified Fortran file at the given path.fixDouble-check the file path provided to `read_file()`. Ensure the file exists and the path is either absolute or correct relative to your current working directory. Use `os.path.exists()` for debugging. -
TypeError: parse() missing 1 required positional argument: 'reader'
cause The `parse()` method of Fortran standard classes expects a `reader` object (e.g., from `read_file` or `read_string`), not a raw string or file path.fixFirst, use `read_file()` or `read_string()` to create a reader object. Then pass this object to the parser: `reader = read_string(my_fortran_code); tree = Fortran2003.parse(reader)`.
Warnings
- breaking fparser underwent a complete rewrite for version 2 (fparser.two). The API for fparser.one is incompatible and should not be used for new projects.
- gotcha Selecting the correct Fortran standard parser (Fortran2003, Fortran2008, Fortran2018) is crucial. Using an older standard parser on modern Fortran code will likely result in parse errors or an incomplete AST.
- gotcha Ensure you use the correct input reader function: `read_file` for physical files and `read_string` for in-memory Fortran code strings. Mixing them will lead to errors.
- gotcha Parsing large Fortran files can be memory-intensive. For very large codebases, consider processing files incrementally or optimizing AST traversal.
Install
-
pip install fparser
Imports
- Fortran2003
from fparser.common.Fortran2003 import Fortran2003
from fparser.two import Fortran2003
- read_file
from fparser.two.readfortran import read_file
from fparser.common.readfortran import read_file
- walk
from fparser.common.walk import walk
from fparser.two.utils import walk
- fparser.one
import fparser.one
Use 'fparser.two' API instead
Quickstart
import os
from fparser.two import Fortran2003
from fparser.two.utils import walk
from fparser.common.readfortran import read_string
# Example Fortran code as a string
fortran_code = """
MODULE my_module
INTEGER, PARAMETER :: DP = KIND(1.0D0)
CONTAINS
SUBROUTINE my_sub(a, b)
REAL(DP), INTENT(IN) :: a
REAL(DP), INTENT(OUT) :: b
b = a * 2.0_DP
END SUBROUTINE my_sub
END MODULE my_module
PROGRAM main
USE my_module
IMPLICIT NONE
REAL(DP) :: x, y
x = 10.0_DP
CALL my_sub(x, y)
PRINT *, "Result:", y
END PROGRAM main
"""
# Read the Fortran code from a string
reader = read_string(fortran_code, ignore_comments=True)
# Parse the Fortran code using the Fortran 2003 standard parser
tree = Fortran2003.parse(reader)
# Walk the AST to find specific nodes, e.g., subroutine calls and variable declarations
print("Walking the AST to find subroutine calls and type declarations:")
for node in walk(tree):
if isinstance(node, Fortran2003.Call_Stmt):
print(f" Found Call Statement: {node.items[0].name}")
elif isinstance(node, Fortran2003.Declaration_Type_Spec):
# For simplicity, just printing the type spec itself.
# Inspecting parent/sibling nodes would reveal variable names.
print(f" Found Type Declaration: {node.items[0]} (raw: {node})")
# Example: Accessing specific parts of the tree (e.g., the program name)
if tree.children and isinstance(tree.children[-1], Fortran2003.Main_Program):
program_name = tree.children[-1].get_name()
print(f"\nMain Program name: {program_name}")
# You can also regenerate the code from the AST
# print("\nRegenerated Fortran code:")
# print(tree.tofortran())