flowchart_docFlowchart

This section explains how a flowchart can be designed in Rhapsody developper for Ada.

Introduction

Usually, an operation body is defined in the operation's implementation feature. The user can write here some Ada code to define the operation's behavior.

A flowchart gives the possibility to define the operation's behavior by using a graphical method. For the Ada language, a specific flowchart has been created. The diagram of a flowchart will represent the whole operation's sequence of statement. A specific design must be respected to represent the operation body. This document gives all the possible representation of Ada code which must be respected.

Create a flowchart on an operation

The flowchart can be created from the context menu of the operation. Right click on the operation and select the menu item Add New > AdaCodeGeneration > AdaFlowchart

A new empty diagram will be opened, and you will be able to create the Flowchart, by using the available Flowchart elements which may appear on the right-hand side of the diagram.

Each element which can be used in an Ada Flowchart is briefly described in the next chapters.

Initial flow

The flowchart will always start with an initial flow. It will indicate from which element, the flowchart will start.

Control flow

The control flow will link the flowchart elements together, to show the order of execution of the elements.

Action

The action is the most basic element of a flowchart. It is used to contain simple statements. The action contains some text which can be either Ada code or Ada comments.

Action block

The Action block can contain a nested flowchart. It will be used to represent Ada block_statements.

Call operation

The Call operation element can be used to represent an Ada call statements.

Switch

The Switch state will be used to represent a case statement. It will contain the expression which is used to execute the switch. Then several control flows can lead from this state, in order to represent the case alternatives.

Exit

The Exit state is used to represent the exit statements.

Loop

The loop block is an action block which has the "Loop" stereotype. It is used to contain the sequence of statements of an Ada loop. This block must have a feedback loop which will specify the condition to exit the loop.

Root

The Root block is an action block which has the "Root" stereoytype. It can be used to enclose all the statements of an operation. It is useful when some exception must be represented.

Decision node

The decision node is used to represent the "if" statement.

Merge node

The merge node is used to finish an "if" statement or a case statement. This element is mandatory, if there is a decision node or a "switch" action. If it is omitted, the generated code may be incorrect.

Diagram Connector

The diagram connector is used to represent a label attached to a loop.

Activity final

The Activity final connector must be set at the end of the flowchart.

ExceptionFC

The ExecptionFC flow is used to define exception handlers which comes from an action block or a root block.

Code

The Code flow is just used to make connections between elements, which don't represent a logical flow. It can be useful, for example, after a return statement which is in the middle of the flowchart.

Dependency

The dependendy can be used to attach any comments or annotations on the flowchart elements.

Simple statements

The simple statement will be represented by an action in the flowchart. The action can contain any comment lines and any Ada statements. It should be used to define a single statement. But it is not forbidden to define several statements in one action. The diagrams thus become more compact, and can show more clearly the architecture of the flowchart and the compound statements ..

Call operation

The call statement will be represented by a Call Operation in the flowchart. There are two possibilities to set up this element. It depends if the called operation exists in the model or not.

        procedure simple_procedure_call_statement is
        begin
                put_line("Hello World");
                test_call("Hello World");
        end simple_procedure_call_statement;
       

Operation defined in the model.

If the operation is defined in the model, then it is possible to reference this by setting the "operation" field of the "call operation".

The actual parameters of the called operation will be defined in the "action on entry" of the "call operation".

Operation not defined in the model.

If the operation is not defined in the model, then the call statement must be written in the "action on entry" of the "call operation".

Exit statement

The exit statement is a little bit more complex. It can also specify a label and/or an exit condition. The following examples show the possible syntaxes.

  • exit;
  • exit label_1;
  • exit when a > 1;
  • exit label_1 when a > 1;

The exit statement will be represented by an action which has the "exit" stereotype. The exit label will be defined in the "action" field of the exit element. The exit condition will be represented by a guard on the incoming control flow. In the following examples, several use cases will be described.

Exit

In examples 1, 2, 3 and 4, the exit statement is alone in the loop statement.

        procedure simple_exit_statement_1 is
        begin
                for i in 1..2 loop
                        exit;
                end loop;
        end simple_exit_statement_1;
       

Exit with label

        procedure simple_exit_statement_2 is
        begin
                for i in 1..2 loop
                        exit label_1;
                end loop;
        end simple_exit_statement_2;
       

Exit with a "when" condition

The exit statement is the first statement of a block, and it also has a "when" condition. In this case, the exit statement will be represented by an empty action and an exit action. The control flow between these 2 actions will contain the "when" condition.

        procedure simple_exit_statement_3 is
        begin
                for i in 1..2 loop
                        exit when a > 1;
                end loop;
        end simple_exit_statement_3;
       

