[Previous] [Next] [Contents] [Index]


    Using SDL Extensions

This chapter describes some of the extensions to SDL that are available in SDT, and that are not documented outside Telelogic.

The extensions covered here are the Own and ORef generators, and the algorithmic extensions to SDL. There are other Telelogic-specific extensions to SDL supported in SDT, mainly concerning data types, generators and operators. These extensions are covered in Data Types in SDT.

Table of Contents 

Own and ORef Generators

Introduction

A major problem to obtain fast applications generated from SDL is the data model, that requires copying of data in a number of places. In an interchange of a signal between two processes, the signal parameters are first copied from the sending process to the signal and then again copied from the signal to the receiver. If the two processes have access to common memory, it would be possible only to pass a reference to the data via the signal, and in that way there would be no need to perform the two copy actions.

The generator Ref can be used for this purpose (see The Ref Generator), but there is a number of important problems when using the Ref generator:

Basic Properties of the Own Generator

The purpose of the Own generator is to solve the situation described above, i.e. it should be possible to limit the number of copy operations that are needed, at the same time as the user should not need to worry about memory deallocation, and simultaneous access to the memory from several processes should not be possible.

The basic property of the Own generator that makes this possible is that only one Own pointer at a time can refer to the same memory. This variable (of Own type) is referred to as the owner of the memory. Ownership is passed to another variable by assignment.


Example 38 : Own variables      

This assignment is interpreted as follows:


By this scheme the basic properties of the Own generator is preserved, i.e. all memory no longer accessible is deallocated and there is only one reference to the data.

To handle more complex cases, the order in which these operations are performed is a bit more complicated. With the same types and variables as in the example above and the procedure P, taking three Own_Data parameters:

we get the following execution:

Ownership is, as can be seen in the example above, passed not only in assignments, but in every case where the reference is assigned to some other place. This happens for example in assignments, input, output, set, reset, procedure call, and create. The only places where ownership is not passed is:

Note that copy(v2) is a "deep" copy, i.e. any Own pointers in the copied data structure are also copied. Otherwise we would end up with several references to the same memory.

Definition of Own Generator

The Own generator is defined in SDL according to the following:

Basically the Own generator is a way to introduce pointers to allocated memory. The Null value is as usual interpreted as "a reference to nothing". The operators "*>" are the Extract! and Modify! operators, i.e. the way to reference or modify the memory referred to by the pointer. Using the type and variables in the previous example the following statements are correct:

The "*>" operator have the same properties as the `*' in C, i.e. "v1*>" has the same meaning as "*v1" in C. To make the syntax a bit easier there is a possibility to let the SDT Analyzer implicitly insert the "*>" in the expressions where it is needed. The example above would then become:

which is a bit easier to read. More details about the implicit type conversions can be found in Implicit Type Conversions.

Before it is possible to start working with components in the data referenced by the Own pointer, the Own pointer must be initialized with a complete value (default is Null as can be seen in the definition). The Make! operator is a suitable way to initialize a variable. As usual the concrete syntax for Make! is "(. x .)", where x should be replaced by a value of the ItemSort for the current Own pointer.

Example of intializations using the data definitions in the examples above:

The inner "(. .)" is for the constructing the struct value and the outer "(. .)" is for the Own make! function. It is, however, possible to avoid the double parentheses as there is an implicit type conversion from a type T to Own(T), by implicitly inserting "(. .)" around a value of type T. So the examples above could (and probably should) be written as

Again, please see Implicit Type Conversions. The other operations available for own pointers, apart from "*>" and make!, are assignment, test for equality, and copy. The assign operator has already been described above. Test for equality (`=' and "/=") does NOT test for pointer equality as two Own pointers cannot be equal. Instead equality is "deep" equality, i.e. the values referred to by the Own pointers are compared.

An implicit copy operator has been inserted for every type. It takes a value and returns a copy of that value. For all types that are not Own pointers or contain Own pointers, this operator is meaningless as it just returns the same value. For Own pointers or for structured values containing Own pointers, the copy function, however, copies the values referenced by the Own pointers.

The ORef Generator

The ORef generator is intended to be used together with the Own generator to provide a way to temporary refer to owned data during some algorithm, without affecting the ownership of the memory. If, for example, Own pointers is used to create a linked list and we would like to write a procedure that calculates the length of the list, then we need a temporary pointer going through the list. If that pointer was a Own pointer the list would be destroyed while we traverse the list, as there may be only one Own pointer referring to the same memory.


Example 39 : Own and ORef      

Note the use of the ListRef type both in the formal parameter Head and in the local variable Temp. If Head would be of ListOwn type, the variable MyList would be null after the call of ListLength, which is not what we intended. If ListOwn was used as type for the variable Temp, as the statement Temp := Temp!Next would unlink the complete list.

