MENTAL
 Main Menu
 Applications
 Computer Science
 Imperative Programming


Imperative Programming
 IMPERATIVE
PROGRAMMING

Programming in the von Neumann architecture

"The computer has brought about a paradigm shift" (Gregory Chaitin).



The von Neumann Architecture

Concept

The von Neumann model basically consists of considering the machine as a sequence of memory cells in which the data and the program itself are stored. This model is inspired by the universal Turing machine [Turing, 1936].

In the early days of computing, programming a computer consisted of constructing a sequence of instructions in machine code. These instructions manipulated data contained in registers and memory cells, which were accessed by addresses. Since then, although languages have evolved, the "principles" of programming have remained the same: This machine model underlies even third-generation languages, which provide high-level abstraction machine access. These languages have two features, which carry over from the conception of first-generation languages:
  1. They are imperative.
  2. They are statement-oriented.
Since the beginning of computers, the von Neumann model has had a decisive influence. On the one hand, it has been the great driving force of computer development. On the other hand, it has conditioned the structure of programming languages, exerting a limiting influence, imposing a restricted conception of the nature of computation, based on implementational references, on the existence of a certain machine model.


Imperative languages

The imperative paradigm is statement or instruction-oriented, with structures for controlling the execution flow of a program. When the language also has a mechanism for constructing procedures and functions, it is also called Procedural Paradigm or Procedural. Examples of procedural languages are Pascal and C.

Classical imperative languages are based on three ideas:
  1. Variables.
    Memory consists of a set of cells. Cells can be assigned symbolic names to store, update and retrieve information. A variable is an abstraction of the memory cell concept and has the attributes of:

    • Address (memory cell position).

    • Content (stored data).

    • Type (indicates the type of values that can be stored, the storage format, as well as, indirectly, the operations that can be performed to create, access and modify such values).

  2. Assignment.
    Any calculated value must be stored in a given cell. This is done by an assignment statement, which is the abstraction of modifying the contents of a memory cell.

    A strange and unnatural form of allocation that is often used is, for example:

      x = x + 1

    To the left of the "=" sign we refer to the address of the variable x. To the right we refer to the content of x. This is not consistent, since consistency consists of maintaining semantics in a context-independent manner.

    Hehner [1978] observed that the classical assignment operator of the von Neumann model is intended backwards: that is, it is more logical to say "assign a name to an object" than "assign the value (object) to a memory location, i.e. indirectly to a name.

  3. Repetition.
    A concept that applies exclusively to a sequence of statements for iterative execution.

Structured Programming

Generic Control Structures

The so-called "Structured Programming" [Dijkstra, 1976] allows to specify in a clear and orderly way the control of the execution flow of a program. It does not contemplate the "go to" statement [Dijkstra, 1968] for two reasons:
  1. Because it is a low-level, implementing mechanism. In fact, the only two mechanisms for controlling the execution flow of a processor are sequencing and jumping.

  2. Because it makes programs difficult to read and understand.
Structured Programming is based on only three generic control structures:
  1. Sequence.
    This is the simplest mechanism. It is used to indicate that the program units (statements or blocks of statements) a1 ... an will be executed in sequence, one after the other.

  2. Exclusive selection.
    It is the selection of only one unit among a certain number of alternative program units. Given the units a1 ... an, the unit ai is selected (1 ≤ in).

  3. Iteration.
    It is the successive repetition (a certain number of times) of a program unit a. The number of times to be evaluated is set by a control variable or a condition.
By means of these three control structures it is possible to express the execution flow of any program [Böhm, 1966].

These three control structures have promoted a conceptual standardization of the flow control specification, due to their ease of understanding and application. In fact it is a humanization of the flow control specification [Dijkstra, 1965], along with a reduction of complexity.

Although there is general consensus on the use of these three structures, modern programming languages distort the "natural" semantics of Structured Programming, moving away from the desired formal standardization. This is due to the existence of different, even redundant, control structures.

In spite of the remarkable progress that this programming technique represented, two important limitations remain:
  1. Programming languages offer only fixed and predetermined control structures. It is not possible to define control structures "tailored" to the needs.

  2. Control structures are not generic. They can only be applied to source code. They cannot be applied to data.

Exclusive selection

