Skip to main content

Beginners guide to Pascal

One of the strangest things is that most common search term for this blog is Turbo Pascal, that I've mentioned once (now twice) in my personal history of computing. I will attempt to honor that by posting a small beginners guide to Pascal. All code presented here should be available for download at this link.

The toolset, compiler and editor

I will not be using the old Turbo Pascal 6.0 environment for these examples. It is not that accessible now as it was 15 years ago when I started to learn programming. Instead I recommend any text editor with syntax highlighting for pascal or delphi and Free Pascal compiler. This should be available for most operating system environments.

Turbo Pascal

Your first program

I don't know why you would like to learn Pascal. It is pretty much a dead language and only lives on in Delphi, which is also on the decline. I can only assume that you need to learn Pascal as a programming assignment at school. If you like the syntax of Pascal and would like to find a similiar language more up to date I would suggest you'd look into Ada or Delphi. Both languages are much more up to date with todays standard and suitable for production use.

program HelloWorld;
 begin
  Writeln('Hello World!');
 end.

  1. Name of the program, remember the semi-colon at the end (;)
  2. Main program listing begins here
  3. Write Hello World! to console output
  4. End the program listing, the main end has a dot (.) instead of a semicolon (;)

When I compile this I get one .o object file and one executable. If I run the executable I will get "Hello World!" written to the console window. Cool!

fpc src/helloworld.pas -obin/helloworld

