# Pascal Programming/Records

The key to successful programming is finding the "right" structure of data and program.

—Niklaus Wirth[1]

After you have learned to use an `array`, this chapter introduces you to another data type structure concept called `record`. Like an `array`, the use of `record`s primarily serves the purposes of allowing you to write clean, structured programs. It is otherwise optional.

## Concept

You briefly saw a `record` in the first chapter. While an `array` is a homogenous aggregation of data, that means all members have to have the same base data type, a `record` is potentially, but not necessarily an aggregation of data having various different data types.[2]

### Declaration

A `record` data type declaration looks pretty much like a collection of variable declarations:

```program recordDemo;
type
(* a standard line on a text console *)
line = string(80);

(* encapsulate all administrative data in one structure *)
student = record
firstname: line;
lastname: line;
end;
```

The declaration begins with the word `record` and ends with `end`. Inbetween you declare fields, or members, member elements of the entire `record`.

 Here again the semicolon has the function of separating members. The keyword `end` will actually terminate a `record` declaration. Note, how in the following correct example there is no semicolon after the last member’s declaration: ```program recordSemicolonDemo; type sphere = record radius: real; volume: real; surface: real end; ```Despite that, it is a frequent practice to put a semicolon there anyway, even though it is not necessary. You would otherwise too often simply add a new member below the last line, forgetting to add the semicolon in the preceding line and thus provoking a syntax error.

All `record` members have to bear distinct names within the `record` declaration itself. For instance in the example above, declaring two “variables”, member elements of the name `level` will be rejected.

There is no requirement on how many fields you have to declare. An “empty” `record` is also possible:[fn 1]

```type
emptyRecord = record
end;
```

### Many fields of the same data type

Similiar to the declaration of variables you can define multiple fields of the same data type at once by separating identifiers with a comma. The previous declaration of `sphere` could also be written as:

```type
sphere = record
end;
```

Most Pascal veterans and style guides, however, discourage the use of this shorthand notation (both for variable as well as `record` declarations, but also in formal parameter lists). It is only reasonable if all declared identifiers absolutely always have same data type; it is virtually guaranteed you will never want to change the data type of just one field in the comma-separated list. If in doubt, use the longhand. In programming, convenience plays a tangential role.

### Use

By declaring a `record` variable you immediately have the entire set of “sub”‑variables at your hand. Accessing them is done by specifying the `record` variable’s name, plus a dot (`.`), followed by the `record` field’s name:

```var
posterStudent: student;
begin
posterStudent.firstname := 'Holden';
posterStudent.lastname := 'Caulfield';
posterStudent.level := 10;
end.
```

You already saw the dot notation in the previous chapter on strings, where appending `.capacity` on a name of a `string(…)` variable refers to the respective variable’s character capacity. This is not a coincidence.

However, especially beginners occasionally confuse the data type name with the variable’s name. The following code highlights the difference. Remember that a data type declaration does not reserve any memory and is mainly informative for the compiler, whereas a variable declaration actually sets some chunk of memory aside.
```program dotNoGo(output); { This program does not compile. }
type
line = string(80);
quizItem = record
question: line;
end;
var
response: line;
challenge: quizItem;
begin
writeLn(line.capacity); { ↯ `line` is not a variable }
writeLn(response.capacity); { ✔ correct }

writeLn(quizItem.question); { ↯ `quizItem` refers to a data type }
{ Data type declarations (as per definition) do not reserve any memory }
{ thus you cannot “read/write” from/to a data type. }
writeLn(challenge.question); { ✔ correct }
end.
```
And, as it has always been, you first need to assign a value to a variable before you are allowed to read it. The source code above ignores that to focus on the main issue. The key point is, the dot (`.`) notation is only valid if there is memory.[fn 2]

But why and when do we want to use a `record`? At first glance and in the given examples so far it may seem like a troublesome way to declare and use multiple variables. Yet the fact that a `record` is handled as one unit entails one big advantage:

• You can copy entire `record` values via a simple assignment (`:=`).
• This means you can pass much data at once: A `record` can be a parameter of routines, and in EP functions can return them as well.[fn 3]

Evidently you want to group data together that always appear together. It does not make sense to group unrelated data, just because we can. Another quite useful advantage is presented below in the section on variant records.

## Routing override

As you saw earlier, referring to members of a `record` can get a little tedious, because we are repeating the variable name over and over again. Fortunately, Pascal allows us abbreviate things a bit.

### `With`-clause

The `with`-clause allows us to eliminate repeating a common prefix, specifically the name of a `record` variable.[3]

```begin
with posterStudent do
begin
firstname := 'Holden';
lastname := 'Caulfield';
level := 10;
end;
end.
```

All identifiers that identify values are first looked for in the `record` scope of `posterStudent`. If there is no match, all variable identifiers outside of the given `record` are considered too.

