This is the subset of Pascal that we have learned so far in Programming I. I'll add more language elements gradually as we learn them in this class.
For more information, see the full reference guide at the Free Pascal site.
{$mode delphi}
Enables the Delphi dialect of Free Pascal. This has several consequences, some of which are quite important:
integer represents a 32-bit signed integer (-2,147,483,648 ≤ i ≤ 2,147,483,647) rather than a 16-bit signed integer (-32,768 ≤ i ≤ 32,767).
string values are not limited to 255 characters.
I recommend that you put this directive at the top of every program.
{$r+}Enable range checking. On every array or string access a[i], the runtime checks that the index i is within the bounds of the array or string. If it isn't, the program will terminate with an error.
I recommend that you put this directive at the top of every program.
There are three different syntaxes for comments in a Pascal program:
{ 1. this is a comment, and may span multiple lines }
(* 2. this comment can also
span
multiple lines *)
// 3. this is a single-line commentComments using syntaxes (1) and (2) may be nested.
Identifiers are the names of variables and constants in a Pascal program. They may contain letters, digits and the underscore character ('_'), and may not begin with a digit.
A boolean
value is either true or false.
An integer
is a 16-bit signed value (-32,768 ≤ i ≤ 32,767) by
default.
If you have enabled Delphi mode (which I recommend), an integer
is a 32-bit signed value (-2,147,483,648 ≤ i ≤ 2,147,483,647).
An int64
is a 64-bit signed value (-9,223,372,036,854,775,808 ≤ i ≤
9,223,372,036,854,775,807).
A real
is a floating-point number, i.e. a number such as 2.347868
that can have digits after the decimal point.
real values have a much larger range than integers:
for example, a real can contain the number 1050
. However, real values will not be precisely accurate
when values are very large or small: they have only 15-16 significant
digits (possibly less on some platforms).
A char
is a single-byte (non-Unicode) character. Any ASCII
value can fit in a char ; this includes all the
characters you can type on a standard English-language keyboard.
A string
holds a sequence of characters. Without Delphi mode, a string
is limited to 255 characters. If you enable Delphi mode, a string
may have any length.
String constants are delimited with single quotes, e.g. 'the
red apple'. To embed a
single quote in a string, type it twice: 'she
didn''t get your letter'.
A string may contain non-ASCII characters such as 'ř'. Such characters are represented using multiple bytes (char values) in the string. Taken together, these bytes define a single Unicode character. (Precisely, this happens using a character encoding such as UTF-8. Such encodings are beyond the scope of this course.)
The length() function returns the length of a string. s[i] retrieves the i-th character of string s. The first character has index 1.
Strings are mutable: you can update character i by assigning to s[i].
An array
holds an indexed set of values of the same type. Arrays come
in two forms, static and dynamic.
A static array holds a fixed number of elements. You can declare a static array like this:
var a: array[1..100] of integer;
The array indices don't need to begin with 1. They can start at 0 or any other value:
var a: array[0..49] of boolean;
You may specify a set of initial values to be stored in a static array:
var
a: array[1..3] of string = ('down', 'the', 'road');The array indices may even be characters:
var a: array['a'..'z'] of integer;
A dynamic array holds a variable number of elements and can grow or shrink as the program runs. You can declare a dynamic array like this:
var a: array of integer;
Before you can use a dynamic array, you must set its length by
calling setLength:
setLength(a, 100);
Dynamic arrays are always indexed from 0, so after the call above the
array will hold values with indices from 0 to 99. When growing a
dynamic array, setLength sets any newly allocated
elements to zero.
You can use the syntax a[i] to read from or write to
a static or dynamic array:
a[44] := 33; a[44] := a[44] + 1;
Both static and dynamic arrays can be multidimensional.
You can declare a multidimensional static array using either of the following syntaxes:
var a: array[1..100][1..20] of integer; b: array[1..100, 1..20] of integer;
The declarations above are equivalent.
Here's how to declare a multidimensional dynamic array:
var d: array of array of integer;
To set the dimensions of such an array, call setLength
and pass each dimension as a separate parameter:
setLength(d, 100, 20);
You can access elements of a multidimensional array using either of
two syntaxes: a[i][j] or a[i, j].
A function or procedure parameter can have an array type with no bounds:
function sum(a: array of integer): integer;
This looks like a dynamic array type, but in this context this is an open array parameter. You can pass either a static or dynamic array to a function that expects an open array.
Just like dynamic arrays, open arrays are always indexed starting from 0, even if their source array has a different indexing base. For example:
procedure first(a: array of integer);
begin
writeln('low = ', low(a), ', high = ', high(a), ', first = ', a[0]);
end;
var
a: array[1..5] of integer = (2, 4, 6, 8, 10);
begin
first(a);
...This program will print
low = 0, high = 4, first = 2
You may pass a partial array to an open array parameter. For example, in the program above we could call
first(a[3..5]);
This will print
low = 0, high = 2, first = 6
You may define enumerated types, which have a fixed number of constant values:
type day = (monday, tuesday, wednesday, thursday, friday, saturday, sunday); var d: day = wednesday; i: integer;
Enumerated values are stored internally as integers.
Certain types are considered to be ordinal types: these
include boolean, all integer types, char,
and enumerated types. Values of ordinal types can be converted
to/from integers. They can be used
with comparison operators such as < and >
as array indices
in case statements
as for loop variables
with the in operator
When you declare a variable of any ordinal type, you can specify a range of values that it may hold:
var i: 10 .. 15; c: 'a' .. 'z';
The runtime will check that values are actually in these ranges only
if you have enabled range checking with the {$r+}
directive.
A record is a compound object that is composed of a set of fields. Each distinct record type defines the names and types of the fields that it contains. For example:
type
book = record
title: string;
author: string;
pages: integer;
end;
You can access a record's fields using the '.' operator.
For example:
var
b: book;
begin
b.title := 'war and peace';
b.author := 'leo tolstoy';
b.pages := 1440;
…
writeln('title = ', b.title);You can initialize a variable of any record type as you declare it:
var b: book = (title: 'war and peace'; author: 'leo tolstoy'; pages: 1440);
A pointer is an indirect reference to a variable. The type ^T means a pointer to type T. For example:
type
pos = record
x, y: real;
end;
var
p: ^pos; // a pointer to a pos
You can use the new function to allocate memory
dynamically. new takes an argument of any pointer type:
new(p); // now p points to a new dynamically allocated pos
The ^ (“circumflex” or “hat”) operator yields the value that a pointer points to:
p^.x := 4; p^.y := 5; writeln(p^.x + p^.y); // writes 9
The dispose function deletes memory that was allocated
with new:
dispose(p); // free the card
The special pointer value nil
points to nothing. If you attempt to access ^p where p is nil,
your program will crash.
If you want to pass a pointer to a function or procedure, or return a pointer from a function, you must declare a named pointer type:
type ppos = ^pos; // pointer to pos function foo(a: ^pos): ^pos; // will not compile! function foo(a: ppos): ppos; // this is fine
The text type represents a text file:
var novel: text;
You can read or write to a text file using the procedures described
in the quick library reference: assign, reset
and so on.
Pascal will implicitly (automatically) convert between certain types:
char → string
integer, int64 → real
integer → int64
int64 → integer
For example:
var c: char; s: string; i: integer; r: real; begin readln(c); readln(i); s := c; // char converted to string r := i; // integer converted to real
not
and
or
These are useful in if statements: if (x >
3) and ((y < 0) or (y > 10)) then ...
+ |
addition |
- |
subtraction |
* |
multiplication |
/ |
floating-point division |
div |
integer division |
mod |
integer remainder |
+, - and * can operate on integers or reals. If both operands are integers, these operators will return an integer; otherwise they return a real value.
/ can operate on integers or reals; it always returns a real.
div and mod can operate only on
integers, and return an integer.
You can also use + to concatenate two strings. (+ will not concatenate a string with a non-string value, unlike in some other languages.)
= |
equal |
<> |
not equal |
< |
less than |
> |
greater than |
<= |
less than or equal |
>= |
greater than or equal |
These operators can compare any values of any primitive type (boolean, integer, real, char, string). Strings are compared alphabetically.
The assignment operator := assigns a new value to a variable:
x := a + b;
The variable itself may appear on the right-hand side:
x := x + 1;
The assignment operators +=, -=, *=
and /= are a convenient shorthand. As an example,
x += 4;
is equivalent to
x := x + 4;
The other operators (-=, *=, /=)
work similarly.
The if statement executes one or more statements if a
condition is true:
if x > 3 then
begin
y := x;
z := x + 1;
end;
If there is only one statement to be executed, you may omit the begin
and end.
An if statement may optionally include an else
clause indicating one or more statements to be executed if the
condition is false:
if x > 3 then
y := x + 1
else
begin
z := x + 1;
y := x – 1;
end;Warning: do not put a semicolon before the else, or the compiler will complain! This is the one place in Pascal where a statement must not be followed by a semicolon.
A case statement uses a given value (of any ordinal
type) to choose which of a set of statements to execute:
var
c: integer;
...
readln(c);
case c of
2..10: writeln(c);
11: writeln('jack');
12: writeln('queen');
13: writeln('king');
14:
begin
writeln('ace');
aces := aces + 1;
end
else
writeln('unknown card');
end;
The else clause is optional. If it is not present, and
the supplied value does not match any case labels, then the entire
case statement is skipped.
Note that you must use begin/end to wrap
multiple statements in any case group except the else
group, in which begin/end are optional.
In the main begin/end block, the exit
statement exits the program immediately:
exit;
If there is no enclosing procedure or function, the program exits.
In a function, exit can take a parameter indicating a value to be returned from the function:
exit(4);
A for…to statement loops over successive values. It
looks like this:
for i := 1 to n do
begin
writeln(i);
writeln(i * 2);
end;
You must declare the loop variable (i in this case) in a
var section before you can use it in a for
statement. The loop variable may be of type integer,
char, or even boolean.
If there is only one statement in the loop body, you can omit the
begin and end.
To loop through decreasing values, use downto rather
than to:
for i := 10 downto 1 do
writeln(i);
writeln('liftoff');
The value of the loop variable is undefined after a for
loop has completed execution.
The for…in statement loops over successive elements
of an array or string:
var a: array[1..100] of integer; sum: integer = 0; … for v in a do sum := sum + v;
The preceding for loop is equivalent to
for i := low(a) to high(i) do sum := sum + a[i];
A while statement loops for as long as a condition is
true. It looks like this:
while i > 0 do
begin
writeln(i);
i := i div 2;
end;
If there is only one statement in the loop body, you can omit the
begin and end.
If the condition in a while loop is false at the
beginning, the loop body is skipped: no iterations will run.
The repeat statement loops until a condition becomes true. It looks like this;'
repeat writeln(x); x := x * 2; until x > 100;
Note that the body of a repeat statement is not enclosed
in begin and end.
The body of a repeat statement always executes at least once.
The break statement breaks out of the nearest
enclosing for, while, or repeat loop.
A type declaration introduces a new name for a type:
type int = integer; array3 = array[1..3] of integer; var i: int; a: array3;
A constant declaration introduces a name for a constant:
const Seconds = 60;
The expression in a constant declaration is evaluated at compile time. It may contain other constants and operators, but no variables:
const Microseconds = Seconds * 1000 * 1000; Three = trunc(pi);
A variable declaration introduces a variable and gives it a type:
var x: integer; r: real;
You may declare several variables of the same type together:
var s, t, u: string;
When declaring a single variable, you may give it an intial value:
var a: integer = 4;
A function declaration introduces a function:
function add(x: integer; y: integer): integer;
begin
add := x + y;
end;A procedure declaration is similar, but procedures return no value:
procedure exclaim(s: string, n: integer);
var
i: integer;
begin
for i := 1 to n do
writeln(s);
end;Variables declared inside a function or procedure are known as local variables, and are not visible outside it.
A function or procedure may read and write variables declared outside it, as long as they appear before the declaration of the function or procedure itself.
By default arguments are passed by value, which means that the receiving function gets its own local copy of each argument and cannot modify a variable passed to the function.
If you precede an parameter declaration with var, the
caller’s variable will be passed by reference, so the caller
can modify it:
procedure increment(var x: integer; by: integer);
begin
x := x + by;
end;
…
var
n: integer = 4;
begin
increment(n, 2); // now n is 6A parameter preceded with out lets a function return
a value by setting a variable that is passed by reference. This is
similar to var, but does not let the function receive a
value from the caller. For example:
// Return the first and last character of a string function firstAndList(s: string; out first: char; out last: char); begin first := s[1]; last := s[length(s)]; end;
out parameters are available only if you enable Delphi
mode.
A function cannot modify a parameter that is preceded with const.
This means that Pascal does not need to make a local copy of the
value that is passed. In particular, this makes passing an array much
more efficient, since internally it can be passed by reference.
For example:
function sum(const a: array of integer): integer;
var
s: integer = 0;
v: integer;
begin
for v in a do
s := s + v;
sum := v;
end;A top-level program has this structure:
program add; uses character, crt; type int = integer; const Factor = 20; var x, y: int; function foo(a: integer, b: integer): boolean; ... begin clrScr; readln(x, y); writeln(x + y); end.
The program element at the very beginning is optional,
as are all declaration sections (uses, type, const, var,
function). Declarations may appear in any order.
The begin and end are required, as is
the period at the end.
Free Pascal lets you divide code into modules using units. A unit is defined in a Pascal source file that looks like this:
unit myUnit;
interface
type
abc = string;
procedure honk(s: abc);
function add(i, j: integer): integer;
implementation
procedure honk(s: abc);
begin
writeln('honk: ', s);
end;
function add(i, j: integer): integer;
begin
add := i + j;
end;
end.
The unit declaration at the top of the file specifies
the name of the unit. It must be the same as the source file name
without the '.pas' extension.
The interface section declares types, procedures and
functions that will be exported by the unit. Procedures and functions
declared in this section must be implemented in the following
implementation section.
A unit ends with the end keyword followed by a
period.
A program that uses a unit may call only the procedures and
functions declared in the interface section. Any other
procedures and functions in the implementation section
are private to the unit.