Another example of a typical application of ORef, is to introduce backward pointer in a linked list, to make it doubly linked. If the forward pointers are Own pointers then the backward pointers cannot be Own pointers as then we would have two Own pointers on the same object.

The ORef generator is defined as:

Where "*>" is used for dereferencing and `&' is an address operator.

Run-Time Errors

There are four situations, concerning Own and ORef, that can lead to a run-time error. These situations are:

These problems are all found during simulation and validation, except that if an ORef pointer refers to a data area that is first deallocated and then allocated again, the ORef pointer is no longer invalid.

Examples of run-time error situations assuming the data types in the previous section.

Implicit Type Conversions

Note: 

Implicit type conversions are by default off in the SDT Analyzer. It can be turned on in the Analyze dialog in the Organizer. Implicit type conversions will, however, influence the time needed for semantic analysis. The more complex an expression is, the more effect on time the implicit type conversions will have, as the number of possibilities increases (often exponentially) with the length of the expression.

The purpose of the implicit type conversions is to simplify the use of the Own generator. The code that operate on data structures should be the same if you use a data structure T or if you use a own pointer to T, own(T). The only thing that a user has to think about is if ownership should be passed or if a copy should be made, when passing data to somewhere else.

The implicit conversions never change the type of, for example, an assignment. If there is an assignment:

no implicit type conversions are applied on R1, as that would change the type of the assignment. Type conversions might be applied on L1 in the right hand side, to obtain the correct type. In an assignment:

the implicit type conversions might also be applied to the index expression, i.e. to a.

In a test for equality and in similar situations, e.g. in:

implicit type conversions are first applied to the left expression, i.e. to L1. If that yields a correct interpretation, that one is selected. Otherwise implicit type conversions are tried on the right expression, i.e. to R1.

Assume a type T and a two generator instantiations Own_T = Own(T) and ORef_T = ORef(T). Assume also the variables:

Then the following implicit type conversions are possible:

Type conversions 1 and 6 make it possible to exclude "*>" in component selections. Instead of writing

it is possible to write

This possibility also exists for ordinary Ref pointers.

Type conversion 2 makes it possible to assign an Own pointer a new value of the Own pointer component type. If A is a Own pointer to a struct containing two integers, then it is possible to write:

which means the same as

where the inner "(. .)" is the make! function for the struct and the outer "(. .)" is the make! function for the Own pointer.

This possibility also exists for ordinary Ref pointers.

Type conversion 3 makes it possible to assign an ORef pointer to an Own pointer. This is already used in the examples above, but is not directly possible, as an ORef and an Own pointer are two distinct types. The demote operator converts a Own pointer to the corresponding ORef pointer. (Corresponding means the first ORef with the same component type in the same scope unit as the Own pointer type is defined).

Type conversion 4 makes it possible to construct a new Own value, starting from a ORef value. The conversion is performed in two steps, first going from ORef_T to T by applying conversion 6, and then from T to Own_T by applying conversion 2.

Type conversion 5 makes it possible to let a ORef_T pointer refer to a DCL variable by writing:

which means the same thing as

where `&' is the address operator (as in C).

Algorithms in SDL

A former problem in SDL is the lack of support for writing algorithms. For pure calculations, not involving communication, the graphical form for SDL tends to become ordinary flow charts, which is usually not a good way to describe advanced algorithms. Such, often large, parts of an SDL diagram also hide other, from the SDL point-of-view, more important parts of the diagram, namely the state machine and the communication aspects.

The algorithmic extensions described here addresses these problems by introducing the possibility to write algorithms in textual form within a Task symbol, and also to define procedures and operators in textual form in text symbols. There are two major advantages with this approach, compared to ordinary SDL:

In addition, the algorithmic extensions make it possible to now define procedures and operators in textual form in text symbols in SDL-GR.

These algorithmic extensions to SDL have been approved by ITU Study Group 10 to be incorporated into the official Master List of Changes that will affect the next ITU recommendation for SDL. There are a few minor differences in the support for SDL algorithms in SDT compared with the ITU definition -- these are noted in the descriptions below.

The constructs that are part of the extensions are:

Compound Statement

The basic concept in the algorithmic extensions is the compound statement. A compound statement starts with a `{', which is followed by a sequence of variable declarations and a sequence of statements, and it then ends with a `}'.

A compound statement may be used in three places:

Note: 

According to the ITU language definition the body of a procedure or operator is allowed to be a statement. In SDT, however, a compound statement is required. This means that if the body consists of only one statement, the enclosing "{ }" are required anyhow.

Note also that the enclosing "{ }" should not be included in a Task symbol in the SDL Editor. These braces will be added when the SDL system is converted to SDL-PR for analysis.


Example 40       