Of course it is still possible to denote a `record` member by its full name. E. g. in the source code above it would be perfectly legal to still write `posterStudent.level` within the `with`-clause. Concededly, this would defeat the purpose of the `with`-clause, but sometimes it may still be beneficial to emphasize the specific `record` variable just for documentation. It is nevertheless important to understand that the FQI, the fully-qualified identifier, the one with a dot in it, does not lose its “validity”.

In principle, all components of structured values “containing dots” can be abbreviated with `with`. This is also true for the data type `string` you have learned in the previous chapter.

```program withDemo(input, output);
type
{ Deutsche Post „Maxi-Telegramm“ }
telegram = string(480);
var
post: telegram;
begin
with post do
begin
'Maximum length = ',
capacity, ' characters.');
{ … }
end;
end.
```

Here, within the `with`-clause `capacity`, and for that matter `post.capacity`, refer to `post.capacity`.

### Multiple levels

If multiple `with`-clauses ought to be nested, there is the short notation:

```	with snakeOil, sharpTools do
begin
…
end;
```

which is equivalent to:

```	with snakeOil do
begin
with sharpTools do
begin
…
end;
end;
```

It is important to bear in mind, first identifiers in `sharpTools` are searched, and if there is no match, secondly, identifiers in `snakeOil` are considered.

## Variant records

In Pascal a `record` is the only data type structure concept that allows you to, so to speak, alter its structure during run-time, while a `program` is running. This super practical property of `record` permits us to write versatile code covering many cases.

### Declaration

Let’s take a look at an example:

```type
centimeter = 10..199;

// order of female, male has been chosen, so `ord(sex)`
// returns the [minimum] number of non-defective Y chromosomes
sex = (female, male)

// measurements according EN 13402 size designation of clothes [incomplete]
clothingSize = record
shoulderWidth: centimeter;
armLength: centimeter;
bustGirth: centimeter;
waistSize: centimeter;
hipMeasurement: centimeter;
case body: sex of
female: (
underbustMeasure: centimeter;
);
male: (
);
end;
```

The variant part of a `record` starts with the keyword `case`, which you already know from selections. After that follows a `record` member declaration, the variant selector, but instead of a semicolon you put the keyword `of` thereafter. Below that follow all possible variants. Each variant is marked by a value out of the variant selector’s domain, here `female` and `male`. Separated by a colon (`:`) follows a variant denoter surrounded by parentheses. Here you can list additional `record` members that are only available if a certain variant is “active”. Note that all identifiers across all alternatives must be unique. The individual variants are separated by a semicolons, and there can be at most one variant part which has to appear at the end. Because you will need to be able to list all possible variants, the variant selector has to be an ordinal data type.

### Use

Using variant records requires you to first select a variant. Variants are “activated” by assigning a value to the variant selector. Note, variants are not “created”; they all already exist at `program` startup. You merely need to make a choice.

```	boobarella.body := female;
boobarella.underbustMeasure := 69;
```

Only after assigning a value to the variant selector and as long as this value remains unchanged, you are allowed to access any fields of the respective variant. It is illegal to reverse the previous two lines of code and attempt accessing the `underbustMeasure` field even though `body` is not defined yet and, more importantly, does not bear the value `female`.

It is certainly permissible to change the variant selector later in your `program` and then use a different variant, but all previously stored values in the variant part relinquish their validity and you cannot restore them. If you switch back the variant to a previous, original value, you will need to assign all values in that variant anew.

### Application

This concept opens up new horizons: You can design your programs more interactively in a neat fashion. You can now choose a variant based on run-time data (data that is read while the `program` is running). Because at any time (after the first assignment of a value to the variant selector) only one variant is “active”, your `program` will crash if it attempts reading/writing values of an “inactive” variant. This is a desirable behavior, because that is the whole idea of having distinct variants. It guarantees your programs overall integrity.

### Anonymous variants

Pascal also permits having anonymous variant selectors, that is selectors not bearing any name. The implications are

• you cannot explicitly select (nor query) any variant, so
• in turn all variants are considered “active” at the same time.

“But wasn’t this the object of the exercise?” you might ask. Yes, indeed, since there is no named selector your `program` cannot keep track which variant is supposed to work and which one is “defective”. You are responsible to determine which variant you can sensibly read/write at present.

Anonymous variants are/were frequently abused to implement “typecasts”. If you have an anonymous variant part, you can declare members bearing different data types which in turn determine the underlying data’s interpretation method. You can then exploit the fact that many (but not necessarily all) compilers put all variants in the same memory block.

Code:

```program anonymousVariantsDemo(output);
type
bitIndex = 0..(sizeOf(integer) * 8 - 1);

exposedInteger = record
case Boolean of
false: (
value: integer;
);
true: (
bit: set of bitIndex;
);
end;

var
i: exposedInteger;
begin
i.bit := [4];
writeLn(i.value);
end.
```

Output:

```16
```
The value `16` is (and this should be considered “a coincidence”) ${\displaystyle 2^{4}}$. We stress that all Pascal standards do not make any statement regarding internal memory structure. A high-level programming language is not concerned about how data is stored, it even does not know the notion of “bits”, “voltage high”/“voltage low”.
 Thus, if you are (intentionally) using any of this demonstrated behavior, you can not say “I am programming in Pascal” anymore, but you are programming specifically for the compiler so-and-so. The memory layout of data structures varies among Pascal implementations.
