Pascal source consists of identifiers, keywords, numbers and special character
sequences. A Pascal identifier must begin with 'a' to 'z', but may continue
with 'a' to 'z' and '0' to '9'. There is no length limit on labels, but there
may be a practical limit. If the compiler cannot process a source line longer
than N, you cannot have a label longer than N, since labels may not cross lines.

Keywords (or reserved words) appear just as labels, but have special meaning
wherever they appear, and may never be used as identifiers:

and array begin case const div do

downto else end file for function goto

if in label mod nil not of

or packed procedure program record repeat set

then to type until var while with

A number can appear in both integer and real form. Integers will appear as
a sequence of digits:

83

00004

Are valid integer numbers. For a number to be taken as "real" (or
"floating point") format, it must either have a decimal point, or
use scientific notation:

1.0

1e-12

0.000000001

Are all valid reals. At least one digit must exist on either side of a decimal
point. Strings are made up of a sequence of characters between single quotes:

'string'

The single quote itself can appear as two single quotes back to back in a
string:

'isn''t'

Finally, special character sequences are one of the following:

+ - * / = < >

[ ] . , : ; ^

( ) <> <= >= .. @

{ } (* *) (. .)

Note that these are just aliases for the same character sequence:

@ and ^ (or the "up arrow" if allowed in the typeface)

(. and [

.) and ]

(* and {

*) and }

Spaces and line endings in the source are ignored except that they may act
as "separators". No identifier, keyword, special character sequence
or number may be broken by a separator or other object. No two identifiers,
keywords or numbers may appear in sequence without an intervening separator:

A Pascal program appears as a nested set of "blocks", each of which
has the following form:

block_type name(parameter [, parameter]...);

label x[, y]...

const x = y;

[q = r;]...

type x = y;

[q = r;]...

var x[,y]...: z;

[x[,y]...: z;]...

[block]...

begin

statement[; statement]

end[. | ;]

Note that:

[option] means optional.

[repeat]... means can appear 0 or more times.

[x | y] means one or the other.

There are three types of blocks, program, procedure and function. Every program
must contain a program block, and exactly one program block exists in the source
file.

Each block has two distinct sections, the declaration and statements sections.
The declarations immediately before a statement section are considered "local"
to that section.

The declaration section builds a description of the data used by the coming
statement section in a logical order. For example, constants are usually used
to build type declarations, and type declarations are used to build variables,
and all of these may be used by nested blocks.

A block can be declared within a block, and that block can declare blocks
within it, etc. There is no defined limit as to the nesting level. Because only
one program block may exist, by definition all "sub blocks" must be
either procedure or function blocks. Once defined, a block may be accessed by
the block it was declared in. But the "surrounding" block cannot access
blocks that are declared within such blocks:

program test;

procedure junk;

procedure trash;

begin { trash }

...

end; { trash }

begin { junk }

trash;

...

end; { junk }

begin { test }

junk;

...

end. { test }

Here test can call junk, but only junk can call trash. Trash is "hidden"
from the view of test. Similarly, a subblock can access any of the variables
or other blocks that are defined in surrounding blocks:

program test;

var x;

procedure q;

begin

end;

procedure y;

begin

q;

x := 1

end;

begin

y;

writeln('x')

end.

The variable "x" can be accessed from all blocks declared within
the same block. It is also possible for a block to call itself, or another block
that calls it. This means that recursion is allowed in Pascal.

Every identifier must be declared before it is used, with only one exception,
pointers, which are discussed later. But there is a way to declare procedures
and functions before they are fully defined to get around problems this may
cause.

Several types are predeclared in Pascal. These include integer, boolean,
char, real and text. predeclared types, just as predeclared functions and procedures,
exist in a conceptual "outer block" around the program, and can be
replaced by other objects in the program.

Types in Pascal can be classed as ordinal, real and structured. The ordinal
and real types are referred to as the "basic" types, because they
have no complex internal structure. Ordinal types are types whose elements
can be numbered, and there are a finite number of such elements.

The basic ordinal type is "integer", and typically it represents
the accuracy of a single word on the target machine:

