There's strictly no warranty for the correctness of this text. You use any of the information provided here at your own risk.
For some course, I had to learn Pascal.
I didn't want to, but I had to. In the course, there were even more restrictions, I didn't like at all. For example were "break" and "continue" forbidden.
So I wanted to get over Pascal as quickly as possible. That's why I wrote this website.
I'm using Free Pascal (fpc) here.
Files with source-code written in Pascal usually have the suffix ".pas" or ".pp".
Here's a "Hello World" in Pascal:
program HelloWorld (output);
begin
writeln('Hello World.');
end.
"HelloWorld" is the name of the program, "(output)" is needed to print something. The ";" is required.
'Hello World.' is a string-constant and has to be written in single quotes.
Notice the dot "." after the last "end".
Notice, that Pascal is not case-sensitive (like it or not).
If you got that ugly message
/usr/bin/ld: warning: link.res contains output sections; did you forget -T?
while compiling, ignore it (and get used to it). It's some bug in fpc and ld. After all, it's only a warning, not an error.
Constants and Variables have to be declared in certain areas named "const" and "var" before the main "begin"-statement. These areas have an indentation of one level (we'll see later, why (the reason is, there can be whole functions and procedures between "var" and "begin"), while the main "begin"- and "end"-statements don't have indentation, so they are on the same indentation-level as "program":
program MyProgram (output);
const
PI = 3.1415;
var
a, b : integer;
begin
a := 5;
b := 10;
writeln(a);
writeln(b);
end.
Notice, that variables have to be declared with ":" and have to be assigned with ":=".
Whereas constants are assigned with a simple "=".
A for-loop is done like that:
program MyProgram (output);
var
i : integer;
begin
for i := 1 to 10 do
writeln(i);
writeln;
for i := 20 downto 10 do
writeln(i);
end.
Notice, that there's no semicolon after the "do"!
In the example above, only the next line is part of the for-loop.
If you want more than one line inside the for-loop, you have to write another "begin"-"end"-block:
program MyProgram (output);
var
i : integer;
begin
for i := 1 to 4 do
begin
writeln('Inside the for-loop');
writeln(i);
end;
end.
Notice, that there has to be a semicolon after the "end" of the for-loop-block!
At least in fpc (but not in the stone-age-Pascal of my recent university-course), there are also "break" and "continue" to exit loops prematurely:
program MyProgram (output);
var
i : integer;
begin
for i := 1 to 20 do
begin
if i = 5 then
begin
writeln('No 5!');
continue;
end;
if i = 10 then
break;
writeln(i);
end;
end.
Comments are written inside curly brackets.
program MyProgram (output);
var
a, b : integer;
begin
a := 1;
b := 2;
if a = 1 then
writeln('a is ', a);
if b > a then
writeln(b, ' is greater than ', a, '.');
if (a < b) and (b = 2) then
writeln('a is less than b and b is 2.');
{ These code-blocks again, if you want more than one line. }
if (a < b) and (b = 2) then
begin
writeln('a is less than b and b is 2.');
writeln('Code-block needed for more than one line.');
end;
if a = 10 then
writeln('a is 10.')
else
writeln('a is not 10.');
if a <> 10 then
writeln('a is really not 10.');
end.
Notice, that the syntax for "is equal" is "=", not "==" like in C/C++ and other languages!
The syntax for "is not equal" is "<>", not "!=" like in C/C++ and other languages.
If you use "and" or "or", you need brackets around the expressions, otherwise you get wrong results!
Notice, that before the "else" of an if-then-else-construction, there must not be a semicolon.
This is even the case, if before the "else" is an "end"-statement of a previous loop or a previous if-statement.
The reason is, that in Pascal the whole if-then-else-construction is seen as a single command.
In "begin ... end"-constructions inside the if-then-else-construction can be semicola, though.
There is also "else if".
This is a nice small program from a Perl-book (by Laura Lemay) I once read. If you come to this program and can run it, you already know some of the constructions, a programming-language uses:
program Kruemelmonster (input, output);
var
Kekse : string[10];
begin
Kekse := '';
while Kekse <> 'Kekse' do
begin
write('Ich will Kekse: ');
readln(Kekse);
end;
writeln('Mmmm. KEKSE.')
end.
So, we can declare a string of 10 characters.
The while-loop works as you might expect. :)
Somehow, we don't have to cut out (chomp) the newline-character of input (we get with "read()" or "readln()").
To get input, we have to write "(input, output);" into the first line.
Built-in datatypes ("simple types") in Pascal are:
Consider this program:
program MyPro (output);
var
a : real;
begin
a := 520.2;
writeln(a);
end.
If I compile and run it, instead of "520.2", I get
Not what I had expected.
The output is formatted in "floating point notation" (dt: "Gleitkommadarstellung"), while I wanted "fixed point notation" (dt: "Festkommadarstellung").
Fortunately, "write()" and "writeln()" can format the values to that.
You have to pass two more values to "write()" to allocate space for the numbers. So the format is "write(value : field_width : decimal_field_width)". Example:
program MyPro (output);
var
a : real;
begin
a := 520.2;
writeln(a : 4 : 1);
end.
"a : 4 : 1", because "520.2" has 4 digits altogether, with 1 digit after the decimal point. It won't harm to allocate more space, make sure, it's always enough for your needs.
There's a lot of theory behind the representation of floating-point numbers.
"write(value : field_width)" can be used for other datatypes too. If you set "field_width" larger than the data, you'd like to print, extra spaces are printed. This is for example useful to produce formatted tables.
More datatypes can be defined in a "type"-part of a Pascal program.
There's for example the "enumerated type" (dt. "Aufzählungstyp"). Several "identifiers" in an enumerated type are declared at once.
Numbers are automatically assigned to these identifiers. You can access these numbers with the "ord()"-function.
Operators like "=", ">=", "<>" can be used directly with the identifiers and are applied to the corresponding numbers.
You can access the next identifier and the previous one with the functions "succ()" and "pred()".
Here's an example:
program MyProgram (output);
type
tColor = (black, blue, red, magenta, green, cyan, yellow, white);
begin
writeln;
writeln('The number of cyan is: ', ord (cyan));
writeln('The successor of cyan is: ', succ(cyan));
writeln('The predecessor of cyan is: ', pred(cyan));
writeln;
if red < yellow then
writeln('The number of red is less than the number of yellow.');
end.
This is similar to the datatype "enum" in C/C++.
There's a "t" before "Color" in "tColor" to show, that "tColor" is a type.
If you declare a variable of the enumerated type, you can assign an identifier to it:
program MyProgram (output);
type
tColor = (black, blue, red);
var
a : tColor;
begin
a := red;
writeln(a);
end.
Then, there's the "subrange type" (dt. "Ausschnittstyp"). It's a datatype for subranges of integers, chars or enumerated types. It is declared with the ".."-operator. Example:
program MyProgram (output);
type
{ a subrange of integers: }
tSlice = 0 .. 5;
{ first an enumerated type: }
tColor = (black, blue, red, magenta, green, cyan, yellow, white);
{ then a subrange of the enumerated type: }
tColorPart = magenta .. cyan;
var
a : tSlice;
b : tColorPart;
begin
a := 3;
b := green;
writeln(a);
writeln(b);
end.
Notice, there are no brackets in the subrange type-declaration.
Now that we know, what enumerated types and subrange types are, we can finally declare an array. The declaration in the "type"-part has the form:
A subrange type is needed, so we would have to declare one first. But it's possible to declare the subrange inside the array-declaration (see example below)
It's useful to use constants for the first and last index-number of the array.
Example:
program MyProgram (output);
{ Creates, fills, and prints an array with the numbers from 0 to 9. }
const
AIndexStart = 0;
AIndexEnd = 9;
type
tArray = array [AIndexStart .. AIndexEnd] of integer;
var
a : tArray;
i : integer;
begin
for i := AIndexStart to AIndexEnd do
a[i] := i;
for i := AIndexStart to AIndexEnd do
writeln(a[i]);
end.
While arrays can only store elements of the same datatype, records (dt. "Verbund", "Verbundtyp") can store elements of different datatypes. The declaration in the "type"-part has the form:
The variable-declarations and the end-statement are often written below each other (i.e. in a culumn).
The variables inside the record (called "record selectors") are accessed with a dot ("."). Example:
program MyProgram (output);
type
tRec = record
a, b : integer;
c : char;
d : boolean;
end;
var
rec : tRec;
begin
rec.a := 5;
rec.b := 10;
rec.c := 'f';
rec.d := false;
writeln(rec.a);
writeln(rec.b);
writeln(rec.c);
writeln(rec.d);
end.
You can have records inside records too:
program MyProgram (output);
type
tRec = record
a : integer;
r2 : record
f : integer;
g : char;
end;
end;
var
rec : tRec;
begin
rec.r2.f := 1;
rec.r2.g := 'b';
writeln(rec.r2.f);
writeln(rec.r2.g);
end.
Maybe there should be no semicolon after the first "end". fpc seems to take both.
The principles of functions seem to be the same for most programming-languages. A code-block takes some arguments, processes them and returns a return-value. That makes it possible to separate a program into small pieces, that deal with more specific problems ("structured programming" (see end of this section too)). I can't teach the principles here (like what it means to have local variables and so on).
Look it up for your favourite language (Python maybe, it's as easy as it gets there).
For Pascal, a function-declaration (with its head and body (dt.: "Kopf und Rumpf")) looks like this:
program MyProgram (output);
function Product(a : integer; b : integer) : integer;
var
c : integer;
begin
c := 5;
Product := a * b * c;
end; { Product }
begin
writeln(Product(5, 10));
end.
So we have an indentation, the key-word 'function', then a function name, then some parameters (and their types) in brackets (notice, the parameters are separated by semicolon, not comma, as usual), then the type of the return-value. Then a semicolon.
After that, we have all the parts, you find in the main-part too. So, in a function there can be:
const
.....
type
.....
var
.....
begin
.....
end;
To return a value, take the name of the function again and assign the return-value to it (there's no "return-statement" like in other languages).
Assigning a value to the name of the function itself doesn't do a "return":
program MyProgram (output);
function Func () : integer;
begin
Func := 5;
Func := 10;
end;
begin
writeln(Func());
end.
Result: 10.
(By the way: Programming with functions in Pascal or especially in C is called
because that term means something else: Pascal, C, C++, Java, and so on, are imperative programming-languages. Commands are used to tell the computer, what to do.
On the other hand, in functional programming-languages (like Haskell, Lisp and Scheme) mathematical functions (like "f(x) = ax + b" and so on) are used, to describe and (hopefully) solve a programming problem.
Many languages (Perl, Python, Ruby) are basically imperative, but also support functional approaches (of course they also support structured programming).
Often, the possibility to use functional programming is added into later versions of a language and doesn't fit well to the rest of the language.
Most programs are still written in imperative style.)
Procedures are similar to functions, but don't return anything.
Strange enough, the keyword to pass values "by reference" is "val" inside the procedure-declaration.
So here's an example:
program MyProgram (output);
procedure ProcedureByValue(a : integer);
begin
writeln('ProcedureByValue: a is now: ', a);
a := 10;
writeln('ProcedureByValue: a is now: ', a);
end;
procedure ProcedureByReference(var a : integer);
begin
writeln('ProcedureByReference: a is now: ', a);
a := 10;
writeln('ProcedureByReference: a is now: ', a);
end;
var
a : integer;
begin
a := 5;
writeln('main: a is now: ', a);
writeln;
ProcedureByValue(a);
writeln('main: a is now: ', a);
writeln;
ProcedureByReference(a);
writeln('main: a is now: ', a);
end.
Inside procedures and functions, there can be other procedures and functions.
Inside the inner procedure or function the variables of the surrounding procedures and functions are visible.
If a variable is declared in an inner procedure or function with the same identifier (name) as a variable in the surrounding environment, the inner declaration is superior to the outer.
program MyProgram (output);
function func1 (a : integer) : integer;
procedure proc1;
begin
{ Variable a, passed to func1, is visible here. }
writeln('a of func1 in proc1: ', a);
end;
begin
proc1();
func1 := 3 * a;
end;
var
b : integer;
begin
b := func1(10);
writeln('b in main: ', b);
end.
Pointers are variables that point to other variables. The pointer itself just stores the memory-address of the other variable.
After they are "dereferenced" though, the content of the other variable can be accessed using the pointer.
Pointers are quite difficult to handle for the programmer, so more programmer-friendly languages like Python or JavaScript get along without them.
C though, makes heavy use of pointers, and Pascal has them too.
So let's just deal with a pointer pointing to an integer. To get a pointer, you declare one with the roof-symbol "^", then call the function "new()". Then you set the pointer to the other variable (the one, to which it is supposed to point). After that you can access the other variable with the pointer:
program MyProgram (output);
var
a : integer;
p : ^integer;
begin
a := 5;
new(p);
p^ := a;
writeln(p^);
end.
By writing "p^" instead of just "p", the pointer is dereferenced.
So: "p^" is the data, the pointer points to, while "p" is the pointer itself. So, if you want to pass a pointer to a function for example, you'll have to pass it "p", not "p^".
You can get rid of a pointer with the "dispose()"-function.
You can set pointers to variables of any datatype, even to complex data-structures such as records for example:
program MyProgram (output);
type
tRec = record
a, b : integer;
c : char;
d : boolean;
end;
var
rec : tRec;
p : ^tRec;
begin
rec.a := 5;
rec.b := 10;
rec.c := 'f';
rec.d := false;
new(p);
p^ := rec;
writeln(p^.b);
writeln(p^.d);
end.
This way, you can pass data-structures by reference (pointers are references) to functions and procedures and (even more important) back from functions.
While arrays and ordinary records are static, so the number of elements has to be declared at the beginning and can't be changed afterwards, with pointers and records dynamic lists can be created.
To implement a linked list, a record is declared, that has elements for the data and at the end a pointer pointing to another record of the same type. So one record-pointer points at the next record and so on. The last pointer in the list of records points to "nil", which is a keyword for "nothing".
In practice you don't implement linked lists yourself, you just use a class that has all the details (also for manipulating such lists), for example tList.
In the following, there are some details on implementing linked lists by hand. Just skip this, if you don't need it.
Well, I think I managed to implement a basic double-ended linked list with the hint from here. He suggests three pointers "first", "last" and "current" to control the list. Actually, it makes sense after that: While writing it that way, the pointers started representing the knots in my mind, almost as (OOP-)objects would have done, so it became easier to imagine the list and what the pointers did:
program ExampleForDoubleEndedLinkedList (output);
uses sysutils;
{ If you don't want sysutils, change the "PyPrintList"-calls to "PrintList"-calls. }
type
tp = ^tRec;
tRec = record
nr : integer;
previous : tp;
next: tp;
end;
var
first, current, last : tp;
i : integer;
procedure InitList;
{ Creating three globally known pointers to control the list. }
begin
new(first);
new(last);
new(current);
last^.next := nil;
first^.previous := nil;
first^.next := last;
last^.previous := first;
current := first;
end;
procedure UnshiftInt(a: integer);
{ Adds an integer to the beginning of a list, like unshift() in Perl. }
var
p : tp;
begin
current := first^.next;
new(p);
p^.nr := a;
first^.next := p;
p^.previous := first;
current^.previous := p;
p^.next := current;
end;
procedure PushInt(a : integer);
{ Adds an integer to the end of a list, like push() in Perl. }
var
p : tp;
begin
current := last^.previous;
new(p);
p^.nr := a;
p^.next := last;
last^.previous := p;
p^.previous := current;
current^.next := p;
end;
procedure PrintList;
{ Prints the integers of the list one per line. }
begin
current := first;
while current^.next <> last do
begin
current := current^.next;
writeln(current^.nr);
end;
end;
procedure PyPrintList;
{ Prints a Pascal-linked list of integers in Python-style. }
var
i, slen, llen : integer;
s, temp : string;
begin
{ Calculating string-length. }
slen := 0;
llen := 0;
current := first;
while current^.next <> last do
begin
llen := llen + 1;
current := current^.next;
temp := IntToStr(current^.nr);
slen := slen + length(temp) + 2 { 2 for ', '. };
end;
slen := slen + 10;
SetLength(s, slen);
s := '[';
current := first;
i := 0;
while current^.next <> last do
begin
current := current^.next;
temp := IntToStr(current^.nr);
s := s + temp;
i := i + 1;
if i < llen then
s := s + ', ';
end;
s := s + ']';
writeln(s);
end;
procedure ClearList;
{ Trying hard to clean up. }
var
temp : tp;
begin
current := first;
while current^.next <> nil do
begin
temp := current;
current := current^.next;
dispose(temp);
end;
end;
begin
InitList;
for i := 1 to 5 do
begin
UnshiftInt(i);
end;
PyPrintList;
writeln;
ClearList;
InitList;
for i := 1 to 10 do
begin
PushInt(i);
end;
PyPrintList;
end.