The example above, for example, was designed for and works with the GPC and the FPC in their default configurations. Do not deem it as “Pascal”, but a descendant of it. There is a good chance that using a different compiler will produce different results.

This concept exists in many other programming languages too. In the programming language C, for instance, it is called a union.

## Conditional loops

So far we have been exclusively using counting loops. This is great if you can predict in advance the number of iterations, how many times the loop’s body needs to be executed. Yet every so often it is not possible to formulate a proper expression determining the number of iterations in advance.

Conditional loops allow you to make the execution of the next iteration dependent on a `Boolean` expression. They come in two flavors:

• tail-controlled loop.

The difference is, the loop’s body of a tail-controlled loop is executed at least once in any case, whereas a head-controlled loop might never execute the loop body at all. In either case, a condition is evaluated over and over again and must uphold for the loop to continue.

A head-controlled loop is frequently called `while`-loop because of its syntax.

The “control” condition appears above the loop body, i. e. at the head.

Code:

```program characterCount(input, output);
type
integerNonNegative = 0..maxInt;
var
c: char;
n: integerNonNegative;
begin
n := 0;

while not EOF do
begin
n := n + 1;
end;

writeLn('There are ', n:1, ' characters.');
end.
```

Output:

```\$ cat ./characterCount.pas | ./characterCount
There are 240 characters.
\$ printf '' '' | ./characterCount
There are 0 characters.
```
The loop’s condition is a `Boolean` expression framed by the words `while` and `do`. The condition must evaluate to `true` for any (subsequent) iteration to occur. As you can see from the output, in the second case, it may even be zero times: Evidently for empty input `n := n + 1` was never executed.

`EOF` is shorthand for `EOF(input)`. This standard `function` returns `true` if there is no further data available to read, commonly called end of file. It is illegal, and will horribly fail, to `read` from a file if the respective `EOF` function call returns `true`.

Unlike a counting loop, you are allowed to modify data the conditional loop’s condition depends on.

```const
(* instead of a hard-coded length `64` *)
(* you can write `sizeOf(integer) * 8` in Delphi, FPC, GPC *)
wordWidth = 64;
type
integerNonNegative = 0..maxInt;
wordStringIndex = 1..wordWidth;
wordString = array[wordStringIndex] of char;

function binaryString(n: integerNonNegative): wordString;
var
(* temporary result *)
binary: wordString;
i: wordStringIndex;
begin
(* initialize `binary` with blanks *)
for i := 1 to wordWidth do
begin
binary[i] := ' ';
end;
(* if n _is_ zero, the loop's body won't be executed *)
binary[i] := '0';

(* reverse Horner's scheme *)
while n >= 1 do
begin
binary[i] := chr(ord('0') + n mod 2);
n := n div 2;
i := i - 1;
end;

binaryString := binary;
end;
```

The `n` the loop’s condition depends on will be repeatedly divided by two. Because the division operator is an integer division (`div`), at some point the value `1` will be divided by two and the arithmetically correct result `0.5` is truncated (`trunc`) toward zero. Yet the value `0` does not satisfy the loop’s condition anymore, thus there will not be any subsequent iterations.

### Tail-controlled loop

In a tail-controlled loop the condition appears below the loop’s body, at the foot. The loop’s body is always run once before even the condition is evaluated at all.

```program repeatDemo(input, output);
var
i: integer;
begin
repeat
begin
write('Enter a positive number: ');
end
until i > 0;

writeLn('Wow! ', i:1, ' is a quite positive number.');
end.
```

The loop’s body is encapsulated by the keywords `repeat` and `until`.[fn 4] After `until` follows a `Boolean` expression. In contrast to a `while` loop, the tail-controlled loop always continues, always keeps going, `until` the specified condition becomes `true`. A `true` condition marks the end. In the above example the user will be prompted again and again until he eventually complies and enters a positive number.

## Date and time

This section introduces you to features of Extended Pascal as defined in the ISO standard 10206. You will need an EP‑compliant compiler to use those features.

### Time stamp

In EP there is a standard data type called `timeStamp`. It is declared as follows:[fn 5]

```type
timeStamp = record
dateValid: Boolean;
timeValid: Boolean;
year: integer;
month: 1..12;
day: 1..31;
hour: 0..23;
minute: 0..59;
second: 0..59;
end;
```

As you can see from the declaration, `timeStamp` also contains data fields for a calendar date, not just the time as indicated by a standard clock.

 A processor (i. e. usually a compiler) may provide additional (thus non-standard) fields. The GPC for instance supplies, among other fields, a field called `timeZone` indicating the offset in seconds versus UTC (“world time”).

### Getting a time stamp