Exit with label and "when" condition

        procedure simple_exit_statement_4 is
        begin
                for i in 1..2 loop
                        exit label_1 when a > 1;
                end loop;
        end simple_exit_statement_4;
       

In examples 5, 6, 7 and 8, there is a statement before the exit statement

Exit

        procedure simple_exit_statement_5 is
        begin
                for i in 1..2 loop
                        a := 1;
                        exit;
                end loop;
        end simple_exit_statement_5;
       

Exit with label

        procedure simple_exit_statement_6 is
        begin
                for i in 1..2 loop
                        a := 1;
                        exit label_1;
                end loop;
        end simple_exit_statement_6;
       

Exit with a when condition

        procedure simple_exit_statement_7 is
        begin
                for i in 1..2 loop
                        a := 1;
                        exit when a > 1;
                end loop;
        end simple_exit_statement_7;
       

Exit with label and "when" condition

        procedure simple_exit_statement_5 is
        begin
                for i in 1..2 loop
                        a := 1;
                        exit label_1 when a > 1;
                end loop;
        end simple_exit_statement_5;
       

In examples 9, 10, 11 and 12, there is a statement after the exit statement

Exit

        procedure simple_exit_statement_9 is
        begin
                for i in 1..2 loop
                        exit;
                        a := 1;
                end loop;
        end simple_exit_statement_9;
       

Exit with label

        procedure simple_exit_statement_10 is
        begin
                for i in 1..2 loop
                        exit label_1;
                        a := 1;
                end loop;
        end simple_exit_statement_10;
       

Exit with "when" condition

        procedure simple_exit_statement_11 is
        begin
                for i in 1..2 loop
                        exit when a > 1;
                        a := 1;
                end loop;
        end simple_exit_statement_11;
       

Exit with label and "when" condition

        procedure simple_exit_statement_12 is
        begin
                for i in 1..2 loop
                        exit label_1 when a > 1;
                        a := 1;
                end loop;
        end simple_exit_statement_12;
       

Exit statement included in an "if" statement

This example shows an "exit" statement inside an "if" statement.

        procedure simple_exit_statement_13 is
        begin
                for i in 1..2 loop
                        if condition_ok then
                                exit;
                        end if;
                end loop;
        end simple_exit_statement_13;
       

Exit statement included in an if statement

This example is similar to example 13, but the exit statement has also a "when" condition.

        procedure simple_exit_statement_14 is
        begin
                for i in 1..2 loop
                        if condition_ok then
                                exit when a > 1;
                        end if;
                end loop;
        end simple_exit_statement_13;
       

If statement

An "if" statement must start with a decision node and must end with a merge node.

The decision node will have, at most, two outgoing control flows.

The guard of one outgoing control flow must contain the "if" condition.

The guard of the second outgoing control flow must have two possible values:

  • it is empty or it contains "else": this is the "else" alternative which can have some statements or no statements.
  • It contains "elsif" (the Ada keyword) condition, for "else if" alternatives.

Simple if condition.

                procedure compound_if_statement is
                begin
                   if a = b then
                          action_1;
                   end if;
                end compound_if_statement;
               

If Else condition

                procedure compound_if_else_statement is
                begin
                   if a = b then
                          action_1;
                   else
                          action_2;
                   end if;
                end compound_if_statement;
               

Else if condition

The "else if" condition has a particular design. Several decision nodes, linked by an "elsif" control flow are used to represent the different "elseif" alternatives. The goal of this design is to have the possibility to specify the order of the "else if" alternatives, which can be very important for the logic of the algorithm.

                procedure compound_if_elsif_statement is
                begin
                   if a = b then
                          action_1;
                   elsif a > b then
                          action_2;
                   elsif a > 10 then
                          action_3;
                   else
                          action_4;
                   end if;
                   a := 1;
                end compound_if_statement;
               

Nested if condition

                procedure compound_nested_if_statement is
                begin
                   if a = b then
                        if a = c then
                                action_1;
                        end if;
                                action_2;
                   end if;
                end compound_if_statement;
               

Loop statement

The loop statement is represented by an action block which has a feedback loop. The reverse engineering tool will add a "loop" stereotype to this action block. It is not mandatory, but it will add more visibility to the diagram. The action block contains a nested diagram. There are three different kind of loops:

  • un-ended loop
  • for loop
  • while loop

These three different kind of loops will be specified in the guard of the feedback loop which will contain the condition necessary to exit the loop.

Un-ended loop

                procedure compound_loop_statement is
                begin
                        loop
                           a := 1;
                        end loop;
                end compound_loop_statement;
               

Loop identifier

