I Language
Reference Manual
1 Elements of the language
1.1 Alphabet
1.1.1
Extended alphabet
1.2 Reserved words
1.3 Comments
1.4 Identifiers
1.5 Literals
1.5.1
Integer numbers
1.5.2
Real numbers
1.5.3
Character strings
2 Declarations
2.1 Constants
2.1.1
Array constants
2.1.2
Predeclared constants
2.2 Labels
2.3 Types
2.3.1
Simple types
2.3.2
Structured types
2.3.3
Dynamic types
2.4 File types
2.5 Variables
2.5.1
External Variables
2.5.2
Entire Variables
2.5.3
Indexed Variables
2.5.4
Indexed Ranges
2.5.5
Virtual array variables
2.5.6
Field Designators
2.5.7
Referenced Variables
2.6 Procedures and
Functions
3 Algorithms
3.1 Expressions
3.1.1
Mixed type expressions
3.1.2
Primary expressions
3.1.3
Unary expressions
3.1.4
Operator Reduction
3.1.5
Complex conversion
3.1.6
Conditional expressions
3.1.7
Factor
3.1.8
Multiplicative expressions
3.1.9
Additive expressions
3.1.10
Expressions
3.1.11
Operator overloading
3.2 Statements
3.2.1
Assignment
3.2.2
Procedure statement
3.2.3
Goto statement
3.2.4
Exit Statement
3.2.5
Compound statement
3.2.6
If statement
3.2.7
Case statement
3.2.8
With statement
3.2.9
For statement
3.2.10
While statement
3.2.11
Repeat statement
3.3 Input Output
3.3.1
Input
3.3.2
Output
3.3.3
Generic array output
3.3.4
Parameter formating
4 Programs and Units
4.1 The export of
identifiers from units
4.1.1
The export of procedures from libraries.
4.1.2
The export of Operators from units
4.2 Unit parameterisation
and generic functions
4.3 The invocation of
programs and units
4.4 The compilation of
programs and units.
4.4.1
Linking to external libraries
4.5 Instantiation of
parametric units
4.5.1
Direct instantiation
4.5.2
Indirect instantiation
4.6 The System Unit
5 Implementation issues
5.1 Invoking the compiler
5.1.1
Environment variable
5.1.2
Compiler options
5.1.3
Dependencies
5.2 Calling conventions
5.3 Array representation
5.4 Directives
5.4.1
Range checking
5.4.2
Linking to external libraries
5.4.3
Modular arithmetic
5.4.4
Include files
5.4.5
Ifdef
6 Compiler porting tools
6.1 Dependencies
6.2 Compiler Structure
6.2.1
Vectorisation
6.2.2
Porting strategy
6.3 ILCG
6.4 Supported types
6.4.1
Data formats
6.4.2
Typed formats
6.4.3
Ref types
6.5 Supported operations
6.5.1
Type casts
6.5.2
Arithmetic
6.5.3
Memory
6.5.4
Assignment
6.5.5
Dereferencing
6.6 Machine description
6.6.1
Registers
6.6.2
Register sets
6.6.3
Register Arrays
6.6.4
Register Stacks
6.6.5
Instruction formats
6.7 Grammar of ILCG
6.8 ILCG grammar
6.8.1
Helpers
6.8.2
Tokens
6.8.3
Non terminal symbols
7 Sample Machine Descriptions
7.1 Basic 386 architecture
7.1.1
Declare types to correspond to internal ilcg types
7.1.2
compiler configuration flags
7.1.3
Register declarations
7.1.4
Register sets
7.1.5
Operator definition
7.1.6
Data formats
7.1.7
Choice of effective address
7.1.8
Formats for all memory addresses
7.1.9
Instruction patterns for the 386
7.2 The MMX instructionset
7.2.1
MMX registers and instructions
7.3 The 486 CPU
7.4 Pentium
7.4.1
Concrete representation
II VIPER
Ken Renfrew
8 Introduction to VIPER
8.1 Rationale
8.1.1
The Literate Programming Tool.
8.1.2
The Mathematical Syntax Converter.
8.2 A System Overview
8.3 Which VIPER to
download?
8.4 System dependencies
8.5 Installing Files
8.6 Setting up the compiler
9 VIPER User Guide
9.1 Setting Up the System
9.1.1
Setting System Dependencies
9.1.2
Personal Setup
9.1.3
Dynamic Compiler Options
9.1.4
VIPER Option Buttons
9.2 Moving VIPER
9.3 Programming with VIPER
9.3.1
Single Files
9.3.2
Projects
9.3.3
Embedding L^{A}T_{E}X
in Vector Pascal
9.4 Compiling Files in
VIPER
9.4.1
Compiling Single Files
9.4.2
Compiling Projects
9.5 Running Programs in
VIPER
9.6 Making VP TEX
9.6.1
VP TEX Options
9.6.2
VPMath
9.7 L^{A}T_{E}X in VIPER
9.8 HTML in VIPER
9.9 Writing Code to
Generate Good VP TEX
9.9.1
Use of Special Comments
9.9.2
Use of Margin Comments
9.9.3
Use of Ordinary Pascal Comments
9.9.4
Levels of Detail within Documentation
9.9.5
Mathematical Translation: Motivation and Guidelines
9.9.6
LaTeX Packages
Index
Vector Pascal is a dialect
of Pascal designed to make efficient use of the multimedia instructionsets of
recent procesors. It supports data parallel operations and saturated
arithmetic. This manual describes the Vector Pascal language.
A number of widely used
contemporary processors have instructionset extensions for improved performance
in multimedia applications. The aim is to allow operations to proceed on
multiple pixels each clock cycle. Such instructionsets have been incorporated
both in specialist DSP chips like the Texas C62xx[35]
and in general purpose CPU chips like the Intel IA32[14]
or the AMD K6 [2].
These instructionset
extensions are typically based on the Single Instructionstream Multiple
Datastream (SIMD ) model in which a single instruction causes
the same mathematical operation to be carried out on several operands, or pairs
of operands at the same time. The level or parallelism supported ranges from 2
floating point operations at a time on the AMD K 6 architecture to 16 byte operations at a time on the intel P4
architecture. Whilst processor architectures are moving towards greater levels
of parallelism, the most widely used programming languages like C ,
Java and
Vector Pascal aims to provide an efficient and concise notation for
programmers using MultiMedia enhanced CPUs. In doing so it borrows concepts
for expressing data parallelism that have a long history, dating back to
Iverson's work on APL in the early '60s[17].
Define a vector of type T as having type T[] . Then if we have a binary operator
X:(T , T)® T
, in languages derived from APL we automatically have an operator X:(T[] ,T[]) ® T[] . Thus if x,y are arrays of
integers k=x+y is the array of integers where k_{i}=x_{i}+y_{i}
.
The basic concept is simple, there are complications to do with the
semantics of operations between arrays of different lengths and different
dimensions, but Iverson provides a consistent treatment of these. The most
recent languages to be built round this model are J , an
interpretive language[19][5][20], and F[28] a modernised Fortran . In principle though any language with array types can be
extended in a similar way. Iverson's approach to data parallelism is machine
independent. It can be implemented using scalar instructions or using the SIMD
model. The only difference is speed.
Vector Pascal incorporates Iverson's approach to data parallelism. Its
aim is to provide a notation that allows the natural and elegant expression of
data parallel algorithms within a base language that is already familiar to a
considerable body of programmers and combine this with modern compilation
techniques.
By an elegant algorithm I mean one which is expressed as concisely as
possible. Elegance is a goal that one approaches asymptotically, approaching
but never attaining[7]. APL and J allow the construction
of very elegant programs, but at a cost. An inevitable consequence of elegance
is the loss of redundancy. APL programs are as concise, or even more concise
than conventional mathematical notation[18] and use a special characterset.
This makes them hard for the uninitiated to understand. J attempts to remedy
this by restricting itself to the ASCII characterset, but still looks
dauntingly unfamiliar to programmers brought up on more conventional languages.
Both APL and J are interpretive which makes them ill suited to many of the
applications for which SIMD speed is required. The aim of Vector Pascal is to
provide the conceptual gains of Iverson's notation within a framework familiar
to imperative programmers.
Pascal [21]was chosen as a base language over
the alternatives of C and Java. C was rejected because notations like x+y for x and y declared as int x[4], y[4], already have the meaning of adding
the addresses of the arrays together. Java was rejected because of the
difficulty of efficiently transmitting data parallel operations via its
intermediate code to a just in time code generator.
Iverson's approach to data parallelism is machine independent. It can be
implemented using scalar instructions or using the SIMD model. The only difference is speed.
Vector Pascal incorporates Iverson's approach to data parallelism.
The Vector
Pascal compiler accepts files in the UTF8 encoding of Unicode as source. Since
ASCII is a subset of this, ASCII files are valid input.
Vector Pascal programs are
made up of letter, digits and special symbols. The letters digits and special
symbols are draw either from a base character set or from an extended character
set. The base character set is drawn from ASCII and restricts the letters to be
from the Latin alphabet. The extended character set allows letters from other
alphabets.
The special symbols used in
the base alphabet are shown in table1.1 .
+ 
: 
( 
 
' 
) 
* 
= 
[ 
/ 
<> 
] 
:= 
< 
{ 
. 
<= 
} 
, 
>= 