EP also defines a unary `procedure` that populates a `timeStamp` variable with values. `GetTimeStamp` assigns values to all members of a `timeStamp record` passed in the first (and only) parameter. These values represent the “current date” and “current time” as at the invocation of this procedure. However, in the 1980’s not all (personal/home) computers did have a built-in “real time” clock. Therefore, the ISO standard 10206 devised prior 21st century stated that the word “current” was “implementation-defined”. The `dateValid` and `timeValid` fields were specifically inserted to address the issue that some computers simply do not know the current date and/or time. When reading values from a `timeStamp` variable, it is still advisable to check their validity first after having `getTimeStamp` fill them out.

If `getTimeStamp` was unable to obtain a “valid” value, it will set

• `day`, `month` and `year` to a value representing January 1, 1 CE, but also `dateValid` to `false`.
• In the case of time, `hour`, `minute` and `second` become all `0`, a value representing midnight. The `timeValid` field becomes `false`.

Both are independent from each other, so it may certainly be the case that just the time could be determined, but the date is invalid.

Note that the Gregorian calendar was introduced during the year 1582 CE, so the `timeStamp` data type is generally useless for any dates before 1583 CE.

### Printable dates and times

Having obtained a `timeStamp`, EP furthermore supplies two unary functions:

• `date` returns a human-readable `string` representation of `day`, `month` and `year`, and
• `time` returns a human-readable `string` representation of `hour`, `minute` and `second`.

Both functions will fail and terminate the `program` if `dateValid` or `timeValid` indicate an invalid datum respectively. Note, the exact format of `string` representation is not defined by the ISO standard 10206.

Putting things together, consider the following `program`:

Code:

```program dateAndTimeFun(output);
var
ts: timeStamp;
begin
getTimeStamp(ts);

if ts.dateValid then
begin
writeLn('Today is ', date(ts), '.');
end;

if ts.timeValid then
begin
writeLn('Now it is ', time(ts), '.');
end;
end.
```

Output:

```Today is 1 Jan 2022.
Now it is 21:29:42.
```
The output may differ. Here, the GPC was used and the hardware had an RTC. It is needless to say, but also you might see nothing if both `dateValid` and `timeValid` are `false`.

## Summary on loops

This is a good time to take inventory and reiterate all kinds of loops.

### Conditional loops

Conditional loops are the tools of choice if you cannot predict the total number of iterations.

```while condition do
begin
…
end;
```
```repeat
begin
…
end
until condition;
```
`condition` must evaluate to `true` for any (including subsequent) iterations to occur. `condition` must be `false` for any subsequent iteration to occur.
comparison of conditional loops in Pascal

It is possible to formulate either loop as the other one, but usually one of them is more suitable. A tail-controlled loop is particularly suitable if you do not have any data yet to make a judgment, to evaluate a proper `condition` prior the first iteration.

### Counting loops

Counting loops are good if you can predict the total number of iterations before entering the loop.

counting up loop counting down loop
```for controlVariable := initialValue to finalValue do
begin
…
end;
```
```for controlVariable := initialValue downto finalValue do
begin
…
end;
```
After each non-final iteration `controlVariable` becomes `succ(controlVariable)`. `controlVariable` must be less than or equal to `finalValue` for another iteration to occur. After each non-final iteration `controlVariable` becomes `pred(controlVariable)`. `controlVariable` must be greater than or equal to `finalValue` for another iteration to occur.
comparison of counting loop directions in Pascal
 Both, the `initialValue` and `finalValue` expressions, are evaluated exactly once.[4] This is very different to conditional loops.

Inside counting loops’ bodies you cannot modify the counting variable, only read it. This prevents you from any accidental manipulations and ensures the calculated predicted total number of iterations will indeed occur.

 It is not guaranteed that `controlVariable` is `finalValue` “after” the loop. If there were exactly zero iterations, no assignments to `controlVariable` were made. Thus generally presume `controlVariable` is invalid/uninitialized after a `for`-loop unless you are absolutely sure there was at least one iteration.

### Loops on aggregations

If you are using an EP-compliant compiler, you furthermore have the option to use a `for … in` loop on sets.

```program forInDemo(output);
type
characters = set of char;
var
c: char;
parties: characters;
begin
parties := ['R', 'D'];
for c in parties do
begin
write(c:2);
end;
writeLn;
end.
```

You have made it this far, and it is quite impressive how much you already know. Since this chapter’s concept of a `record` should not be too difficult to grasp, the following exercises mainly focus on training. A professional computer programmer spends most of his time on thinking what kind of implementation, using which tools (e. g. `array` “vs.” `set`), is the most useful/reasonable. You are encouraged to think first, before you even start typing anything. Nonetheless, sometimes (esp. due to your lack of experience) you need to just try things out, which is fine if it is intentional. Aimlessly finding a solution does not discern an actual programmer.