var i: integer;

A predefined constant exists, "maxint", which tells you what the
maximum integral value of an integer is. So:

type integer = -maxint..maxint;

Would be identical to the predefined type "integer". Specifically,
the results of any operation involving ordinals will only be error free if they
lie within -maxint to +maxint. Although other ordinal types exist in Pascal,
all such types have a mapping into the type "integer", and are bounded
by the same rules. The "ord" function can be used on any ordinal to
find the corresponding integer.

Enumerated types allow you to specify an identifier for each and every value
of an ordinal:

type x = (one, two, three, four);

Introduces four new identifiers, each one having a constant value in sequence
from the number 0. So for the above:

one = 0

two = 1

three = 2

four = 3

Enumerated types may have no relationship to numbers whatever:

type y = (red, green, blue);

Or some relationship:

type day = (mon, tue, wed, thur, fri, sat, sun);

Here the fact that "day"s are numbers (say, isn't that a lyric
?) is useful because the ordering has real world applications:

if mon < fri then writeln('yes');

And of course, subranges of enumerated types are quite possible:

type workday = (mon..fri);

Enumerated types are fundamentally different from integer and subrange types
in the fact that they cannot be freely converted to and from each other. There
is only one conversion direction defined, to integer, and that must be done
by special predefined function:

The only predefined enumerated type is "boolean", which could be
declared:

type boolean = (false, true);

However, booleans cannot be cross converted (being enumerated types), this
user created type could not in fact be used just as the predeclared one. Booleans
are special in that several predefined procedures, and all of the Comparison
operators ("=", ">", etc.) give boolean results. In addition,
several special operators are defined just for booleans, such as "and",
"or" etc.

Character types in Pascal hold the values of the underlying character set,
usually ISO single byte encoded (including ASCII). The Pascal standard makes
no requirements as to what characters will be present or what order they will
appear in. However, as a practical matter, most Pascal programs rely on the
characters of the alphabet and the digits '0'-'9' being present, and that these
are numbered sequentially (which leaves out EBCDIC, for example). A character
declaration appears as:

var c: char;

Character values can also be converted to and from integers at will, but
only by using the special functions to do so:

Real types, or "floating point", allow approximations of a large
range of numbers to be stored. The tradeoff is that reals have no direct ordinality
(cannot be counted), and so have no direct relationship with integers. Real
types are the only basic type which is not ordinal.

var r: real;

Integers are considered "promotable" to reals. That is, is is assumed
that an integer can always be represented as a real. However, there may be a
loss of precision when this is done (because the mantissa of a real may not
be as large as an integer). Reals are never automatically promoted to integer,
however, and the programmer must choose between finding the nearest whole number
to the real, or simply discarding the fraction. This choice must be made explicitly
by predefined function.

A structured type is a type with a complex internal structure. In fact, the
structured types all have one thing in common: they can hold more than one basic
type object at one time. They are structured because they are "built up"
from basic types, and from other structured types.

Structured types can also be "packed", which is indicated by the
keyword "packed" before the type declaration. Packing isn't supposed
to change the function of the program at all. Stripping the "packed"
keywords out of a program will not change the way it works (with the exception
of "strings", below). Packing means that (if implemented: its optional)
the program should conserve space by placing the values in as few bits as possible,
even if this takes more code (and time) to perform.

Packing is better understood if you understand the state of computers before
Microprocessors (the Jurassic age of computers ?). Most mainframe computers
access memory as a single word size only, and not even a neat multiple of 8
bits either (for example, 36 bit computer; the CDC 6000 has 60 bit words). The
machine reads or writes in words only. There is no byte access, no even/odd
addressing, etc. Because storage on such a machine of small items could be wasteful
(especially characters), programs often pack many single data items into a single
word.

The advent of the Minicomputer changed that. DEC started with an 8 bit machine
(just as microprocessors did), and when they changed to 16, then 32 bits the
ability to address single bytes was maintained.

