gfc_code#
The executable statements in a program unit are represented by a
nested chain of gfc_code structures. The type of statement is
identified by the op member of the structure, the different
possible values are enumerated in gfc_exec_op. A special
member of this enum is EXEC_NOP which is used to
represent the various END statements if they carry a label.
Depending on the type of statement some of the other fields will be
filled in. Fields that are generally applicable are the next
and here fields. The former points to the next statement in
the current block or is NULL if the current statement is the
last in a block, here points to the statement label of the
current statement.
If the current statement is one of IF, DO, SELECT
it starts a block, i.e. a nested level in the program. In order to
represent this, the block member is set to point to a
gfc_code structure whose next member starts the chain of
statements inside the block; this structure’s op member should be set to
the same value as the parent structure’s op member. The SELECT
and IF statements may contain various blocks (the chain of ELSE IF
and ELSE blocks or the various CASE s, respectively). These chains
are linked-lists formed by the block members.
Consider the following example code:
IF (foo < 20) THEN
PRINT *, "Too small"
foo = 20
ELSEIF (foo > 50) THEN
PRINT *, "Too large"
foo = 50
ELSE
PRINT *, "Good"
END IF
This statement-block will be represented in the internal gfortran tree as
follows, were the horizontal link-chains are those induced by the next
members and vertical links down are those of block. ==| and
--| mean NULL pointers to mark the end of a chain:
... ==> IF ==> ...
|
+--> IF foo < 20 ==> PRINT *, "Too small" ==> foo = 20 ==|
|
+--> IF foo > 50 ==> PRINT *, "Too large" ==> foo = 50 ==|
|
+--> ELSE ==> PRINT *, "Good" ==|
|
+--|
IF Blocks#
Conditionals are represented by gfc_code structures with their
op member set to EXEC_IF. This structure’s block
member must point to another gfc_code node that is the header of the
if-block. This header’s op member must be set to EXEC_IF, too,
its expr member holds the condition to check for, and its next
should point to the code-chain of the statements to execute if the condition is
true.
If in addition an ELSEIF or ELSE block is present, the
block member of the if-block-header node points to yet another
gfc_code structure that is the header of the elseif- or else-block. Its
structure is identical to that of the if-block-header, except that in case of an
ELSE block without a new condition the expr member should be
NULL. This block can itself have its block member point to the
next ELSEIF or ELSE block if there’s a chain of them.
Loops#
DO loops are stored in the tree as gfc_code nodes with their
op set to EXEC_DO for a DO loop with iterator variable and
to EXEC_DO_WHILE for infinite DO s and DO WHILE blocks.
Their block member should point to a gfc_code structure heading
the code-chain of the loop body; its op member should be set to
EXEC_DO or EXEC_DO_WHILE, too, respectively.
For DO WHILE loops, the loop condition is stored on the top
gfc_code structure’s expr member; DO forever loops are
simply DO WHILE loops with a constant .TRUE. loop condition in
the internal representation.
Similarly, DO loops with an iterator have instead of the condition their
ext.iterator member set to the correct values for the loop iterator
variable and its range.
SELECT Statements#
A SELECT block is introduced by a gfc_code structure with an
op member of EXEC_SELECT and expr containing the expression
to evaluate and test. Its block member starts a list of gfc_code
structures linked together by their block members that stores the various
CASE parts.
Each CASE node has its op member set to EXEC_SELECT, too,
its next member points to the code-chain to be executed in the current
case-block, and extx.case_list contains the case-values this block
corresponds to. The block member links to the next case in the list.
BLOCK and ASSOCIATE#
The code related to a BLOCK statement is stored inside an
gfc_code structure (say c)
with c.op set to EXEC_BLOCK. The
gfc_namespace holding the locally defined variables of the
BLOCK is stored in c.ext.block.ns. The code inside the
construct is in c.code.
ASSOCIATE constructs are based on BLOCK and thus also have
the internal storage structure described above (including EXEC_BLOCK).
However, for them c.ext.block.assoc is set additionally and points
to a linked list of gfc_association_list structures. Those
structures basically store a link of associate-names to target expressions.
The associate-names themselves are still also added to the BLOCK ‘s
namespace as ordinary symbols, but they have their gfc_symbol ‘s
member assoc set also pointing to the association-list structure.
This way associate-names can be distinguished from ordinary variables
and their target expressions identified.
For association to expressions (as opposed to variables), at the very beginning
of the BLOCK construct assignments are automatically generated to
set the corresponding variables to their target expressions’ values, and
later on the compiler simply disallows using such associate-names in contexts
that may change the value.