Description of DIESEL

Here, we give a brief summary of DIESEL. More detailed information will be given later, in the various parts of the lab assignment. As DIESEL has much in common with Pascal and Modula-2, we will make use of them and point out differences from them, particularly when there is ambiguity.

Declarations

A program in DIESEL starts just as in Pascal, but you can not write file specifications such as (input, output) .

Declaring constants

State machine of lexical definition for constants.
Constants are positive

Constant definitions such as:

const
   SIZE = 10;
   PI = 3.14159;
   BUF_MAX = SIZE;

give names to numbers. Note the distinction between the number 10 and the constant SIZE. Both are of integer type.

Furthermore, string constants can be declared in DIESEL but you are not allowed to use them 1:

const
   version = 'version 1.1';

Unlike Pascal, numerical constants can only have non-negative values:

Declaring Variables

State machine of lexical definition for variables.
State machine of lexical definition for types

DIESEL has no mechanism for creating new types and thus has no type– construction. This, and also the absence of records and pointers, is the main weakness of DIESEL. boolean and char do not exist either, but fortunately integer and real do. Variables can be declared as one of the simple types or an array of these:

var
   i : integer;
   a : array[10] of real;

Note that you cannot write:

var
   i, j : integer; { wrong! }

Only one-dimensional arrays exist. These are indexed by integers. In the example above the index can vary between 0 and 9 (i.e. there are 10 elements). The operations allowed on arrays are assignment and reference of elements. Arrays cannot be used as parameters to procedures or functions.

Boolean values are simulated by integers where 0 represents false and everything else true.

Declaring functions and procedures

State machine of lexical definition for functions and procedures
State machine of lexical definition for parameter lists

DIESEL provides both functions and procedures. These can be nested arbitrarily and they can be recursive. As there is no forward construction, mutual recursion is a little more difficult, but can be achieved by placing one function or procedure inside another.

Functions can return values of the integer or real types whereas procedures do not return a value. It is possible to send expressions of the integer or real types as actual parameters. These are bound to the formal parameters according to the call-by-value principle, i.e. the called function or procedure can not modify the values of the actual parameters.

The same restriction applies here as to the declaration of variables; the following is wrong:

procedure p(i, j : integer; x, y : real); {wrong!}

and should be written as:

procedure p(i : integer; j : integer; x : real; y : real);

Finally, after all the declarations, we come to the main program:

State machine of lexical definition for the main program.

Statements

Assignments

State machine of lexical definition for assignments.

You can assign values to variables, and to elements in an array.

Type conflicts arise if the variable is of the integer type but the expression results in a floating-point number. However, type conversion is carried out in the following assignment:

var
   x : real;
begin
   x := 3;
end;

This is the same rule as in Pascal.

Procedure calls

State machine of lexical definition for procedure and function calls.

Calling a procedure is carried out in the same way as in Pascal with one important exception: the parentheses must always be written out. The same applies to functions.

There is a pre-defined procedure, write, which takes an argument (integer) interpreted as ASCII and prints it on the screen. For example,

write(48);

prints a zero. Procedures for writing integers and floating-point numbers are written in the language and can be found in the appendix.

Conditionals

DIESEL uses the same syntax for conditional statements as Modula-2:

State machine of lexical definition for conditional statements.
Table 1 Differences between DIESEL and PASCAL for conditional instructions.

DIESEL

PASCAL

if a > b then
   c := d;
end;
if a > b then
   c := d;
if a > b then
   c := d;
   e:= f;
else
   g := h;
end;
if a > b then
begin
   c := d;
   e := f;
end
else
   g := h;
if a > b then
   c := d;
   e := f;
elsif g > h then
   i := j;
   k := l;
elsif m > n then
   o := p;
else
   q := r;
   s := t;
end;
if a > b then
begin
   c := d;
   e := f;
end
else if g > h then
begin
   i := j;
   k := l;
end
else if m > n then
   o := p;
else
begin
   q := r;
   s := t;
end;

Repetition

The only repetition statement in DIESEL is while:

State machine of lexical definition for repetitions.

Note that the while-statement, like the if-statement, always finishes with an end without an introductory begin.

Examples:

Table 2 Comparing while instructions between DIESEL and PASCAL.

DIESEL

PASCAL

while a > b do
   c := d;
end;
while a > b do
  c := d;
while a > b do
   c := d;
   e := f;
end;
while a > b do
begin
   c := d;
   e := f;
end;

Return

In Pascal a function gets its value from an assignment statement where the function name appears on the left-hand side. In contrast DIESEL has borrowed the return-statement from Modula-2 which achieves the same thing.