For this reason, many people refer to such a machine as "automatically
packed", or that Pascal's packing feature is unnecessary on such machines.
However, quantizing data by 8 bit bytes is not necessarily the most extreme
packing method available. For example, a structure of boolean values, which
take up only 1 bit per element, left to byte packing would waste 7/8s of the
storage allocated.

The most basic structured type is the array. Pascal is unusual in that both
the upper and lower bounds of arrays are declared (instead of just the upper
bound or length), and that the index type can be any ordinal type:

var a: array [1..10] of integer;

Would declare an array of 10 integers with indexes from 1 to 10. You may
recognize the index declaration as a subrange, and indeed any subrange type
can be used as an index type:

type sub = 0..99;

var a: array [sub] of integer;

Arrays can also be declared as multidimensional:

var a: array [1..10] of array [1..10] of char;

There is also a shorthand form for array declarations:

var a: array [1..10, 1..10] of char;

Is equivalent to the last declaration.

A special type of array definition is a "string". Strings are arrays
of packed characters, with integer indexes, whose lower bound is 1:

var s: packed array [1..10] of char;

String types are special in that any two strings with the same number of
components are compatible with each other, including constant strings.

Records give the ability to store completely different component types together
as a unit. There they can be manipulated, copied and passed as a unit. It is
also possible to create different typed objects that occupy the same storage
space.

var r: record

a: integer;

b: char

end;

Gives a single variable with two completely different components, which can
be accessed independently, or used as a unit.

var vr: record

a: integer;

case b: boolean of { variant }

true: (c: integer; d: char);

false: (e: real)

{ end }

end;

Variant records allow the same "collection of types", but introduce
the idea that not all of the components are in use at the same time, and thus
can occupy the same storage area. In the above definition, a, b, c, d, and e
are all elements of the record, and can be addressed individually. However,
there are three basic "types" of record elements in play:

1. "base" or normal fixed record elements, such as a.

2. The "tagfield" element. Such as b.

3. The "variants", such as c, d, and e.

All the elements before the case variant are normal record elements and are
always present in the record. The tagfield is also always present, but has special
function with regards to the variant. It must be an ordinal type, and ALL of
it's possible values must be accounted for by a corresponding variant. The tagfield
gives both the program and the compiler the chance to tell what the rest of
the record holds (ie., what case variant is "active"). The tagfield
can also be omitted optionally:

var vr: record

a: integer;

case boolean of { variant }

true: (c: integer; d: char);

false: (e: real)

{ end }

end;

In this case, the variant can be anything the program says it is, without
checking. The variants introduce what essentially is a "sub record"
definition that gives the record elements that are only present if the selecting
variant is "active". A variant can hold any number of such elements.
If the compiler chooses to implement variants, the total size of the resulting
record will be no larger than the fixed record parts plus the size of the largest
variant. It is possible for the compiler to treat the variant as a normal record,
allocating each record element normally, in which case the variant record
would be no different from a normal record.

Files are identical to arrays in that they store a number of identical components.
Files are different from arrays in that the number of components they may store
is not limited or fixed beforehand. The number of components in a file can change
during the run of a program. A file can have any type as a component type, with
the exception of other file types. This rule is strict: you may not even have
structures which contain files as components. A typical file declaration is:

var f: file of integer;

Would declare a file with standard integer components. A special predefined
file type exists:

var f: text;

Text files are supposedly equivalent to:

type text = file of char;

But there are special procedures and functions that apply to text files only.

Pointers are indirect references to variables that are created at runtime:

var ip: ^integer;

Pointers are neither basic or structured types (they are not structured because
they do not have multiple components). Any type can be pointed to. In practice,
pointers allow you to create a series of unnamed components which can be arranged
in various ways. The type declaration for pointers is special in that the type
specified to the right of "^" must be a type name, not a full
type specification. Pointer declarations are also special in that a pointer
type can be declared using base types that have not been declared yet:

type rp: ^rec;

rec: record

next: rp;

val: integer

end;

The declaration for rp contains a reference to an undeclared type, rec. This
"forward referencing" of pointers allows recursive definition of pointer
types, essential in list processing.

[set] - Set constant. A set constant consists of zero or more elements

