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.