If the loop has an identifier, then it will be represented by a diagram connector.

                procedure compound_loop_statement_1 is
                begin
                        label_1:
                        loop
                           a := 1;
                        end loop;
                end compound_loop_statement_1;
               

For loop

The "for" loop has a guard on the feedback loop. The guard shall contain the Ada declaration of the kind of loop. In the following example it shall contain "for i in 1..2".

                procedure compound_loop_statement_2 is
                begin
                        for i in 1..2 loop
                           a := 1;
                        end loop;
                end compound_loop_statement_2;
               

While loop

The "while" loop has a guard on the feedback loop. The guard shall contain the Ada declaration of the kind of loop. In the following example it shall contain "while a < 10".

                procedure compound_loop_statement_3 is
                begin
                        while a < 10 loop
                           a := 1;
                        end loop;
                end compound_loop_statement_3;
               

Nested loop

Nested loop are represented with nested action blocks.

                procedure compound_nested_loop_statement is
                begin
                        for i in 1..2 loop
                                for j in 1..2 loop
                                        a := 1;
                                end loop;
                        end loop;
                end compound_nested_loop_statement;
               

Case statement

A case statement is represented by an action with the stereotype "switch". It must be closed by a merge connector. The expression of the case statement is set in the "action" field of the "switch" action. Each alternative is represented by a control flow with a guard, which comes from of the "switch" action.

        procedure compound_case_statement is
        begin
                case color is
                  when red => a := 1;
                  when green => a := 2;
                  when blue => a := 3;
                  when others => a := 4;
                end case;
        end compound_case_statement;
       

Block statement

A block statement is represented by an action block. The block statement can have a block identifier which will be represented by a diagram connector.

        procedure compound_block_label_statement is
        begin
                Label_1:
                declare
                   a : integer;
                begin
                   action_1;
                end label_1;
                a := 1;
        end compound_block_statement;
       

Exception

Exceptions are caught from any place in the code within a block statement. For this reason, exception will be represented by an "exception" control flow which goes out of an action block. There are two situations:

  • exception caught in a block statement
  • exception caught in the operation body

Exception on block statement

The exception handlers are represented by "exception" control flows which comes from an action block, and goes to a list of actions.

        procedure exception_handler_on_block is
        begin
                begin
                        a := 1;
                exception
                        when error_1 => check_error_1;
                        when error_2 => check_error_2;
                end;
        end exception_handler_on_block;
       

Exception on operation body

The exception handlers which are defined in an operation are created from its root action block. In this case, the operation flowchart is nested into a "root" action block. This "root" action block is supposed to represent the operation itself. It will help to represent the exception handlers defined in the operation.

        procedure exception_handler_on_operation is
        begin
                a := 1;
        exception
                when error_1 => check_error_1;
                when error_2 => check_error_2;
        end exception_handler_on_operation;
       

Declarative part

The declarative part of an operation or a block statement, has a similar structure to the Ada package body declarative part. It is represented by a Rhapsody class with the stereotype "DeclarativePart". As operations or action blocks cannot have nested classes, the nested "DeclarativePart" classes are created on the Owner of the operations. These "DeclarativePart" classes are linked to their corresponding elements (operation or action block) by a dependency. The reverse engineering tool will create a class with the same name as the operation, prefixed with "Decl_Part_". The user is free to set the name as he wants.

In the following example, the declarative part is composed of the declaration of an attribute "a", and an operation "nested_operation".

        procedure the_procedure is
                a : integer;
                procedure nested_operation is
                begin
                        b := 1;
                end nested_operation;
        begin
                a := 1;
        end the_procedure;
       

The screenshot of the Rhapsody browser shown below, shows the architecture of the class which has an operation with a declarative part.

  • The class_with_operation class declares one operation which has a declarative part.
  • The class_with_operation class declares a nested class Decl_Part_The_Procedure. This nested class will declare an attribute and a nested operation.
  • The The_Procedure operation has a dependency to Decl_Part_ The_Procedure.

This representation is recursive. In the example above, the declarative part of Nested_Operation should be represented by nested class Decl_Part_Nested_Operation, which should be created on Decl_Part_The_Procedure class.

Create a Flowchart from operation implementation

It is possible to create a flowchart directly from an existing Rhapsody operation implementation. If you right click on an operation, you will get a menu item which will create a flowchart from the selected operation.

The operation implementation is still present in the model, after having imported the flowchart. The code will still be generated from the operation implementation. User can remove implementation manually, if needed.

It is possible to remove automatically the operation implementation, by setting the property "removeOriginalCode" to true, in the file Sodius/RiA_CG/AdaRevEng/op2FC.ini.