Mercurium is a C/C++/Fortran source-to-source compilation infrastructure aimed at fast prototyping developed by the Programming Models group at the Barcelona Supercomputing Center
GNU Lesser General Public License v3.0
69
stars
23
forks
source link
Enforce the order of Fortran statements within a program unit #23
Since the beginning, Mercurium hasn't enforced the order of Fortran
statements within program units. This leads to some complication
and wrongly handled cases.
Also the FE lacked a generic mechanism to delay actions. Unfortunately
some of the actions must be delayed until we know some form of statement
cannot occur again (e.g. USE, IMPLICIT), so we could not reliably do this.
Each statement is now assigned to a statement ordering class. For the
specific case of IMPLICIT NONE we need a new AST node for it so we
can do this (it was currently represented with the same AST kind as
a regular IMPLICIT statement). A few classes only
represent a single statement (SOC_DATA, SOC_FORMAT, SOC_IMPLICIT,
SOC_IMPLICIT_NONE, SOC_IMPORT, SOC_USE). Classes SOC_DECLARATION
and SOC_EXECUTABLE represent non-executable and executable Fortran
statements respectively. Note that because of the way we parse the
Fortran code, statements that demarcate the range of program or
subprogram units (like CONTAINS, FUNCTIONS, SUBROUTINE and their
related END-statements) are not assigned a statement order class.
The array statement_order has one entry per set of classes allowed
at a given point. A program unit starts at the beginning.
When handling the statements within a program unit
the current statement (once disambiguated) is checked against
the current statement order. If it still allowed, nothing changes,
if the statement is not allowed, then the order is advanced until
it is allowed. If no order allows the current statement then this
statement is misplaced within the program unit and this is an error.
Each program unit kind is assigned a statement constraint checker
which basically is an index in the above statement_order array and
a function that filters statements that are not allowed in the program
unit (e.g. we used to ICE when an executable statement was used
in the specification part of a MODULE, this is not the case any more).
This change also adds a generic mecanism for delayed actions. We had some
ad-hoc delayed actions in the past but now that we can rely on the order
we can now be more generic and more fine-grained. There is a set of
delayed categories which mean at which point the delayed action will be
run. We can now delay tasks after all the use statements have been
seen, all the implicit statements, all the declarations and at the
end of the current program unit. Delayed actions are associated
to a category and a pair function-data (i.e. a closure).
Because now we can delay the initializations of the declarations,
we no longer need to do odd things while checking an initializer
expression. The same applies when checking the bounds of array
declarations. Thanks to this, we can also make the handling of intrinsics
more consistent and we can remove the previous exceptional cases.
Since the beginning, Mercurium hasn't enforced the order of Fortran statements within program units. This leads to some complication and wrongly handled cases.
Also the FE lacked a generic mechanism to delay actions. Unfortunately some of the actions must be delayed until we know some form of statement cannot occur again (e.g. USE, IMPLICIT), so we could not reliably do this.
Each statement is now assigned to a statement ordering class. For the specific case of IMPLICIT NONE we need a new AST node for it so we can do this (it was currently represented with the same AST kind as a regular IMPLICIT statement). A few classes only represent a single statement (SOC_DATA, SOC_FORMAT, SOC_IMPLICIT, SOC_IMPLICIT_NONE, SOC_IMPORT, SOC_USE). Classes SOC_DECLARATION and SOC_EXECUTABLE represent non-executable and executable Fortran statements respectively. Note that because of the way we parse the Fortran code, statements that demarcate the range of program or subprogram units (like CONTAINS, FUNCTIONS, SUBROUTINE and their related END-statements) are not assigned a statement order class.
The array statement_order has one entry per set of classes allowed at a given point. A program unit starts at the beginning. When handling the statements within a program unit the current statement (once disambiguated) is checked against the current statement order. If it still allowed, nothing changes, if the statement is not allowed, then the order is advanced until it is allowed. If no order allows the current statement then this statement is misplaced within the program unit and this is an error.
Each program unit kind is assigned a statement constraint checker which basically is an index in the above statement_order array and a function that filters statements that are not allowed in the program unit (e.g. we used to ICE when an executable statement was used in the specification part of a MODULE, this is not the case any more).
This change also adds a generic mecanism for delayed actions. We had some ad-hoc delayed actions in the past but now that we can rely on the order we can now be more generic and more fine-grained. There is a set of delayed categories which mean at which point the delayed action will be run. We can now delay tasks after all the use statements have been seen, all the implicit statements, all the declarations and at the end of the current program unit. Delayed actions are associated to a category and a pair function-data (i.e. a closure).
Because now we can delay the initializations of the declarations, we no longer need to do odd things while checking an initializer expression. The same applies when checking the bounds of array declarations. Thanks to this, we can also make the handling of intrinsics more consistent and we can remove the previous exceptional cases.