; 
> 
.. 
+: 
@ 
*) 
: 
$ 
(* 
_ 
** 

The
extended alphabet is described in Using Unicode with
Vector Pascal.
ABS,
ADDR, AND, ARRAY,
BEGIN,
BYTE2PIXEL,
CASE,
CAST, CDECL, CHR, CONST,
DISPOSE,
DIV, DO, DOWNTO,
END,
ELSE, EXIT, EXTERNAL,
FALSE,
FILE, FOR, FUNCTION,
GOTO,
IF,
IMPLEMENTATION, IN, INTERFACE, IOTA,
LABEL,
LIBRARY, LN,
MAX,
MIN, MOD,
NAME,
NDX, NEW, NOT,
OF,
OR, ORD, OTHERWISE,
PACKED,
PROCEDURE,
PROGRAM, PROTECTED ,
RDU,
READ, READLN, RECORD, REPEAT, ROUND,
SET,
SHL, SHR, SIN, SIZEOF, STRING, SQRT, SUCC,
TAN,
THEN, TO, TRANS, TRUE, TYPE,
VAR,
WITH,
WHILE, WRITE, WRITELN, UNIT, UNTIL, USES
Reserved words may be
written in either lower case or upper case letters, or any combination of the
two.
{ < any sequence
of characters not containing ``}'' > }
may be inserted between any
two identifiers, special symbols, numbers or reserved words without altering
the semantics or syntactic correctness of the program. The bracketing pair (* *) may substitute
for {
}. Where a comment
starts with { it
continues until the next }. Where it starts with (* it must be terminated by *)^{1}.
Identifiers are used to
name values, storage locations, programs, program modules, types, procedures and
functions. An identifier starts with a letter followed
by zero or more letters, digits or the special symbol _. Case is not significant in
identifiers. ISO Pascal allows the Latin letters AZ to be used in identifiers.
Vector Pascal extends this by allowing symbols from the Greek, Cyrillic,
Katakana and Hiragana, or CJK character sets
Integer numbers are formed
of a sequence of decimal digits, thus 1, 23, 9976 etc, or as hexadecimal numbers,
or as numbers of any base between 2 and 36. A hexadecimal number takes the form
of a $ followed
by a sequence of hexadecimal digits thus $01, $3ff, $5A. The letters in a hexadecimal
number may be upper or lower case and drawn from the range a..f or A..F.
A based integer is written with the base first followed by a # character
and then a sequence of letters or digits. Thus 2#1101 is a binary number 8#67 an octal number
and 20#7i a base 20 number.
The default precision for
integers is 32 bits^{2}.
<digit
sequence> 
<digit> + 
<decimal
integer> 
<digit
sequence> 
<hex integer> 
`$'<hexdigit>+ 
<based
integer> 
<digit
sequence>'#'<alphanumeric>+ 
<unsigned
integer> 
<decimal
integer> 

<hex integer> 

<based
integer> 
Table 1.2: The hexadecimal digits of
Vector Pascal.
Value 
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
Notation 1 
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
A 
B 
C 
D 
E 
F 
Notation 2 










a 
b 
c 
d 
e 
f 
.
Real numbers are supported
in floating point notation, thus 14.7, 9.99e5, 38E3, 3.6e4 are all valid denotations for real numbers. The default precision for real numbers is also 32
bit, though intermediate calculations may use higher precision. The choice of
32 bits as the default precision is influenced by the fact that 32 bit floating
point vector operations are well supported in multimedia instructions.
<exp> 
`e' 

`E' 
<scale
factor> 
[<sign>]
<unsigned integer> 
<sign> 
`' 

`+' 
<unsigned
real> 
<decimal
integer> `.' <digit sequence> 