Can you have a `record` contain another `record`?
Like it was possible for an `array` to contain another `array`, this is quite possible for a `record` too. Write a test `program` to see for yourself. The important thing is to note that the dot-notation can be expanded indefinitely (`myRecordVariable.topRecordFieldName.nestedRecordFieldName.doubleNestedRecordFieldName`). Evidently at some point it becomes too difficult to read so use this wisely.
Like it was possible for an `array` to contain another `array`, this is quite possible for a `record` too. Write a test `program` to see for yourself. The important thing is to note that the dot-notation can be expanded indefinitely (`myRecordVariable.topRecordFieldName.nestedRecordFieldName.doubleNestedRecordFieldName`). Evidently at some point it becomes too difficult to read so use this wisely.

Write a loop that never ends, that means it is impossible that the loop will ever terminate. If your test program does not terminate, you most likely have achieved this task. On a standard Linux terminal you can then press Ctrl+C to forcefully kill the program.
There are two flavors of infinite loops:
```while true do
begin
…
end;
```

The condidition needs to be negated in a `repeat … until` loop:

```repeat
begin
…
end
until false;
```
Infinite loops are very undesirable. While constant expressions like in these examples are easy to spot, tautologies, expressions that always evaluate to `true`, or expressions that can never be fulfilled (in the case of a `repeat … until` loop), are not. For instance, given that `i` was an `integer` the loop `while i <= maxInt do` will run indefinitely, because `i` can never exceed `maxInt`[fn 6] and thus break the loop’s condition. Therefore be reminded to carefully formulate expressions for conditional loops and ensure it will eventually reach a terminating state. Otherwise it can be frustrating for the user of your `program`.
There are two flavors of infinite loops:
```while true do
begin
…
end;
```

The condidition needs to be negated in a `repeat … until` loop:

```repeat
begin
…
end
until false;
```
Infinite loops are very undesirable. While constant expressions like in these examples are easy to spot, tautologies, expressions that always evaluate to `true`, or expressions that can never be fulfilled (in the case of a `repeat … until` loop), are not. For instance, given that `i` was an `integer` the loop `while i <= maxInt do` will run indefinitely, because `i` can never exceed `maxInt`[fn 6] and thus break the loop’s condition. Therefore be reminded to carefully formulate expressions for conditional loops and ensure it will eventually reach a terminating state. Otherwise it can be frustrating for the user of your `program`.

Rewrite the following loop as a `while`-loop:
```repeat
begin
imagineJumpingSheep;
sheepCount := sheepCount + 1;
waitTwoSeconds;
end
until asleep;
```
The important thing is to realize is that the entire loop body is repeated above the `while`-loop even begins:
```imagineJumpingSheep;
sheepCount := sheepCount + 1;
waitTwoSeconds;

while not asleep do
begin
imagineJumpingSheep;
sheepCount := sheepCount + 1;
waitTwoSeconds;
end;
```
Do not forget to negate the condition when transforming a conditonal loop into the other kind. Obviously the `repeat … until`-loop is more suitable in this case.
The important thing is to realize is that the entire loop body is repeated above the `while`-loop even begins:
```imagineJumpingSheep;
sheepCount := sheepCount + 1;
waitTwoSeconds;

while not asleep do
begin
imagineJumpingSheep;
sheepCount := sheepCount + 1;
waitTwoSeconds;
end;
```
Do not forget to negate the condition when transforming a conditonal loop into the other kind. Obviously the `repeat … until`-loop is more suitable in this case.

If you are using a Linux or FreeBSD OS and an EP‑compliant compiler: Write a `program` that takes the output of the command `getent passwd` as input and only prints the first field/column of every line. In a `passwd(5)` file, fields are separated by a colon (`:`). Your `program` will list all known user names.
You can run the following program with the command `getent passwd | ./cut1` (the file name of your executable program may differ).
```program cut1(input, output);
const
separator = ':';
var
line: string(80);
begin
while not EOF(input) do
begin
{ This reads the _complete_ line, but at most}
{ line.capacity characters are actually saved. }
writeLn(line[1..index(line, separator)-1]);
end;
end.
```
Remember that `index` will return the index of the colon character which you do not want to print, thus you will need to subtract `1` from its result. This `program` will evidently fail if a line does not contain a colon.
You can run the following program with the command `getent passwd | ./cut1` (the file name of your executable program may differ).
```program cut1(input, output);
const
separator = ':';
var
line: string(80);
begin
while not EOF(input) do
begin
{ This reads the _complete_ line, but at most}
{ line.capacity characters are actually saved. }
writeLn(line[1..index(line, separator)-1]);
end;
end.
```
Remember that `index` will return the index of the colon character which you do not want to print, thus you will need to subtract `1` from its result. This `program` will evidently fail if a line does not contain a colon.

