Sequence Control

Synopsis

Roughly, sequence control structures fall into one of the three following groups

Sequencing with Arithmetic Expressions

How is the following expression evaluated :-

  a*3 * sqrt(0.8) / 3 * 8.

It is common for a language implementation to specify the tree representation of this structure.

The basic sequence control mechanism is function composition. Function composition defines the structure of the tree representation.

Note that a tree structure leaves part of the order of evaluation undefined. For example, in the expression above, is sqrt(0.8) done before a*3. This is often left unspecified (so that it may be optimised).


Postfix notation: The above expression could be rewritten as

   a 3 * 0.8 sqrt * 3 / 8 *
Evaluating this expression is a simple matter of adding each operand to a stack, then when each operator is found, it is applied to the appropriate number of operands on the top of the stack, then the result is pushed back on the stack.


Prefix notation: As above but the operator comes first

   * /  * * a 3 sqrt 0.8 3 8
Cambridge notation uses brackets to surround each operator with its operands
   (* (/  (* (* a 3) (sqrt 0.8)) 3) 8)


Infix notation: a*3 * sqrt(0.8) / 3 * 8.

Evaluation Infix notation is inherently ambiguous.. there must be a set of rules that describe which operators have precedence over which others.. it is not suited for writting operators with other than two operands..
i.e. biggest (1, 2, 0), it is more difficult to evaluate. Most compilers transform infix notation into either pre- or post- fix notation prior to producing machine code.


Hierarchy of Operators

Most languages specify precedence with a precedence table.

In general associativity, is left-to right, i.e. a*b*c is ((a*b)*c).

As you are aware, some languages are written using prefix (like LISP) and thus do not need precedence tables. Some (like Smalltalk) assume almost everything is the same precedence.


Some other problems with infix notation include.

Sequencing with Nonarithmetic Expressions

Some languages offer quite powerful pattern matching facilities,i.e. $_ =~ s/$pattern{$position}/$replaceString/g;, where the language is doing many operations to check the validity of the statement.

Term rewriting is a restricted form of pattern matching.. in some languages it can be used to emulate procedures.. In ML
fun fact(1) = 1 | fact(N::int) = N * fact (N-1) When ML processes a function call, it will replace it with the appropriate definition.

Unification (PROLOG) is another form of nonarithmetic expression

Substitution is the process of replacing one thing with another, i.e. (C)
#define macro1(N) printf("Hello N");
whenever the program sees something of the form, macro1(jill), it will replace it with print("Hello jill");

Sequence Control Between Statements

Basic Statements

Most languages assume assignment is a separate statement giving expressions of the form A:= B+7, but in C, assignment is an operator that returns the value assigned, so if ((A=7)==C) and A=B=C=D=7 are legal.

Input/Output is another area where assignment to variables occur. It is worth remembering that most input and output is buffered.. the operation often does not finish until a new line is read or printed.

Finally, assignment occurs in many other locations, such as parameter passing and unification.

Forms of Statement-Level Control

Explicit Sequence Control

Most languages provide unconditional "GOTO label", and conditional "if A=0 then GOTO label", GOTO statements. They equate to a machine code instruction that transfers control to another memory location. GOTOs are claimed to be good because they are

However, they are blamed for created unstructured programming. One of the ideas behind structured programming is that each section of code should have one entry point and one exit point, goto's break this.

Many languages provide a special command (Ada - exit, C - break) that will jump from the inside of a loop to just past its end. C also provides the continue command that jumps to the end of the loop (but still inside it). Both these structures are still considered structured as they still have only one exit.

Structured Sequence Control

Compound Statements

Introduced by ALGOL 60 in the form of begin...end

A block is a compound statement that can define a new scope (with local variables)

Most structured languages have some sort of compound statement that collects terms together.. C {}, Algol 68 begin .. end, Smalltalk [].


Conditional Statements

The common if statements.. If test then statements endif and if test then statements else statements2 endif are implemented by simple machine code statements that check a value, then dependent on whether it is true or false, jump to the appropriate location.

Nested Selectors


     Pascal: 

         if ... then
             if ... then
                 ...
             else ...

Which "then" gets the "else"? Pascal's rule: else goes with the nearest then

Alternate solution: Closing Reserved Words
In Ada:



CASE statements are more complicated as often multiple tests must be performed.



Case design issues:


Iteration Statements

The repeated execution of a statement or compound statement is accomplished either by iteration or recursion

Here we look at iteration, because recursion is unit-level control

General design issues for iteration control statements:

Two common strategies: counter-controlled, and logically-controlled

Design Issues:

FORTRAN 77 and 90

     Syntax: 

         DO label var = start, finish [, stepsize]

     Stepsize can be any value but zero 

     Parameters can be expressions 

     Design choices: 
          Loop var can be INTEGER, REAL, or DOUBLE 
          Loop var always has its last value 
          Loop parameters are evaluated only once 
          The loop var cannot be changed in the loop, but the
          parameters can; because they are evaluated only once, it
          does not affect loop control

ALGOL 60 For Loop

     Syntax: 

         for var :=  do statement

     where  can have: 
          list of expressions 
          expression step expression until expression 
          expression while boolean_expression 

         for index := 1 step 2 until 50, 60, 70,
                      80, index + 1 until 100 do


     (index = 1, 3, 5, 7, ..., 49, 60, 70, 80, 81, 82, ..., 100) 

ALGOL 60 For Design Choices

     Control expression can be int or real; its scope is whatever it
     is declared to be 

     Control var has its last assigned value after loop termination 

     The loop var cannot be changed in the loop, but the parameters
     can, and when they are, it affects loop control 

     Parameters are evaluated with every iteration, making it very
     complex and difficult to read 

Pascal For Loop

     Syntax: 

         for var := initial (to | downto) final do 
             statement


     Design Choices: 
          Loop var must be an ordinal type of usual scope 
          After normal termination, loop var is undefined 
          The loop var cannot be changed in the loop 
          The loop parameters can be changed, but they are evaluated
          just once, so it does not affect loop control

Ada For Loop


Syntax: 

         for var in [reverse] discrete_range loop
             ...
         end loop;


     Design choices:

     Type of the loop var is that of the discrete range; its scope is
     the loop body (it is implicitly declared)

     The loop var does not exist outside the loop

     The loop var cannot be changed in the loop, but the discrete
     range can;  it does not affect loop control

     The discrete range is evaluated just once 


Another Look at Structured Sequence Control:



 
 

Theory of Prime Programs

Consider 3 classes of flowchart nodes:

Any flowchart is a graph of directed arcs and these 3 types of nodes:

A proper program is a flowchart with:
1 entry arc
1 exit arc
There is a path from entry arc to any node to exit arc

A prime program is a proper program which has no embedded proper subprogram of greater than 1 node.
i.e., cannot cut 2 arcs to extract a prime subprogram within it.

A composite program is a proper program that is not prime.
 

Prime Program Decomposition

Every proper program can be decomposed into a hierarchical set of prime subprograms:

This decomposition is unique (except for special case of linear sequences of function nodes).
 

Enumeration of Primes

All prime programs can be enumerated:

Each implements a function.
What is function for 2-node primes (c) and (d) and 4-node primes (l) through (q)?
 

Structure Theorem of Bohm-Jacobini

Use of prime programs to define structured programming:
Concept first used by Dijkstra in 1968 as gotoless programming.

Called structured programming in early 1970s-
Program only with if, while and sequence control structures.

Issue in 1970s: Does this limit what programs can be written?
Resolved by Structure Theorem of Bohm-Jacobini.

An Example


**** original program with goto's

    x := 0 ;
A:  if (p(x)) goto B ;
    x := f(x) ;
    if (q(x)) goto C ;
B:  X := g(x) ;
    goto A :
C:  print X ;
    exit ;

**** original program with line numbers

1        x := 0 ;
2    A:  if (p(x)) goto B ;
3        x := f(x) ;
4        if (q(x)) goto C ;
5    B:  x := g(x) ;
6        goto A :
7    C:  print x ;
8        exit ;

**** Using variable LN to simulate line numbers (use LN == 0 for exit)

    LN := 1 ;
    while (LN <> 0) {
      if (LN == 1) {
        x  := 0 ;
        LN := 2 ;
      } else if (LN == 2) {
        if (p(x))
          LN := 5 ;
        else
          LN := 3 ;
      } else if (LN == 3) {
        x := f(x) ;
        LN := 4 ;
      } else if (LN == 4) {
        if (q(x))
          LN := 7 ;
        else
          LN := 5 ;
      } else if (LN == 5) {
        x := g(x) ;
        LN := 6 ;
      } else if (LN == 6) {
        LN := 2 ;
      } else if (LN == 7) {
        print x ;
        LN := 8 ;
      } else if (LN == 8) {
        LN := 0 ;
      }
    }

**** A little more efficient

    x  := 0 ;
    LN := 1 ;
    while (LN <> 0) {
      if (LN == 2) {
        if (p(x))
          LN := 5 ;
        else {
          x := f(x) ;
          if (q(x))
            LN := 7 ;
          else
            LN := 5 ;
        }
      } else if (LN == 5) {
        x := g(x) ;
        LN := 2 ;
      } else if (LN == 7) {
        print x ;
        LN := 0 ;
      }
    }