State machine of lexical definition for return statements.

Executing a return-statement means that the function is assigned the value given by the expression; then the return is performed immediately. The expression’s type must be assignment compatible with the declared function name. Example:

function max(a : integer; b : integer) : integer;
begin
   if a > b then
      return a;
   else
      return b;
   end
end;

In an ordinary procedure you can have return-statements without a following expression. Such return-statements act as alternative return points in the procedure. Example:

procedure down(n : integer);
begin
   if n = 0 then
      return ;
   else
      down(n-1);
      write_int(n);
      newline();
   end;
end;

Arithmetic expressions

Factors

Factor is a constant.
Factor is a variable.
Factor is a function call.
Factor is an expression.
Factor is a unary negation.

A factor in an arithmetic expression can be a number or a constant, a variable, the value of a function (note the obligatory parentheses), an expression in parentheses, or a logical negation.

There are two standard functions that deal with arithmetics:

  • read takes no arguments but returns the next input character as an integer (ASCII). Example:

    var
       i : integer;
    begin
       i := read();
    end;
    
  • trunc transforms floating-point numbers to integers by truncation. Example:

    var
       i : integer;
    begin
       i := trunc(3.7);
    end;
    

    which assigns the value 3 to i.

Terms

Terms can be built from factors:

Building terms from factors.

Note that DIV is an integer operation and is defined only for integer arguments. Also note that / always returns a floating-point result, even if it is used with integer arguments. Boolean numbers are integer values and therefore boolean operations only accept integer operands. Their results should be either 1 (true) or 0 (false).

Simple expression

Simple expressions are built out of terms:

Building simple expressions out of terms.

Expressions

Finally, an arithmetic expression can be either a simple expression or a logical comparison of two simple expressions. In the latter case the result will be an integer value of 1 or 0.

Note that <= and >= do not exist.

Building expressions.

stdio.d

Listing of some standard I/O functions in DIESEL.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
{ ******************************* }
{ *                             * }
{ *   Standard I/O primitives   * }
{ *                             * }
{ ******************************* }

procedure newline;
const
    NEWLINE = 10;
begin
    write(NEWLINE);
end;

procedure write_int(val : integer);
const
    ASCII0 = 48;                { ascii value of '0' }
    MINUS = 45;
var
    c : integer;
    buf : array[25] of integer; { enough for 25 digits. }
    bufp : integer;
begin
    if (val = 0) then
        write(ASCII0);
        return;
    end;
    if (val < 0) then
        write(MINUS);
        val := -val;
    end;
    bufp := 0;
    while val > 0 do
        c := val mod 10;
        buf[bufp] := c + ASCII0;
        bufp := bufp + 1;
        val := val div 10;
    end;
    while (bufp > 0) do
        bufp := bufp - 1;
        write(buf[bufp]);
    end;
end;

procedure write_real(val : real);
const
    DOT = 46;
    DIGITS = 6;
var
    i : integer;
    multi : integer;
begin
    write_int(trunc(val));
    write(DOT);
    i := 0;
    multi := 1;
    while(i < DIGITS) do
        i := i + 1;
        multi := multi * 10;

        { avoid precision loss as much as we can }
        write_int(trunc(val * multi) mod 10);
    end;
end;

function read_int : integer;
const
    BLANK = 32;
    ASCII0 = 48;
    ASCII9 = 57;
var
    acc : integer;
    c : integer;
begin
    acc := 0;
    c := read();
    while (c < ASCII0) or (c > ASCII9) do
        c := read();
    end;
    while not ((c < ASCII0) or (c > ASCII9)) do
        acc := 10 * acc + c - ASCII0;
        c := read();
    end;
    return acc;
end;

function read_real : real;
const
    BLANK = 32;
    ASCII0 = 48;
    ASCII9 = 57;
    DOT = 46;
var
    res : real;
    acc : integer;
    c : integer;
begin
    acc := 0;
    c := read();
    while (c < ASCII0) or (c > ASCII9) do
        c := read();
    end;
    while not ((c < ASCII0) or (c > ASCII9)) do
        acc := 10 * acc + c - ASCII0;
        c := read();
    end;
    res := acc;
    if (c <> DOT) then
        return res;
    end;
    acc := 1;
    c := read();
    while not ((c < ASCII0) or (c > ASCII9)) do
        acc := 10 * acc;
        c := c - ASCII0;
        res := res + c/acc;
        c := read();
    end;
    return res;
end;
1

The aim is to make the lexical analysis a little more interesting.