<decimal
integer>` .' <digit sequence> <exp><scale factor> 

<decimal integer><exp>
<scale factor> 
In Vector Pascal pixels are represented as signed fixed point fractions in the range
1.0 to 1.0. Within this range, fixed point literals have the same syntactic
form as real numbers.
Sequences of characters
enclosed by quotes are called literal strings. Literal
strings consisting of a single character are constants of
the standard type char. If the string is to contain a quote character this
quote character must be written twice.
'A' 'x'
'hello' 'John''s house'
are all valid literal
strings. The allowable characters in literal strings are any of the Unicode
characters above u0020. The character strings must be input to the compiler in
UTF8 format.
Vector Pascal is a language
supporting nested declaration contexts. A declaration
context is either a program context, and unit interface or implementation
context, or a procedure or function context. A resolution context determines
the meaning of an identifier. Within a resolution context, identifiers can be
declared to stand for constants, types, variables, procedures or functions.
When an identifier is used, the meaning taken on by the identifier is that
given in the closest containing resolution context. Resolution contexts are any
declaration context or a with statement context. The ordering of these contexts when resolving an
identifier is:
1.
The
declaration context identified by any with statements which nest the current
occurrence of the identifier. These with statement contexts are searched
from the innermost to the outermost.
2.
The
declaration context of the currently nested procedure declarations.
These procedure contexts are searched from the innermost to the outermost.
3.
The
declaration context of the current unit or program .
4.
The
interface declaration contexts of the units mentioned in the use list of the
current unit or program. These contexts are searched from the rightmost unit
mentioned in the use list to the leftmost identifier in the use list.
5.
The
interface declaration context of the System unit.
6.
The
predeclared identifiers of the language.
A constant definition
introduces an identifier as a synonym for a constant.
<constant
declaration> 
<identifier>=<expression> 

<identifier>':'<type>'='<typed
constant> 
Constants
can be simple constants or typed constants. A simple constant must be a
constant expression whose value is known at compile time. This restricts it to
expressions for which all component identifiers are other constants, and for
which the permitted operators are given in table2.1 . This restricts simple constants to be of scalar or
string types.
Table 2.1: The operators permitted
in Vector Pascal constant expressions.
+ 
 
* 
/ 
div 
mod 
shr 
shl 
and 
or 
Typed constants provide the
program with initialised variables which may hold array types.
<typed
constant> 
<expression> 

<array
constant> 
Array constants are comma
separated lists of constant expressions enclosed by brackets. Thus
tr:array[1..3]
of real =(1.0,1.0,2.0);
is a valid array constant
declaration, as is:
t2:array[1..2,1..3]
of real=((1.0,2.0,4.0),(1.0,3.0,9.0));
The array constant must structurally match the
type given to the identifier. That is to say it must match
with respect to number of dimensions, length of each dimension, and type of the
array elements.
<array
constant> 
'(' <typed
constant> [,<typed constant>]* ')' 
The largest supported integer value.
A real numbered approximation to p
The highest character in the character set.
The maximum number of characters allowed in a
string.
The highest representable real.
The smallest representable positive real
number.
The smallest real number which when added to
1.0 yields a value distinguishable from 1.0.
The highest representable double precision real
number.
The smallest representable positive double
precision real number.
A complex number with zero real and imaginary
parts.
A complex number with real part 1 and imaginary
part 0.
Labels are written as digit
sequences. Labels must be declared before they are used. They can be used to
label the start of a statement and can be the destination of a goto
statement. A goto statement must have as its destination
a label declared within the current innermost declaration
context. A statement can be prefixed by a label followed by a colon.
Example
label
99;
begin
read(x); if x>9 goto 99; write(x*2);99: end;
A type declaration
determines the set of values that expressions of this type may assume and
associates with this set an identifier.
<type> 
<simple type> 

<structured
type> 

<pointer
type> 
<type
definition> 
<identifier>'='<type>

Simple types are either
scalar, standard, subrange or dimensioned types.
<simple type> 
<scalar type> 

<integral
type> 

<subrange
type> 

<dimensioned
type> 

<floating point
type> 
A scalar
type defines an ordered
set of identifier by listing these identifiers. The declaration takes the form
of a comma separated list of identifiers enclosed by brackets. The identifiers
in the list are declared simultaneously with the declared scalar type to be constants
of this declared scalar type. Thus
colour = (red,green,blue);
day=(monday,tuesday,wednesday,thursday,
friday,saturday,sunday);
are valid scalar type declarations.
The
following types are provided as standard in Vector Pascal:
Table
2.2: Categorisation of the standard types.
type 
category 


real 
floating
point 
double 
floating
point 
byte 
integral 
pixel 
fixed point 
shortint 
integral 
word 
integral 
integer 
integral 
cardinal 
integral 
boolean 
scalar 
char 
scalar 
The
numbers are in the range maxint to +maxint.
These
are a subset of the reals constrained by the IEEE 32 bit floating point format.
These
are a subset of the real numbers constrained by the IEEE 64
bit floating point format.
These
are represented as fixed point binary fractions in the range 1.0 to 1.0.
These
take on the values (false ,true )
which are ordered such that true<false.
These
include the characters from chr(0)
to charmax . All the allowed characters for
string literals are in the type char, but the characterset may include other
characters whose printable form is country specific.
Defined
as char.
These
take on the positive integers between 0 and 255.
These
take on the signed values between 128 and 127.
These
take on the positive integers from 0 to 65535.
These
take on the positive integers form 0 to 4292967295, i.e., the most that can be
represented in a 32 bit unsigned number.
A
32 bit integer, retained for compatibility with Turbo Pascal.
A
64 bit integer.
A
complex number with the real and imaginary parts held to 32 bit precision.
A
type may be declared as a subrange of another scalar or
integer type by indicating the largest and
smallest value in the subrange. These values must be constants known at compile
time.
<subrange type> 
<constant> '..' <constant> 
Examples:
1..10, 'a'..'f', monday..thursday.
The
conceptual
model of pixels in Vector Pascal is that they are real numbers in
the range 1.0..1.0
. As a signed representation it lends itself to subtraction. As an unbiased representation,
it makes the adjustment of contrast easier. For example, one can reduce
contrast 50% simply by multiplying an image by 0.5 ^{3}. Assignment to pixel variables in
Vector Pascal is defined to be saturating  real numbers outside the range 1..1 are clipped to it. The
multiplications involved in convolution operations fall naturally into place.
The
implementation
model of pixels used in Vector Pascal is of 8 bit signed integers
treated as fixed point binary fractions. All the conversions necessary to
preserve the monotonicity of addition, the range of multiplication etc, are
delegated to the code generator which, where possible, will implement the
semantics using efficient, saturated multimedia arithmetic instructions.
These
provide a means by which floating point types can be specialised to represent
dimensioned numbers as is required in physics calculations. For example:
kms =(mass,distance,time);
meter=real of distance;
kilo=real of mass;
second=real of time;
newton=real of mass * distance * time POW 2;
meterpersecond = real of distance *time POW 1;
The
grammar is given by:
<dimensioned type> 
<real type> <dimension >['*'
<dimension>]* 
<real type> 
'real' 

'double' 
<dimension> 
<identifier> ['POW' [<sign>]
<unsigned integer>] 
The
identifier must be a member of a scalar type, and that
scalar type is then referred to as the basis space of the dimensioned type. The
identifiers of the basis space are referred to as the
dimensions of the dimensioned type . Associated with each dimension of a
dimensioned type there is an integer number referred to as the power of that
dimension. This is either introduced explicitly at type declaration time, or determined
implicitly for the dimensional type of expressions.
A
value of a dimensioned type is a dimensioned value. Let log_{d}t of a
dimensioned type t be the power to which the dimension d of type t is raised.
Thus for t = newton in the example above, and d = time, log_{d}t=2
If
x and y are values of dimensioned types t_{x}
and t_{y} respectively, then the following operators are only
permissible if t_{x}=t_{y}
+ 
 
< 
> 
<> 
= 
<= 
>= 
For
+ and , the dimensional type of the result is the
same as that of the arguments. The operations
* 
/ 
are
permitted if the types t_{x} and t_{y} share the same basis
space, or if the basis space of one of the types is a subrange of the basis
space of the other.
The
operation POW
is permitted between dimensioned types and integers.
* Dimension deduction rules
1. If x=y*z for x:t_{1},y:t_{2},z:t_{3}
with basis space B then

2.
If
x=y/z for x:t_{1},y:t_{2},z:t_{3} with basis space B
then

3.
If
x=y POW
z for x:t_{1},y:t_{2},z:integer with basis space for t_{2}
, B then

.
An array type is a structure
consisting of a fixed number of elements all of which are the same type. The
type of the elements is referred to as the element type. The elements of an
array value are indicated by bracketed indexing expressions. The definition of
an array type simultaneously defines the permitted type of indexing expression
and the element type.
The index type of
a static array must
be a scalar or subrange type. This implies that the bounds
of a static array are known at compile time.
<array
type> 
'array' '['
<index type>[,<index type>]* ']' 'of' <type> 
<index
type> 
<subrange
type> 

<scalar
type> 

<integral
type> 
Examples
array[colour] of
boolean;
array[1..100] of
integer;
array[1..2,4..6] of
byte;
array[1..2] of
array[4..6] of byte;
The notation [b,c] in an
array declaration is shorthand for the notation [b] of array [ c ]. The number of dimensions
of an array type is referred to as its rank. Scalar types have rank 0.
A string type
denotes the set of all sequences of characters up to some finite length and
must have the syntactic form:
<stringtype> 
'string['
<integer constant>']' 

'string' 

'string('
<ingeger constant>')' 
the integer constant indicates the
maximum number of characters that may be held in the string type. The maximum
number of characters that can be held in any string is indicated by the
predeclared constant maxstring. The type string is shorthand for string[maxstring].
A record type defines a set of
similar data structures. Each member of this set, a record instance, is a
Cartesian product of number of components or fields specified in the record type definition. Each field has an identifier and a type.
The scope of these identifiers is the record itself.
A record type may have as a final
component a variant part. The variant part, if a variant part
exists, is a union of several variants, each of which may itself be a Cartesian
product of a set of fields. If a variant part exists there may be a tag field
whose value indicates which variant is assumed by the record instance.
All field identifiers even if they
occur within different variant parts, must be unique within the record type.
<record
type> 
'record'
<field list> 'end' 
<field
list> 
<fixed
part> 

<fixed
part>';' <variant part> 

<variant
part> 
<fixed
part> 
<record
section> [ ';' <record section.]* 
<record
section> 
<identifier>[','
<identifier>]* ':' <type> 

<empty> 
<variant
part> 
'case'
[<tag field> ':'] <type identifier> 'of'<variant>[';'
<variant>]* 
<variant> 
<constant>
[',' <constant>]*':' '(' <field list> ')' 

<empty> 
A set type defines
the range of values which is the powerset of its base type. The base type must
be an ordered type, that is a type on which the operations < , = and >
are defined^{4}.
Thus sets may be declared whose base types are characters, numbers, ordinals,
or strings. Any user defined type on which the comparison operators have been
defined can also be the base type of a set.
<set
type> 
'set' 'of'
<base type> 
Variables
declared within the program are accessed by their identifier. These variables
exist throughout the existence of the scope within which they are declared, be
this unit, program or procedure. These variables are assigned storage locations
whose addresses, either absolute or relative to some register, can be
determined at compile time. Such locations a referred to as static ^{5}. Storage locations may also be
allocated dynamically. Given a type t,
the type of a pointer to an instance of type t
is t.
A
pointer of type t
can be initialised to point to a new store location of type t by use of the
built in procedure new.
Thus if p:t,
new(p);
causes
p
to point at a store location of type t.
The
types pointed to by pointer types can be any of the types mentioned so far,
that is to say, any of the types allowed for static variables. In addition
however, pointer types can be declared to point at dynamic arrays. A dynamic
array is an array whose bounds are determined at run time.
Pascal 90[15] introduced the notion of schematic
or parameterised types as a means of creating dynamic arrays. Thus where r is some integral or ordinal type
one can write
type
z(a,b:r)=array[a..b] of t;
If p:z, then
new(p,n,m)
where n,m:r initialises p to point to an array of bounds n..m. The bounds of the array can then
be accessed as p.a, p.b. Vector Pascal currently allows
dynamic but not static parameterised types.
A
type may be declared to be a file of a type. This form of definition is kept
only for backward compatibility. All file types are treated as being
equivalent. A file type corresponds to a handle to an operating system file. A
file variable must be associated with the operating system file by using the
procedures assign, rewrite,
append, and reset
provided by the system unit. A predeclared file type text exists.
Text
files are assumed to be in Unicode UTF8 format. Conversions are performed
between the internal representation of characters and UTF8 on input/output
from/to a text file.
Variable declarations consist of a
list of identifiers denoting the new variables, followed by their types.
<variable
declaration> 
<identifier>
[',' <identifier>]* ':' <type><extmod> 
Variables are abstractions over
values. They can be either simple identifiers, components or ranges of
components of arrays, fields of records or referenced dynamic variables.
<variable> 
<identifier> 

<indexed
variable> 

<indexed
range> 

<field
designator> 

<referenced
variable> 
Examples
x,y:real;
i:integer;
point:real;
dataset:array[1..n]of
integer;
twoDdata:array[1..n,4..7]
of real;
A variable may be declared to be
external by appending the external modifier.
<extmod> 
';'
'external' 'name' <stringlit> 
This indicates that the variable is
declared in a non Vector Pascal external library. The name by which the
variable is known in the external library is specified in a string literal.
Example
count:integer;
external name '_count';
An entire
variable is denoted by its identifier. Examples x,y,point,
A component of an n
dimensional array variable is denoted by the variable followed by n index
expressions in brackets.
<indexed
variable> 
<variable>'['
<expression>[','<expression>]* ']' 
The type of the indexing expression
must conform to the index type of the array variable. The type of the indexed
variable is the component type of the array.
Examples
twoDdata[2,6]
dataset[i]
Given the declaration
a=array[p] of q
then the elements of arrays of type a, will have type q and will be identified by indices of type p thus:
b[i]
where i:p, b:a.
Given the declaration
z = string[x]
for some integer x £ maxstring, then the characters within strings of type z will be identified by indices in
the range 1..x, thus:
y[j]
where y:z, j:1..x.
A range of components of an array
variable are denoted by the variable followed by a range expression in
brackets.
<indexed
range> 
<variable>
'[' <range expression>[',' <range expression>]* ']' 
<range
expression> 
<expression>
'..' <expression> 
The expressions within the range expression must conform to the index type of the array
variable. The type of a range expression a[i..j] where a: array[p..q] of t is array[0..ji] of t.
Examples:
dataset[i..i+2]:=blank;
twoDdata[2..3,5..6]:=twoDdata[4..5,11..12]*0.5;
Subranges may
be passed in as actual parameters to procedures whose corresponding formal
parameters are declared as variables of a schematic type. Hence given the following declarations:
type
image(miny,maxy,minx,maxx:integer)=array[miny..maxy,minx..maxx] of byte;
procedure
invert(var im:image);begin im:=255im; end;
var
screen:array[0..319,0..199] of byte;
then the following statement would
be valid:
invert(screen[40..60,20..30]);
If an array variable
occurs on the right hand side of an assignment statement, there is a further
form of indexing possible. An array may be indexed by another array. If x:array[t0] of t1 and y:array[t1] of t2, then y[x] denotes the virtual array of type array[t0] of t2 such that y[x][i]=y[x[i]]. This construct is useful for
performing permutations. To fully understand the following example refer to
sections 3.1.3,3.2.1.
Example
Given the declarations
const
perm:array[0..3] of integer=(3,1,2,0);
var
ma,m0:array[0..3] of integer;
then the statements
m0:= (iota 0)+1;
write('m0=');for
j:=0 to 3 do write(m0[j]);writeln;
ma:=m0[perm];
write('perm=');for
j:=0 to 3 do write(perm[j]);writeln;
writeln('ma:=m0[perm]');for
j:=0 to 3 do write(ma[j]);writeln;
would produce the output
m0= 1 2 3 4
perm= 3 1 2 0
ma:=m0[perm]
4 2 3 1
A component of an instance of a
record type, or the parameters of an instance of a schematic type are denoted
by the record or schematic type instance followed by the field or parameter
name.
<field
designator> 
<variable>'.'<identifier> 
If
p:t,
then p
denotes the dynamic variable of type t
referenced by p.
<referenced variable> 
<variable> '' 
Procedure
and function declarations allow algorithms to be identified by name and have
arguments associated with them so that they may be invoked by procedure
statements or function calls.
<procedure declaration> 
<procedure heading>';'[<proc
tail>] 
<proc tail> 
'forward' 
must be followed by definition of procedure
body 




'external' 
imports a non Pascal procedure 

<block> 
procedure implemented here 
<paramlist> 
'('<formal parameter
section>[';'<formal parameter section>]*')' 
<procedure heading> 
'procedure' <identifier>
[<paramlist>] 

'function'<identifier>
[<paramlist>]':'<type> 
<formal parameter section> 
['var']<identifier>[','<identifier>]':'<type> 
The
parameters declared in the procedure heading are local to the scope of the
procedure. The parameters in the procedure heading are termed formal parameters. If the identifiers in a formal
parameter section are preceded by the word var, then the formal parameters are
termed variable parameters. The block^{6} of a procedure or function
constitutes a scope local to its executable compound statement. Within a
function declaration there must be at least one statement assigning a value to
the function identifier. This assignment determines the result of a function,
but assignment to this identifier does not cause an immediate return from the
function.
Function
return values can be scalars, pointers, records, strings or sets. Arrays may
not be returned from a function.
Examples
The
function sba is the mirror image of the abs function.
function sba(i:integer):integer;
begin if i>o then sba:=i else sba:=i end;
type stack:array[0..100] of integer;
procedure push(var s:stack;i:integer);
begin s[s[0]]:=i;s[0]:=s[0]+1; end;
A
parameter declaration may be prefixed by the word PROTECTED.
ISO10206 
A
protected parameter may not be assigned to within the body of the function.
Protected parameters are useful for obtaining the semantic effect of a value
parameter where efficiency considerations lead an array to be passed as a var
parameter.
Standard
Pascal requires the types of parameters to be given by type names. Where arrays
are passed as parameters they must be of user defined array types. Vector
Pascal allows array types to be explicitly given in the parameter declarations.
An
expression is a rule for computing a value by the application of operators and
functions to other values. These operators can be monadic  taking a single
argument, or dyadic
 taking two arguments.
The
arithmetic operators are defined over the base types integer and real. If a
dyadic operator that can take either real or integer arguments is applied to
arguments one of which is an integer and the other a real, the integer argument
is first implicitly converted to a real before the operator is applied.
Similarly, if a dyadic operator is applied to two integral numbers of different
precision, the number of lower precision is initially converted to the higher
precisions, and the result is of the higher precision. Higher precision of
types t,u
is defined such that the type with the greater precision is the one which can
represent the largest range of numbers. Hence reals are taken to
be higher precision than longints even though the number of significant bits in
a real may be less than in a longint.
When
performing mixed type arithmetic between pixels and another numeric data type,
the values of both types are converted to reals before the arithmetic is
performed. If the result of such a mixed type expression is subsequently
assigned to a pixel variable, all values greater than 1.0 are
mapped to 1.0 and all values below 1.0 are mapped to 1.0.
<primary
expression> 
'('
<expression> ')' 

<literal
string> 

'true' 

'false' 

<unsigned
integer> 

<unsigned
real> 

<variable> 

<constant
id> 

<function
call> 

<set
construction> 
The most primitive expressions are
instances of the literals defined in the language: literal strings, boolean
literals, literal reals and literal integers. '
An expression surrounded by brackets
( ) is also a primary expression. Thus
if e
is an expression so is ( e ).
<function
call> 
<function
id> [ '(' <expression> [,<expression>]* ')' ] 
<element> 
<expression> 

<range
expression> 
Let e be an expression of type t_{1}
and if f is an identifier of type function ( t_{1} ): t_{2} , then f( e ) is a primary expression of type t_{2}
. A function which takes no parameters is invoked without following its
identifier by brackets. It will be an error if any of the actual parameters
supplied to a function are incompatible with the formal parameters declared for
the function.
<set
construction> 
'['
[<element>[,<element>]*] ']' 
Finally a primary expression may be
a set construction. A set construction is written as a sequence of zero or more
elements enclosed in brackets [ ] and separated by commas. The
elements themselves are either expressions evaluating to single values or range
expressions denoting a sequence of consecutive values. The type of a set
construction is deduced by the compiler from the context in which it occurs. A
set construction occurring on the right hand side of an assignment inherits the
type of the variable to which it is being assigned. The following are all valid
set constructions:
[], [1..9],
[z..j,9], [a,b,c,]
[] denotes the empty set.
A unary expression is formed by
applying a unary operator to another unary or primary expression. The unary
operators supported are +, , *, /, div , mod , and ,
or , not , round , sqrt , sin , cos , tan , abs , ln , ord , chr , byte2pixel , pixel2byte , succ ,
pred , iota , trans , addr and @
.
Thus
the following are valid unary expressions: 1,
+b, not true,
sqrt abs x,
sin theta. In
standard Pascal some of these operators are treated as functions,.
Syntactically this means that their arguments must be enclosed in brackets, as
in sin(theta).
This usage remains syntactically correct in Vector Pascal.
The
dyadic operators +, , *, /, div, ¸, ×, mod , and or
are all extended to unary context by the insertion of an implicit value under
the operation. Thus just as a = 0a
so too /2 = 1/2.
For sets the notation s
means the complement of the set s.
The implicit value inserted are given below.
type 
operators 
implicit
value 



number 
+, 
0 
string 
+ 
'' 
+ 
empty set 

number 
*,/ ,div,mod 
1 
number 
max 
lowest representable number of the type 
number 
min 
highest representable number of the type 
and 
true 

boolean 
or

false 
A
unary operator can be applied to an array argument and returns
an array result. Similarly any user declared function over a scalar type can be applied to an array type and return an
array. If f is a function or unary operator
mapping from type r to type t then if x is an array of r, and a an array of t, then a:=f(x) assigns an array of t such that a[i]=f(x[i])
rhs 
meaning 

<unaryop> 
'+' 
+x = 0+x identity
operator 

'' 
x = 0x, 


note: this is
defined on integer, real and complex 

'*', '×' 
*x=1*x identity
operator 

'/' 
/x=1.0/x 


note: this is
defined on integer, real and complex 

'div', '¸' 
div x =1 div x 

'mod' 
mod x = 1 mod x 

'and' 
and x = true and
x 

'or' 
or x = false or x 

'not', 'Ø' 
complements
booleans 

'round' 
rounds a real to
the closest integer 

'sqrt', 'Ö{} ' 
returns square
root as a real number. 

'sin' 
sine of its
argument. Argument in radians. Result is real. 

'cos' 
cosine of its
argument. Argument in radians. Result is real. 

'tan' 
tangent of its
argument. Argument in radians. Result is real. 

'abs' 
if x<0 then
abs x = x else abs x= x 

'ln' 
log_{e}
of its argument. Result is real. 

'ord' 
argument scalar
type, returns ordinal 


number of the
argument. 

'chr' 


'succ' 
argument scalar
type, 


returns the next
scalar in the type. 

'pred' 
argument scalar
type, 


returns the
previous scalar in the type. 

'iota', 'i' 


'trans' 


'pixel2byte' 
convert pixel in range
1.0..1.0 to byte in range 0..255 

'byte2pixel' 
convert a byte in
range 0..255 to a pixel in 


the range
1.0..1.0 

'@','addr' 
Given a variable,
this returns an 


<unary
expression> 
<unaryop>
<unary expression> 

'sizeof' '('
<type> ')' 

<operator
reduction> 

<primary
expression> 

'if'<expression>
'then' <expression> 'else' <expression> 
There is a pair of built in
operators succ and pred defined over every scalar type t
such that x = succ predx "x Î t and y = pred succy "y Î t.
Vector 
This definition of the successor and
predecessor functions differs from that given in the Pascal Standard which
defines succ as follows:
succ(x)
ISO7185 
The function shall yield a value
whose ordinal number is one greater than that of the expression x, if such a
value exists. It shall be an error if such a value does not exist. ^{7}
PROGRAM scalars;
TYPE day=( sunday, monday, tuesday, wednesday,
thursday, friday, saturday);
VAR today,tomorrow,day2:day;
BEGIN
today:= friday MAX saturday;
tomorrow := SUCC today;
day2:=SUCC(tommorrow,2);
write(today, tomorrow,today < friday, today=saturday);
END.
output generated:
saturday sunday false tuesday
Figure 3.1: Which presents a program
illustrating both the comparability of user defined scalar types and their
cyclical nature.
The
implication of these definitions are that in Vector Pascal the successor
function operates in a modulo fashion. As one steps through an scalar type with
the successor function one eventually gets back to the starting point. This is
illustrated in figure 3.1.
This modular operation of succ and pred can be switched off by using the
{$M} inline directive.
Vector Pascal follows ISO Extended
Pascal in allowing a second integer parameter to the functions as illustrated
in figure 3.1.
The construct sizeof ( t ) where t is a type, returns the number
of bytes occupied by an instance of the type.
The operator iota i returns the ith
current implicit index^{8}.
Examples
Thus given the definitions
var
v1:array[1..3]of integer;
v2:array[0..4] of
integer;
then the program fragment
v1:=iota 0;
v2:=iota 0 *2;
for i:=1 to 3 do
write( v1[i]); writeln;
writeln('v2');
for i:=0 to 4 do
write( v2[i]); writeln;
would produce the output
v1
1 2 3
v2
0 2 4 6 8
whilst given the definitions
m1:array[1..3,0..4]
of integer;m2:array[0..4,1..3]of integer;
then the program fragment
m2:= iota 0 +2*iota
1;
writeln('m2:= iota
0 +2*iota 1 ');
for i:=0 to 4 do
begin for j:=1 to 3 do write(m2[i,j]); writeln; end;
would produce the output
m2:= iota 0 +2*iota 1
2 4 6
3 5 7
4 6 8
5 7 9
6 8 10
The argument to iota must
be an integer known at compile time within the range of implicit indices in the
current context. The reserved word ndx is a synonym for iota.
perm
A
generalised permutation of the implicit indices is performed using the
syntactic form:
perm[indexsel[,indexsel]* ]expression
The
indexsels are integers known at compile time which specify a
permutation on the implicit indices. Thus in e evaluated in context perm[ i,j,k ] e ,
then:
iota 0 = iota i, iota 1= iota j, iota 2= iota k
This
is particularly useful in converting between different image formats. Hardware
frame buffers typically represent images with the pixels in the red, green,
blue, and alpha channels adjacent in memory. For image processing it is
convenient to hold them in distinct planes. The perm
operator provides a concise notation for translation between these formats:
type rowindex=0..479;
colindex=0..639;
var channel=red..alpha;
screen:array[rowindex,colindex,channel] of pixel;
img:array[channel,colindex,rowindex] of pixel;
...
screen:=perm[2,0,1]img;
trans and
diag provide shorthand notions for expressions in terms of perm
.
Thus in an assignment context of rank 2, trans = perm[1,0]
and diag = perm[0,0].
The
operator trans transposes a vector or matrix. It
achieves this by cyclic rotation of the implicit indices . Thus if trans e is evaluated in a context with
implicit indices
iota 0.. iota n
then the expression e is evaluated
in a context with implicit indices
iota'0.. iota'n
where
iota'x = iota ( (x+1)mod n+1)
It should be noted that
transposition is generalised to arrays of rank greater than 2.
Examples
Given the definitions used above in
section 3.1.3, the program fragment:
m1:= (trans v1)*v2;
writeln('(trans
v1)*v2');
writeln(m1);
m2 := trans m1;
writeln('transpose
1..3,0..4 matrix');
writeln(m2);
will produce the output:
(trans v1)*v2
0 2 4 6 8
0 4 8 12 16
0 6 12 18 24
transpose 1..3,0..4 matrix
0 0 0
2 4 6
4 8 12
6 12 18
8 16 24
Any dyadic operator can be converted
to a monadic reduction operator
by the functional . Thus if a is an array, +a denotes the sum over the array.
More generally \Fx for some dyadic operator F means x_{0}F(x_{1}F..(x_{n}Fi)) where i is the implicit value given the
operator and the type. Thus we can write + for summation, * for nary product etc. The dot
product of two vectors can thus be written as
x:= \+ y*x;
instead of
x:=0;
for i:=0 to n do
x:= x+ y[i]*z[i];
A reduction operation takes an
argument of rank r and returns an argument of rank r1 except
in the case where its argument is of rank 0, in which case it acts as the
identity operation. Reduction is always performed along the last array dimension of its argument.
The
operations of summation and product can be be written eithter as the two
functional forms \ + and \ * or as the prefix operators å
(Unicode 2211) and Õ
(Unicode 220f).
<operator reduction> 
''<dyadic op> <multiplicative expression> 

'å'
<mutliplicative expression> 

'Õ'
< multiplicative expression> 
<dyadic op> 
<expop> 

<multop> 

<addop> 
The
reserved word rdu is available as a lexical
alternative to , so + is equivalent to rdu+.
Complex numbers can be produced from reals using the function cmplx . cmplx(re,im) is
the complex number with real part re, and imaginaray part im.
The
real and imaginary parts of a complex number can be obtained by the functions re and
im. re(c) is the
real part of the complex number c. im(c) is the
imaginary part of the complex number c.
The
conditional expression allows two different values to be returned depenent upon
a boolean expression.
var a:array[0..63] of real;
...
a:=if a>0 then a else a;
...
The if
expression can be compiled in two ways:
1. Where the two arms of the if
expression are parallelisable, the condition and both arms are evaluated and
then merged under a boolean mask. Thus, the above assignment would be
equivalent to:
a:= (a and (a > 0))or(not (a > 0) and a);
were
the above legal Pascal^{9}.
2. If the code is not paralleliseable
it is translated as equivalent to a standard if statement. Thus, the previous
example would be equivalent to:
for i:=0 to 63 do if a[i] > 0 then a[i]:=a[i] else
a[i]:=a[i];
Expressions
are non parallelisable if they include function calls.
The
dual compilation strategy allows the same linguistic construct to be used in
recursive function definitions and parallel data selection.
In
array programming many operations can be efficiently be expressed in terms of
boolean mask vectors. Given the declarations:
const i:array[1..4] of integer=(2,4,6,8);
r:array[1..4] of real =(1.0,1.1,1.2,1.4);
b:array[1..4] of boolean=(true,false,true,false);
s:array[1..4] of string=('from','the','masters','of');
then
the boolean array b can
be used to mask the other arrays such that
write(i and b);
write(r and b);
write(s and b);
produces
2 0 6 0
1 0 1.2 0
from masters
Anding
a number or string with true leaves the number or string unchanged. Anding a
number of string with false returns the additive identity element : 0 or the
null string respectively.
A
factor is an expression that optionally performs exponentiation. Vector Pascal
supports exponentiation either by integer exponents or by real exponents. A
number x
can be raised to an integral power y by using the construction x pow y. A number can be raised to an arbitrary real
power by the **
operator. The result of ** is
always real valued.
<expop> 
'pow' 

'**' 
<factor> 
<unary expression> [ <expop> <unary
expression>] 
Multiplicative
expressions consist of factors linked by the multiplicative operators *, ×, /, div, ¸, , mod , shr , shl and . The use of these operators is
summarised in table 3.2.
Table
3.2: Multiplicative operators
Operator 
Left 
Right 
Result 
Effect of a
op b 
*, × 
integer 
integer 
integer 
multiply 

real 
real 
real 
multiply 

complex 
complex 
complex 
multiply 

string 
integer 
string 
replication: 'ab'*2 = 'abab' 
/ 
integer 
integer 
real 
division 

real 
real 
real 
division 

complex 
complex 
complex 
division 
div, ¸ 
integer 
integer 
integer 
division 
mod 
integer 
integer 
integer 
remainder 
and, Ú 
boolean 
boolean 
boolean 
logical and 
shr 
integer 
integer 
integer 
shift a by b bits right 
shl 
integer 
integer 
integer 
shift a by b bits left 
in, Î

t 
set of t 
boolean 
true if a is member of b 
<multop> 
'*' 

'×' 

'/' 

'div' 

'¸' 

'shr' 

'shl' 

'and' 

'Ú' 

'mod' 
<multiplicative
expression> 
<factor>
[ <multop> <factor> ]* 

<factor>'in'<multiplicative
expression> 
An additive expression allows
multiplicative expressions to be combined using the addition operators + ,
 , or, +: ,max , min , :
, >< .
The additive operations are summarised in table3.3 .
Table 3.3: Addition operations

Left 

Right 
Result 
Effect of
a op
b 






+ 
integer 

integer 
integer 
sum of a and b 

real 

real 
real 
sum of a and b 

complex 

complex 
complex 
sum of a and b 

set 

set 
set 
union of a and b 

string 

string 
string 

 
integer 

integer 
integer 
result of
subtracting b
from
a 

real 

real 
real 
result of
subtracting b
from
a 

complex 

complex 
complex 
result of
subtracting b
from
a 

set 

set 
set 

+: 
0..255 

0..255 
0..255 
saturated +
clipped to 0..255 

128..127 

128..127 
128..127 
saturated +
clipped to 128..127 
: 
0..255 

0..255 
0..255 


128..127 

128..127 
128..127 
saturated 
clipped to 128..127 
min 
integer 

integer 
integer 
returns the
lesser of the numbers 

real 

real 
real 
returns the
lesser of the numbers 
max 
integer 

integer 
integer 
returns the greater
of the numbers 

real 

real 
real 
returns the
greater of the numbers 
or, Ù 
boolean 

boolean 
boolean 
logical or 
>< 
set 

set 
set 
symetric
difference 
<addop> 
'+' 

'' 

'or' 

'Ù' 

'max' 

'min' 

'+:' 

':' 
<additive
expression> 
<multiplicative
expression> [ <addop> <multiplicative expression> ]* 
<expression> 
<additive
expression> <relational operator> <expression> 
An
expression can optionally involve the use of a relational operator to compare
the results of two additive expressions. Relational operators always return
boolean results and are listed in table 3.4.
Table 3.4: Relational operators
Less than 

> 
Greater than 
<=
, £

Less than or equal to 
>=
, ³

Greater than or equal to 
<>

Not equal to 
= 
Equal to 
The
dyadic operators can
be extended to operate on new types by operator overloading. Figure 3.2 shows how arithmetic on the type complex required by
Extended Pascal [15] is defined in Vector Pascal. Each
operator is associated with a semantic function and if it is a nonrelational
operator, an identity element. The operator symbols must be drawn from the set
of predefined Vector Pascal operators, and when expressions involving them are
parsed, priorities are inherited from the predefined operators. The type
signature of the operator is deduced from the type of the function^{10}.
<operatordeclaration> 
'operator' 'cast' '=' <identifier> 

'operator' <dyadicop> '='
<identifier>','<identifier> 

'operator' <relational operator> '='
<identifier> 
***¯***¯***¯***¯***¯***¯***¯***¯***¯***¯***¯***¯***¯
interface 
type 
Complex =
record data : array [0..1] of real ; 
\<
end ; 
\<
var 
complexzero,
complexone : complex; 
\<function real2cmplx ( realpart :real ):complex ;
\<function cmplx (
realpart ,imag :real ):complex ;
\<function
complex_add ( A ,B :Complex ):complex ;
\<function
complex_conjugate ( A :Complex ):complex ;
\<function complex_subtract
( A ,B :Complex ):complex ;
\<function
complex_multiply ( A ,B :Complex ):complex ;
\<function
complex_divide ( A ,B :Complex ):complex ;
{ Standard
operators on complex numbers } 
{ symbol
function identity element } 
operator +
= Complex_add , complexzero ; 
operator /
= complex_divide , complexone ; 
operator *
= complex_multiply , complexone ; 
operator 
= complex_subtract , complexzero ; 
operator
cast = real2cmplx ; 
Figure 3.2: Defining operations on
complex numbers
Note that only the function headers are given here as this code comes
from the interface part of the system unit. The function bodies and the
initialisation of the variables complexone and complexzero are handled in the
implementation part of the unit.
When parsing expressions, the
compiler first tries to resolve operations in terms of the predefined operators
of the language, taking into account the standard mechanisms allowing operators
to work on arrays. Only if these fail does it search for an overloaded operator
whose type signature matches the context.
In the example in figure 3.2, complex numbers are defined to be records containing
an array of reals, rather than simply as an array of reals. Had they been so
defined, the operators +,*,,/ on reals would have masked the corresponding operators on complex
numbers.
The provision of an identity element
for complex addition and subtraction ensures that unary minus, as in x for x: complex, is well defined,
and correspondingly that unary / denotes complex reciprocal. Overloaded
operators can be used in array maps and array reductions.
The Vector
Pascal language already contains a number of implicit type conversions that are
context determind. An example is the promotion of integers to reals in the
context of arithmetic expressions. The set of implicit casts can be added to by
declaring an operator to be a cast as is shown in the line:
operator cast = real2cmplx ; 
Given an implict cast from type t_{0}® t_{1}, the function associated with
the implicit cast is then called on the result of any expression e:t_{0}
whose expression context requires it to be of type t_{1}.
<statement> 
<variable>':='<expression> 

<variable>'¬'<expression> 

<procedure statement> 

<empty statement> 

'goto' <label>; 

'exit'['('<expression>')'] 

'begin' <statement>[;<statement>]*'end' 

'if'<expression>'then'<statement>['else'<statement>] 

<case statement> 

'for' <variable>':=' <expression> 'to'
<expression> 'do' <statement> 

'for' <variable>':=' <expression>
'downto' <expression> 'do' <statement> 

'for' <variable> 'in' <expression> 'do'
<statement> 

'for' <variable> ' Î ' <expression> 'do' <statement> 

'repeat' <statement> 'until'
<expression> 

'with' <record variable> 'do' <
statement> 

<io statement> 

'while' <expression> 'do' <statement> 
An assignment replaces the current
value of a variable by a new value specified by an expression. The assignment
operator is := .
Standard Pascal allows assignment of whole arrays . Vector Pascal extends this to allow consistent use of mixed
rank expressions on the
right hand side of an assignment. Given
r0:real;
r1:array[0..7] of real;
r2:array[0..7,0..7]
of real
then we can write
1.
r1:= r2[3]; {
supported in standard Pascal }
2.
r1:= /2; { assign 0.5 to each element of r1 }
3.
r2:= r1*3; { assign 1.5 to every element of r2}
4.
r1:= + r2; { r1 gets the totals along the rows of r2}
5.
r1:= r1+r2[1];{ r1 gets the corresponding elements of
row 1 of r2 added to it}
The assignment of arrays is a
generalisation of what standard Pascal allows. Consider the first examples
above, they are equivalent to:
1.
for i:=0 to 7 do r1[i]:=r2[3,i];
2.
for i:=0 to 7 do r1[i]:=/2;
3.
for i:=0 to 7 do
for j:=0 to 7 do r2[i,j]:=r1[j]*3;
4.
for i:=0 to 7 do
begin
t:=0;
for j:=7 downto 0 do t:=r2[i,j]+t;
r1[i]:=t;
end;
5.
for i:=0 to 7 do r1[i]:=r1[i]+r2[1,i];
In other words the compiler has to
generate an implicit loop over the elements of the array
being assigned to and over the elements of the array acting as the datasource.
In the above i,j,t are assumed to be temporary variables not referred to anywhere else in
the program. The loop variables are called implicit indices and may be
accessed using iota.
The variable on the left hand side
of an assignment defines an array context within which expressions
on the right hand side are evaluated. Each array context has a rank given by
the number of dimensions of the array on the left hand
side. A scalar variable has rank 0. Variables occurring in expressions with an
array context of rank r must have r or fewer dimensions. The n bounds of any n
dimensional array variable, with n £ r occurring within an expression evaluated in an array context of rank r must match
with the rightmost n bounds of the array on the left hand side of the
assignment statement.
Where a variable is of lower rank
than its array context, the variable is replicated to fill the array context . This is shown in examples 2 and 3 above. Because
the rank of any assignment is constrained by the variable on the left hand
side, no temporary arrays, other than machine registers, need be allocated to
store the intermediate array results of expressions.
The Unicode ¬ can be used as an alternative to the ASCII
sequence := for assignment.
A procedure statement executes a
named procedure . A procedure statement may, in the
case where the named procedure has formal parameters, contain a list of actual
parameters. These are substituted in place of the formal parameters contained
in the declaration. Parameters may be value parameters or variable parameters.
Semantically the effect of a value
parameter is that a copy is taken of the actual parameter and
this copy substituted into the body of the procedure. Value parameters may be
structured values such as records and arrays. For scalar values, expressions
may be passed as actual parameters. Array expressions are not currently allowed
as actual parameters.
A variable parameter is passed by
reference, and any alteration of the formal parameter induces a corresponding
change in the actual parameter. Actual variable parameters must be variables.
<parameter> 
<variable> 
for formal
parameters declared as var 

<expression> 
for other formal
parameters 
<procedure statement> 
<identifier> 

<identifier>
'(' <parameter> [','<parameter>]* ')' 
Examples
1.
printlist;
2.
compare(avec,bvec,result);
A goto statement transfers control
to a labelled statement. The destination label must be declared in a label declaration. It is illegal to jump into or out of a
procedure.
Example
An exit statement transfers control
to the calling point of the current procedure or function. If the exit
statement is within a function then the exit statement can have a parameter: an
expression whose value is returned from the function.
Examples
1.
exit;
2.
exit(5);
A list of statements separated by
semicolons may be grouped into a compound statement by bracketing them with begin and end .
Example
The basic control flow construct is
the if statement. If the boolean expression between if and then is true then the statement following
then is followed. If it is false and an
else part is present, the statement following else is executed.
The case statement
specifies an expression which is evaluated and which must be of integral or
ordinal type. Dependent upon the value of the expression control transfers to
the statement labelled by the matching constant.
<case
statement> 
'case'<expression>'of'<case
actions>'end' 
<case
actions> 
<case list> 

<case list>
'else' <statement> 

<case list>
'otherwise' <statement> 
<case list> 
<case list
element>[';'<case list element.]* 
<case list
element> 
<case
label>[',' <case label>]':'<statement> 
<case label> 
<constant> 

<constant>
'..' <constant> 
Examples
case i of 
case c of 
1:s:=abs s; 
'a':write('A'); 
2:s:= sqrt s; 
'b','B':write('B'); 
3: s:=0 
'A','C'..'Z','c'..'z':write('
'); 
end 
end 
Within the component statement of
the with statement the fields of the record variable can be
referred to without prefixing them by the name of the record variable. The
effect is to import the component statement into the scope defined by the
record variable declaration so that the fieldnames appear
as simple variable names.
Example
var s:record
x,y:real end;
begin
with s do begin
x:=0;y:=1 end ;
end
A for statement
executes its component statement repeatedly under the control of an iteration variable. The iteration variable must be of an integral
or ordinal type. The variable is either set to count up through a range or down
through a range.
is equivalent to
i:=e1;
temp:=e2;while i<=temp do s;
whilst
is equivalent to
i:=e1; temp:=e2;while
i>= temp do s;
A special form of for statement
allows iteration through a set.
for x in y do s
or alternatively
for x Î y do s
will execute statement s for each element x of the set y in turn. The elements are selected
in the order specified by the < operator on the base type of the set. The
varible x must
conform to the base type of the set y.
A while statement
executes its component statement whilst its boolean expression is true. The
statement
while e do s