Pascal Quick Reference

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.

directives

{$mode delphi}

Enables the Delphi dialect of Free Pascal. This has several consequences, some of which are quite important:

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.

comments

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 comment

Comments using syntaxes (1) and (2) may be nested.

identifiers

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.

types

boolean

A boolean value is either true or false.

integer

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).

int64

An int64 is a 64-bit signed value (-9,223,372,036,854,775,808 ≤ i ≤ 9,223,372,036,854,775,807).

real

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).

char

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.

string

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].

arrays

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;

multidimensional arrays

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].

open arrays

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

enumerated types

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.

ordinal types

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

ranges

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.

records

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);

pointers

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

files

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.

type conversions

Pascal will implicitly (automatically) convert between certain types:

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

boolean operators

not
and
or

These are useful in if statements: if (x > 3) and ((y < 0) or (y > 10)) then ...

arithmetic operators

+

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.)

comparison operators

=

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.

assignment statements

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.

branching

if

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.

case

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.

exit

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);

looping

for...to

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.

for...in

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];

while

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.

repeat

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.

break

The break statement breaks out of the nearest enclosing for, while, or repeat loop.

type declarations

A type declaration introduces a new name for a type:

type
  int = integer;
  array3 = array[1..3] of integer;

var
  i: int;
  a: array3;

constant declarations

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);

variable declarations

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;

function/procedure declarations

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.

var parameters

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 6

out parameters

A 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.

const parameters

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;

programs

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.

units

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.