Pascal Quick Reference

This is a summary of the subset of Pascal that we are learning and using in Progamming I.

This is a work in progress. I'll add more language elements 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. This has two consequences:

I recommend that you put this directive at the top of every program that uses arrays.

{$optimization tailrec}

Enable tail recursion optimization, which tells the Pascal compiler to transform tail-recursive functions into iterative code that uses a fixed amount of stack space.

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, constants, functions and procedures 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.

signed integer types

A signed integer can be either positive, zero, or negative.

type

size (bytes)

size (bits)

range

shortint

1

8

-128 … 127

smallint

2

16

-32,768 .. 32,767

integer*, longint

4

32

-2,147,483,648 .. 2,147,483,647

int64

8

64

-9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807

* - integer is longint assuming you have remembered to enable Delphi mode.

In most programs you can simply use integer for all integer variables.

unsigned integer types

An unsigned integer can be zero or positive, but never negative.


type

size (bytes)

size (bits)

range

byte

1

8

0 .. 255

word

2

16

0 .. 65535

longword

4

32

0 .. 4294967295

qword

8

64

0 .. 18446744073709551615

real types

Real types hold floating-point values. These types have a much larger range than integer types, but will not be precisely accurate when values are very large or small. (The name “real” is a slight misnomer since these values can never be irrational.)

type

size (bytes)

significant digits

range

single

4

7-8

1.5E-45 ... 3.4E38

real*, double

8

15-16

5.0E-324 .. 1.7E308

* - real may be equal to single on some platforms.

In most programs you can simply use real for all non-integer numbers.

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 single-byte (non-Unicode) characters. It may be any length (unless you forgot to enable Delphi mode, in which case it will be limited to 255 characters).

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

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
  b: 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');

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. You can convert an enumerated value to or from an integer using a type cast expression:

i := integer(d);
writeln(i);
d := day(i);

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

variant records

A variant record is a record whose field set can vary depending on the value of a tag field in the record. For example:

type
  shapeType = (square, rectangle, circle);

  shape = record
    centerX, centerY: real;

    case kind: shapeType of
      square: (side: real);
      rectangle: (length, height: real);
      circle: (radius: real);
    end;

In the example above, kind is the tag field, and has type shapeType which is an enumerated type. A tag field may alternatively have any ordinal type, such as integer or boolean.

To use a variant record, simply set its tag field and associated field values:

var
  s: shape;

begin
  s.kind := rectangle;
  s.length := 5.0;
  s.height := 3.0;
  ...

Code that processes a variant record will often want to use a case statement to branch based on its tag field:

  case s.kind of
    square:    area := s.side * s.side;
    rectangle: area := s.length * s.height;
    circle:    area := pi * s.radius * s.radius;
  end;

pointers

A pointer is an indirect reference to a variable. The type ^T means a pointer to type T. For example:

var
  p: ^integer;   // a pointer to an integer

The @ (“address of”) operator yields a pointer to a variable:

var
  i: integer;
begin

  i := 7;
  p := @i;      // now p points to i
…

The ^ (“circumflex” or “hat”) operator yields the value that a pointer points to:

  writeln(p^);  // writes 7
  p^ := 8;
  writeln(i);   // writes 8

You can use the new function to allocate memory dynamically. new takes an argument of any pointer type. For example:

type
  suit = (clubs, hearts, diamonds, spades);
  card = record
    rank: 2 .. 14;
    suit: suit;
  end;

var
  p: ^card;

begin
  new(p);   // now p points to a new dynamically allocated card
  p^.rank := random(13) + 2;
  p^.suit := suit(random(4));
  …

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
  pint = ^integer;    // pointer to integer

function foo(a: ^integer): ^integer;   // will not compile!

function foo(a: pint): pint;           // this is fine

function pointers

A function pointer is a value that refers to a function.

You can declare a function pointer type like this:

type
  intFun = function(a, b: integer): integer

Here is a function whose signature matches this function pointer type:

function add(a, b: integer): integer;
begin
  add := a + b;
end;

Use the @ (“address-of”) operator to get a pointer to a named function in your program:

var
  p: intFun;
begin
  p := @add;

You can call a function through a function pointer:

  writeln(p(3, 4));  // writes 7

files

The text type represents a text file:

var
  novel: text;

The file type represents a file on disk containing a particular type of binary data:

var
  f: file of integer;
  g: file of real;

Often a file will hold a compound type:

type
  time = record
    year, month, day: integer;
    hour, minute, second: integer;
  end;

var
  timestamps: file of time;

Note, however, that a file cannot contain data of any of these types:

If you want to store character data in a binary file, you must use a fixed-size character array, e.g. an array[1..100] of char.

For information about the various library functions that operate on files (assign, reset and so on), see the Run-Time Library Quick Reference.

boolean operators

not
and
or

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

unary arithmetic operators

+

identity

-

negation

binary 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 ordinal type, and also strings. Strings are compared alphabetically.

It is not possible to compare values of compound types, such as arrays and records.

in operator

The in opererator tests whether a value is in a range:

if c in ['A'..'Z'] then ...

It may be used with values of any ordinal type.

assignment statement

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

branching statements

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.

goto

A goto statement branches to an arbitrary label in the current block of code. You must declare a label before you can use it:

var
  x: integer;

label
  loop;

begin
  x := 1;

 loop:
  writeln(x);
  x := x + 1;
  if x <= 5 then goto loop;
end.

exit

The exit statement immediately exits the nearest enclosing procedure or function:

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 statements

for...to

A for…to statement loops over successive values of any ordinal type. 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.

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 values of an array:

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.

continue

The continue statement continues with the next iteration of the nearest enclosing for, while, or repeat loop.

If continue is executed during the last iteration of a for loop, the loop exits. When continue is executed in a while or repeat loop, the loop condition is tested before beginning a new iteration; if it is false (for while) or true (for repeat) then the loop exits.

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, operators, and calls to functions in the system unit, 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 yell(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. There are several keywords you can use to change Pascal’s argument-passing behavior.

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