Based on your previous solution, extend your `program` so only user names whose UID is greater than or equal to `1000`. The UID is stored in the third field.
The changed lines have been highlighted. A comment from the previous source code has been omitted.
```program cut2(input, output);
const
separator = ':';
minimumID = 1000;
var
line: string(80);
nameFinalCharacter: integer;
uid: integer;
begin
while not EOF do
begin

nameFinalCharacter := index(line, separator) - 1;

{         ↑ `nameFinalCharacter + 1` }
{          ↑ `… + 2` is the index of the 1st password character }
uid := index(subStr(line, nameFinalCharacter + 2), separator);

{ Note that the preceding `index` did not operate on `line` }
{ but an altered/different/independent “copy” of it. }
{ This means, we’ll need to offset the returned index once again. }
readStr(subStr(line, nameFinalCharacter + 2 + uid), uid);
{ number from the source if a non-digit character is encountered. }
{ (Preceding blanks/space characters are ignored and }
{ the _first_ character still may be a sign, that is `+` or `-`.)}

if uid >= minimumID then
begin
writeLn(line[1..nameFinalCharacter]);
end;
end;
end.
```
Recall from the previous chapter that the third parameter in `subStr` can be omitted effectively meaning “give me the rest of a `string`.” Note that this programming task mimics (some of) the behavior of `cut(1)`. Use programs/source code that has already been programmed for you whenever possible. Reinventing the wheel is not necessary. Nonetheless, this basic task is a good exercise. On a RHEL system you may rather want to set `minimumID` to `500`.
The changed lines have been highlighted. A comment from the previous source code has been omitted.
```program cut2(input, output);
const
separator = ':';
minimumID = 1000;
var
line: string(80);
nameFinalCharacter: integer;
uid: integer;
begin
while not EOF do
begin

nameFinalCharacter := index(line, separator) - 1;

{         ↑ `nameFinalCharacter + 1` }
{          ↑ `… + 2` is the index of the 1st password character }
uid := index(subStr(line, nameFinalCharacter + 2), separator);

{ Note that the preceding `index` did not operate on `line` }
{ but an altered/different/independent “copy” of it. }
{ This means, we’ll need to offset the returned index once again. }
readStr(subStr(line, nameFinalCharacter + 2 + uid), uid);
{ number from the source if a non-digit character is encountered. }
{ (Preceding blanks/space characters are ignored and }
{ the _first_ character still may be a sign, that is `+` or `-`.)}

if uid >= minimumID then
begin
writeLn(line[1..nameFinalCharacter]);
end;
end;
end.
```
Recall from the previous chapter that the third parameter in `subStr` can be omitted effectively meaning “give me the rest of a `string`.” Note that this programming task mimics (some of) the behavior of `cut(1)`. Use programs/source code that has already been programmed for you whenever possible. Reinventing the wheel is not necessary. Nonetheless, this basic task is a good exercise. On a RHEL system you may rather want to set `minimumID` to `500`.

Write a prime sieve. One routine does the calculations, another routine prints them. This exercise’s goal is to give you an opportunity to type, to write an adequate program. If necessary, you can peek at existing implementations, but still write it on your own, adding your own comments to the source code.
The following `program` meets all requirements. Note, an implementation using an `array[1..limit] of Boolean` would have been perfectly fine as well, although the shown `set of natural` implementation is in principle preferred.
```program eratosthenes(output);

type
{ in Delphi or FPC you will need to write 1..255 }
natural = 1..4095;
{\$setLimit 4096}{ only in GPC }
naturals = set of natural;

const
{ `high` is a Borland Pascal (BP) extension. }
{ It is available in Delphi, FPC and GPC. }
limit = high(natural);

{ Note: It is important that `primes` is declared }
{ in front of `sieve` and `list`, so both of these }
{ routines can access the _same_ variable. }
var
primes: naturals;

{ This procedure sieves the `primes` set. }
{ The `primes` set needs to be fully populated }
{ _before_ calling this routine. }
procedure sieve;
var
n: natural;
i: integer;
multiples: naturals;
begin
{ `1` is by definition not a prime number }
primes := primes - [1];

{ find the next non-crossed number }
for n := 2 to limit do
begin
if n in primes then
begin
multiples := [];
{ We do _not_ want to remove 1 * n. }
i := 2 * n;
while i in [n..limit] do
begin
multiples := multiples + [i];
i := i + n;
end;

primes := primes - multiples;
end;
end;
end;

{ This procedures lists all numbers in `primes` }
{ and enumerates them. }
procedure list;
var
count, n: natural;
begin
count := 1;

for n := 2 to limit do
begin
if n in primes then
begin
writeLn(count:8, '.:', n:22);
count := count + 1;
end;
end;
end;

{ === MAIN program === }
begin
primes := [1..limit];
sieve;
list;
end.
```
Appreciate the fact that because you have separated the `sieve` task from the `list` task, both routine definitions and the main part of the `program` at the bottom remain quite short and are thus easier to understand.
The following `program` meets all requirements. Note, an implementation using an `array[1..limit] of Boolean` would have been perfectly fine as well, although the shown `set of natural` implementation is in principle preferred.
```program eratosthenes(output);

type
{ in Delphi or FPC you will need to write 1..255 }
natural = 1..4095;
{\$setLimit 4096}{ only in GPC }
naturals = set of natural;

const
{ `high` is a Borland Pascal (BP) extension. }
{ It is available in Delphi, FPC and GPC. }
limit = high(natural);

{ Note: It is important that `primes` is declared }
{ in front of `sieve` and `list`, so both of these }
{ routines can access the _same_ variable. }
var
primes: naturals;

{ This procedure sieves the `primes` set. }
{ The `primes` set needs to be fully populated }
{ _before_ calling this routine. }
procedure sieve;
var
n: natural;
i: integer;
multiples: naturals;
begin
{ `1` is by definition not a prime number }
primes := primes - [1];

{ find the next non-crossed number }
for n := 2 to limit do
begin
if n in primes then
begin
multiples := [];
{ We do _not_ want to remove 1 * n. }
i := 2 * n;
while i in [n..limit] do
begin
multiples := multiples + [i];
i := i + n;
end;

primes := primes - multiples;
end;
end;
end;

{ This procedures lists all numbers in `primes` }
{ and enumerates them. }
procedure list;
var
count, n: natural;
begin
count := 1;

for n := 2 to limit do
begin
if n in primes then
begin
writeLn(count:8, '.:', n:22);
count := count + 1;
end;
end;
end;

{ === MAIN program === }
begin
primes := [1..limit];
sieve;
list;
end.
```
Appreciate the fact that because you have separated the `sieve` task from the `list` task, both routine definitions and the main part of the `program` at the bottom remain quite short and are thus easier to understand.