separated by ",":

[1, 2, 3]

A range of elements can also appear:

[1, 2..5, 10]

The elements of a set must be of the same type, and the

"apparent" base type of the set is the type of the elements.

The packed or unpacked status of the set is whatever is

required for the context where it appears.

ident - Identifier. Can be a variable or constant from a const

declaration.

func(x, y) - A function call. Each parameter is evaluated, and the

function called. The result of the function is then used

in the encompassing expression.

The basic construct built on these operands is a "variable access",
where "a" is any variable access.

ident - A variable indentifier.

a[index] - Array access. It is also possible to access any number of

dimensions by listing multiple indexes separated by ",":

[x, y, z, ...]

a.off - Record access. The "off" will be the element identifier as

used in the record declaration.

a^ - Pointer reference. The resulting reference will be of the

variable that the pointer indexes. If the variable reference

is a file, the result is a reference to the "buffer variable"

for the file.

Note that a VAR parameter only allows a variable reference, not a full expression.
For the rest of the expression operators, here they are in precedence, with
the operators appearing in groups according to priority (highest first). "a"
and "b" are operands.

(a) - A subexpresion.

not - The boolean "not" of the operand, which must be boolean.

a*b - Multiplication/set intersection. If the operands are real or

integer, the multiplication is found. If either operand is

real, the result is real. If the operands are sets, the

intersection is found, or a new set with elements that exist

in both sets.

a/b - Divide. The operands are real or integer. The result is a real

representing a divided by b.

a div b - Integer divide. The operands must be integer. The result is an

integer giving a divided by b with no fractional part.

a mod b - Integer modulo. The operands must be integer. The result is an

integer giving the modulo of a divided by b.

a and b - Boolean "and". Both operands must be boolean. The result is a

boolean, giving the "and" of the operands.

+a - Identity. The operand is real or integer. The result is the

same type as the operand, and gives the same sign result as the

operand (essentially a no-op).

-a - Negation. The operand is real or integer. The result is the

same type as the operand, and gives the negation of the

operand.

a+b - Add/set union. If the operands are real or integer, finds the

sum of the operands. If either operand is real, the result is

real. If both operands are sets, finds a new set which contains

the elements of both.

a-b - Subtract/set difference. If the operands are real or integer,

finds a minus b. If either operand is real, the result is

real. If both operands are sets, finds a new set which contains

the elements of a that are not also elements of b.

a or b - Boolean "or". Both operands must be boolean. The result is

boolean, giving the boolean "or" of the operands.

a < b - Finds if a is less than b, and returns a boolean result.

The operands can be basic or string types.

a > b - Finds if a is greater than b, and returns a boolean result.

The operands can be basic or string types.

a <= b - Finds if a is less than or equal to b, and returns a boolean

result. The operands can be basic, string, set or pointer

types.

a >= b - Finds if a is greater than or equal to b, and returns a boolean

result. The operands can be basic, string, set or pointer

types.

a = b - Finds if a is equal to b, and returns a boolean result.

The operands can be basic, string, set or pointer types.

a <> b - Finds if a is not equal to b, and returns a boolean result.

The operands can be basic, string, set or pointer types.

a in b - Set inclusion. A is an ordinal, b is a set with the same base

There is a special operator for assignment, ":=" (or "becomes").
Only a single variable reference may appear to the right, and any expression
may appear to the left. The operands must be assignment compatible, as defined
above.

In Pascal, only boolean type expressions may appear for the condition (not
integers). The if statement specifies a single statement to be executed if the
condition is true, and an optional statement if the condition is false. You
must beware of the "bonding problem" if you create multiple nested
if statements:

if a = 1 then if b = 2 then writeln('a = 1, b = 2')

else writeln('a <> 1');

Here the else clause is attached to the very last statement that appeared,
which may not be the one we want.

The for statement executes the target statement as long as the "control
variable" lies within the set range of lower..upper. It may not execute
at all if lower > upper. The control variable in a for is special, and it
must obey several rules:

1. It must be ordinal.

2. It must be local to the present block (declared in the present block).