The most common and well-known form of selection is by means of the IF-THEN-ELSE mechanism, which is fully supported and accepted by all imperative languages: The condition (true or false) is the result of the evaluation of a logical expression. And two blocks are distinguished: the IF block (associated with the true condition) and the ELSE block (associated with the false condition).

The ELSE block is optional. In this case the form is: Many programming languages support the CASE statement, which is a two-way generalization of IF-THEN-ELSE:
  1. Any type of expression is usually supported, not just a logical expression.

  2. The form is multi-path, i.e., there may be more than two alternatives.
The typical form is: The ELSE block is also optional.

A more generic form would be to use n conditions: where the conditions are assumed to be mutually exclusive. If they are not, only the unit ai corresponding to the first condition ci that is met is executed.

Limitations and problems:
Iteration

Control structures for iteration (or loops) are traditionally of two categories:
  1. Fixed number of iterations.
    The classical form is as follows:

      FOR v = v1 TO v2 STEP v3
          a
      END FOR

    The control variable v is of type integer and v1, v2 and v3 are integer expressions. STEP v3 is optional (by default, it assumes v3=1). The block a is called the "body" of the loop.

  2. Variable number of iterations.
    Control is performed by evaluating a condition, which is specified at the beginning or end of the loop. The classical forms are:

    Condition
    up
    Condition
    down
    WHILE condición
        a
    END WHILE
    REPEAT
        a UNTIL condition
Limitations and issues:
Implementation in MENTAL

Classic IF-THEN-ELSE specification

The classic IF-THEN-ELSE form. is specified by the full conditional form: In both cases, if the condition c is satisfied, a1 is evaluated. If it is not satisfied, a2 is evaluated. If there is no ELSE block, it is sufficient to specify (a1 ← c) or (c → a1). If c is satisfied, a1 is evaluated. Similarly, if only ELSE block (contrary condition) exists, (a2 ←' c) or (c →' a2) is specified.