Write a `program` that reads an infinite number of numerical values from `input` and at the end prints on `output` the arithmetic mean.
```program arithmeticMean(input, output);
type
integerNonNegative = 0..maxInt;
var
i, sum: real;
count: integerNonNegative;
begin
sum := 0.0;
count := 0;

while not eof(input) do
begin
sum := sum + i;
count := count + 1;
end;

{ count > 0: do not do division by zero. }
if count > 0 then
begin
writeLn(sum / count);
end;
end.
```

Note that using a data `type` excluding negative numbers (here we named it `integerNonNegative`) mitigates the issue that `count` may flip the sign, a condition known as overflow. This would cause the `program` to fail if `count := count + 1` became too large, and effectively falls out of the range `0..maxInt`.

There is, despite `maxReal`, no programmatic way to tell that `sum` became too large or too small rendering it severely inaccurate, because any value of `sum` may be legit nevertheless.
```program arithmeticMean(input, output);
type
integerNonNegative = 0..maxInt;
var
i, sum: real;
count: integerNonNegative;
begin
sum := 0.0;
count := 0;

while not eof(input) do
begin
sum := sum + i;
count := count + 1;
end;

{ count > 0: do not do division by zero. }
if count > 0 then
begin
writeLn(sum / count);
end;
end.
```

Note that using a data `type` excluding negative numbers (here we named it `integerNonNegative`) mitigates the issue that `count` may flip the sign, a condition known as overflow. This would cause the `program` to fail if `count := count + 1` became too large, and effectively falls out of the range `0..maxInt`.

There is, despite `maxReal`, no programmatic way to tell that `sum` became too large or too small rendering it severely inaccurate, because any value of `sum` may be legit nevertheless.

This task is a fine exercise for those using an EP-compliant compiler: Write a `time function` that returns a `string` in the “American” time format `9:04 PM`. This may look easy at first, but it can become quite a challenge. Have fun!
A smart person would try to reuse `time` itself. However, the output of `time` itself is not standardized, so we will need to define everything by ourselves:
```type
timePrint = string(8);

function timeAmerican(ts: timeStamp): timePrint;
const
hourMinuteSeparator = ':';
anteMeridiemAbbreviation = 'AM';
postMeridiemAbbreviation = 'PM';
type
noonRelation = (beforeNoon, afterNoon);
letterPair = string(2);
var
{ contains 'AM' and 'PM' accessible via an index }
m: array[noonRelation] of letterPair;
{ contains a leading zero accessible via a Boolean expression }
z: array[Boolean] of letterPair;
{ holds temporary result }
t: timePrint;
begin
{ fill `t` with spaces }
writeStr(t, '':t.capacity);
```

This fallback value (in the case `ts.timeValid` is `false`) allows the programmer/“user” of this `function` to “blindly” print its return value. There will be a noticeable gap in the output. Another sensible “fallback” value would be an empty `string`.

```	with ts do
begin
if timeValid then
begin
m[beforeNoon] := anteMeridiemAbbreviation;
m[afterNoon] := postMeridiemAbbreviation;
z[false] := '';
z[true] := '0';

writeStr(t,
((hour + 12 * ord(hour = 0) - 12 * ord(hour > 12)) mod 13):1,
hourMinuteSeparator,
z[minute < 10], minute:1, ' ',
m[succ(beforeNoon, hour div 12)]);
```