3. It must not be "threatened" in the executed statement. To threaten
means to modify, or give the potential to modify, as in passing as a VAR parameter
to a procedure or function (see below).

The case statement defines an action to be executed on each of the values
of an ordinal:

case x of

c1: statement;

c2: statement;

...

end;

The "selector" is an expression that must result in an ordinal
type. Each of the "case labels" must be type compatible with the selector.
The case statement will execute one, and only one, statement that matches
the current selector value. If the selector matches none of the cases, then
an error results. It is NOT possible to assume that execution simply continues
if none of the cases are matched. A case label MUST match the value of the selector.

2. A goto cannot jump into any one of the structured statements above (if,
while, repeat, for or case statements).

3. If the target of the goto is in another procedure or function, that
target label must be in the "outer level" of the procedure or function.
That means that it may not appear inside any structured statement at all.

A statement block gives the ability to make any number of statements appear
as one:

begin statement [; statement]... end

All of the above statements control only one statement at a time, with the
exception of repeat. The compound statement allows the inclusion of a whole
substructure to be controlled by those statements.

When you need to use a block of the same statements several times, a compound
block can be turned into a procedure or function and given a name:

procedure x;

begin

...

end;

function y: integer;

begin

...

end;

Then, the block of statements can be called from anywhere:

var i: integer;

x; { calls the procedure }

i := y; { calls the function }

The difference between a procedure and a function is that a function returns
a result, which can only be a basic or pointer type (not structured). This makes
it possible to use a function in an expression. In a function, the result is
returned by a special form of the assign statement:

function y: integer;

begin

...

y := 1 { set function return }

end;

The assignment is special because only the name of the function appears on
the left hand side of ":=". It does not matter where the function
return assignment appears in the function, and it is even possible to have multiple
assignments to the function, but AT LEAST one such assignment must be executed
before the function ends. If the procedure or function uses parameters, they
are declared as:

procedure x(one: integer; two, three: char);

begin

...

end;

The declaration of a parameter is special in that only a type name may be
specified, not a full type specification. Once appearing in the procedure or
function header, parameters can be treated as variables that just happen to
have been initialized to the value passed to the procedure or function. The
modification of parameters has no effect on the original parameters themselves.
Any expression that is assignment compatible with the parameter declaration
can be used in place of the parameter during it's call:

x(x*3, 'a', succ('a'));

If it is desired that the original parameter be modified, then a special
form of parameter declaration is used:

procedure x(var y: integer);

begin

y := 1

end;

Declaring y as a VAR parameter means that y will stand for the original parameter,
including taking on any values given it:

var q: integer;

...

x(q);

Would change q to have the value 1. In order to be compatible with a VAR
the passed parameter must be of identical type as the parameter declaration,
and be a variable reference. Finally, Pascal provides a special mode of parameter
known as a procedure or function parameter which passes a reference to a given
procedure or function:

procedure x(procedure y(x, q: integer));

...

procedure z(function y: integer);

...

To declare a procedure or function parameter, you must give it's full parameter
list, including a function result if it is a function. A procedure or function
is passed to a procedure or function by just it's name:

procedure r(a, b: integer);

begin

...

end;

begin

x(r); { pass procedure r to procedure x }

...

The parameter list for the procedure or function passed must be "congruent"
with the declared procedure or function parameter declaration. This means that
all it's parameters, and all of the parameters of it's procedure or function
parameters, etc., must match the declared parameter. Once the procedure or function
has been passed, it is then ok for the procedure or function that accepts it
to use it:

procedure x(procedure y(x, q: integer));

begin

y(1, 2);

...

Would call r with parameters 1 and 2.

Procedures and functions can be declared in advance of the actual appearance
of the procedure or function block using the forward keyword:

procedure x(a, b: integer); forward;

procedure y;

begin

x(1, 2)

...

end;

procedure x;

begin

...

The forward keyword replaces the appearance of the block in the first appearance
of the declaration. In the second appearance, only the name of the procedure
appears, not it's header parameters. Then the block appears as normal. The advance
declaration allows recursive structuring of procedure and function calls that
would be otherwise not be possible.

