Thursday, January 21, 2010

Language constructs

Pascal, in its original form, is a purely procedural language and includes the traditional array of Algol-like control structures with reserved words such as if, then, else, while, for, and so on. However, Pascal also has many data structuring facilities and other abstractions which were not included in the original Algol60, like type definitions, records, pointers, enumerations, and sets. Such constructs were in part inherited or inspired from Simula67, Algol68, Niklaus Wirth's own AlgolW and suggestions by C. A. R. Hoare.

Hello world

Pascal programs start with the program keyword with a list of external file descriptors as parameters; then follows the main block encapsulated by the begin and end keywords. Semicolons separate statements, and the full stop ends the whole program (or unit). Letter case is ignored in Pascal source.

Here is an example of the source code in use for a very simple "Hello world" program:

Program HelloWorld(output);
begin
writeln('Hello, world!')
end.

Data types

A type in Pascal, and in several other popular programming languages, defines a variable in such a way that it defines a range of values which the variable is capable of storing, and it also defines a set of operations that are permissible to be performed on variables of that type. The predefined types are:

Data type Type of values which the variable is capable of storing
integer Whole numbers
real Floating point numbers
boolean The value TRUE or FALSE
char A single character from an ordered character set

The range of values allowed for each (except boolean) is implementation defined.

The programmer has the freedom to define other commonly-used data types (e.g. byte, string, etc.) in terms of the predefined types using Pascal's type declaration facility. e.g.

type
byte = 0..255;
signedbyte = -128..127;
string = packed array [1..255] of char;

Scalar types

Pascal's scalar types are real, integer, character, boolean and enumerations, a new type constructor introduced with Pascal:

var
r: Real;
i: Integer;
c: Char;
b: Boolean;
e: (apple, pear, banana, orange, lemon);

Subrange types

Subranges of any ordinal type (any simple type except real) can be made:

var
x: 1..10;
y: 'a'..'z';
z: pear..orange;

Set types

In contrast with other programming languages from its time, Pascal supports a set type:

var
set1: set of 1..10;
set2: set of 'a'..'z';
set3: set of pear..orange;

A set is a fundamental concept for modern mathematics, and they may be used in a great many algorithms. Such a feature is highly useful and may be faster than an equivalent construct in a language that does not support sets. For example, for many Pascal compilers:

if i in [5..10] then
...

executes faster than:

if (i>4) and (i<11) then
...

Sets of non-contiguous values can be particularly useful, in terms of both performance and readability:

if i in [0..3, 7, 9, 12..15] then
...

For examples like these which involve sets over small domains, the improved performance is usually achieved by the compiler representing set variables as bitmasks. The set operators can then be implemented efficiently as bitwise machine code operations.

However, for examples where the range of values is significantly larger than the native word size, set expressions are likely to result in worse performance and greater memory usage than equivalent expressions using relational operators.

Type declarations

Types can be defined from other types using type declarations:

type
x = Integer;
y = x;
...

Further, complex types can be constructed from simple types:

type
a = Array [1..10] of Integer;
b = record
x: Integer;
y: Char
end;
c = File of a;

File type

As shown in the example above, Pascal files are sequences of components. Every file has a buffer variable which is denoted by f^. The procedures get (for reading) and put (for writing) move the buffer variable to the next element. Read is introduced such that read(f, x) is the same as x:=f^; get(f);. Write is introduced such that write(f, x) is the same as f^ := x; put(f); The type text is predefined as file of char. While the buffer variable could be used to inspect the next character that would be used (check for a digit before reading an integer), this concept lead to serious problems with interactive programs with early implementations, but was solved later with the "lazy I/O" concept.

In Jensen & Wirth Pascal, strings are represented as packed arrays of chars; they therefore have fixed length and are usually space-padded. Some dialects have a custom string type.

Pointer types

Pascal supports the use of pointers:

type
a = ^b;
b = record
a: Integer;
b: Char;
c: a
end;
var
pointertob: a;

Here the variable pointertob is a pointer to the data type b, a record. Pointers can be used before they are declared. This is a forward declaration, an exception to the rule that things must be declared before they are used. To create a new record and assign the value 10 and character A to the fields a and b in the record, and to initialise the pointer c to nil, the commands would be:

new(pointertob);
pointertob^.a := 10;
pointertob^.b := 'A';
pointertob^.c := nil;
...

This could also be done using the with statement, as follows

new(pointertob);

with pointertob^ do
begin
a := 10;
b := 'A';
c := nil
end;
...

Inside of the scope of the with statement, a and b refer to the subfields of the record pointer pointertob and not to the record b or the pointer type a.

Linked lists, stacks and queues can be created by including a pointer type field (c) in the record (see also nil and null (computer programming)).

Unlike many languages that feature pointers, Pascal only allows pointers to reference dynamically created variables that are anonymous, and does not allow them to reference standard static or local variables. Additionally, pointers are type-bound e.g. a pointer to a char is not type-compatible with a pointer to an integer. The net effect is that Pascal pointers are "safe", and free of the type security issues inherent with other pointer implementations.

Control structures

Pascal is a structured programming language, meaning that the flow of control is structured into standard statements, ideally without 'go to' commands.

while a <> b do writeln('Waiting');

if a > b then writeln('Condition met')
else writeln('Condition not met');

for i := 1 to 10 do writeln('Iteration: ', i:1);

repeat
a := a + 1
until a = 10;

case i of
0: write('zero');
1: write('one');
2: write('two')
end;

Procedures and functions

Pascal structures programs into procedures and functions.

program mine(output);

var i : integer;

procedure print(var j: integer);

function next(k: integer): integer;
begin
next := k + 1
end;

begin
writeln('The total is: ', j);
j := next(j)
end;

begin
i := 1;
while i <= 10 do print(i)
end.

Procedures and functions can nest to any depth, and the 'program' construct is the logical outermost block.

Each procedure or function can have its own declarations of goto labels, constants, types, variables, and other procedures and functions, which must all be in that order. This ordering requirement was originally intended to allow efficient single-pass compilation. However, in some dialects the strict ordering requirement of declaration sections is not required.

Semicolons as statement separators

Pascal adopted many language syntax features from the ALGOL language, including the use of a semicolon as a statement separator. This is in contrast to other languages, such as PL/I, C etc. which use the semicolon as a statement terminator. As illustrated in the above examples, no semicolon is needed before the end keyword of a record type declaration, a block, or a case statement; before the until keyword of a repeat statement; and before the else keyword of an if statement.

The presence of an extra semicolon was not permitted in early versions of Pascal. However, the addition of empty statements in the 1973 Revised Report and later changes to the language in ISO 7185:1983 now allow for optional semicolons in most of these cases. The exception is that a semicolon is still not permitted immediately before the else keyword in an if statement.

The empty statement is genuinely required in some situations:

(* skip blanks *)
while GetChar() = ' ' do ;

However, indiscriminate use can be problematic. While the following is syntactically correct it is unlikely that the result is as intended:

if alarm then;
begin;
SendMayday();
EjectPilot();
end;

No comments:

Post a Comment