This is the most complicated part of this problem. First of all, all number parameters to `writeStr` are explicitly suffixed with `:1` as the minimum-width specification, because there are some compilers that would otherwise assume, for example, `:20` as a default value. Since we know that `timeStamp.hour` is in the range `0..23` we can use the `div` and `mod` operations as demonstrated. However, we will need account of an `hour` value of `0`, which is usually denoted as 12:00 AM (and not zero). A conditional “shift” by 12 using the shown `Boolean` expression and `ord` “fixes” this. Furthermore, here is a brief reminder that in EP the `succ` function accepts a second parameter.

```		end;
end;

timeAmerican := t;
end;
```
Finally we will need to copy our temporary result, to the function result variable. Remember there must be exactly one assignment, although not all compilers enforce this rule.
A smart person would try to reuse `time` itself. However, the output of `time` itself is not standardized, so we will need to define everything by ourselves:
```type
timePrint = string(8);

function timeAmerican(ts: timeStamp): timePrint;
const
hourMinuteSeparator = ':';
anteMeridiemAbbreviation = 'AM';
postMeridiemAbbreviation = 'PM';
type
noonRelation = (beforeNoon, afterNoon);
letterPair = string(2);
var
{ contains 'AM' and 'PM' accessible via an index }
m: array[noonRelation] of letterPair;
{ contains a leading zero accessible via a Boolean expression }
z: array[Boolean] of letterPair;
{ holds temporary result }
t: timePrint;
begin
{ fill `t` with spaces }
writeStr(t, '':t.capacity);
```

This fallback value (in the case `ts.timeValid` is `false`) allows the programmer/“user” of this `function` to “blindly” print its return value. There will be a noticeable gap in the output. Another sensible “fallback” value would be an empty `string`.

```	with ts do
begin
if timeValid then
begin
m[beforeNoon] := anteMeridiemAbbreviation;
m[afterNoon] := postMeridiemAbbreviation;
z[false] := '';
z[true] := '0';

writeStr(t,
((hour + 12 * ord(hour = 0) - 12 * ord(hour > 12)) mod 13):1,
hourMinuteSeparator,
z[minute < 10], minute:1, ' ',
m[succ(beforeNoon, hour div 12)]);
```

This is the most complicated part of this problem. First of all, all number parameters to `writeStr` are explicitly suffixed with `:1` as the minimum-width specification, because there are some compilers that would otherwise assume, for example, `:20` as a default value. Since we know that `timeStamp.hour` is in the range `0..23` we can use the `div` and `mod` operations as demonstrated. However, we will need account of an `hour` value of `0`, which is usually denoted as 12:00 AM (and not zero). A conditional “shift” by 12 using the shown `Boolean` expression and `ord` “fixes” this. Furthermore, here is a brief reminder that in EP the `succ` function accepts a second parameter.

```		end;
end;

timeAmerican := t;
end;
```
Finally we will need to copy our temporary result, to the function result variable. Remember there must be exactly one assignment, although not all compilers enforce this rule.

Sources:

1. Wirth, Niklaus (1979). "The Module: a system structuring facility in high-level programming languages". proceedings of the symposium on language design and programming methodology. Berlin, Heidelberg: Springer. Abstract. doi:10.1007/3-540-09745-7_1. ISBN 978-3-540-09745-7. Retrieved 2021-10-26.
2. Cooper, Doug. "Chapter 11. The `record` Type". Oh! Pascal! (third edition ed.). p. 374. ISBN 0-393-96077-3. "[…] records have two unique aspects:
• First, the stored values can have different types. This makes records potentially heterogeneous—composed of values of different kinds. Arrays, in contrast, hold values of just one type, so they’re said to be homogeneous.
• […]"
3. Wirth, Niklaus (1973-07-00). The Programming Language Pascal (Revised Report ed.). p. 30. "Within the component statement of the with statement, the components (fields) of the record variable specified by the with clause can be denoted by their field identifier only, i.e. without preceding them with the denotation of the entire record variable."
4. Jensen, Kathleen; Wirth, Niklaus. Pascal – user manual and report (4th revised ed.). p. 39. doi:10.1007/978-1-4612-4450-9. ISBN 978-0-387-97649-5. "The initial and final values are evaluated only once."

Notes:

1. This kind of `record` will not be able to store anything. In the next chapter you will learn a (and the only) instance it could be useful.
2. Indeed most compilers consider the dot as a dereferencing indicator and the field name denotes a static offset from a base memory address.
3. In Standard (“unextended”) Pascal, ISO standard 7185, a `function` can only return “simple data type” and “pointer data type” values.
4. Actually the shown `begin … end` is redundant since `repeat … until` constitute a frame in their own right. For pedagogical reasons we teach you to always use `begin … end` nevertheless whereever a sequence of statements usually appears. Otherwise you might change your `repeat … until` loop to a `while … do` loop forgetting to surround the loop’s body statements with a proper `begin … end` frame.
5. The `packed` designation has been omitted for simplicity.
6. According to most compilers’ definition of `maxInt`. The ISO standards merely require, that all arithmetic operations in the interval `-maxInt..maxInt` work absolutely correct, but it is thinkable (although unlikely) that more values are supported.

Next Page: Pointers | Previous Page: Strings

Home: Pascal Programming