A file is not accessed directly (as an array is). Instead, Pascal automatically
declares one component of the files base type which is accessed by special syntax:

f^

So that:

f^ := 1;

Assigns to the file "buffer" component, and:

v := f^;

Reads the file buffer. Unless the file is empty or you are at the end of
the file, the file buffer component will contain the contents of the component
at the file location you are currently reading or writing. Other than that,
the file buffer behaves as an ordinary variable, and can even be passed as a
parameter to routines. The way to actually read or write through a file is by
using the predeclared procedures:

get(f);

Loads the buffer variable with the next element in the file, and advances
the file position by one element, and:

put(f);

Outputs the contents of the buffer variable to the file and advances the
file position by one. These two procedures are really all you need to implement
full reading and writing on a file. It also has the advantage of keeping the
next component in the file as a "lookahead" mechanism. However, it
is much more common to access files via the predefined procedures read and write:

read(f, x);

Is equivalent to:

x := f^; get(f);

And:

write(f, x);

Is equivalent to:

f^ := x; put(f);

Read and write are special in that any number of parameters can appear:

read(f, x, y, z, ...);

write(f, x, y, z, ...);

The parameters to read must be variable references. The parameters to write
can be expressions of matching type, except for the file parameter (files must
always be VAR references). Writing to a file is special in that you cannot write
to a file unless you are at the end of the file. That is, you may only append
new elements to the end of the file, not modify existing components of the file.

Files are said to exist in three "states":

1. Inactive.

2. Read.

3. Write.

All files begin life in the inactive state. For a file to be read from, it
must be placed into the read state. For a file to be written, it must be placed
in the write state. The reset and rewrite procedures do this:

reset(f);

Places the buffer variable at the 1st element of the file (if it exists),
and sets the file mode to "read".

rewrite(f);

Clears any previous contents of the file, and places the buffer variable
at the start of the file. The file mode is set to "write". A file
can be tested for only one kind of position, that is if it has reached the end:

eof(f);

Is a function that returns true if the end of the file has been reached.
eof must be true before the file can be written.

As alluded to before, text files are treated specially under Pascal. First,
The ends of lines are treated specially. If the end of a line is reached, a
read call will just return a space. A special function is required to determine
if the end of the line has been reached:

eoln(f);

Returns true if the current file position is at the end of a line. Pascal
strictly enforces the following structure to text files:

line 1<eoln>

line 2<eoln>

...

line N<eoln>

<eof>

There will always be an eoln terminating each line. If the file being read
does not have an eoln on the last line, it will be added automatically. Besides
the standard read and write calls, two procedures are special to text files:

readln(f...);

writeln(f...);

Readln behaves as a normal read, but after all the items in the list are
read, The rest of the line is skipped until eoln is encountered. Writeln behaves
as a normal write, but after all the items in the list are written, an eoln
is appended to the output. Text files can be treated as simple files of characters,
but it is also possible to read and write other types to a text file. Integers
and reals can be read from a text file, and integers, reals, booleans,
and strings can be written to text files. These types are written or read from
the file by converting them to or from a character based format. The format
for integers on read must be:

[+/-]digit[digit]...

Examples:

9

+56

-19384

The format for reals on read is:

[+/-]digit[digit]...[.digit[digit]...][e[+/-]digit[digit]...]

Examples:

-1

-356.44

7e9

+22.343e-22

All blanks are skipped before reading the number. Since eolns are defined
as blanks, this means that even eoln is skipped to find the number. This can
lead to an interesting situation when a number is read from the console. If
the user presses return without entering a number (on most systems), nothing
will happen until a number is entered, no matter how many times return is hit!

Write parameters to textfiles are of the format:

write(x[:field[:fraction]]);

The field states the number of character positions that you expect the object
to occupy. The fraction is special to reals. The output format that occurs in
each case are:

integer: The default field for integers is implementation defined, but is
usually the number of digits in maxint, plus a position for the sign. If a field
is specified, and is larger than the number of positions required to output
the number and sign, then blanks are added to the left side of the output until
the total size equals the field width. If the field width is less than the required
positions, the field width is ignored.