Examples:
  1. (a ← x>3 →' b) // if x>3, we get a. Otherwise, we have b

  2. (a ← x>3) // if x>3, we have a.

  3. (a ← (x>3 ∧ x<10) →' b) // If x>3 and x<10, we have a. Otherwise, we have b

  4. (a ← (x>3 ∨ y>5) →' b) // If x>3 or y>5, we have a. Otherwise, we have b

  5. (a ← (x=1 ∨ x=2 ∨ x=3) →' b) // If x is 1, 2 or 3, we have a. Otherwise, we have b

CASE specification

We will implement the following generic form: Specifies to evaluate ai if condition ci is met. The conditions c1, ... , cn can be exclusive or not.

In MENTAL can be specified in the following ways:
  1. Sequential (inclusive selection).

      ((c1 → a1) (c2 → a2) ... (cn → an))

    All the ai corresponding to the conditions ci that are met are evaluated.

  2. Hierarchical (exclusive selection).
    Nested full conditional expressions are used.

    • For two conditions:

      (a1 ← c1 →' (a2 ← c2 →' a3))

    • For three conditions:

      (a1 ← c1 →' (a2 ← c2 →' (a3 ← c3 →' a4))))

    • Etc.

    In this case, the conditions are evaluated in a descending hierarchical way, i.e., first c1 is evaluated; if it is not fulfilled, c2 is evaluated, and so on. In the end only one of the ai would be evaluated.

    For clarity, they can be specified on different lines and with relative offsets. For example, for three conditions:

    (a1 ← c1 →'
        (a2 ← c2 →'
            (a3 ← c3 →' a4)
       )
    )


    The three-level hierarchical full conditional expression.

      (a1 ← c1 →' (a2 ← c2 →' (a3 ← c3 →' a4))))

    can be represented by

      (z1 (z2 (z2 (z3 a4)))

    being

      ⟨( zi = (ai ← ci →')↓ )⟩

    ie,

      (z1 (z2 (z2 (z3 a4)))/⟨( zi = (ai ← ci →')↓ )⟩

    In general, for n conditions,

      (⟨( (z1...zn a(n+1)))/á( zi = (ai ← ci →')↓ )⟩

Simple loop

To determine the structure associated with a loop, the best method is to start from the extensive (developed) form and successively compact it by identifying common expressions, to finally obtain a reduced expression, which is then generalized.

A simple example of structure would be the successive evaluation of the body a with the values 1, 3 and 5 of the variable x: If we call (v = (1 3 5)↓) that is, the open sequence of values that runs through the variable x, we finally have the general expression: which we can express in parameterized form as follows: being; The classic simple loop would be specified as:

loop(v (v1 v1+v3 ... v2) a)


Bucles jerarquizados

These are nested or higher-order loops where for each variable value of a one-level loop, all the values of the rest of the variables corresponding to the lower levels are traversed. Let us now analyze the following forms:

LevelsLoop
1 FOR x1 = v1
    a1
END FOR
2 FOR x2 = v2
    a2
    FOR x1 = v1
        a1
    END FOR
END FOR
3 FOR x3 = v3
    a3
    FOR x2 = v2
        a2
        FOR x1 = v1
           a1
        END FOR
    END FOR
END FOR

Where x1, x2, x3, ... are the control variables, and v1, v2, v3, ... are the sequences (open expressions) of values corresponding to those variables.

The one-level loop is: The two-level loop is: The three-level loop is: In general, for n levels, we have a hyperloop, i.e., a structure of nested loops with varying number of levels: Example:
Finite repetition loops

These are loops in which the body a is evaluated a certain number n of times (fixed or variable). Their associated structure is: where n is the number of times to evaluate the a body. In this case, no loop control variable is needed.


Bucles condicionales

These are those that use a condition to end a loop:
  1. Loop with the condition above (the condition is evaluated at the beginning of each loop). Its classical form is:

      WHILE c
          a
      END WHILE

    In MENTAL:

      (loop = (c → (a loop))

    It can also be specified using keywords:

      ⟨( (WHILE c a END WHILE) = (loop = (c → (<[b>a loop)) )⟩

  2. Loop with condition below (the condition is evaluated at the end of each loop). Its classical form is:

      REPEAT
          a
      UNTIL c

    In MENTAL:

      ( loop = (a (c → loop)) )

    It can also be specified using keywords:

      ⟨( (REPEAT a UNTIL c) = ( loop = (a (c → loop)) ) )⟩

    Alternative ways of specifying conditional loops are:

    LoopCode
    WHILE (b = ((←' c → a) b)!
    ( (¡ ←' c → a)★ )!
    REPEAT (b = ((a ← c →' )!
    ( a (c →' ¡)★ )!

Advantages of MENTAL for control structure specification
Procedures

A procedure is a program unit that performs a certain task. In a procedure you can define parameters, which can be: input, output and input/output.

When invoking a procedure, if a parameter is an output or input/output parameter, the parameter name must be specified. This is analogous to traditional imperative languages, where a distinction is made between content (value) and address of a variable. In MENTAL, the equivalent of address is the name of a variable.

Examples:
  1. Ascending sorting of a sequence of numbers by the bubble method.

    The first component of the sequence is compared with each of the remaining components, swapping the components if they are not in ascending order. The same is done with the second component with respect to the rest (from the third onwards). And so on until the penultimate component is reached, which is compared with the last one. In this case there is only one parameter (the sequence), which is input/output.

    ⟨( clasif(s) = ((n = s#) // sequence length

    [(i = [1...(n−1)]) // traverse the elements

    [(j = [(i+1)...n]]) // traverse following

    (((s\i) > s\j) → ((u = s\i) //switch

    (((s\i) = s\j) (((s\i) = u)))
    ]
    ]
    )
    )⟩

    (s = (36 5 17 12)) // example sequence.

    classif( s ) // name is used as parameter

    s // ev. (5 12 17 36) (sorted sequence)


  2. Same procedure as above, but with two parameters: one input (s) and one output (t).

    ⟨( clasif(s t) = ((n = s#) // length of the sequence

    (t = s) // copy input sequence

    [(i = [1...(n−1)]) // traverse elements

    [(j = [(i+1)n]) // traverse following

    ((t\i) > t\j) → ((u = t\i) //exchange

    (((t\i) = t\j)(((t\j) = u))))
    ]
    ]
    )
    )⟩

    (s = (36 5 17 12)) // example sequence.

    classif(s t)

    s // ev. (36 5 17 17 12)) (original sequence)

    t // ev. (5 12 17 36) (sorted sequence)
One could have also defined classif(s) as a function: with s as input parameter and as output of the function the sorted sequence.



Bibliography