Next: , Up: Frontend Data Structures


3.1 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 CASEs, 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" ==|
                            |
                            +--|

3.1.1 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.

3.1.2 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 DOs 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.

3.1.3 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.

3.1.4 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.