real: The default field for reals is implementation defined. There are two
different format modes depending on whether the fraction parameter appears.

If there is no fraction, the format is:

-0.0000000e+000

Starting from the left, the sign is either a "-" sign if the number
is negative, or blank if the number is positive or zero. Then the first digit
of the number, then the decimal point, then the fraction of the number, then
either 'e' or 'E' (the case is implementation defined), then the sign of the
exponent, then the digits of the exponent. The number of digits in the exponent
are implementation defined, as are the number of digits in a fraction if no
field width is defined. If the field width appears, and it is larger than the
total number of required positions in the number (all the characters in the
above format without the fraction digits), then the fraction is expanded until
the entire number fills the specified field, using right hand zeros if required.
Otherwise, the minimum required positions are always printed.

If a fraction appears (which means the field must also appear), the format
used is:

[-]00...00.000..00

The number is converted to it's whole number equivalent, and all the of whole
number portion of the number printed, regardless of the field size, proceeded
by "-" if the number is negative. Then, a decimal point appears, followed
by the number of fractional digits specified in the fraction parameter. If the
field is greater then the number of required positions and specified fraction
digits, then leading spaces are appended until the total size equals the field
width. The minimum positions and the specified fractional digits are always
printed.

The header files feature was originally designed to be the interface of Pascal
to the external files system, and as such is implementation by definition. It
is also (unfortunately) ignored in most implementations. The header files appear
as a simple list of identifiers in the program header:

program test(input, output, source, object);

Each header file automatically assumes the type text. If the file needs to
be another type, it should be declared again in the variables section of the
program block:

program test(intlist);

var intlist: file of integer;

Two files are special, and should not be redeclared. These are input and
output. The input files are understood to represent the main input and main
output from the program, and are present in all Pascal programs. In addition,
they are the default files is special forms of these procedures and functions:

Because arrays are incompatible with each other even when they are of the
same type if their packing status differs, two procedures allow a packed array
to be copied to a non-packed array and vice versa:

unpack(PackedArray, UnpackedArray, Index);

Unpacks the packed array and places the contents into the unpacked array.
The index gives the starting index of the unpacked array where the data is to
be placed. Interestingly, the two arrays need not have the same index type or
even be the same size ! The unpacked array must simply have enough elements
after the specified starting index to hold the number of elements in the packed
array.

pack(UnpackedArray, Index, PackedArray);

Packs part of the unpacked array into the packed array. The index again gives
the starting position to copy data from in the unpacked array. Again, the arrays
need not be of the same index type or size. The unpacked array simply need enough
elements after the index to provide all the values in the packed array.

In Pascal, pointer variables are limited to the mode of variable they can
index. The objects indexed by pointer types are anonymous, and created or destroyed
by the programmer at will. A pointer variable is undefined when it is first
used, and it is an error to access the variable it points to unless that variable
has been created:

var p: ^integer;

...

new(p); { create a new integer type }

p^ := 1; { place value }

Would create a new variable. Variables can also be destroyed:

dispose(p);

Would release the storage allocated to the variable. It is an error (a very
serious one) to access the contents of a variable that has been disposed. A
special syntax exists for the allocation of variant records:

var r: record

a: integer;

case b: boolean
of

true:
(c: integer);

false:
(d: char)

{ end }

end;

...

new(p, true);

...

dispose(p, true);

For each of new and dispose, each of the tagfields we want to discriminate
are parameters to the procedure. The appearance of the tagfield values allow
the compiler to allocate a variable with only the amount of space required for
the record with that variant. This can allow considerable storage savings if
used correctly. The appearance of a discriminant in a new procedure does not
also automatically SET the value of the tagfield. You must do that yourself.
For the entire life of the variable, you must not set the tagfield to any other
value than the value used in the new procedure, nor access any of the variants
in the record that are not active. The dispose statement should be called with
the exact same tagfield values and number. Note that ALL the tagfields in a
variable need not appear, just all the ones, in order, that we wish to allocate
as fixed.