This will compile the source code to bin/helloworld (use helloworld.exe if you're in DOS32 environment).

Variables

A variable is an identifier that has a value. You use them to store values into memory for later processing. There are 6 main types in the Pascal programming language.

Type Example
integer Numbers: 3, 34, 0, -345
real Numbers with decimals: 3.0, -0.05, 3.14
char Single characters: a, F, 2, !
string Multiple characters: Hello World!, Cheers!, My dog is Sam
boolean True or false: true, false
pointer more about this later

First you declare a variable identifier and type, then you may assign a value to that variable, and them you're ready to use the variable.

program Variables;
 var width : integer;
 var height : integer;
 var area : integer;
 begin
  width := 12;
  height := 4;
  area := width * height;

Write('With the width ' +); Write(width); Write(' and the height '); Write(height); Write(' you have the area '); Writeln(area); end.

And you will get the expected output.

With the width 12 and the height 4 you have the area 48

If you have a value that never changes, you should use a constant instead of a variable. Here's an example with the constant of PI.

program Constants;
 const pi = 3.14;
 var radius, area : real;
 begin
  radius := 5.0;
  area := radius * radius * pi;

Write('With the radius '); Write(radius:1:0); Write(' we have the area '); Writeln(area:6:2); end.

  1. The strange notation is formatting. It means that we should use 1 space for the number and display 0 decimals.
  2. The same way this means, use 6 spaces for the number with 2 decimals.

The expected output is

With the radius 5 we have the area  78.50

Read input from user

You easily read input from user with Readln.

program ShoeSize;
 var name : string;
 var size : real;
 begin
  Write('What is your name: ');
  Readln(name);

Write('What is your shoe size: '); Readln(size);

Write('Hello '); Write(name); Write(', your shoesize is '); Writeln(size:3:1); end.

And the output looks like this. Yellow markings are input done by the user.

What is your name: Mikael
What is your shoe size: 41.5
Hello Mikael, your shoesize is 41.5

Control flow

Time to take a look at if-then-else and looping constructs in Pascal.

program GuessTheNumber;
 const Max = 1000;
 var number, guess, guesses : integer;
 begin
  Writeln('The number is between 1-1000.');

(* Initialize variables *) number := Random(Max) + 1; guess := -1; guesses := 0;

while guess <> number do begin Write('Guess the number: '); Readln(guess);

if guess > number then Writeln('Your guess was too high') else Writeln('Your gess was too low');

guesses := guesses + 1; end;

Write('You found the number in '); Write(guesses); Writeln(' tries.'); end.

  1. Rand(Max) will randomize a number of 0-999. We add 1 to get a random number of 1-1000.
  2. The while loop will not exit until guess is equal to number. Begin marks the beginning of a code block.
  3. Runs the next expression if guess is larger than number, otherwise runs the else case.
  4. Notice that semicolon (;) is missing when there is an else case.

The expected output is

The number is between 1-1000.
Guess the number: 500
Your gess was too low
Guess the number: 800
Your guess was too high
Guess the number: 750
Your guess was too high
Guess the number: 650
Your guess was too high
Guess the number: 550
Your guess was too high
Guess the number: 525
Your gess was too low
Guess the number: 535
Your gess was too low
Guess the number: 545
Your gess was too low
Guess the number: 548
Your gess was too low
Guess the number: 549
Your gess was too low
You found the number in 10 tries.

As you notice, the code will tell us that "Your guess was too low" even when we're spot on. How do we fix that bug?

For-loop

The for loop starts at a number and counts it up until it reaches a max.

program Pyramid;
 var i, j : integer;
 var height : integer;
 begin
  Write('Height of pyramid: ');
  Readln(height);

for i := 1 to height do begin

(* Write empty spaces before building blocks *) for j := 1 to (height - i) do Write(' ');

(* Write building blocks ) for j := 1 to (i + (i - 1)) do Write('');

Writeln(); end; end.

  1. Will loop "height" number of times. First time i will be 1, second time it will be 2 and so on. Notice the begin that marks beginning of a block that ends on line 19.
  2. It's ok to have inner for loops and to use arithmetic expressions to calculate upper bound.

The output of this should be

Height of pyramid: 5
    *
   ***
  *****
 *******
*********

And we could also count down, with the keyword downto.

program Factorial;
 var i, n, result : integer;
 begin
  Write('Calculate factor of: ');
  Readln(n);

result := 1; for i := n downto 1 do result := result * i;

Write(n); Write('! = '); Writeln(result); end.

The output of this would be

Calculate factor of: 5
5! = 120

Case-else can be quite useful for building menu options.

program Menu;
 var input : integer;
 begin
  (* Initialize variables *)
  input := 0;

while input <> 5 do begin Writeln('Welcome, please select any of the following'); Writeln('1. Vegetables'); Writeln('2. Fruit'); Writeln('3. Gardening tools'); Writeln('4. Electronic equipment'); Writeln('or 5 to quit'); Write('> '); Readln(input);

case input of 1..2 : Writeln('You selected food'); 3, 4 : Writeln('You selected a tool'); 5 : Writeln('Thank you, and welcome back') else Writeln('Error: Unrecognized option'); end; end;
end.

  1. You can scoop up cases based on ranges of values.
  2. or you can use discrete values
  3. Notice that this line has no semicolon ending, because there is an else on the next line.
  4. The case statement has an end; even without begin.

Part of the output looks like this

Welcome, please select any of the following
1. Vegetables
2. Fruit
3. Gardening tools
4. Electronic equipment
or 5 to quit
> 88
Error: Unrecognized option

String and arrays

Strings are arrays of characters. You can specify the length of the string when you define them, or leave the length out and have it set to 255. Who needs longer strings than that anyway?

program Encrypt;
 const Alphabet = 25;
 var data, result : string; (* char array of 255 characters *)
 var encKey, i : integer;
 var encChar : char;

begin Write('Enter the encryption key: '); Readln(enckey);

Write('Enter the phrase to encrypt (capital letters): '); Readln(data);

result := ''; for i := 1 to Length(data) do begin (* Add the encryption key digit to all characters *) encChar := Chr(((Ord(data[i]) + encKey) mod Alphabet) + Ord('A')); result := result + encChar; end;

Write('Encrypted phrase: '); Writeln(result); end.

  1. The Length(data) function will return the length of the array, or string in this case.
  2. Ord(c) will get ascii number for the character, mod is the modulus operator and Chr(i) will get the char for that ascii number. The result is an encrypted character.

I assume that you did recognize the ceasar cipher used. Not very strong, but works well on the feeble minded.

Enter the encryption key: 1337
Enter the phrase to encrypt (capital letters): SECRET
Encrypted phrase: UGETGV

Arrays

You can create a new array by saying var [name] : array[x..y] of [type]. Here's an example of the fibonacci calculation.

program Fibonacci;
 const Max = 10;
 var numbers : array[1..Max] of integer;
 var i : integer;

begin numbers[1] := 1; numbers[2] := 2;

(* Calculate fibonacci sequence *) for i := 3 to Max do numbers[i] := numbers[i - 2] + numbers[i - 1];

(* Print out the sequence *) Write('Fibonacci: '); for i := 1 to Max do begin Write(numbers[i]); Write(' '); end;

Writeln; end.

  1. The Max constant used for top limit of the array could as easily been a number. I used a constant here for reuse in both for statements.

And the expected printout as follows.

Fibonacci: 1 2 3 5 8 13 21 34 55 89

Procedures

A procedure is some piece of code that you might want to cut out and call several times.

program Procedures;
 const Width = 33;

procedure Title; begin Writeln('*** PASCAL WILL RULE THE WORLD ***'); end;

procedure Separator; var i : integer; begin for i := 0 to Width do Write('*'); Writeln; end;

(* Main program begins here *) begin Separator; Title; Separator; end.

  1. Notice that this constant is global, which means that it can be reached within a procedure, example at line 12.
  2. This variable i is local for the procedure, which means that it will be destroyed when the execution ends the procedure.

Expected output

**********************************
*** PASCAL WILL RULE THE WORLD ***
**********************************

You can send arguments to a procedure as I do with the Swap procedure below. I'm using the numbers array as a global variable. Shame on me.

program BubbleSort;
 const Max = 20;
 var numbers : array[1..Max] of integer;

(* Randomize digits in the array *) procedure Randomize; var i : integer; begin for i := 1 to Max do numbers[i] := Random(100); end;

(* Swap two values in the array *) procedure Swap(x, y : integer); begin numbers[x] := numbers[x] xor numbers[y]; numbers[y] := numbers[x] xor numbers[y]; numbers[x] := numbers[x] xor numbers[y]; end;

procedure Sort; var i, j : integer; begin for i := 1 to Max - 1 do begin for j := i + 1 to Max do begin if numbers[i] > numbers[j] then Swap(i, j); end; end; end;

procedure Print; var i : integer; begin for i := 1 to Max do begin Write(numbers[i]); Write(' '); end; Writeln; end;

(* Main program starts here *) begin Randomize; Sort; Print; end.

  1. You will recognize the infamous XOR swap algorithm here. We define two arguments with the type integer.
  2. We call the Swap procedure with the arguments i, and j which are positions in the array that needs swapping.

The expected output

5 27 29 38 38 42 43 47 54 54 59 60 62 64 71 84 84 85 89 96

Functions and recursion

The difference with functions and procedures is that functions will return a value which makes it usable for recursion, i.e. calling itself. Following function uses recursion to do a binary search algorithm on a sorted list. Complexity should me O(n log n).

program Find;
 const Min = 1;
 const Max = 10;
 type Vector = array[Min..Max] of integer;

var guess : integer;

function CreateVector() : Vector; var v : Vector; begin v[1] := 27; v[2] := 29; v[3] := 38; v[4] := 42; v[5] := 43; v[6] := 47; v[7] := 54; v[8] := 59; v[9] := 60; v[10] := 62;

CreateVector := v; end;

function Exists(min, max, search : integer; v : Vector) : boolean; var middle : integer; begin

(* Found *) if (search = v[min]) or (search = v[max]) then Exists := true

(* Not found *) else if max - min < 2 then Exists := false

(* Keep looking *) else begin middle := min + Trunc((max - min) / 2);

if (search &gt;= v[middle]) then
 Exists := Exists(middle, max, search, v)
else
 Exists := Exists(min, middle - 1, search, v);  

end; end;

(* Main program starts here *) begin Write('Test if a number is in vector: '); Readln(guess);

Writeln(Exists(Min, Max, guess, CreateVector())); end.

  1. I create a type alias for the array. It will be easier reference to it in function calls.
  2. A function that should return a Vector
  3. You return a value by giving the function the value you want to return.
  4. min, max and search are arguments of integer, and v is of Vector. The return result is true/false that indicates if value is found.
  5. Recursive call to the same function that is running.
Test if a number is in vector: 38
TRUE

Records and pointers - linked lists

Records can be used to bundle primitives together and the most useful combination is with pointers. As you can use pointers from one record to another record and create linked lists. In the following piece of code I will use the sieve of Eratosthenes to produce the first 100 primes.

program Primes;
 type
  ListRef = ^List;

List = record current : integer; next : ListRef; end;

var result : ListRef;

(* Build a list of integers ranging from min to max *) function Range(min, max: integer) : ListRef; var list : ListRef; begin New(list);

if min = max then list^.current := max

else begin list^.current := min; list^.next := Range(min + 1, max); end;

Range := list; end;

(* Filter all the specific factors from the list *) function FilterFactors(numbers : ListRef; factor : integer) : ListRef; var next : ListRef; begin if numbers = nil then FilterFactors := numbers

else if numbers^.current mod factor = 0 then begin next := numbers^.next; numbers^.next := nil; Dispose(numbers);

FilterFactors := FilterFactors(next, factor);

end

else begin numbers^.next := FilterFactors(numbers^.next, factor); FilterFactors := numbers; end; end;

(* Remove all numbers that aren't primes *) function FilterPrimes(numbers : ListRef) : ListRef; begin if numbers <> nil then begin numbers^.next := FilterFactors(numbers^.next, numbers^.current); numbers^.next := FilterPrimes(numbers^.next); end;

FilterPrimes := numbers; end;

(* Print the list *) procedure Print(numbers : ListRef); begin if numbers <> nil then begin Write(numbers^.current); Write(' ');

Print(numbers^.next);

end; Writeln; end;

(* Main program starts here *) begin result := FilterPrimes(Range(2, 100)); Print(result); end.

  1. Alias the List pointer type to ListRef
  2. Define a record of an integer and a pointer to next item in the linked list
  3. Create space on the heap for a new list item
  4. Clear the memory that the pointer points to, to be used by other programs

The output is as expected

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

Read on...

I'm impressed that you read this far. It must mean that you have almost as perverted mind as I have (that spent a whole Sunday writing Pascal examples). I could continue and tell you about writing and reading files from disc. I could go into graphics programming or object oriented programming with Pascal. I won't. Sorry. But I have uploaded all of my examples so that you can run them yourself in your favorite compiler. Have fun!

Update: This guide now has a follow up on units and objects.

comments powered by Disqus