Contents in Task symbol in SDL-GR:

Corresponding code in SDL-PR:


Example 41       

A procedure in a text symbol in SDL-GR, or in SDL-PR:


Local Variables

Within a compound statement it is allowed to define a number of local variables. These variables will be created when the compound statement is entered and will be destroyed when the compound statement is left. The semantics of a compound statement is very much like a procedure without parameters, which is defined and called at the place of the compound statement.

A variable declaration within a compound statement looks that same as ordinary variable declarations, except that "exported" and "revealed" are not allowed. Example:

Statements

A statement within a compound statement my be of any of the following types:

Note that each statement (and each variable declaration statement) ends with a `;'. The following statement types use the same syntax as in ordinary SDL-PR:


Example 42 : Ordinary SDL-PR statements      

Note: 

According to the ITU language definition the keyword call in a procedure call is optional. In SDT it is, however, required.

If Statements

The structure of an if statement is:

where the else part is optional. The Boolean expression is first calculated. If it has the value true, the first statement is executed, otherwise the else statement, if present, is executed.


Example 43       

If there are several possible if statements for an else path (the "dangling else" problem), the innermost if is always selected.


Example 44       

means:


Decision Statements

A decision statement has much in common with the ordinary decisions found in SDL, i.e. it is a multi-branch statement. The major differences between decision statements and ordinary statements is that all paths in a decision statement ends at the enddecision.


Example 45       

The decision question and the decision answers follows the same syntax and semantics as in ordinary decisions. Following an answer there should be a statement, which might be a compound statement.

Loop Statements

A loop statement is used to repeat the execution of a statement (or usually a compound statement), a number of times. The loop is controlled by a loop variable, which either can be locally defined in the loop or defined somewhere outside of the loop.

The loop control part contains three fields:


Example 46       

should be interpreted as (in C-like syntax):


Note the difference between SDL and C when it comes to the variable update. In C this is a statement, in SDL it is an expression to be assigned to the variable mentioned in the loop variable indicator.

In the loop variable indicator, either a new variable can be defined or a previously defined variable can be used. Example:

Other possibilities in loop statements:

Label Statements

A label statement is just a label followed by a statement. These labels are only of interest if the statement following the label is a loop statement. The label name can be used in break statements (see below) to break out of a loop statement. Example:

Note: 

There are no "join" or "goto" statements allowed in the algorithmic extensions to SDL.

Jump Statements

Jump statements, i.e. break and continue, are used to change the execution flow within a loop.

A continue statement, which only may occur within a loop, is defined as: "skip the remaining part of the loop body and continue with updating the loop variable to its next value."


Example 47       

should be interpreted as (in C like syntax):


A break statement can be used to stop the execution of the loop and directly goto the statement after the loop.


Example 48       

should be interpreted as (in C like syntax):


A break statement breaks out of the innermost loop statement. By using labeled loop statements breaks out of outer loops can be achieved.


Example 49       

The break statement in the inner loop breaks out from both loops as it mentions the label for the outer loop.


Empty Statements

It is allowed to have an empty statement, represented by just writing nothing. This is sometimes useful, for example as loop statement:

Grammar for the Algorithmic Extensions

Meta grammar:

Start of Grammar
End of Grammar

Algorithms in Simulator/Validator

The textual trace in the SDT Simulator and Validator for the new algorithmic extensions will be according to the table below.

Statement Textual trace Comment

Compound


No trace

If

IF (true)
IF (false)


Decision

DECISION  Value: 7

Same trace as for ordinary decisions

Loop

LOOP variable b := 3
LOOP test TRUE
LOOP test FALSE

For loop variable assignments

For loop tests

Jump

CONTINUE
BREAK
BREAK LoopName


Empty


No trace

A compound statement without variables declarations is seen as just a sequence of statements, while a compound statement with variable declarations is seen as a procedure call of a procedure with no name, without parameters. However, no trace information is produced for this implicit procedure call or procedure return.

When it comes to variables, these are available in the simulator interface just in the same way as if compound statements where true procedures. That is, the commands Up and Down can be used to view variables in different scopes. Note that a variable defined in a loop variable indicator introduces a scope of its own.

There is one exception of this general treatment of variables in local scopes and that is procedures defined as a compound statement.

In this procedure:

the parameter a and the variable b will be in the same scope, the procedure scope. For compound statements within the outermost procedure scope the general rules above apply.

Execution Performance in Applications

Cadvanced

All concepts in the algorithmic extensions have efficient C implementations, except variable declarations in local scopes (including in a loop variable indicator), as such compound statements will become SDL procedure calls.

Cmicro

All concepts in the algorithmic extensions have efficient C implementations. Compound statements containing variables are implemented using C block statements.


[Previous] [Next] [Contents] [Index]