000792 A01_Domain_Pascal_Language_Reference_Dec90 A01 Domain Pascal Language Reference Dec90

000792-A01_Domain_Pascal_Language_Reference_Dec90 000792-A01_Domain_Pascal_Language_Reference_Dec90

User Manual: 000792-A01_Domain_Pascal_Language_Reference_Dec90

Open the PDF directly: View PDF PDF.
Page Count: 611

Download000792-A01_Domain_Pascal_Language_Reference_Dec90 000792-A01 Domain Pascal Language Reference Dec90
Open PDF In BrowserView PDF
Domain Pascal
Language Reference

Domain Pascal Language Reference
Order No. 000792-AOl

Apollo Systems Division
A subsidiary of
rl~ HEWLETT
~
.... PACKARD

©

Hewlett-Packard Co. 1981, 1990.

First Printing:
Last Printing:

September 1981
December 1990

UNIX is a registered trademark of AT&T in the USA and other countries.
NOTICE
The information contained in this document is subject to change without notice.
HEWLETT-PACKARD MAKES NO WARRANTY OF ANY KIND WITH REGARD TO THIS
MATERIAL INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Hewlett-Packard shall not be
liable for errors contained herein or for incidental or consequential damages in connection with the
furnishing, performance or use of this material.
Hewlett-Packard assumes no responsibility for the use or reliability of its software on equipment that is not
furnished by Hewlett-Packard.
This document contains proprietary information which is protected by copyright. All rights reserved. No part
of this document may be photocopied, reproduced or translated to another language without the prior
written consent of Hewlett-Packard Company.
RESTRICTED RIGHTS LEGEND. Use, duplication, or disclosure by government is subject to restrictions
as set forth in subdivision (c) (1) (ii) of the Rights in Technical Data and Computer Software Clause at
DFARS 252.227.7013. Hewlett-Packard Co., 3000 Hanover St., Palo Alto, CA 94304
10 9 8 7 6 5 4 3 2 1

Preface

The Domain Pascal Language Reference explains how to code, compile, bind, and execute
Domain Pascal programs.
We've organized this manual as follows:

Chapter 1

Introduces Domain Pascal and provides an overview of its extensions.

Chapter 2

Defines Domain Pascal building blocks (like the length of an identifier) and describes the structure of the main program.

Chapter 3

Explains all the Domain Pascal data types.

Chapter 4

Contains alphabetized listings describing all the functions, procedures,
statements, and operators that you can use in the code portion of a
program.

Chapter 5

Explains how to declare and call procedures and functions.

Chapter 6

Details compiling, binding, debugging, and executing.

Chapter 7

Describes how you can break your program into two or more separately compiled modules (which can be in Domain Pascal, Domain
FORTRAN, or Domain/C).

Chapter 8

Contains an overview of the I/O resources available to Domain Pascal
programmers.

,Chapter 9

Covers compiler diagnostic messages and how to handle them.

Appendix A

Contains a table of Domain Pascal reserved words and predeclared
identifiers.

Appendix B

Contains an ISO Latin-l table that includes ASCII characters.

Appendix C

Describes Domain Pascal's extensions to ISO/ANSI standard Pascal.

Appendix D

Describes Domain Pascal's deviations from ISO/ANSI standard Pascal.

Preface

iii

I

Appendix E

Describes built-in routines available for systems programmers.

Appendix F

Describes how to obtain the best floating-point performance on
MC68040-based Domain workstations.

Audience
We wrote this manual to serve programmers at a variety of levels of Pascal expertise. Our
goal is to keep the writing as simple as possible, but to assume that you know the fundamentals of Pascal programming. If you are totally inexperienced in a block-structured language like Pascal or PL/I, you probably should study a Pascal tutorial before using this
manual. If you have a little experience with a block-structured language, you will probably
benefit most by experimenting with the many examples we provide (particularly in Chapter
4). If you are an expert Pascal programmer, turn to Appendix C first for a list of our extensions to standard Pascal.

Summary of Technical Changes
This manual describes Version 8.8 of the Domain Pascal compiler. The last update to the
Domain Pascal manual was at SR10. The following list summarizes the features added to
Domain Pascal since SR10:
•

The introduction of new Boolean operators and then and or else

•

Modified operator precedence rules (to accommodate the and then and or else Boolean
operators)

•

The following new compiler directives:

%push_aJignment and %pop_aJignment
•

The following new compiler options:
-bounds violation and -no bounds_violation
-compress and -ncompress
The -cpu arguments mathlib_srlO, mathlib, mathchip, Cpal, a88k, and
m68k
-nclines
-prasm and -nprasm

iv

Pre/ace

•

Compatibility with NFS (Network File System)

•

Larger maximum set size

•

Enforcement of name compatibility when assigning the address of an actual routine
to a procedure or function pointer

Change bars in the margin indicate technical changes since the last revision of this manual.
Because Appendix F is completely new with this revision, it does not have change bars.

Related Manuals
The file /install/doc/apoll%s.v.latest_software_release_number_manuals lists current titles and revisions for all available manuals.
For example, at SR10.3 refer to /install/doc/apoll%s.v.l0.3_manuals to check that you
are using the correct version of manuals. You may also want to use this file to check that
you have ordered all of the manuals that you need.
(If you are using the Aegis environment, you can access the same information through the
Help system by typing help manuals.)

Refer to the Apollo Documentation Quick Reference (002685) for a complete list of relate~
documents. For more information on topics related to the Domain Pascal compiler, refer
to the following documents:
•

Getting Started with Domain/OS (002348) explains the fundamentals of the Domain system.

•

The Domain/OS Call Reference, Volume 1 (007196) and Volume 2 (012888) describe the
system service routines provided by the operating system and explain how to call these
routines from user programs.

•

Programming with Domain/OS Calls (005506) covers writing Domain Pascal programs
that use stream calls and many other important system calls.

•

The Domain/C Language Reference (002093) describes the Domain implementation of
the C language.

•

The Domain FORTRAN Language Reference (000530) describes the Domain implementation of FORTRAN.

•

The Domain/C++ Programmer's Guide (017874), the AT&T C++ Language System
(017823), and the C++ Primer by Stanley Lippman (017997) describe the Domain implementation of C++.

•

The Domain Floating-Point Guide (015853) describes floating-point calculations on
Domain systems.

Preface

v

•

The Aegis Command Reference (002547) describes the Aegis environment.

•

The BSD Command Reference (005800) describes the BSD environment.

•

The SysV Command Reference (005798) describes the SysV environment.

•

The Domain/OS Programming Environment Reference (011010) describes how to use the
bind utility to link object modules and the librarian utility to create library files.

•

The BSD Unix Programmer's Manual (017272) and the SysV Programmer's Guide, Volume II (017625) describe the make and dbx utilities and the Source Code Control System (SCCS).

•

The Domain Distributed Debugging Environment Reference (011024) describes the highlevel language debugger.

•

The Domain Software Engineering Environment (DSEE) Reference (003016), Getting
Started with DSEE (08788), and Engineering in the DSEE Environment (008790) describe the DSEE product.

•

The Domain/Dialogue User's Guide (004299) describes the Domain/Dialogue product.

•

The Open Dialogue Reference (012807), Creating User Interfaces with Open Dialogue
(011167), the MOTIF Style Guide (017153), and Customizing Open Dialogue (011166)
describe the Open Dialogue product.

•

Analyzing Program Performance with Domain/PAK (008096) describes the Domain Performance Analysis Kit.

•

Using NFS on the Domain Network (010414) describes the use of the Network File
System (NFS).

You can order Apollo documentation by calling 1-800-5290. If you are calling from outside the U.S., you can dial (508) 256-6600 and ask for Apollo Direct Channel.

Pascal Tutorials

vi

•

Jensen, K. and N. Wirth, revised by Mickel, A. and J. Miner. Pascal User Manual and
Report. Third Edition. Springer-Verlag, New York: 1985.

•

Grogono, Peter. Programming in Pascal. Revised Edition. Reading, Massachusetts: Addison-Wesley, 1980.

•

Cooper, D., and M. Clancy. Oh! Pascal! New York: WW Norton, 1982.

Preface

Does This Manual Support Your Software?
This manual was released with Version 8.8 of Domain Pascal. Domain Pascal Version 8.8
runs on Software Release 10.0 or a later version of Domain/OS.
To verify which version of operating system software you are running, type
bldt
If you are running Domain/IX on a release of the operating system earlier than SR10.0,
then type
leom/bldt

To check the version of Domain Pascal, type:
leom/pas -version

If you are using a later version of software than that with which this manual was released,
use one of the following ways to check if this manual was revised or if additional manuals
exist:

•

Read Chapter 3 of the release document that shipped with your product. The release
document is online. It has one of the following pathnames:
linstall/doe/apollo/pas. v. version number. m notes
linstall/doe/apollo/pas. v. version-number. mpi notes
linstall/doe/apollo/pas. v. version=number. p __oOtes
linstall/doe/apollo/pas. v. version_number. pmx__notes

•

Telephone 1-800-225-5290. If you are calling from outside the U.S., dial (508)
256-6600 and ask for Apollo Direct Channel.

•

Refer to the lists of manuals described in the preceding section, "Related Manuals."

To determine which of two versions of the same manual is newer, refer to the order number that is printed on the title page. Every order number has a 3-digit suffix; for example,
-AOO. A higher suffix number indicates a more recently released manual. For example, a
manual with suffix -A02 is newer than the same manual with suffix -AOI.

Preface

vii

Problems, Questions, and Suggestions
If you have a question or problem with our hardware, software, or documentation, please

contact either your HP Response Center or your local HP Representative.
You may call the Tech Pubs Connection with your questions and comments about our documentation:
•

In the USA, call 1-800-441-2909

•

Outside the USA, call (508) 256-6600 extension 2434

The recorded message that you will hear when you call includes information about our new
manuals.
You may also use the Reader's Response Form at the back of this manual to submit comments about documentation.

Documentation Conventions
Unless otherwise noted in the text, this manual uses the following symbolic conventions.

literal values

Bold words or characters in formats and command descriptions represent commands or keywords that you must use literally. Pathnames
are also in bold. Bold words in text indicate the first use of a new
term.

user-supplied values Italic words or characters in formats and command descriptions represent values that you must supply.
sample user input

In samples, information that the user enters appears in color.

Domain extensions Domain-specific features of Pascal appear in color.
output

[ ]

Information that the system displays appears in this
typeface.
Large square brackets enclose optional items in formats and command
descriptions.
Regular sized square brackets in Pascal statements assume their Pascal
meanings.

viii

Pre/ace

{

}

Braces enclose a list from which you must choose an item in formats
and command descriptions. In sample Pascal statements, braces assume their Pascal meanings.
A vertical bar separates items in a list of choices.

<

>

CTRLI

Angle brackets enclose the name of a key on the keyboard.
The notation CTRLI followed by the name of a key indicates a control
character sequence. Hold down  while you press the key.
Horizontal ellipsis points indicate that you can repeat the preceding
item one or more times.
Vertical ellipsis points mean that irrelevant parts of a figure or example have been omitted.

I
----88----

Change bars in the margin indicate technical changes from the last
revision of this manual. Because Appendix F is completely new with
this revision, it does not have change bars.
This symbol indicates the end of a chapter.

----88----

Preface

ix

Contents

Chapter 1
1.1
1.2
1.2.1
1.2.2
1.2.3
1.3
1.3.1
1.3.2
1.3.3
1.3.4
1.3.5
1.3.6
1.3.7
1.3.8

Chapter 2

Introduction
A Sample Program ...........................................
Online Sample Programs ......................................
What You Get When You Install Sample Programs ..............
Creating Links to the Sample Programs .................. .....
Invoking getpas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .....
Overview of Domain Pascal Extensions ...........................
Extensions to Program Organization ..........................
Extensions to Data Types ...................................
Extensions to Code ........................................
Extensions to Routines .....................................
Extensions to Program Development ..........................
External Routines and Cross-Language Communication ..........
Extensions to I/O .........................................
Diagnostic Messages .......................................

.
.
.
.
.
.
.
.
.
.
.
.
.
.

1-1
1-2
1-2
1-3
1-3
1-4
1-4
1-5
1-5
1-6
1-7
1-7
1-7
1-7

.
.
.
.
.
.
.
.
.

2-1
2-1
2-2
2-2
2-3
2-4
2-4
2-6
2-6

Blueprint of a Program

Building Blocks of Domain Pascal ...............................
2.1
Identifiers ................................................
2.1.1
Integers .................................................
2.1.2
Real Numbers ............................................
2.1.3
Comments
...............................................
2.1.4
Strings ..................................................
2.1.5
Embedding Special Characters in Strings ...................
2.1.5.1
Case-Sensitivity ...........................................
2.1.6
Spreading Source Code Across Multiple Lines ..................
2.1.7

Contents

xi

2.2
Organization ................................................ .
2.2.1
Program Heading .......................................... .
Declarations .............................................. .
2.2.2
2.2.2.1
Label Declaration Part .................................. .
Const Declaration Part .................................. .
2.2.2.2
2.2.2.3
Type Declaration Part .................................. .
2.2.2.4
Var Declaration Part ................................... .
Define Declaration Part-Extension ....................... .
2.2.2.5
2.2.2.6
Attribute Declaration Part-Extension ...................... .
2.2.3
Routines ................................................. .
2.2.3.1
Routine Heading ....................................... .
2.2.3.2
Declaration Part of a Routine ............................ .
Nested Routines ....................................... .
2.2.3.3
2.2.3.4
Action Part of a Routine ................................ .
2.2.4
Action Part of the Main Program ............................ .
Global and Local Variables .................................... .
2.3
2.4
Nested Routines ............................................. .

Chapter 3
3.1
3.2
3.2.1
3.2.2
3.2.3
3.2.4
3.3
3.3.1
3.3.2
3.3.3
3.3.4
3.4
3.5
3.5.1
3.5.2
3.5.3
3.6
3.6.1
3.6.2
3.6.3
3.6.4
3.7
3.7.1
3.B
3.B.1

xii

Contents

2-7
2-10
2-11
2-11
2-12
2-13
2-14
2-15
2-15
2-15
2-16
2-16
2-17
2-17
2-17
2-17
2-19

Data Types
Data Type Overview ..........................................
Integers ....................................................
Declaring Integer Variables ..................................
Initializing Integer Variables-Extension .......................
Defining Integer Constants ..................................
Internal Representation of Integers ...........................
Real Numbers ...............................................
Declaring Real Variables ....................................
Initializing Real Variables-Extension ..........................
Defining Real Constants ....................................
Internal Representation of Real Numbers ......................
Unsigned Types .............................................
Booleans ...................................................
Initializing Boolean Variables-Extension ......................
Defining Boolean Constants .................................
Internal Representation of Boolean Variables ...................
Characters ..................................................
Declaring Character Variables ...............................
Initializing Character Variables-Extension .....................
Defining Character Constants ................................
Internal Representation of Char Variables .....................
Enumerated Data .............................................
Internal Representation of Enumerated Variables ................
Subrange Data ..............................................
Internal Representation ~f Subranges .........................

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

3-1
3-3
3-4
3-4
3-5
3-5
3-6
3-6
3-6
3-7
3-7
3-9
3-10
3-10
3-11
3-11
3-11
3-11
3-12
3-12
3-13
3-13
3-13
3-14
3-14

3.9
Sets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
3.9.1
Declaring Set Variables ..................................... .
3.9.2
Initializing Set Variables-Extension . . . . . ...................... .
3.9.3
Internal Representation of Sets ........ ...................... .
3.10
Records .................................................... .
3.10.1
Fixed Records ............................................ .
3.10.2
Variant Records ........................................... .
Unpacked Records and Packed Records ....................... .
3.10.3
3.10.4
Initializing Data in a Record-Extension ....................... .
3.10.5
Internal Representation of Unpacked Records .................. .
3.10.5.1
Alignment ............................................ .
3.10.5.2
Natural Alignment ..................................... .
Guaranteed Default Alignment of Record Fields ............. .
3.10.5.3
Default Alignment ...................................... .
3.10.5.4
3.10.5.5
Layout of Unpacked Records ............................ .
3.10.5.6
Memory Allocation ..................................... .
3.10.5.7
Arranging Record Fields in Descending Order by Size ........ .
3.10.6
Aligned Record and Unaligned Record Data Type ............... .
3.10.7
Internal Representation of Packed Records. . . . . . . . . . . . . . . . . . . . ..
3.11
Arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
3.11.1
Initializing Array Variables-Extension .........................
3.11.1.1
Initializing Multiple Components with a Single
Expression-Extension ...................................
3.11.1.2
Initializing Components to Individual Values-Extension. . . . . . ..
3.11.1.3
Initializing Arrays Using Repeat Counts-Extension. . . . . . . . . . ..
3.11.1. 4
Initializing Components in Any Order-Extension .............
3.11.1.5
Defaulting the Size of an Array-Extension ..................
3.11.1.6
Mixing Methods of Array Initialization-Extension ........... .
3.11.2
Variable-Length Arrays-Extension ........................... .
3.11.3
Packed Arrays ............................................ .
3.11.4
Internal Representation of Arrays ............................ .
3.11.4.1
Non-Packed Arrays .................................... .
3.11.4.2
Packed Arrays ......................................... .
3.12
Files ....................................................... .
3.13
Pointers .................................................... .
Standard Pointer Type ..................................... .
3.13. 1
U niv_ptr-Extension ....................................... .
3.13.2
3.13.3
Procedure and Function Pointer Data Types-Extension .......... .
Initializing Pointer Variables-Extension ....................... .
3.13.4
Internal Representation of Pointers ........................... .
3.13.5
3.14
Putting Variables into Overlay Sections-Extension ................. .
Attributes for Variables and Types-Extension ..................... .
3.15
Volatile-Extension ........................................ .
3.15.1
Atomic-Extension ........................................ .
3.15.2
Device-Extension ......................................... .
3.15.3
Address-Extension ....................................... .
3.15.4
Size-Extension ........................................... .
3.15.5

Contents

3-15
3-15
3-15
3-16
3-17
3-17
3-19
3-21
3-21
3-22
3-23
3-23
3-23
3-26
3-26
3-27
3-29
3-33
3-35
3-37
3-38
3-39
3-39
3-40
3-41
3-42
3-43
3-44
3-45
3-45
3-45
3-47
3-48
3-49
3-49
3-50
3-50
3-51
3-51
3-52
3-53
3-56
3-56
3-57
3-59
3-60

xiii

3.15.6
3.15.6.1
3.15.6.2
3.15.6.3
3.15.6.4
3.15.6.5
3.15.6.6

Alignment-Extension ......................................
Format for the aligned and natural Attributes ..............
Aligning Objects on Natural Boundaries ....................
Using the aligned Attribute to Prevent Padding ..............
Ensuring the Same Layout in All Alignment Environments .....
Suppressing Informational Messages about Alignment .........
Informing the Compiler that an Object Is Not Naturally Aligned
(Series 10000 Only) ....................................
3.15.6.7
Dereferencing Pointers ..................................
3.15.6.8
Passing Arguments by Reference ..........................
3.15.7
Attribute Inheritance-Extension .............................
3.15.8
Special Considerations-Extension ............................
3.16
Attribute Declaration Part-Extension ............................

Chapter 4
4.1
4.2
4.3
4.3.1
4.3.2
4.3.3
4.4
4.5
4.6
4.7

xiv

Contents

.
.
.
.
.
.

3-62
3-63
3-64
3-69
3-72
3-74

.
.
.
.
.
.

3-74
3-75
3-76
3-76
3-77
3-78

Overview: Conditional Branching ............................... .
Overview: Looping ........................................... .
Overview: Mathematical Operators .............................. .
Expansion of Operands ..................................... .
Predeclared Mathematical Functions .......................... .
Mixing Signed and Unsigned Operands in Expressions ........... .
Overview: 1/0 ............................................... .
Overview: Miscellaneous Routines and Statements .................. .
Overview: Systems Programming Routines ........................ .
Encyclopedia of Domain Pascal Code ............................ .
Abs ..................................................... .
Addr (Extension) ......................................... .
Align (Extension) ......................................... .
And, And Then .......................................... .
Append (Extension) ....................................... .
Arctan .................................................. .
Array Operations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Arshft (Extension) .........................................
Begin. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Bit Operators (Extension) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Case. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Chr. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Close (Extension) ..........................................
Compiler Directives (Extension) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Cos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Ctop (Extension) ..........................................
Discard (Extension) .......................................
Dispose ..................................................
Div . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Do ......................................................

4-1
4-2
4-2
4-5
4-5
4-6
4-8
4-8
4-10
4-10
4-12
4-13
4-16
4-18
4-21
4-23
4-25
4-29
4-31
4-33
4-36
4-39
4-41
4-43
4-59
4-61
4-62
4-64
4-66
4-68

Code

Downto ................................................. .
Else .................................................... .
End .................................................... .
Eof ..................................................... .
Eoln .....................
Exit (Extension) ..
Exp ..
Expressions ......................
Find ..............
Firstof (Extension) .....
For ..........................
Get.
Goto .....................................
If .......
In ...................................................... .
In_range (Extension) ....
Lastof (Extension) ........................................ .
Ln ..................................................... .
Lshft (Extension) ........................................ .
Max (Extension) ......................................... .
Min (Extension) ......................................... .
Mod .................................................... .
New .................................................... .
Next (Extension) ......................................... .
Nil ..................................................... .
Not ..................................................... .
Odd .................................................... .
Of ...................................................... .
Open (Extension) ......................................... .
Or, Or Else .............................................. .
Ord .................................................... .
Pack .................................................... .
Page .................................................... .
Pointer Operations ......................................... .
Pred .................................................... .
Ptoc (Extension) .......................................... .
Put ..................................................... .
Read, Readln ............................................ .
Record Operations .............................•............
Repeat/Until ............................................. .
Replace (Extension)
..................................... .
Reset ................................................... .
Return (Extension) ........................................ .
Rewrite ................................................. .
Round .................................................. .
Rshft (Extension) ......................................... .
Set Operations ............................................ .
Sin ..................................................... .
0.000.00.0

0

0

••••••

0

••••••

0

••••••

0.00

•••••••••• · ••••••••••••

0

0

••••••

0

•

0

0

••••••

0

•

0

0

0

•••

••••••••••••••

•••••••••••••••••••••••••••••••

•••••••••••••••••••••••••••••••••

0

0

••••••••••••••••••••••

••••••••••••••••••••••••••••••••••••••••

•••••••

0

••

0

••

000

•••••••

0

•••

••••••••••••••••••••••••••••••••••••••••••••••••••••

0

0

•••••••••••••••

0

0

•••••••••••••••

••

0

••••••••••••••••••••••

0

•••••

••••

0

••••••••••••••••••••••••••••

Contents

4-69
4-70
4-71
4-73
4-75
4-77
4-79
4-81
4-83
4-87
4-89
4-92
4-95
4-99
4-102
4-104
4-106
4-107
4-109
4-111
4-113
4-115
4-117
4-123
4-125
4-126
4-128
4-129
4-130
4-134
4-137
4-139
4-142
4-144
4-147
4-149
4-152
4-155
4-158
4-161
4-163
4-164
4-166
4-168
4-170
4-171
4-173
4-179

xv

Sizeof (Extension) ........................................ .
Sqr ..................................................... .
Sqrt .................................................... .
Statements ............................................... .
Substr (Extension) ........................................ .
Succ .................................................... .
Then ................................................... .
To ...................................................... .
Trunc ................................................... .
Type Transfer Functions (Extension) ......................... .
Unpack ................................................. .
Until ................................................... .
Variable-Length String Operations ............................ .
While ................................................... .
With .................................................... .
Write, Writeln ........................................... .
Xor (Extension) .......................................... .

Chapter 5
5.1
5.2
5.3
5.3.1
5.3.2
5.3.3
5.3.4
5.3.4.1
5.4
5.5
5.5.1
5.5.2
5.5.3
5.5.4
5.5.5
5.5.6
5.5.7
5.5.8
5.5.9
5.5.10
5.5.11
5.5.12
5.6
5.6.1
,5.6.2

xvi

Contents

4-181
4-184
4-186
4-188
4-189
4-191
4-193
4-194
4-195
4-197
4-200
4-203
4-204
4-208
4-211
4-215
4-221

Procedures and Functions
Parameter List .............................................. .
Argument Passing Conventions ................................. .
Parameter Types ............................................. .
Variable Parameters and Value Parameters .................... .
In, Out, and In Out-Extension ............................. .
Univ-Universal Parameter Specification-Extension ............. .
Pointers to Routines-Extension .............................. .
Data Type Checking .................................... .
Procedures and Functions as Parameters ......................... .
Routine Options ............................................. .
Routine Option Syntax ..................................... .
forward ................................................. .
extern-Extension ......................................... .
internal-Extension ........................................ .
variable-Extension ....................................... .
abnormal-Extension ...................................... .
val_param-Extension ..................................... .
nosave-Extension ......................................... .
noreturn-Extension ....................................... .
dO_return-Extension ...................................... .
aO_return-Extension ...................................... .
c-param-Extension ........................................ .
Defining Your Own Routine Options ............................. .
Syntax of the routine_option Declaration Part ................. .
Examples of the routine_option Declaration Part ............... .

5-1
5-3
5-5
5-6
5-7
5-10
5-11
5-13
5-13
5-15
5-15
5-16
5-17
5-17
5-17
5-19
5-19
5-19
5-20
5-20
5-20
5-21
5-21
5-21
5-22

5.6.3
5.6.4
5.7
5.7.1
5.8

Chapter 6

Rules for Using the routine_option Declaration Part .............
Using default_routine_options ..............................
Attribute List-Extension ......................................
Section-Extension ........................................
Recursion ..................................................

.
.
.
.
.

5-22
5-22
5-24
5-24
5-26

Program Development

6.1
6.2
6.3
6.3.1
6.4
6.4.1
6.4.2
6.4.3
6.4.4

Program Development in a Domain Environment .................. .
Compiler Variants ............................................ .
Compiling .................................................. .
Compiler Output .......................................... .
Compiler Options ............................................ .
-ac and -pic: Memory Addressing .......................... .
-alnchk: Displaying Messages about Alignment ................ .
-b and -nb: Binary Output ................................ .
-bounds_violation and -no_bounds_violation: Array Bounds
Checking ................................................ .
-comchk and -ncomchk: Comment Checking .................. .
6.4.5
6.4.6
-compress and -ncompress: Object File Storage ............... .
6.4.7
-cond and -ncond: Conditional Compilation ................... .
-config: Conditional Processing .............................. .
6.4.8
-cpu: Target Workstation Selection ........................... .
6.4.9
6.4.9.1
Choosing an Appropriate -cpu Argument: The cpuhelp Utility .
-db. -ndb. -dba. -dbs: Debugger Preparation ................. .
6.4.10
-exp and -nexp: Expanded Listing File ....................... .
6.4.11
-frnd and -nfrnd: Floating-Point Rounding ................... .
6.4.12
-idir: Search Alternate Directories for Include Files ............. .
6.4.13
-imap and -nimap: Generate Symbol Table l\faps for Include Files.
6.4.14
-indexl and -nindexl: Array Reference Index ................. .
6.4.15
6.4.16
-info nand -ninfo: Information Messages ..................... .
-inlib: Library Files ...................................... .
6.4.17
6.4.18
-iso and -niso: Standard Pascal ............................. .
-I and -nl: Listing Files .................................... .
6.4.19
-map and -nmap: Symbol Table Map ........................ .
6.4.20
-msgs and -nmsgs: Messages .............................. .
6.4.21
-natural and -nnatural: Setting the Environment to Natural
6.4.22
Alignment ............................................... .
-nclines: COFF Line Number Tables ........................ .
6.4.23
-opt: Optimized Code ..................................... .
6.4.24
Using the Debugger at Higher Optimization Levels ........... .
6.4.24.1
-prasm and -nprasm: Expanded Listing Format ............... .
6.4.25
-slib: Precompilation of Include Files ......................... .
6.4.26
-std and -nstd: Nonstandard References ...................... .
6.4.27
-subchk and -nsubchk: Subscript Checking ................... .
6.4.28
-version: Version of Compiler ............................... .
6.4.29

Contents

6-1
6-3
6-4
6-4
6-5
6-9
6-9
6-9
6-10
6-11
6-12
6-12
6-i2
6-14
6-17
6-18
6-18
6-19
6-20
6-21
6-21
6-21
6-22
6-23
6-24
6-24
6-25
6-25
6-26
6-26
6-32
6-33
6-33
6-35
6-35
6-35

xvii

6.4.30
-warn and -nwarn: Warning Messages .......................
-xrs and -nxrs: Register Saving .............................
6.4.31
Linking Programs .. ' ..........................................
6.5
The Id Utility .............................................
6.5.1
The bind Command .......................................
6.5.2
Archiving and Using Libraries ..................................
6.6
Executing a Program .........................................
6.7
6.8

6.8.1
6.8.2

6.9
6.9.1
6.9.2
6.9.3
6.9.4
6.10

Chapter 7

7.1
7.1.1
7.2
7.2.1
7.2.2
7.2.2.1
7.2.3
7.2.4
7.3
7.3.1
7.3.2
7.3.3
7.3.4
7.4
7.5
7.5.1
7.5.2
7.5.3
7.6

7.7
7.7.1
7.7.2
7.7.3
7.7.4
7.7.5

xviii

Contents

Debugging Programs in a Domain Environment ....................
The Domain Distributed Debugging Environment Utility ..........
The dbx Utility ...........................................
Program Development Tools ...................................
Traceback (tb) ................... ,........................
The DSEE Product ........................................
Open Dialogue and Domain/Dialogue .........................
Domain/PAK .............................................
Program Development Using the Network File System (NFS) ........

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

6-35
6-36
6-36
6-36
6-37
6-38

6-39
6-39
6-39
6-40
6-40
6-40
6-41

6-42
6-43
6-43

External Routines and Cross-Language
Communication
Modules ................................................... .
Module Heading .......................................... .
Accessing a Variable Stored in Another Pascal Module ............. .
Method 1 ................................................ .
Method 2 ................................................ .
Initializing Extern Variable Arrays ................... ..... .
Method 3 ................................................ .
Method4 ................................................ .
Accessing a Routine Stored in Another Pascal Module .............. .
Extern .................................................. .
Internal ................................................. .
Method 1 ................................................ .
Method 2 ................................................ .
Calling a FORTRAN Routine from Pascal ........................ .
Data Type Correspondence for Pascal and FORTRAN .............. .
Boolean and Logical Correspondence ......................... .
Simulating FORTRAN's Complex Data Type ................... .
Array Correspondence ..................................... .
Passing Data Between FORTRAN and Pascal ..................... .
Calling FORTRAN Functions and Subroutines ..................... .
Calling a Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..... .
Calling a Subroutine ...................................... ..
Passing Character Arguments ................................ .
Passing a Mixture of Data Types . . . . . . . . . . . . . . . . . . . . . . . . ..... .
Passing Procedures and Functions ............................ .

7-1
7-2
7-3
7-4
7-4
7-5
7-6
7-7
7-8
7-8
7-8
7-8
7-10
7-13
7-14

7-15
7-15
7-16
7-17
7-17
7-18

7-19
7-20

7-21
7-24

7.8
Calling a C Routine from Pascal ................................ .
7.8.1
Reconciling Differences in Argument Passing ................... .
7.8.2
Case-Sensitivity Issues ...................................... .
Using Registers ............................................ .
7.8.3
7.9
Data Type Correspondence for Pascal and C ...................... .
7.9.1
Passing Integers and Real Numbers ........................... .
7.9.2
Passing Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.9.3
Passing Arrays ............................................ .
7.9.4
Passing Pointers ........................................... .
7.9.5
Passing Procedures and Functions ............................ .
7.9.6
Data Sharing Between C and Pascal .......................... .
7.9.6.1
Declaring .data and .bss Global Variables .................. .
7.9.6.2
Creating Overlay Data Sections ........................... .

Chapter 8
8.1
8.1.1
8.1.2
8.1.3
8.1.4
8.1.5
8.1.6
8.1.7
8.2
8.2.1
8.2.2
8.2.3
8.2.4
8.2.5

Chapter 9
9.1
9.1.1
9.1.2
9.2
9.2.1
9.2.2
9.3
9.3.1
9.3.2
9.3.3
9.3.4

7-28
7-29
7-29
7-29
7-30
7-30
7-32
7-36
7-38
7-41
7-43
7-43
7-45

Input and Output
Some Background on Domain I/O ...............................
Input/Output Stream (lOS) Calls . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
VFMT Calls. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
File Variables and Stream IDs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Default Input/Output Streams. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Interactive I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Stream Markers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
File Organization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Predeclared Domain Pascal I/O Procedures . . . . . . . . . . . . . . . . . . . . . . ..
Creating and Opening a New File .............................
Opening an Existing File. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Reading from a File ........................................
Writing to a File ...........................................
Closing a File. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..

8-1
8-1
8-2
8-3
8-3
8-4
8-5
8-6
8-6
8-6
8-7
8-7
8-8
8-9

Diagnostic Messages
Errors Reported by Open and Find . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Printing Error Messages .....................................
Testing for Specific Errors ...................................
Compiler Error, Warning, and Information Messages ................
Error, Fatal Error, Warning, and Information Message Conventions.
Error, Warning, and Information Messages .....................
Run-Time Error Messages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Causes of Run-Time Errors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Debugging Run-Time Errors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Operating System Error Messages .............................
Floating-Point Errors .......................................

9-1
9-2
9-3
9-4
9-5
9-5
9-50
9-50
9-52
9-52
9-54

Contents

xix

Appendix A

Reserved Words and Predeclared Identifiers

Reserved Words and Predeclared Identifiers 00000 0 0 0 0 0 0000000 0 0 0 0 0 00000000

Appendix B

ISO Latin-l Table

ISO Latin-l Table 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ..... 0..... 0. 0..... 0 0 . . . . ..

Appendix C

Contents

B-1

Extensions to Standard Pascal

Extensions to Program Organization ........ 0.................... .
Col
Identifiers 0 . 0 0 0 0 . 0 0. 0 ........ 0........... 0........... 0.... .
Col.1
Integers 000 .. 0 . 0 0..... 0......... 0 0.... 0 0 . 0 0.... 00 ........ .
Co1.2
Comments ............. 0 0.................. 0 ............. .
Col.3
Sections 00 ... 0.0 ... 0 .. 000. 0 .. 0 . 0 0 .. 0.... 00 .... 0.......... .
C.l.4
Declarations 0 0 . 0 . . . . . . ... 0. 0 .. 0 0 .. 0 . 0 0 . 0 0 . 0 0.............. .
Col.S
Constants 0000.0.00. 0 ... 0 0..... 0 .. 0 . 0 . 0 0 0........ 0 0....... .
Col.6
Labels .. 0 0 0 .. 0 . 0 0.... 0 .. 0 . 0 0 0..... 0 0 . 0 . 0... 0 0 . 0 0 ....... 0 .0
Col.7
Extensions to Data Types ........ 0 0 . 0 0 .. 0.... 0........... 0 0 0 .. 0
C.2
Initializing Variables in the Var Declaration Part 0 0 .. 0 ........... .
C.2.1
Integers 00' 0 . 0 . 0...... 0 0..... 0 ..... 0..... 0 0.............. .
Co202
Reals .. 0.... 0 0 . 0 0 .. 0 ....... 0 0 0.... 0 0.... 0 . 0 0 ... 0 ......... .
C.2.3
Pointer Types ... 0 0 . 0.... 0 0 0......... 0..................... .
Co2.4
Variable-Length Strings o. 0 0 . 0 ... 0 .. 0 0 . 0....... 0. 0.... 0 ..... .
C.2oS
Named Sections . 0 0 ... 0 0 .. 0 . 0 0..... 0 0 ... 0 0 . 0 0............ 0 ..
C.2.6
Variable and Type Attributes 0 . 0...... 0.... 0........ 0........ .
C.2.7
Aligned Record and Unaligned Record ..... 0................ .
Co2.S
Extensions to Code ... 0......... 0 .. 0.... 0 0 .. 0.......... 0 0.... .
C.3
Exponentiation Operator ............. 0 0...... 0..... 0........ .
Co301
Bit Operators 0 0 . 0................... 0 ... 0 . . . . . ....... 0.... .
Co302
Boolean Short-Circuit Operators ..... 0 . 0..................... .
C.3.3
Bh-Shift Functions 0 ... 0.00 .. 0............. 0............... .
Co303
Compiler Directives .... 0 0 ... 0 ........ 0 .. 0 . 0 . . . . ............ .
C.3.4
Addr Function 0.................. 0 0 . 0 0................... .
Co3.S
Align Function ....... 0 0 .. 0 0 0 0.... 0 0 . 0.............. 0 0 0 ... .
Co306
Max and Min Functions 0 ... 0 0 0 . 0.... 0 .. 0 0 . 0 0 0 . 0 0.......... 0
C.307
Discard Procedure .. 0 0 0 0 0 . 0 . 0 0 .. 0 .. 0.... 0 0 . 0 .. 0 ....... 0 ... .
Co3oS
Routines for Variable-Length Strings 0 0 0 . 0 . 0 .. 0 0..... 0 0 0..... 0 ..
Co309
1/0 Procedures .... 0 .. 0 0 0 0 . 0 0 .. 0.......... 0 . 0 ............. .
Co3010
Loops ..... 0 ... 00 .... 0.' . 0 0 0 o. 0.... 0..... 00 .............. .
Co3.12
Range of a Specified Data Type 0 0 0 0 0 0 . 0 ... 0 0 .. 0 ... 0 0 0 ... 0 ... .
C.3.13
Integer Subrange Testing . 0...... 0 0 . 0.... 0 0 . 0 ... 0....... 0 0 .. .
Co3014

xx

A-l

C-1
C-1
C-1
C-2
C-2
C-2
C-3
C-3
C-4
C-4
C-4
C-4
C-4
C-S
C-S
C-S
C-6
C-6
C-6
C-6
C-6
C-6
C-7
C-7
C-7
C-7
C-7
C-S
C-S
C-9
C-9
C-9

Extensions to Read and Readln .............................
C.3.1S
Premature Return from Routines .............................
C.3.16
Memory Allocation of a Variable ............................
C.3.17
Extensions to With ........................................
C.3.18
Type Transfer Functions ....................................
C.3.19
Extensions to Write and Writeln .............................
C.3.20
Extensions to Routines ........................................
C.4
Direction of Data Transfer ..................................
C.4.1
Universal Parameter Specification ............................
C.4.2
Routine Options ...........................................
C.4.3
Routine Attribute List ......................................
C.4.4
Modularity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .......
C.S
Other Features of Domain Pascal ...............................
C.6

Appendix D
D.1
D.2

Appendix E
E.1
E.2

Appendix F

F.1
F.2
F.3
F.3.1
F.3.2
F.3.3
F.4
F.4.1
F.4.2
F.S

.
.
.
.
.
.
.
.
.
.
.
.
.

C-9
C-9
C-10
C-10
C-11
C-11
C-11
C-11
C-12
C-12
C-13
C-14
C-14

Deviations from Standard Pascal
Deviations from the Standard ...................................
Deviations from Specific Sections of the Standard ..................

D-1
D-2

Systems Programming Routines
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Restrictions for Use ...........................................

E-1
E-2

Optimizing Floating-Point Performance on
MC68040-Based Domain Workstations
Instruction Emulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
How to Determine If an Application Relies Heavily on Instruction
Emulation ................... <. <. : •••••••• '. "••••••.••••••••.•••.
How Instruction Emulation Affects Performance . . . . . . . . . . . . . ...... .
Changing from -cpu 3000 (-cpu mathchip) to -cpu mathlib or
-cpu mathlib_srlO ........................................ .
Changing from -cpu any to -cpu mathlib or -cpu mathIib_srlO .. .
Changing from -cpu any to -cpu mathchip (-cpu 3000) ........ .
What Steps to Take for Your Application ........................ .
Should You Recompile? .................................... .
If You Recompile, Which -cpu Argument Should You Use? ...... .
If You Get Different Results on the 68040 and the 68020/68030 ..... .

F-2
'

F:::"2
F-3
F-4
F-4
F-4
F-4
F-4
F-S
F-7

Index

Contents

xxi

Figures

1-1.

Sample Program ............................................ .

1-1

2-1.
2-2.
2-3.
2-4.

Format of Main Program in Domain Pascal .....................
Labeled Main Program ......................................
Global Variables Example ....................................
Nesting Example ...........................................

.
.
.
.

2-8
2-9
2-18
2-20

3-1.
3-2.
3-3.
3-4.
3-5.
3-6.
3-7.
3-8.
3-9.
3-10.
3-11.
3-12.
3-13.
3-14.
3-15.
3-16.
3-17.
3-18.
3-19.
3-20.
3-21.
3-22.
3-23.
3-24.
3-25.
3-26.
3-27.
3-28.
3-29.

Program Declaring All Available Data Types .....................
16-Bit Integer Format .......................................
32-Bit Integer Format .......................................
Single-Precision Floating-Point Format .........................
Double-Precision Floating-Point Format ........................
Storage of Sample Set .......................................
Natural Alignment for Pascal Simple Data Types .................
Default Layout of Record S 1 .................................
Layout of Record S2 ........................................
Naturally Aligned Record S3 with 1-Byte Padding ................
Layout of S4 Using Word Alignment ...........................
Memory Arrangement for Record with Poorly Arranged Fields ......
Memory Arrangement According to Decreasing Size of Fields ......
Array of SI Records, Not Naturally Aligned .....................
An Aligned Record Type Record .............................
An Unaligned Record Type Record ...........................
Sample Packed Record ......................................
Pointer Variable Format .....................................
Naturally Aligned Record S ...................................
Array of S Records .........................................
Naturally Aligned Record S ...................................
Naturally Aligned Record S 1 ..................................
Default Layout for S 1 .......................................
Layout for SI with Byte Alignment Specified ....................
Layout for SI with Natural Alignment Specified ..................
Layout for SI with Word Alignment Specified ...................
Layout for SI with Word Alignment for B Specified ..............
Naturally Aligned Structure S2 ................................
Word Aligned Structure S2 ...................................

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

3-3
3-5
3-5
3-8
3-9
3-16
3-25
3-27
3-27

5-1.
5-2.
5-3.

Program Illustrating Variable Parameters: var_parameter_example
Program Illustrating Value Parameters: value_parameter_example
Program Illustrating in, out, and in out Value Passing:
in_out_example ........................................... .
Program and Module Illustrating Pointers to Routines:
pass_routine_ptrs and square ................................ .

5-4.

xxii

Contents

3-28
3-29
3-30
3-31
3-32
3-34
3-35
3-37
3-51
3-65
3-66
3-67

3-68
3-69
3-70
3-71
3-71
3-72
3-73
3-73
5-6
5-7
5-9
5-12

5-5.
5-6.

Program Illustrating the forward Option: forward_example ....... .
Program Illustrating the variable Option: variable_attribute_example

5-16
5-18

6-1.

6-2.

Program Development in a Domain System ...................... .
A Program Illustrating Conditional Variables: config_example ..... .

6-13

7-1.
7-2.
7-3.
7-4.
7-5.
7-6.
7-7.
7-8.
7-9.
7-10.
7-11.
7-12.
7-13.
7-14.
7-15.
7-16.
7-17.
7-18.
7-19.
7-20.
7-21.
7-22.
7-23.
7-24.
7-25.

Format of a Module ........................................ .
Method 1 for Accessing an External Routine .................... .
Method 2 for Accessing an External Routine .................... .
Another Example of Calling External Routines .. . . . . . . . . . . . . . . . . . .
An Example of Calling FORTRAN: pas_to_ftn_hypo_func ........ .
An Example of Calling FORTRAN: hypotenuse ................. .
An Example of Calling FORTRAN: pas_to_ftn_hypo_sub ........ .
An Example of Calling FORTRAN: hypot_sub .................. .
An Example of Calling FORTRAN: pas_to_ftn_mixed ........... .
An Example of Calling FORTRAN: mixed_types ................ .
An Example of Calling FORTRAN: pass_func_to_fortran_p ...... .
An Example of Calling FORTRAN: funcs_for_fortran_p ......... .
An Example of Calling FORTRAN: sort_array_f ................ .
An Example of Calling C: pas_to_c_hypo ...................... .
An Example of Calling C: hypot_c ............................ .
An Example of Calling C: pas_to_c_stringsl ................... .
An Example of Calling C: capitalize .......................... .
An Example of Calling C: pas_to_c_strings2 ................... .
An Example of Calling C: pass_char .......................... .
An Example of Calling C: pas_to_c_arrays .................... .
An Example of Calling C: single_dim ......................... .
An Example of Calling C: pas_to_c_ptrs ...................... .
An Example of Calling C: append ............................ .
An Example of Calling C: sort_array_c ....................... .
An Example of Calling C: pass_func_to_c_p ................... .

7-27
7-31
7-31
7-32
7-33
7-34
7-35
7-37
7-37
7-39
7-40
7-41
7-42

9-1.

System Memory and Run-Time Errors ......................... .

9-51

F-1.

Which -cpu Argument Is Best for Your Application? ............. .

F-6

2-1.

Domain Pascal Mathematical Operators ......................... .

2-13

3-1.
3-2.
3-3.
3-4.
3-5.
3-6.
3-7.

Representation of an Enumerated Variable ......................
Guaranteed Default and Natural Alignment for Simple Data Types ..
Storage of Packed Record Fields ..............................
Size of One Element of an Array ..............................
Storage of Packed Array Elements .............................
Summary of Attributes for Variables and Types ..................
Size of Simple Data Types ...................................

3-14
3-24
3-36
3-46
3-47
3-55
3-61

6-2

7-2
7-9
7-10
7-12
7-18
7-18
7-19
7-20
7-22
7-23
7-25

7-26

Tables

.
.
.
.
.
.
.

Contents

xxiii

4-1.
4-2.
4-3.
4-4.
4-5.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

4-3
4-4
4-4

4-10.
4-11.
4-12.
4-13.
4-14.

Domain Pascal Operators .....................................
Exponentiation Expressions ...................................
Order of Precedence in Evaluating Expressions ...................
Mathematical Functions .....................................
Predeclared 1/0 Procedures ..................................
Miscellaneous Elements ......................................
Systems Programming Routines ................................
Truth Table for & (Bitwise And Operator) ......................
Truth Table for ! ( Bitwise Or Operator) .......................
Truth Table for - (Bitwise Not Operator) .......................
Compiler Directives .........................................
Truth Table for Logical or Operator ...........................
Set Operators ..............................................
Truth Table for xor Function .................................

5-1.

Argument Passing Conventions ................................ .

5-5

6-1.
6-2.
6-3.
6-4.

Sample Object File Names ...................................
Domain Pascal Compiler Options ..............................
Arguments to the -cpu Option ................................
Relative Performance with Different -cpu Arguments .............

.
.
.
.

6-5
6-6
6-16

7-1.
7-2.

Domain Pascal and Domain FORTRAN Data Types .............. .
Domain Pascal and Domain/C Data Types ...................... .

7-14
7-30

8-1.

The Default Streams ........................................ .

8-4

9-1.
9-2.

Common Error Codes Returned by open ....................... .
Common Error Codes Returned by find ........................ .

9-3
9-3

A-1.
A-2.

Reserved Words ............................................ .
Predeclared Identifiers ....................................... .

A-1
A-2

B-1.

ISO Latin-1 Codes ......................................... .

B-2

E-1.

Systems Programming Routines ................................ .

E-1

F-1.

Emulated Intrinsic Functions ................................. .

F-3

4-6.
4-7.

4-8.
4-9.

----88----

xxiv

Contents

4-6
4-8
4-9
4-10
4-33
4-34
4-34
4-44
4-134
4-174
4-221

6-17

Chapter 1
Introduction

You should be somewhat familiar with Pascal before attempting to use this manual. If you
are not, please consult a good Pascal tutorial. (We've listed some good tutorials in the
Preface.) If you are somewhat familiar with Pascal or if you are expert in a highly blockstructured language such as PL/I, then you should be able to write programs in Domain
Pascal after reading this manual.

1.1 A Sample Program
The best way to get started with Domain Pascal is to write, compile, and execute a simple
program. Figure 1-1 shows a simple program that you can use to get started.

PROGRAM getting started;
{A simple program to tryout.}
VAR
x
y

:

integer16;
integer32;

BEGIN
write('Enter an integer -- ');
readln(x);
y := x * 2;
writeln;
writeln(y:l, ' is twice', x:l);
END.
Figure 1-1. Sample Program

Although you are welcome to type in this program yourself, it is also available through the
getpas utility. The following section contains details about using getpas to run sample programs.

Introduction

1-1

Suppose you store the program in the file easy. pas. (Although it is not required that the
filename end with the .pas extension, we recommend its use so that you can readily identify Pascal source programs.)
To compile a program, simply enter the shell command pas followed by the filename. If
you do use the .pas extension, you can include or omit that extension at this step. Domain
Pascal doesn't care which way you type it. For example, to compile easy.pas, you can enter either of the following commands:
$ pas easy

or
$ pas easy. pas

The compiler creates an executable object in filename easy. bin. To execute this object you
merely enter its name. For example:
$ easy. bin

Enter an integer -- 15
30 is twice 15

1.2 Online Sample Programs
Many of the programs from this manual are stored online, along with sample programs
from other Domain manuals. These programs come automatically with the Domain Pascal
product. They illustrate features of the Domain Pascal language, and demonstrate programming with Domain graphics calls and system calls. You retrieve these online sample
programs with the getpas utility.

1.2.1 What You Get When You Install Sample Programs
When you (or your system administrator) load the Domain Pascal product, the install procedure will ask if you want to install sample programs. We recommend that you answer
"y" (for yes). If you answer "y", the install program will store the following three files in
the /domain_examples/pascal_examples directory:
examples

This is a master file containing all the sample Pascal programs.

list_of_examples

This is a help file describing all the sample Pascal programs.

getpas

This is the utility that retrieves the sample programs out of the examples file.

Note that the sample programs take up a lot of disk space (> 600 Kbytes), so we recommend that you install the sample programs in only one site on the network and have users
link to them.

1-2

Introduction

1.2.2 Creating Links to the Sample Programs
If you want to be able to invoke getpas from any directory on the system, you must create
the appropriate links. The links differ according to your type of environment. Also, before you can set up the links, you must find out the name of the disk on which the examples are stored, and use that name as node in the command lines shown below.

If you are in the Aegis environment, you can set up the following link:

$ crl -/com/getpas IInode/domain_examples/pascal_examples/getpas
If you are in a UNIX environment, you can set up the following link:

$ In -s IInodeldomain_examples/pascal_examples/getpas a_dirlgetpas
where node is the name of the disk where the examples are stored and a_dir is the name
of a directory in your path.
If node is not your node, then you should also create one of the following links, depending
on your operating system environment:

$ crl /domain_examples/pascal_examples Ilnodeldomain_examples/pascal_examples
$ In -s IInodeldomain_examples/pascal_examples Idomain_examples/pascal_examples
NOTE:

Instead of creating links you can set your working directory to the
IInodeldomain_examples/pascal_examples directory and invoke getpas from there.

1.2.3 Invoking getpas
You invoke getpas in the same manner regardless of the operating system environment.
There are two different ways to invoke getpas. The first, and simplest, way is to specify
its name on any shell command line.
For example, in an Aegis environment:
$ getpas
After you invoke getpas, the utility will prompt you for the appropriate information.
The second way to invoke getpas is to indicate the desired information on the command
line itself. To do so, issue a command with the following format:
$ getpas sampleyrogram_name outputJile_name

Introduction

1-3

For example, the following command line finds the sample program named getting_started
and writes it to pathname IIdolphin/pascalJ)rograms/getting_started. pas:

$ getpas getting_started II dol phin/pascal_programslgetting_started. pas
For full details on using getpas, issue the following command:

$ getpas -usage

1.3 Overview of Domain Pascal Extensions
Domain Pascal supports many extensions to ISOI ANSI standard Pascal. The purpose of
this section is to provide an overview of these extensions. For a complete list of all the extensions, see Appendix C. All extensions to the standard are marked in color like this or
are noted explicitly in text as an extension. For a list of omissions from standard Pascal,
see Appendix D.
Naturally, the more you take advantage of Domain Pascal extensions, the less portable
your code will be. Therefore, if you are very concerned with portability, you should avoid
using the extensions.

1.3.1 Extensions to Program Organization
Chapter 2 describes the organization of a Domain Pascal program contained within one
file. Following is an overview of the extensions described within the chapter. You can

1-4

U

or dollar sign ($) in an identifier.

•

Specify an underscore

•

Specify integers in any base from 2 to 16.

•

Specify comments in three ways.

•

Specify that the compiler assign the code or data in your program to nondefault
named sections.

•

Declare the label, const, type, and var declaration parts in any order.

•

Declare define and attribute parts in addition to the standard declaration parts.

•

Use constant expressions when declaring constants, as long as the components of
the expressions are constants.

•

Use both identifiers and integers as labels.

Introduction

1.3.2 Extensions to Data Types
Chapter 3 describes the data types supported by Domain Pascal. Domain Pascal supports
the following extensions that allow you to
•

Specify two additional pointer types. The first is a special pointer to procedures
and functions. The second is a universal pointer type that will hold a pointer to a
variable of any data type.

•

Initialize static variables in the var declaration part of your program.

•

Group variables into named sections for better run-time performance.

•

Specify variable and type attributes that let you better control compiler optimization and data layout.

•

Embed unprintable characters in string constants.

•

Create variable-length strings.

•

Specify two additional record types-aligned record and unaligned record. You
can use the first type to make sure that records are always naturally aligned, and
you can use the second to make sure that records are always aligned on word
boundaries.

1.3.3 Extensions to Code
Chapter 4 describes the action portion of your program. Domain Pascal supports the following extensions to executable statements:
•

An addr function that returns the address of a specified variable

•

An align function that returns a correctly aligned copy of an expression passed as
a routine parameter

•

An append procedure for concatenating strings

•

Bit operators or functions for bitwise and, not, or, and exclusive or operations

•

Three bit-shift functions (rshft, arshft, and Ishft)

•

Many compiler directives that enable features like include files and conditional
compilation

•

A ctop procedure for converting a C-style string into a Domain Pascal variablelength string

•

A discard procedure for explicitly discarding an expression's value and so suppressing some compiler optimizations

Introduction

1-5

•

An exit statement for jumping out of the current loop

•

An exponentiation operator (* *)

•

A find procedure for locating a specified element in a file

•

A firstof and a lastof function for returning the first and last possible value of a
specified data type

•

Some additional capabilities for the if statement

•

An in_range function for determining whether a specified value is within the defined range of an integer subrange or enumerated type

•

A max and a min function for finding the greater and lesser of two specified expressions

•

A next statement for skipping over the current iteration of a loop

•

An open procedure for opening files and a close procedure for closing files

•

A ptoc procedure for converting a Domain Pascal variable-length string into a Cstyle string

•

A replace procedure that allows you to modify an existing element in a file

•

A return statement for causing a premature return to a calling procedure or function

•

A sizeof function for'returning the size (in bytes) that a specified data type requires in storage

•

A substr function for extracting a substring from a string

•

Additional type transfer functions that transform the data type of a variable or
expression into some other data type

•

Some additional capabilities for the with statement

1.3.4 Extensions to Routines
Chapter 5 describes procedures and functions (routines). This chapter documents extensions that allow you to:

1-6

•

Specify the direction of parameter passing with the special in, out, and in out
keywords.

•

Use the univ keyword to suppress parameter type checking.

•

Specify routine attribute clauses, routine options clauses, and a routine option declaration part to control how the compiler processes a routine.

•

Specify argument lists on both the forward declaration and the routine heading of
routines declared past the calling statement.

Introduction

1.3.5 Extensions to Program Development
Chapter 6 explains how to compile, bind, debug, and execute your program. Program development tools are an implementation-dependent feature of a Pascal implementation; that
is, there is no standard for these tools.

1.3.6 External Routines and Cross-Language Communication
Chapter 7 explains how to write a program that accesses code or data written in another
separately compiled module or library. It also describes how to access routines written in
Domain FORTRAN or Domain/C. The entire chapter describes features that are
implementation-dependent.

1.3.7 Extensions to 1/0
Chapter 8 describes input and output from a Domain Pascal programmer's point of view.
Domain Pascal supports all the standard I/O procedures. In addition, it supports the open,
close, find, and replace procedures. As a further extension to the standard, Domain
Pascal permits you to access the operating system's I/O and formatting system calls~

1.3.8 Diagnostic Messages
Chapter 9 lists compile-time and run-time messages and explains how to deal with them.
Diagnostic messages are an implementation-dependent feature of Pascal.

-------00-------

Introduction

1-7

Chapter 2
Blueprint of a Program

This chapter describes the building blocks and organization of a Domain Pascal program.

2.1 Building Blocks 9f Domain Pascal
In this section we describe the basic building blocks or elements of the Domain implementation of Pascal. We define identifiers, integers, real numbers, comments, and strings, and
we explore case-sensitivity and spreading source code across multiple lines.

2.1.1 Identifiers
In this manual, the term "identifier" refers to any sequence of characters that meets the
following criteria:
•

The first character is a letter (ASCII values 65 through 90 and 97 through 122)

•

The remaining characters are any of the following:
A ... Z and a ... z (ASCII values 65 through 90 and 97 through 122)
0 ... 9
_ (underscore)
$ (dollar sign)

Identifiers are case-insensitive. An identifier can have up to 4096 characters.

Blueprint of a Program

2-1

2.1.2 Integers
The first character of an integer must be a positive sign (+), a negative sign (-), or a digit.
Each successive character must be a digit. (See the "Integers" section in Chapter 3 for a
description of the range of various integer data types.)
An unsigned integer must begin with a digit. Each successive character must be a digit.
Note that Pascal prohibits two consecutive mathematical operators. If you want to divide 9
by -3, you might be tempted to use the following expression:

{WRONG!}

9 DIV -3

However, this produces an error, since Pascal interprets the negative sign as the subtraction
operator (and that makes two mathematical operators in a row). Where the sign of an integer can be confused with an addition or subtraction operator, enclose the integer within
parentheses. Thus, the correct expression for 9 divided by -3 is:

{RIGHT!}

9 DIV (-3)

Pascal assumes a default of base 10 for integers. If you want to express an integer in another base, use the following syntax:
base#value
For base, enter an integer from 2 to 16. For value, enter any integer within that base. If
the base is greater than 10, use the letters A through F (or a through f) to represent digits
with the values 10 through 15.
For example, consider the following declarations of integer constants:

half life
hexagrams
luck
wheat

.-

.-

.-

.-

5260;
16#lc6;
2#10010;
8#723;

/*
/*
/*
/*

default
hexadecimal
binary
octal

(base
(base
(base
(base

10)
16)
2)
8)

*/
*/
*/
*/

2.1.3 Real Numbers
Domain Pascal supports the standard Pascal definition of a real number literal, which is
integer. unsigned_integerEinteger
In other words, a valid real number literal may contain a decimal point, but it doesn't
have to. If the real number literal contains a decimal point, you must specify at least one
digit to the left of the decimal point and at least one digit to the right of the decimal point.

2-2

Blueprint of a Program

To express expanded notation (powers of 10), use the letter e or E followed by the exponent; for example:
5.2
5.2EO
-5.2E3
5.2E-2

means
means
means
means

+5.2
+5.2
-5200.0
+0.052

Compare the right and wrong way for writing decimals in your program:
.5
0.5
5E-l

{wrong}
{right}
{right}

Note that although using .5 in your source code causes an error at compile time, entering
.5 as input data to a real variable does not cause an error at run time.

2.1.4 Comments
You can specify comments in any of the following three ways:
{ comment}
(* comment *)
"comment"
For example, here are three comments:
{ This is a comment. }
(* This is a comment. *)
"This is a comment."
The spaces before and after the comment delimiters are for clarity only; you don't have to
include these spaces.
NOTE:

If you use a compiler directive within comment delimiters you
cannot use spaces. Also, surrounding a compiler directive by
comment delimiters does not necessarily cause it to be treated as
a comment by the compiler. This is because you can specify a
compiler directive anywhere a comment is valid by specifying its
name inside a comment or as a statement; see the listing for
"Compiler Directives" in Chapter 4 for details.

Unlike standard Pascal, the comment delimiters of Domain Pascal must match. For example, a comment that starts with a left brace doesn't end until the compiler encounters a
right brace. Therefore, you can nest comments, for example:
{ You can (*nest*) comments inside other comments. }

Blueprint of a Program

2-3

Standard Pascal does not permit nested comments. If you want to use unmatched comment
delimiters, as standard Pascal allows, you must compile with the -iso option. (See Section
6.4.18 for details about this option.)
The Domain Pascal compiler ignores the text of the comment, and interprets the first
matching delimiter as the end of the comment. Use quotation marks to set off comments
only if you are converting existing applications to the Domain system. In all other programs, you should use either of the other two methods.
Note that Pascal comments can stretch across multiple lines; for example, the following is a
valid comment:

{ This is a comment
that stretches across
multiple lines. }
NOTE:

You can use the -comchk compiler option (described in Chapter
6) to warn you if a new comment starts before an old one finishes.
This option can help you find places where you forgot to close a
comment.

2.1.5 Strings
We refer to strings throughout this manual. In Domain Pascal, a string is a sequence of
characters. A string can be represented by a string literal, which is formed by enclosing a
sequence of characters in single quotes ("). Strings differ from identifiers in that you can
use any character within a string. Here are some sample strings:

'This is a string.'
'18'
'b[2-{q"%pl'

'can"t'
To include a single quote in a string, write the single quote twice; for example:

can"t do it.'
'Then don"t try!'

'!

NOTE:

Within a string, Domain Pascal treats the comment delimiters as
ordinary characters rather than as comment delimiters.

2.1. 5.1 Embedding Special Characters in Strings
The Domain Pascal compiler allows you to embed any ISO Latin-1 character in a string by
placing the decimal ISO Latin-1 value in parentheses. This is especially useful for embedding unprintable characters. (The ISO Latin-1 character set, described in Appendix B,
includes the ASCII character set.)

2-4

Blueprint of a Program

For example, the following statements cause the compiler to output a tab (ISO Latin-l
value 9) following the text line:
CONST
TAB

9;

writeln(~Print

a tab:

~(TAB»;

In essence, the compiler concatenates two string literals, one designated by the normal
single quotes, and the other designated by the new ISO Latin-l code syntax. There is no
limit to the number of special characters and strings that you can concatenate provided
that the total number of characters is not greater than 1024 and that the first component is
a string within single quotation marks. For example, all of the following definitions are
legal:
CONST
NUL
LF
CR
SI
S2
S3

=

0;
10;

13;
~newline'(CR)(LF);

carriage returns~ (13) (CR) (13)
null-terminated string~(NUL);

~three
~A

~followed

by more

text~;

However, it is illegal to begin a string with an ASCII code:
S3 :=

(CR)(LF)~newline~;

{ILLEGAL!}

The compiler supports an alternative syntax that allows you to specify more than one ISO
Latin-l code at a time by enclosing all of the ISO Latin-l codes in parentheses, separated
by commas.
F or instance, the expression
'newline' (CR) (LF)
can also be written
'newline' (CR,LF)

Blueprint of a Program

2-5

I

The following example illustrates some uses of embedded characters:

PROGRAM print_special_strings;
CONST·
NUL

BEL
TAB
LF
CR =

0;

7;
9;
10;

13;

BEGIN
writeln('Output four bells' (BEL) (BEL) (BEL) (BEL»;
writeln('Print two tabs' (TAB ,TAB) 'followed by text');
writeln('Print a carriage return' (CR) 'and linefeed' (LF»;
END.

2.1.6 Case-Sensitivity
Domain Pascal, like standard Pascal, is case-insensitive to keywords and identifiers (i.e.,
variables, constants, types, and labels), but case-sensitive to strings. That is, Domai.n Pascal
makes no distinction between uppercase and lowercase letters except within a string. For
example, the following three uses of the keyword begin are equivalent:

BEGIN
begin
Begin
However, the following two character strings are not equivalent:

'The rain in Spain';
'THE RAIN IN SPAIN';
NOTE:

At SRI0, Domain/OS is case-sensitive for pathnames. Be sure
that strings containing pathnames store the pathnames in the correct case.

2.1. 7 Spreading Source Code Across Multiple Lines
In Pascal, you can start a statement or declaration at any column and spread it over as
many lines as you want. However, note that you cannot split a token (keyword, identifier,
or string) across a line. For example, consider the writeln statement which can take character strings as an argument. The following use of writeln is wrong because it splits the
string across a line:

WRITELN('This is an uninteresting
long string');

2-6

Blueprint 0/ a Program

Instead, the line should appear this way:
WRITELN('This is an uninteresting long string');
You can also break the string into two strings and separate them by a comma:
WRITELN('This is an uninteresting'
" long string');
This works because the writeln procedure takes more than one argument.
NOTE:

By default, any text file you open for reading can have a maximum of 256 characters per line. You can specify an optional
buffer size when you open the file, however, to change that default.

2.2 Organization
You can write a Domain Pascal program in one file or across several files. This section explains the proper structure for a program that fits into one file. Chapter 7 details the structure for a program that is spread over several files.
A Domain Pascal program takes the format shown in Figure 2-1. Note that routines are
themselves declarations.

Blueprint of a Program

2-7

,."""

~,

Label
Const
Type
Var
Define

declaration part
declaration part

-~

declaration part
declaration part
declaration part

Attribute declaration part

~,

program heading

-

~

declarations
routines

,.",

routine heading

Begin

declarations
action

-.....

nested routines
End.
Begin

action
End;

Figure 2-1. Format of Main Program in Domain Pascal
Figure 2-2 is a labeled program designed to help you understand the structure of a
Domain Pascal program. The following subsections detail the parts of a program.

2-8

Blueprint of a Program

PROGRAM labeled;

{program heading}

{start of the declaration part of the main program.
}
{These declarations will be global to the entire program.}
LABEL
{LABEL declaration part}
finish;
CONST
axiom
TYPE
flavors

{CONST declaration part}
'Clarity is wonderful!';
{TYPE declaration part}
(mint, lime, orange, beige);

VAR

{VAR declaration part}
x, y, z : integer;
ice_cream: flavors;
{End of the declaration part of the main program.}

{Start of the roots procedure.}
Procedure roots;

{routine heading}

. {Start of the declaration part of roots.}
{These declarations will be local to roots.}
{VAR declaration part}
VAR
q : real;
{End of the declaration part of roots.}
BEGIN
{Start of the action part of roots.}
write('Enter a number - '); readln(q);
writeln('The square root of ',q, ' is ',sqrt(q»;
END;
{End of the action part of roots.}
{End of the roots procedure.}

I

BEGIN
{Start of the action part of the main program.}
writeln(axiom);
x := 5; y:= 7; z:= x + 5;
if z > 100 then goto finish;
for ice_cream := mint to beige do
writeln(ice_cream);
roots;
finish:
{End of the action part of the main program.}
END.
Figure 2-2. Labeled Main Program

Blueprint of a Program

2-9

2.2.1 Program Heading
Your program must contain a program heading. The program heading has the following
format:

I

In Domain Pascal, as in standard Pascal, you must supply a name for the program. Name
must be an identifier. This identifier has no meaning within the program, but is used by
the binder, the librarian, and the loader. (See the Domain/OS Programming Environment
Reference manual for details on these utilities for Aegis. For the UNIX utilities Id and ar,
refer to the SysV Command Reference and the BSD Command Reference.)
In standard Pascal you can supply an optional file _list to the program heading. The
file_list specifies the external files (including standard input and output) that you are going
to access from the program. However, unlike standard Pascal, the file_list in a Domain
Pascal program has no effect on program execution; the compiler ignores it. (For details
on 110, see Chapter 8.)

Code_section_name and data_section_name are optional elements of the program heading.
Use them to specify the names of the sections in which you want the compiler to store
your code and data. A section is a named contiguous area of memory in which all entities
share the same attributes. (See the Domain/OS Programming Environment Reference for
details on sections and attributes.) By default, Domain Pascal assigns all the code in your
program to the . text section and all the data in your program to the . data section. To assign your code and data to nondefault sections, specify a code_section_name and a
data _section _name.
NOTE:

In addition to nondefault code and data section names for the
entire program, you can also specify a nondefault section name
for a procedure, a function, or a group of variables. See the" Section" section of Chapter 5 for an explanation of how to assign
section names to procedures and functions, and see the" Putting
Variables into Sections" section of Chapter 3 to learn how to
assign section names to groups of variables.

To specify the default .text section together with an alternate .data section, use the following syntax:

program name [(file_list)], , data_section_name;

2-10 Blueprint of a Program

Let's now consider some sample program headings. Despite the options available, most Domain Pascal program headings can look as simple as the following:
Program trapezoids;
Those of you desiring to write standard Pascal programs will also probably want to supply a
file _list as in the next example:
Program trapezoids (input, output, datafile);
Finally, those of you wanting to capitalize on certain run-time features may wish to define
your own section names. For example, if you want the compiler to store the code into section mycode and the data into section mydata, you would issue the following program
heading:
Program trapezoids, mycode, mydata;

2.2.2 Declarations
The declarations part of a program is optional. It can consist of zero or more label declaration parts, const declaration parts, type declaration parts, var declaration parts, define
declaration parts, and attribute declaration parts. Domain Pascal allows you to specify
these parts in any order.

2.2.2.1 Label Declaration Part
You define labels in the label declaration part. A label has only one purpose-to act as a
target for a goto statement. (See Chapter 4 for a description of the goto statement.) In
other words, the statement

GOTO 40;
works only if you have defined 40 as a label.
The format for a label declaration part is
label

l

labell [, ... labelN

A label is either an identifier or an unsigned integer. If there are multiple labels, you must
separate them with commas. Remember, though, to put a semicolon after the final label.
For example, the following is a sample label declaration:

LABEL
40, reprompt, finish, 9999;

Blueprint of a Program

2-11

2.2.2.2 Const Declaration Part
You define constants in the const declaration part. A constant is a synonym for a value
that will not (and cannot) change during the execution of the program.
The const declaration part takes the following syntax:
const
identifier} = value};

[
identifierN = valueN;]
An identifier is any valid Domain Pascal identifier. A value must be a real, integer, string,
char, or set constant expression. Value can also be the pointer expression nil.
For example, here is a sample const declaration part:

CONST
pi = 3.14;
cup = 8;
key = 'Y';

blank = ' ';
words = 'To be or not to be';
v owe 1 s = [' a', ' e', ' i', ' 0 ' ,
ptr1 = nil;

'

u '] ;

{A real number}
{An integer}
{A character}
{A character}
{A string}
{A set}
{A pointer}

The preceding sample involves simple expressions; however, you can also specify a more
complex expression for value. Such an expression can contain the following types of terms:
•

A real number, an integer, a character, a string, a set, a Boolean, or nil

•

A constant that has already been defined in the const declaration part (note that
you cannot use a variable here)

•

Any predefined Domain Pascal function (for example, chr, sqr, Ishft, sizeof, but
only if the argument to the function is a constant)

•

A type transfer function

You can optionally separate these terms with any of the operators shown in Table 2-1.

2-12 Blueprint of a Program

Table 2-1. Domain Pascal Mathematical Operators
Operator

Data Type of Operand

+, -, *

Integer, real, or set

/

Real

mod, div, I, &, -

Integer

**

Exponentiation

Chapter 4 describes these operators.
For example, the following const declaration part defines eight constants:

CONST
x
y

10;
100;

z
x + y;
current_year
leap_offset
bell
pathname
pathname_len

1994;

(current_year mod 4);
chr (7) ;
'jjetjgo_home';
sizeof(pathname);

2.2.2.3 Type Declaration Part
Chapter 3 details the many predeclared data types Domain Pascal supports. In addition to
these Pascal-defined data types, you can create your own data types in the type declaration part. After creating your own data type, you can then declare variables (in the var
declaration part) that have these data types. The format for a type part is as follows:
type

identifier1 = typename 1 :

[
identifierN = typenameN:]
An identifier is any valid Domain Pascal identifier. A typename is any predeclared Domain
Pascal data type (like integer or real), any data type that you create, or the identifier of a
data type that you created earlier in the type declaration part.

Blueprint of a Program

2-13

For example, here is a sample type declaration part:

type
long = integer32;
{A predeclared Domain Pascal
student_name = array[l .. 20] of long;
{A user-defined
colors = (magenta, beige, mauve);
{A user-defined
hue = set of colors;
{A user-defined
table = array [magenta .. mauve] of real;
{A user-defined

data
data
data
data
data

type}
type}
type}
type}
type}

2.2.2.4 Var Declaration Part
Declare variables in the var declaration part. A variable has two components - a name
and a data type. The format for the var declaration part is:
var
identifier_list 1 : typename 1 ;

[
identifier_listN : typenameN;]

An identifier_list consists of one or more identifiers separated by commas. Each identifier
in the identifier_list is assigned the data type of typename. Typename must be one of
these:
•

A predeclared Domain Pascal data type

•

A data type you declared in the type declaration part

•

An anonymous data type (that is, a data type you define for the variables in this
identifier_list only)

2-14 Blueprint of a Program

For example, consider the following type declaration part and var declaration part:
type
names = array[1 .. 20] of char;
colors = (red, yellow, blue);
var
counter, x, y: integer;
{integer is
angles:real;
{real is
a_letter: char;
{char is
couch_colors: colors;
evil;boolean;
{boolean is
mystery_guest:names;
seniors:67 .. 140;
pet: (cat, dog);

a predeclared Domain Pascal
a predeclared Domain Pascal
a predeclared Domain Pascal
{colors is defined in the
a predeclared Domain Pascal
{names is defined in the
{An anonymous subrange
{An anonymous enumerated

data
data
data
type
data
type
data
data

type.}
type.}
type.}
part.}
type.}
part.}
type.}
type.}

In the preceding example, note that counter, x, and yare three variables that have the
same data type (integer).

2.2.2.5 Define Declaration Part-Extension
In addition to the const, type, var, and label declaration parts of standard Pascal, Domain Pascal also supports an optional define declaration part, which is described in the
first three sections of Chapter 7.

2.2.2.6 Attribute Declaration Part-Extension
Domain Pascal supports an optional attribute declaration part, which is described in the
"Attribute Declaration Part" section of Chapter 3.

~.2.3

Routines
A program can contain zero or more routines. There are two types of routines in Domain
Pascal: procedures and functions. A routine consists of three parts: a routine heading, an
optional declaration part, and an action part.

Blueprint of a Program

2-15

2.2.3.1 Routine Heading
Routine headings take the following format:

[ attribute_list] procedure name [(parameter_list) ] ; [routine_options; ]
or

[ attribute_list] function name [(Parameter_list)] : typename; [routine_options;]
where:

•

attribute _list is optional. Inside the attribute _list, you can specify nondefault section names for the routine's code and data. For a description, see Chapter 5.

•

name is an identifier. You call the routine by this name.

•

parameter_list is optional. It is here that you deClare the names and data types of
all the parameters that the routine expects from the caller. See Chapter 5 for details on the parameter_list.

•

typename is the data type of the value that the function returns. The difference
between a procedure and a function is that the name of a procedure is simply a
name, but the name of a function is itself a variable with its own typename. You
must assign a value to this variable at some point within the action part of the
function. (It is an error if you don't.) You cannot assign a value to the name of a
procedure. (It is an error if you do.)

•

routine_options is an optional element of the routine heading. You can specify
characteristics of the routine such as whether or not it can be called from another
routine. Chapter 5 describes the routine_options.

2.2.3.2 Declaration Part of a Routine
The optional declaration part of a routine follows the same rules (with one exception) as
the optional declaration part under the program heading. The constants, data types, variables, and labels are local to the routine declaring them and to any routines nested within
them. (See the "Global and Local Variables" and "Nested Routines" sections at the end
of this chapter for details.)
One difference between the declaration part of a routine and the declaration part of the
main program is that the declaration part of a routine cannot contain a define declaration
part. Another difference is that you cannot initialize non-static variables in a routine,
though you can initialize them in the main program.

2-16 Blueprint of a Program

2.2.3.3 Nested Routines
You can optionally nest one or more routines within a routine. See the "Nested Routines"
section at the end of this chapter for details.

2.2.3.4 Action Part of a Routine
The action part of a routine starts with the keyword begin and finishes with the keyword
end. Between begin and end you supply one or more Domain Pascal statements. (See
Chapter 4 for a description of Domain Pascal statements.) You must place a semicolon
after the final end in a routine.
For example, consider the following sample action part of a routine:

BEGIN
x := x * 100;
writeln(x);
END;

2.2.4 Action Part of the Main Program
The action part of the main program is almost identical to the action part of a routine.
Both start with begin, both finish with end, and both contain Domain Pascal statements in
between. The only difference is that you must place a period (rather than a semicolon)
after the final end in the main program. For example, consider the following sample action
part of the main program:

BEGIN
x := x * 100;
writeln(x);
END.

2.3 Global and Local Variables
The declarations in the declaration part of the main program are global to the entire program. The declarations in the declaration part of a routine are local to that routine (assuming no nesting). For example, consider the following program. In it, variable g is global
and variable I is local to procedure addl00.

Blueprint oj a Program

2-17

Program scope;
VAR
g : integer16;
Procedure add100;
VAR
1: integer16;
BEGIN
1 := g + 100;
{Variable I is accessible within this procedure only,}
{while g is global and so is accessible anywhere.
}
END;

BEGIN

:= 10;
add100;

g

{variable g is accessible because it is global. }
{Call the procedure.
}
{Variable I is not accessible here because it is}
{local to procedure add100.
}

END.
What happens when you specify a local variable with the same name as a global variable?
To answer this question, see Figure 2-3 for two more programs. In the program on the
left (global_example), x is declared as a global variable. In the program on the right (local_example), x is declared twice. The first declaration specifies x as a global variable.
The second declaration declares x as local to procedure convert.

Program global_example;

Program local_example;

VAR {global declarations}
x : integer16;

VAR {global declarations}
x : integer16;

PROCEDURE convert;
BEGIN
x := -10;
writeln('In convert, x=',x:1);
END;

BEGIN {main}
x := +10;
convert;
writeln('In main, x=',x:1);
END.

PROCEDURE convert;
VAR {local declarations}
x : integer16;
BEGIN
x := -10;
writeln('In convert, x=',x:1);
END;
BEGIN {main}
x := +10;
convert;
writeln(In main, x=', x:1);
END.

Figure 2-3. Global Variables Example

2-18 Blueprint of a Program

If you execute the programs in Figure 2-3, you get the following results:

Execution of global_example
In convert, X= -10
In main, X= -10

Execution of local_example
In convert, X= -10
In main, X= 10

In program local_example, within procedure convert, the declaration of the local variable
x overrides the global declaration of x. Within convert, the fact that the local variable and
the global variable have the same name (x) prevents procedure convert from accessing the
global variable x at all.
Both programs are available online and are named global_example and local_example.

2.4 Nested Routines
A nested routine is a routine that is declared inside another routine. A nested routine can
access any declared object (label, constant, type, or variable) in a routine outside it, provided that the object is not hidden by a local declaration. The reverse is not true; that is,
a routine cannot access an object in a routine nested inside it. Thus, the purpose of nesting routines is to create a hierarchy of access. You might view declared objects in the following way:
•

Global to the entire program.

•

Local to a single routine.

•

Local to the routine it is defined in and to all routines nested within it (that is,
neither truly local nor truly global). This is termed an "intermediate level" object.

Note that the main program is itself a routine, and that all routines are nested at least one
level inside it. A routine can call any routine nested one level inside it, but cannot explicitly call any routine nested two or more levels inside it. A routine can also call any routine
at its level or outside it, though a routine cannot explicitly call the main program.
For example, consider the program in Figure 2-4. Procedure one is nested inside the main
program. Procedures two a and twob are both nested inside procedure one. The mostnested procedures (twoa and twob) can access the most variables. The least-nested procedure (the main program) can access the least number of variables.

Blueprint of a Program

2-19

Program

nesting_example;

VAR

g : integer16;
procedure one;
VAR
1 : integer16;
procedure twoa;
VAR
n1 : integer16;
BEGIN {twoa}
{can access g, 1, and n1.}
n1 := 1 + g + 500;
END; {twoa}
procedure twob;
VAR
n2 : integer16;
BEGIN {twob}
{can access g, 1, and n2.}
n2 := 1 + g + 1000;
END;
{twob}
BEGIN {one}
{can access g and I.}
1 := g + 10;
twob;
END; {one}
BEGIN {main program}
{can only access g.}
g := 1;

g := g * 2;
one;
END.
{main program}
Figure 2-4. Nesting Example

2-20 Blueprint of a Program

Note that the main program can call procedure one, but cannot call procedure two a or
twob (since they are nested two levels inside it). Procedure one can call procedure two a
or twob. Procedure twob can call procedure twoa or one. In Pascal, you cannot make a
forward reference to a routine unless you declare the routine with the forward option (described in Chapter 5). If you used forward in this example, procedure twoa could call
twob or one.

----88----

Blueprint of a Program

2-21

Chapter 3
Data Types

This chapter explains Domain Pascal data objects. It tells you how to declare variables using the predeclared Domain Pascal data types and how to define your own data types. The
chapter also shows how Domain Pascal represents each data type internally. Finally, the
chapter describes attributes for variables and types and an attribute declaration part. You
can use these attributes to define characteristics in addition to the data type.

3.1 Data Type Overview
Domain Pascal supports data types that can be sorted into three groups-the simple, structured, and pointer data types. Furthermore, Domain Pascal provides extensions to the
standard in each category of data type. In this section, we list all the Domain Pascal data
types according to category.
The following list shows the simple data types:
•

Integers-Domain Pascal supports the three predeclared integer data types integer,
integer16, and integer32.

•

Real numbers-Domain Pascal supports the three predeclared real number data
types real, single, and double.

•

Boolean-Domain Pascal supports the predeclared data type boolean.

•

Character-Domain Pascal supports the predeclared char data type.

•

Enumerated-Domain Pascal supports enumerated data types.

•

Subrange-Domain Pascal supports a subrange of scalar data types. The scalar
data types are integer, Boolean, character (char), and enumerated.

Data Types

3-1

You can use the simple data types to build the following structured data types:
•

Sets-Domain Pascal permits you to create a set of elements of a scalar data type.

•

Records-Domain Pascal supports the record, aligned record, unaligned record,
and packed record data types.

•

Array-Domain Pascal supports the array and packed array data types. It also
supports a predeclared character array type called string, and variable-length array type declared with the varying keyword.

•

Files-Domain Pascal supports the file and text data types.

You can declare any of three kinds of pointer data types:
•

Type-specific pointer-points to any previously defined data type.

•

Universal pointer-Domain Pascal supports univ_ptr, a predeclared pointer data
type that is compatible with any pointer type.

•

Procedure and function pointers-Domain Pascal supports a special data type that
points to procedures and functions.

The program shown in Figure 3-1 contains sample declarations of the above data types.
This program is available online and is named sample_types.

3-2

Data Types

PROGRAM sample_types;
TYPE
real_pointer
"'real;
}
{This is a pointer type.
writers
(Amy, Phil, Janice);
{This is an enumerated type.}
element
record
}
{This is a record type.
atomic_number
INTEGER16;
atomic_weight
SINGLE;
half life
DOUBLE;
end;
VAR

i1
i2
i3
r1
r2
r3
consequences
onec
teenage_years
good_writers
tw
e
cat_nums

INTEGER;
INTEGER16;
INTEGER32;
REAL;

SINGLE;
DOUBLE;
BOOLEAN;
CHAR;
13 .. 19;
{teenage_years is a subrange variable.}
writers; {good_writers is an enumerated variable.}
SET OF writers;
{tw is a set variable.}
element;
{e is a record variable.}
array[l .. 5] of INTEGER16;
{cat~nums is an array variable.}
STRING;
{a_sentence is an array variable of 80 characters.}
hamlets_soliloquy: TEXT; {hamlets_soliloquy is a text file variable.}
periodic_table
FILE OF element;
{periodic_table is a file variable.}
real_pointer;
{rl_ptr is a pointer variable.}
UNIV_PTR;
{Any_ptr is a universal pointer variable.}
pp
"'PROCEDURE (IN x : INTEGER);
{pp is a pointer to a procedure variable.}
BEGIN
writeln('Greetings.');
END.
Figure 3-1. Program Declaring All Available Data Types

3.2 Integers
This section explains how to declare variables as integers, how to initialize integer variables,
and how to define integer constants. It also explains how Domain Pascal represents integers
internally.

Data Types

3-3

3.2.1 Declaring Integer Variables
Domain Pascal supports the following predeclared integer data types:
•

Integer-Use it to declare a signed 16-bit integer. A signed 16-bit integer variable
can have any value from -32768 to +32767.

•

Integer16-Use it to declare a signed 16-bit integer. (Integer and integer16 have
identical meanings.)

•

Integer32-Use it to declare a signed 32-bit integer. A signed 32-bit integer variable can be any value from -2147483648 to +2147483647.

For example, consider the following integer declarations:
VAR

x, y, z : INTEGER;
quarts : INTEGER16;
social_security_number : INTEGER32;
If you want to define unsigned integers, you must use a subrange declaration. (Refer to the

"Subrange" section later in this chapter.)

3.2.2 Initializing Integer Variables-Extension
Domain Pascal permits you to initialize the values of integers within the variable declaration
in most cases. You initialize a variable by placing a colon and equal sign (:=) immediately
after the data type. For example, the following excerpt initializes X and Y to 0, and Z to
7000000:
VAR

X,Y
Z

INTEGER16.- 0;
INTEGER32 .- 7000000;

If the variable declaration occurs within a procedure or function, you cannot initialize the

variable at the declaration unless it has been declared static. This is because storage within
routines is dynamic and so variables in them do not necessarily retain their values between
executions.
For example, the following is incorrect:
FUNCTION do_nothing(IN OUT x : INTEGER) : BOOLEAN;
VAR

init_value : INTEGER := 0;

{wrong!}

This is the correct way to initialize the variable at its declaration in a routine:
init value: STATIC INTEGER := 0;

3-4

Data Types

{Right!}

See the" Accessing a Variable Stored in Another Pascal Module" section of Chapter 7 for
more information on the static attribute.

3.2.3 Denning Integer Constants
When you declare an integer constant, Domain Pascal internally represents the value as a
32-bit integer. For example, in the following declarations, Domain Pascal represents both
poco and grande as 32-bit integers.

CONST
poco
6;
grande = 6000000;
You can specify an integer constant anywhere in the range -2147483648 to +2147483647.
It is also possible to compose constant integers as a mathematical expression. (Refer to the
"Const Declaration Part" section in Chapter 2 for details.)
The predeclared integer constant maxint has the value +32767.

3.2.4 Internal Representation of Integers
Domain Pascal represents a 16-bit integer (types integer and integer16) as two contiguous
bytes, as shown in Figure 3-2. Bit 15 contains the most significant bit (MSB), and bit 0
contains the least significant bit (LSB). If the integer is signed, bit 15 contains the sign bit.
15 (MSB)

0 (LSB)

1--------B~-e--O--------------B-~-e--1-------1

Figure 3-2. 16-Bit Integer Format
Domain Pascal represents a 32-bit integer (type integer32) in four contiguous bytes as illustrated in Figure 3-3. The most significant bit in the integer is bit 31; the least significant
bit is bit O. If the integer is signed, bit 31 contains the sign bit.
31 (MSB)

16
B~e

0

B~e

1

B~e

2

B~e

3

o (LSB)

15

Figure 3-3. 32-Bit Integer Format
By default, Domain Pascal aligns freestanding 16-bit integers on word boundaries and
32-bit integers on longword boundaries. (See the "Internal Representation of Records"
section of this chapter for details about alignment for integers that are part of records.)

Data Types

3-5

3.3 Real Numbers
This section describes how to declare variables as real numbers, how to define real numbers as constants, and how Domain Pascal represents real numbers internally.

3.3.1 Declaring Real Variables
Domain Pascal supports the following real data types:
•

Real-Use it to declare a signed single-precision real variable. Domain Pascal represents a single-precision real number in 32 bits. A single-precision real variable
has approximately seven significant digits.

•

Single-Same as real.

•

Double-Use it to declare a signed double-precision real variable. Domain Pascal
represents a double-precision real number in 64 bits. A double-precision real variable has approximately 16 significant digits.

For example, consider the following declarations:

VAR
1, m, n : REAL;
winning_time : SINGLE;
cpu_time : DOUBLE;

3.3.2 Initializing Real Variables-Extension
Domain Pascal permits you to initialize the values of real numbers within the variable declaration in most cases. You initialize a value by placing a colon and equal sign (:=) immediately after the data type. For example, the following excerpt initializes variable pi to
3.14:

VAR
pi

: SINGLE := 3.14;

If you declare a variable as single or real, and if you attempt to initialize it to a number
with more than seven significant digits, then Domain Pascal rounds (it does not truncate)
the number to the first seven significant digits.

For example, if you try to initialize pi this way:

VAR
pi

: SINGLE := 3.1415926535;

Domain Pascal rounds pi to 3.141593.

3-6

Data Types

As with integers, if the variable declaration occurs within a procedure or function, you can
initialize the variable at the declaration only if it has been declared static. This is because
storage within routines is dynamic and so variables in them do not necessarily retain their
values between executions. For example, the following is incorrect:
FUNCTION do_nothing(IN OUT x : REAL) : BOOLEAN;
VAR

init_value : REAL := 0.0;

{Wrong!}

This is the correct way to initialize the variable at its declaration in a routine:
init_value : STATIC REAL := 0.0;

{Right!}

See the" Accessing a Variable Stored in Another Pascal Module" section of Chapter 7 for
more specific information on the static attribute.

3.3.3 Denning Real Constants
When you use a real number as a constant, Domain Pascal automatically defines the constant as a double-precision real number. This is true even if the constant can be accurately
represented as a single-precision real number. However, when you use a real constant in a
mathematical operation with a single-precision number, Domain Pascal automatically
rounds the constant to a single-precision number to produce a more accurate result. The
following fragment defines four valid (and one invalid) real constants:
CONST
24.57;
{ Valid real number. }
2E19;
{ Valid, symbolizes 2.0 * (10 19 ) }
G
6.67E-ll;
{ Valid, symbolizes 6.67 * (10- 11 ) }
X
.5;
{ Not a valid real literal because it does }
{ not contain a digit to the left of the }
{ decimal point. }
{Valid real literal.}
X2 = 0.5;
N

N2

3.3.4 Internal Representation of Real Numbers
Single-precision floating-point numbers (types real and single) occupy four contiguous
bytes of a longword, as shown in Figure 3-4. Domain Pascal uses the IEEE standard format for representing 32-bit real values. Bit 31 is the sign bit with "1" denoting a negative
number. If the value is normalized, the next eight bits contain the exponent plus 127, and
the remaining 23 bits contain the mantissa of the number without the leading 1. (Domain
Pascal stores the mantissa in magnitude form, not in two's-complement.)

Data Types

3-7

31

30

$

I

22

1

Exponent + 127

16
Mantissa

Mantissa (cont.)

o

15

Figure 3-4. Single-Precision Floating-Point Format

For example, Pascal represents +100.5 in the following manner:
0100001011001001
0000000000000000
The number breaks into sign, exponent, and mantissa as follows:
sign
exponent
significant part of mantissa

o (positive)
10000101 (133 in decimal)
1001001

The exponent is 133; 133 is equal to 127 plus 6. Therefore, you can view the mantissa bits
as follows:
bit 22 represents 2 to the fifth power
bit 21 represents 2 to the fourth power
bit 20 represents 2 to the third power

bit 16 represents 2 to the negative first power.
You get 100.5 by adding (2 6 + 25 + 22 + 2_1 ). (The implicit leading 1 of the mantissa
corresponds to 26 .)
A number with a negative exponent is stored differently. Pascal represents 5E-2 (+0.05)
as follows:
0011110101001100
1100110011001101
The number breaks into sign, exponent, and mantissa as follows:
sign
exponent
significant part of mantissa

3-8

Data Types

o

(positive)
01111010 (122 in decimal)
10011001100110011001101

The exponent is 122; 122 is equal to 127 plus -5. Therefore, you can view the mantissa
bits as follows:

bit 22 represents 2 to the -6 power
bit 21 represents 2 to the -7 power
bit 20 represents 2 to the -8 power

bit 0 represents 2 to the -29 power
You get 5E-2 by adding 2_5 + 2_6 + 2_9 and so on.
Domain Pascal represents double-precision floating-point numbers (type double) in eight
bytes of a longword (64 bits). Figure 3-5 illustrates the format. The first bit (bit 63) contains the sign bit. If the value is normalized, the next 11 bits contain the exponent plus
1023. The remaining 52 bits hold the mantissa, without the leading 1.

63

$

62

I

51

Exponent + 1023

I

48
Mantissa

Mantissa (cont.)
Mantissa (cont.)
Mantissa (cont.)
15

o

Figure 3-5. Double-Precision Floating-Point Format
By default, Domain Pascal stores single-precision floating-point numbers (types real and
single) on longword boundaries. It stores double-precision floating-point numbers (type
double) on quadword boundaries. (See the "Internal Representation of Records" section
of this chapter for details about alignment for real numbers that are part of records.)
For complete information about floating-point formats, see the Domain Floating-Point
Guide.

3.4 Unsigned Types
Although Domain Pascal does not have a true unsigned data type, it does offer unsigned
ranges. Through the use of large unsigned subranges (from 0 .. 230 up to 00 .. 2 31 _1), you
can achieve much of the effect of having true unsigned types.

Data Types

3-9

The following code fragment illustrates the simulation of unsigned types through the use of
unsigned subranges:
TYPE
signed_32
unsigned_32

-2147483648 .. 2147483647;

o.. 2147483647;

VAR
signed_32;
unsigned_32;

s32
u32

NOTE:

{ Signed 32-bit integer. }
{ Unsigned 31-bit integer. Not
exactly the full 32 bits, but
enough to convince the compiler
that u32 is much like an unsigned
32-bit integer. }

The true full range of unsigned 32-bit integers cannot be expressed because constants larger than 2147483647 are not valid.
You cannot get around this restriction by using constants with an
explicit base with the signed bit set because the compiler treats
them as negative numbers (for example, 16#FFFFFFFF).
When you have an unsigned subrange that is large enough to require 31 bits, the compiler allocates 32 bits.

3.5 Booleans
A Boolean variable can have only one of two values-true or false. This section describes
how you declare Boolean variables. how you define Boolean constants. and how Domain
Pascal represents Boolean variables internally.

3.5.1 Initializing Boolean Variables-Extension
Domain Pascal permits you to initialize the values of Boolean variables within the variable
declaration in most cases. You initialize a value by placing a colon and equal sign (:=) immediately after the data type. For example. the following excerpt declares liar to be a
Boolean variable with an initial value of false:

VAR
liar : boolean := false;
If the variable declaration occurs within a procedure or function. you cannot initialize the
variable at the declaration unless it has been declared static. This is because storage within
routines is dynamic and so variables in them do not necessarily retain their values between
executions. For example, the following is incorrect:

FUNCTION do_nothing(IN OUT x

INTEGER) : BOOLEAN;

VAR
liar : BOOLEAN := false;

3-10

Data Types

{Wrong!}

This is the correct way to initialize the variable at its declaration in a routine:

liar : STATIC BOOLEAN := false;

{Right!}

See Chapter 7 for information on the static attribute.

3.5.2 DefIning Boolean Constants
To define a Boolean constant, simply write the name of the constant, followed by an equal
sign, and concluding with either true or false. For instance, the following excerpt defines
constant virtue and sets it to true:

CONST
virtue = true;
Notice that you do not enclose true or false inside a pair of apostrophes.

3.5.3 Internal Representation of Boolean Variables
Domain Pascal represents Boolean values in one byte. The system sets all eight bits to 1
for true and sets all eight bits to 0 for false. By default, Domain Pascal stores freestanding
Boolean objects on byte boundaries. However, a Boolean field in a packed record will
have a different allocation (see the "Internal Representation of Packed Records" section
later in this chapter for details).

3.6 Characters
This section describes how you declare a variable as a character data type, how you define
characters as constants, and how Domain Pascal represents characters internally.

3.6.1 Declaring Character Variables
Use the char type to declare a variable that holds one character; for example:
VAR

To declare a variable that holds more than one character you must use an array or the
predefined type string (both of which are detailed in the" Arrays" section later in this
chapter).

Data Types

3-11

3.6.2 Initializing Character Variables-Extension
Domain Pascal permits you to initialize the values of character variables within the variable
declaration in most cases. You initialize a value by placing a colon and equal sign (:=) immediately after the data type. For example, the following excerpts each declare cl as a
char variable with an initial value of a:

VAR
c1

CHAR.- 'a'; {you must enclose the character in single quotes}

VAR
c1 : CHAR := chr (65);
If the variable declaration occurs within a procedure or function, you cannot initialize the

variable at the declaration unless it has been declared static. This is because storage within
routines is dynamic and so variables in them do not necessarily retain their values between
executions.
For example, the following is incorrect:
FUNCTION do_nothing (IN OUT x

INTEGER)

BOOLEAN;

VAR
best_grade: CHAR := 'A';

{wrong!}

This is the correct way to initialize the variable at its declaration in a routine:
best_grade: STATIC CHAR := 'A';

{Right!}

See the" Accessing a Variable Stored in Another Pascal Module" and" Accessing a Routine Stored in Another Pascal Module" sections of Chapter 7 for· more information on the
static attribute.

3.6.3 Denning Character Constants
There are two common methods of assigning character constants. The first is to simply enclose a character inside a pair of single quotes. For example:
CONST
c1

=

'b';

This first method works only if the character is printable, but the second method works for
all ISO Latin-l characters (printable or not). The second method uses the chr function
(which is detailed in Chapter 4). As an example, suppose you want constant bell to contain the bell ringing character. The bell ringing character has an ISO Latin-l value of 7, so
to assign this value to constant bell you can make the following declaration:
CONST
bell

3-12

Data Types

CHR(7) ;

3.6.4 Internal Representation of Char Variables
Domain Pascal stores the ISO Latin-1 value of a char variable in one 8-bit byte. By default, freestanding char variables are byte aligned.

3.7 Enumerated Data
An enumerated data type consists of an ordered group of identifiers. The only value you
can assign to an enumerated variable is one of the identifiers from its group of identifiers.
Here are declarations for four enumerated variables:
VAR

citrus
(lemon, lime, orange, carambola, grapefruit);
primary_colors
(red, yellow, blue);
Beatles
(John, Paul, George, Ringo);
German_speaking_countries : (Germany, Switzerland, Austria);
In the code portion of your program, you can only assign the values red, yellow, or blue
to variable primary_colors.
Notice that the elements of an enumerated type must be identifiers. Identifiers cannot begin with a digit, so, for example, the following declaration produces an "Improper enumerated constant syntax" error:
VAR

first_six_primes : (2, 3, 5, 7, 11, 13);

{error}

3.7.1 Internal Representation of Enumerated Variables
Domain Pascal represents an enumerated variable in one 16-bit word. In this word, Domain Pascal stores an integer corresponding to the ordinal position of the current value of
the enumerated variable. For example, consider the following declaration:
VAR

pets: (cats, dogs, dolphins, gorillas, pythons);
Pets has five elements; Domain Pascal represents those five elements as integers from 0 to
4 as shown in Table 3-1.

Data Types

3-13

Table 3-1. Representation of an Enumerated Variable

Variable

Representation

pets :== cats

0000000000000000

.-

0000000000000001

pets

dogs

pets := dolphins
pets

.-

gorillas

pets := pythons

0000000000000010
0000000000000011
0000000000000100

3.8 Subrange Data
A variable with the subrange type has a valid range of values that is a subset of the range

of another type called the base type. When you define a subrange, you specify the lowest
and highest possible value of the base type. You can specify a subrange of integers, characters, or any previously defined enumerated type. The following fragment declares four different subrange variables:
TYPE
mountains = (Wachusett, Greylock,
Washington, Blanc, Everest);

{Mountains is an enumerated type.}

{The following four variables all have subrange types.}
{Subrange of INTEGER.}
teenage_years
13 .. 19;
positive_integers
1 .. MAXINT;
{Subrange of INTEGER.}
,
A'
..
'
Z'
;
capital_letters
{Subrange of CHAR.}
{Subrange of MOUNTAINS.}
small_mountains
Wachusett .. Washington;

VAR

Currently, Domain Pascal does not support subrange checking. For example, if you try to
assign the value 25 to teenage_years, Domain Pascal does not report an error. However,
you can use the in_range function to determine whether 25 is within the declared subrange. (See the "In_range" section of Chapter 4 for information on the in_range function.)

3.8.1 Internal Representation of Subranges
The storage allocation for subrange variables is the same as that for their base types. However, a subrange field in a packed record will have a different allocation. (See the "Internal Representation of Packed Records" section later in this chapter for details.)

3-14

Data Types

3.9 Sets
A set in Domain Pascal is similar to a set in standard mathematics. For instance, Domain
Pascal can compute unions and intersections of Domain Pascal set variables just as you can
find unions and intersections of two mathematical sets. Refer to the "Set Operations" listing in Chapter 4 for information on using sets in the action part of your program.

3.9.1 Declaring Set Variables
The format for specifying a set variable is as follows:

set of

boolean

I char I enumerated_type I subrange_type

For example, consider the following set declarations:

TYPE

very
lowints

(ochen, sehr, tres, muy);
O .. 100;

VAR
ASCII_values : set of char;
possibilities : set of boolean;
capital_letters: set of 'A' .. 'Z';
lots : set of very;
digits : set of lowints;

{Char is base type.}
{Boolean is base type.}
{Subrange of CHAR is base type.}
{Enumerated type is base type.}
{lowints is base type.}

If the base type is a subrange of integers, then the low end of the subrange cannot be a

negative number. Also, the high end of the subrange cannot exceed 1023.
NOTE:

Although Domain Pascal lets you declare packed set variables or
packed set types, the compiler ignores the designation. (That is,
the packed designation does not affect the amount of memory
the compiler uses to represent the set.) See Section 3.9.3 for
further information about the ihtefililrrepresentation of sets and a
description of a technique for the packing of small sets.

I

3.9.2 Initializing Set Variables-Extension
In most cases, you can initialize set variables with an assignment statement in the variable
declaration. For example, consider the following set variable initializations:

TYPE

unstable_elements

(U, PI, Ei, Ra, Xe);

VAR

letters: set of CHAR := ['A', 'E', 'I', '0', 'U'];
humanmade_elements : set of unstable elements .- [PI, Ei];

Data Types

•

3-15

If the variable declaration occurs within a procedure or function, you cannot initialize the

variable at the declaration unless it has been declared static. This is because storage within
routines is dynamic and so variables in them do not necessarily retain their values between
executions. For example, the following is incorrect:

FUNCTION assign_grades(IN OUT score : INTEGER)
BOOLEAN;
VAR
grades: set of CHAR := ['A', 'B', 'C', 'D', 'E'];

{Wrong!}

This is the correct way to initialize the variable at its declaration in a routine:

grades : STATIC set of CHAR : = ['A', 'B', 'C', 'D', 'E'];

{Right! }

See the "Accessing a Variable Stored in Another Pascal Module" and" Accessing a Routine Stored in Another Pascal Module" sections of Chapter 7 for more information on the
static attribute.
Refer to the "Set Operations" listing in Chapter 4 for more information on set assignment.

3.9.3 Internal Representation of Sets

I

I

A set can contain up to 1024 elements; their ordinal values are 0 to 1023. Sets are stored
as bit masks, with one bit representing one element of the set. The number of bits that
Domain Pascal allocates to a set is the number of elements in the set, rounded up to a
multiple of 16 bits. That is, a set occupies the minimum number of words that provides
one bit per element. Consequently, the minimum storage size for a set is one word (16
bits) and the maximum size is 64 words (1024 bits). The one exception to this is small
sets within a packed records. See Section 3.10.7 for a technique that packs small sets
within a packed record.
For example, suppose you define an enumerated type named Greek_letters, with values
Alpha, Beta, Gamma, and so forth, up to Omega. You can then declare a set of
Greek_letters as follows:

VAR
Greek_alphabet : SET of Greek_letters
Greek_alphabet has 24 values, and therefore, Greek_alphabet requires at least 24 bits.
The nearest word boundary is 32 bits, so Domain Pascal allocates 32 bits (2 words) for the
variable. It then stores the values as shown in Figure 3-6:
15

o 15

7
Omega

I

3

I

Gamma

Figure 3-6. Storage of Sample Set

3-16

Data Types

I

Word 2

Word 1

o

2
Beta

Alpha

I

If the base type of the set is a subrange of integers or a subrange of char, then the ordinal

value of the high end of the subrange determines the amount of space required to store
the set. For example, consider the following two set declarations:
TYPE

possible_values
small_letters

80 .. 170;
'a' .. 'z';

VAR

pos
sma

set of possible_values;
set of small_letters;

Domain Pascal stores variable pos in 11 words (176 bits). That is because the highest ordinal value of the base type (possible_values) is 170. The next word boundary up from 170
is 176.
Domain Pascal stores variable sma in eight words (128 bits). In the base type (small_letters), the ordinal value of z is 122. The next word boundary up from 122 is 128.

3.10 Records
A record variable is composed of one or more different components (called fields) which
may have different types. Domain Pascal supports the two standard kinds of records: fixed
records and variant records. The following subsections describe both kinds.

3.10.1 Fixed Records
A fixed record consists of zero or more fields. Each field can have any valid Domain Pas-

cal data type. To declare a fixed record type, issue a declaration of the following format:
type

record_name = record
field1

fieldN
end;
Each field has the following format:

field_name 1 , ... field_nameN : typename;

Data Types

3-17

For example, consider the following three record declarations:
TYPE

student

record
name
id

{Contains two fields.}
array[1 .. 30] of char;
INTEGER16;

end;
element

record
name
symbol
atomic_number
atomic_weight

{Contains four fields.}
array[1 .. 15] of char;
array[1 .. 2] of char;
1 .. 120;
real;

record
station
sky_condition
windspeed
winddirection
pressure

{Contains five fields.}
array[1 .. 3] of char;
(fair, ptly_cloudy, cloudy);
1 .. 100;
1 .. 360;
single;

end;
weather

end;
VAR

new_students
noble_gases
w1

student;
element;
weather;

Note that you can declare a record type as the data type of a field. For example, notice
the changes in the declaration of the record weather:
TYPE
wind

record
speed: 1 .. 100;
direction: 1 .. 360;

end;
weather

end;

3-18

Data Types

record
station
sky_condition
gradient
pressure

array[1 .. 3] of char;
(fair, ptly_cloudy, cloudy);
wind;
single;

NOTE:

A common mistake is to misuse the equal sign (=) and the
colon (:). When declaring a record in the type declaration part,
put an equal sign between the name of the record and the keyword 'record. For example:
type
weather = record ...
When declaring a record in the var declaration part, put a colon
between them. For example:
var
wI : weather;

3.10.2 Variant Records
A variant record is a record with multiple data type possibilities. When you declare a variant record, you specify all the possible data types that the record can have. You also specify the condition for selecting among the multiple possibilities.
In other words, at run time a fixed record variable has the same group of data types from
one use of the variable to another. However, a variant record variable has a flexible group
of data types from one use of the variable to another.
The variant record has the following format:
type

record_name = record
fixedyart;
variant yart;
end;
The fixedyart of a variant record is optional. It looks just like a fixed record. In other
words, the fixed yart consists of one or more fields each having the following format:

field_name 1 , ... field_nameN : typename;
The variantyart of a variant record takes the following format:

case [tagJield] typename of
constantlist 1: (field; ... jieldN);

constantlistN: (field; ... fieldN);
The constantlist is one or more constants that share the same data type. For instance, if
typename is integer, then every constant in constantlist must be an integer. You associate
one or more fields with each constantlist. With one exception, each field has the same
syntax as a field in the fixed part. The one exception is that fieldN can itself be a variantJart.

Data Types

3-19

Note that you can optionally associate a tagJield with the typename. The tagJield is simply an identifier followed by a colon (:). You can use the tagJield to select the desired
variant at run time. For more information on tagJields, see the "Record Operations" listing in Chapter 4.
Consider the following declaration for variant record type worker. Worker contains a fixed
part and a variant part. The fixed part contains two fields (employee and id_number).
The typename of the variant part is worker_groups, which is an enumerated type. Wo has
two possible values, exempt and non_exempt. When wo is exempt, the field name is
yearly_salary which is an integer32 data type, and when wo is non_exempt, the field
name is hourly_wage which has a real data type.

TYPE
worker_groups = (exempt, non exempt);
{enumerated
{record
worker = record
employee: array[I .. 30] of char;
{field in fixed
id_number : integerl6;
{field in fixed
CASE wo
worker_groups OF
{variant
exempt : (yearly_salary
integer32);
non_exempt : (hourly_wage
real) ;
end:

type}
type}
part}
part}
part}

Consider the following declaration for my_code, a variant record that does not contain a
fixed part. The data type of the variant part is integer, so the case portion declares integer
constants. Choosing 1, 2, 3, and 4 as the constants is totally arbitrary; you could pick any
four integers. These constants serve no purpose except to establish the fact that there are
four choices. The fields themselves provide four different ways to view the same 4-byte
section of main memory.
my_code = record
CASE integer OF
I
(all: array[I .. 4] of char);
2
(first_half: array[I .. 2] of char;
second_half: array[I .. 2] of char);
3
(xl
integerl6;
x2 : boolean;
x3 : char);
4
(raIl: single);
end;
NOTE:

3-20

Data Types

{variant part}

The preceding example shows four parts that take up exactly four
bytes. However, it is perfectly valid to declare parts that take up
differing numbers of bytes.

3.10.3 Unpacked Records and Packed Records
Domain Pascal supports regular (unpacked) records and "packed" records. You declare a
packed record by putting the keyword packed prior to record in the record declaration;
for example:
VAR

student

PACKED record
ages : 10 .. 20 ;
grade: (seventh, eighth, ninth, tenth, eleventh, twelfth);
graduating : boolean;

end;
The advantage to declaring a packed record is that it can save space. The disadvantage is
that you cannot pass a field from a packed record as an argument to a procedure (including predeclared procedures like read). The next subsection details the space savings of
packing. Note that you should not directly manipulate fields in a packed record. If you
want to perform some operation that changes the value of an existing field in a packed
record, use the following steps:
1. Assign the value of the field to a variable of the same type.

2. Perform the operation on the variable.
3. Assign the value of the variable to the field of the packed record.

3.10.4 Initializing Data in a Record-Extension
Domain Pascal permits you to initialize a record in the variable declaration portion of the
program unless that declaration comes within a procedure or function and the record has
not been declared static. (See the "Accessing a Variable Stored in Another Pascal Module" and" Accessing a Routine Stored in Another Pascal Module" sections of Chapter 7
for more information on the static attribute.) You can initialize some or all of the fields
in a record.
To initialize a field in a record, enter a declaration with the following format:
var

name_ol_record_variable : type_ol_record :=
[in it ,

·
·

·

,
,
,

init ];

where init is a statement having one of the following formats:

or

initial_value

Data Types

3-21

If you use the second format, Domain Pascal assumes that the initial_value applies to the

next field_name in the record definition. For example, consider this record initialization:

TYPE

messy

record
rx
real;
c
: char;
abc: array[1 .. 3] of integer;
case integer of
o (i32: integer32);
1
(i16: integer);
2
(hb, lb : char);
end;

VAR

very

MESSY:=
[ c : = 'X',
[ -1, -2, -3],

rx := 123.456,
'Y',

lb := 'a',
hb := 'z' ];
The preceding example initializes field c to 'X'. The next declaration [-1, -2, -3] applies
to field abc (because it follows field c). Field rx gets initialized to 123.456. Then, field c
gets reinitialized to 'Y' (because it follows field rx). Finally, the third field in the variant
portion of the record gets initialized, with field Ib getting the value 'a' and field hb getting
set to 'z'.

3.10.5 Internal Representation of Unpacked Records
In order to understand the internal representation of unpacked records, you need to understand the following concepts:
•

Alignment

•

Natural alignment

•

Guaranteed default alignment

•

Default alignment

•

Layout of records

•

Memory allocation

•

Arranging record fields in descending order by size

We describe each of these concepts in the following sections.

3-22

Data Types

3.10.5.1 Alignment
An object's alignment is the set of addresses at which the compiler can allocate the object. For example, the compiler can allocate byte aligned objects on any byte boundary;
it can allocate word aligned objects only at addresses that are evenly divisible by 2 (word
boundaries, or shortword boundaries); and it can allocate longword aligned objects only
at addresses that are evenly divisible by four (longword boundaries).

3.10.5.2 Natural Alignment
An object is naturally aligned if it begins at an address that is a mUltiple of its size in
bytes. For example, a 2-byte integer is naturally aligned if it starts on an even address
boundary. Similarly, an 8-byte double-precision floating-point number is naturally aligned
if it starts on an address divisible by 8. A record is considered to be naturally aligned when
it starts on a boundary that results in natural alignment for its fields.
Since char and boolean type values are one byte long, their natural alignment is byte
aligned. Similarly, since integer and integer16 values are two bytes long, their natural
alignment is word aligned. Since real, single, integer32, and pointer types are four bytes
long, their natural alignment is longword aligned. And, since double types are eight bytes
long, their natural alignment is quadword aligned. Figure 3-7 illustrates natural alignment
for these simple data types.

3.10.5.3 Guaranteed Default Alignment of Record Fields
A type's guaranteed default alignment is not necessarily the same as its natural alignment.
A type's guaranteed default alignment is the alignment it is guaranteed if a field of that
type is a component of a record. The guaranteed default alignment of types char and
boolean is byte alignment, which also happens to be the natural alignment for these types.
However, the guaranteed default alignment for the other unstructured types (integer, integer16, real, single, integer32, pointer, and double) is word alignment. Table 3-2 compares the guaranteed default and natural alignments of the simple data types.

Data Types

3-23

Table 3-2. Guaranteed Default and Natural Alignment for Simple Data Types
Data Type

3-24

Data Types

Guaranteed
Default Alignment

Natural Alignment

char

byte

byte

boolean

byte

byte

integer

word

word

integer16

word

word

real

word

longword

single

word

longword

integer32

word

longword

pointer

word

longword

double

word

quadword

longword __ .......
- - - - - - 1 word----·~~
boundary
char1
char2
shortword __
boundary
bool1
bool2
BYTE ALIGNMENT

longword __
boundary

natural_integer

shortword __
boundary

naturaLinteger18
WORD ALIGNMENT

longword __
boundary
shortword __
boundary

natural_pointer

longword __
boundary
shortword __
boundary
longword __
boundary
shortword __
boundary
longword __
boundary
shortword __
boundary

natural_integer32

LONGWORD ALIGNMENT

quadword __
boundary
shortword __
boundary
longword __
boundary

natural_double

shortword __
boundary
QUAD WORD ALIGNMENT

Figure 3-7. Natural Alignment for Pascal Simple Data Types

Data Types

3-25

3.10.5.4 Default Alignment
The default alignment of a simple data type is the same as its natural alignment.
For the structured data types, such as records, default alignment is somewhat complex.
The default alignment rules affect two properties of records:
•

How fields are laid out in the record (whether padding is inserted between fields).

•

How memory for the entire record is allocated.

We describe these two properties in the next two sections.

3.10.5.5 Layout of Unpacked Records
Domain Pascal follows these rules for the layout of unpacked records:
•

The size of a record must be an even number of bytes. There is no way to override this rule. This means that the smallest possible record is 2 bytes.

•

The default alignment of the beginning of a record is at least word aligned.

•

By default, Domain Pascal allocates the same amount of space for each field in a
record that the field would have required if it were not part of the record. For
example, the compiler allocates one byte for a char field.

•

By default, the compiler lays out record fields based on their guaranteed default
alignment. Thus, all objects longer than a byte are aligned on word boundaries.
Objects which are chars and booleans may be aligned on byte boundaries.

•

By default, the compiler aligns a record according to the largest alignment of its
fields.

•

A byte aligned field may not cross two word boundaries. This means that a

32-bit object, such as an integer32 type variable, cannot be byte aligned.
The default alignment rules for the layout of records can produce padding (also called
"holes" or "gaps") in a structure. However, each gap is never larger than one byte.
For example, consider the following record declaration:

81 == record
a: integer32;
b: char;
c: integer16
end;
Figure 3-8 shows how the fields for SI records are laid out. Note that there is a byte of
padding inserted after b to ensure that c is aligned on a word boundary.

3-26

Data Types

....4 - - - - 1 word

a

b

c
Figure 3-8. Default Layout of Record S1
Since the total size of a record must be a multiple of two bytes, records sometimes have a
byte of padding at the end. Figure 3-9 shows the layout of a record that contains a gap in
the middle and a gap at the end as a result of the default alignment rules.
82

= record
c1: char;
81: integer16;
c2: char
end;

Figure 3-9. Layout of Record S2

3.10. S. 6 Memory Allocation
Domain Pascal always allocates a record on at least a word boundary. It allocates a record
on a larger boundary if that larger allocation produces natural alignment for any of the record's fields. Specifically, the compiler uses the following algorithm to allocate records:
1. It assumes that the starting address of the record is zero.

2. It lays out the fields in the order they are declared, noting which fields are naturally aligned.
3. It looks for the largest naturally aligned field.
4. The compiler allocates the entire record on a boundary that matches the natural
alignment for the field it identified in Step 3.

Data Types

3-27

Note that the compiler must layout the record before it allocates memory for it.
Consider the following record type:

83 = record
integer32;
char;
integer16

a

b
c

end;
.....
- - - - - 1 word - - - ...

o
a

2
4

b

6

c

Figure 3-10. Naturally Aligned Record S3 with 1-Byte Padding
Figure 3-10 shows the layout for S3. The compiler assumes a beginning address of 0 and
lays out the fields according to the default alignment rules. For this record, the default
alignment rules produce a layout in which all elements are naturally aligned. The compiler
then searches for the largest field that is naturally aligned, which is a. Since a's natural
alignment is longword, the compiler allocates records of type S3 on longword boundaries.
Consider a second example:

84 = record
a
b

integer16;
integer32

end;
Figure 3-11 shows the layout for S4. In this case, a is naturally aligned. However, b is
not naturally aligned because its offset from the start of the record, which is 2, is not
evenly divisible by its size, which is 4. The largest field in S4 that is naturally aligned,
therefore, is a. The compiler uses word alignment, which is the natural alignment of a, to
allocate records of type S4.

3-28

Data Types

o
2

b
4

Figure 3-11. Layout of S4 Using Word Alignment

3.10.5.7 Arranging Record Fields in Descending Order by Size

You can usually improve the efficiency of memory accesses significantly by carefully arranging fields within records. The best guideline to improve access efficiency when you set up
natural alignment for records is to arrange record fields in descending order by size. Consider the following example:

FOO = record
a:char;
b:integer16;
c:char;
d:double;
e:integer32
end;
By default, this declaration will produce the memory arrangement shown in Figure 3-12.
Due to a poor ordering of fields, there are 4 bytes of gaps and members d and e are not
naturally aligned.

Data Types

3-29

~

0

1 word

a

•

2
4

c
6
8
d
10
12
14

e
16

Figure 3-12. Memory Arrangement for Record with Poorly Arranged Fields
Following the preceding rule of arranging fields according to descending order by size, you
change the declaration to:

FOO = record
d: double;
e: integer32;
b: integer16;
a, c: char
end;
The above declaration produces the memory arrangement shown in Figure 3-13. All fields
are naturally aligned and padding fields are not necessary to achieve natural alignment for
the record.

3-30

Data Types

-4

.

1 word

0
2
d
4

6
8

•

10
12

b
14
8

c

Figure 3-13. Memory Arrangement According to Decreasing Size of Fields

NOTE:

You can usually guarantee that all fields of a record will be naturally aligned by arranging the fields in descending order of size.
This will always work if all the fields are scalar objects. This technique may not work if one or more of the record fields is a record
or array. Arranging fields in decreasing order of size also guarantees that there will be no padding between record fields, although
there might still be a byte of padding at the end of the record to
make it an even number of bytes.

In some instances, a record that would normally be allocated on a longword or quadword
boundary receives a different allocation because the record is part of a larger aggregate
type (e.g., a record or array). For example, consider the declaration of Sl:

81 = record
x: integer32;
y: integer16
end;
The compiler can guarantee that an individual record of type S 1 will be allocated on a
longword boundary (so that x and y will be naturally aligned), but if you declare an array
of three Sl records, only two-thirds of them will be aligned on longword boundaries:

Data Types

3-31

Figure 3-14 shows the layout of an array of three S1 records. Note that the second element is aligned on a word (2-byte) boundary, not a longword (4-byte) boundary, and so
the second element is not naturally. aligned.

~

1 word

0
2

..

x

4
6

8

x

10
12
14

x

16

Figure 3-14. Array of Sl Records, Not Naturally Aligned

To ensure that all elements of array_of_sl_records are naturally aligned, you need to insert an additional word of padding at the end of S 1. You could do this explicitly, as
shown in the following declaration:
51

record
x: integer32;
y: integer16;
padding: integer16
end;

You could also tell the compiler to add the padding by using the natural or aligned attributes in the record declaration or by specifying a %natural_alignment compiler directive.
See the" Attributes" section of this chapter for details about the natural and aligned attributes. See the "Compiler Directives" section of Chapter 4 for details about the %naturat_alignment compiler directive.

3-32

Data Types

3.10.6 Aligned Record and Unaligned Record Data Type
To make sure that records are always naturally aligned regardless of the alignment environment, you can use the aligned record data type. The alignment environment is the alignment that you set when you use compiler directives or the default alignment that is set by
the compiler.
For example, the %natural_alignment directive tells the compiler to use natural alignment
for any data that does not have an alignment attribute in its declaration. (See the "Compiler Directives" section of Chapter 4 for more details about the %natural_alignment and
%word_ align men t directives.)
To declare an aligned record data type, use the following syntax:
type

record_name =

aligned record
field] ;
field2;

fieldN;
end;
Note that the aligned record data type sets alignment for records only. The aligned and
natural attributes set alignment for records and fields.
The syntax for the aligned record data type is just like the syntax for a regular Domain
Pascal record except that you use aligned record instead of record. For example, consider the following declaration:
TYPE

nat_ree

ALIGNED RECORD
a : integer;
b : integer32;
END;

The above declaration defines an object of type nat_rec to be a record laid out as shown
in Figure 3-15.

Data Types

3-33

word

a

Figure 3-15. An Aligned Record Type Record

All nat_rec type objects will have the layout shown in Figure 3-15 even if they are in programs compiled with a %word_alignment directive.
To make sure that records are aligned according to word alignment rules regardless of their
alignment environment, use the unaligned record data type. To declare an unaligned
record type, use the following syntax:
type
record_name

=

unaligned record
field1 ;
field2;
fieldN;
end;

Note that the syntax for the unaligned record data type is just like the syntax for a regular Domain Pascal record except that you use unaligned record instead of record. For
example, consider the following declaration:
TYPE

not nat ree

UNALIGNED RECORD
a : integer;
b : integer32;
END;

The preceding declaration defines an object of type not_nat_rec to be a record laid out as
shown in Figure 3-16.

3-34

Data Types

...~----- 1 word

a
b
1-------------------------

Figure 3-16. An Unaligned Record Type Record
All not_nat_rec type objects will have the layout shown in Figure 3-16 even if they are in
programs compiled with a "natural_alignment directive.

3.10.7 Internal Representation of Packed Records
Table 3-3 shows the space required for fields in packed records.
Domain Pascal always starts the first field of a packed record on a word boundary. After
the first field, if the exact number of bits required for the next field crosses zero or one
16-bit boundary, the field starts in the next free bit. If the field would cross two or more
16-bit boundaries, it starts at the next 16-bit boundary. Pascal allocates fields left to right
within bytes and then by increasing byte address.
The minimum size of a packed record is 16 bits.
In packed records, characters are byte aligned. Structured types, except for sets, are
aligned on word boundaries. Sets are aligned only if they cross two or more 16-bit
boundaries.

Data Types

3-35

Table 3-3. Storage of Packed Record Fields
Data Type of Field

Space Allocation

Integer; Integer16

16 bits; word aligned.

Integer32, Real, Single

32 bits; word aligned.

Double

64 bits; word aligned.

Boolean

1 bit; bit aligned.

Char

8 bits; byte aligned

Enumerated

Number of bits required for largest ordinal value;
bit aligned.

Subrange

Subrange of char fields require eight bits; all
other subrange fields take up the number of bits
required for their extreme values. Subrange of char
fields are byte aligned. All other subrange fields are
bit aligned.

Set

If fewer than 32 elements, then exactly one bit per
element; if more then 32 elements, then same size as
set. Bit aligned.

Array

Mayor may not be packed; requires the same space
as an array outside of a packed record. (See the
"Internal Representation of Arrays" section.)

Pointer

32 bits; word aligned.

The following type declaration, along with Figure 3-17, illustrates the storage of a packed
record type.

TYPE
Shapes = (Sphere, Cube, Ovoid, Cylinder, Tetrahedron);
Uses = (Toy, Tool, Weapon, Food);
Characteristics = PACKED RECORD
Mass
Real;
Shape
Shapes;
Boolean;
B
Purpose
SET OF Uses;
Low_temp
-100 .. 40;
Class
'A' .. 'Z';
end;

3-36

Data Types

The fields require the following number of bits:

Mass
Shape
B

Purpose
Low_temp
Class

32
3
1
4
8
8

bits
bits
bit
bits
bits
bits

(word aligned)
(bit aligned)
(bit aligned)
(bit aligned)
(bit aligned)
(word aligned)

(The variable low_temp requires eight bits because it can take a range of 140 values (-100
to +40) and seven bits can represent only 128 values.)
Domain Pascal represents fields in the same order you declared them, as shown in
Figure 3-17.

15

131211

o

8 7
Mass
Mass

Shape

1sl Purpose
Class

Low temp
Unused

Figure 3-17. Sample Packed Record

In this example, the order of field declaration has been chosen very carefully. The whole
record takes up only eight bytes, and out of the eight bytes, only eight bits are unused. If
the fields had been declared in a different order, the record might have taken up 10 or 12
bytes.

3.11 Arrays
Like standard Pascal, Domain Pascal supports array types. An array consists of a fixed
number of elements of the same data type. This data type is called the component type.
The component type can be any predeclared or user-declared data type.
Use an index type to specify the number of elements the array contains. The index type
must be a subrange expression. Domain Pascal permits arrays of up to eight dimensions.
Specify one subrange expression for each dimension.

Data Types

3-37

This fragment includes declarations for five arrays:

TYPE
elements

(H, He, Li, Be, B, C, N, 0, FI, Ne);
{elements is an enumerated type.}

VAR

test_data
atomic_weights
last_name
a_thought
lie_test

{Here are the five array declarations.}
array[1 .. 100] of INTEGER16;
array[H .. Be] of REAL;
{Range defined in TYPE}
{declaration.
}
array[1 .. 15] of CHAR;
STRING;
array[l .. 4,1 .. 2] of BOOLEAN; {2-dimensional array.}

Notice that variable a_thought is of type string. String is a predefined Domain Pascal array type. Domain Pascal defines string as follows:

TYPE
string

= array[1 .. 80]

of CHAR;

In other words, string is a data type of 80 characters. Use string to handle lines of text
conveniently.
See the" Array Operations" listing in Chapter 4 for a description of array bound checking.

3.11.1 Initializing Array Variables-Extension
If an array has been declared static or its declaration is not in a function or procedure,

you can initialize array components in Domain Pascal in a variable declaration statement.
(See the "Accessing a Variable Stored in Another Pascal Module" and "Accessing a RoUtine Stored in Another Pascal Module" sections of Chapter 7 for more information on the
static attribute.) Domain Pascal initializes only those components for which it finds initialization data; it does not initialize the other components. For example, if an array consists
of 10 components and you specify six initialization constants, Domain Pascal initializes the
first six components and leaves the remaining four components uninitialized.
This section describes the following three basic methods of initializing single-dimensional
and multidimensional arrays:

I

•

Initializing mUltiple components to a single value

•

Initializing components individually

•

Initializing using repeat counts

In addition, this section describes controlling the order of initialization and setting a default
for the size of the array.

3-38

Data Types

3.11.1.1

Initializing Multiple Components with a SingBe Expression-Extension

To initialize multiple components with a single expression, specify an assignment operator
(:=) followed by the value. This initialization method is especially useful for components of
type char, where the value is a string of characters. You can also initialize the char components individually, but it's usually easier to do it as a string.
For example, consider the following single-dimensional initializations:
CONST
msg1

= 'This is message 1';

VAR
sl
s2
blank_line

.-

array [1 .. 40] of CHAR
'Quoted strings are ok';
array [1 .. 30] of CHAR := msg1;
STRING
.- chr(lO) ; {Newline}

These initializations assign elements 1 through 21 of array sl with the string "Quoted
strings are ok", elements 1 through 17 of array s2 with "This is message 1", and element
1 of blank_line with the newline character.
You can also use this method to initialize multidimensional arrays. To do this, you must
assign the value to each row. For example the following initialization statement initializes
columns 1 through 6 in rows 1 and 2 to 0:

VAR
I2

array[1 .. 2, 1 .. 6] of INTEGER16 .- [
[1 .. 6 .- 0],
[1 .. 6 .- 0],
] ;

3.11.1.2

Initializing Components to Individual Values-Extension

To initialize array components individually, specify an assignment operator (:=) followed by
the values to which the components should be initialized. You must enclose the values inside a pair of brackets and separate each value with a comma.
For example, consider the following single-dimensional array initializations:

VAR
I
R
B

array[1 .. 6] of INTEGER16 := [1, 2, 4, 8, 16, 32];
array[1 .. 3] of SINGLE := [-5.2, -7.3, -2E-3];
array[l .. S] of BOOLEAN := [true, false, true, true, true];

Data Types

3-39

I

You can also use this method . (and the method described in Section 3.11.1. 1) to initialize
multidimensional arrays. For example, the following fragment initializes two multidimensional arrays (12 and B2). 12 has two subrange index types (1..2 and 1..6). The first index
type consists of two values, so you must supply two rows of brackets. The second index is
1.. 6, so you must specify six values for each row, initializing a total of 12 components.

VAR
I2

array[I .. 2, 1 .. 6] of INTEGER16 .[1,2,3,4,5,6],
[7,5,9,1,2,8],
] ;

B2

array[I .. 4, 1 .. 3] of BOOLEAN .[true, true,
[true, false,
[false, true,
[false, false,

true],
false],
false],
false],

] ;

3.11.1.3 Initializing Arrays Using Repeat Counts-Extension
Repeat counts let you initialize groups of elements in an array. There are two forms of
repeat counts.
The first form takes the following syntax:

n of constant
where of is a keyword, n is an integer, and constant is any valid constant that corresponds
to the data type specified in the declaration of the array.
This form tells the compiler to initialize n components of the array to the value of constant. n can be an integer or an expression that evaluates to an integer. The following
initializations demonstrate this form of the repeat count:
CONST

x = 50;

VAR
a
b

array[I .. 1024] of INTEGER16 := [512 OF 0, 512 OF -1];
array[I .. 400] of REAL := [x of 3.14, 400-x OF 2.7];

In the preceding example, Domain Pascal initializes the first 512 values of array a to 0 and
the second 512 values to -1. Domain Pascal also initializes the first 50 components of array b to 3.14 and the remaining 350 components to 2.7.
The second form of the repeat count takes the following syntax:
• of constant

3-40

Data Types

The asterisk (.) tells Domain Pascal to initialize the remainder of the components in the
array to the value of constant. The following initializations demonstrate this form of the
repeat count:

VAR
c
d

array[l .. 2000] of INTEGER16 := [* of 0];
array[1 .. 50] of BOOLEAN := [12 of true, * of false];

In the preceding example, Domain Pascal initializes all 2000 components in array c to O.
Domain Pascal also initializes the first 12 components of array d to true and the remaining
38 components to false.
You can use repeat counts to initialize multidimensional arrays. You must initialize a multidimensional array column by column rather than all at once. For example, compare the
right and wrong ways to initialize a 2-dimensional array:

VAR
x
Y

z

array[l .. 2, 1 .. 5] of INTEGER16
array[l .. 2, 1 .. 5] of INTEGER16
array[l .. 2, 1 .. 5] of INTEGER16

..-

.-

[10 of 0];
of 0];

[*
[

{wrong!}
{wrong!}

[5 of 0] ,
of 0] ,

[5
] ;

q

{Right!}

array[l .. 2, 1 .. 5] of INTEGER16 .- [
of 0] ,
[* of 0] ,

[*
] ;

3.11.1.4

{Right!}

Initializing Components in Any Order-Extension

You can initialize array components in any order. Consider the following initialization
statements:

VAR
C1

array[1 .. 7] of INTEGER .[

3 .. 4
7

2,

.-

1

-1

3

] ;

These statements produce the following initializations:
Component
Component
Component
Component
Component
Component
Component

1
2
3
4
5
6
7

= 3

=
=
=
=
=
=

undefined
2
2
undefined
undefined
-1

Data Types

3-41

3.11.1.5 Defaulting the Size of an Array-Extension
When you initialize an array in the var declaration part of a program, you can let Domain
Pascal determine the size of the array for you. To do this, put an asterisk (*) in place of
the upper bound of the array declaration.
For example, in the following fragment, the upper bound of init4 is 18; the upper bound
of initS is 22; and the upper bound of init6 is 4. The compiler defines the upper bound
once it has counted the number of initializers.

CONST
msg5

=

'And this is message 5.';

VAR
init4
initS
init6

ARRAY[l .. *] of CHAR := 'This is message 4.';
ARRAY[l .. *l of CHAR := msg5;
ARRAY[l .. *] of INTEGER16 := [1, -17, 35, 46];

NOTE:

You can use an asterisk in the index type only if you supply an
initialization value for the array. For example, the following fragment causes a "Size of TABLEt is zero" warning:

VAR
table1

3-42

Data Types

array[l .. *] of integer16;

3.11.1. 6 Mixing Methods of Array Initialization-Extension
You can combine all methods of array initialization described in this section. The following example illustrates the use of the methods to initialize an array named array_example:

CONST
x

= 100;

TYPE
subr

one, two, three, four, five, six, seven, eight, nine,
ten, eleven, twelve );

VAR

array_example; ARRAY [subr] OF integer :=
[

2 of -1,

{repeat count method}

four .. five := 47,

{initializing multiple components
to a single value}

2 of x,

{repeat count method}

42,

{initializing components
individually}

ten .. *

.-

814

{initializing multiple components
to a single value}

] ;

The results of the preceding declarations are:
Component
Component
Component
Component
Component
Component
Component
Component
Component
Component
Component
Component

1 = -1
2 = -1
3 = undefined
4 = 47
5 = 47
6 = 100
7 = 100
8 = 42
9 = undefined
10 = 814
11 = 814
12 = 814

Data Types

3-43

\

3.11.2 Variable-Length Arrays-Extension
Domain Pascal supports an array data type that enables you to construct and manipulate
variable-length strings. A variable-length string is a string whose length can change dynamically during program execution. This is in contrast to a fixed-length string whose
length is specified by the subrange expression in its declaration. Although the size of a
variable-length string can change, it cannot exceed a maximum, which you specify in the
declaration.
The syntax for declaring a variable-length string is:

varying[max_length] of char;
where max_length is a positive integer between 1 and 65535.
For example, the following are legal declarations:

VAR
short_string
long_string
array_of_var_str

VARYING [10) of CHAR;
VARYING [10000) of CHAR;
ARRAY[1 .. 5) of VARYING[20) of CHAR;

It is illegal to use the varying type specifier with any type other than char.
When you declare a variable-length string, the compiler allocates enough memory to hold
a string of the maximum length. You can assign strings of any length not greater than the
maximum to the array. When the variable-length string is read, only as many. characters
as indicated by the current length are accessed.
Internally, the compiler translates the varying type into a record of the form:

RECORD
length: 0 .. 65535;
body: PACKED ARRAY[l .. max_length) of CHAR;
{unnamed filler}
END;
The length field contains the current length of the string. When you assign a string to a
variable-length character array, the compiler adjusts the value of length to reflect the size
of the assigned string. The body field contains the actual string. Following the body field,
the compiler allocates additional bytes, if necessary, for a trailing null character and padding. The trailing null character and pad bytes are described in the following section.
You can reference the length and body fields explicitly by using the same syntax and semantics you would use for a normal record. For example:
cur_length := short_string. length;
last_char := short_string.body[short_string.length);

3-44

Data Types

Be aware that if you update the character string in the body field. it will not automatically
update the value in the length field.
It is illegal to subscript a variable-length array. For example:
VAR

var_string

VARYING [100] of CHAR;

var_string[5] .- 'a';

{ ILLEGAL }

To access a particular element in a variable-length string. subscript into the body field.

3.11.3 Packed Arrays
Like standard Pascal. Domain Pascal allows you to use packed arrays to store sequences of
characters. byte integers. and boolean variables. To declare a packed array. use the following format:
var
name_oJ_array : packed array [low_value .. high_value] of variable_type;

For example. consider the following variable declarations:
VAR

switches: PACKED ARRAY [1 .. 100] OF boolean;
names: PACKED ARRAY [1 .. 25] OF char;
numbers: PACKED ARRAY [0 .. 100] OF integer;
Although you can save space by using packed arrays, you may pay a price in the efficiency
of loading from and storing to elements in the arrays.

3.11.4 Internal Representation of Arrays
Packed arrays usually require less storage space than arrays that are not packed. In this
section we describe how both types of arrays are represented internally.

3.11.4.1 Non-Packed Arrays
With two exceptions. the total amount of memory required to store an array that is not
packed equals the number of elements in the array times the amount of space required to
store one element. The amount of space for one element depends on the component type
of the array. as shown in Table 3-4.

Data Types

3-45

Table 3-4. Size of One Element of an Array
Base Data Type

Size of One Element

Integer 16 or Integer

16 bits

Integer32
Single or Real

32 bits

Double

64 bits

Boolean

8 bits

Char

8 bits

Subrange

size of base type of subrange

Enumerated

16 bits

32 bits

The two exceptions to this rule are arrays of booleans and varying arrays of chars.
If the component type of an array is boolean and an odd number of elements are de-

clared, the compiler adds an extra pad byte to the storage space for the array so that the
storage is an even number of bytes. For example, if you declare boolean array b as

VAR
b

: array[1 .. 5] of boolean;

Domain Pascal reserves six bytes of memory for b.
A variable-length string always begins with a 2-byte length field, followed by the body

field, followed by padding. The body field must always be capable of holding a null character at the position just beyond the current length. Consequently, the compiler always
allocates to the body field one byte more than the maximum length specified in the declaration. The compiler adds 2 or 3 bytes of padding to make the total size of the string an
even number of longwords (4 bytes).
In summary, to figure the total number of bytes allocated for a variable-length string: add
either 5 or 6 bytes to the number of bytes specified as the maximum length for the string
such that the total number of bytes is an even number. For instance:

VAR
v2:
v7:
vB:

VARYING [2] OF CHAR;
VARYING [7] OF CHAR;
VARYING[B] OF CHAR;

{B bytes are allocated}
{12 bytes are allocated}
{14 bytes are allocated}

Multidimensional Arrays
Multidimensional arrays are stored in row major order. Given a 2-dimensional array of
the following declaration:

a : array[1 .. 2, 1 .. 3] of integer16;

3-46

Data Types

Domain Pascal represents it in the following order:
a[l,l]
a[l,2]
a[l,3]
a[2,l]
a[2,2]
a[2,3]

first
second
third
fourth
fifth
sixth

3.11.4.2 Packed Arrays
Table 3-5 shows the space required for each type of element in a packed array.
Table 3-5. Storage of Packed Array Elements
Type of Element

Space Allocation

Subranges of integers
Enumerated
Subrange of enumerated

Exact number of bits required .;
bit aligned ••

Integer
Integer16

16 bits; word aligned

Boolean

1 bit; bit aligned

Real
Integer32
Pointer

32 bits; word aligned

Double

64 bits; word aligned

Character
Subrange of character

8 bits; byte aligned

Character array

Exact number of bytes required; byte
aligned

Record
Array of non-characters

Exact number of words required; word
aligned

Set

Exact number of bits required
bit aligned 2

1;

1

If the element size is less than 16 bits, the element is padded up to the nearest

2

If the element size is greater than 16 bits, then the elements are word aligned.

power of 2 bits.

In packed arrays, if the element size is less than 16 bits, then the element is padded up to
the nearest power of 2 bits. Thus, in the following example, 4 bits would be used to store
each element of arrayl and 2 bytes would be used to store the entire arrayl:

array1: PACKED ARRAY [1 .. 3] OF 0 .. 7

Data Types

3-47

Contrast this to the following declaration:

array2: ARRAY [1 .. 3] OF 0 .. 7
Each element of arrayl requires 16 bits of storage, and 48 bits would be used to store the
entire arrayl.

3.12 Files
When you open a file for I/O access, you must specify a file variable that will be the pseudonym for the actual pathname of the file. Thereafter, you specify the file variable (not
the pathname) to refer to the file. Domain Pascal supports the file data type and the text
data type. (Throughout this manual, the word "file," in boldface type, means the file data
type, and the word "file," in roman type, means a disk file.) Files of both file type and
text type are stored as Domain unstruct (unstructured ISO Latin-1) files. These files are
compatible with text .files produced under UNIX systems.

I

The following declaration establishes variable fl as an identifier of a text file:

VAH

fl : text;
A text file contains sequences of ISO Latin-1 characters representing variable-length lines

of text. You can read or write entire lines of a text file. You can read from or write to a
text file the values of a variable of any type (except pointer and file). Chapter 8 describes
text files in more detail.
You specify a file variable with the following format:

variable: file of base_type;

I

A variable with the file type specifies an unstruct binary file composed of values having
the base_type. That is, the only permissible values in such a file all have the same data
type, that of the base_type. The base_type can be any type except a pointer, file, or text
type. For example, the following declaration creates a file type corresponding to a file that
consists entirely of student records:

TYPE
student
end;
U_of_M

record
name
array [1 .. 30] of char;
integer32
id
FILE OF student;

The Domain/OS operating system stores each occurrence of student in 34 bytes: 30 bytes
for name and 4 bytes for id.

3-48

Data Types

NOTE:

Older versions of Domain Pascal created special record structured Domain files (called "rec" files) when you opened a file
with file type. For compatibility with older versions, the current
version of Domain Pascal allows you to manipulate rec files, but
you cannot create them. When you open an existing file with the
file type, Domain Pascal checks whether it is a rec or unstruct
file, and accesses it appropriately. Whenever you open a new file,
however, Domain Pascal creates an unstruct file.

I

3.13 Pointers
A pointer variable points to a dynamic variable. In Domain Pascal, the value of a pointer
variable is a variable's virtual address. Domain Pascal supports the pointer type declaration
of standard Pascal as well as a special univ_ptr data type and procedure and function
pointer types. This section details the declaration of pointer types. You should also refer to
the "Pointer Operations" listing of Chapter 4 for information on using pointers in your programs.

3.13.1 Standard Pointer Type
To declare a pointer type, use the following format:
type
name_oj_type = "typename;

You can specify any data type for typename. The pointer type can point only to variables
of the given typename. For example, consider the following pointer type and variable declarations:
TYPE

ptr_to_int16 = "integer16;
{points only to integer16 variables.}
ptr_to_real = "real;
{Paints only to real variables.}
studentptr = "student;
{points only to student record variables.}
student = record
name: array[l .. 25] of char;
id
: integer;
next_student : studentptr;
end;
VAR

x
integer16;
p_x : ptr_to_int16;
half_life: real;
p_half_life : ptr_to_real;
Brown_Univ : student;

Data Types

3~49

3.13.2 Univytr-Extension
The predeclared data type univ_ptr is a universal pointer type. A variable of type
univ_ptr can hold a pointer to a variable of any type.
You can use a univJ)tr variable only in the following contexts:
•

Comparison with a pointer of any type

•

Assignment to or from a pointer of any type

•

Formal or actual parameter for any pointer type

•

Assignment to the result of a function

Note that you cannot dereference a univ.J)tr variable. Dereferencing means finding the
contents at the logical address that the pointer points to. You must use a variable of an
explicit pointer type for the dereference. Please see the "Pointer Operations" listing in
Chapter 4 for more information on univ_ptr.

3.13.3 Procedure and Function Pointer Data Types-Extension
Domain Pascal supports a special pointer data type that points to a procedure or a function. By using procedure and function data types, you can pass the addresses of routines
obtained with the addr predeclared function. (See the addr listing of Chapter 4 for a description of this function.) You may obtain the addresses only of top-level procedures and
functions; you cannot obtain the addresses of nested or explicitly declared internal procedures and functions. Note that the compiler checks pointers for data type and name compatibility when addresses are assigned to a pointer or procedure. (See Chapter 5 for details
about declaring internal procedures and details about compatibility checking of pointers.
See Chapter 7 for details about using internal.)
Procedure and function pointer type declarations are the same as regular procedure and
function declarations, except for the following:
•

The procedure or function has no identifier; in other words, the procedure or
function does not have a name.

•

The type declaration begins with a caret (A), as in standard pointer type declarations.

You can declare procedure and function pointers in either of two ways: in the type and
var declaration parts or just in the var declaration part.
Here is an example of declaring a procedure pointer and a function pointer using both the
type and var declaration parts:

TYPE

proc_ptr
func_ptr

"procedure (a,h,c: integer);
"function (x,y: real): real;

VAR

my_proc_ptr: proc_ptr;
my_func_ptr: func_ptr;

3-50

Data Types

And here is an example of declaring the same pointers as above in just the var declaration
part:

VAR
my_proc_ptr: Aprocedure (a,b,c: integer);
my_func_ptr: Afunction (x,y: real): real;
See the "Pointers to Routines-Extension" section of Chapter 5 for a sample program
showing how to pass function pointers as parameters.

3.13.4 Initializing Pointer Variables-Extension
Domain Pascal permits you to initialize the values of pointer variables within its variable
declaration in most cases. You initialize a value by placing a colon and equal sign (:=) immediately after the data type. For example, the following fragment declares my_ptr as a
type ptr_to_int16 with an initial value of NIL:

TYPE
VAR
my_ptr : ptr_to_int16 := NIL;
If the variable declaration occurs within a procedure or function, you cannot initialize the
variable at the declaration unless it has been declared static. This is because storage within
routines is dynamic and so variables in them do not necessarily retain their values between
executions. For example, the following is incorrect:

TYPE
FUNCTION do_nothing(IN OUT x

INTEGER)

BOOLEAN;

VAR
{Wrong!}
This is the correct way to initialize the variable at its declaration in a routine:
my_ptr : STATIC ptr_to_int16 := NIL;

{Right!}

See Chapter 7 for information on the static attribute.

3.13.5 Intemal Representation of Pointers
Domain Pascal stores pointer variables in the 32-bit record shown in Figure 3-18.
16

31

Address
Address
15

I

0

Figure 3-18. Pointer Variable Format

Data Types

3-51

By default, pointer-type objects are stored on longword boundaries.
A pointer to a procedure or function (a Domain Pascal extension) points to the starting
address of that routine.

3.14 Putting Variables into Overlay Sections-Extension
A section is a named area of code or data. An overlay section is a section whose contribution from a module "overlays" that of other modules. A Domain Pascal overlay section
is just like a named common block in FORTRAN.
At run time, the code or data in a particular section occupies contiguous logical addresses.
By default, all variables that you declare in a var declaration part are stored in the . data
section. However, Domain Pascal lets you assign variables to sections other than .data.
To specify an overlay data section, place the section name inside a set of parentheses after
the reserved word var. The section name can be any valid identifier or a string within quotation marks. For example, both of the following are valid names for a section:

thi s_is_a_sect ion_name
'this is a section name'
The following is the format to declare a section name for a var declaration part.
var (section_name)
identifier_list 1 : typename 1 ;

[
identifier_listN : typenameN;]

All the variables named in all the identifier_lists will be stored in section name. Since
you can put multiple var declaration parts in the same program, you can create multiple
named sections. If you do not specify a section_name, Domain Pascal puts the variables in
the .data section.
Domain Pascal allocates variables defined in a var declaration part sequentially within the
specified section. If more than one var declaration specifies the same section name, the
subsequent declarations are considered to be continuations of the first declaration.
By forcing certain variables into the same section, you can reduce the number of page
faults and thus make your program execute faster. For example, suppose you declare the
following three variables:

VAR

integer16;
array[l .. 5000] of integer16;
single;

3-52

Data Types

Further suppose that whenever you need the value of x, you also need the value of y. By
default. Domain Pascal places x, b_data. and y inside the .data section. The .data section
encompasses 10 pages (1 page = 1024 bytes). There is no way to ensure that x and y will
be on the same page in .data because Domain Pascal might place b_data in between x
and y. However, by putting x and y in the same named section, you can improve the odds
to over 99%. For example, to put x and y into section important, you must issue the following declarations:

VAR (important)
x
INTEGER16;
y : REAL;

{will go into section "important"}
{will go into section "important"}

VAR
b_data: array[1 .. 5000] of INTEGER16;

{will go into section ".data"}

See the "Section-Extension" section of Chapter 5 for information about using sections
within routines. Sections are important at bind time. For complete information on the Domain binder, see the Domain/OS Programming Environment Reference.

3.15 Attributes for Variables and Types-Extension
Domain Pascal supports attributes for variables and types. These attributes supply additional
information to the compiler when you declare a variable or a type. The attribute names
are:
•

volatile

•

atomic

•

device

•

address

•

bit, byte, word, long, quad (size attributes)

•

aligned(n), natural (alignment attributes)

The volatile, atomic, and device attributes enable you to turn off certain compiler optimizations that would otherwise ruin programs that access device registers or shared memory locations. The address attribute associates a variable with a specific virtual address.
Alignment and size attributes enable you to enhance your program's performance by specifying storage allocation and data layout information.
Specify volatile, device, alignment, and size attributes inside a pair of brackets immediately before the type in the type or var declaration. For example:
TYPE

[VOLATILE] array[l .. 10) of integer;
VAR
x

[DEVICE] integer16;

Data Types

3-53

Specify address and atomic: attributes inside a pair of brackets immediately prior to the
type in the var declaration. For example:

VAR
x: [ATOMIC] integer;
To specify more than one attribute for a particular data type or variable, separate the at..
tributes with commas. For example:

VAR
x: [ATOMIC, DEVICE] integer;
Table 3-6 summarizes the attributes that Domain Pascal supports. The following subsec..
tions provide details about the attributes.

3-54

Data Types

Table 3-6. Summary of Attributes for Variables and Types
Attribute

Example of Syntax

Purpose

volatile

TYPE
int array = [volatile]
- array[l .. lO]of integer;
VAR
x: [volatile] integer;

Prevent certain default optimizations based on assumptions about
value.

atomic

VAR
x: [atomic] integer;

Implies volatile. Also perform updates with single instruction when
possible.

device

TYPE
keyboard = [device] char;
VAR
x: [device] integer16;

Implies volatile. Also prevent additional optimizations.

address

VAR
peb page: [address
(16'ff7000) ,device] char;

Bind a variable to a specified virtual
address (use with volatile or device).

SIZE
ATTRIBUTES

bit
byte
word
long
quad

TYPE
big boo =
- [long] boolean;
VAR
large boo:
-[long] boolean;

Specify amount of storage for types
and/or objects.

ALIGNMENT
ATTRIBUTES

aligned
natural

TYPE
word aligned integer32 =
[aligned(l)] integer32;
VAR
natural_int:[natural]integer;

Control the data layout.

Data Types

3-55

3.15.1 Volatile-Extension
Volatile informs the compiler that memory contents may change in a way that the compiler
cannot predict. There are two situations, in particular, where this might occur:
•

The variable is in a shared memory location accessed by two or more processes.

•

The variable is accessible through two different access paths. (That is, multiple
pointers with different base types refer to the same memory locations.)

In both of these situations, it is crucial that you tell the compiler not to perform certain
default optimizations.
For example, the following module causes optimizations leading to erroneous behavior:

Module volatile_example;
VAR
P : "integer;
Procedure Init(VAR v
BEGIN
p .- addr(v);
END;

integer);

Procedure Update;
BEGIN
p" .- p" + 1; {anonymous path.}
END;
Procedure Top;
VAR
i : integer;
BEGIN
Init(i);
i := 0;
while i < 10 do
update;
END;

{ViSible modification.
}
{Visible reference.
}
{Hidden modification to i.}

However, you can prevent these destructive optimizations if you change the declaration of
variable ito:

VAR
i : [volatile] integer;

3.15.2 Atomic-Extension
You declare a variable to be atomic if you want to make sure that its value does not
change unpredictably as a result of mUltiprocessing. Atomic prevents the same optimizations as volatile. In addition, the compiler handles any assignment statements whose left
side is a variable specified as atomic and whose right side contains the same variable in a
special way that protects the value of the variable from being changed by other processes.

3-56

Data Types

Atomic attributes can only be used with scalar variables. The scalar data types are integer,
Boolean, character, and enumerated.
For example, consider the following declaration:
VAR

x: [atomic] integer;
The above declaration tells the compiler to make sure that the value of x is not changed
by other processes while it completes an assignment statement such as the following:

x := x + 2;

3.15.3 Device-Extension
Device informs the compiler that a device register (control or data) is mapped to a specific
virtual address. Device registers are memory locations bound to a specific device, such as
a disk drive. The device attribute prevents the same optimizations that volatile prevents,
and it also prevents two other optimizations, which are described below.
By default, the compiler optimizes certain adjacent references by merging them into one
large reference. The device attribute prevents this optimization.
For example, consider the following fragment:
VAR

a,b : integer16;
BEGIN
a .- 0;
b .- 0;

By default, the compiler optimizes the two 16-bit assignments by merging them into one
32-bit assignment. (That is, at run time, the system assigns a 32-bit zero instead of assigning two 16-bit zeros.) By specifying the device attribute, you suppress this optimization.
The device attribute also prevents the compiler from generating gratuitous read-modifywrite references for device registers. That is, specifying a variable as device causes the
compiler to avoid using instructions that do unnecessary reads.
Now, consider an example. Suppose kb in the following fragment is a device register that
accepts characters from the keyboard.
TYPE

keyboard

char;

VAR

c, c1
kb

char;
"'keyboard;

BEGIN
c
.- kb"';
c1 . - kb"';

Data Types

3-57

The purpose of the program is to read a character from the keyboard and store it in c,
then read the next character and store it in ct. However, the compiler, unaware that the
value of kb can be changed outside of the block, optimizes the code as follows: it stores
the value of kb in a register, and thus assigns the same value to both c and ct. Obviously,
this· is not what the programmer intended since Domain Pascal assigns the same character
to both c and ct. To ensure that Domain Pascal reads kb twice, declare it as:

TYPE

keyboard = [DEVICE] char;
Another situation when normal optimization techniques can change the meaning of a program is in loop-invariant expressions. For instance, using the keyboard example again, suppose you have the program segment:

TYPE

keyboard

char;

VAR
x
c
kb

integer;
char;
"keyboard;

while (x < 10) do
begin
c := kb";
foo(c);
x := x + 1;
end;
The purpose of the block is to read 10 successive characters from the keyboard and pass
each to a function called foo. However, to the compiler, it looks like an inefficient program since c will be assigned the same value 10 times. To optimize the program, the compiler may translate it as if it had been written as follows:
c := kb";
while (x<10) do
begin
foo(c);
x

:=

x + 1;

end;
To ensure that the compiler does not optimize your program in that manner, declare kb as
follows:

TYPE

keyboard = [DEVICE] char;
VAR
kb : "keyboard;

3-58

Data Types

In addition to suppressing optimizations, you can also use device to specify that a device is
either exclusively read from or exclusively written to. You achieve this by using the read
and write options which have the following meanings:
•

Device(read)-This attribute specifies read-only access for this variable or type.
That is, if you attempt to write to this variable, the compiler flags the attempt as
invalid and issues an error message.

•

Device(write)-This attribute specifies write-only access for this variable or type.
That is, if you attempt to read from this variable, the compiler flags the attempt as
invalid and issues an error message.

•

Device(read, write)-This attribute specifies both read and write access for this
variable. This attribute is identical to the device attribute without any options.

•

Device(write, read)-Same as device(read, write).

For example, here are some sample declarations using the device attributes:

TYPE
truth_array: [DEVICE] array[l .. lO] of boolean;
VAR
c

c2

t

[DEVICE(read)] char;
[DEVICE(write)] char;
truth_array;

{read-only access.}
{write-only access.}
{read and write access.}

3.15.4 Address-Extension
Address takes one required argument.
The address specifier binds a variable to the specified virtual address, specified by a constant. You can only use address in a var declaration, not in a type declaration.
Address is useful for referencing objects at fixed locations in the address space, such as
device registers, the PEB (Performance Enhancement Board) page, or certain system data
records. Typically, the compiler generates absolute addressing modes when accessing such
an operand. You cannot specify define, extern, or static when you use this option.
Using address by itself (without device or volatile) does not suppress any compiler optimizations. You should use it in conjunction with volatile or device. The example below
associates the variable peb_page with the hexadecimal virtual address FF7000.
VAR

peb_page

[ADDRESS (16#FF7000), DEVICE(read)]

char;

Data Types

3-59

3.15.5 Size-Extension
Size attributes specify the amount of storage to be reserved for the following:
• Variables
• Formal parameters
• Function results
• Record fields
• Array components
You declare size attributes in either of two ways-as part of a type-identifier or as part of
an object. Declaring a size attribute as part of a type identifier indicates the amount of
storage to be reserved for every object of that type. Declaring a size attribute as part of
an object declaration specifies the amount of storage reserved for that particular object.
Domain Pascal supports five size attribute-names:
•

bit (1 bit)

•

byte (8 bits)

•

word (16 bits)

•

long (32 bits)

•

quad (64 bits)

Each attribute-name represents a unit of storage. You indicate the number of units of
storage to be reserved by including an integer-expression, n, in parentheses immediately
after the attribute-name, as follows:

[attribute-name [ (n) ] ] typename
If (n) is missing, then the compiler uses a default value of 1.

For example, each of these two variable declarations reserves 32 bits of memory 'for
original_value:

TYPE
big_number = [long] integer16;
VAR
original_value
and

VAR
original_value

3-60

Data Types

[long] integer16;

Compare the above declarations to the following declaration, which reserves 16 bits for
original_value:

VAR
original_value: integer16;
In Domain Pascal, the following size rules apply:
•

Every data type has a minimum size.

•

A size attribute must specify at least the number of bits required for the type to
which it is applied.

•

A size attribute can specify a number of bits greater than the minimum for integer, boolean, and set data types. If you use a size attribute to specify a size
larger than the minimum for a data type, then the compiler uses all of the bits in
the larger object to represent the value of an object of that type.

Table 3-7 shows the minimum number of bits for Domain Pascal data types.

Table 3-7. Size of Simple Data Types
Data Type

Minimum Size

Integer16 or Integer

16 bits

Integer32

32 bits

Single or Real

32 bits

Double

64 bits

Boolean

8 bits

Char

8 bits

Subrange

Number of bits needed
to store subrange

Enumerated

16 bits

Data Types

3-61

You can use size attributes to create bit arrays. Domain Pascal supports arrays of 1-, 2-,
and 4-bit elements. The order of elements within words is from most significant bit to
least significant bit. The only aggregate bit array operation that Domain Pascal supports is
aggregate assignment. The following program illustrates the use of bit arrays:

program bit_array;
type
element = [bit (4)] O.. 1;
{Declares a subrange type that occupies 4 bits.}
arr = packed array [1 .. 6] of element;
{You need to say 'PACKED' to get the intended size, 3 bytes}
VAR

a1 : arr;
begin
a1 [4] : = 2;
wri teln ('The size of a1 is: '
writeln('
a1[4] = '
end.

sizeof(a1):4, ' bytes');
a1[4]:4 );

The output of this program is as follows:

The size of a1 is:
a1[4] =

3 bytes
2

You can also use size attributes to declare an array of byte integers, such as:
TYPE

byte_integer = [byte] O.. 255;
byte_int_array = array[l .. 1000] of byte_integer;
Finally, size attributes are useful for declaring variables in Domain Pascal that you want to
correspond to data types in other languages. For example, the Domain Pascal type
[byte] 0 .. 255 corresponds to the unsigned char data type in Domain/C. (See Chapter 7
for a more detailed discussion of cross-language communication.)
Notice that you use size attributes in the declaration part of your program, whereas you use
type transfer functions in the action part of your program. (See the "Type Transfer Functions" listing in Chapter 4 for details about type transfer functions.)

3.15.6 Alignment-Extension
Domain Pascal supports two alignment attributes: aligned and natural. In the following
sections we tell you:

3-62

•

The format for the aligned and natural attributes.

•

How to use natural and aligned to align objects on natural boundaries.

•

How to use aligned to prevent padding by default.

Data Types

•

How to use aligned to ensure the same record layout in all alignment environments.

•

How to suppress informational messages about alignment by using the alignment
attributes.

•

How and why to use alignment attributes to inform the compiler that an object is
not naturally aligned. This is especially important in connection with dereferencing pointers and passing arguments by reference.

3.15.6.1 Format for the aligned and natural Attributes
The format for the aligned attribute is:

[aligned [ (n) ]] typename;
where n is the number of low order zeros in the address (in binary representation). If you
omit a value for n, then the compiler will default to a value of 0 (byte aligned). Note
that:
aligned

specifies

byte alignment

aligned (I)

specifies

word alignment

aligned (2)

specifies

longword alignment

aligned (3)

specifies

quadword alignment

aligned (4)

specifies

octaword alignment

Thus, aligned(n) implies 2**n-byte alignment. For example, the declaration
TYPE

word_aligned_integer32 = [ALIGNED(l)] integer32;
tells the compiler that all objects of type word_aligned_integer32 are at least word
aligned.
The format for the natural attribute is as follows:
[natural] typename;
For example, the declaration
TYPE

natural_integer32

=

[NATURAL] integer32;

tells the compiler that all objects of type natural_integer32 are at least longword aligned.

Data Types

3-63

The natural attribute has one main use;
•

Overriding the· default alignment rules to ensure that objects are stored on natural
boundaries.

Similarly, you can use the aligned attribute to ensure natural alignment by specifying the
correct value for n. In addition, the aligned attribute has these uses:
•

Preventing the compiler from inserting padding in records.

•

Ensuring the same layout in all alignment environments.

•

Suppressing informational messages.

•

Dereferencing pointers to unaligned objects.

•

Passing arguments by reference.

Each of these uses is described in the following sections.

3.1S. 6. 2 Aligning Objects on Natural Boundaries
In general, natural alignment produces faster executable code, although the efficiency savings vary a great deal from one processor to another. (See Section 3.10.5 for a description of natural alignment.) Code for the 68000 family of processors runs slightly faster if
objects are naturally aligned. Code for the Series 10000 workstations runs significantly
faster if objects are naturally aligned. Moreover, on the Series 10000, if the compiler assumes that an object is naturally aligned when it is not, then the loss of efficiency is severe.
Although natural alignment often results in faster code, it can also produce holes in structures such as arrays and records, which can have an impact on memory efficiency. Before
naturally aligning record fields, you need to weigh these two efficiency concerns.
The aligned and natural attributes override the default alignment rules (described in the
"Internal Representation of Unpacked Records" section of this chapter) as well as the
alignment rules specified by any compiler alignment directive that is currently in effect.
(See Chapter 4 for more information about specifying alignment rules with compiler directives.)
Note that if all of the record fields are scalar, it is always possible to guarantee natural
alignment of the entire record by arranging the fields in decreasing order of size. This
method is preferable to using the aligned and natural attributes because it is portable.
(See the "Internal Representation of Unpacked Records" section of this chapter for an
example of using this rule.)

3-64

Data Types

Although it is usually possible to align record fields naturally by arranging them in descending order of size, the arrangement of fields does not guarantee that a record will remain
aligned if it is used within another aggregate (that is, in an array or record). Consider the
following example:

TYPE
S

record

a: integer32;
b: integer16
end;
The layout is shown in Figure 3-19. Note that both a and b are naturally aligned, and
that the entire record is aligned on a longword boundary .

...

1 word

0-------------.. . .
2

a

4

Figure 3-19. Naturally Aligned Record S
Note what happens, however, if we declare an array of three S records:

VAR
bunch_of_records: ARRAY [1 .. 3] OF S;
The memory layout for this array is shown in Figure 3-20.

Data Types

3-65

4

1 word

0
2

.

a

4

6

8

a

10
12
14

a

16

Figure 3-20. Array of S Records
Note that the second element of the array, which starts at address 6, is not naturally
aligned. This alignment results from the fact that each element is six bytes long and array
elements must be laid out contiguously in memory. There are several solutions to this
problem. They are as follows:
•

Explicitly enter a word of padding in the record so that the total size of the record is divisible by four. Specifically, change the declaration of S-type records to:

TYPE

S

•

record
a: integer32;
b: integer16;
padding: integer16
end;

Use the natural attribute for the record. Specifically, change the declaration to:

TYPE

S

3-66

Data Types

[NATURAL] record
a: integer32;
b: integer16
end;

•

Use the aligned attribute for the record. Specifically, change the declaration to:

TYPE
S

•

[ALIGNED(2)] record
a: integer32;
b: integer16
end;

Use the natural attribute for field a. This works because a record inherits the
largest alignment specification of its fields. Since a is declared to be aligned on a
longword boundary, the entire record will be also be longword aligned. Specifically, change the declaration to:

TYPE
S

•

record
a: [NATURAL] integer32;
b: integer16
end;

Use the aligned attribute for field a. This method also works because of the rule
that a record inherits the largest alignment specification of its fields. Specifically,
change the declaration to:

TYPE
S

record
a: [ALIGNED(2)] integer32;
b: integer16
end;

Figure 3-21 shows the memory allocation for S records resulting from all of the above
methods of declaring S.
1 word _ _ _- - I. . . .
o~----------------------

2

a

4~-----------------------------------~

b

6

Figure 3-21. Naturally Aligned Record S
The principal difference between declaring a padding field and using an alignment attribute
is that the padding word is accessible if you explicitly declare it. It is inaccessible if the
compiler includes it to satisfy an alignment attribute. Furthermore, if you use padding instead of the attribute, your record declaration is portable.

Data Types

3-67

NOTE:

Assigning attribute specifications to a record or field can have
unexpected repercussions. Consider the following declarations:
TYPE

S

record
a: [NATURAL] integer32;
b: integer16

Sl

end;
record
x: integer16;
y: S;
z: integer16
end;

The layout for record S is shown in Figure 3-21 and the layout
for SI is shown in Figure 3-22. Note that record S inherits the
alignment of field a (longword alignment) and that this alignment
requirement causes an additional word of padding to be inserted
between x and y. In addition, record S 1 inherits longword alignment from record S, causing a word of padding to be added at the
end of S1.

0

...

word

~

x
2
4
6

S.a

8
S.b

10
12
14
16
Figure 3-22. Naturally Aligned Record Sl

3-68

Data Types

3.1S.6.3 Using the aligned Attribute to Prevent Padding
In the previous example, we used the aligned attribute to insert padding in a record so
that the size of the record would be evenly divisible by the size of its largest field (four
bytes). You can also use the aligned attribute to prevent the compiler from inserting padding. This is particularly useful. if you need to declare a record that maps onto an existing
layout (for example, a shared memory area).
Suppose, for example, that you want to declare a record that consists of a char followed
by two integers:

TYPE

52

record
a: char;
b, c: integer16
end;

By default, the compiler produces the layout shown in Figure 3-23.

...

1

word------I~~

Figure 3-23. Default Layout for Sl
The compiler inserts a byte of padding after a to ensure that b starts on a word boundary.
If you want to create a record without padding at this position, you need to use the
aligned specifier as shown in the following declaration:

TYPE

82

record
a: char;
b, c: [ALIGNED(O)] integer16
end;

The aligned(O) attribute tells the compiler that these fields may be aligned on byte
boundaries. This declaration results in the layout shown in Figure 3-24.

Data Types

3-69

1 word

0-------

...

2
4

6

Figure 3-24. Layout for Sl with Byte Alignment Specified
Note that the compiler still inserts a byte of padding so that the size of the record is evenly
divisible by two. There is no way to suppress this trailing byte. Records created by Domain Pascal are always 2-byte multiples.
Suppressing padding sometimes becomes more important if a "natural_alignment directive
is in effect. The "natural_alignment directive tells the compiler to use natural alignment
for any data that does not have an alignment attribute in its declaration. (See the "Compiler Directives" section of Chapter 4 for more details about the "natural_alignment
directive). Consider the following declaration:

81 = record

a: char;
b: integer32;
c: char
end;
The "natural_alignment directive applies not only to each field, but also to the entire
record. A record is considered to be naturally aligned if it starts on a boundary that ensures natural alignment for its largest field (and every other field). The layout for SI is
shown in Figure 3-25.

3-70

Data Types

0

.

1 word

~

2

4

6
8
10

Figure 3-25. Layout for Sl with Natural Alignment Specified
By specifying word alignment for the record, we can remove the final word of padding, as
shown in Figure 3-26.

TYPE
51 = [ALIGNED(1)] record
a: chari
b: integer32i
c: char
endi

1 word ----.~.

Figure 3-26. Layout for Sl with Word Alignment Specified

Data Types

3-71

To remove at least some of the padding between a and b, we need to specify word alignment for b. Figure 3-27 shows the layout if we specify word alignment for b as well as for
the whole record.

TYPE
81

= [ALIGNED(1)] record
a: char;

b: [ALIGNED(1)] integer32;
c: char
end;

...

1

word,..-----I~~

o----------------------~--~----~--~

a

4

c

Figure 3-27. Layout for Sl with Word Alignment for B Specified

Note that specifying byte alignment for b produces the same layout as specifying word
alignment for b-namely, the layout in Figure 3-27. The results are the same because of
the rule that a byte aligned object may not cross two word boundaries. (See the "Internal
Representation of Unpacked Records" section of this chapter for more details about the
rules for record layout.)

3.15.6.4 Ensuring the Same Layout in All Alignment Environments
Alignment attributes can be particularly useful for ensuring that a record receives the same
layout regardless of what alignment environment is in effect due to a compiler directive or
a compiler option.
Suppose, for example, that you want to declare a record that consists of an integer16 followed by an integer32, and you want to guarantee that there is no padding in the structure
regardless of the alignment environment. Consider the following declaration:

82 = record
a: integer16;
b: integer32
end;

3-72

Data Types

If the alignment environment is natural alignment, then the layout of 82 type records will
be the layout shown in Figure 3-28. If the alignment environment is word alignment, then

the layout will be that shown in Figure 3-29.

o
2

1

word'-----~·

a

4

6

b

Figure 3-28. Naturally Aligned Structure S2

o

word -------------....

a
2
4

b

Figure 3-29. Word Aligned Structure S2

You can use the aligned attribute to ensure that 82 never receives padding between a
and b:

82

=

record
a: integer16;
b: [ALIGNED(l)] integer32
end;
NOTE: You can also use the aligned record data type or the unaligned
record data type to ensure that your records have the same layout
in all alignment environments.

Data Types

3-73

3.1S.6.S Suppressing Informational Messages about Alignment
In general, the compiler assumes that all objects are naturally aligned. If the compiler encounters an object that it knows is not naturally aligned, it issues an informational message.
This happens, for example, when the compiler is forced to use word alignment rules for a
record field that is larger than a word, or when a record cannot be aligned because it is
embedded in another aggregate object. The following declarations, for example, will produce two informational messages:

TYPE
53

record
a: integer16;
b: integer32;
c: double
end;

The messages inform you that band c are not naturally aligned. If you attempt to declare
an array of S3 records, you will receive another informational message telling you that the
array elements are not naturally aligned.
The best way to suppress these messages is to rearrange the record so all the fields are
naturally aligned. If rearrangement is impossible, however, you can suppress these messages by specifying the alignment and telling the compiler that the objects are not naturally
aligned:

TYPE
53

record
a: integer16;
b: [ALIGNED(l)] integer32;
c: [ALIGNED(l)] double
end;

Note that these alignment specifications do not affect the record's layout-they merely reaffirm that the compiler should use word alignment rules rather than natural alignment rules.
NOTE:

If you compile with -info 4, you will receive informational mes-

sages even if you specify alignment. See Chapter 6 for more information about the -info option.

3.1S.6.6 Informing the Compiler that an Object Is Not Naturally Aligned
(Series 10000 Only)
In many instances, the compiler can determine whether an object is naturally aligned.
When the compiler knows that an object is not naturally aligned, it produces code that accesses the object as if it consisted of separate parts, where each part is naturally aligned.
For example, suppose a program accesses a 4-byte integer that starts on a 2-byte boundary. Because the computer can't access the entire integer at once, the compiler treats the
4-byte integer as if it ~ere composed of two contiguous 2-byte integers, each of which is

3-74

Data Types

naturally aligned. The compiler produces code that accesses each half of the 4-byte object
and then recombines the two halves to obtain the 4-byte integer value.
Obviously, this decomposition and recomposition of objects is less efficient than accessing
the object in a single instruction. Still, it is considerably better than taking a hardware
trap, which is what occurs if the compiler assumes that an object is naturally aligned when,
in fact, the object is not naturally aligned. The trap invokes a software routine to handle
the unaligned data, which results in a significant loss of efficiency.
There are some situations where the compiler cannot determine whether an object is or is
not naturally aligned:
•

You declare a pointer to point to a naturally aligned object, and then assign it the
address of an object that is not naturally aligned.

•

You pass an argument to a routine by reference.

In both of these cases, the compiler assumes that the object is naturally aligned. If you
know that this is not the case, you should inform the compiler with the aligned· attribute or
with the align function. (See the "Align" listing in Chapter 4 for details about the align
function). This causes the compiler to use the decomposition/recomposition technique
instead of suffering a hardware fault at run time.
NOTE:

If you run your Domain Pascal program on a Series 10000 work-

station, you should make sure that the compiler is informed about
any objects that are not naturally aligned. If the compiler assumes that an object is naturally aligned when, in fact, the object
is not naturally aligned, your program will suffer a severe loss of
efficiency when you run it on Series 10000 workstations.

3.1S.6.7 Dereferencing Pointers
When you declare a pointer to an object, the compiler assumes that the object pointed to
is naturally aligned unless you tell it otherwise. Consider the following declarations:

TYPE
rec

record
int16
int32
end;

integer16;
[ALIGNED (1)] integer32

VAR
iptr : Ainteger32;
r: rec
BEGIN
iptr := ADDR (rec.int32)
END;
In this example, the assignment of addr(rec.int32) to iptr will cause a compile-time warning. The program declared iptr as a pointer to an integer32 type, which is assumed to be
naturally aligned. However, .the address of rec.int32 has been declared to be word
aligned.

Data Types

3-75

You can correct this problem by declaring iptr as pointing to a word aligned integer32
type variable, as follows:
VAR

word_int32 : [ALIGNED (1)] integer32;
iptr : Aword int32
- {iptr is a longword aligned pointer; it points
to a word aligned 4-byte integer}
Note that the above declaration tells the compiler that iptr points to a word aligned
integer32-type variable. It is different from the following declaration, which tells the compiler that iptr is a word aligned pointer variable and also that what it points to is a word
aligned integer32-type variable:
VAR

word_int32 : [ALIGNED (1)] integer32;
int_ptr: Aword_int32;
iptr : [ALIGNED(l)] int_ptr;
{iptr is a word aligned pointer variable;
it points to a word aligned 4-byte integer}

3.1S.6.8 Passing Arguments by Reference
The compiler is unable to, determine the alignment of objects passed by reference as arguments to routines. By default, the compiler assumes that such objects are naturally
aligned. Therefore, if you know that an argument passed by reference is not naturally
aligned, you should specify its alignment.

3.15.7 Attribute Inheritance-Extension
Types and variables inherit the device attribute, and in some cases the volatile attribute,
from more primitive data types. If you define a data type in terms of a more primitive data
type declared with device or volatile, the new data type may inherit the attributes of that
more primitive data type. For example, in the following declarations, resource inherits the
volatile attribute from semaphore:

TYPE
semaphore
resource

3-76

Data Types

[VOLATILE] integer;
array[l .. lO] of semaphore;

If you define a record type as volatile or device, all the fields within the record inherit the

attribute. And if you designate anyone field within a record as having the device attribute,
the entire record itself inherits the device attribute. However, the same is not true for a
volatile field within a record; the entire record is not considered volatile just because one
field is declared that way. Consider the following:

TYPE

lock
queue

[VOLATILE] integer;
RECORD
key : lock;
users : integer;

end;

VAR
wait : queue;
In this example, all references to wait.key are volatile, because the lock type is declared
as volatile, but references to wait. users are not volatile. If you want all the fields to be
volatile, insert the following after the record definition:

volque - [VOLATILE] queue;
NOTE:

Pointer types do not inherit the device or volatile attributes of
their base type. However, when pointer variables are
dereferenced, the system applies any attributes of their base type.

3.15.8 Special Considerations-Extension
A common mistake is to associate an attribute with a pointer type. For example, we do not
recommend that you use the following declaration:

VAR
iodata : [DEVICE] Ainteger16;
The memory location of iodata is normally on the stack or in the .data section. You don't
want to make the local variable a device; you want to make the local variable a pointer to
a device. Specify the following declarations instead:

TYPE

DevInt

[DEVICE] integer;

iodata

ADevInt;

VAR

Data Types

3-77

3.16 Attribute Declaration Part-Extension
Domain Pascal supports an attribute declaration part that allows you to define your own
attributes. The syntax for the attribute declaration part is as 'follows:
attribute

identifier] = attribute_name] [, ... , attribute_nameN];

identifierN

=attribute_name] [.

'" • attribute_nameN]:

An identifier is any valid Domain Pascal identifier. An attribute_name is any predeclared
Domain Pascal attribute (such as aligned (0) or long) or the identifier of an attribute that
you 'created earlier in the attribute declaration part.
For example, the following is a sample attribute declaration part:

ATTRIBUTE
integer_attributes = long, natural;
keyboard_attributes = device;
array_attributes = volatile;
peb_page_attributes = address (16#ff7000), keyboard_attributes;
And here is an example of type and var declaration parts that correspond to the above
attribute declaration part:
TYPE

intI
int2

[integer_attributes] integer32;
[integer_attributes] integerl6;

VAR
i,j: intI;
k: int2;
peb_page: [peb_page_attributes] char;
int_array: [array_attributes] ARRAY[I .. IO] of

intI;

You can use attributes that you define in an attribute declaration part in any context that
you can use the predeclared attributes that are included in the definition. The compiler
follows the same scope rules for attributes as it does for variables; the compiler evaluates
attributes when they are declared.

- - - - 88 ------

3-78

Data Types

Chapter 4
Code

This chapter describes the statements, procedures, functions, and operators constituting the
action part of a Domain Pascal program or routine. The beginning of the chapter provides
an overview of what's available. The remainder of the chapter is a Domain Pascal encyclopedia complete with many examples. If you are a Pascal beginner, you should read a good
Pascal tutorial before trying to use this chapter.
The overview of Domain Pascal is divided into the following categories:
•

Conditional branching

•

Looping

•

Mathematical operators

•

Input and output

•

Miscellaneous functions and procedures

•

Systems programming functions and procedures

4.1 Overview: Conditional Branching
Domain Pascal supports the two standard Pascal conditional branching statements-if and

case.

Code

4-1

4.2 Overview: Looping
Domain Pascal supports for, repeat, and while-the three looping statements of standard
Pascal. All three looping statements support the next and exit extensions. Next causes a
jump to the next iteration of the loop, and exit transfers control to the first statement following the end of the loop.

4.3 Overview: Mathematical Operators
Domain Pascal supports all the standard arithmetic, logical, and set operators, as well as
three additional operators for bit manipulation, two additional Boolean operators, and one
additional operator for exponentiation. Table 4-1 lists these operators.

I

4-2

Code

Table 4-1. Domain Pascal Operators

Data Types
Numeric

Operator

Meaning

+

Addition
Subtraction
Multiplication
Division (real values)
Division (integer values)
Modulus (returns remainder of
integer division)
Exponentiation

-

*
I

div
mod
**

Integer

&
I

Bitwise and
Bitwise or
Bitwise negation

+

<=
>=
in

Set union
Set intersection
Set exclusion
Set equality
Set inequality
First operand is subset of second
First operand is superset of second
First operand is element of second

Boolean

and
and then
or
or else
not

Logical
Logical
Logical
Logical
Logical

Non-pointer
types

>
>=
<
<=

Greater than
Greater than or equal to
Less than
Less than or equal to

=

Equal to
Not equal to

-

Set

*

-

=

<>

All types

<>

NOTE:

and
and (short -circuit)
or
or (short-circuit)
negation

For the Boolean "short-circuit" operators, if the system can determine the value of the expression after evaluating the first operand, it does not check the second operand.

The exponentiation operator has the following syntax:

mantissa

** exponent

Code

4-3

Table 4-2 shows the meaning of various expressions that use the exponentiation operator.
An important restriction on the exponentiation operator is that you may not use a negative
mantissa with a noninteger exponent.

Table 4-2. Exponentiation Expressions
Expression

Meaning
y

x •• y

Raise x to the power y

x
z

x •• y •• z

Raise y to the power z;
then raise x to the result

y

x

x·· (y + z)

(y + z)
x

Evaluate (y + z); then
raise x to the result

When evaluating expressions, Domain Pascal uses the order of precedence rules found in
Table 4-3. The operators grouped together have the same precedence. Note that some
operators work as both mathematical operators and as set operators. Nevertheless, the
precedence rules are the same no matter how the operator is used.

Table 4-3. Order of Precedence in Evaluating Expressions
Operator
not

Order of Precedence
highest precedence
h

**

• / div
mod and

&

r +

-

or

= <> ><
>= <=
in

and then
or else

4-4

Code

,if
lowest precedence

Domain Pascal permits the mixing of real and integer types in arithmetic expressions. For
such mixed operations, Domain Pascal promotes the integers to reals before performing the
operation.

4.3.1 Expansion of Operands
The compiler computes operands smaller than 32 bits with 32 bits of precision when necessary to achieve correct arithmetic. This means integer16 operands sometimes are expanded
to integer32 before calculations. These data expansions produce more accurate results;
however, the compiler tries to avoid the extra code produced by data expansion.

4.3.2 Predeclared Mathematical Functions
In addition to the mathematical operators, you can use any of the predeclared mathematical functions listed in Table 4-4. Note that although the arctan, cos, exp, In, sin, and
sqrt functions permit integer arguments, the compiler converts an integer argument to a
real number before calculating the function. Therefore, when possible, it is better to supply
real, rather than integer, arguments to these functions.

Code

4-5

Table 4-4. Mathematical Functions
Function

Argument(s)

Result

abs(x)

integer or real

same type as x

Absolute value of x.

arctan (x)

integer or real

real

Arctangent of x.

arshft(x,n)

both are integer

integer

Shifts the bits in x to the right n
places. Preserves the sign of x.

cos (x)

integer or real

real

Cosine of x.

exp(x)

integer or real

real

Raises exponential function e to
the x power.

In (x)

integer or real

real

Natural log of x; x >0

)shft(x,n)

both are integer

integer

Shifts the bits in x to the left n places.

odd (x)

integer

boolean

True if x is an odd value.

round (x)

real

integer

Rounds x up or down to nearest
integer.

rshft(x,n)

both are integer

integer

Meaning

Shifts the bits in x to the right

n places.
sin (x)

integer or real

real

Sine of x.

sqr(x)

integer or real

same type as x

Square of x.

sqrt(x)

integer or real

real

Square root of x.

trunc(x)

real

integer

Truncates the fractional part of x
(rounds x towards zero).

xor(x,n)

both are integer

integer

Bit exclusive or.

4.3.3 Mixing Signed and Unsigned Operands in Expressions
Although Domain Pascal does not have an unsigned type, it does support unsigned ranges.
(See Section 3.4 for further information on unsigned types.)
Mixing signed and unsigned integer operands is tricky for the following operations:

4-6

Code

•

>

•

>=

•

<

•

<=

•

min

•

max

•

div

•

mod

The compiler interprets these operations as signed except under the following circumstances:
•

Both operands are unsigned run-time values.

•

One operand is an unsigned run-time value and the other is a constant in the positive subrange 0 .. 2147483647.

For these two cases, the compiler uses unsigned operations.
You can use a type transfer to force the desired type of operation if it does not result from
the above rules. (See the section on "Type Transfer Functions" later in this chapter for
further information.) The following code fragment illustrates the use of type transfer for
operations involving mixed signedness:
TYPE

u_type

O.. 2147483647;

VAR
integer32;
u_type;
integer32;

s32
u32
a

a

.-

s32 DIV integer32(u32);

{ Compiler generates a signed
divide. }

{ OR }

a

.-

u_type(s32) DIV u32;

{ Compiler generates an unsigned
divide. }

Code

4-7

4.4 Overview: 1/0
Domain Pascal supports the I/O procedures described in Table 4-5. For details on these
routines, consult the encyclopedia later in this chapter and Chapter 8.

Table 4-5. Predeclared I/O Procedures
Name

Action

close

Closes a file.

eof

Tests whether the stream marker is pointing to the end of the file.

eoln

Tests whether the stream marker is pointing to the end of a line.

find

Sets the stream marker to the specified record.

get

Reads from a file.

open

Opens a file for future access.

page

Inserts a formfeed (page advance) into a file.

put

Writes to a file.

read

Reads information from the specified file (or from the keyboard) into
the specified variables. After reading the information, read positions
the stream marker so that it points to the character or component immediately after the last character or component it read.

readln

Similar to read except that after reading the information, readln positions the stream marker so that it points to the character or component
immediately after the next end-of-line character.

replace

Substitutes a new record component for an existing record.

reset

Specifies that an open file be open for reading only.

rewrite

Specifies that an open file be open for writing only, or tells the
system to open a temporary file.

write

Writes the specified information to the specified file (or to the screen).

writeln

Same as write except that writeln always appends a linefeed to its
output.

4.5 Overview: Miscellaneous Routines and Statements
Table 4-6 lists several Domain Pascal elements that do not fit neatly into categories.

4-8

Code

Table 4-6. Miscellaneous Elements
Element

Action

addr
append

Returns the address of the specified .variable.
Concatenates two or more strings.

chr

Finds the character whose ISO Latin-l value equalshe specified number.

ctop

Converts a C-style string into a Domain Pascal variable-length string.

discard

Explicitly discards a computed value.

dispose

Deallocates the storage space that a dynamic record was using.

exit

Transfers control to the first statement following a for, while, or repeat loop.

firstof

Returns the first possible value of a type or a variable.

goto

Unconditionally jumps to the first command following the specified label.

in_range

Tells you if the specified value is within an enumerated variable's defined range.

lastof

Returns the last possible value of a type or a variable.

max

Returns the larger of two expressions.

min

Returns the smaller of two expressions.

new

Allocates space for storing a dynamic record.

next

Transfers control to the test for the next iteration of a for, while, or repeat loop.

nil

A special pointer value that points to nothing.

ord

Finds the ordinal value of a specified integer, Boolean,enumerated, or char type.

pack

Copies unpacked array elements to a packed array.

pred

Finds the predecessor of a specified value.

ptoc

Converts a Domain Pascal variable-length stringinto a C-style string.

return

Causes program control to jump back to the calling procedure or function.

sizeof

Returns the size (in bytes) of the specified data type.

substr

Extracts a substring from a string.

succ

Finds the successor of a specified value expression in the code portion of your
program.

type transfer
functions

Permits you to change the data type of a variable or expression in the code
portion of your program.

unpack

Copies packed array elements to an unpacked array.

with

Lets you abbreviate the name of a record. With is standard, but Domain Pascal
includes an extension that supports a name tag.

!

Code

4-9

4.6 Overview: Systems Programming Routines
Several Domain Pascal routines are available for systems programmers' use. Table 4-7 lists
these routines. Because only a few programmers will need to use these routines, they are
not described in the encyclopedia section that follows. Instead, they appear in Appendix E.

Table 4-7. Systems Programming Routines
Routine

Action

disable

Turns off the interrupt enable in the hardware status register.

enable

Turns on the interrupt enable in the hardware status register.

set_sr

Saves the current value of the hardware status register and then
inserts a new one.

4.7 Encyclopedia of Domain Pascal Code
The remainder of this chapter contains an explanation of the concepts and keywords that
you can use in the action part of a Domain Pascal program or routine. These items are
listed alphabetically.
The concepts that we include are as follows:

•
•
•
•
•
•
•
•
•
•

4-10

Code

Array operations
Bit operators
Compiler directives
Expressions
Pointer operations
Record operations
Set operations
Statements
Type transfer functions
Variable-length string operations

The keywords that we include are:

end

for
get
goto
if
in
in_range

new
next
nil
not
odd
open

arctan

eof

lastof

or

arshft
begin

eoln
exit

In
Ishft

case
chr
dose

exp
find
firstof

max
min
mod

abs
addr
align
and
and then
append

cos
ctop
discard
dispose
div

ptoc
put
read, readln
repeat/until
replace

sqr
sqrt
substr
succ
trunc
unpack

reset
return

while

ord
or else

rewrite

with

round

write, writeln

pack
page
pred

rshft
sin
sizeof

xor

Code

4-11

Abs

Abs Returns the absolute value of an argument.

FORMAT

{abs is a function.}

abs(number)

ARGUMENTS
number

Any real or integer expression.

FUNCTION RETURNS

The abs function returns a real value if number is real and an integer value if number is
an integer.

DESCRIPTION

The abs function returns the absolute value of the argument. The absolute value is the
number if it is nonnegative, and the negative of the number if it is negative. Note that
number cannot be -2147483648 (which is the lowest negative integer).

EXAMPLE

program abs example;
{ This prog;am displays the absolute values for two numbers }
VAR
x
INTEGER;
REAL;
Y
BEGIN
x := ABS(x);
x := -3;
y := ABS(y);
y := -456.78;
WRITELN(x,Y);
END.

USING THIS EXAMPLE
If you execute the sample program named abs_example, you get the following output:

3

4-12

Code

4. 567800E+02

Addr

Addr Returns the address of the specified variable. (Extension)

FORMAT
addr(x)

{addr is a function.}

ARGUMENTS

x

Can be a variable declared as any data type except as a procedure or
function data type having the internal attribute. x can also be a string
constant but it cannot be a constant of any type other than string.

FUNCTION RETURNS
The addr function returns an univ_ptr value. (Chapter 3 describes the univ_ptr data
type.)

DESCRIPTION
Use addr to return the address at which variable x is stored. If x is a variable-length
string, addr returns the address of the entire record, not the address of the string component. Addr is particularly useful with variables defined as pointers to functions or procedures.
Using addr can prevent some compiler optimizations. If you apply addr to a variable that
is local to a routine, and the variable is not a set, record, or array, you do not get optimizations and register allocation for that variable or any expressions using the variable.
This means the routine's code might be larger and slower than it otherwise would be.
Applying addr to a variable is equivalent to declaring the variable volatile. See Chapter 3
for more information on volatile.
Refer to the "Pointer Operations" listing later in this chapter for an example of addr.

Code

4-13

Addr
NOTE:

The compiler issues a warning if you assign the result of addr to a
pointer type variable that expects an alignment greater than the
alignment of the addr result. For example,
TYPE
natural _integer = [natural] integer32;
rec = record
integer16;
int16
[ALIGNED (1)] integer32;
int32
end;
VAR

iptr
"'natural- integer;
r: rec
BEGIN
iptr := ADDR (r.int32)
END;
In this example, the assignment of addr(r.int32) to iptr causes a
compile-time warning. The code in the example declares iptr as
a pointer to a naturally aligned integer32 type, but assigns to it the
address of a word-aligned object, r.int32. (See the "Internal
Representation of Records" and" Alignment" sections of Chapter 3 for further details about alignment.)

EXAMPLE

Program addr_example;
{This program displays the contents stored at an address returned}
{by the addr function}
TYPE
ptr_to_real
"'real;
VAR
y, y2
real;
ptr_to_y
ptr_to_real;
BEGIN
write('Enter a real number -- ');
readln(y);
ptr to y := ADDR(y);
- - {Set ptr_to_y to the address at which y is stored. }
y2 := ptr_to_y"';
{ Set y2 to the contents stored at y's address;
}
{ i.e., set y2 equal to y. }
writeln(y2);
END.

4-14

Code

Addr

USING THIS EXAMPLE
Following is a sample run of the program named addr_example:

Enter a real number -- 5.3
5.300000E+OO

Code

4-15

Align

Align Causes the compiler to copy an expression that is being passed as a parameter. (Extension)

FORMAT
align (expression);

{align is a function.}

ARGUMENTS

expression

Any valid Domain Pascal expression that is being passed as an input
parameter to a routine.

FUNCTION RETURNS
The align function returns a correctly aligned copy of expression.

DESCRIPTION
The align function tells the compiler to make a copy of an expression passed as an in parameter to an external routine. The alignment of the copy matches the alignment specified
for the formal parameter. The compiler uses the copy as the actual parameter when the
external routine is called.
The align function is useful for making sure that expressions are correctly aligned when
they are passed as arguments to functions and procedures. An expression is correctly
aligned if its alignment matches the alignment specified for it in the formal parameter definition.
The main use of the align function is to pass a record field that is not naturally. aligned to
a routine that expects the parameter to be naturally aligned. This use is illustrated in the
example.
Although correct alignment for parameters passed by reference generally produces at least
somewhat faster executable code on all Apollo workstations, the improvement is very significant on Series 10000 workstations. If you run your program on a Series 10000 workstation and the compiler assumes that an object is naturally aligned when in fact, it is not
naturally aligned, your program will suffer a severe loss of efficiency.

4-16

Code

Align
EXAMPLE

PROGRAM align example;
{This program-shows how to use the ALIGN function, a Domain Pascal
}
{extension that causes parameters passed as IN parameters to external }
{functions to be aligned according to the expectations of the called }
{routine.
}
{NOTE: You must also compile the add_em Pascal program and bind it
}
with align_example to get an executable file.
}
{
TYPE
rec
record
short_num
integer16;
long_num
integer32; {this field is not naturally aligned}
end;
VAR

sum: rec;
1,J : integer32;

FUNCTION add_em (IN x
y,

z

integer32;
integer32 ) :integer32; extern;

BEGIN
with sum do
begin
short_num := 7;
long_num .- 3;
end;
i := 1;
j := 1942;
write('The sum of the numbers is ');
writeln(add_em(ALIGN(Sum.long_num), i,j»;
{use the ALIGN function to make sure that sum.long_num is }
{naturally aligned when it is passed to the add_em function}
{If you omit the ALIGN function, you get a warning from
}
{the compiler.
}
END.
MODULE add_em;
{This function is called by the align_example program}
FUNCTION add_em (IN x
integer32;
y,z : integer32) : integer32;
BEGIN
add_em:= x+y+z;
END;
These programs are available online and are named align_example and add_em. A sample run of the program is shown below:
The sum of the numbers is

1946

Code

4-17

And, And Then

I

And, And Then Calculate the logical and of two Boolean arguments.

•

FORMAT

x and y
x and then y

•

{and is an operator.}
{and then is an operator.}

ARGUMENTS

x, y

Any Boolean expressions.

OPERATOR RETURNS

•

The result of an and or an and then operation is a Boolean value.

DESCRIPTION
Sometimes and is called Boolean multiplication. Use it to find the logical and of expressions x and y. Here is the truth table for and:

x

y

Result

true
true
false
false

true
false
true
false

true
false
false
false

(See also the listings for the logical operators or and not later in this encyclopedia).
NOTE:

Some programmers confuse and with &. & is a bit operator; it
causes Domain Pascal to perform a logical and on all the bits in
its two arguments. For example, compare the following results:
the result of (true and false) is false
the result of (75 & 15) is 11
(Refer to "Bit Operators" later in this encyclopedia.)

4-18

Code

And, And Then
The Boolean operator and then is a Domain extension to standard Pascal. You can use
and then in any statement where you use and in standard Pascal. The choice between
and and and then, however, affects the run-time evaluation of a statement.
When and then appears between two Boolean operands in an expression, the system begins evaluating the operands in the order in which they appear. If the first operand is
false, the system does not evaluate the second. If one operand is false, then the entire
expression is false.
Hence, and then guarantees "short-circuit" evaluation. That is, at run time, the system
evaluates an operand only if necessary.
For example, in the statement

IF boolean 1 AND THEN boolean_2
THEN ...
the system first evaluates boolean_I. If boolean_l is false, the system does not evaluate
boolean_2. In this statement, the operands boolean_l and boolean_2 can be any valid
Pascal Boolean expressions.
The operator and then can be more efficient than and. For example, in the statement

IF boolean 1 AND boolean_2
THEN ...
the system may evaluate both boolean_l and boolean_2 to test if the statement is true.
Also, there is no guarantee that the system will evaluate the two operands in the order in
which they appear.
The and then operator helps you avoid nested constructions. For example, compare the
standard Pascal code on the left with the equivalent Domain Pascal code on the right:
Standard Pascal

Domain Pascal

WHILE c1 DO
WHILE c2 DO

WHILE c1 AND THEN c2 DO
81;

81;

In this example, the standard Pascal code contains one while loop nested within another.
The Domain Pascal code, however, contains only one loop.

Code

4.... 19

And, And Then

I

The following example illustrates how to avoid referencing a NIL pointer through the use
of the and then operator:

WHILE P <> NIL AND THEN NOT pA.flag DO
p : = p A. next;

EXAMPLE

The following example uses an and operation to calculate the gravitational force between
two objects.

Program and_example;
CONST
g = 6.6732e-11;
VAR

mass!, mass2, radius, force: single;
BEGIN
write('This program finds the gravitational force between two ');
writeln('objects.');
write('Enter the mass of the first object (in Kg) -- ');
readln(mass1);
write('Enter the mass of the second object (in Kg) -- ');
readln(mass2);
write('Enter the dist. between their centers (in M) -- ');
readln(radius);
if (mass! > 0.0) AND (mass2 > 0.0)
then force := (g * mass! * mass2) / sqr(radius)
else begin
writeln('The data you have entered seems inappropriate');
return;
end;
writeln('The force between these two objects is
force:9:7, ' N');
END.

USING THIS EXAMPLE

This program is available online and is named and_example.

4-20

Code

Append

Append

Concatenates two or more strings. (Extension)

FORMAT
append(dst_string, sl, s2, s3, s4, sS, s6, s7, s8, s9);

{append is a procedure.}

ARGUMENTS
A variable-length character string.
sl

A variable-length string, character array, or character-string constant that
will be appended to the destination string.

s2 .. s9

Optional arguments. Up to nine variable-length strings, character arrays,
and character-string constants may be appended to the destination string.

DESCRIPTION
append builds a destination string by concatenating the destination string and up to nine
additional strings.
An error trap is generated if concatenating the source string(s) with the destination string
results in a string that is larger than the maximum size of the destination string.

EXAMPLE

PROGRAM append_example;
VAR

str1
str2
str3

varying [100] of char;
varying [20] of char;
array[l .. 20] of char;

BEGIN
str1 .- 'one ... ';
str2 .- 'two ... ';
str3 .- 'three ... ';
append (str1, str2, str3, 'four');
writeln(str1);
END.

Code

4-21

Append

USING THIS EXAMPLE
Executing this program, named append_example, results in the following output:
one ... two ... three ...

four

Note that the fixed-length array, str3, is padded with spaces, whereas the variable-length
strings are not padded. Also note that the first parameter must be a variable-length string.

4-22

Code

Arctan

Arctan Returns the arctangent of a specified number.

FORMAT
{arctan is a function.}

arctan (number)

ARGUMENTS
number

Any real or integer expression.

FUNCTION RETURNS
The arctan function returns a real value for the angle in radians.

DESCRIPTION
The arctan function returns the arctangent (in radians) of number. The arctangent of a
number has the following relationship to the tangent:

y = arctan(x) means that x = tan(y)
Note that Pascal does not support a predeclared tangent function. However, you can find
tangent(x} by dividing sin(x} by cos(x}.

Code

4-23

Arctan

EXAMPLE

PROGRAM arctan example;
{ This progr;m demonstrates the ARCTAN function. }
CONST
degrees_per_radian

180.0 / 3.14159;

VAR
q, answer_in_radians
answer_in_degrees

REAL;

INTEGER16;

BEGIN
q := 2.0;
{First, find the arctangent of 2.0 in radians. }
answer_in_radians := ARCTAN(q);
writeln('The arctan of " q:5:3, ' is', answer_in_radians:6:3,
, radians');

{Now, convert the answer to degrees. }
answer_in_degrees := round(answer_in_radians * degrees_per_radian);
writeln('The arctan of " q:5:3, ' is " answer_in_degrees:l,
, degrees');
END.

USING THIS EXAMPLE
If you execute the sample program named arctan_example, you get the following output:

The arctan of 2.000000E+00 in radians is 1.107149E+00
The arctan of 2.000000E+00 in degrees is 63

4-24

Code

Array Operations

Array Operations
Chapter 3 explains how to declare and initialize an array. In this listing, we explain how to
use arrays in the code portion of your program. See "Variable-Length String Operations"
in this chapter for information about accessing varying arrays of chars.

ASSIGNING VALUES TO ARRAYS

To assign a value to an array variable, you must supply the following information:
•

The name of the array variable.

•

An index expression enclosed in brackets. The value of the index expression must
be within the declared subrange of the index type.

•

A value of the component type.

For example, the following program fragment assigns values to four arrays:

TYPE
{elements is an enumerated type.}
elements
(H, He, Li, Be, B, C, N, 0, FI, Ne);
student = record
name: packed array [1 .. 50] of char;
id
integer16;
class: (freshman, sophomore, junior, senior);
end;
VAR

{Here are four array declarations.}
test_data
array[1 .. 100] of INTEGER16;
atomic_weights
array[H .. Be] of REAL;
lie_test
array[1 .. 4, 1 .. 2] of BOOLEAN; {2-dimensional array}
enrollment
array[1 .. 500] of student;
BEGIN
test_data [37]
:=
atomic_weights [He] :=
lie_test [3, 2]
:=
enrollment[30].name
enrollment[30].id
enrollment [30] .class

9018;
4.0;
true;
.- 'Betsy Ross' ;
:= 8245;
.- senior;

Code

4-25

Array Operations
There are a few exceptions to the rule that you must supply an index expression.
The first exception is that you can assign a string to an array of char variable without
specifying an index expression; for example, consider the following assignments to greeting
and farewell:

CONST
hi

'aloha';

VAR
greeting, farewell

array[1 .. 12] of CHAR;

BEGIN
greeting : = hi;
farewell := 'a bientot';
The only restriction on this kind of assignment is that the number of bytes in the string
must be less than or equal to the declared number of declared components in the array.
For example, you cannot assign the string 'auf wiedersehen' to farewell because the string
contains 15 bytes and the array is declared as only 12 bytes. If you do try that assignment,
the compiler will give you the following error message:

Assignment statement expression is not compatible with the
assignment variable.
There is a second exception to the rule that you must specify an index expression when
assigning a value to an array. The exception is that you can assign the value of one array
to another array if both arrays are char arrays that contain the same number of bytes. For
example, in the following program fragment, a, b, and e are the same size, while c and d
are uniquely declared:

I

CONST
quote = 'Ottawa!';
VAR
a
b
c
d
e

I

BEGIN
a
b
e
c

I

4-26

Code

array[1 .. 20] of CHAR;
array[1 .. 20] of CHAR;
array[1 .. 21] of CHAR;
array[1 .. 19] of CHAR;
array[21 .. 40] of CHAR;

.-

..-

.-

quote; {Assign the string 'ottawa!' to array a.
}
a; {This is a valid assignment.
}
a: {This is a valid assignment.
}
a; {WRONG!}
{This is not a valid assignment because a and c }
}
{ have different declared lengths.

Array Operations
d .- a;

{WRONG!}
{This is not a valid assignment because a and d }
{ have different declared lengths.
}

The assignment b := a causes Domain Pascal to assign all components of array a to the
corresponding indices in array b; that is, b := a is equivalent to the following 20 assignments:
b[l]
b [2]

.- a[l];
. - a [2] ;

b[20]

.- a[20];

NOTE:

In standard Pascal, before assigning a string to an array, you must
explicitly pad the string to the length of the array. Domain Pascal
automatically pads with spaces any string of fewer than 4096 characters.

I

USING ARRAYS

You can specify an array component wherever you can specify a component variable of the
same data type. In other words, if the compiler expects a real number, you can specify any
real expression including a component of an array of real numbers.

Code

4-27

Array Operations

EXAMPLE

PROGRAM array_example;
{This simple example reads in five input values, assigns the values to}
{elements of an array, and then finds their mean.
}
CONST
VAR

a : arraY[l .. number_of_elements] of single;
running_total : single := 0.0;
n : integer16;
BEGIN
for n := 1 to number_of_elements do
begin
write('Enter a value -- ');
readln(a[n]);
end;
for n := 1 to number_of_elements do
running_total := running_total + a[n];
writeln(chr(lO) ,'The mean is "

running_total/number_of_elements:3:1);

END.

USING THIS EXAMPLE

Following is a sample run of the program named array_example:
Enter
Enter
Enter
Enter
Enter

a
a
a
a
a

value
value
value
value
value

The mean is 6.4

4-28

Code

4.3
10.3
9.5

6.2
1.5

Arshft

Arshft Shifts the bits in an integer to the right by a specified number of bits. Preserves the sign of

the integer. (Extension)

FORMAT
arshft(num, sh)

{arshft is a function.}

ARGUMENTS
Must be integer expressions. sh should be nonnegative.

num, sh

FUNCTION RETURNS
The function returns an integer value.

DESCRIPTION
Arshft does an arithmetic right shift of an integer. The arshft function tells the compiler
to preserve the sign bit of num and shift the other bits sh positions to the right. The expression num can be any integer expression smaller than 32 bits.

Say, for example, num is a 16-bit integer and the result of the function is to be stored in
a 16-bit integer variable. In this case, arshft expands num to a 32-bit integer, performs
the shift, and then converts it back to a 16-bit integer.
First examine how arshft shifts a positive integer. Consider the effect of arshft on the
16-bit positive integer + 100 in the following table:
unshifted
ARSHFT(+100, 1)
ARSHFT(+100,2)
ARSHFT(+100,3)

0000000001100100
0000000000110010
0000000000011001
0000000000001100

+100
+50
+25
+12

Notice three things in the preceding table. First, the sign bit (the leftmost bit) never
changes. Second, notice that the bits move to the right. Third, notice that the bits do not
wrap around from right to left; the absolute value always gets smaller.

Code

4-29

Arshft
Now, examine how arshft shifts a negative integer. Consider the effect of arshft on the
16-bit negative integer -100 in the following table:

unshifted
ARSHFT(-100,1)
ARSHFT(-100,2)
ARSHFT(-100,3)

1111111110011100
1111111111001110
1111111111100111
1111111111110011

-100
-50
-25
-13

In contrast to the preceding table, notice that arshft fills the leftmost bits with ones rather
than zeros as the rightmost bits are shifted off the right end of the number.
Results are unpredictable if sh is negative.

EXAMPLE

PROGRAM arshft_example;
{ This program compares ARSHFT with RSHFT. }
VAR

integer32 .- 0;
BEGIN
write('Enter a positive or negative integer -- ');
readln(original_number );
for spaces_to_shift .- 1 to 5 do
BEGIN
writeln;
writeln('When shifted " spaces_to_shift:l, , spaces.');
r := RSHFT(Original_number, spaces_to_shift);
writeln('
The rshft result is " r:l);
ar := ARSHFT(Original_number, spaces_to_shift);
writeln('
The arshft result is " ar:l);
END;
END.

USING THIS EXAMPLE
This program is available online and is named arshft_example.

4-30

Code

Begin

Begin Marks the start of a compound statement.

FORMAT

begin is a reserved word.

DESCRIPTION

Begin and end establish the limits of a sequence of Pascal statements. A program must
contain at least as many ends as begins. (Note that a program can contain more ends then
begins.) You must use a begin/end pair to indicate a compound statement. (Refer to the
"Statements" listing later in this encyclopedia.)

EXAMPLE

{This program does very little work, but does have lots of BEGINS}
{and ENDs.
}
TYPE
student = record
age : 6 .. 12;
id : integer16;
end; {student record definition}
VAR

x

integer32;

PROCEDURE do_nothing;
BEGIN
{do_nothing}
writeln('You have triggered a procedure that does absolutely nothing.');
writeln('Though it does do nothing with elan.').
END;
{do_nothing}
FUNCTION do_next_to_nothing(var y
BEGIN {do_next_to_nothing}
do_next_to_nothing := abs(y);
END;
{do_next_to_nothing}

integer32)

integer32;

Code

4-31

Begin
BEGIN {main procedure}
write('Enter an integer -- ');
readln(x);
if x < 0
then BEGIN
writeln('You have entered a negative number!!!');
writeln('Its absolute value is
do_next_to_nothing(x):l);
END
else if x = 0
then BEGIN
writeln('You have entered zero');
do_nothing;
END
else
writeln('You have entered a positive number!! !');
END.
{main procedure}

USING THIS EXAMPLE

This program is available online and is named begin_end_example.

4-32

Code

Bit Operators

Bit Operators Calculate and, or, and not on a bit-by-bit basis. (Extension)

FORMAT
opJ & op2
opJ lop2
-opJ

{& (an ampersand) is bit and.}
{I (an exclamation point) is bit or.}
(a tilde) is bit not.}

r

ARGUMENTS
opJ, op2

Must be integer expressions.

OPERATOR RETURNS
All three operators return integer results.

DESCRIPTION
Domain Pascal supports three bit operators, all of which are extensions to standard Pascal.
The operators perform operations on a bit-by-bit level using the following truth tables:
Table 4-8. Truth Table for & (Bitwise And Operator)
& (and)

bit x
of opt

bit x
of op2

0
0
1
1

0
1
0
1

bit x of
result
0
0
0
1

Code

4-33

Bit Operators

Table 4-9. Truth Table for ! ( Bitwise Or Operator)
! (or)

bit x
of opl

bit x
of op2

0
0

0

0

1

1
1

0

1
1
1

bit x of
result

1

Table 4-10. Truth Table for - (Bitwise Not Operator)
- (not)
bit x
of opl

bit x of
result

0

1

1

0

Don't confuse these bit operators with the logical operators. Bit operators take integer operands; logical operators take Boolean operands.
In addition to the three bit operators, Domain Pascal supports the following bit functions:
Ishft, rshft, arshft, and xor. All of these functions have their own listings in the encyclopedia.
NOTE:

If one of the operators is declared as integer32, and the other

operator is declared as integerl6, Domain Pascal extends the integerl6 to an integer32 before calculating the answer.
When performing these bitwise operations, Domain Pascal treats
the sign bit just as it treats any other bit.

4-34

Code

Bit Operators

EXAMPLE

PROGRAM bit_operators_example;
{ This program demonstrates bitwise AND, OR, and NOT. }
CONST
{ The 2# prefix specifies a base 2 number. }
x = 2#0000000000001010; {10}
y = 2#0000000000010111; {23}
VAR

resultl, result2, result3
BEGIN
resultl .- x & y;
result2 .- x ! y;
result3 .- -x;
END.

integer16;

writeln(x:l, ' AND " y:l, ' = " resultl:l);
writeln(x:l, ' OR " y:l, ' = " result2:1);
writeln('NOT " x:l, ' = " result3:1);

USING THIS EXAMPLE
If you execute the sample program named bit_operators_example, you get the following
output:

10 AND 23 = 2
10 OR 23 = 31
NOT 10 = -11

Code

4-35

Case

Case A conditional branching statement that selects among several statements based on the value of
an ordinal expression.

FORMAT
There are two different forms of the case statement. Here, we describe the use of case in
the body of your program. The other use of case is in the variable or type declaration portion of the program. (See the "Variant Records" section in Chapter 3 for details on this
use.)
Case takes the following syntax:
case expr of
constant list 1 : stmnt 1 ;

{case is a statement.}

constantlistN : stmntN;
otherwise stmnt_list;
end;

ARGUMENTS

4-36

expr

Any ordinal expression (variable, constant, etc.) The ordinal types are
integer, Boolean, char, enumerated, and subrange. You cannot specify an
array as an expr, though you can specify an element of an array (assuming the element has an ordinal type). Also, you cannot specify a record,
though you can specify a field of the record (assuming the field has an
ordinal type).

constantlist

One or more values (separated by commas) having the same data type as
expr.

stmnt

A simple statement or a compound statement (refer to the "Statements"
listing later in this encyclopedia).

stmnt_list

One or more statements associated with the optional otherwise clause.
(The otherwise clause tells the system to execute stmnt_list if expr
matches none of the constants in any of the constantlists.) The stmnt_list
differs from a compound statement in that you do not have to bracket
the stmnt_list with a begin/end pair (though doing so does not cause an
error) .

Code

Case

DESCRIPTION
The case statement performs conditional branching. It is very useful in situations involving
a multi-way branch. When the value of expr equals one of the constants in a constantlist ,
the system executes the associated stmnt.
Note that case and if/then/else serve nearly identical purposes. The differences between
case and if/then/else are:
•

Case can compare only ordinal values. If/then/else can compare values of any
data type.

•

The system can sometimes execute a case statement faster than an equivalent iff
then/else statement. That's because the Domain Pascal compiler sometimes translates a case statement into a dispatch table and always translates an if/then/else
statement into a series of conditional tests.

Also, note that a case statement is often more readable than an if/then/else statement.
For instance, compare the following if/then/else statement to its equivalent case statement:

IF grade = 'A' THEN
write('Excellent')
ELSE IF grade = 'B' THEN
wri te ('Good')
ELSE IF grade = 'c' THEN
wri te (' Average')
ELSE IF grade = '0' THEN
wri te (' Poor' )
ELSE IF grade = 'F' THEN
write('Failing');

CASE grade OF
'A'
write('Excellent');
'B'
write('Good');
'c'
write('Average');
'0'
write('Poor');
'F'
write('Failing');
end;

Otherwise-Extension
As an extension to the case statement, Domain Pascal supports the otherwise clause. The
otherwise clause tells the compiler to execute stmnt_list if expr matches none of the constants in any of the constant lists . For example, you can write the preceding case example
as follows. Notice that you do not put a colon {:} after the keyword otherwise.

CASE grade OF
'A'
write('Excellent');
'B'
write('Good');
'c'
write('Average');
'0'
write('Poor');
OTHERWISE write('Failing');
end;

Code

4-37

Case
As mentioned earlier, the begin/end pair is optional in an otherwise clause. Therefore,
these two case statements are equivalent:
CASE number OF
1, 2, 3 : writeln('Good');
OTHERWISE writeln('Great.');
writeln('Encore.');
end;

CASE number OF
1,2, 3 : writeln('Good');
OTHERWISE begin
writeln('Great');
writeln('EnCore');
end;
end;

EXAMPLE

PROGRAM case_example;
{ This program demonstrates the use of the case statement }
VAR

char;
sale
boolean;
price
array[l .. 5] of char;
BEGIN
write('Is whole wheat bread on sale today? -- ');
readln(a_letter);
CASE a letter OF
'y', 'Y'
sale := true;
begin
'n', 'N'
sale := false;
writeln('Remember to tell them it"s organic.');
end;
begin
OTHERWISE
writeln('You have made a mistake.');
writeln('The correct. response was YES or NO');
writeln('please rerun the program');
return;
end;
end; {CASE}
if sale then
price .- '$1.99'
else
price .- '$2.99';
writeln('Mark it as' price:5);
END.

USING THIS EXAMPLE

This program is available online and is named case_example.

4-38

Code

Chr

Chr Returns the character whose ISO Latin-l value corresponds to a specified ordinal number.

FORMAT

chr(number)

{chr is a function.}

ARGUMENTS

number

An integer.

FUNCTION RETURNS
The chr function returns a value with the char data type.

DESCRIPTION
The chr function returns the character that has an ISO Latin-l value equal to the value of
the low eight bits of number. Appendix B contains a table of ISO Latin-l values.
Chr produces a character with the bit pattern
number & 16#FF
Usually, number is between 0 and 127, in which case the character that chr returns is simply the character that has the ISO Latin-1 value of number. If number is greater than 127,
chr returns the character having the ISO Latin-l value of
number MOD 256
See the mod listing later in this encyclopedia.
Note that the ord function is the inverse of chr when ord's argument type is char. (See
the ord listing later in this encyclopedia.)

Code

4-39

Chr

EXAMPLE

PROGRAM chr example;
{ This program demonstrates three uses for the CHR function.

}

VAR

capital_letter: 65 .. 90;
y : CHAR;
age: 10 .. 99;
c_array: array[1 .. 2] of char;
BEGIN
{ First, we'll use CHR to convert an integer to its ISO Latin-1 value.}
write('Enter an integer from 65 to 90 -- ');
readln(capital_letter);
y := CHR(capital_letter);
writeln(capital_letter:1,
corresponds to the' y:1, ' character');
writeln;
{ Second, we'll use CHR to ring the node bell.
write(chr(7»;

}

{ The graphics primitive function gpr_$text writes character arrays}
{ to the display. But suppose you want gpr_$text to write an
}
{ integer. In order to accomplish this task, you would write a
}
{ routine similar to the following. which converts a 2-digit integer}
{ into a 2-character array. Note that 48 is the ISO Latin-1 value }
{ for the '0' character, 49 for the '1' character, and so on up to }
{ 57 for the '9' character.
}
write('Enter an integer from 10 to 99 -- '); readln(age);
c_array[l] := CHR«age DIV 10) + 48);
c_array[2] := CHR«age MOD 10) + 48);
writeln('The first digit is " c_array[l]:l);
writeln('The second digit is
c_array[2]:1);
writeln('The entire array is " c_array);
END.
USING THIS EXAMPLE

Following is a sample run of the program named chr_example:
Enter an integer from 65 to 90 -- 83
83 corresponds to the S character
Enter an integer from 10 to 99 -- 71
The first digit is 7
The second digit is 1
The entire array is 71

4-40

Code

Close

Close Closes the specified file. (Extension)

FORMAT
{close is a procedure.}

close (filename)

ARGUMENTS
A file variable.

filename

DESCRIPTION
Use the close procedure to close the file filename that you opened with the open procedure. By closing, we mean that the operating system unlocks it. When a program terminates (naturally or as a result of a fatal error), the operating system automatically closes all
open files. So the close procedure is optional.
You cannot close the predeclared files input and output, but if you try, Domain Pascal
does not issue an error.
If filename is a temporary file, close (filename) deletes it.

Please see Chapter 8 for an overview of I/O.
NOTE:

For permanent text files, your program should issue a writeln to
the file just before closing it in order to flush the file's internal
output buffer. If you don't include that writeln, the last line of
the file may not be written.

EXAMPLE

PROGRAM close_example;
{ This program demonstrates the CLOSE procedure. }
CaNST
pathname
VAR
class
name
status

= 'primates';
text;
{a file variable}
array[l .. 20] of char;
integer32;

Code

4-41

Close
begin
writeln('This program writes data to file "primates"');
open(class, pathname, 'NEW', status);
if status = 0 then
rewrite(class)
else
return;

{Open a file for writing.}

writeln('Enter the names of the children in your class -- ');
writeln('The last entry should be "end"');
repeat
read In (name) ;
if name <> 'end' then
writeln(class, name)
else
exit;
until false;
CLOSE (class) ;

{

{Close the file for writing.}

}

{ Execute some time-consuming routines that do not access 'primates'. }

{

}

{Now, re-open the file for reading.}
open(class, pathname, 'OLD', status);
reset(class);
writeln;
writeln('Here are the names you entered:');
repeat
readln(class, name);
writeln(name) ;
until eof(class);
CLOSE(class);
end.

USING THIS EXAMPLE

This program is available online and is named close_example.

4-42

Code

Compiler Directives

Compiler Directives Specify a variety of special services including conditional compilation and
include files. (Extension)

FORMAT
The Domain Pascal compiler understands the directives shown in Table 4-11. All directives
begin with a percent sign (%). You can specify a directive anywhere a comment is valid.
To use a directive, specify its name as a statement or inside a comment. (There is one
exception: directives associated with the -config option cannot be used as comments.) For
example, all of the following formats are valid:

%directive
{%directive}
(* %directive*)

If you specify a directive within a comment, the percent sign must be the first character

after the delimiter (where spaces count as characters). In addition, you do not need to put
a semicolon at the end of the directive.
You must place a semicolon after some directives if you use them as statements. Those
directives are:

•
•
•
•
•
•
•
•
•
•

I

%begin_inline;
%begin_noinline;
%debug;
%eject;

I

%end_inline;
%end_noinline;
%include 'pathname';
%list;

•

%natural_alignment;
%nolist;

Code

4-43

Compiler Directives

•

•

%slibrary 'pathname';

•

%word_alignment;

Table 4-11. Compiler Directives

*

*
*
*
*

Directive

Action

%begin_inline;

Directs the compiler to expand subsequent routines inline,
if -opt 3 or -opt 4 is specified.

%begin_noinline;

Directs the compiler not to expand subsequent routines
inline, even if -opt 4 is specified.

%config

Lets you easily set up a warning message if you forget
to compile with the -config compiler option.

%debug;

Directs Domain Pascal to compile lines prefixed with this
directive when you use the -cond compiler option. If
you do not use -cond when you compile, lines prefixed
with %debug are not compiled.

%eject;

Directs Domain Pascal to put a formfeed in the listing file
at this point.

%else

Specifies that a block of code should be compiled if
the preceding %if predicate %then is false.

%elseif predicate %then

Directs the compiler to compile the code until the
next %else, %elseif, or %endif directive, if and
only if the predicate is true.

%elseifdef predicate %then

Checks whether additional predicates have been
declared with a %var directive.

%enable;

Sets compiler directive variables to true.
Directs the compiler to stop inline expansion, if -opt 3 or
-opt 4 is specified.

%end_noinline;

Allows the compiler to resume inline expansion, if -opt 4
is specified.

Marks the end of a conditional compilation area of
* %endif
the program.
Prints 'string' as an error message whenever you compile.
* %error 'string'
* is a directive described in "Directives Associated with the -Config Option" later in this chapter.

(Continued)

4-44

Code

Compiler Directives
Table 4-11. Compiler Directives (Cont.)
Directive

Action

*
*

%exit

Directs the compiler to stop conditionally processing
the file.

%if predicate %then

Directs the compiler to compile the code until the next
%else, %elseif, or %endif directive, if and only if the
predicate is true.

*

%ifdef predicate %then

Checks whether a predicate was previously declared with
a %var directive.

%include 'pathname';

Causes Domain Pascal to read input from the specified file.

%list;

Enables the listing of source code in the listing file.

%natural_alignment;

Sets environment to natural alignment.

%nolist;

Disables the listing of source code in the listing file.

%slibrary 'pathname';

Causes Domain Pascal to incorporate a precompiled
library into the program.

%pop_alignment;

Saves the current alignment by pushing it onto a stack.

%push_alignment;

Restores the alignment saved by the last %push_alignment.

%var

Lets you declare variables that you can then use as
predicates in compiler directives.

%warning 'string'

Prints 'string' as a warning message whenever you compile.

%word_alignment;

Sets environment to default alignment.

*

* is a directive described in "Directives Associated with the -Config Option" later in this chapter.
DIRECTIVES ASSOCIATED WITH THE -CONFIG OPTION
This subsection describes the following compiler directives: %if, %then, %elseif, %else,
%endif, %ifdef, %elseifdef, %var, %enable, %config, %error, %warning, and %exit.
The conditional directives mark regions of source code for conditional compilation. This
feature allows you to tailor a source module for a specific application. You invoke conditional processing by using the -config option when you compile. Unlike the other compiler
directives, conditional directives cannot be used as comments.

Code

4-45

Compiler Directives
Several of the directives take a predicate. A predicate can contain any of the following:
•

Special variables that you declare with the %var directive

•

Optional Boolean keywords not, and, or or

•

A predeclared conditional variable, _BFMT__COFF
BFMT__ COFF is a Boolean variable. The value of BFMT__ COFF is set
to true whenever the compiler is generating COFF (Common Object File Format) files. Otherwise, the value of _BFMT__COFF is set to false.
Beginning with SR10, the Domain Pascal compiler generates COFF files whenever it compiles your source code.
NOTE:

•

There are two underscore U characters between 'BFMT' and
'COFF' in the name of this variable.

A pair of predeclared conditional variables that you can use to find out whether
the compiler is generating code for the 68000 family of workstations or for the
Series 10000. These variables are:
_ISP__M68K (for 68000 code generation)
_ISP__A88K (for Series 10000 code generation)
NOTE:

There are two underscore
names of these variables.

CJ

characters after ' ISP' in the

For example, given that color and mono are special variables that you defined using %var,
here are some possible predicates:

4-46

Code

•

color

•

not (color)

•

mono or color

•

(mono and color)

Compiler Directives

%if predicate %then
If the predicate is true, Domain Pascal compiles the code after %then and before the next

%else, %elseif, or %endif directive.
For example, to specify that a block of code is to be compiled for a color node, you might
choose an attribute name such as color to be the predicate. Then write:

%VAR color

{Tell the compiler that 'color' can be used in a predicate.}

%IF color %THEN
Code
%ENDIF;
To set color to true, you can either use the %enable directive in your source code or the
-config option in your compile command line.

%else
The %else directive is used in conjunction with %if predicate %then. %Else specifies a
block of code to be compiled if the predicate in the %if predicate %then clause evaluates
to false. For example, consider the following fragment:

%VAR color

{Tell the compiler that 'color' can be used in a predicate.}

%IF color %THEN
Code
%ELSE
Code

{Compile this code if color is false.}

%ENDIF;

%elseif predicate %then
%Elseif predicate %then is used in conjunction with %if predicate %then. It serves an
analogous purpose to the Pascal statement
else if cond then statement

Code

4-47

Compiler Directives
For example, suppose you want to compile one sequence of statements if the program is
going to run on a color node, and another sequence of statements if the program is going
to run on a monochromatic node. To accomplish that, you could organize your program in
the following way:
%VAR color mono {Tell the compiler that 'color' and 'mono' can be }
{used in a predicate.
}

%1F color %THEN
{Compile the following code if color is true.}
Code for color nodes
%ELSE1F mono %THEN {Compile the following code if mono is true.}
Code for monochromatic nodes
%END1F;
To set color or mono to true, you can either use the %enable directive in your source
code or the -con fig option in your compile command line. If color and mono are both
true, Domain Pascal compiles the code for color nodes since it appears first. Note that you
can put mUltiple %elseif directives in the same block.
Or, suppose that you want to tailor a source module for a specific application, depending
on whether the compiler is generating code for the 68000 family of workstations or the
Series 10000. Consider the following fragment:
%1 F

I SP_ M6 8K %THEN PROCEDURE do_6 8K ...

%ELSEIF

ISP

A88K

%THEN PROCEDURE do 100000

%ENDIF;
The above fragment tells the compiler to compile the do_ 68K procedure if it is generating
68K code and to compile the do_lOOOO procedure if it is generating code for the Series
10000.

NOTE:

Since _ISP__ M68K and _ISP __A88K are predeclared, you
cannot use the %enable directive or the -config option with
them.

%endif
The %endif directive tells the compiler where to stop conditionally processing a particular
area of code.

4-48

Code

Compiler Directives

%ifdef predicate %then
Use %ifdef predicate %then to check whether a variable was already declared with a %var
directive. If you accidentally declare the same variable more than once, Domain Pascal
issues an error message. %lfdef is a way of avoiding this error message. %lfdef is especially helpful when you don't know if an include file declares a variable.
For example, consider the following use of %ifdef:

%INCLUDE 'bitmap_init.ins';{Source code that mayor may not have used
{%VAR to declare the variable 'color'.
%IFDEF not (color) %THEN
%VAR color
%ENDIF;
NOTE:

}
}

{If color has not been declared }
{with %VAR, declare it now.
}

The difference between %if and %ifdef is the following. Variables in an %if predicate are considered true if you set them to
true with %enable or -config; however, variables in an %ifdef
predicate are considered true if they have been declared with
%var.

%elseifdef predicate %then
%Elseifdef is to %ifdef as %elseif is to %if. Use %elseifdef predicate %then to check
whether or not additional variables were declared with %var; for example:

%INCLUDE 'bitmap_init.ins'; {Source code that mayor may not have
{used %VAR to declare the variables
{'color' or 'mono.'

}
}
}

%IFDEF not (color) %THEN
%VAR color

{If color has not been declared with
{%VAR, declare it now.

}
}

%ELSEIFDEF not (mono) %THEN
%VAR mono

{If mono has not been declared with
{%VAR, declare it now.

}
}

%ENDIF;

Code

4-49

Compiler Directives

%var
The %var directive lets you declare variable and attribute names that will be used as predicates later in the program. You cannot use a name in a predicate unless you first declare it
with the %var directive. The following example declares the names code.old and code.new
as predicates:
%VAR

code. old

code. new

The compiler preprocessor issues an error if you attempt to declare with %var the same
variable more than once. (Use %ifdef or %elseifdef to avoid this error.)

%enable
Use the %enable directive to set a variable to true. (%Enable and the -config compiler
option perform the same function.) You create variables with the %var directive. If you do
not specify a particular variable in an %enable directive or -config option, Domain Pascal
assumes that it is false.
For example, the following example declares three variables named code.sr9, code.sr8,
and code.sr7, then it sets code.sr9 and code.sr7 to true:
%VAR
code.sr9
%ENABLE code.sr9

code.sr8
code.sr7

code.sr7

The compiler preprocessor issues an error message if you attempt to set (with %enable or
-con fig) the same variable to true more than once.

%config
The %config directive is a predeclared attribute name. You can use %config only in a
predicate. The Domain Pascal preprocessor sets %config to true if your compiler command
line contains the -config option, and sets %config to false if your compiler command line
does not contain the -config option. The purpose of the %config directive is to remind
you to use the -config option when you compile; for example:
%IF color %THEN
{This is the code for color nodes.}
%ELSEIF mono %THEN

4-50

Code

Compiler Directives
{This is the code for monochromatic nodes.}
%ELSEIF %config %THEN
%warning('You did not set color or mono to true.');
%ENDIF
NOTE:

You cannot declare %config in a %var directive.

%error 'string'
This directive causes the compiler to print 'string' as an error message. You must place this
directive on a line all by itself.
For example, suppose you want the compiler to print an error message whenever you compile with the -config mono option. In that case, set up your program like this:
%VAR color mono
%IF color %THEN
{Code for color nOde.}
%ELSEIF mono %THEN
%ERROR 'I have not finished the code for a monochromatic node.'
%ENDIF
If you do compile with the -config mono option, Domain Pascal prints out the following
error message:

(0011)

%ERROR 'I have not finished the code for a monochromatic node.'
Line 11: Conditional compilation user error.
1 error, no warnings, Pascal Rev n.nn

********

Because of the error, Domain Pascal does not create an executable object.

%warning 'string'
This directive causes the compiler to print 'string' as a warning message. You must place
this directive on a line all by itself. For example, suppose you want the compiler to print a

Code

4-51

Compiler Directives
warning message whenever you forget to compile with the -config color option. In that
case, set up your program like this:
%VAR color mono
%IF color %THEN
{Code for color node.}
%ELSE
%WARNING 'You forgot to use the -CONFIG color option.
%ENDIF
Then, if you don't compile with the -config color option, Domain Pascal prints out the
following error message:
%WARNING 'You forgot to use the -CONFIG color option.
Conditional compilation user warning.
No errors, 1 warning, Pascal Rev n.nn
(0011)

******** Line 11: Warning:

A warning does not prevent the compiler from creating an executable object.

%exit
%Exit directs the compiler to stop processing the file. For example, if you put %exit in an
include file, Domain Pascal only reads in the code up until %exit. (It ignores the code that
appears after %exit.)
%Exit has no effect if it is in a part of the program that does not get compiled.

DIRECTIVES NOT ASSOCIATED WITH THE -CONFIG OPTION

The remaining compiler directives are not specifically associated with the -config compiler
option.

%begin.:....inline; and %end_inline;

I

4-52

The %begin_inline and %end_inline directives are delimiters that define routines for in line
expansion. Inline expansion means that the compiler generates code for a given routine
wherever a call to that routine appears.

Code

Compiler Directives
Inline expansion of a given routine allows you to avoid the overhead of a procedure or
function call. When used with small routines, inline expansion can increase execution
speed. It also increases the size of the executable code, however.
Follow these rules when using %begin_inline and %end_inline:
•

Place %begin_inline on a line in the source file before you begin any appropriate
procedure or function definitions.

•

Place %end_inline on the line following the last routine that you define for inline
expansion.

Suppose that a program contains this function declaration:
%begin_inline;
function test_pos (number: real)
begin
test_pas .- (number >= 0.0);
end;
%end_inline;

boolean;

Whenever you call the function test_pos in your main program, the compiler generates
code for the function at that point, instead of transferring control to the function.
You cannot nest these directives, and you must have matching pairs to begin and end the
specification. The compiler detects recursion and will not use inline expansion if doing so
would cause the compiler to loop indefinitely.
The %begin_inline and %end_inline directives are effective only if you compile with an
optimization level of 3 or 4. With Domain Pascal, level 3 is the default.
At optimization level 3, the compiler expands all routines that are enclosed between
%begin_inline and %end_inline directives, so long as they are not recursive. At optimization level 4, the compiler expands all of these functions, and also selects other functions
that are suitable for inline expansion.

%begin_noinline; and %end_noinline;
The %begin_noinline and %end_noinline directives are delimiters for routines that the
compiler must never expand inline. These delimiters are the converse of %begin_inline
and %end_jnline. Use %begin_noinline and %end_noinline if you specify an optimization level of 4, but want to restrict inline expansion of certain functions.

Code

4-53

Compiler Directives
Follow these rules when using %begin_noinline and %end_noinline:
•

Place %begin_noinline on a line in the source file before you begin any appropriate procedure or function definitions.

•

Place %end_noinline on the line following the last routine that you define for no
inline expansion.

The following code fragment tells the compiler not to use inline expansion for the for_loop
procedure under any circumstances.
%begin_noinline;
procedure for_loop;
var
i : integer32;
begin
for i := 1 to 100 do
writeln('i is
i);
end;
%end_noinline;

%debug;
The %debug directive marks source code for conditional compilation. The "condition" is
the compiler option, -condo If you compile with the -cond option, then the compiler
compiles the lines that begin with %debug. If you do not compile with the -cond switch,
Domain Pascal does not compile the lines that begin with %debug. The reason this directive is called %debug is that it can help you debug your program.
For instance, consider the following fragment:

%DEBUG;

value := data + offset;
writeln('Current value is

value:3);

The preceding fragment contains one %debug directive. If you compile with the -cond
option, then the system executes the writeln statement at run time. If you compile without
the -cond option, the system does not execute the writeln statement at run time. Therefore, you can compile with the -cond option until you are sure the program works the way
you want it to work, and then compile without the -cond option to eliminate the (now)
superfluous writeln message.
The %debug directive applies to one physical line only, not to one Domain Pascal statement. Therefore, in the following example, % debug applies only to the for clause. If you
compile with -cond, Domain Pascal compiles both the for statement and the writeln pro-

4-54

Code

Compiler Directives
cedure. If you compile without -cond, Domain Pascal compiles only the writeln procedure
(and thus there is no loop).

%DEBUG;

FOR j

:= 1 to max size do
WRITELN(barray[j]);

If you %debug within a line, text to the left of the directive is always compiled, and text
to the right of the directive is conditionally compiled.

%eject;
The %eject directive does not affect the. bin file; it only affects the listing file. (The -I
compiler option causes the compiler to create a listing file.) The %eject directive specifies
that you want a page eject (formfeed) in the listing file. The statement that follows the
%eject directive appears at the top of a new page in the listing file.

%include 'pathname';
Use the %include directive to read in a file ('pathname') containing Domain Pascal source
code. This file is called an include file. The compiler inserts the file where you placed the
%include directive.
Many system programs use the %include directive to insert global type, procedure, and
function declarations from common source files, called insert files. The Domain system
supplies insert files for your programs that call system routines. The insert files are stored
in the Isys/ins directory; see Chapter 6 for details.
Domain Pascal permits the nesting of include files. That is, an include file can itself contain an %include directive.
The compiler option -idir enables you to select alternate pathnames for insert files at compiletime. See Chapter 6 for details.
NOTE:

This directive has no effect if it's in a part of the program that
does not get compiled.

%list; and %nolist;
The %list and %nolist directives do not affect the . bin file, they only affect the listing file.
(The -I compiler option causes the compiler to create a listing file.) %List enables the list-

Code

4-55

Compiler Directives
ing of source code in the listing file, and %nolist disables the listing of source code in the
listing file.
For example, the following sequence disables the listing of the two insert files, and then
re-enables the listing of future source code:

%NOLIST;
%INCLUDE 'jsysjinsjbase.ins.pas';
%INCLUDE 'jsysjinsjios.ins.pas';
%LIST;
%List is the default.

%slibrary 'pathname';
The %slibrary directive is analogous to the %inc1ude directive. While %inc1ude tells the
compiler to read in Domain Pascal source code, %slibrary tells it to read in previouslycompiled code.
The %slibrary directive tells the compiler to read in a precompiled library residing at
'pathname'. The compiler inserts the precompiled library where you place the %slibrary
directive. The compiler acts as if the files that were used to produce the precompiled library were included at this point, except that any conditional compilation will have already
occurred during precompilation.
Precompiled libraries can only contain declarations; they may not contain routine bodies
and may not declare variables that would result in allocating storage in the default data
section, .data. This means the declarations must either put variables into a named section,
or must use the extern variable allocation clause. See Chapter 3 for more information
about named sections, and Chapter 7 for details on extern.
Use the -slib compiler option (described in Chapter 6) to precompile a library and then
insert -slib's result in 'pathname'. For example, if you create a precompiled library called
mystuff.ins.plb, this is how to include it in your program:
%SLIBRARY'mystuff.ins.plb';
Precompiled library pathnames by default end in . plb.

4-56

Code

Compiler Directives

%natural_alignment; and %word_alignment;
Use the %natural_alignment and %word_alignment directives to tell the compiler how to
align any data that does not have an alignment attribute in its declaration. (See the
"Alignment-Extension" section of Chapter 3 for details about the alignment attributes).
Specifically,
•

Use the %natural_alignment directive to set data alignment to natural.

•

Use the %word_alignment directive to set all data in the environment to word
alignment.

By default, the Domain Pascal compiler aligns all objects larger than a byte in wordalignment mode. If you want to change this, you can use the %natural_alignment directive. Conversely, if you want the compiler to resume word-alignment mode, you can specify the %word_alignment directive, which overrides the previous directive. In any case,
the alignment directive you specify stays in effect until you specify another one.
You can use these directives in combination with
_ISP__68K and _ISP__A88K to compile source
be run on 680xO or Series 10000 workstations.
program so that it will run efficiently on a Series
lines to the beginning of the program:

the predeclared conditional variables
modules according to whether they will
For example, one way to compile your
10000 workstation would be to add these

%IF ISP A88K
%THEN
%NATURAL_ALIGNMENT;
%ENDIF
NOTE:

You can use an alignment directive to set the alignment for programs or program modules written prior to SR10 that did not include alignment attributes. Thus, you can gain the improved performance that results from natural alignment without rewriting all
your variable and type declarations.
However, you must be careful when using these directives with
files on disk that have pre-SR10 record formats. The %natural_alignment and %word_alignment directives change record
layout. This means that the fields of records are in different positions and you may be unable to access them. (See the "Internal
Representation of Unpacked Records" section of Chapter 3 for
details about the alignment of data in records.)

Code

4-57

Compiler Directives

%push_aJignment; and %pop_alignment;
The %push_aJignment and %pop_aUgnment directives are designed to save and restore
the current alignment mode while another alignment mode is used by a particular structure
or file. The %push_alignment directive saves the current alignment mode by pushing it
onto a stack. The %pop_alignment directive restores the alignment mode saved by the
last %push_aJignment by popping it off the stack.
These directives are useful for controlling the alignment of %include files. For example, a
%push_aJignment directive placed at the top of an %include file tells the compiler to save
the current alignment mode by pushing it onto the stack. A %pop_alignment directive
placed at the end of the %include file restores the alignment mode saved by the last
%push_aJignment.

4-58

Code

Cos

Cos Calculates the cosine of the specified number.

FORMAT

{cos is a function.}

cos (number)

ARGUMENTS

Any real or integer value in radians (not degrees).

number

FUNCTION RETURNS

The cos function returns a real value (even if number is an integer).

DESCRIPTION

The cos function calculates the cosine of number.

EXAMPLE

PROGRAM cos_example;
{ This program demonstrates the COS function. }
CaNST
pi

3.1415926535;

VAR

degrees : INTEGER;
q, c1, c2, radians

REAL;

BEGIN
q := 0.5;
c1 := COS(q); {Find the cosine of one-half radians. }
writeln('The cosine of' q:5:3, ' radians is " c1:5:3);

Code

4-59

Cos
{The following statements show how to convert from degrees to radians.}
{More specifically. they find the cosine of 14 degrees.}
degrees := 14;
radians := «degrees * PI) / 180.0);
c2 := COS(radians);
writeln('The cosine of '. degrees: 1. ' degrees is
c2:5:3);
END.

USING THIS EXAMPLE
If you execute the sample program cos_example. you get the following output:

The cosine of 0.500 radians is 0.878
The cosine of 14 degrees is 0.970

4-60

Code

Ctop

Ctop Converts a C-style string to a variable-length string.

(Extension)

FORMAT
{ctop is a procedure.}

etop(string) :

ARGUMENTS
string

A variable-length string.

DESCRIPTION
The ctop procedure converts a C-style null-terminated string into a variable-length string
by searching the body field of the string for a terminating null byte and setting the string's
length field accordingly. (See the "Variable-Length Arrays-Extension" section of Chapter
3 for details about variable-length strings.) Note that this function does not remove the
null byte; it simply sets the length field to one less than the null byte position.
See the description of ptoc for information about converting a variable-length string into a
null-terminated string.

EXAMPLE
(See the description of the ptoe procedure.)

Code

4-61

Discard

Discard Explicitly discards the return value of an expression. (Extension)

FORMAT
{discard is a procedure.}

discard (exp)

ARGUMENTS
Any expression, including a function call.

exp

DESCRIPTION
In its effort to produce efficient code, the compiler sometimes issues warning messages concerning optimizations it performs. Those optimizations might not be right for your particular
situation. For example, if you compute a value but never use it, the compiler may eliminate the computation, or the assignment of the value, and issue a warning message.
However, there are times when you call a function for its side effects rather than its return
value. You don't need the value, but a Pascal function always returns a value to retain
legal program syntax. You must keep the function call in your program, but if you don't
use the value, the compiler's optimizer automatically discards the return value and issues a
warning message.
Since you know the return value is useless, in such a case you may want to eliminate this
particular warning message. Domain Pascal's discard procedure explicitly throws away the
value of its exp and so gets rids of the warning. For example, to call a function that returns a value in argl without checking that value, use discard as follows:
DISCARD(rny_function(argl»;

EXAMPLE

PROGRAM discard_example;
VAR

payment, monthly_sal: real;
{
{
{

4-62 Code

The following function figures out whether a user can afford the
}
mortgage payments for a given house based on the rule that no more }
than 28% of one's gross monthly income should go to housing costs. }

Discard
FUNCTION enough(in
payment
in out monthly_sal

real;
real)

boolean;

VAR

amt_needed : real;
BEGIN
writeln;
amt_needed := monthly_sal

*

0.28;

if amt_needed < payment then
begin
enough := false;
monthly_sal := payment / (0.28);
writeln ('Your monthly salary needs to be' monthly_sal:6:2);
end
else
begin
enough := true;
writeln('Amazing! You can afford this house.');
end
END;
{end function enough}
BEGIN
{main program}
write ('How much is the monthly payment for this house? ');
read In (payment);
write ('What is your gross monthly salary? ');
readln (monthly_sal);
{ The function enough can change the value of the global variable }
{ monthly_sal, so the function call is important, but its return }
}
{ value is not. DISCARD that return value.
DISCARD (enough(payment,monthly_sal»;
END.

USING THIS EXAMPLE

Following is a sample run of the program named discard_example:
How much is the monthly payment for this house? 928
What is your gross monthly salary? 2400
Your monthly salary needs to be 3314.29

Code

4-63

Dispose

Dispose Deallocates the storage space that a dynamic variable was using. (Refer also to New.)

FORMAT
Dispose is a predeclared procedure that takes one of two formats. The format you choose
depends on the format you use to call the new procedure. If you create a dynamic variable with the short form of new, then you must use the short form for dispose, which is:

{dispose is a procedure.}

dispose(p)

If you create a dynamic variant record with the long form of new, then you must use the

long form of dispose, which is:
dispose(p, tagl .. tagN);

ARGUMENTS

tag

One or more constants. The number of constants in a dispose call must
match the number of constants in the new call.

p

A variable declared as a pointer. After you call dispose (P), Domain Pascal sets p to nil.

DESCRIPTION
If P is a pointer, then dispose (p) causes Pascal to deallocate space for the occurrence of
the record that p points to. Deallocating means that Pascal permits the memory locations
occupied by the dynamic record to be occupied by a new dynamic record. For example,
consider the following declarations:

TYPE

employeepointer = Aemployee;
employee = record
first name
array[l .. lO] of char;
last name
array[1 .. 14] of char;
next_emp
employeepointer;
end;
VAR
current_employee

4-64

Code

employeepointer;

Dispose
To store employee records dynamically, call new(current_emp)oyee) for every employee.
If an employee leaves the company, and you want to delete his or her record, you can call
dispose (current_emp)oyee) . Dispose returns the storage occupied by that record for reuse
by a subsequent new call.
If you create a dynamic record using a long-form new procedure, then you must call dis-

pose with the same constants. For example, if you create a dynamic record by calling
new(widget, 378, true), then to deallocate the stored record, you must call dispose(widget, 378, true).
Note that the dispose procedure merely de allocates the record. If this disconnects a linked
list, then it is up to you to reset the pointers. If some other variable points to this record
and another program uses dispose to deallocate the record, then you get erroneous results.

NOTE:

If you call dispose(p) when p is nil, Domain Pascal reports an

error. It is also an error to call dispose when p points to a block of
storage space that you already deallocated with dispose. Finally,
if you use a pointer copy that points to deallocated space, the
results are unpredictable.

EXAMPLE
For a sample program that uses dispose, refer to the new listing later in this encyclopedia.

Code

4-65

Div

Div Calculates the quotient (excluding the remainder) of two integers.

FORMAT
dl div d2

{div is an operator.}

ARGUMENTS
Any integer expression.

dl. d2

OPERATOR RETURNS
The result of a div operation is always an integer.

DESCRIPTION
The expression (d 1 div d2) produces the integer (nonfractional) result of dividing d 1 by
d2. The div operator uses the division rules of standard mathematics regarding negatives.
For example, consider the following results:

is
is
is
is
is

9
10
11
12
13

DIV
DIV
DIV
DIV
DIV

3
3
3
3
3

9
10
11
12
13

DIV
DIV
DIV
DIV
DIV

(-3)
(-3)
(-3)
(-3)
(-3)

equal
equal
equal
equal
equal

is
is
is
is
is

to
to
to
to
to

equal
equal
equal
equal
equal

3
3
3
4
4

to
to
to
to
to

-3
-3
-3
-4
-4

is
is
is
is
is

-9
-10
-11
-12
-13

DIV
DIV
DIV
DIV
DIV

3
3
3
3
3

-9
-10
-11
-12
-13

DIV
DIV
DIV
DIV
DIV

(-3)
(-3)
(-3)
(-3)
(-3)

equal
equal
equal
equal
equal

is
is
is
is
is

to
to
to
to
to

-3
-3
-3
-4
-4

equal
equal
equal
equal
equal

to
to
to
to
to

3
3
3
4
4

To find the remainder of an integer division operation, use the mod operator. (See the
mod listing later in this encyclopedia.)
See the "Expressions" listing later in this encyclopedia for information on using binary and
unary operators together.

4-66 Code

Div

EXAMPLE

PROGRAM div_example;
{ This program converts a 3-digit integer to a 3-character array.
{ Note that the character 0 has an ISO Latin-1 value of 48, the
{ character 1 has an ISO Latin-1 value of 49, and so on up until the
{ character 9, which has an ISO Latin-1 value of 57.
VAR
x
digits

100 .. 999;
array[1 .. 3] of char;

BEGIN
write('Enter a three-digit integer -- ');
readln(x);
digits[l] :=chr(48 + (x DIV 100»;
x := x MOD 100;
digits[2] .- chr(48 + (x DIV 10»;
digits[3] := chr(48 + (x MOD 10»;
writeln(digits);
END.

USING THIS EXAMPLE

This program is available online and is named div_example.

Code

4-67

}
}
}
}

Do

Do Refer to the For or While listings later in this encyclopedia.

4-68

Code

Downto

Downto Refer to For later in this encyclopedia.

Code

4-69

Else

Else Refer to If later in this encyclopedia.

4-70

Code

End

End Signifies the end of a group of Pascal statements.

FORMAT
End is a reserved word.

DESCRIPTION
End is the terminator for a sequence of Pascal statements. A Pascal program must contain
an end to match every begin.
Pascal requires a begin/end pair to indicate a compound statement. (Refer to the" Statements" listing later in this encyclopedia.)
Pascal requires end (without an accompanying begin) in the following situations:
•

To terminate a case command.

•

To terminate a record declaration.

EXAMPLE

{This program does very little work, but does have lots of BEGINs }
{and ENDs.
}
TYPE
student = record
age: 6 .. 12;
id : integer16;
end; {student record definition}
VAR

x

integer32;

PROCEDURE do_nothing;
BEGIN
{do_nothing}
writeln('You have triggered a procedure that does absolutely nothing.');
writeln('Though it does do nothing with elan.').
END;
{do_nothing}

Code

4-71

End
FUNCTION do next to nothing(var y
BEGIN {do_~ext_to_~othing}
do next to nothing := abs(y);
END; -{do_~ext_to_nothing}

integer32)

integer32;

BEGIN {main procedure}
readln(x);
write('Enter an integer -- ');
if x < 0
then BEGIN
writeln('You have entered a negative number!!!');
writeln('Its absolute value is " do_next_to_nothing(x):l);
END
else if x == 0
then BEGIN
writeln('You have entered zero');
do_nothing;
END
else
writeln('You have entered a positive number!! I');
END.
{main procedure}

USING THIS EXAMPLE

This program is available online and is named begin_end_example.

4-72 Code

Eof

Eor Tests the current file position to see if it is at the end of the file.

FORMAT

{eor is a function.}

eor (filename)

ARGUMENTS

filename

A file variable symbolizing the pathname of an open file. The filename
argument is optional. If you do not specify filename, Domain Pascal assumes that the file is standard input (input).

FUNCTION RETURNS
The eor function returns a Boolean value.

DESCRIPTION
The eor function returns true if the current file position is at the end of file filename; otherwise, it returns false. With one exception, filename must be open for either reading or
writing when you call eor. The one exception occurs when filename is input; for a description of this exception, see the "Interactive 1/0" section in Chapter 8.

Code

4-73

Eof

EXAMPLE

PROGRAM eot_example;
{NOTE: Before running this program, you must obtain file "annabel lee" }
and store it in the same directory as the program.
}
{
CONST
title_of_poem = 'annabel_lee';
VAR
poetry
text;
stat
integer32;
a_line
string;
BEGIN
{Open file anabel_lee for reading.}
open (poetry , title_of_poem, 'OLD', stat);
if stat = 0 then
reset (poetry)
else
return;
{Read each line from the file and write each line to the screen. }
{Halt execution when end of file is reached.
}
while not EOF(poetry) do
begin
readln (poetry , a_line);
writeln(output, a_line);
end;
END.

USING THIS EXAMPLE

This program is available online and is named eor_example.

4-74

Code

Eoln

Eoln Tests the current file position to see if it is pointing to the end of a line.

FORMAT
eoln(/)

{eoln is a function.}

ARGUMENTS
A variable having the text data type. f is optional; if you do not specify
it, eoln tests the standard input (input) file.

f

FUNCTION RETURNS
The function returns a Boolean value.

DESCRIPTION
The eoln function returns true when the stream marker points to an end-of-line character;
otherwise, with two exceptions, eoln returns false. The two exceptions are:
•

Eoln causes a run-time error if f was not opened for reading (with reset) or for
writing (with rewrite). However, you do not need to open input or output for
reading or for writing. (See the "Interactive I/O" section in Chapter 8 for details
on input and output.)

•

Eoln causes a run-time error if eof(f) is true.

EXAMPLE

PROGRAM eoln_example;
{NOTE: Before running this program, you must obtain file "annabel_lee" }
and store it in the same directory as the program.
}
{
CaNST
title_of_poem

'annabel_lee';

VAR
poetry
stat
a char

text;
integer32;
char;

Code

4-75

Eoln
BEGIN
{ Open file annabel_lee for reading. }
open(poetry, title_of_poem, 'OLD', stat);
if stat == 0
then reset(poetry)
else return;
{ Read in the first line of the poem one character at a time,
{ and write each character to the screen.
repeat
read (poetry, a_char);
writeln(output, a_char);
until EOLN(poetry);
END.

USING THIS EXAMPLE

This program is available online and is named eolo_example.

4-76

Code

}
}

Exit

Exit Transfers control to the first statement following a for, while, or repeat loop. (Extension)

FORMAT
Exit is a statement that neither takes arguments nor returns values.

DESCRIPTION
Use exit to terminate a loop prematurely; that is, to jump out of the loop you're in. In
nested loops, exit applies to the innermost loop in which it appears. You can use exit
within a for, while, or repeat loop only. If exit appears elsewhere in a program, Domain
Pascal issues an error.
It is preferable to use exit for jumping out of a loop prematurely rather than goto. That's
because goto inhibits some compiler optimizations that exit does not.

EXAMPLE
PROGRAM exit_example;
{This program demonstrates the exit statement.

}

VAR

integer16;
real;
array[l .. 5, 1 .. 3] of real .- [[* of 0.0], [* of 0.0] ,];

i, j
, data
geiger

BEGIN
for i := 1 to 4 do
begin
writeln;
for j := 1 to 3 do
begin
writeln(chr(10), 'Enter the data for coordinates', i:2, ',', j:1);
write('(or enter -1 to jump down to the next row) -- ');
readln(data);
if data = -1 then

EXIT
else
geiger[i,j] .- data;
end; {for j}
end; {for i}

END.

Code

4-77

Exit

USING THIS EXAMPLE
Following is a sample run of the program named exit_example:

Enter the data for coordinates 1,1
(or enter -1 to jump down to the next row) -- 1.2
Enter the data for coordinates 1,2
(or enter -1 to jump down to the next row) -- -1
Enter the data for coordinates 2,1
(or enter -1 to jump down to the next row) -- 3.2
Enter the data for coordinates 2,2
(or enter -1 to jump down to the next row) -- 1.2
Enter the data for coordinates 2,3
(or enter -1 to jump down to the next row) -- 4.3
Enter the data for coordinates 3,1
(or enter -1 to jump down to the next row) -- -1
Enter the data for coordinates 4,1
(or enter -1 to jump down to the next row) -- 1.3
Enter the data for coordinates 4,2
(or enter -1 to jump down to the next row) -- 4.2
Enter the data for coordinates 4,3
(or enter -1 to jump down to the next row) -- -5

4-78

Code

Exp

Exp Calculates the value of e, the base of natural logarithms, raised to the specified power.
(See also Ln.)

FORMAT
{exp is a function.}

exp(number)

ARGUMENTS
Any real or integer expression.

number

FUNCTION RETURNS
The exp function returns a real value.

DESCRIPTION
The exp function returns e raised to the power specified by number.
e to 16 significant digits is 2.718281828459045.

Note that Domain Pascal supports an exponentiation operator. (See the "Overview: Mathematical Operators" section earlier in this chapter for details about the exponentiation operator.)

EXAMPLE

PROGRAM exp_example;
{This example demonstrates the use of EXP in calculating the}
{exponential growth of bacteria.
}
CONST
cl

0.3466;

VAR
starting_quantity
: INTEGER;
ending_quantity, elapsed_time

REAL;

Code

4-79

Exp
BEGIN

write('How many bacteria are there at zero hour? -- ');
readln(starting_quantity);
write('How many hours pass? -- ');
readln(elapsed_time);
ending quantity := starting_quantity

*

writeln('There will be approximately'

EXP(c1

*

elapsed_time);

ending_quantity:1,' bacteria.');

END.

USING THIS EXAMPLE

Following is a sample run of the program named exp_example:
How many bacteria are there at zero hour? -- 10500
How many hours pass? -- 5.6
There will be approximately 7.313705E+04 bacteria.

4-80

Code

Expressions

Expressions

Throughout this encyclopedia, we refer to expressions. Here, we define expressions. An
expression can be any of the following:
•

A constant declared in a const declaration part

•

A variable declared in a var declaration part

•

A constant value

•

A function call

•

Anyone of the above preceded by a unary operator appropriate to its data type

•

Any two of the above separated by a binary operator appropriate to their data
types

You can organize expressions into more complex expressions with parentheses. For example, the odd function requires an integer expression as an argument. The following program fragment demonstrates several possible arguments to odd:

CONST
century .- 100;

VAR
x, y
result

integer;
boolean;

BEGIN
result
result
result
result
result
result

......-

ODD (century) ;
ODD (x) ;
ODD(15);
ODD(sqr(25»;
ODD(x + y);
ODD ( (x * 3) + sqr(y»;

{a constant}
{a variable}
{a value}
{a function}
{an operation}
{several operations}

Code

4-81

Expressions
NOTE:

You cannot follow a binary operator with a unary operator of
lower precedence. For example, consider the following proper
and improper expressions:
9 DIV -3
{improper expression}
9 DIV (-3) {proper expression}
5 * -100
{improper expression}
5 * (-100) {proper expression}

Table 4-3 shows the order of precedence of operators.

4-82 Code

Find

Find Sets the file position to the specified record .. (Extension)

FORMAT

find(jile_variabJe, record_number, error_status);

{find is a JJrocedure.}

ARGUMENTS

file variable

Must be a variable having the file data type. The file_variable argument
cannot be a variable having the text data type.

record_number

Must be an integer between 1 and n or between -1 and -n, where 1 denotes the first record of the file and n denotes the last record.

error_status

Must be declared as a variable with the integer32 data type. Domain Pascal returns a hexadecimal number in error_status which has the following
meaning:

o-

no error or warning occurred.

greater than 0 - an error occurred.
less than 0 - a warning occurred.
NOTE:

Your program is responsible for handling the error. We detail error handling in Chapter 9.

DESCRIPTION
Before reading this, make sure you are familiar with the description of I/O in Chapter 8.
When you open a file for reading, the operating system sets the stream marker to the beginning of the file. You can call read to move this stream pointer sequentially, or you can
call find to move it randomly.
Before you can call find, you must have first opened the file symbolized by file_variable
for reading. (See Chapter 8 for a description of opening files for reading.) When you call
find, Domain Pascal sets the stream marker to point. to the record specified by
record_number.

Code

4-83

Find
If you specify a record_number between 1 and n, where n is the number of records in the
file, find locates that number record. If record_number is between -1 and -n, find counts
backward from the end of the file to locate the proper record. For example, if there are
five records in the file and you specify -4 for record_number, Domain Pascal counts back
four from the end of the file and retrieves record number 2.
If you specify record_number as zero, the compiler returns an error code in error_status.
If you specify a record_number that is one greater than the number of records stored in
the file, Domain Pascal does not return an error code, but does not change the stream
marker either.

After executing a find, Domain Pascal sets the stream marker to point to the beginning of
the next record. For example, if record_number is 2, then after executing a find, Domain
Pascal sets the stream marker to point to record 3.
Frequently, programmers use the find procedure with the replace procedure (which is described later in this encyclopedia).
NOTE:

The term "record," as it applies to files of file type, refers to a
data object of the file's base type. This is not necessarily a Domain Pascal record type.

EXAMPLE

{This program demonstrates the FIND and REPLACE procedures. }
{ NOTE: File 'his101' must exist before you run get_example. }
{
To create 'his101', you must run put_example.
}
%NOLIST; { We need these include files for error checking.
%1 NCLUDE '/sys/ins/base.ins.pas';
%1 NCLUDE '/sys/ins/error.ins.pas';
%1 NCLUDE '/sys/ins/streams.ins.pas';
%LIST;
CONST
pathname

'his101';

TYPE
student

4-84

Code

RECORD
name
age
END;

array[l .. 12] of char;
integer16;

}

Find
VAR
class
a_student
st
more_corrections
particular_record
n

FILE OF student;
student;
status_$t;
char;
integer16 :== 0;
integerl6;

PROCEDURE print_records;
BEGIN
n : == 0;

writeln(chr(10), 'Here are the records stored in the file:');
reset(class);
repeat
n :== n + 1;
read(class, a student);
writeln('record " n:2, '
a_student.name, a_student.age);
until eof(class);
END:
PROCEDURE correct_errors;
BEGIN
write('Enter the number of the record you wish to change -- ');
readln(particular_record);
if particular_record == n+l then
writeln ('There are only' n:2, ' records in the file.')
else
BEGIN
FIND(class, particular_record, st.all);
if st.code == 0 then
BEGIN
write('What should this name be -- ');
readln(a_student.name);
write('What should this age be -- ');
readln(a_student.age);
class :== a_student;
REPLACE(class);
END
else if st.code == stream_$end_of_file then
BEGIN
write('You specified a number greater than the number of ');
writeln ('records in the file.');
END
else
error_$print(st);
END;
END;
A

Code

4-85

Find
BEGIN {main procedure}
open(class, pathname, 'OLD', st.all);
if st.code = 0 then
BEGIN
repeat
print_records;
write('Do you want to correct any records? (enter y or n) -- ');
readln(more_corrections);
if more_corrections = 'y' then
correct errors
else
exit;
until false;
END
else if st.code = stream_$name_not_found then
writeln('Did you remember to run put_example to create hislOl?')
else
error_$print(st);
END.

USING THIS EXAMPLE
Following is a sample run of the program named find_and_replace_example

Here are the records you have entered:
record 1
Kerry
28
record 2
Barry
26
record 3
Jan
25
Do you want to correct any records? (enter y or n) -- y
Enter the number of the record you wish to change -- 2
What should this name be -- Sandy
What should this age be -- 27
Here are the records you have entered:
record 1
Kerry
28
record 2
Sandy
27
record 3
Jan
25
Do you want to correct any records? (enter y or n) -- n

4-86

Code

Firstof

Firstof Returns the first possible value of a type or a variable. (Extension)

FORMAT
firstof(x)

{firstof is a function.}

ARGUMENTS
Is either a variable or the name of a data type. The data type can be a
predeclared Domain Pascal data type, or it can be a user-defined data
type. x cannot be a record, file, or pointer type.

x

FUNCTION RETURNS
The firstof function returns a value having the same data type as x.

DESCRIPTION
The firstof function returns the first possible value of x according to the following rules:

Data Type of x

Firstof Returns

integer or integer16

-32767

integer32

-2147483647

char

The character represented by chr(O)
called nul.

boolean

False.

enumerated

The first (leftmost) identifier in the
data type declaration.

array

The lower bound of the subrange that
defines the array's size.

varying array

1

The firstof function is particularly useful for finding the first element of an enumerated
type (as in the example).

Code

4-87

Firstof

EXAMPLE

PROGRAM firstof_lastof_example;
{This program demonstrates the use of the firstof and lastof functions}
TYPE
(aristotle, galileo, newton, tycho, kepler);
astronomers
VAR

stargazers
astronomers;
BEGIN
writeln('The following is a list of great astronomers:');
for stargazers := firstof(astronomers) to lastof(astronomers) do
writeln(stargazers);
END.

USING THIS EXAMPLE
If you execute the sample program named firstof_lastof_example, you get the following

output:

The following is a list of great astronomers:
ARISTOTLE
GALILEO
NEWTON
TYCHO
KEPLER

4-88

Code

For

For Repeatedly executes a statement a fixed number of times.

FORMAT
for index_variable:= start_exp to
stmnt;

I down to

stop_exp do
{for is a statement}

ARGUMENTS

index_variable

Any variable declared as an ordinal type. The ordinal types are enumerated, subrange, integer, Boolean, and char. Note that index_variable cannot be a real number. As an extension to standard Pascal, Domain Pascal
permits the index_variable to be declared in a scope other than the scope
of the routine immediately containing the for loop.

start_exp

An expression matching the type of the index_variable.

stop_exp

An expression matching the type of the index_variable.

stmnt

A simple statement or compound statement. (Refer to the "Statements"
listing later in this encyclopedia.)

DESCRIPTION
For, repeat, and while are the three looping statements of Pascal. With for, you explicitly
define both a starting and an ending value to the index_variable.
When executing a for loop, Pascal initializes the index_variable to the value of the
start_exp, and then either increments (to) or decrements (downto) the value of the index_variable by 1 until its value equals that of the stop_expo When the index_variable
equals the value of the stop_exp, Pascal executes the statements in the loop one final time
before exiting the loop. You may not assign a value to index_variable within the body of
the for loop.
If index_variable is an integer or subrange variable, for increments or decrements its
value by 1 for each cycle. If index_variable is a char variable, then for increments or
decrements its ISO Latin-l value by 1 for each cycle. If index_variable is an enumerated
variable, then incrementing means selecting the next element in sequence and decrementing means selecting the preceding element. If index_variable is a Boolean, then true has a
value greater than false.

Code

4-89

For
The keyword to causes incrementing; the keyword downto causes decrementing.
If you want to jump out of a for loop prematurely (i.e., before the value of the index_variable equals the value of the stop_exp), you have the following choices:

•

Execute an exit statement to transfer control to the first statement following the
for loop.

•

Execute a goto statement to transfer control to outside of the loop.

•

Execute a return statement to transfer control back to the calling routine.

In addition to these measures, you can also execute a next statement to skip the remainder of the statements in the loop and proceed to the next iteration. Here are some tips for
using the for statement:
•

Within the stmnt, you are not allowed to change the value of the index_variable.

•

If you set up a meaningless relationship between the start_exp and the stop _exp
(for example, for x := 8 to 5 or for x := 10 downto 20), Pascal does not execute
the loop even once.

EXAMPLE
PROGRAM for example;
{This program demonstrates several uses of for loops}
VAR

time, year, zeta: integer16 := 0;
hurricanes : (king, donna, cleo, betsy, inez);
scores: arraY[l .. 5, 1 .. 3] of integer16;
i, j : integer16;
BEGIN
{If you do not use a BEGIN/END pair, FOR assumes that the loop}
{consists of the first statement following it. }
FOR time := 1 TO 3 DO
writeln(time);

4-90

Code

For
{TO create a loop consisting of multiple statements, enclose the}
{ loop in a BEGIN/END pair. }
FOR time := 21 TO 30 DO
begin
year := year + time;
writeln(year:5); {Write a running total. }
end;
{Here's an example of DOWNTO. }
FOR time := year DOWNTO (year - 100) DO
zeta := zeta + (time * 3);
writeln;
writeln(zeta,' is the result of the downto for loop');
writeln;
{Here's an example of an enumerated index variable. }
FOR hurricanes := donna TO inez DO
writeln(hurricanes);
{And finally, we use nested FOR loops to load a 2-dimensional array.}
FOR i := 1 TO 5 DO
begin
{for i}
FOR j := 1 TO 3 DO
begin {for j}
write('Enter the score for player' ,i:1,' game' ,j:1,' -- ');
readln(scores[i,j]);
end;
{for j}
writeln;
end;
{for i}
END.

USING THIS EXAMPLE
This program is available online and is named for_example.

Code

4-91

Get

Get Advances the stream marker to the next component of a file.

FORMAT
get(j)

{get is a procedure.}

ARGUMENTS
A variable having the file or text data type.

f
DESCRIPTION

If f is a file variable, calling get causes the operating system to advance the stream marker
so that it points to the next record in the file. If f is a text variable, calling get causes the

operating system to advance the stream marker so that it points to the next character in
the file.
After calling get to advance the stream marker, you can use another statement to read in
the data that the stream marker points to and assign it to a variable from your program.
Therefore, the sequence for reading in data looks like the following:

GET(f);
{ Advance the stream marker. }
variable := fA; { Set variable equal to whatever the stream marker}
{ points to.
}
For example, the following program fragment demonstrates input via the get procedure:

VAR
primes
poem
a_number
a letter

file of integer16;
text;
integer16;
char;

BEGIN
GET(primes);
a_number := primes A; {Set a_number equal to next record in primes}
GET(poem);
a_letter .- poemA;

4-92

Code

{Set a_letter equal to next character in poem}

Get
Note that the two statements

GET (poem) ;
a_letter := poem

A
;

{Set a_letter equal to next character in poem

}

are identical to the single statement

READ (poem, a_letter);
Also notice that unlike read, get allows you to save the contents of fA.
You must open f for reading (with reset) before calling get. If eor(j) is true, calling get(j)
causes a "read past end of file" error trap.

EXAMPLE

PROGRAM get_example;
{ This program demonstrates the GET procedure.
}
{ File 'hisl0l' must exist before you run get_example. }
}
{ To create 'hisl0l', you must run put_example.
%NOLIST;
%INCLUDE '/sys/ins/base.ins.pas';
%INCLUDE '/sys/ins/error.ins.pas';
%INCLUDE '/sys/ins/streams.ins.pas';
%LIST;
CONST
file to read from

'hisl0l';

TYPE
student
record
name
age
end;

array [1 .. 12] of char;
integer16;

VAR
class
a student
st

file of student;
student;
status_$t;

Code

4-93

Get
BEGIN
{Open a file for reading.}
open(class, file_to_read_from, 'OLD', st.all );
if st.code = 0
then reset(class)
else if st. code = stream_$name_not_found
then begin
writeln('Did you forget to run put_example?');
return;
end
else error_$print(st);
{Now that the file is open, read all the records from it. }
repeat
a_student := class
GET(class);
write(chr(lO), a_student.name);
writeln(a_student.age:2);
until eof(class);
END.
A

;

USING THIS EXAMPLE
This program is available online and is named get_example.

4-94

Code

Goto

Goto Unconditionally jumps to a specified label in the program.

FORMAT
goto Ibl;

{goto is a statement.}

ARGUMENTS
Is an unsigned integer or identifier that you have previously declared as a
label. (For information on declaring labels, see the "Label Declaration
Part" section in Chapter 2.)

Ibl

DESCRIPTION
A goto statement breaks the normal sequence of program execution and transfers control
to the statement immediately following Ibl.
A declared Ibl usually is local to the block in which it is declared. That is, if you know
you declared a label, but the compiler still reports the following error, you must move your
label declaration to the correct procedure or function:
(Name_of_Label) has not been declared in routine (name_of_routine)

It is illegal to use goto to jump inside a structured statement (for example, a for, while,
case, with, or repeat) from outside that statement. This means a fragment like this produces an error:
if error_flag = true then
goto cleanup;

for i := 1 to 10 do
begin
cleanup:
end;

{WRONG! }

{close for statement}

It is illegal to jump into an if/then/else statement if you compile with the -iso option. See
Chapter 6 for more details.

Code

4-95

Goto
Gotos are useful for handling exceptional conditions (such as an unexpected end of file).
Nonlocal gotos, whose target Ibl is in the main program or some other routine at a higher
level, have a great effect on the generated code. They generally shut off most compiler
optimizations on the code near the target Ibl. In order to produce the most efficient code,
you should try to use goto as infrequently as possible.
You cannot jump into a structured statement from outside that statement. For example,
the go to 100 statements in the bad_gotos program below are illegal. This program also
contains a goto 900 statement that is illegal if you compile with the -iso option.

PROGRAM bad_gotos;
VAR
z,x,value
integer16;
a_char
char;
LABEL 900;
PROCEDURE f 00 ;
LABEL 100;
BEGIN
for x := 1 to 100 do
begin
writeln ('value " x);
100: write ('Enter a value ');
readln(value);
Z := Z + value;
end;
COTO 100;
{ILLEGAL: cannot jump to a label inside}
{the for loop.
}
END;
BEGIN
write ('Do you want to use the program? ');
readln (a_char);
if a_char = 'y' then
{ILLEGAL: cannot jump to a label in
COTO 100
}
{another routine.
}
else if a_char
'n' then
{ILLEGAL IF COMPILED WITH -ISO SWITCH:}
COTO 900
{cannot jump to a label that's inside}
{another statement.
}
else if a_char = '0' then
writeln ('0 is not a legal response')
else
900: writeln ('ok, we won"t use the program');
END.

4-96

Code

Goto
Note that you can use goto to jump directly from a nested routine to an outer routine. For
example, procedure xxx issues a valid goto in the following program:

Program non_local_goto;
Label
900;
Procedure xxx;
BEGIN
GOTO 900;
END;
BEGIN
900: writeln('back in main program.');
END.

EXAMPLE

PROGRAM goto_example;
{This program demonstrates the use of the goto statement}
TYPE
possible_values = 10 .. 25;
VAR
x : possible_values;
LABEL
100;
BEGIN
writeln('You will now enter the experimental data.', chr(10»;
100:
write('Please enter the obtained value for x -- ');
readln(x);
if in_range (x) then
writeln('This value seems possible.')
else
begin
writeln('This value seems suspicious.');
GOTO 100;
end;
END.

Code

4-97

Goto

USING THIS EXAMPLE

Following is a sample run of the program named goto_example:

You will now enter the experimental data.
Please enter the
This value seems
Please enter the
This value seems

4-98

Code

obtained value for x
suspicious.
obtained value for x
possible.

3S
17

If

If Tests one or more conditions and executes one or more statements according to the outcome of
the tests.

FORMAT

You can use if, then, and else in the following two ways:
if cond then stmnt;

{first form}

if cond then stmnt 1 else stmnt2;

{second form}

ARGUMENTS

cond

Any Boolean expression.

stmnt

A simple statement or a compound statement. (Refer to the "Statements"
listing in this encyclopedia.) Note that stmnt can itself be another if statement.

DESCRIPTION

The if and case statements are the two conditional branching statements of Pascal.
In an if/then statement, if cond evaluates to true, Pascal executes stmnt. If cond is false,
Pascal executes the first statement following stmnt.
In an if/then/else statement, if cond is true, Pascal executes stmntl. However, if cond is
false, Pascal executes stmnt2.
You often use an if statement to evaluate multiple conditions. To do so, just remember
that a stmnt can itself be an if statement. For example, consider the following if statement
which evaluates multiple conditions:

IF age < 3 THEN
price = 0.0
ELSE IF (age >= 3) AND (age <= 6) THEN
price = 1.00
ELSE IF (age> 6) AND (age <=12) THEN
price
2.00
ELSE
price
4.00;

Code

4-99

If

EXAMPLE

PROGRAM if_example;
{This program demonstrates IF/THEN and IF/THEN/ELSE.}
VAR
y, age, of_age, root_ratings : integer16;
tree
(ficus, palm, poinciana, frangipani, jacaranda);
grade
: char;
BEGIN
write('Enter an integer -- ');
readln(y);
IF Y < 0 THEN
writeln('Its absolute value equals'
write('Enter an age -- ');
readln(age) ;
IF age > 18 THEN
writeln(' An adult')
ELSE
begin
of_age .- 18 - age;
writeln(' A minor for another '
end;

{USAGE 1}
(abs(y»:3);
{USAGE 2}

of_age:1,' years.');

write('Enter a grade -- ');
readln(grade);
IF (grade = 'A') OR (grade = 'B') THEN
writeln(' Good work')
ELSE IF (grade = 'C') OR (grade = 'D') THEN
begin
writeln(' Satisfactory work');
writeln(' Though improvement is indicated.');
end
ELSE IF (grade = 'F') THEN
writeln(' Failing work');

4-100

Code

{USAGE 3}

If
write('Enter the name of a tropical tree -- ');
readln(tree);
IF (tree = poinciana) OR (tree = jacaranda) THEN
begin
writeln(' Blossoms in June and July.');
root_ratings := 9;
end
ELSE IF tree = palm THEN
root_ratings := 8
ELSE
root_ratings := 2;

{USAGE 4}

END.

USING THIS EXAMPLE

Following is a sample run of the program named if_example:
Enter an integer -- -10
Its absolute value equals 10
Enter an age -- 13
A minor for another 5 years.
Enter a grade -- B
Good work
Enter the name of a tropical tree -- poinciana
Blossoms in June and July.

Code

4-101

In

In Evaluates an expression to see if it is a member of a specified set.

FORMAT
{in is a set operator.}

exp in setexp

ARGUMENTS
setexp

A set expression.

exp

An expression of the same data type as the elements constituting the base
type of setexp.

OPERATOR RETURNS
The result of an in operation is always Boolean.

DESCRIPTION
Use in to determine if exp is an element in set setexp. In returns either true or false.

EXAMPLE

PROGRAM in example;
{ This program prompts the user for a word, then counts the number of }
{ ordinary vowels (a, e, i, 0, and u) in the word. }
VAR
word
count_of_vowels
x

array [1 .. 20] of char .integer16 := 0;
integer16;

[*

of ' '];

BEGIN
write('Enter a word -- ');
readln (word) ;
for x := 1 to 20 do
if word[x] IN ['a', 'e', 'i', ' 0 ' , 'u']
then count_of_vowels := count_of_vowels + 1;
writeln('This word contains', count_of_vowels:1, ' ordinary vowels.');
END.

4-102 Code

In

USING THIS EXAMPLE

Following is a sample run of the program named in_example:

Enter a word -- computers
This word contains 3 ordinary vowels.

Code

4-103

In_range Determines whether or not a specified value is within the defined integer subrange.
(Extension)

FORMAT
{in_range is a function.}

ARGUMENTS

x

A variable having a scalar (Le., integer, Boolean, char, enumerated, or
subrange) data type. For most practical purposes, x must be an enumerated or a subrange variable.

FUNCTION RETURNS
The in_range function returns a Boolean value.

DESCRIPTION
The in_range function returns true if the value of x is within its defined range; otherwise,
it returns false. The following program fragment demonstrates a possible use of in_range.
We want to use in_range in this example, because it generates very efficient code:
TYPE

small_int = -7 .. 7;
VAR

x : integer16;
BEGIN

readln(x) ;
if IN_RANGE(Small_int(x»
then

else ...

4-104

Code

EXAMPLE

PROGRAM in_range_example;
{This program demonstrates the use of the in_range function }
TYPE

possible_temperature_range

48 .. 97;

VAR
possible_temperature_range;
boolean;
BEGIN
repeat
write('Enter the current air temp. (in deg. fahrenheit) -- ');
readln(air_temp);
if not IN_RANGE(air_temp) then
begin
writeln('This temperature is out of the historical range.');
writeln;
stop := false;
end
else begin
writeln('This value is within the historical range.');
stop := true;
end;
until stop;
END.

USING THIS EXAMPLE

Following is a sample execution of the program named in_range_exampJe :
Enter the current air temp. (in deg. fahrenheit) -- 100
This temperature is out of the historical range.
Enter the current air temp. (in deg. fahrenheit) -- 47
This temperature is out of the historical range.
Enter the current air temp. (in deg. fahrenheit) -- 52

Code

4-105

Lastof

Lastof Returns the last possible value of a type or a variable. (Extension)

FORMAT
lastof(x)

{lastof is a function.}

ARGUMENTS
Either a variable or the name of a scalar data type. The data type can be
a predeclared Domain Pascal data type, or it can be a user-defined data
type. x cannot be a record, file, set, floating-point, or pointer type.

x

FUNCTION RETURNS
The lastof function returns a value having the same data type as x.

DESCRIPTION
The lastof function returns the final possible value of x according to the following rules:
Data Type of x
integer or integer16

Lastof Returns
32767

integer32

2147483647

char

A symbol indicating an unprintable
character; however, ord(lastof(char»
returns 255.

boolean

True.

enumerated

The last (rightmost) identifier in the
data type declaration.

array

The upper bound of the subrange that
defines the array's size.

varying array

The maximum length of the array.

The lastof function is particularly useful for finding the last value in an enumerated type.

EXAMPLE
See the example in the firstof listing earlier in this encyclopedia.

4-106

Code

Ln

Ln Calculates the natural logarithm of a specified number.

FORMAT

In (number)

{In is a function.}

ARGUMENTS
number

Any real or integer expression that evaluates to a positive number.

FUNCTION RETURNS

The In function always returns a real value (even if number is an integer).

DESCRIPTION

The In function returns the natural logarithm of number. Refer to the exp listing earlier in
this encyclopedia for a practical definition involving In.

EXAMPLE

PROGRAM In_example;
{ Each radioactive isotope has a unique K constant.}
{ This program uses LN and empirical data to calculate the k constant.}
VAR
starting_Quantity, ending_Quantity: real;
elapsed_time, k : real;
BEGIN
write('Enter the Quantity at time zero -- ');
readln(starting_Quantity);
write('Enter the elapsed time (t) -- ');
readln(elapsed_time);
write('Enter the Quantity at time (t) -- ');
readln(ending_Quantity);
k := LN(starting_Quantity/ending_Quantity) * (1.0 / elapsed_time);
writeln('The k constant for this radioactive element is " k);
END.

Code

4-107

Ln

USING THIS EXAMPLE
Following is a sample run of the program named In_example:

Enter
Enter
Enter
The k

4-108

Code

the quantity at time zero -- 1230
the elapsed time (t) -- 47
the quantity at time t -- 753
constant for this radioactive element is 0.010

Lshft

Lshft Shifts the bits in an integer a specified number of bit positions to the left. (Extension)

FORMAT
Ishft(num, sh)

{Ishft is a function.}

ARGUMENTS
num, sh

Integer expressions.

FUNCTION RETURNS
The Ishft function returns an integer value.

DESCRIPTION
The Ishft function shifts the bits in Dum to the left sh places. Lshft does not wrap bits
around from the left edge to the right; instead, Ishft shifts zeros in on the right. For example, consider the following results:
VAR

i, n : INTEGERI6;
BEGIN
i := 2000;
{ 2#0000011111010000
LSFHT(i, 1) ; { 2#0000111110100000
LSHFT(i, 3) ; { 2#0011111010000000
LSHFT(i, 7) ; { 2#1110100000000000

10#+2000
10#+4000
10#+16000
10#-6144

}
}
}
}

Results are unpredictable if sh is negative.
Compare Ishft to rshft and arshft.

EXAMPLE
PROGRAM lshft_example;
{ThiS program demonstrates the use of the lshft function}
VAR

unshifted_integer, shifted_integer, shift_left, x : integerl6;
choice
0 .. 15;
drink_info: array[O .. 6] of integer16 := [* of 0];

Code

4-109

Lshft
BEGIN
{In the following subroutine, LSHFT acts as a multiplier according}
{to the equation LSHFT(num,sh) = num * (2 to the sh power). Beware}
}
{ of overflow when you use LSHFT for this purpose.
unshifted_integer := 15; {15 is 0000000000001111 in binary}
shift_left := 3;
shifted_integer := LSHFT(unshifted_integer, shift_left);
writeln(unshifted_integer:5, ' times 2 to the' shift_left:l,
, power = ' shifted_integer:l);
{The result will be 120.}
{120 is 0000000001111000 in binary.}
{You can also use LSHFT to pack information more effectively. For
{example, suppose you asked 24 people to name their favorite soft
{drink from a list of 16 possibilities. Since we can represent 16
{possibilities in 4 bits, we can store 4 people's responses in one
{16-bit word in the following manner:

}
}
}
}
}

{
{Bit #

{
{

{
{

}
0

3

4

7

--------------- ---------------Response 1
Response 2
--------------- ----------------

8

11

}

Response 3

12
Response 4

}

{Therefore, we will only need six 16-bit words to store the data
{rather than 24 16-bit words. The following code uses the LSHFT
{function to accomplish this data reduction.
writeln;
for x := 0 to 23 DO
BEGIN
write('Enter the preference (0-15) of client'
x: 1, '

END.

USING THIS EXAMPLE

This program is available online and is named Ishft_example.

Code

}

I}

}
}
}
}

-- ');

readln(choice);
drink_info[x div 4] := drink_info[x div 4] !
LSHFT(choice, (4 * (x mod 4»);
writeln(DRINK_INFO[x DIV 4]);
END;
{You can also achieve this sort of packing with packed records.

4-110

15

}

Max

Max Returns the larger of two expressions. (Extension)

FORMAT
max (expJ ,exp2)

{max is a function.}

ARGUMENTS

expJ, exp2

Any valid expression.

DESCRIPTION
Domain Pascal's max function returns the larger of the two input expressions. The arguments expJ and exp2 must be the same type or must be convertible to the same type by
Pascal's default conversion rules (for example, integer converted to a real).
If expJ and exp2 are unsigned scalars or pointers, Domain Pascal performs an unsigned
comparison. (The unsigned scalar data types are non-negative subranges of integers,
Boolean, character, and enumerated.) If they are real, single, or double, a floating-point
comparison is done, while if they are signed integers, Domain Pascal performs a signed
comparison.

See also min.

EXAMPLE
PROGRAM max_example;
{This program demonstrates the use of the max function}
VAR
small_num, big_num, biggest : REAL;
BEGIN
big_num := 1000.0;
small_num := 2.0;
WHILE small_num <= big_num DO
BEGIN
small_num := SQR(Small_num);
big_num := SQRT(big_num);
biggest := MAX (small_num, big_num);
WRITELN ('The biggest number now equals' biggest);

END;

END.

Code

4-111

Max

USING THIS EXAMPLE

Following is a sample run of the program named max_example:

The biggest number now equals
The biggest number now equals

4-112

Code

3.162278E+Ol
1.600000E+Ol

Min

Min Returns the smaller of two expressions. (Extension)

FORMAT
min (expJ,exp2)

{min is a function.}

ARGUMENTS

expJ, exp2

Any valid expression.

DESCRIPTION
Domain Pascal's min function returns the smaller of the two input operands. The arguments expJ and exp2 must be the same type or must be convertible to the same type by
Pascal's default conversion rules (for example, integer converted to a real).
If expJ and exp2 are unsigned scalars or pointers, Domain Pascal performs an unsigned
comparison. (The unsigned scalar data types 'are non-negative subranges of integers,
Boolean, character, and enumerated.) If they are real, single, or double, a floating-point
comparison is done, while if they are signed integers, Domain Pascal performs a signed
comparison.

See also max.

Code

4-113

Min

EXAMPLE

program min_example;
var
storenum : integer;
lowprice, x, y, newprice1,
begin
{ The program finds the lowest
{ stores sell. The stores have
{ featuring different discount
{ the second.

newprice2 : real;
discounted price for an item that two}
different regular prices and are
}
rates: 18% at the first, and 15% at
}
}

write ('Enter the regular price at the first store: ') ;
readln (x);
write ('Enter the regular price at the second store: ');
read In (y);
newprice1 := x - (x
newprice2 .- y - (y

* 0.18);
* 0.15);

lowprice :- MIN(newpricel,newprice2);
if lowprice = newprice1 then
storenum := 1
else
storenum := 2;
write ('The best discounted price is at store number "
writeln (' and it is " lowprice:6:2);
end.

storenum:1);

USING THIS EXAMPLE

Following is a sample run of the program named min_example:

Enter the regular price at the first store: 1599.99
Enter the regular price at the second store: 1515.15
The best discounted price is at store number 2 and it is 1287.88

4-114

Code

Mod

Mod Calculates the remainder upon division of two integers.

FORMAT

dl

{mod is an operator.}

mod d2

ARGUMENTS
Any integer expressions.

dl, d2

OPERATOR RETURNS
The mod operator returns an integer value.

DESCRIPTION
Domain Pascal's mod operator works like standard Pascal's mod operator when dl is positive. When dl is negative and you compile without the -iso switch, Domain Pascal's mod
operator works in a nonstandard manner.

When d 1 Is Positive
The expression (dl MOD d2) produces the remainder of dl divided by d2. Therefore,
the expression (dl MOD d2) always evaluates to an integer from 0 up to, but not including, Id21. For example, consider the following results:

9 MOD 3
MOD 3
MOD 3
MOD 3
MOD 3
MOD -3

10
11
12
13
13

is
is
is
is
is
is

equal
equal
equal
equal
equal
equal

to
to
to
to
to
to

0
1
2
0
1
1

(To find the quotient (Le., nonfractional) portion of the division, use the div operator described earlier in this encyclopedia.)

When dl Is Negative
If dl is negative, then (dl MOD d2) equals
-1

*

remainder of Id11 divided by Id21

Code

4-115

Mod
For example, consider the following results:
-9
-10
-11
-12
-13

MOD
MOD
MOD
MOD
MOD

-3
-3
-3
-3
-3

is
is
is
is
is

equal
equal
equal
equal
equal

to 0
to -1
to -2
to 0
to -1

-9
-10
-11
-12
-13

MOD
MOD
MOD
MOD
MOD

3
3
3
3
3

is
is
is
is
is

equal
equal
equal
equal
equal

to 0
to -1
to -2
to 0
to -1

Compiling with the -iso Switch
If you compile with the -iso switch (described in Chapter 6), mod follows the standard

Pascal rules. That is, mod returns a value result such that:
result := dl - (dl DIV d2)

*

d2

Since a negative modulus is illegal under standard Pascal rules, if result is negative, then:
result := result + d2

EXAMPLE

PROGRAM mod_example;
{This program uses the MOD function to find the coming leap years.}
CONST

cycle = 4;
VAR

remainder, year: integerl6;
BEGIN
for year := 1985 to 1999 do
begin
remainder .- year MOD cycle;
if remainder = 0
then writeln(year:4, ' is a leap year');
end;
END.

USING THIS EXAMPLE
If you execute the sample program named mod_example, you get the following output:

1988 is a leap year
1992 is a leap year
1996 is a leap year

4-116

Code

New

New Allocates space for storing a dynamic variable.

FORMAT
new(p)

{Short form. New is a procedure.}

new(p, tag], . . . tagH)

{Long form.}

ARGUMENTS
An input argument that names one or more constants. Tag is valid only if
p" is a record. The maximum number of tags is the number of tag fields

tag

in the record to which p points.
A pointer variable used for input and output. Pascal creates a dynamic
variable of the type to which p points. After allocating this variable, Pascal returns the address of the newly allocated dynamic variable into p.
The contents of the address pointed to is undefined. If there was insufficient address space or disk space remaining to satisfy the request for dynamic memory, then Domain Pascal returns the value nil in p.

p

DESCRIPTION
New causes Pascal to allocate enough space for storing one occurrence of a dynamic variable. You use new to create dynamic space and dispose (described earlier in this encyclopedia) to deallocate the dynamic space.
You can use the short form of new to allocate any kind of dynamic variable. The long
form of new is only useful for allocating dynamic variant records.

The Short Form

Consider the following record declaration:

TYPE
employeepointer = "employee;
employee = record
first_name
array[l .. lO] of char;
last_name
array[1 .. 14] of char;
next_emp
employeepointer;
end;

VAR
current_employee

employeepointer;

Code 4-117

New
If you want to store employee records dynamically, then you must call NEW(current_em-

ployee) for every occurrence of an employee. To allocate space for 100 employees, call
NEW(current_employee) 100 times. You can assign values to an employee record only
after Pascal has allocated space for an occurrence.

The Long Form
Pascal uses tagl..tagN to help determine the amount of space to allocate for a variant record. Tagl..tagN corresponds to the tag fields of the variant record. For example, consider the type declaration for the following variant record:

TYPE
emp_stat
(exempt, nonexempt);
workerpointer
Aworker;
worker = record
first_name
array[l .. 10] of char;
last_name
array[1 .. 14] of char;
next_emp
workerpointer;
CASE emp_stat OF
exempt
(salary
integer16) ;
nonexempt : (wages
single;
plant
array[l .. 20] of char);
end;

VAR
current_worker : workerpointer;
Because worker contains a tag field, you have the option of passing the value of a constant
to new; for example:

NEW (current_worker , exempt)
Since tag1 is exempt, when Domain Pascal allocates space for one worker record, it allocates two bytes for the variant portion (since integer16 takes up only two bytes). If tag1
had been nonexempt, Domain Pascal would have allocated the space necessary (24 bytes)
to hold it.
Note that the number of constants you pass to new must be less than or equal to the number of tag fields in the record declaration.

4-118

Code

New
For machines with a larger address space (DNx60 machines, DN3000, etc.), you can access that larger amount of space by performing the following two steps:
1.

Use new to allocate a large amount of memory (such as a megabyte) at the beginning of the program's execution.

2. Immediately after allocating the memory, use dispose to deallocate it.

These steps cause the operating system to increase the number of memory pages it allocates to your program. You should only use this technique if it is possible that your program may run out of address space.

EXAMPLE

{The following example uses NEW and DISPOSE to create and disassemble}
{a linked list. For a description of the theory of linked lists,
}
{consult a Pascal tutorial.
}
TYPE
studentpointer =
student;
student
record
name: array[1 .. 30] of char;
age : integer16;
next student : studentpointer;
end;
A

VAR

base
a_name
an_age
option
done

studentpointer;
array[1 .. 30] of char;
integer16;
char;
boolean;

Procedure error_message; {gives a message if student not on list}
begin
writeln;
writeln('That person is not on the list. Let"s try again.');
writeln
end;

Code 4-119

New
Procedure print_list; { Print the linked list in order. }
VAR

ns : studentpointer;
BEGIN
ns := base;
writeln;
while ns <> NIL do
with NS" do
begin
writeln(name, '
ns .- next_student;
end;
END;

age);

Procedure Enter_data;
VAR

ns, previous : studentpointer;
BEGIN
base := nil;
repeat
write('Enter the name of a student (or end to stop) -- ');
readln(a_name);
if a_name <> 'end' then
begin
NEW(ns);
{ allocate space for a new occurrence of a student.}
write('Enter his or her age -- '); readln(an_age);
if base = nil
then base := ns
{set base to first record. }
else previous".next student := ns;
{add record to end of list.}
ns".name := a_name; {Initialize fields of new record. }
ns".age := an_age;
nS".next_student := nil;
previous := ns;
{ Save pointer to this new student }
end
until a_name = 'end';
END;

4-120

Code

New
Procedure delete_a_student;
VAR

ns, previous : studentpointer;
BEGIN
previous := base;
ns := base;
write('What is the name of the student you want to delete? -- ');
read In (a_name) ;
while ns <> nil do
begin
if ns A.name = a_name then {delete record}
begin
if ns = base then
base := nsA.next_student
else
previousA.next_student .- nSA.next_student;
DISPOSE (ns) ;
exit;
end
else
begin
previous := ns;
ns := nsA.next_student;
if ns = nil then error_message;
end; {if}
end; {while}
END; {delete_a_student}
BEGIN {main}
base := nil;
enter_data;
print_list;

repeat
if base = nil then return;
write('Do you want to delete a student from the list? (y or n)--');
readln(option);
done := not (option in ['y', 'Y']);
if not done then
begin
delete_a_student;
print_list;
end
until done;
END.

Code 4-121

New

USING THIS EXAMPLE
Following is a sample run of the program named build_8_linked_list:

Enter
Enter
Enter
Enter
Enter
Enter
Enter

the
his
the
his
the
his
the

name of a student
or her age -- 28
name of a student
or her age -- 27
name of a student
or her age -- 29
name of a student

(or end to stop)

Kerry

(or end to stop)

Jan

(or end to stop)

Lance

(or end to stop)

end

Kerry
Jan
Lance
Do you want to delete a student from the
What is the name of the student you want

28
27
29

list? (y or n) -- y
to delete? -- Jan

Kerry
28
Lance
29
Do you want to delete a student from the list? (y or n)

4-122

Code

-- n

Next

Next Jump to the next iteration of a for, while, or repeat loop. (Extension)

FORMAT
Next is a statement that neither takes arguments nor returns values.

DESCRIPTION
You use next to skip over the current iteration of a loop. You can only use next within a
for, while, or repeat loop. If next appears elsewhere in a program, Domain Pascal issues
an error. Next tells Domain Pascal to ignore the remainder of the statements within the
body of the loop for one iteration. For instance, consider the following example:

FOR x := 5 to 35 do
begin
if

(x

MOD 10)

o

then NEXT;

end;
When x is 10, 20, or 30, Domain Pascal ignores the statements following the next. You
can use a goto statement instead of a next statement. For example, you can rewrite the
preceding example to look like the following:

FOR x := 5 to 35 do
begin
if
100:

(x

MOD 10)

o

then GOTO 100;

end;

Code 4-123

Next

EXAMPLE

PROGRAM next example;
{ This prog~am counts the occurrences of the digits 0 through 9 in }
}
{ a line of integers and real numbers.
CONST
blank = , '.,
, .' ,
decimal_point
VAR
dig : char;
count_digits: array[48 .. 57] of integer16 .- [* of 0];
x : integer16;
BEGIN
writeln('Enter a line of integers and real numbers:');
repeat
read(dig) ;
if «dig = blank) or (dig = decimal_point» then NEXT;
write(dig, ' ');
count_digits[ord(dig)] := count_digits[ord(dig)] + 1;
until eoln;
writeln;
for x := 48 to 57 do
chr ( x) : 1, ' s' ) ;
writeln( count_digits [x] :2, ' of the digits were'
END.

.

USING THIS EXAMPLE

Following is a sample run of the program named next_example:
Enter a line of integers and/or real numbers.
1741374.13 33 821
174 1 3 74133 8
0 of the digits were Os
4 of the digits were Is
1 of the digits were 2s
4 of the digits were 3s
3 of the digits were 4s
0 of the digits were 5s
0 of the digits were 6s
2 of the digits were 7s
1 of the digits were 8s
0 of the digits were 9s

4-124

Code

Nil

Nil A special pointer value that points to nothing.

FORMAT
Nil is a predeclared constant, except when the code has been compiled with the -iso option. When the -iso option has been used, nil is a reserved word. You can only use nil
in expressions. Nil is a pointer value; therefore, you must assign it to or compare it to a
pointer variable. Nil never points to an object.

DESCRIPTION
Use nil when you must assign a value to a pointer, but you don't know what that value
should be. For example, when creating a linked list, you can set the last record in the list
to point to nil. Then, when walking through the list, you can easily find the end of the list
by checking for nil.

EXAMPLE
For a sample program that uses nil, refer to the listing for new earlier in this chapter.

Code 4-125

Not

Not Returns true if an expression evaluates to false.

FORMAT
{not is a unary operator.}

not b

ARGUMENTS
Any Boolean expression.

b

OPERATOR RETURNS
The result of a not operation is always a Boolean value.

DESCRIPTION
If b evaluates to false, then not b evaluates to true. If b evaluates to true, then not b

evaluates to false.
Note that you can put and or or immediately before not. Note the order of precedence in
an expression like the following:
a AND NOT b

actually means

a AND (NOT b)

Another potentially confusing expression is the following:
NOT a AND b

actually means

Please refer to the order of precedence rules in Table 4-3.

4-126

Code

(NOT a) AND b

Not

EXAMPLE

PROGRAM not example;
{This program demonstrates the use of the not operator}
VAR

pet_lover, timid: boolean;
BEGIN
writeln('Career aptitude test.', chr(lO»;
write('You like pets (true or false)
'); readln(pet_lover);
write('You are timid (true or false) -- '); readln(timid);

if pet_lover and NOT timid
then writeln('Have you considered becoming a lion tamer?')
else writeln('Plastics ... there"s a great future in plastics.');
END.

USING THIS EXAMPLE

This program is available online and is named not_example.

Code 4-127

Odd

Odd Tests whether the specified integer is an odd number.

FORMAT
odd (i)

{odd is a function.}

ARGUMENT
Any integer expression.

FUNCTION RETURNS
The odd function returns a Boolean value.

DESCRIPTION
Odd returns true if i is an odd integer and false if i is an even integer.

EXAMPLE
PROGRAM odd_example;
{ThiS program demonstrates the use of the odd function}

VAR
i : integer;
BEGIN
write('Enter an integer -- ');
readln(i);
if ODD(i)
then writeln(i:1, ' is an odd number.')
else writeln(i:l, ' is an even number.');
END.

USING THIS EXAMPLE
Following is a sample run of the program named odd_example:
Enter an integer -- 14
14 is an even number.

4-128

Code

Of

Of Refer to Case earlier in this encyclopedia.

Code 4-129

Open

Open Opens a file so that you can eventually read from or write to it. (Extension)

FORMAT

open(jile_variable, pathname, file_history, error_status, buffer_size);

{open is a procedure.}

ARGUMENTS

file variable

A variable having the text or file data type.

pathname

The name of the file that you want to open. Pathname is a string constant or string variable, that you specify in any of the following five ways:

•

Enter a Domain pathname as defined in Getting Started with Domain/OS.

•

Enter a string in the form 'An', where n is an integer from 1 to 9. n corresponds
to the ordinal value of the arguments that the user passes to the program when he
or she executes or debugs the program. For example, suppose you compile Domain Pascal source code to create executable object file sample.bin. You can pass
the two arguments xxx and yyy by executing the program as follows:
$

sample. bin xxx yyy

The preceding command line causes Domain Pascal to assign xxx to ,A l' and yyy
to '''2'.

4-130

Code

•

Enter a string in the form '·prompt-string'. At run time, Domain Pascal prints the
prompt-string at standard output, and then reads the user's response from standard input. (The response should be the name of the file to be opened.) The
prompt-string can contain any printable character except blanks; Domain Pascal
stops printing at the first blank it encounters. An asterisk by itself tells Domain
Pascal to read the response from standard input without printing a prompt at standard output.

•

A string in the form '-STDIN' or '-STDOUT'. These strings correspond to the
streams that the operating system opens automatically. However, specifying one of
these strings does not cause an error. (See Chapter 8 for an explanation of
streams.)

•

A variable or constant containing any of the preceding items.

Open
file_history

A variable or string that tells the open procedure how to open the file.
The variable or string must have one of the following three values:

•

'NEW' - If the file exists, Domain Pascal reports an error. If the file does not
exist, Domain Pascal creates the file and then opens it.

•

'OLD' - If the file exists, Domain Pascal opens it. If the file does not exist, Domain Pascal reports an error.

•

'UNKNOWN' - If the file exists, Domain Pascal opens it. If the file does not exist, Domain Pascal creates the file and then opens it.
Remember to enclose the file_history within single quotes (for example, 'NEW').
An optional argument. If you specify an error_status, it must have an integer32 data type. At run time, Domain Pascal returns a hexadecimal
number into error_status which has the following meaning:

o-

no error or warning occurred.

greater than 0 - an error occurred.
less than 0 - a warning occurred.
Your program is responsible for handling any errors. We detail error handling in
Chapter 9.
An optional argument that may only be specified for files of type text.
Buffer_size must be at least as long as the longest line in the file being
read; if it is shorter, the excess characters in a line are truncated. If the
file is open for writing only, you don't need to specify a large buffer_size.
No data is lost even if a line being written is longer than buffer_size. The
default size is 256 bytes.

DESCRIPTION
Before you can read from or write to a file, you must first open it for I/O operations. To
open a permanent file, you must use the open procedure. To open a temporary file, use
the rewrite procedure without using an open procedure.
After you've opened a file, you then specify whether it is available for reading (by calling
reset) or for writing (by calling rewrite). Note that you do not need to open the standard
input (input) and standard output (output) files before attempting to read from or write to
them. They are always open.
When your program terminates, the operating system automatically closes all opened files;
however, please refer to the description of the close procedure earlier in this chapter.
For a complete overview of Domain I/O, see Chapter 8.

Code 4-131

Open

EXAMPLE

Program open_example;
{NOTE: Before running this program, you must obtain file "annabel_lee"
and store it in the same directory as the program.
{
{ This program uses a variety of techniques to open three files.
{ In order for it to work properly, you must pass the pathname of a
{ file as the first argument on the execution or debug command line.
{ For example, if you compile this program to create open_example. bin,
{ then you could invoke the program with the following command:
$ open_example. bin //arnie/nouveau/comps
{
%NOLIST;
%INCLUDE '/sys/ins/base.ins.pas';
%INCLUDE '/sys/ins/error.ins.pas';
%LIST;
CONST
name_of_file
file3

'annabel_lee';
'*enter_a_filename--';

VAR

poem, paragraph, stanza
statrec

text;
status_$t;

BEGIN
{ Open an existing file.}
OPEN (poem, name_of_file, 'OLD', statrec.all);
{ If there was no error on open, then specify that the file be
}
{ open for reading.
}
if statrec.all = 0
then begin
writeln('Opened' name_of_file, ' for reading');
reset (poem)
end
else writeln('Difficulty opening
{ Open a new file. The pathname of the new file will be the first }
{ argument that you pass on the execution or debug command line.
}
OPEN (paragraph , 'Al', 'NEW', statrec.all);

4-132

Code

}
}
}
}
}
}
}
}

Open
{ If there was no error on open, then specify that the file be open}
{ for writing. If there was an error, print the error code.
}
if statrec.all = status_Sok
then rewrite(paragraph)
else begin
writeln(chr(lO), 'Did you remember to pass an argument');
writeln('to the command line?');
writeln('error code = " statrec.all, chr(lO»;
end;
{ Open a file that mayor may not exist. Prompt user for name of
{ file at runtime.
OPEN (stanza , file3, 'UNKNOWN', statrec.all);

}
}

{ A slightly more sophisticated method of error reporting is to use
}
{ the system call ERROR_SPRINT to print the error message.
}
{ NOTE: In order to call ERROR_SPRINT, you must specify both
}
{
/sys/ins/base.ins.pas and /sys/ins/error.ins.pas as %INCLUDE files.}
if statrec.all = status_Sok
then rewrite(stanza)
else ERROR_SPRINT(statrec);
END.

USING THIS EXAMPLE

This program is available online and is named open_example.

Code 4-133

Or, Or Else

lOr, Or Else Calculate the logical or of two Boolean arguments.

FORMAT

•

x or y
x or else y

{or is an operator.}
{or else is an operator.}

ARGUMENTS

x, y

Any Boolean expressions.

OPERATOR RETURNS

•

The result of an or or an or else operation is always a Boolean value.

DESCRIPTION

Use or to find the logical or of expressions x and y. Here is the truth table for or:

Table 4-12. Truth Table for Logical or Operator
x

y

Result

true
true
false
false

true
false
true
false

true
true
true
false

Compare or to and and not (which are described elsewhere in this encyclopedia).
NOTE:

Some programmers confuse or with the exclamation point (I) operator. I is a bit operator; it causes Domain Pascal to perform a
logical or on all the bits in its two arguments. For example, compare the following results:

(true OR false) is equal to true
(75 ! 15) is equal to 79
Refer to the "Bit Operators" listing earlier in this encyclopedia.

4-134

Code

Or, Or Else
The Boolean operator or else is a Domain extension to standard Pascal. You can use or
else in any statement where you use or in standard Pascal. The choice between or and or
else, however, affects the run-time evaluation of a statement.
When or else appears between two Boolean operands, the system begins evaluating the
operands in the order in which they appear. If the first operand is true, the system does
not evaluate the second. If one operand is true, then the entire expression is true.
Hence, or else guarantees "short-circuit" evaluation. That is, at run time, the system
evaluates an operand only if necessary.
For example, in the statement
IF boolean 1 OR ELSE boolean_2
THEN ...

the system first evaluates boolean_I. If boolean_l is true, the system does not evaluate
boolean_2. In this statement, boolean_l and boolean_2 can be any valid Pascal Boolean
expressions. The operator or else can be more efficient than or. For example, in the
statement
IF boolean 1 OR boolean_2
THEN ...

the system may have to evaluate both boolean_l and boolean_2 to test if the statement is
true. Also, there is no guarantee that the system will evaluate the two expressions in the
order in which they appear.
The or else operator helps you avoid nested constructions. For example, compare the
standard Pascal code on the left with the equivalent Domain Pascal code on the right:
Standard Pascal

Domain Pascal

IF c1 THEN
51
ELSE
IF c2 THEN
51:

IF c1 OR ELSE c2 THEN
51;

In this example, the standard Pascal code contains an if/then/else statement with another
if statement nested inside it. The Domain Pascal code, however, contains only one if
statement.

Code 4-135

Or, Or Else
The following example illustrates how to avoid taking the log of 0.0:

REPEAT
i .- i + 1;
f . - a[i);

UNTIL f

= 0.0

OR ELSE In(f) < 2.0;

EXAMPLE

PROGRAM or_example;
{This program demonstrates the use of the or operator}
VAR

tall, good_jumper, good_athlete

boolean;

BEGIN
writeln('Career aptitude test.', chr(10»;
write('You are taller than 1.95 meters (true or false) -- ');
readln(tall);
write('You can jump high (true or false) -- ');
readln(good_jumper);
write('You are athletic (true or false) -- ');
readln(good_athlete);
if (taIlOR good_jumper) AND good_athlete
then writeln(chr(10) ,'Have you considered playing pro basketball.')
else writeln(chr(10), 'Computers are a stable field.');
END.

USING THIS EXAMPLE
This program is available online and is named or_example.

4-136

Code

Ord

Ord Returns the ordinal value of a specified integer, Boolean, char, or enumerated expression.

FORMAT
ord(x)

{ord is a function.}

ARGUMENT

x

Any scalar (i.e., integer, Boolean, char, or enumerated) expression.

FUNCTION RETURNS
The ord function returns an integer value.

DESCRIPTION
The ord function returns the ordinal value of x according to the following rules:

Data Type of x

Ord Returns

Integer

Numerical value of x.

Boolean

o if x

Char

x's ASCII value. Appendix B contains an ISO
Latin-1 table that includes ASCII values.

Enumerated

An integer representing x's position within the
enumeration declaration. For instance, in
program ord_example, ORD (rice) returns
0, ORD(tofu) returns 1, and so on up until
ORD (tamari), which returns 4.

is false and 1 if x is true.

Note that the chr function is the inverse of ord.

Code 4-137

Ord

EXAMPLE

PROGRAM ord_example;
{This program demonstrates the use of the ord function}
TYPE
macro

(rice, tofu, seaweed, miso, tamari);

VAR

c
e

char;
macro;

BEGIN
c := 'd';

WRITELN('The ordinal value of "
e := seaweed;
WRITELN('The ordinal value of'
END.

c, ' is
e:7,' is

ORD (c) : 3) ;

ORD(e) : 1) ;

USING THIS EXAMPLE
If you execute the sample program named ord_example, you get the following output:

The ordinal value of d is 100
The ordinal value of SEAWEED is 2

4-138

Code

Pack

Pack Copies an unpacked array to a packed array.

FORMAT
pack (unpacked_array, index, packed_array)

{pack is a procedure.}

ARGUMENTS

unpacked_array An array that has been defined without the keyword packed.
index

A variable that is the same type as the array bounds (integer, boolean,
char, or enumerated) of unpacked_array. Index designates the array element in unpacked_array from which pack should begin copying.
An array that has been defined using the keyword packed.

DESCRIPTION
Pack copies an unpacked array to a packed one. However, data access with unpacked arrays generally is faster since data elements are always aligned on word boundaries.

Unpacked_array and packed_array must be of the same type, and for every element in
packed_array, there must be an element in unpacked_array. That is, if you have the following type definitions
TYPE

x
y

array[i .. j] of single;
packed array[m .. n] of single;

the subscripts must meet these requirements:
j

-

index >= n - m

{"index" as set in the call to pack}

For example, it is legal to use pack on two arrays defined like this:
TYPE

big_array
small_array

array[1 .. 100] of integer;
packed array[l .. 10] of integer;

VAR
grande
petite

big_array;
small_array;

Code 4-139

Pack
You use index to indicate the array element in unpacked_array from which pack should
begin copying. For instance, given the previous variable declarations and assuming variable
i is an integer, this fragment

:= 1;

i

pack (grande , i, petite);
tells pack to begin copying at grande[I]. Pack keeps copying until it reaches the highest
index value that petite can take-which in this case is 10. The remaining elements in
grande are not copied.

Index can take a value outside of packed_array's defined subscripts. That is, if in the example above, i equals 50, pack copies these values this way:
petite[1] := grande[50];
petite[2] .- grande [51] ;

petite[10] := grande [59] ;
See the listing for unpack later in this encyclopedia.

EXAMPLE

PROGRAM pack_example;
{ThiS program demonstrates the pack procedure}
TYPE

uarray
parray

array[1 .. 50] of integer16;
packed array[1 .. 10] of integer16;

VAR

full_range
sub_range
i, j

uarray;
parray;
integer16;

BEGIN
for i := 1 to 50 do
full_range[i] := i;
j := 20;
PACK(full_range, j, sub_range);
writeln ('The packed array now contains: ');
for i := 1 to 10 do
writeln (' sub_range [' • i:2. '] = '. sub_range[i] :2);

END.

4-140

Code

Pack

USING THIS EXAMPLE
If you execute the sample program named pack_example, you get the following output:

The packed array now contains:
sub_range [ 1]
20
sub_range [ 2]
21
sub_ranger 3]
22
sub_ranger 4]
23
sub_ranger 5]
24
sub_range [ 6]
25
sub_range [ 7]
26
sub_ranger 8]
27
sub_ranger 9]
28
sub_range [10]
29

Code 4-141

Page

Page Inserts a formfeed (page advance) into a file.

FORMAT
page(/)

{page is a procedure.}

ARGUMENT

I

A text variable. I is optional. If you do not specify
the file is standard output (output).

I,

page assumes that

DESCRIPTION
Use the page procedure to insert a formfeed (ISO Latin-1 character 12) into the file
specified by I. Page is useful for formatting text that will be printed or for text that meets
fixed-length window dimensions. If you print the file on a line printer, the printer advances to the next page when it encounters the formfeed.
Before calling page, you must open the file named in I for writing. See Chapter 8 for a
description of opening files.

4-142

Code

Page

EXAMPLE

PROGRAM page_example;
{This program demonstrates the PAGE procedure.}
CONST
lines_in_a_page

54;

{Our printer prints 54 lines to a page.}

VAR
information
statint
x

text;
integer32;
integer16;

BEGIN
{ Create a file and open it for writing; exit on error. }
open(information, 'square_root_table', 'NEW', statint);
if statint = 0 then
rewrite (information)
else
begin
writeln('Pascal reports error', statint, ' on OPEN.');
return;
end;
{Print the square roots from 1 to 200, inserting }
{formfeeds where needed.
}
for x := 1 to 200 do
begin
writeln(information, 'The square root of'
if «x mod lines_in_a_page) = 0) then
PAGE(information);
end;

x:3, ' is

sqrt(x»;

END.

USING THIS EXAMPLE
This program is available online and is named page_example.

Code 4-143

Pointer Operations

Pointer Operations

Chapter 3 explains how to declare pointer types. Here, we describe how to use pointers in
the action part of your program.

DESCRIPTION
You can do the following things with a pointer variable:
•

Use the addr function to assign the virtual address of a variable to the pointer
variable.

•

Compare or assign the value of one pointer variable to another compatible pointer
variable.

•

De-reference a pointer variable. De-referencing means that you find the contents
of the variable to which the pointer variable was pointing.

The following program fragment does all three things:

Program test;
TYPE

pi

~integer16;

VAR
plquart, p2quart
quartl,
quart2

pi;
integer16 .- 5;

BEGIN
plquart .- addr(quartl);
p2quart := plquart;
quart2 . - p2quart ~ ;
END.

Manipulating Virtual Addresses-Extension

Domain Pascal supports type transfer functions that are quite useful in manipulating virtual
addresses. For example, you cannot directly write a pointer value to a text file; however,
you can use a type transfer function to transfer the address to an integer32 value (which
can be written).

4-144

Code

Pointer Operations
For example, compare the right and wrong ways to write the virtual address of quart! to
output:
writeln(plquart);
writeln(integer32(plquart»;

{wrong}
{right}

Invoking Procedure and Function Pointers-Extension
You de-reference a procedure or function pointer like any other pointer; that is, with the
caret (A). In this way, functions can return pointers to other functions; for example:
TYPE

retbool = "'function : boolean;
retfunptr = "'function : retbool;
VAR

xp : retbool;
rf : retfunptr;
flag : boolean;

FUNCTION myfunc; retbool;

rf := ADDR(myfunc);
xp : = rf"';
flag := xp"';
The expression rfA invokes the myfunc function, which returns a pointer to a function that
returns a Boolean value. You cannot use the following assignment
flag := rf ...... ;
because you cannot de-reference the return value of a function call.

Addressing Procedure and Function Pointers-Extension
To obtain procedure and function addresses, use the predeclared function addr. Thus,
there is no ambiguity about a function reference, especially one with no parameters. It is
either invoked by name only, or its address is taken by the addr function.
Although the addr function has been declared to return a univ_ptr, the compiler adds
extra type checking whenever you try to pass a procedure or function address to a specific

Code 4-145

Pointer Operations
procedure or function pointer. In the assignment pptr := addr(proc2) from the following
program fragment, the declaration for proc2 must exactly match the template for the procedure type of pptr. If not, the compiler reports an error. If, however, the assignment is
to a univ_ptr, like xxx := addr(funcl), the compiler cannot do this extra type checking.
VAR

xxx
pptr

UNIV_PTR;
AProcedure(IN i, j
OUT
a
VAR
r

integer;
char;
real); EXTERN;

BEGIN

4-146

Code

xxx .- funcl;

{This is a call.}

xxx .- addr(funcl);

{This takes the address.}

pptr := addr(proc2);

{This takes the address and cheeks.}

Pred

Pred Returns the predecessor of a specified ordinal value.

FORMAT
{pred is a function.}

pred(x)

ARGUMENT

x

An integer, Boolean, char, or enumerated expression.

FUNCTION RETURNS
The pred function returns a value having the same data type as x.

DESCRIPTION
Pred returns the predecessor of x according to the following rules:

Data Type of x

Pred Returns

Integer

The numerical value equal to x-J.

Boolean

False-even if x already equals false.

Char

The character with the ISO Latin-l value one less than
the ISO Latin-l value of x. If this character (x-J)
does not exist, Domain Pascal cannot detect the error.

Enumerated

The identifier to the left of x in the type declaration.
If x is the leftmost identifier, pred's return value is
undefined.

pred(firstof(x» generally is undefined; however, Domain Pascal does not report an error.
Domain Pascal also doesn't report an error if you specify an integer value that is outside
the range of the specified integer type. Therefore, your program should test for an out-ofbounds condition.
Compare the pred function to the succ function.

Code 4-147

Pred

EXAMPLE

PROGRAM pred_example;
TYPE
jours = (lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche);
VAR

i

cl, c2
semaine

integer;
char;
jours;

BEGIN
i := 53; cl:= 'n'; semaine:= vendredi;
writeln('The predecessor of' i:2,' is " pred(i):2);
c2 := pred(cl);
writeln('The predecessor of' cl:l,' is " c2);
writeln('The predecessor of' semaine:8,' i s ' pred(semaine):8);
END.

USING THIS EXAMPLE
If you execute the sample program named pred_example, you get the following output:

The predecessor of 53 is 52
The predecessor of n is m
The predecessor of VENDREDI is

4-148

Code

JEUDI

Ptoc

Ptoc

Appends a null byte to a variable-length string. (Extension)

FORMAT
{ptoc is a procedure.}

ptoc(string) ;

ARGUMENTS
A variable-length string.

string

DESCRIPTION
ptoc appends a null byte to the body of a variable-length string. The address of the
string's body can then be passed to routines that expect a C-style, null-terminated string.
The length field is not changed, so that the null character will not be visible in Pascal expressions that access the array.
When variable-length strings are allocated by the Pascal compiler, they are padded with at
least one byte in order to guarantee that ptoc will not write beyond the bounds of the
string even if its current run-time size is the maximum size of the string.
See the description of ctop for information about converting a null-terminated string into a
variable-length string.

EXAMPLE
In the following example, the Pascal program calls a C function called strip_extra_spaces
that converts substrings of two or more space characters into a single space character.
Note that we pass the body field rather than the variable-length string because the C function expects a pointer to a char, not a pointer to a structure.

PROGRAM ptoc_and_ctop_example;
{This program demonstrates the use of the ptoc and ctop }
{procedures. It calls an external C module, which is
}
{named strip_extra_spaces. You must compile the C
}
}
{module and bind it with ptoc_and_ctop_example.bin to
{create an executable program.
}
TYPE

str

ARRAY[l .. lOO] of CHAR;

VAR

VARYING [100] of CHAR;

Code 4-149

Ptoc
PROCEDURE strip_extra_spaces (IN OUT s
BEGIN
var_string := 'This
string
has
strip_extra_spaces(var_string.body);

str); OPTIONS(EXTERN);
too many

spaces';

{ The length has not been changed, so the following writeln }
}
{ procedure outputs extra characters.
writeln(var_string);
{ Calling CTOP changes the current length by searching for
}
{ the terminating null. }
CTOP(var_string);
writeln(var_string);
var_string := 'This
string
has
too many spaces';
var_string.length := 30; {Change the length explicitly}
{ PTOC places a null char at the 31st position. }
PTOC(var_string);
strip_extra_spaces(var_string.body);
CTOP(var_string);
writeln(var_string);
END.
/*This module is called by the Pascal program named */
/*ptoc_and_ctop_example.
*/
#define SPACE 32
#define NUL 0
void strip_extra_spaces( s )
char *s;
{
char *start
s;
while (*s)
{
if «*start++
*s++) == SPACE)
while (*s
SPACE)
s++;
}
*start = NUL;
}

USING THIS EXAMPLE
Executing this program, named ptoc_and_ctop_example, produces the following output:

This string has too many spacesny
This string has too many spaces
This string has too

4-150

Code

spaces

Ptoc
The first writeln procedure outputs the string before we have changed the current length.
Even though the string was shortened by strip_extra_spaces, Pascal has no knowledge of
the new length, so it outputs the number of characters indicated by the old length.
Before the second writeln procedure, we call ctop, which adjusts the current length by
searching for the null character implanted by the C function. This is the proper usage of
ctop.
The last writeln call illustrates what happens when you explicitly change the length field.
In this case, we change the length to 30, then we call ptoc which inserts a null character
at the 31st position. This makes the new length known to the C function. The strip_extra_spaces function, therefore, looks only at the first 30 characters. Note that we need to
call ctop again to change the length field after the C function has shortened the string.

Code 4-151

Put

Put Writes to a file.

FORMAT
put(f)

{put is a procedure.}

ARGUMENT
A variable having the file or text data type.

f
DESCRIPTION

If f is a file variable, then put(f) appends one record to the file symbolized by f. If f is a

text variable, then put(f) appends one character to the file symbolized by f.
Before calling put (f) , you must assign a record or character to fA. So the sequence for
writing out data looks like the following:

fA := record_or_character;
PUT(f);
For example, the following program fragment demonstrates output via the put procedure:

VAR
primes
poem
a number
a_letter

file of integer16;
text;
integer16;
char;

BEGIN

a_number := 17;
primes A := a_number;
PUT(primes);
{ Append 17 to the file symbolized by primes. }
a_letter := 'Q' ;
poem"
: = a letter;
- {APpend 'Q' to the file symbolized by poem. }
PUT (poem) ;

4-152

Code

Put
Note that the three statements

a_letter := 'Q';
poem""
:= a_letter;
PUT(poem);
{ Append 'Q' to the file symbolized by poem. }
are identical to the two statements

a_letter := 'Q';
write (poem, a_letter);
You must open I for writing (with rewrite) before calling put.
NOTE:

When you want to close the text file on which you were performing puts, your program should issue a writeln to the file just before closing it. This is in order to flush the file's internal output
buffer. If you don't include the writeln, the last line of the file
may not be written.

EXAMPLE

PROGRAM put_example;
{ This program builds a file of student records in file 'hislOl'.

}

CONST
file to write to
'hislOl';
TYPE
student =
record
name
array[1 .. 12J of char;
age
integer16;
end;
VAR

class
a_student
iostat

FILE OF student;
student;
integer32;

Code 4-153

Put
BEGIN

{ Opens file hislOl for writing. }
open(class, file_to_write_to, 'NEW', iostat);
if iostat = 0
then rewrite(class)
else return;
{ Prompt users for input.
repeat
writeln;
write('Enter the name of a student -- ');
readln(a_student.name);
if a_student.name = 'end' then exit;
write('Enter the age of this student -- ');
readln(a_student.age);

}

{ Append each record to the end of the rec file.
class := a_student;
PUT(class);

}

A

until false;
END.

USING THIS EXAMPLE

This program is available online and is named put_example.

4-154

Code

Read, Readln

Read, Readln Read information from the specified file (or from the keyboard) into the specified
variable (s).

FORMAT
read (f, var), ... , varN) ;

{read is a procedure.}

and
readln (f, var), ... , varN) ;

{readln is a procedure.}

ARGUMENTS

I

A variable having a file data type. For read, f can be a text or a file
variable. However, for readln f must be a text variable. F is optional. If
you do not specify I, Domain Pascal reads from standard input (input),
which is usually the keyboard.

var

One or more variables separated by commas. Var can be any real, integer, char, Boolean, subrange, or enumerated variable. (Boolean and enumerated are extensions to the standard.) Var can also be an array variable or variable-length string (see "Array Operations" earlier in this encyclopedia), an element of an array, or a field of a record variable.

DESCRIPTION
Read and readln perform input operations. (Refer to the get listing earlier in this encyclopedia.) You use read or readln to gather one or more pieces of data from f and store
them into var} through varN. Read and readln store the first piece of gathered data into
var}, the second piece into var2, and so on until varN.
If var is an array of char, read and readln attempt to read as many characters as the array can hold. If there are not enough characters in the file to fill the array, the remaining
elements of var are padded with spaces. If var is a varying array, read and readln attempt to read the number of characters specified as the maximum length of the string. If
there are fewer characters, no padding occurs. The current length of the string is adjusted
to reflect the number of characters actually read.

Before calling read or readln, you must open the file symbolized by f for reading. Chapter
8 explains how to do that.
There is a subtle, but important, difference between read and readln. After a read, the
stream marker points to the character or component after the last character or component

Code 4-155

Read, Readln
it read from the file. In contrast, after a readln, the stream marker points to the character
or record after the next end-of-line character in the file. In other words, after getting the
data for varN, readln skips over the remainder of the current line in the input file. (Note
that var] through varN may themselves cover several lines of data in the file.) If you call
readln and var is a record variable, the compiler reports an error; however, it is not an
error to call read with the same variable-as long as the record variable is the base type of

f·
If you call read or readln when eor (j) is true, the operating system reports an error.

EXAMPLE

PROGRAM read_example;
{ NOTE: Before running this program, you must obtain file
}
{ "annabel_lee" and store it in the same directory as the program.
}
{ This program demonstrates READLN by reading from the poem stored in}
{ pathname 'annabel_lee'.
}
CONST
pathname
VAR
a_line
poem
title
st
count, n

'annabel_lee';
string;
text;
array[1 .. 60] of char;
integer32;
integer16;

BEGIN
{ Open the file for reading.
open(poem, pathname, 'OLD', st);
if st = 0
then reset(poem)
else begin
writeln('Cannot open
return;
end;
readln(poem, title);
writeln('Which line of' title);
write('do you want to retrieve?
readln(n) ;
for count := 1 to (n + 1) do
read In (poem, a_line);
writeln(output, a_line);
END.

4-156

Code

}

pathname) ;

');

Read, Readln

USING THIS EXAMPLE

Following is a sample run of the program named read_example:

Which line of
Annabel Lee
do you want to retrieve? -- 3
That a maiden there lived whom you may know

Code 4-157

Record Operations

Record Operations

In Chapter 3 you learned how to declare record types and variables. This section explains
how to refer to records in the action part of your program.

Referring to Fixed Records
In the action part of your program, you specify a field of a fixed record in the following
way:

For example, consider the following declaration of a fixed record variable:
VAR

student

record
array[l .. 26] of char;
integer16;

n

id
end;

You can assign values to the two fields with the following statements:
student.n
student.id

.- 'Herman Melville';
.- 37;

If the data type of the field is itself a record, you must specify the ultimate field in the
following way:

For example, consider the following record within a record declaration:
TYPE

name = record
first
array[l .. lO] of char;
middle
array[l .. lO] of char;
last
arraY[1 .. 16] of char;
end;
VAR

student
n
id
end;

4-158

Code

record
name;
: integer16;

Record Operations
You can assign values to all four fields with the following statements:
student.n.first := 'Kerry' ;
student.n.middle :== 'Bruce';
student.n.last
.- 'Raduns';
student.id
.- 134;

Variant Records
In the "Variant Records" section of Chapter 3, the variant records worker and my_code
were declared as follows:
TYPE

worker_groups = (exempt, non_exempt);
{enumerated type}
worker = record
{record type}
employee: array[l .. 30] of char; {field in fixed part}
id_number : integer16;
{field in fixed part}
CASE wo : worker_groups OF
{variant part}
exempt : (yearly_salary
integer32) ;
non_exempt
(hourly_wage
real);
end;
my_code
record
CASE integer OF
{variant part}
(all
array[1 .. 4] of char);
1
2
(first_half: array[1 .. 2] of char;
second_half: array[1 .. 2] of char);
3
(xl
integer16;
x2 : boolean;
x3 : char);
4
(raIl: single);
end;
VAR
w worker;
mc
my_code;
The following fragment assigns values to w:
write('Enter the person"s name -- ');
readln(w.employee);
write('Enter the person"s id number -- '); readln(w.id_number);
write('Enter pay status (exempt or non_exempt) -- '); readln(w.wo);
if W.wo = exempt
then begin
write('Enter yearly salary -- '); readln(w.yearly_salary);
end
else begin
write('Enter hourly wage -- '); readln(w.hourly_wage);
end;

Code 4-159

Record Operations
NOTE:

Suppose you execute the preceding fragment and load values into
w.employee, w.id_Dumber, w.wo, and w.hourly_wage. Note
that the compiler won't protect you from mistakenly trying to access w.yearly_salary rather than w.hourly_wage.

The following fragment assigns values to mc. (Notice that we do not use the constants 1,
2, 3, and 4 to specify these fields.)
write('Enter two characters -- '); readln(mc.first_half);
write('Enter two more characters -- '); readln(mc.second_half);
writeln('Together, the four characters are " mc.all);

Arrays of Records
A common way to store records is as an array of records. You must use the following
format to specify a field in an array of records:

array_name[componentl.field_name
For example, given the following declaration for school:

TYPE
student = record
age: 11 .. 20;
class: 7 .. 12;
name: array[1 .. 20] of char;
end;

VAR
school: array[1 .. 1000] of student;
you can specify the 500th record as:
school [500] . age := 15;
school [500] .class := 10;
school[500].name := 'John Donne';

4-160

Code

Repeat/Until

Repeat/Until Executes the statements within a loop until a specified condition is satisfied.

FORMAT
repeat
stmnt; .
until cond;

{repeat is a statement.}

ARGUMENTS

stmnt

An optional argument. For stmnt, specify a simple statement or a compound statement. (Ordinarily, you must indicate a compound statement
with a begin/end pair; however, the begin/end pair is optional within a
repeat statement.)

cond

Any Boolean expression.

DESCRIPTION
Repeat marks the start of a loop; until marks the end of that loop. At run time, Pascal
executes stmnt within that loop until cond is true. As long as cond is false, Pascal continues to execute the statements within the loop.
The following list describes two methods of jumping out of a repeat loop prematurely (Le.,
before the condition is true):
•

Use exit to transfer control to the first statement following the repeat loop.

•

Use goto to transfer control outside the loop.

In addition to these measures, you can also execute a next statement to skip the remainder of the statements in the loop for one iteration.

EXAMPLE
PROGRAM repeat_example;
{ This program demonstrates two different REPEAT loops. }
{ Compare it to while_example.
}
VAR

num
test_completed
i

integer16;
boolean;
integer32;

Code 4-161

RepeatlUntil
BEGIN
write('Enter an integer -- ');
readln(num);
REPEAT
num := num + 10;
writeln(num, sqr(num»;
UNTIL (num> 101);
writeln;
test_completed := false;
REPEAT
write('Enter another integer (or 0 to stop the program) -- ');
readln(i);
if i = 0 then
test_completed := true
else
writeln('The absolute value of' i:1,' is
abs(i):l);
UNTIL test_completed;
END.

USING THIS EXAMPLE

Following is a sample run of the program named repeat_example:

Enter an integer -- 70
80
6400
90
8100
100
10000
110
12100
Enter another integer
The absolute value of
Enter another integer
The absolute value of
Enter another integer

(or 0 to stop the program) -- 4
4 is 4
(or 0 to stop the program)
-5
-5 is 5
(or 0 to stop the program)
0

Now, consider a second run of repeat_example. This time, the user enters an integer
greater than 101. In contrast to while_example, the program still executes the loop once:

Enter an integer -- 102
112
12544
Enter another integer (or 0 to stop the program) -- 0

4-162

Code

Replace

Replace Substitutes a new record for an existing record in a file. (Extension)

FORMAT
{replace is a procedure.}

replace (file _variable)

ARGUMENT

file_variable

A file variable.

DESCRIPTION
Use the replace procedure to replace an element in the file specified by file_variable. You
can use replace only on files with file type; you cannot use it to replace an element in a
text file.
Before calling replace you must do the following:
1. Open the file for reading. (Chapter 8 explains how to do this.)
2.

Specify the record that you wish to replace. To do this, you can use the find procedure (described earlier in this chapter).

3. Store the replacement record by entering a statement of the format

file_variable" := replacement_record;
The replace procedure permits a program to rewrite file components-for example, to correct errors-while the file is open for read access. The program need not close the file and
reopen it.
NOTE:

The term "record", as it applies to a file of file type, refers to an
object of the file's base type. This mayor may not be a Domain
Pascal record type. (For example, the object could be an integer
type.)

EXAMPLE
For a full example of replace, see the example for the find procedure that appears earlier
in this encyclopedia.

Code 4-163

Reset

Reset Makes an open file available for reading.

FORMAT
{reset is a procedure.}

reset (filename)

ARGUMENT

filename

A variable having the text or file data type.

DESCRIPTION
Before you can read data from a file other than standard input, you must reset the file. If
the file is a temporary file and does not already exist, reset creates an empty file. If the
file is not a temporary file, it must already exist, and you must have previously opened it
using open. The open procedure tells the system to open a file for some type of I/O operation; reset tells the system to allow you to read from the file, but prevents you from
modifying the file. (See the description of the find procedure for one exception to this
rule.)

Filename must symbolize an open file.
Calling reset sets the stream marker to point to the beginning of the file. Therefore, filename" will contain the first character or component of the file. You can change the stream
marker by reading from the file (with read, readln, or get) or by calling the find procedure.
If the file is empty when you call reset, then filename" is totally undefined. That is, there

is no way to predict what the value of filename" will be.
To open the file for write access you must call rewrite instead of reset.

4-164

Code

Reset

EXAMPLE

PROGRAM reset example;
{NOTE: Before-running this program, you must obtain file "annabel_lee"
and store it in the same directory as the program.
{
{ Demonstrates reset. After opening a file (with OPEN), the program
{ reads the first line of the file and writes it to standard output.

}
}
}
}

{ We need the two include files in order to use status_$t and
{ error_$print.
%NOLIST;
%INCLUDE '/sys/ins/base.ins.pas';
%INCLUDE '/sys/ins/error.ins.pas';
%LIST;
CONST
pathname_of_file

}
}

'annabel- lee" ,

VAR
assignment
openstatus
a_line

text;
status_$t;
string;

BEGIN
{Open the file for reading.
open (assignment , pathname_of_file, 'OLD', openstatus.all);
if openstatus.all = status_$ok
then RESET(assignment)
else begin
error_$print(openstatus); {print any error
return;
end;
{See Chapter 9 for a discussion of error handling.

}

-}
}

{Read the first line of the file.
readln(assignment, a_line);

}

{Write this line to standard output (usually the transcript pad).
writeln(output, a_line);

}

END.

USING THIS EXAMPLE
This program is available online and is named reset_example.

Code 4-165

Return

Return Causes program control to jump back to the calling procedure or function. (Extension)

FORMAT
Return is a statement that takes no arguments and returns no values.

DESCRIPTION
Ordinarily, after Domain Pascal executes the last statement in a routine, it returns control
to the calling routine. However, you can use return to jump back prematurely (Le., before
the last statement) to the calling procedure or function. You can use return anywhere in
the body of a procedure or function.
Using return in the main procedure causes the program to terminate.

EXAMPLE
PROGRAM return example;
{This program-demonstrates the RETURN statement. }
VAR

Ph : single;
Procedure check_Ph;
BEGIN
if (Ph < 2.0) or (Ph> 14.0) then
begin
writeln('You have entered an invalid result.');
RETURN;
end
else if (Ph <= 4.5) then
writeln('You have entered a valid (but suspicious) result.')
else
{Ph> 4.5}
writeln('You have entered a valid result.');
writeln('Thank you for your cooperation.');
END;
BEGIN {main procedure}
write('Enter the Ph of the test sample -- ');
readln(Ph) ;
check_Ph;
END.

4-166

Code

Return

USING THIS EXAMPLE
This program is available online and is named return_example.

Code 4-167

Rewrite

Rewrite Makes an open file available for writing only.

FORMAT
rewrite (filename)

{rewrite is a procedure.}

ARGUMENT
filename

A variable having the text or file data type.

DESCRIPTION
Before you can write data to a permanent file other than standard output, you must do two
things. First, open the file with the open procedure. Second, call the rewrite procedure.
Open tells the system to open a file for some type of 1/0 operations; rewrite tells the system to allow you to modify the open file. Filename must symbolize an open file.
To open a temporary file for writing, you merely have to call the rewrite procedure (that
is, don't call the open procedure).
NOTE:

Rewrite clears an existing file of its entire contents. To avoid inadvertently erasing an important file, you might consider using the
file_history value 'NEW' when you call open.

Rewrite sets the stream marker to the beginning of the file. Each call to write, writeln, or
put advances the stream marker.
After calling rewrite, the file is empty. Therefore, the value of filename" is totally undefined. That is, there is no way to predict what its value will be.
To open the file for read access you must call reset instead of rewrite.

4-168

Code

Rewrite

EXAMPLE

PROGRAM rewrite_example;
{ This program demonstrates rewrite. Opens a file for writing.
{ The program will prompt you for the name of the file to open.
{ After opening the file, you can write a sentence to it.
{ We need the two include files in order to use status_$t and
{ error_Sprint.

}
}
}
}
}

%NOLIST;
%INCLUDE '/sys/ins/base.ins.pas';
%INCLUDE '/sys/ins/error.ins.pas';
%LIST;
VAR

name_of_file
profound
openstatus
a_line

array[l .. 50] of char;
text;
status_$t;
string;

BEGIN
{ Prompt the user for the name of a file to open. }
write('What is the pathname of the file you want to write to -- ');
readln(name_of_file);
{ Open the file for writing. }
open (profound , name_of_file, 'NEW', openstatos.all);
if openstatus.all = status_$ok
then REWRITE(profound)
else begin
error_$print(openstatus); {Print an error message. }
return;
end;
{ Prompt the user. }
writeln('Now enter a line of text.');
read In (a_line) ;
{ Write the line out to the open file. }
writeln(profound, a_line);
END.

USING THIS EXAMPLE
This program is available online and is named rewrite_example.

Code 4-169

Round

Round Converts a real number to the closest integer.

FORMAT
{round is a function.}

round(n)

ARGUMENT

Any real expression.

n
FUNCTION RETURNS

The round function returns an integer value.

DESCRIPTION

The round function rounds (up or down) n to the closest integer. If the decimal part of n
is equal to or greater than .5, the round function rounds up. (Compare round to trunc.)

EXAMPLE

PROGRAM round_example;
{This program demonstrates the
VAR
x : REAL;
y : INTEGER;
BEGIN
x := 54.2; y : = ROUND (x) ;
x .- 54.5; y : = ROUND (x) ;
: = ROUND (x) ;
x := 54.8;
x .- -54.8; y : = ROUND (x) ;
END.

round function}

WRITELN('If
WRITELN('If
WRITELN('If
WRITELN('If

you
you
you
you

round , ,x, , you get , ,y)
round , ,x, , you get , ,y)
round , ,x, , you get , ,y)
,
,
,
round ,x, you get ,y)

USING THIS EXAMPLE
If you execute the sample program named round_example, you get the following output:

If
If
If
If

4-170

Code

you
you
you
you

round 5.420000E+Ol
round 5.450000E+Ol
round 5.480000E+Ol
round -5.480000E+Ol

you
you
you
you

get
get
get
get

54
55
55
-55

;
;
;
;

Rshft

Rshft Shifts the bits in an integer a specified number of spaces to the right. (Extension)

FORMAT
rshft(num, sh)

{rshft is a function.}

ARGUMENTS

num, sh

Integer expressions.

FUNCTION RETURNS
The rshft function returns an integer value.

DESCRIPTION
The rshft function shifts the bits in num to the right sh places. The expr~ssion num can be
any integer expression smaller than 32 bits. Rshft does not wrap bits around from the
right edge to the left; instead, rshft shifts zeros in from the left end.
Rshft does not preserve the sign bit. The sign bit moves to the right just like every other
bit. This means that if Dum is negative and is a 32-bit integer, the result of an rshft is
always positive. Of course, if Dum already is positive, the result of an rshft will still be
positive.
Say, for example, num is a 16-bit signed integer and the result of the function is to be
stored in a 16-bit integer variable. In this case, rshft expands num to a 32-bit integer,
performs the shift, and converts it back to a 16-bit integer. Note that, because of the expansion and contraction, rshft always returns a negative number when num is a 16-bit
negative expression and sh is less than or equal to 16.
Consider this example. Suppose num is 16 bits and equals -9. You perform an rshft with
sh equaling 3 and put the result back in a 16-bit integer. Here's what happens at each
step:

Before the rshft
Convert to 32-bit integer
Rshft 3 bits
Convert to 16-bit integer

1111111111110111

-9

11111111111111111111111111110111
00011111111111111111111111111110

1111111111111110

-2

Code 4-171

Rshft
If you print the rshft result before it is converted back to 16 bits, you get the number rep-

resented in the third step above which, of course, is a different number than the final result. Write your code like this to get that 32-bit result
writeln(rshft(num,3»;
instead of like this
answer := rshft(num,3);
writeln(answer);

{Assume answer is a 16-bit integer.}

Results are unpredictable if sh is negative.
Compare rshft to Ishft and arshft.

EXAMPLE

See the example shown in the arshft listing earlier in this encyclopedia.

4-172

Code

Set Operations

Set Operations

In Chapter 3 we described how to declare set variables. This section explains how to use
set variables in the code portion of your program.

ASSIGNMENT
To assign value(s} to a set variable, use one of the following formats:

set_variable
set_variable
set_variable
set_variable

:=
:=
:=
:=

[];

[el, el, ... el];
[el .. ell;
set_expression set_operator set_expression;

The brackets are mandatory. El must be an expression with a value having the same data
type as the base type of the set variable.
(The set_operators are detailed later in this listing.)
The following program fragment shows seven possible set assignments for the paint set:

TYPE
colors

(white, beige, black, red, blue, yellow, green);

VAR

c : colors; {enumerated variable}
paintl, paint2, paint3, paint4, paintS, paint6, paint7

SET OF col-

ors;
BEGIN
c := blue;
paintl .paint2 .'paint3 .paint4 .paint5 .paint6 .paint7 .-

[] ;
{Null set.}
{Illegal assignment.}
[rojo] ;
[red] ;
[beige, green, black];
green] ;
[white
{All seven elements.}
{beige, black, red, and blue.}
[beige .. blue] ;
{blue.}
[c] ;

Code

4-173

Set Operations

SET OPERATORS
Table 4-13 shows the eight set operators Domain Pascal supports. The following subsections describe these operators individually.

Table 4-13. Set Operators
Set Operator

+

•

=
<>
<=
>=
in

Operation
Union of two sets
Intersection of two sets
Set exclusion
Set equality
Set inequality
Subset
Superset
Inclusion

Union
The union of two sets is a set containing all members of both sets. In the following example, paint3 contains the union of sets paintl and paint2:

TYPE
colors

(white, beige, black, red, blue, yellow, green);

VAR

c : colors;
paint!, paint2, paint3

SET OF colors .- [];

BEGIN
paint! .- [white, black, red];
paint2 .- [black, yellow];
paint3 .- paint! + paint2;
{paint3 will contain white, black, red, and yellow.}
If there are duplicates (for example, black), the resulting set does not store the duplicate

value twice. Thus, paint3 contains black only once.

4-174

Code

Set Operations

Intersection
The intersection of two sets is a set containing only the duplicate elements. In the following
example, paint3 contains the intersection of sets paintl and paint2:

TYPE

colors

(white, beige, black, red, blue, yellow, green);

VAR

c : colors;
paintl, paint2, paint3

SET OF colors := [];

BEGIN
paintl .- [white, black, red];
paint2 .- [black, yellow];
paint3 .- paintl * paint2;
{paint3 will contain black.}

Set Exclusion
Pascal finds the result of a set exclusion operation by starting with all the elements in the
left operand and crossing out any of the elements that are duplicated in the right operand.
The following program fragment demonstrates two set exclusion operations:

TYPE

colors

(white, beige, black, red, blue, yellow, green);

VAR
c : colors;
paintl, paint2, paint3

SET OF colors .- [];

BEGIN
paintl .- [white, black, red];
paint2 .- [black, yellow];

paint3 .- paintl - paint2;
{paint3 will contain white and red.}
paint3 := paint2 - paintl;
{paint3 will contain yellow.}

Code

4-175

Set Operations

Set Equality and Inequality
The result of a set equality (=) or inequality (<» operation is a Boolean value. If two set
variables contain exactly the same elements (or are both null sets), then = is true and <> is
false. The following program fragment demonstrates set equality:
TYPE
colors

(white, beige, black, red, blue, yellow, green);

VAR
c : colors;
paintl, paint2

SET OF colors .- [];

BEGIN
paintl := [white, black, red];
paint2 .- [black, yellow];
if paintl = paint2
then writeln('The two sets contain the same elements.');
else writeln('The two sets do not contain the same elements.');

Subset
The result of a subset operation «=) is a Boolean value. If the first operand is a subset of
the second operand, then the result is true; otherwise, the result is false.
TYPE
colors

(white, beige, black, red, blue, yellow, green);

VAR
c : colors;
paintl, paint2

SET OF colors .- [];

BEGIN
paintl .- [white, black, red];
paint2 := [white, red];
if paint2 <= paintl
{this is true}
then writeln ('Paint2 is a subset of paintl');

Superset
The result of a superset operation (>=) is a Boolean value. If the first operand is a superset of the second operand, then the result is true; otherwise, the result is false.

4-176

Code

Set Operations
TYPE

colors = (white, beige, black, red, blue, yellow, green);
VAR

c : colors;
paintl, paint2 : SET OF colors := [];
BEGIN
paintl := [white, black, red];
paint2 := [white, red];
if paintl >= paint2 {this is true.}
then writeln('Paintl is a superset of paint2.');

Inclusion
See the separate in listing earlier in this encyclopedia.

EXAMPLE

PROGRAM set_example;
{This program demonstrates I/O with set variables. You cannot
{use a set variable as an argument to any of the predeclared
{Pascal I/O procedures, so you must use a somewhat roundabout
{method involving the base type of the set.

}
}
}
}

TYPE

possible_ingredients
(sugar, nuts, chips, milk, flour, carob, salt, bkg_soda);
VAR

pi
possible_ingredients;
set of possible_ingredients .- [];
cookies
answer
char;
BEGIN
{Read the proper cookie ingredients and store }
{them in the cookies variable.
}
for pi := sugar to bkg_soda do
begin
write('Should the recipe contain' pi:4, '1 (y or n) -- ');
readln(answer);
if (answer = 'y') or (answer = 'Y') then
cookies := cookies + [pi];
end; {for}
{Write the list of ingredients.
}
writeln(chr(lO), 'The ingredients are: ');
for pi := sugar to bkg_soda do
if pi IN cookies then
writeln(pi);
END.

Code

4-177

Set Operations

USING THIS EXAMPLE

Following is a sample run of the program named set_example:
Should
Should
Should
Should
Should
Should
Should
Should

the
the
the
the
the
the
the
the

recipe
recipe
recipe
recipe
recipe
recipe
recipe
recipe

contain
contain
contain
contain
contain
contain
contain
contain

The ingredients are:
SUGAR
NUTS
CHIPS
FLOUR
SALT
BKG_SODA

4-178

Code

SUGAR? (y or n) -- y
NUTS? (y or n) -- y
CHIPS? (y or n) -- y
MILK? (y or n) - n
FLOUR? (y or n) -- y
CAROB? (y or n) -- n
SALT? (y or n) -- y
BKG SODA? (y or n) -- y

Sin

Sin Calculates the sine of the specified number.

FORMAT
sin (number)

{sin is a function.}

ARGUMENT
number

Any real or integer expression.

FUNCTION RETURNS
The sin function returns a real value (even if number is an integer).

DESCRIPTION
The sin function calculates the sine of a number. This function assumes that the argument
(number) is a radian measure (as opposed to a degree measure). (Refer also to the cos
listing earlier in this encyclopedia.)

Code

4-179

Sin

EXAMPLE

PROGRAM sin_example;
{This program demonstrates the SIN function.}
CONST
pi = 3.1415926535;
VAR

angle_in_radians, c1, converted_to_radians, c2, angle_in_degrees: REAL;
BEGIN
write('Enter an angle in radians -- ');
readln(angle_in_radians);
c1 := SIN(angle_in_radians);
writeln('The sine of " angle_in_radians:5:3, ' radians is "

c1:5:3);

{The following statements show how to convert from degrees to radians.}
write('Enter another angle (in degrees) -- ');
readln(angle_in_degrees);
converted_to_radians := «angle_in_degrees * pi) / 180.0);
c2 := SIN(COnverted_to_radians);
writeln('The sine of " angle_in_degrees:5:3, ' is " c2:5:3);
END.

USING THIS EXAMPLE
Following is a sample run of the program named siD_example:

Enter an angle in radians -- 1.0
The sine of 1.000 radians is 0.841
Enter another angle (in degrees)
The sine of 14.200 is 0.245

4-180

Code

14.2

Sizeof

Sizeof Returns the size (in bytes) of the specified data object. (Extension)

FORMAT
The sizeof function has two formats:
sizeof(x)

{first form}

sizeof(x, tag], . . . tagN)

{second form}

ARGUMENTS

x

The name of a type (standard or user-defined), a variable, a constant, or
a string.

tag

One or more constants corresponding to the fields in a variant record.
You specify these tags only if you want to find the size of a variant record. The number of tags can be no greater than the number of tag
fields in the variant record.

FUNCTION RETURNS
The function returns an integer value.

DESCRIPTION
Sizeof returns an integer equal to the number of bytes that the program uses to store x. If
the argument to sizeof is a variable-length string, sizeof returns the size of the entire record, including the current length field and any padding bytes.
You must often supply a string and its length as input arguments when calling a procedure
or function. You can use sizeof to calculate the string's length, although the way you call
sizeof affects the answer you get. For example, if your code includes the following:

VAR
length
animal

integer;
string;

animal .- 'wildebeest';
length .- SIZEOF(animal);

Code

4-181

Sizeof
sizeof returns 80 because animal is declared to be a string, and string is defined as being an array of 80 chars. However, if you call the function this way:
length := SIZEOF('wildebeest');
sizeof returns a value of 10.
To find the size of a specified variant record, you must pass both the name of the variant
record type (or variable), and tag fields. For example, consider the following record declaration:

TYPE
worker_stat = (exempt, nonexempt);
worker = record
name: array[1 .. 24] of char;
case worker_stat of
exempt
(salary
integer16);
(wages
single;
nonexempt
plant
array[l .. 20] of char);
end;
end;
To find the size of a record if worker_stat equals exempt, call sizeof as follows:

•

SIZEOF(worker, exempt)
To find the size of a record if worker_stat equals nonexempt, call size of as follows:

•

SIZEOF(worker, nonexempt)

4-182

Code

Sizeof

EXAMPLE

PROGRAM sizeof_example;
{ This program demonstrates the SIZEOF function. }
CONST
'ficus';
tree
TYPE
student = RECORD
name
array[1 .. 19] of char;
age
integer16;
id
integer32;
end;
VAR

t2

integer16;

BEGIN
writeln('The
writeln('The
writeln('The
writeln('The

size
size
size
size

of
of
of
of

constant tree is " SIZEOF(tree):l);
variable t2 is " SIZEOF(t2):1);
an integer32 variable is " SIZEOF(integer32):1);
a student record is " SIZEOF(student):l);

END.

USING THIS EXAMPLE
If you execute the sample program named sizeof_example, you get the following output:

The
The
The
The

size
size
size
size

of
of
of
of

constant tree is 5
variable t2 is 2
an integer32 variable is 4
the student record type is 26

Code

4-183

Sqr

Sqr Calculates the square of a specified number.

FORMAT
sqr(n)

{sqr is a function.}

ARGUMENT
Any integer or real expression.

n

FUNCTION RETURNS
The $qr function returns an integer if n is an integer, and returns a real number if n is
real.

DESCRIPTION
The sqr function calculates n • n. A potential problem for users is that the square of a
large integer16 value often exceeds the maximum value (32,767) for integer16 variables.
If this error is possible in your program, assign the square of an integer16 variable to an
integer32 variable.

EXAMPLE
PROGRAM sqr_example;
{ThiS program demonstrates the use of the sqr function}
VAR

i_short : integer16;
i_long
: integer32;
rl, r2 : real;

BEGIN
write('Enter an integer -- '); readln(i_short);
i_long := SQR(i_short);
writeln('The square of " i_short:l, ' is " i_long:l);
write('Enter a real number -- '); readln(rl);
r2 := SQR(rl);
writeln('The square of " rl:l, ' is " r2:1);

END.

4-184

Code

Sqr

USING THIS EXAMPLE

Following is a sample run of the program named sqr_example:

Enter an integer -- 1100
The square of 1100 is 1210000
Enter a real number -- -5.23
The square of -5.230000E+00 is 2.735290E+01

Code

4-185

Sqrt

Sqrt Calculates the square root of a specified number.

FORMAT
sqrt(n)

{sqrt is a function.}

ARGUMENT

n

Any integer or real expression that evaluates to a number greater than
zero.

FUNCTION RETURNS
The sqrt function returns a real value (even if n is an integer).

DESCRIPTION
The sqrt function calculates the square root of n.

EXAMPLE

PROGRAM sqrt_example;
{This program demonstrates the use of the sqrt function}
VAR

i_long
r_single
r_double

integer32;
single;
double;

BEGIN
write('Enter an integer -- '); readln(i_long);
r_double := SQRT(i_long);
writeln('The square root of " i_long: 1, ' is "

r_double);

write('Enter a real number -- '); readln(r_single);
r_double := SQRT(r_single);
writeln('The square root of' r_single, ' is' r_double);
END.

4-186

Code

Sqrt

USING THIS EXAMPLE
Following is a sample run of the program named sqrt_example:
Enter an integer -- 24
The square root of 24 is
4. 898979663848877E+OO
Enter a real number
24.0
The square root of
2.400000E+Ol is
4. 898979663848877E+OO

Code

4-187

Statements

Statements
Throughout this encyclopedia, we refer to statements, both simple and compound. Here,
we define statement.

Statement
When a format requires a statement, you must enter one of the following:
•

An assignment statement like x := 5 or x := y + z. An assignment statement can
also be a call to a function like x := ORD('a').

•

A procedure call like writeln('hi').

•

A goto, if/then, if/then/else, case, for, repeat, while, with, exit, next, or re-

turn statement.
•

A compound statement.

•

An empty statement. An empty statement causes no action except an advance to
the next statement. It can be represented by two consecutive semicolons (;;).

Simple and Compound Statements
When the format part of a listing in this chapter says that a command requires a simple
statement, it just means that we require one statement (see above). A compound statement
is a group of zero or more statements bracketed by the keywords begin and end. In other
words, a compound statement has the following format:
begin
statement 1 ;

statementN

end;
The action part of a routine is itself a compound statement. A statement can be preceded
by a label (but not every label is accessible; see the goto listing earlier in this chapter).

4-188

Code

Substr

Substr Extracts a substring from a string. (Extension)

FORMAT

substr(src_string, start, length):

{su bstr is a function.}

ARGUMENTS
A variable-length string, character array, or character-string constant.

start

The position of the first character in the desired substring of src_string.

length

The number of characters in the desired substring (length is a positive
integer).

FUNCTION RETURNS
The substr function returns a variable-length string.

DESCRIPTION
The substr function returns a substring of the source string. The start parameter indicates
the position of the first character of the desired substring. The length parameter indicates
the number of characters to return.
If the values of either start or length specify a character position outside of the bounds of

the run-time size of the source string, an error trap occurs.

Code

4-189

Substr

EXAMPLE

PROGRAM substr example;
{This program demonstrates the use of the substr function.}
{It displays a substring of a given string.
}
VAR
strl
str2
str3

array[1 .. 30] of char;
varying [30] of char;
varying [30] of char;

BEGIN
strl .- 'Foolish consistency is ';
str2 .- 'the hobgoblin of ';
str3 := substr( 'little minds', 8, 5 );
writeln( substr(strl, 1, 8»;
writeln( substr(str2, 5, 10»;
writeln( str3 );
END.

USING THIS EXAMPLE
Executing this program, named substr_example, produces the following output:

Foolish
hobgoblin
minds

4-190

Code

Succ

Succ Returns the successor of a specified ordinal value.

FORMAT
succ(x)

{succ is a function.}

ARGUMENT

x

Must be an integer, Boolean, char, or enumerated expression.

FUNCTION RETURNS
The succ function returns a value having the same data type as x.

DESCRIPTION
The succ function returns the successor of x according to the following rules:

Data Type of x

Succ Returns

Integer

The numerical value equal to x + 1.

Boolean

True-even if x already equals true.

Char

The character with the ISO Latin-l
value one greater than the ISO
Latin-l value of x.

Enumerated

The identifier to the right of x in
the type declaration.

succ(lastof(x» generally is undefined; however, Domain Pascal does not report an error.
Domain Pascal also doesn't report an error if you specify an integer value that is outside
the range of the specified integer type. Therefore, your program should test for an out-ofbounds condition.
Compare the succ function to the pred function.

Code

4-191

Succ

EXAMPLE

PROGRAM succ_example;
{This program demonstrates the use of the succ function}
TYPE
jours

(lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche);

VAR

int : integer;
ch
: char;
semaine : jours;
BEGIN
int := succ(53);
writeln('The successor to 53 is " int:l);
ch := succ('q');
writeln('The successor to q is " ch);
semaine := succ(jeudi);
writeln('The successor to jeudi is " semaine:8);
END.

USING THIS EXAMPLE
If you execute the sample program named succ_example, you get the following output:

The successor to 53 is 54
The successor to q is r
The successor to jeudi is VENDREDI

4-192

Code

Then

Then Refer to if earlier in this encyclopedia.

Code

4-193

To

To Refer to for earlier in this encyclopedia.

4-194

Code

Trune

Trune Truncates a real number to an integer.

FORMAT
{trune is a function.}

trune(n)

ARGUMENT

n

Any real value.

FUNCTION RETURNS
The trune function returns an integer.

DESCRIPTION
The trune function removes the fractional part of n to create an integer. (Compare trune
to round.)

EXAMPLE

PROGRAM trunc example;
{ This progra; demonstrates the use of the trunc function. }
}
{ Compare to round function.
VAR

x : REAL;
y : INTEGER;
BEGIN
x .- 54.2; y
54.5; Y
x
x .- 54.8; Y
x :=-54.8; Y
END.

....-

TRUNC(x)
TRUNC(x)
TRUNC (x)
TRUNC(x)

;
;
;
;

WRITELN('If
WRITELN('If
WRITELN('If
WRITELN('If

you
you
you
you

truncate
truncate
truncate
truncate

,

,x, ,
,x, ,
,
,x, ,
,
,x, ,
,

you
you
you
you

get
get
get
get

Code

' ,Y) ;
' ,Y) ;
,
,Y) ;
' ,Y)

4-195

Trone

USING THIS EXAMPLE
If you execute the sample program named trune_example, you get the following output:
54
54
54
-54

Compare these results to the results of executing program round_example.

4-196

Code

Type Transfer Functions

Type Transfer Functions

Permit you to change the data type of a variable or expression in
the code portion of your program. (Extension)

FORMAT

transferJunction (x)

{Type transfer functions are functions.}

ARGUMENTS

transferJunction
The name of any predeclared Domain Pascal data type or any userdefined data type that has been declared in the program.

x

An expression.

DESCRIPTION
Domain Pascal type transfer functions enable you to change the type of a variable or expression within a statement. To perform a type transfer function, use any user-created or
standard type name as if it were a function name in order to "map" the value of its argument into that type.
With one exception, the size of the argument must be the same as the size of the destination type. (Chapter 3 describes the sizes of each data type.) This size equality is required
because the type transfer function does not change any bits in the argument. Domain Pascal just "sees" the argument as a value of the new type. The one exception is that integer
subranges are always compatible regardless of their sizes.
It is important to remember that type transfer functions do not convert any value. Consider
the following data type declarations:
VAR

i
r

INTEGER32;
REAL;

The following assignment converts the value of variable i to a floating-point number:
r

:= i;

Code

4-197

Type Transfer Functions
However, in the following assignment, Domain Pascal "sees" the bits in i as if they were
actually representing a floating-point number. In this case, there is a transfer, but no conversion:

r := real(i);
Note that there are restrictions on the data types to which you can convert a given Domain
Pascal data type. For example, you get an error if you try the following:

:=

i

r;

In such a case, there's no way for Domain Pascal to know what you want to do with the
portion of r after the decimal point. Use the trunc or round functions (described earlier in
this encyclopedia) instead.
A practical application of type transfer functions is in controlling the bit precision of a
computation. For example, consider the following program fragment:

VAR
x, y

integer16;

BEGIN
if x + y > 5
then .
By default, the compiler expands operands x and y to 32-bit integers and performs 32-bit
addition before making the comparison to 5. However, by using the following type transfer
function, we can produce more efficient code:

VAR
x, y

integer16;

BEGIN
if INTEGER16(x +
then . . .

y)

> 5

The disadvantage to using the type transfer function in the preceding fragment is that it
ignores the possibility of integer overflow.

4-198

Code

Type Transfer Functions

EXAMPLE

PROGRAM type_transfer_functions_example;
{ This program demonstrates two uses of type transfer functions. }
TYPE
car_manufacturers
(ford, chevy, nissan, dodge, caddy, honda);
pointer_to_word
"'word;
array[l .. 10] of char;
word
VAR

ordinal_value_of_car : integer16;
car, actual_value_of_car : car_manufacturers;
name, rename
word:= [* of ' '];
namepointer
: pointer_to_word;
BEGIN
car := dodge;
ordinal_value_of_car := ord(car);
actual value of car := CAR MANUFACTURERS(ordinal value of car);
-{ The-ab~ve stateme~t transfers an intege; value into}
{ an enumerated value. }
write('The actual value of ordinal value ');
writeln(ordinal_value_of_car:1,' is', actual_value_of_car:7);
{ It is illegal to perform mathematical operations on a pointer
}
{ variable. However, by using type transfer functions you can
}
{ temporarily make a pointer variable into an integer variable so
}
{ that you can perform mathematical operations on it. Then, after }
{ using the integer in a math calculation, you can transfer the
}
{ integer back to a pointer type by using a second type transfer
}
{function. This routine prints the final eight characters in the }
{ specified name.
}
write('Enter a name that is 10 characters long -- ');
readln(name);
namepointer := addr(name); {get starting address of name array}
namepointer := UNIV_PTR(INTEGER32(namepointer) + 2);
rename := namepointer"';
rename: 8);
writeln('The last eight characters of the name are
END.

USING THIS EXAMPLE
If you execute the sample program named ttf_example, you get the following output:

The actual value of ordinal value 3 is
DODGE
Enter a name that is 10 characters long -- CALIFORNIA
The last eight characters of the name are LIFORNIA

Code

4-199

Unpack

Unpack Copies a packed array to an unpacked array.

FORMAT
unpack (packed_array, unpacked_array, index)

{unpack is a procedure.}

ARGUMENTS

unpacked_array An array that has been defined without the keyword packed.
An array that has been defined using the keyword packed.
A variable that is the same type as the array bounds (integer, boolean,
char, or enumerated) of unpacked_array. Index designates the array element in unpacked_array to which unpack should begin copying.

index

DESCRIPTION
Unpack copies the elements in a packed array to an unpacked one. Data access with un ..
packed arrays generally is faster since data elements are always aligned on word boundaries.

Unpacked_array and packed_array must be of the same type, and for every element in
packed_array, there must be an element in unpacked_array. That is, if you have the following type definitions
TYPE

x
y

array[i .. j] of single;
packed array[m .. n] of single;

the subscripts must meet these requirements:
j

index >= n - m

-

{"index" as set in the call to unpack}

For example, it is legal to use unpack on two arrays defined like this:
TYPE

big_array
small_array

array[l .. 100] of integer;
packed array[l .. 10] of integer;

VAR

grande
petite

4-200

Code

big_array;
small_array;

Unpack
You use index to indicate the array element in unpacked_array to which unpack should
begin copying. For instance, given the previous variable declarations and assuming variable
i is an integer, this fragment
i := 1;
unpack(petite, grande, i);

tells unpack to begin copying into grande [1] . Unpack keeps copying until it has exhausted
all of petite's elements - in this case 10. Unpack always copies all of its packed_array's
elements, regardless of how many elements are defined for unpacked_array.

Index can take a value outside of packed_array's defined subscripts. That is, if in the example above, i equals 50, unpack copies these values this way:

grande [50] := petite[l];
grande[51]:= petite[2];

grande [59] := petite[10];
See the listing for pack earlier in this encyclopedia.

EXAMPLE

PROGRAM unpack_example;
{This program demonstratest the use of the unpack procedure}
TYPE
uarray
array[l .. 50] of integer16;
parray
packed array[1 .. 10] of integer16;
VAR

full_range
sub_range
i, j

uarray;
parray;
integer16;

BEGIN
for i := 1 to 10 do
sub_range[i] .- i;
j := 30;

UNPACK(sub_range, full_range, j);
writeln ('The unpacked array now contains: ');
for i := 30 to 39 do
writeln ('full_range[', i:2, '] = ' full_range[i] :2);
END.

Code

4-201

Unpack

USING THIS EXAMPLE
If you execute the sample program named unpack_example, you get the following output:

The unpacked array now contains:
full_range [30]
1
full_range [31]
2
full_range [32]
3
full_range [33]
4
full_range [34]
5
full_range [35]
6
full_range [36]
7
full_range [37]
8
full_range [38]
9
full_range [39]
10

4-202

Code

Until

Until Refer to Repeat earlier in this encyclopedia.

Code

4-203

Variable-Length String Operations

Variable-Length String Operations

This section describes how to use variable-length strings in the code portion of your program. See Chapter 3 for information about declaring variable-length strings.

USING VARIABLE-LENGTH STRINGS
You may assign a character constant, string constant, or character array to a variablelength string. You make assignments to variable-length strings in the same manner that you
make assignments to arrays of char. For example:

VAR
var_string
ar_of_char

varying [20] of char;
array[1 .. 20] of char;

BEGIN
var_string .- 'test';
ar_of_char .- 'test';

When you assign to a variable-length string, however, the unassigned elements of the array
are not padded with spaces as they are for arrays of char. Unassigned elements maintain
their old values. When you output a variable-length string with write or writeln, the procedure writes only the characters included in the string's current length. The following
example illustrates this essential difference between variable-length and fixed-length arrays:

VAR
var string : VARYING [100] of CHAR;
fixed_string: PACKED ARRAY[1 ... 100] of CHAR;
BEGIN
fixed_string .- 'string';
{length is always 100 - unassigned }
{ chars are padded with spaces
}
var_string := 'string'; {current length 6 }.
writeln(var_string);
{ outputs only six characters}
writeln(fixed_string);
{outputs 100 characters }
var_string .- 'longer string'; {current length is 13 }

END.

4-204

Code

Variable-Length String Operations

Trailing Null Character
The Pascal compiler appends a null character to a variable-length string under the following conditions:
•

A string constant is assigned to a variable-length string.

•

A character constant is assigned to a variable-length string.

•

An array is assigned to a variable-length string.

•

A string is assigned to a variable-length string via a read call.

The trailing null byte facilitates communication with routines written in other languages,
such as C, that expect strings to end with a terminating null character. Note, however,
that the current length of the string does not include the terminating null character, so the
null character is invisible to Pascal routines that do not access the body field directly. For
example:
PROGRAM null_char;

VAR
VARYING [80] of CHAR;
BEGIN
var_string := 'string';
{ null char is appended, but current length is 6 }
writeln(var_string);
{ Does not output null char}
writeln(var_string.body[7]); { Outputs null character}

END.
Note that you can inadvertently overwrite the null character by accessing the length or
body fields directly:

var_string := 'string';
var_string.length := 3; {terminating character is 'i', not null}
var_string.body := 'longer string'; {null character is overwritten
and body is padded with spaces}

For routines that communicate with C functions, you should be careful about directly
changing length and body fields. To be on the safe side you should use the ptoc function,
which explicitly appends a null character to a variable-length string. (See the description
of ptoc in Chapter 4 for an example of passing a variable-length string to a C function.)

Code

4-205

Variable-Length String Operations

ASSIGNING TO AND FROM VARIABLE-LENGTH STRINGS
When you make an assignment to a variable-length string, the compiler automatically promotes the assigned object to a variable-length string. Promotion of string constants occurs
at compile time so it does not affect execution speed. Promotion of characters to
variable-length strings occurs at run time, but is relatively efficient. Promotion of character
arrays to variable-length strings, however, can have a noticeable impact on execution
speed. If execution speed is a serious concern, therefore, you should avoid situations in
which character arrays must be promoted to variable-length strings.
The compiler never demotes variable-length strings to character arrays. To treat a variable-length string as a normal array of characters you should reference its body field.
The following sections contain more detailed information about legal assignments involving
variable-length strings.

varying : = varying

Only those characters included in the current length of the source string (plus the trailing
null character) are copied to the destination string. Note that the compiler does not check
to see whether the trailing byte is in fact a null character. It simply copies a string equal
to one greater than the current length. The length of the destination string is set equal to
the current length of the source string (the trailing null character is not included in the
length).
If the compiler option -subchk is off (default), the compiler copies the source string to the
destination array without checking bounds. If -subchk is on, a run-time check verifies

that the current length of the source string is not larger than the maximum length of the
destination variable. If the string is too large, a run-time error occurs.

varying : = array of char

The compiler promotes the character array to a variable-length string and assigns it to the
destination string variable. It then appends a null character to the destination string. The
length of the reSUlting string is the number of elements in the source character array (Le.,
the length does not include the null character). A compile-time error occurs if the character array is larger than the maximum size of the destination string.

4-206

Code

Variable-Length String Operations

varying : = char
The compiler assigns the character to the body field of the variable-length string and sets
the length field equal to 1. A trailing null character is also assigned to the destination.

Pointer Assignment
Pointers to variable-length strings obey standard Pascal type compatibility rules - two
pointers are compatible only if they share the same type name.

Passing Variable-Length Parameters
The type compatibility rules for variable-length strings that are procedure/function parameters are very similar to the rules for normal assignment. Characters, character arrays,
character-string constants, and variable-length strings may be passed to varying parameters
that are passed by value or as in parameters. The rules for compatibility are the same as
if the argument were being assigned to a variable of the parameter's type. Arguments
passed to variable-length string parameters by reference (var, out or in out) must be
variable-length strings with exactly the same maximum size as the parameter.

Comparing Variable-Length Strings
You can compare two variable-length strings for equality, inequality, and lexicographic order. The lengths of strings being compared depend solely on the strings' current length
values. The lengths are independent of the strings' maximum sizes, as declared at compile
time.
If two strings being compared have different lengths, the comparison is performed as if the

shorter string were padded with spaces to make its length equal to the longer string.

Code

4-207

While

While Executes the statements within a loop as long as the specified condition is true.

FORMAT
while condition do
stmnt;

{while is a statement.}

ARGUMENTS

condition

Any Boolean expression.

stmnt

A simple statement or a compound statement. (Refer to "Statements"
earlier in this encyclopedia.)

DESCRIPTION
For, repeat, and while are the three looping statements of Pascal. With while, you specify
the condition under which Pascal continues looping.
While marks the beginning of a loop. As long as condition evaluates to true, Pascal executes stmnt. When condition becomes false, Pascal transfers control to the first statement
following the loop.
To jump out of a while loop prematurely (Le., before the condition is true), do one of the
following things:
•

Use exit to transfer control to the first statement following the while loop.

•

Use goto to transfer control outside the loop.

In addition to these measures, you can also call the next statement to skip the remainder
of the statements in the loop for one iteration.

4-208

Code

While

EXAMPLE

PROGRAM while example;
{ This program contains two while loops. }
}
{ Compare it to repeat_example.
VAR

num
test_completed
i

integer16;
boolean;
integer32;

BEGIN
write('Enter an integer -- '); readln(num);
WHILE (num < 101) DO
BEGIN
num := num + 10;
writeln(num, sqr(num»;
END;
writeln;
test_completed := false;
WHILE test_completed = false DO
BEGIN
write('Enter an integer (enter a 0 to stop the program) -- ');
readln(i) ;
if i = 0 then
test_completed := true
else
writeln('The absolute value of' i:1,' is
abs(i):1);
END;
END.

Code

4-209

While

USING THIS EXAMPLE
Following is a sample run of the program named while_example:

Enter an integer -- 70
80
90
100
110

6400
8100
10000
12100

Enter an integer (enter a 0 to stop the program)
The absolute value of 4 is 4
Enter an integer (enter a 0 to stop the program)
The absolute value of -5 is 5
Enter an integer (enter a 0 to stop the program)

4
-5
0

Now, consider a second run of while_example. In contrast to repeat_example, while_example does not execute the loop even once when x > 101.

Enter an integer -- 102
Enter an integer (enter a 0 to stop the program) -- 0

4-210

Code

With

With Lets you abbreviate the name of a record.

FORMAT
With is a statement that takes the following format:
with vl, v2, ... vN do

stmnt;
This format is equivalent to:
with vl do
with v2 do

with vN do

stmnt;

ARGUMENTS

vl

A record expression; that is, v1. must evaluate to a record. For example,
it might be the name of a record, a pointer to a record, or a particular
component in an array of records.

v2, ... vN

Optional record references or references that are qualified by v1,
v(N-l).

stmnt

A simple or compound statement. (Refer to the "Statements" listing earlier in this chapter.)

DESCRIPTION
Use with to abbreviate a reference to a field in a record. With works in the following
manner. Suppose that X is a field within record MATHVALUES. Ordinarily, you must
specify the full name MATHVAL UES. X whenever you want to refer to the contents of
field X. However, by using the statement

WITH MATHVALUES

Code

4-211

With
you can simply specify X to refer to the contents of the field. Moreover, suppose that record MATHVALUES contains a field called TRIGONOMETRY which itself contains a
field named Y. By specifying
WITH MATHVALUES, TRIGONOMETRY

you can refer to Y as Y rather than as MATHVALUES.TRIGONOMETRY.Y. Note that
Domain Pascal evaluates the expression vI only once, and this evaluated expression is implied within the body of the with statement.
Now consider a fragment demonstrating with:
TYPE

P = "basketball_team;
VAR

bb = basketball_team;
BEGIN
WITH p" DO
BEGIN

mascot

.- 'tiger';

p

.- nil;
height
.- 198.2;
bb.mascot .- 'lion';

END;

Note two things about the preceding example. First, changing p does not affect access to
the record identified by the with statement. Second, you can reference other records of
the same type by completely qualifying the reference.

Extension to Standard Pascal
Domain Pascal supports the standard format of with and also supports the following alternative format:
with vl:identifierl, v2:identifier2, ... vN:identifierN do
stmnt;
This is very similar to the standard format for with. In this extension, the identifier is a
pseudonym for the record reference v. To specify a record, use the identifier instead of
the record reference v. Furthermore, to specify a field in a record, use identifier.field_name rather than merely field_ name.

4-212

Code

With
For example, given the following record declaration:
VAR

basketball_team : record
mascot
array[1 .. 15] of char;
height
: single;
end;
consider the following three methods of assigning values:
readln(basketball_team.mascot);
readln(basketball_team.height);

{Not using WITH.}
{Not using WITH.}

WITH basketball_team DO
begin
readln(mascot);
readln(height);
end;

{Using standard WITH.}

WITH basketball_team : B DO
begin
readln(B.mascot);
readln(B.height);
end;

{Using extended WITH.}

This feature is useful for working with long record names when two records contain fields
that have the same names. (See the example at the end of this listing.)

EXAMPLE

PROGRAM with_example;
{ This program demonstrates the WITH statement. }
TYPE

name = record
first: array[l .. 10] of char;
last: array[l .. 14] of char;
end;
documentation_department = record
their_name
name;
current_project
: string;
end;
VAR

documentation_department;

Code

4-213

With
BEGIN
writeln('In this routine, you enter data about Apollo documentors.');
{ First, we demonstrate the standard use of WITH. }
WITH our_technical_writers, their_name DO
BEGIN
write('Enter the first name of the writer -- ');
readln(first);
write('Enter the last name of the writer -- ');
readln(last);
write('Enter a brief description of his or her current project--');
readln(current_project);
END; {with}
writeln;
{ Next,we demonstrate the Domain Pascal extensions to WITH.
}
{ Use of the identifiers Wand E permits a distinction between}
{ the records inside the scope of the WITH statement.
}
WITH our_technical_writers
W, our_editors : E DO
BEGIN
write('Enter the first name of the editor -- ');
readln(E.their_name.first);
write('Enter the last name of the editor -- ');
readln(E.their_name.last);
E.current_project := W.current_project;
END;
END.

USING THIS EXAMPLE
This program is available online and is named with_example.

4-214

Code

Write, Writeln

Write, Writeln Writes the specified information to the specified file (or to the screen).

FORMAT
write(f, expJ :field_width,

... , expN : field_width)
{write and writeln are procedures.}

and
writeln(f, expJ :field_width, ... , expN : field_width)

ARGUMENTS

f

A variable having either the text or file data type. F is optional. If you
do not specify f, Domain Pascal writes to standard output (output) which
is usually the transcript pad. (Note that output has a text data type.)

exp

One or more expressions separated by commas. An expression can be
any of the following:
•

A string constant

•

An integer, real, double, char, Boolean, or enumerated
expression

•

An element of an array (assuming the element is one of the
previous types listed)

•

The name of an array variable whose base type is char

Note that exp cannot be a set variable.
An integer expression that specifies the number of characters that write
or writeln uses to output the value of this argo Field_width is optional. Its
effect depends on the data type of the exp to which it applies. (We detail
these effects in the next section.) Note that you can specify field_width
only if the f has the text data type.

DESCRIPTION
Write and writeln are output procedures. (Put is also. an output procedure; see the put
listing earlier in this encyclopedia.) Write and writeln both write the values of arguments

Code

4-215

Write, Writeln
expl through expN to the file specified by f. At run time, Pascal writes the value of expJ
first, the value of exp2 second, and so on until expN.
Write and writeln are identical in syntax and effect except that writeln appends a newline
character after writing the exps but write does not. In addition, when using write, f can
have a file or text data type; however, when using writeln, f must have a text data type
only.
Before calling write or writeln to write to an external file, you must open the file for writing. Chapter 8 details this process. Note that you do not need to open the standard output
(output) file before writing to it.
Following the call to write, fA is totally undefined.
The following paragraphs explain the output rules that Domain Pascal uses to print the
value of an expo

Char Variables, Array of Char Variables,
Variable-Length Strings, and String Constants
The following list shows the default field_widths for char variables, array of char variables,
variable-length strings, and string constants:
•

If exp is a char variable, the default field_width is 1.

•

If exp is an array of char variable, the default field_width is the declared length

of the array. For example, if you declare an array named Oslo_array as

Oslo_array: array[1 .. 10] of char;
then the default field_width is 10.

4-216

Code

•

If exp is a variable-length string, the default field_width is the current length of
the string.

•

If exp is a string constant, the default field_width is the number of characters in
the string.

Write, Writeln
If you do specify a field_width, here's how write and writeln interpret it:

field_width

What Domain Pascal Does

= default

Writes a value with no leading or trailing blanks.

> default

Adds leading blanks.

< default

Truncates the excess characters at the end of
the array or string.

= -1

Truncates any trailing blanks in the array.
Standard Pascal issues an error if you specify a
negative field_width. (Negative values are legal
only for types char and string.)

For example, notice how the field_widths in the following writeln statements affect output.
(The first two lines of output form a column ruler to help you notice columns.)

Output

Domain Pascal statements

VAR
name
name_var
grade

array[l .. 20] of char;
varying [20] of char;
char;

BEGIN
name := 'Zonker Harris';
name_var := 'Zonker Harris';
grade : = 'F';
1

WRITELN(name, grade);
WRITELN(name_var, grade);
WRITELN(name:-1, grade);
WRITELN(name_var:-1, grade);
WRITELN(name:4, grade);
WRITELN(name_var:4, grade);
WRITELN(name:25, grade);
WRITELN(name_var:25, grade);

3

2

123456789012345678901234567890
Zonker Harris
F
Zonker HarrisF
zonker HarrisF
zonker HarrisF
ZonkF
ZonkF
zonker Harris
F
Zonker HarrisF

Integer Values
The default field_width for an integer value is 10 spaces. This default applies to integer,
integerl6, integer32, and subrange variables, and to elements of an array that have one

Code

4-217

Write, Writeln
of these types as a base type. It also applies to record fields that have one of the aforementioned types.
If you specify a field_width greater than the number of digits in the integer value, Domain

Pascal prints the value with leading blanks.
If you specify a field_width less than or equal to the number of digits in the integer value,
Domain Pascal writes the value without leading or trailing blanks. Note that specifying a
field_width never causes Domain Pascal to truncate the written value.

For example, consider an integer16 variable named small_int with a value of 452 and an
integer32 variable named large_int with a value of 70,600,100. Notice how the
field_widths in the following writeln statements affect output. (The first two lines of output
form a column ruler to help you notice columns.)

Domain Pascal statements

WRITELN(Small_int);
WRITELN(large_int);
WRITELN(Small_int:S);
WRITELN(Small_int:1);

Output
123
123456789012345678901234567890
452
70600100
452
452

Real Values
For real exp you can supply no field_width, a one-part field_width, or a two-part
field_width with a colon separating the two parts. Here are the rules:
•

If you don't supply a field_width, Domain Pascal uses 13 spaces to write a single-

precision value and 22 spaces to write a double-precision value.
•

If you supply a one-part field_width, Domain Pascal adds or removes digits from
the fractional part.

•

If you supply a two-part field_width, Domain Pascal interprets the first part of the
field_width as the total number of characters to print and the second part of the
field_width as the number of digits to print following the decimal point. Note that
the second part of the field_width has priority over the first part. For instance.
suppose that you request a total width (the first part) of 5 characters and a frac~
tional width (the second part) of 7 characters. Since Domain Pascal cannot satisfy
both parts, it will satisfy only the second part.

If you don't supply a two-part field_width, Domain Pascal always leaves one leading space
for positive numbers; none for negative numbers.

4-218

Code

Write, Writeln
If there is not enough room for all the digits in the number, Domain Pascal rounds the
value rather than truncating it.

For example, suppose that a single-precision real variable named velocity has a value of
43.54893. The following table shows how various writeln statements affect output. (The
first two lines of output form a column ruler to help you notice columns.)

Domain Pascal statements

Output

123
123456789012345678901234567890
WRITELN(velocity);
WRITELN(velocity:20);
WRITELN(velocity:1);
WRITELN(velocity:15:4);
WRITELN(velocity:7:4);
WRITELN(velocity:7:2);
WRITELN(velocity:3:0);
WRITELN(velocity:1:5);

4.354893E+01
4. 3548930000000E+01
4.4E+01
43.5489
43.5489
43.55
44.
43.54893

Enumerated and Boolean Values
Domain Pascal keeps the same rules for writing enumerated and Boolean values. For both
types, the default field_width is 15. Here's what happens if you specify your own
field_width:
•

If you specify a field_width less than 15, Domain Pascal subtracts a suitable number of leading blanks.

•

If you specify a field_width greater than 15, Domain Pascal adds a suitable num-

ber of leading blanks.
Note that Domain Pascal never truncates any of the characters in the value (even if the
field_width is less than the number of characters).

Code

4-219

Write, Writeln
The following example shows how various field_widths affect output. (The first two lines of
output form a column ruler to help you notice columns.)

Domain Pascal statements
VAR
colors
evil

Output

(red, brown, magenta);
boolean;
1

2

3

123456789012345678901234567890
BEGIN
colors := brown;
WRITELN(colors);
WRITELN(colors:8);
WRITELN(colors:1);
evil := true;
WRITELN(evil);
WRITELN(evil:2);

BROWN
BROWN
BROWN
TRUE
TRUE

EXAMPLE

PROGRAM write_example;
{ This example reads one input line from the keyboard and writes it to }
{ filename 'truth'. Then it writes a message to the display.
}
CONST
pathname
'truth';
VAR
a_line
string;
wisdom
text;
statint
integer32;
BEGIN
open (wisdom, pathname, 'NEW', statint);
if statint <> 0
then return
else rewrite(wisdom);
WRITE('Enter a sentence of truth -- ');
readln(a_line);
WRITELN(wisdom, a_line);
close (wisdom) ;
WRITELN(chr(10) , chr(lO) , chr(9), 'Thank You', chr(7»;
{ ASCII 10 is a line feed. ASCII 9 is a tab. ASCII 7 is the bell. }
END.
USING THIS EXAMPLE
This program is available online and is named write_example.

4-220

Code

Xor

Xor Returns the exclusive or of two integers. (Extension)

FORMAT
{xor is a function.}

xor(intl, int2)

ARGUMENTS

intI, int2

Integer expressions.

FUNCTION RETURNS
The xor function returns an integer value.

DESCRIPTION
Use the xor function to take the bitwise exclusive or of int] and int2. The xor function
belongs to the bitwise class consisting of &, !, and -, and does not belong to the Boolean
operator class consisting of and, or, and not. When matching bits for an xor function,
Domain Pascal uses the following truth table:

Table 4-14. Truth Table for xor Function
bit x
of opl

bit x
of op2

0
0
1
1

0
1
0
1

bit x of
result
0
1
1
0

Code

4-221

Xor

EXAMPLE

PROGRAM xor_example;
{This program finds the exclusive or of two integers by using XOR. }
VAR

i1, i2, result

integer16;

BEGIN
write('Enter an integer -- '); readln(i1);
write('Enter another integer
'); readln(i2);
result := XOR(i1, i2);
writeln('The exclusive or of' i1:1,' and', i2:1, ' is
result: 1);
END.

USING THIS EXAMPLE
Following is a sample run of the program named xor_example:

Enter an integer -- 6
Enter another integer -- 20
The exclusive or of 6 and 20 is 18

-------88-------

4-222

Code

Chapter 5
Procedures and Functions

This chapter explains how to declare and call procedures and functions. The term routine, which appears throughout this chapter, means either procedure or function. The
terms parameter and argument also appear throughout this chapter. In this case, argument means the data passed to a routine, while parameter means the templates for the
data that the called routine receives. (Another term for argument is actual parameter;
another term for parameter is formal parameter.)
Chapter 2 mentioned that routine headings take the following format:

[ attribute_list] procedure name [(parameter_list) ]; [routine_options;]
or

[ attribute_list] function name [(parameter_liSt)] : typename; [ routine_options;]
This chapter details the parameter_list, routine_options, and attribute list.

5.1 Parameter List
You can declare a routine with or without parameters. If you declare it without parameters,
you cannot pass any arguments to the routine. If you declare it with parameters, you must
specify the data type of each argument that can be passed to the routine.
You specify parameters within a parameter list. You can specify a maximum of 65 parameters within the list. A parameter list has the following format:

typenamel;

. .. ,

Procedures and Functions

5-1

The param_type (or mode) is optional; for information, see the "Parameter Types" section
later in this chapter.
A par_list consists of one or more parameters that have the same data type. Thus, the
combination
par_list : typename

is similar to a variable declaration. Like a variable declaration, each parameter in par_list
must be a valid identifier. Also, each data type must be a predeclared Domain Pascal or
user-defined data type. That is, you cannot specify an anonymous data type. (See the
"Var Declaration Part" section in Chapter 2 for more information on anonymous data
types.)
You can use a parameter in the action part of the routine just as you would use any variable. Consider the following sample routine declarations:
{ Declare a procedure with no parameter list. }
Procedure simple;
{ Declare a procedure with a parameter list that has two parameters. }
Procedure con(a
integer;
b : real);
{ Declare a function with a parameter list that has two parameters }
{ sharing the same data type. }
Function anger(x,y : boolean) : integer16;
{ Declare a function with a parameter list that has three parameters. }
Function big(quart
integer16;
volume
real;
cost
single): single;
The following routine declaration is wrong because it uses an anonymous data type:
Procedure range(small_range : O.. 10);

5-2

Procedures and Functions

{WRONG! }

To call a routine, simply specify its name. If the procedure. has a parameter list, you must
also specify arguments. The data type of each argument must match the data type of its
corresponding parameter. For example, if the second parameter is declared as integer16,
the second argument must be an integer16 value. The following examples call the routines
that were previously declared:

{ Call simple with no arguments. }
simple;
{ Call con with two arguments. The first argument must be an integer, }
{ and the second argument must be a real number. }
con(14, 5.2);

{ Call anger with two Boolean arguments. Variable answer must have
{ been declared as an integer.
answer := anger (true , false);

}
}

{ Call big with three arguments. Assume that pints is an integer and
{ price is a real (single) number.
if big(pints * 2, 4.23E3, price) > 1.40
then ...

}
}

Domain Pascal supports many features that let you specify precisely how a routine is to be
called. The remainder of this chapter describes these features in detail after first describing
argument passing conventions.

5.2 Argument Passing Conventions
A program or procedure can pass arguments to another procedure by value (the actual
value of the argument) or by reference (the address of the argument). By default, Pascal
passes all arguments of externally called routines by reference regardless of the parameter
type. However, you can pass arguments by value rather than by reference if you use the
val_param option in the procedure or function heading. In addition, the c_param routine
option tells the compiler to return function results in register DO (on 680xO workstations),
and to pass all record data types by value rather than by reference. This facilitates crosslanguage calling with C and FORTRAN. (For more information on val_param, see Section 5.5.7. For more information on c_param, see Section 5.5.12.)

Procedures and Functions

5-3

In an external call, even arguments with call-by-value semantics (which is the default) are
actually passed by reference. For example, consider the following code fragment:

PROCEDURE dump (size: integer);

IF size> maxsize THEN size .- maxsize;

Pascal semantics require that the change to size not affect the value of the caller's argument. The code that the Pascal compiler generates for this call takes care of this, by making a local copy of the argument that can be modified.
Internal routines can be called only within the same compilation unit in which they are
defined. Since the compiler knows all the calls to the routine, it can optimize argument
passing without regard to the argument passing conventions. Currently, however, internal
routines are treated the same as val_param routines.
Table 5-1 summarizes Domain Pascal argument passing conventions.
NOTE:

All character arrays are treated like arguments with fewer than
four bytes, regardless of their size.
Double-precision reals on Series 10000 workstations are treated
like arguments with four bytes or fewer.

5-4

Procedures and Functions

Table 5-1. Argument Passing Conventions

Modifiers
Mode
IN

Default Caller

Default Callee

Arguments> 4 bytes

Arguments <= 4 bytes

Passes
addresses of
arguments.

Makes indirect
references to
arguments.

val.J>aram: No effect

val_param or internal:
Causes the caller to pass
the value of the argument and the callee to
make direct references
to it.

internal: No effect
UNIV: No effect

UNIV: Cancels the
effect of var_param
and internal.
IN OUT
V AR

No
mode

Passes
addresses of
arguments.

Passes
addresses of
arguments.

Makes indirect
references to
arguments.

Creates local
copies of
arguments and
makes direct
references to
them.

val param: No effect

val_param: No effect

internal: No effect

internal: No effect

UNIV: No effect

UNIV: No effect

val param: No effect

val param or internal:
CaUSes the caller to pass
the value of the argument and the callee to
make direct references
to it.

internal: No effect
UNIV: No effect,
but considered bad
programming
practice. Since the
callee does not know
the type of the
incoming argument,
it makes a local copy
as described by the
parameter.

UNIV: Cancels the
effect of val param
and internal:"
Considered bad
programming practice.
Since the callee has no
idea of the incoming
argument's type, it
makes a local copy as
described by the
parameter.

5.3 Parameter Types
A param_type (or mode) is optional. If you do not include one, you are in effect passing
a value parameter. Value parameters are discussed in this section. If you want to specify a
param_type, it must be one of the following:

•

var (a variable parameter)

•

in

Procedures and Functions

5-5

•

out

•

in out

The following subsections describe each of these.

5.3.1 Variable Parameters and Value Parameters
In standard Pascal, you pass arguments to and from routines as variable parameters or
value parameters. Domain Pascal supports both methods plus certain extensions described
later in this subsection. The following examples illustrate the distinction between variable
parameters and value parameters.
Pascal regards variable parameters as synonyms for the variable you pass to them. In
Figure 5-1, a program named var_parameter_example, variable parameter y becomes a
synonym for argument x; that is, whatever happens to y in addc happens also to x (and
vice versa). You must pass a variable as an argument to a variable parameter. You cannot
pass a value.
Pascal does not regard value parameters as synonyms to the arguments you pass to them.
In Figure 5-2, a program named value_parameter_example, value parameter y takes on
a copy of the value of x within addc; therefore, whatever happens to y in addc has no
effect on the value of x. Note that you can pass variables, values, or expressions as arguments to a routine with value parameters.
Both sample programs are available online.

{**********************************************************************}
PROGRAM var_parameter_example;
{ Compare this program to value_parameter_example. }
VAR

x : integer16;
PROCEDURE ad de (VAR y
integer16); { y is a variable parameter. }
BEGIN
Y := Y + 100;
writeln('In adde, y=',y:4);
END;
BEGIN

x := +10;
adde(x);
writeln('In main, x=',x:4);
END.

{**********************************************************************}
Figure 5-1. Program Illustrating Variable Parameters: var_parameter_example

5-6

Procedures and Functions

{**********************************************************************}
PROGRAM value_parameter_example;
{ Compare this program to var_parameter_example. }
VAR

x : integer16;
PROCEDURE addc(y
integer16); { y is a value parameter. }
BEGIN
Y := Y + 100;
writeln('In addc, y=',y:4);

END;
BEGIN
x := +10;
addc(x);
writeln('In main, x=',x:4);

END.
{**********************************************************************}
Figure 5-2. Program Illustrating Value Parameters: value_parameter_example
The results of the sample programs in Figure 5-1 and Figure 5-2 are shown below.
Execution of
var_parameter_example
In addc, y= 110
In main, x= 110

Execution of
value_parameter_example
In addc, y= 110
In main, X= 10

The only difference between the two programs is the keyword var in the procedure declaration statement of varyarameter_example. This keyword identifies y as a variable parameter; the absence of var identifies y as a value parameter.

5.3.2 In, Out, and In Out-Extension
In standard Pascal, you cannot specify the direction of parameter passing. However, Domain Pascal supports extensions to overcome this problem. You can use the following keywords in your routine declaration:
•

In-This keyword tells the compiler that you are going to pass a value to this parameter, and that the routine is not allowed to alter its value. If the called routine does attempt to change its value (that is, use the parameter on the left side of
an assignment statement), the compiler issues an "Assignment to IN argument"
error.

•

Out-This keyword tells the compiler that you are not going to pass a value to the
parameter, but that you expect the routine to assign a value to the parameter. It is
incorrect to try to use the parameter before the routine has assigned a value to it,
although the compiler does not issue a warning or error in this case.

Procedures and Functions

5-7

If the called routine does not attempt to assign a value to the parameter the comt

piler may issue a "Variable was not initialized before this use" warning. This could
occur if your routine assigns a value to the parameter only under certain conditions. If that is the case, you should designate the parameter as var instead of
out.
In some cases, the compiler cannot determine whether or not· all paths leading to
an out parameter assign a value to it. If that happens, the compiler does not issue
a warning message.
•

In out-This keyword tells the compiler that you are going to pass a value to the
parameter, and that the called routine is permitted to modify this value. It is incorrect to call the routine before assigning a value to the parameter, although the
compiler does not issue a warning or error in this case. The compiler also doesn't
complain if the called routine does not attempt to modify this value.

For example, consider the program shown in Figure 5-3, which is also available online.

5-8

Procedures and Functions

{**********************************************************************}
PROGRAM in_out_example;
{This program demonstrates the IN, OUT, and IN OUT parameters.}
VAR

leg1, leg2
: integer16;
hypotenuse
single;
temp
real;
unit : char;
PROCEDURE pythagoras(IN
leg1
integer16;
leg2
IN
integer16;
single);
OUT hypotenuse
BEGIN
hypotenuse .- sqrt«leg1 * leg1) + (leg2 * leg2»;
END;
FUNCTION boiling(IN
IN
BEGIN
if uni t
'F'
then temp :=
if temp >= 100
then boiling
else boiling :=
END;

OUT

temp
unit

(temp - 32)

real;
char)

boolean;

* 0.55555;

:= true
false;

BEGIN
write('Enter the length of a leg of a right triangle --');
readln(leg1);
write('Enter the length of the other leg --'); readln(leg2);
pythagoras(leg1, leg2, hypotenuse);
writeln('Hypotenuse of the triangle is " hypotenuse);
writeln(chr(10), chr(10) , 'Assume 1 Atm. pressure');
write('Enter the water temperature --'); readln(temp);
write('Is this temp. in Fahrenheit or Celsius (F or C) -- ');
readln(unit);
if boiling(temp, unit)
then writeln(temp:5:1, ' degrees C water will boil!')
else writeln(temp:5:1, ' degrees C water will not boil.');
END.
{**********************************************************************}
Figure 5-3. Program Illustrating in, out, and in out Value Passing: in_out_example
NOTE:

The compiler checks for misuses of in, out, and in out at compile
time, but the system does not check for such errors at run time.

Procedures and Functions

5-9

5.3.3 Univ-Universal Parameter Specification-Extension
U niv is a special parameter type that you specify immediately prior to the typename (rather
than prior to the par_list). You use univ to pass an argument that has a different data
type than its corresponding parameter.
By default, Domain Pascal checks that the argument you pass to a routine has the same
data type as the parameter you defined for the routine. However, you can tell Domain
Pascal to suppress this type checking by using the keyword univ prior to a type name in a
parameter list.
Univ is especially useful for passing arrays. For example, the following program would be
incorrect without the keyword univ. That's because little_array and big_array have different data types:
TYPE

array[l .. 50] of integer32;
VAR

large_array
medium_array
little_array
sum

array[l .. 50] of integer32;
array[l .. 25] of integer32;
array[l .. 10] of integer32;
integer32;

Procedure sum_elements(in
b
in array_size
out
sum
BEGIN

UNIV big_array;
integer16;
integer32) ;

END;
BEGIN {main}
sum_elements (little_array, 10, sum);
END.
In addition to the procedure call listed above, you could also make either of the following
calls to procedure sum_elements:

sum_elements (medium_array, 25, sum);
or

sum_elements (large_array, 50, sum);
Use univ carefully I It can cause problems if improperly used. The most frequent source Of
trouble is a difference in size between the argument and parameter data types. The data
type of the parameter determines how the called routine treats the data passed to it. Typically, routines that use univ parameters have another parameter that supplies additional
information about the size or type of the argument. In the preceding example, the array_size parameter gives the size of the array parameter passed. In addition, you should

5-10

Procedures and Functions

not pass an argument that is larger than the parameter. If you do, your program may produce unexpected results. The following example shows this misuse of univ:

Program univ_example;

{POOR USE OF UNIV!!!}

{This example demonstrates poor use of UNIV.}
{The program uses UNIV to pass two double-precision arguments to two}
{single-precision parameters. The calculation of 'mean' will not be}
{correct because single- and double-precision real numbers have
}
{different bit patterns for exponent and mantissa. Furthermore,
}
{the compiler will not warn you about this problem.
}
VAR

first_value, second_value : double;
Procedure average(s,t

UNIV single);

VAR

mean
double;
BEGIN
mean := (s + t) / 2.0;
writeln('The average is
END;

,mean);

BEGIN {main}
write('Enter the first value --'); readln(first_value);
write('Enter the second value --'); readln(second_value);
average (first_value , second_value);
END.
NOTE:

To prevent some problems that result from suppressing type
checking, explicitly declare univ parameters as in, out, in out, or
var.

When you pass an expression argument (as opposed to a variable argument) to a univ parameter, Domain Pascal extends the expression to be the same size as the univ parameter.
o In addition, the compiler issues the following message:

Expression passed to UNIV formal NAME was converted to NEWTYPE.

5.3.4 Pointers to Routines-Extension
As noted in Chapter 3, Domain Pascal supports a special pointer data type that points to
a procedure or a function. You can use these routine pointers in combination with the
addr function to pass addresses of routines as parameters.
For example, the sample program in Figure 5-4, which is also available online, returns the
square of the number provided by the user. It is a simple illustration of the use of a routine pointer as a parameter. Note that the square function must be in an external module. You cannot obtain the addresses of internal routines. See the "Procedure and
Function Pointer Data Types-Extension" section of Chapter 3 for more details about declaring routine· pointers.

Procedures and Functions

5-11

{**********************************************************************}
PROGRAM pass routine ptrs;
{ This program prompts the user for a number and returns the square
}
}
{ of the number. The procedure write_square uses a routine pointer
{ to call the external function square. To run the pass_routine_ptrs }
}
{ program you must compile the square.pas module and then bind
{ together square. bin and pass_routine-ptrs.bin.
}
TYPE
func_ptr

AFUNCTION (x:integer) : integer;
{declaration of routine pointer}

VAR

number: integer;
FUNCTION square (x:integer):integer; EXTERN;
PROCEDURE write_square(a_ptr:func_ptr; y:integer);
BEGIN
writeln('The square of the number is ',a_ptrA(y»;
END;
BEGIN
write('What number would you like to square?
readln(number);
write_square (addr(square) , number);
END.

');

MODULE square;
{This function is called by the pass_routine_ptrs program}
FUNCTION square (x:integer):integer;
BEGIN
square := x*x;
END;
{**********************************************************************}
Figure 5-4. Program and Module Illustrating Pointers to Routines: pass_routine_ptrs
and square

Here is a sample run of the compiled and bound pass_routine_ptrs program:
What number would you like to square? 25
The square of the number is
625

5-12

Procedures and Functions

5.3.4.1 Data Type Checking
The compiler checks pointers to routines for data type name compatibility when addresses
are assigned to a pointer or procedure. For example, assume you use the statements
shown below to declare a data type, a pointer to a routine, and a procedure named foo:

TYPE
pinteger

0 ... 65535;

VAR

pptr: APROCEDURE (r: pinteger);
PROCEDURE faa (r: integer);
The type pinteger is defined as a subrange of base type integer. The pointer pptr points
to a procedure that takes one parameter of type pinteger. The procedure foo, however,
takes one parameter of type integer. Even though pinteger and integer are both 16-bit
integers, the following assignment statement causes an error because integer and pinteger
are not name compatible (that is, they do not have the same name):

pptr := addr(foo);

5.4 Procedures and Functions as Parameters
Any procedure or function can be a parameter for any other procedure or function. Procedure and function parameters must appear in the parameter list. If the function or procedure being passed has parameters, these parameters must also appear in the declaration.
For example:

PROCEDURE caller (PROCEDURE callee (A, B : integer) );
Function parameters must specify the type they return, for example:

PROCEDURE caller (FUNCTION cal lee : integer);
A function or procedure that is a parameter may also contain functions or procedures as
parameters; for example:

PROCEDURE caller (FUNCTION A (PROCEDURE B) : integer);
You pass the name of a procedure or function just as you would any other parameter.
Only the name of the procedure or function is specified. Its parameter list, if any, does
not appear here. For example:

caller (callee);
The following example uses a procedure as a parameter.

Procedures and Functions

5-13

{**********************************************************************}
PROGRAM procedure as parameter;
{This program inv~kes a procedure that has another procedure as a
parameter.}
VAR

I : integer;
Procedure square;
BEGIN
I :== I * I;
END;
Procedure callproc (procedure A);
BEGIN
A;
{Invokes procedure A}
END;
BEGIN
I

{main program}
:== 3;

callproc(square);
writeln(I)

{procedure square is the parameter.}
{I == 9}

END.
{**********************************************************************}
The following example uses a function as a parameter.
{************************************************************************************}
PROGRAM function as parameter;
{This program in;ok~s a function that has another function as a
parameter.}

VAR
I, val: integer;
Function value : integer;
BEGIN
value :== 4;
END;

{Function value is 4.}

Function cube(Function a : integer) : integer;
BEGIN
{Cubes the function value.}
cube :== a * a * a
END;
BEGIN
I :== cube(value)
{Argument is Function value.}
writeln(value);
writeln(I);
{I == 64}
END.
{************************************************************************************}

5-14

Procedures and Functions

5.5 Routine Options
As mentioned in the beginning of this chapter, you can optionally specify routine_options
at the end of the routine declaration. Domain Pascal supports the following routine options:

•
•
•
•
•
•
•
•
•
•
•

forward
extern
internal
variable
abnormal
val_param
nosave
noreturn
dO_return
aO_return
c_param

5.5.1 Routine Option Syntax
Use the following format to specify any of the routine options:
options (routine_option 1 , . . . routine_optionN);
Here are some examples of this format:

FUNCTION

eggs_and_ham(letter: char) : char;

PROCEDURE sam_i_am(x.

y

:

real);

INTERNAL;

OPTIONS (EXTERN. ABNORMAL);

You can use the shorter format shown below only for the forward. extern, internal, and
val_param routine options:

routine _option 1 ; . . . routine _optionN;
Here are some examples of the shorter format:

FUNCTION

eggs_and_ham(letter: char) : char;

PROCEDURE sam_i_am(x.

y

:

real);

INTERNAL;

EXTERN; val_param;

The remainder of this section explains the routine options.

Procedures and Functions

5-15

5.5.2 forward
The forward option is a feature of standard Pascal and Domain Pascal. By default, you
can call only a routine that was previously declared in the program. The forward option
identifies the procedure prior to both its use (call) and its definition.
Figure 5-5 is a program named forward_example, which is available online. In this program, the procedure convert_degrees_to_radians is declared as forward. This allows procedure find_tangent to call procedure convert_degrees_to_radians even though
find_tangent precedes it in the file.

{**********************************************************************}
PROGRAM forward_example;
{This program demonstrates the FORWARD option}
Function convert_degrees_to_radians(d : real) : real; FORWARD;

VAR
degrees, tangent: real;
Procedure find_tangent(IN degrees
out tangent

real;
real);

VAR
radians : real;
BEGIN
radians .- convert_degrees_to_radians(degrees);
tangent:= sin(radians) / cos(radians);
END;
real)
real;
Function convert_degrees_to_radians(d
CONST
degrees~per_radian = 57.2958;
BEGIN
convert_degrees_to_radians .- (d / degrees_per_radian);
END;
BEGIN
write('Enter a value in degrees -- ');
readln(degrees);
find_tangent (degrees , tangent);
writeln('The tangent of " degrees:6:3, ' is "
END.

tangent:6:3);

{**********************************************************************}
Figure 5-5. Program Illustrating the forward Option: forward_example
If it were not for the forward option, the compiler would issue the following error:

CONVERT_DEGREES_TO_RADIANS has not been declared in routine FIND_TANGENT
Note that the program in Figure 5-5 declares function convert_degrees_to_radians and its
parameters in the declaration part of the main program and in the routine heading.

5-16

Procedures and Functions

Domain Pascal allows you to choose whether to include parameters in the routine heading.
Thus, you could substitute the following routine heading for the one shown above:
Function convert_degrees_to_radians;

{No parameters included here.}

In any case, you must include the forward option in the declaration part of the main program.

5.5.3 extern-Extension
Extern is an extension to standard Pascal. It tells the compiler that the routine is possibly
defined outside of this source code file. (The" Accessing a Variable Stored in Another
Pascal Module" and "Accessing a Routine Stored in Another Pascal Module" sections of
Chapter 7 detail extern. See also define, which is also detailed in the same sections of
Chapter 7.)

5.5.4 internal-Extension
Internal is an extension to standard Pascal. By default, all top-level routines defined in a
module become global symbols. But if you declare the routine with the internal option,
the compiler makes the routine a local symbol. (The" Accessing a Variable Stored in Another Pascal Module" and" Accessing a Routine Stored in Another Pascal Module" sections of Chapter 7 detail internal.) Declaring routines "internal" results in slightly more
efficient code and faster linking/loading.

5.5.5 variable-Extension
Variable is an extension to standard Pascal. By default, you must pass the same number
of arguments to a routine each time you call the routine. However, the variable option
allows you to pass a variable number of arguments to the routine. You may want to specify an argument count as the first parameter. There is one case in which you cannot use
the variable extension. You must supply an argument if the called routine makes a local
copy of any parameter. See Section 5.2 for more information on argument passing conventions.
Figure 5-6 is a sample program named variable_attribute_example that is available online. It illustrates the use of the variable option.

Procedures and Functions

5-17

I

{**********************************************************************}
PROGRAM variable_attribute_example;
{This program demonstrates the routine attribute called VARIABLE which}
{ allows you to pass a variable number of arguments to a routine.
}
VAR

first_value, second_value
precision : real;
answer : char;

real;

Procedure average(arg_count : integer16;
d1, d2
real;
p : real);
options(VARIABLE);
{We can pass up to four arguments.}
VAR
mean: real;
BEGIN
mean := (d1 + d2) / 2.0;
if arg_count = 3
then writeln('The mean is
mean:4:1, , to a precision of 0.1')
else if (arg_count = 4) and (p = 0.01)
then writeln('.The mean is , , mean:4:2, , to a precision of .01')
else if (arg_count = 4) and (p = 0.001)
then writeln('The mean is , , mean:4:3, , to a precision of .001' )
else
writeln('Improper argument count or precision');
END;

BEGIN {main}
writeln('This program calculates the mean of two real numbers.');
write('Enter the first value --'); readln(first_value);
write('Enter the second value --'); readln(second_value);
write('Do you want to specify a precision (enter y or n) --');
read In (answer) ;
if answer = 'y' then
begin
write('Please enter the precision (.01 or .001) --');
readln(precision);
average (4 , first_value, second_value, precision);
end
average (3 , first_value, second_value);
else
END.
{**********************************************************************}

Figure 5-6. Program Illustrating the variable Option: variable_attribute_example

5-18

Procedures and Functions

5.5.6 abnormal-Extension
Abnormal is an extension to standard Pascal. It warns the compiler that a routine can
cause an abnormal transfer of control. This option affects the way the compiler optimizes
the calling routine, but does not affect the way the compiler optimizes the called routine
(that is, the routine that is declared abnormal).
For example, the following use of abnormal causes the compiler to be careful about optimizing around any cleanup handler:

FUNCTION pfm_Scleanup (current_record: clean_up_record) :
status_ST; OPTIONS(ABNORMAL);

5.5.7 valj>aram-Extension
ValJJaram is an extension to standard Pascal. By default, Pascal passes arguments by reference. This means that Domain Pascal passes the address of the argument rather than the
value of the argument, regardless of the declared parameter type (in, out, in out, or var).
When you use the valJaram option in a procedure or function heading, you tell Domain
Pascal to pass arguments by value when possible. Under the val_param option, all arguments four bytes or less in size (on 680xO workstations) and 8-byte double-precision reals
on Series 10000 workstations (except for character arrays) are passed by value, provided
that they are declared as value parameters or as in parameters. All other arguments are
passed by reference. See Table 5-1 for a summary of the use of val_param with different
qualifiers.
This option produces more efficient calling sequences for Domain Pascal routines. However, when you are writing a routine that calls a Domain/C routine, you should use the
cJaram option. (See Section 5.5.12 for details about c_param.)
The following example illustrates a val_param option in a function declaration. The first
declaration uses the standard syntax. The second uses the shorter syntax:

FUNCTION pass_value (letter

char)

char;

OPTIONS (EXTERN, VAL_PARAM);

FUNCTION pass_value (letter

char)

char;

EXTERN; VAL_PARAM;

5.5.8 nos ave-Extension
Nosave is an extension to standard Pascal. You should use it with a Pascal program call to
an assembly language routine that doesn't follow the usual conventions for preserving these
registers:
•

Data registers D2 through D7

•

Address registers A2 through A4

•

Floating-point registers FP2. through FP7

Procedures and Functions

5-19

Nosave indicates that the contents of these registers will not be saved when the assembly
language routine finishes executing and returns to the Pascal program. However, the assembly language routine must always preserve register AS, which holds the pointer to the current stack area. It also must always preserve A6, which holds the address of the current
data area. That is, the called routine must preserve AS and A6 even if you use nosave.

5.5.9 noreturn-Extension
Noreturn is an extension to standard Pascal. This routine specifies an unconditional transfer of control; once a procedure or function with noreturn is called, control can never
return to the caller. The routine marked noreturn is executed, and the program terminates.
When you specify this keyword, the compiler may optimize the code it generates so that
any return sequence or stack adjustments after the call to the routine marked noreturn are
eliminated as being unreachable code.

5.5.10 dO_return-Extension
The dO_return option is an extension to standard Pascal. By default, a Pascal function
returning the value of a pointer puts that value in address register AO. When you use the
dO_return option, the compiler does the following:
•

Puts the value of the returned pointer in AO and also in data register DO.

•

Causes routines that call a function marked dO_return to expect the value of the
returned pointer variable to be in DO.

You should use dO_return in the heading for Pascal functions that call external C or FORTRAN routines because C and FORTRAN return function results in DO.
For example, consider the following routine heading:

function string_c : string_ptr; options (extern,dO_return);
The preceding declaration tells the compiler to expect the string_ptr type value returned
by string_c to be in register DO.
NOTE:

The second character in this option is a zero, not a capital O.

5.5.11 aO_return-Extension
The aO_return option is an extension to standard Pascal. It is allowed on any function
signature. If you specify aO_return for a Pascal routine, the compiler does the following:
•

Puts into AO any values returned from that routine that should go into a register.

•

Looks in AO for any values returned to a caller of that routine.
NOTE:

5-20

The second character in this option is a zero, not a capital O.

Procedures and Functions

5.5.12 cj)aram-Extension
The cyaram option is an extension to standard Pascal. Specifying c_param is equivalent
to specifying dO_return and valyaram. In addition, the cyaram option tells the compiler to pass all record data types by value rather than by reference. For an example of
this option, see Section 7.9.5.
Any Pascal procedure that calls or is called by a C program must use the c_param option
to pass by value any single-precision or double-precision floating-point, record or struct,
simple datum, or pointer.
The following example illustrates the use of a c_param optionin a function declaration:

FUNCTION c_function (letter: char) : char;
NOTE:

OPTIONS (EXTERN , C_PARAM);

Using the c_param option does not guarantee that the size of
arguments passed by value from a Domain Pascal routine will
match the size of arguments in the Domain/C called routine. For
example, when you pass Domain Pascal integer, integerl6, char
values to Domain/C, the compiler does not widen them to 32 bits
as Domain/C does. Similarly, when you pass Domain Pascal real
values, the compiler does not widen them to 64 bits. Thus, if you
use c_param, you must make sure that you declare the parameters that you pass from Domain Pascal to Domain/C to be the
correct size.

5.6 Defining Your Own Routine Options
In addition to the predeclared routine options, Domain Pascal supports a routine_option
declaration part that allows you to define your own names for groups of routine options.
Furthermore, Domain Pascal provides a special name-default_routine_options-that allows you to define the default routine options for every routine in a module. We describe
both of these features in this section.

5.6.1 Syntax of the routine_option Declaration Part
The syntax for the routine_option declaration part is as follows:
routine_option
identifier 1 = routine_option_name 1

[. routine_option_name2 • ...• routine_option_nameN]:
[ identi/ierN

= routine_option_namel

[. routine_option_name2 • ...• routine_OPtion_nameN]:]

Procedures and Functions

5-21

I

An identifier is any valid Domain Pascal identifier. A routine_option~name is the identifier
of a routine option that you created earlier in the routine option declaration part or any
of the following predeclared Domain Pascal routine options:

noreturn

abnormal

c-param

val-param

variable

The following routine options cannot appear in a routine_option declaration part:
extern

forward

internal

5.6.2 Examples of the routine_option Declaration Part
Here's a sample routine_option declaration part along with a corresponding routine heading:

ROUTINE_OPTION
my_C_routine_options

aO_return, dO_return, c_param;

The above declaration tells the compiler to handle the procedure calling_a_C_module as
if it specified aO_return, dO_return, and c_param in its routine heading.

5.6.3 Rules for Using the routine_option Declaration Part
You can use routine options that you define in a routine_option declaration part in any
context that you can use the predeclared routine options included in the definition.

5.6.4 Using default_routine_options
You can use the special name default_routine_options for the list of options that you declare in a routine_option declaration part. If you do so, then the options that you define
in your list are used as the default routine options for every subsequent routine in that
module that does not specify a routine option. The rules for the scope of default_routine_options are the same rules that Domain Pascal follows for the scope of variables.

5-22

Procedures and Functions

For example, consider the following fragment:

ROUTINE_OPTION
default_routine_options
PROCEDURE fee;
PROCEDURE fie;
PROCEDURE foe;
PROCEDURE fum;
The preceding declarations tell the compiler to handle the procedures fee, fie, foe, and
fum as if each one specified aO_return, dO_return, and val_param as routine options in
its routine heading. In other words, they have the same effect as:

PROCEDURE fee; OPTIONS (aO_return, dO_return, val_param);
PROCEDURE fie; OPTIONS (aO_return, dO_return, val_param);
PROCEDURE foe; OPTIONS (aO_return, dO_return, val_param);
PROCEDURE fum; OPTIONS (aO_return, dO_return, val_param);
You can override the default_routine_options for any routine by specifying different routine options for that particular routine. The override does not affect the other routines.
Continuing the previous example, assume you have defined default_routine_options as
listed previously for a module that contains the fee, fie, foe, and fum procedures.

Procedures and Functions

5-23

However, you do not want to apply all of the default_routine_options to the foe procedure. You can change the routine heading for foe as follows:

ROUTINE_OPTION
default_routine_options
PROCEDURE fee
PROCEDURE fie;
PROCEDURE foe; OPTIONS (abnormal)
PROCEDURE fum;
The above set of declarations tells the compiler to handle the foe procedure as if it specified just one routine option-namely, the abnormal option.

5.7 Attribute List-Extension
As noted in the beginning of this chapter, you can declare an optional routine attribute_list at the beginning of a routine heading. With this list, you can specify a nondefault
section name for the code and data of a routine. The attribute_list affects a routine body,
while the routine_options affect the routine interface.
The attribute_list consists of one or more routine attributes enclosed by brackets. Domain
Pascal currently supports the section routine attribute.

5.7.1 Section-Extension
By using the routine attribute section, you can specify a nondefault section name for the
code and data in a routine. A "section" is a named contiguous area of an executing object. (See the Domain/OS Programming Environment Reference for details on sections.)
By default, the compiler assigns code to the . text section and data to the . data section.
Thus, by default, all code from every routine in the program is assigned to . text, and all
static data from every routine in the program is assigned to .data. However, Domain Pascal permits you to override the default of .text and .data on a routine-by-routine basis.
(You can also override the defaults on a variable-by-variable or module-by-module basis.)
You can use the section routine attribute to organize the run-time placement of routines
so that logically related routines can share the same page of main memory and thus reduce
page faults. Likewise, you can declare a rarely called routine as being in a separate section
from the frequently called routines.

5-24

Procedures and Functions

To override the default sections, preface your routine heading with a phrase of the following format:
[section ( codesect, datasect )] procedure . . .
or
[section ( codesect, datasect )] function .
To specify an alternate data section while keeping the default . text section, use the following syntax:
[section ( , datasect )] procedure . . .
or
[section ( , datasect )] function . . .
you omit either the codesect or the datasect, the present default continues to take effect.

If

For example, consider the following fragment:
Program example;
VAR stat: integer;
PROCEDURE top;
VAR datI : static integer;
BEGIN

{ In .data }
{ In . text }
{ In . data }
{ In .text }

END;
[SECTION (npc, npd) ] FUNCTION foobarl
VAR seed : static real;
BEGIN

REAL;

{ In "npc" }
{ In "npd" }

{ In "npc" }

END;
[SECTION (error_rout_c, error_rout_d)] PROCEDURE xxx; {In error_rout_c }
VAR check: static integer32;
{In error_rout_d }
BEGIN
END;
FUNCTION regular : integer;
VAR dat2 : static real;
BEGIN

{ In . text }
{ In .data }
{ In . text }

END;

Procedures and Functions

5-25

[SECTION (npc, npd)] PROCEDURE foobar2;
VAR seedling: static real;
BEGIN

{ In "npc"· }
{ In "npd" }
{ In "npc" }

END;
BEGIN {main}
{ In .text }
END;
Nested routines inherit the section definitions of their outer routine unless they specify
their own section definitions. For example, if the foobarl function contained nested routines, Domain Pascal defaults to placing their code and static data into the "npc" and
"npd" sections respectively.

5.8 Recursion
A recursive routine is a routine that calls itself. Domain Pascal, like standard Pascal, supports recursive routines. The following example demonstrates a recursive method for calculating factorials:

PROGRAM recursive_example;
{ Demonstrates recursion by calculating a factorial. }
VAR
x, y : integer32;
integer32)
integer32;
Function factorial(n
BEGIN
if n = 0
then factorial := 1
else factorial := n * factorial(n-l);
{factorial calls itself.}
END;
BEGIN {main}
writeln('This program finds the factorial of a specified integer.');
write('Enter a positive integer (from 0 to 16) --'); readln(x);
y := factorial(x);
writeln('The factorial of " x:l, ' is " y:l);
END.

----88----

5-26

Procedures and Functions

Chapter 6
Program Development

This chapter describes how to produce an executable object file (that is, a finished program) from Domain Pascal source code. There are three Domain environments in which
you can develop programs: Aegis, SysV, and BSD. Where the development process differs
from one environment to another, we describe each environment separately.

6.1 Program Development in a Domain Environment
Briefly, you create an executable object file using the following steps:
1. Compile each file of source code that constitutes the program. The compiler creates one object file for each file of source code.
2. Link (bind) the object files if necessary. Linking is necessary if your program
consists of more than one object file. The linker resolves external references; that
is, it connects the different object files so that they can communicate with one
another. Before linking, you may wish to package related object files into a library file with the UNIX archiver utility or the Aegis librarian.
3. Debug or execute the program.
Figure 6-1 illustrates the general program development process. As described in later sections, the details differ somewhat depending on whether you are developing programs in an
Aegis or UNIX environment.

Program Development

6-1

Begin

Edit

Compile
~---s-4

Find
errors

Execute
object
file

Yes

Errors

?

No
End

Figure 6-1. Program Development in a Domain System

This chapter details the compiler and provides brief overviews of the linker (binder), and
debugger utilities.
In addition to the traditional programming development scheme shown in Figure 6-1, you
can also use the Domain Software Engineering Environment (OSEE) system to develop
Pascal programs. This chapter also contains a brief description of Domain/Dialogue, a
product that simplifies the writing of user interfaces.

6-1

Program Development

Use the pas command to preprocess and compile a single source file (plus %included
files), and produce a single object file. If your program contains more than one object
file, you must link the object files together with the bind or Id command. These two commands perform similar operations: bind invokes the Aegis binder; Id is the UNIX link editor. You can use either command to link object modules together. Use the -b binder option to tell the binder to create one executable object file.
If your program accesses routines in a user-supplied library, you need to link your program

with the user-supplied library.

6.2 Compiler Variants
We have four different variants of the Domain Pascal compiler. The four variants differ in
the kind of machine they run on and the kind of machine for which they generate code.
The variants are
•

MC680xO native compiler

•

Series 10000 (PRISM) native compiler

•

MC680xO-to-PRISM cross compiler

•

P RISM-to-MC680xO cross compiler

You probably have two of these four variants installed on your system, but you may be
able to use the other two by means of links to other systems. To find out which variant of
the compiler you are using, use the -version option of the pas command. The following
codes indicate the variants:
68K

MC680xO native compiler

PRISM

Series 10000 (PRISM) native compiler

68K=>PRISM

MC680xO-to-PRISM cross compiler

PRISM=>68K

PRISM-to-MC680xO cross compiler

Where the compiler differs from one variant to another, we describe each variant separately; otherwise, you can assume that all four variants of the compiler behave the same.

Program Development

6-3

6.3

Compiling
You compile a Domain Pascal source code file in any Domain/OS environment by entering
the following command:

$ pas

souTce"'pathname [optionl ... optionN]

SourceJathname is the pathname of the source file you want to compile. You can compile only one source file at a time. In order to simplify your search for Pascal source programs, we recommend that sourceJathname end with a •pas suffix. If you use the suffix,
you need not specify it in the compile command line.
The compile command line can contain one or more of the options listed in Table 6-2.
Note that you cannot abbreviate these options.
For example, consider the following three sample compile command lines, all of which
compile source code file circles. pas:

$

pas circles

$

pas circles -I

$

pas circles -map -exp -cond -cpu 3000

6.3.1 Compiler Output
If there are no errors in the source code and the compilation proceeds normally, the com-

piler creates an object file in your current working directory.
The compiler names the files it creates according to the following rules:
•

If the source pathname ends with . pas, the compiler rep/aces that suffix with . bin.

•

If the source pathname does not end with . pas, then by default Domain Pascal

gives the object file the same pathname as the source pathname, but with the . bin
suffix.
•

If you want the object file to have a non-default name, use the -':b pathname

option.
Table 6-1 shows examples for each of these rules.

6-4

Program Development

Table 6-1. Sample Object File Names

Source Code

Command

Object File Name

Source code file
named with .pas
suffix

extratext. pas

$ pas extratest

extratest. bin

Source code file
named with other
suffix

test. first

$ pas test.first

test. first. bin

test

$ pas test
-b IIgood/compiIers/newtest

/ / good/compilers/newtest. bin

Source code file
named with no
suffix

or
$ pas extratest.pas

6.4 Compiler Options
Domain Pascal supports a variety of compiler options. Table 6-2 summarizes the options,
and the following sections describe all the options in detail.

Program Development

6-5

Table 6-2. Domain Pascal Compiler Options
Option

What It Causes the Compiler to Do

-ac

Produce absolute code. The compiler sets the load address at compile
time, and therefore your program runs faster. Default for MC680xO
compiler variants, invalid for Series 10000 compiler variants.

-pic

Produce position-independent code). The compiler uses relative
addressing for your data and sets the address at run time. Default for
Series 10000 compiler variants.

'*

-alnchk

Display messages about alignment of data structures. Default for
Series 10000 compiler variants.

'*

-b pathname

Generate a binary file in the current directory at
sourceJile_name.bin, or in another file at pathname.bin.

-nb

Suppress creation of binary file.

-bounds_violation

Allow referencing beyond the end of an array. Optimization of
code is less efficient.

-no_bounds_ violation

Do not allow referencing beyond the end of an array. This
option allows superior optimization of the code.

-comchk

Issue a warning if comments are not paired correctly.

-ncomchk

Suppress checking for paired comments.

-compress

Store the object file in compressed form.

-ncompress

Store the object file in noncompressed form.

-cond

Compile lines prefixed with the %debug compiler directive.

-ncond

Ignore lines prefixed with the %debug compiler directive.

-con fig varl ... varN

Set special conditional compilation variables to true.

-cpu id

Generate code for a particular workstation type. The id argument is
usually one of the following: mathlib_srlO, mathlib, or mathchip.
The default for MC680xO compilers is mathlib_srlO. The only valid
argument for Series 10000 compilers is a88k.

'*

'*
'*
'*

'* denotes a default option
(Continued)

6-6

Program Development

Table 6-2. Domain Pascal Compiler Options (Cont.)
Option
-ndb

* -db

What It Causes the Compiler to Do
Suppress creation of debugging information. The debugger cannot
debug such a program.
Generate minimal debugging information. When you debug this
program, you can set breakpoints, but you can't examine variables.

-dbs

Generate full debugging information and optimize the code in the
executable object file. (Implies -opt 3.)

-dba

Generate full debugging information but don't optimize the code
in the executable object file.

-exp

Generate assembly language listing (implies -I).

* -nexp
-frnd

* -nfrnd

Suppress creating assembly language listing.
Round floating-point numbers at key points during program
execution.
Optimize execution by computing floating-point expressions in
greater precision than that specified by the program, when the
compiler detects an opportunity to do so.

-idir dirl ... dirN

Search for an include file in alternate directories.

-imap

Generate symbol table maps for %included files (implies -map).

* -nimap
-indexl

* -nindexl
-info n

Suppress creation of symbol table maps for %included files
(implies -nmap).
Produce a 32-bit index for all array references.
Refer to source code for array reference index information.
Display information messages to the nth level. n is an optional
specifier that must be between 0 and 4. If n is omitted, or the entire
switch is omitted, display information messages to level 2.

-inlib pathname

Load pathname (a PIC binary file) at run time and resolve global
variable references. Thus you can use pathname as a library file for
many different programs.

-iso

Compile the program using ISO/ANSI Standard Pascal rules for
certain Domain Pascal features that deviate from the standard.

* -oiso
-I

pathname

* -01denotes a default option
*

Compile the program using Domain Pascal features.
Generate a listing file at program_name. 1st or pathname.lst.
Suppress creation of listing file.

(Continued)

Program Development

6-7

Table 6-2. Domain Pascal Compiler Options (Cont.)

Option

What It Causes the Compiler to Do

-map

* -nmap
-msgs
* -nmsgs
-natural

Generate symbol table map (implies -I).
Suppress creation of symbol table map.
Generate final error and warning count message.
Suppress creating final error and warning count message.
Set environment to natural alignment. Has the same effect
as the %natural_alignment compiler directive.

-nnatural

Suppress setting the environment to natural alignment.

-nclines

Suppress the generation of COFF line number tables so as to
save space in the object file. Valid option for MC680xO
compiler variants only.

* -opt

n

* -prasm

Cause the compiler to perform global program optimizations to
the nth level, where n is between 0 and 4. If n is omitted, or
if the option is omitted. the default optimization level is 3.
Create an expanded listing in Series 10000 assembly-code
format, if -exp is specified and if Series 10000 code is being
generated.

-nprasm

Create an expanded listing in alternate assembly-code format.

-sUb pathname

Treat the input as an include file and produce a precompiled
library of include files at program_name.plb or
pathname.plb.

-std

* -nstd
-subchk
* -nsubchk
-version

Issue warning messages when nonstandard language elements
are encountered.
Suppress warning messages for nonstandard elements.
Generate extra subscript checking code in the executable object
file. This code signals an error if a subscript is outside the
declared range for the array.
Suppress subscript checking.
Display version number of compiler. Note that you do not
include a filename when you use this option. The following
command line shows the usage of this option: pas -version

-warn
* -nwarn

Display warning messages.

* -xrs
-nxrs
* denotes a default option.

Save registers across a call to an external procedure or function.

6-8

Program Development

Suppress warning messages.

Do not assume that calls to external routines have saved the
registers.

6.4.1 -ac and -pic: Memory Addressing
The -ae option is the default on MC680xO systems. On Series 10000 systems, -pie is the
default, and -ae is an invalid option.

I

If you use the -ae option, Domain Pascal uses absolute code to compile your program.
This means that the compiler sets the load address for your data at compile time. As a
result, your program runs faster.
If you use the -pie option, then the compiler generates PIC (Position Independent Code).
This means that the compiler uses relative addressing and that the addresses are set at run
time, rather than at compile time. As a result, your program may be less efficient to run
than if you use the default -ae option.

Use the -pie option for compiling library files that you load with the -inlib option. Since
these files are used by many different programs, their addresses must be set at run time.
You should also use -pie for extensible streams and GPIO drivers.

6.4.2 -alnchk: Displaying Messages about Alignment

I

The -alnehk option is always set for the compiler variants that generate Series 10000
code.
When you use the -alnehk option, the compiler displays messages telling you whether your
data is naturally aligned. Naturally aligned data increases efficiency at least slightly on any
workstation, but the increase in efficiency is very significant on Series 10000 workstations.
See the "Internal Representation of Unpacked Records" and "Alignment-Extension" sections of Chapter 3 for more details about alignment.

6.4.3 -b and -nb: Binary Output
The -b option is the default.
If you use the -b option, and if your source code compiles with no errors, Domain Pascal
creates an object file with the source pathname and the . bin suffix. If you specify a pathname as an argument to -b, then Domain Pascal creates an object file at pathname.bin.
If you use the -nb option, Domain Pascal suppresses creating an object file. Consequently, compilation is faster than if you had used the -b option. Therefore, -nb can be
useful when you want to check your source code for grammatical errors, but you don't
want to execute it.

Program Development

6-9

Given that error-free Domain Pascal source code is stored in file test. pas, here are some
sample command lines:
$ pas test

{Domain Pascal creates test. bin}
pas test -b
{Domain Pascal creates test. bin}

%

$ pas test -b jest

{Domain Pascal creates jest. bin}
$ pas test -b jest. bin

{Domain Pascal creates jest. bin}
pas test -nb
{Domain Pascal doesn't create an object file}

%

6.4.4 -bounds_violation and -no_bounds_violation: Array Bounds Checking
The -bounds_violation option is the default.
If you use the -bounds_violation option, you are permitted to reference an element be-

yond the bounds of an array. For example, if you declared an array as:
a : ARRAY [0 .. 15] OF integer32;
you could assign a value to a[16]. However, you may destroy the values stored in other
variables by writing beyond the bounds of an array.
If you use the -no_bounds_violation option, you are not permitted to reference an ele-

ment beyond the bounds of an array. This option provides better optimization than the
default.
If the following example is compiled with the -bounds_violation option, it will print the
value 10. If it is compiled with -no_bounds_violation, it will print 0, but the program will

be better optimized.

6-10

Program Development

PROGRAM bounds_violation;
TYPE

boundless
a
i

RECORD
ARRAY [ 0 .. 9 ] OF INTEGER32;
: integer32;

END;
VAR
b
j

boundless;
integer;

BEGIN
b.i := 0;
FOR j : = 0 TO 10 DO
b.a[j] := j;
writeln(b. i);
END.

6.4.5 -comchk and -ncomchk: Comment Checking
The -ncomchk option is the default.
If you compile with -ncomchk, the compiler does not check to see if you've balanced your

comment delimiters. Consequently, if you forget to close an open comment, the compiler
will probably misinterpret a piece of code as part of a comment. If you compile with the
-ncomchk option, you get the default results.
If you compile with the -comchk option, the compiler checks to see that comment pairs

are balanced; that is, that there are no extra left comment delimiters before a right comment delimiter. The left comment delimiters are {, (*, and "; the right comment delimiters are }, *), and". If you compile with -comchk, the compiler returns a warning for
every additional left comment delimiter.
For example, the following fragment produces weird results because of an unclosed comment:
{This comment should be closed, but I forgot to do it!
x := 0;

{We need this statement.}

However, if you compile with -comchk, the compiler returns the following warning message:
Warning: Unbalanced comment; another comment start found
before end.
Note that -comchk causes the compiler to look only for the same kind of left comment
delimiter. For example, if you start the comment with (*, the compiler does not flag any
extra left brace { that occurs before the next *).

Program Development

6-11

6.4.6

~compress

and -ncompress: Object File Storage

The -compress option is the default.
The -compress option stores object file data in compressed form. The -ncompress option
stores the data in uncompressed form. Uncompressed data is an exact image of the data
as it will be loaded into memory. Compressed data contains instructions to the loader that
describe how to load the data into memory.
For example, consider an array of 100 bytes, all initialized to O. In uncompressed form,
this array occupies 100 bytes in the object file. In compressed form, it occupies only
enough space for a single .rwdi instruction: load 100 bytes with value O. (.rwdi stands
for "read-write data initialization.")
You may find the -ncompress option especially useful if you are linking modules with uncompressed data to modules with compressed data. In this case, the linker will expand the
compressed data. The linker output file then contains the uncompressed data from the
two modules and, in addition, the .rwdi instructions from the compressed module, creating
an output file that is larger than if both modules had stored the data in uncompressed
form.

6.4.7 -cond and -ncond: Conditional Compilation
The -ncond option is the default.
The -cond option invokes conditional compilation. If you compile with -cond, Domain
Pascal compiles the lines of source code marked with the %debug directive. (Refer to the
"Compiler Directives" listing in Chapter 4 for details on %debug.)
If you compile with -ncond, Domain Pascal treats the lines of source code marked with

%debug as comments.
You can simulate the action of this switch with the -config compiler option. For new program development, you should use the -con fig syntax, since the -cond option is considered obsolete.

6.4.8 -config: Conditional Processing
Use the -config option to set conditional variables to true. (Refer to the "Compiler Directives" listing of Chapter 4 for details on the conditional variables.)
You declare these conditional variables with the %var compiler directive. By default, their
value is false. You can set their value to true with the %enable directive (described in the
"Compiler Directives" listing) or with the -config option. The format of the -config option is
-config var1 [ ... varN]
where var must be a conditional variable declared with %var.

6-12

Program Development

For example, consider the program shown in Figure 6-2. The program is available online
and is named config_example.

{**********************************************************************}
PROGRAM config_example;
{ You can use this program to experiment with the }
{ -CONFIG compiler option. }
VAR
x, y, Z

integer16 .- 0;

BEGIN
writeln('The start of the program.');
%VAR first, second, third
%IF first %THEN
x := 5;
writeln(x,y,z);
%ENDIF
%IF second %THEN
y := 10;
writeln(x,y,z);
%ENDIF
%IF third %THEN
Z := 15;
writeln(x,y,z);
%ENDIF
writeln('The end of the program');
END.

{**********************************************************************}
Figure 6-2. A Program Illustrating Conditional Variables: config_example

Program Development

6-13

First, notice what happens when you compile without -config.
$ pas config_example

No errors, no warnings, Pascal Rev n.nn
$ config_example. bin·

The start of the program.
The end of the program
Now, use the -config option to set conditional variables first and third to true. Here's
what happens:
$ pas config_example -config first third

No errors, no warnings, Pascal Rev n.nn
$ config_example. bin

The start of the program.
5 0 0
o
5
15

The end of the program
To simulate the action of the -cond compiler switch, enclose the section of code you want
conditionally compiled in an %if config_variable %then structure. Then use -config to set
config_variable to true when you want to compile that section of code.

6.4.9 -cpu: Target Workstation Selection

I
I

The -cpu mathlib_srl0 option is the default if you are using a compiler variant that generates MC680xO code. The -cpu a88k option is the default if you are using a compiler
variant that generates Series 10000 code. For information about compiler variants, see
Section 6.2.
Use the -cpu option to select the target workstations that the compiled program can run
on. If you choose an appropriate target workstation, your program may run faster; however, if you choose an inappropriate target workstation, the run-time system will issue an
error message telling you that the program cannot execute on this workstation. The format
for the -cpu option is
-cpu id
You select the code generation mode through the argument that you specify immediately
after -cpu. Table 6-3 shows the possible arguments and the code generation mode that
each argument selects. For example, to compile prog. pas with the mathchip argument,
use the following command line:
pas prog. pas -cpu mathchip
The advantage of the processor-specific code generation modes is that the compiler generates code optimized for that particular processor, which makes the programs so compiled
run faster. The advantage is seen mostly in programs that make frequent use of floatingpoint operations. Programs that make heavy use of multiplication and division with 32-bit
integers may also show significant improvement. To find out how to obtain the best
floating-point performance on the new Domain MC68040-based workstations, refer to
Appendix F.

6-14

Program Development

The -cpu mathchip option generates the best possible code for the following Apollo workstations, each of which has an MC68020 or MC68030 microprocessor and an MC68881 or
MC68882 floating-point coprocessor:
HP Apollo 9000 Series 400 Model 400dl
HP Apollo 9000 Series 400 Model 400s
HP Apollo 9000 Series 400 Model 400t
DN4500
DN4000
DN3500
DN3000
DN2500
DN580
DN570
DN560
DN330
DSP90
The mathlib_srl0 and any arguments allow your code to run on a wider variety of platforms with some loss of performance. The default option for MC680xO-based workstations, -cpu mathlib_srl0, generates code that runs very well on all of the above workstations and on MC68040-based workstations. This option is the default if you are using a
compiler variant that generates MC680xO code.
Note that there are many possible arguments to -cpu; however, many of them generate
identical code. For example, -cpu mathchip produces exactly the same code as -cpu
570, -cpu 580, and -cpu 3000.

Program Development

6-15

I

Table 6-3. Arguments to the -cpu Option

Argument

* mathlib_srlO
* a88k

What the Argument Causes the Compiler To Do
Generates code for workstations with an MC68040 microprocessor, or with an
MC68020 or MC68030 microprocessor and an MC68881 or MC68882
floating-point coprocessor. Code compiled with this argument runs on
SR10.0 and later versions of Domain/OS. The -cpu mathlib_srlO option is
the default if you are using a compiler variant that generates MC680xO code.
Generates code for a Series 10000 workstation. The -cpu a88k option is the
default if you are using a compiler variant that generates Series 10000 code.

mathlib

Produces optimal code for workstations with an MC68040 microprocessor
(including the HP Apollo 9000 Series 400 Model 425t and 433s). Also generates code for workstations with an MC68020 or MC68030 microprocessor
and an MC68881 or MC68882 floating-point coprocessor. Code compiled
with this argument runs only on SR10.3 and later versions of Domain/OS.
Use mathlib_sr10 if your code must also run on SR10.0, SR10.1, or SR10.2.

mathchip
3000
580
570
560
330
90

Generates code for workstations with an MC68020 or MC68030 microprocessor and an MC68881 or MC68882 floating-point coprocessor. These seven
arguments generate identical code. We recommend that you use the mathchip argument; the other six arguments will become obsolete at a future compiler release. (Code compiled with mathchip will also run on the MC68040,
but not very well.)

160
460
660

Generates code for a DSP160, DN460, or DN660 workstation. These three
arguments generate identical code.

Cpal

Generates code for DN3000, DN4000, or DN4500 workstations with an FPA1
floating-point accelerator unit.

Cpx

Generates code for DN5xx workstations with an FPX floating-point
accelerator unit.

peb

Generates code for workstations with a Performance Enhancement Board
(PEB) (includes the DN100, DN320, DN400, and DN600, when equipped
with an optional PEB).

any

Generates Series 10000 code if you are using a compiler variant that
generates Series 10000 code; generates generic MC680xO code if you are
using a compiler variant that generates MC680xO code.

m68k

Generates code for any MC680xO-based workstation (same as any on all
workstations other than the Series 10000).

* denotes a default option
6-16

Program Development

Table 6-4 shows the relative performance of the MC680xO code generated with different
arguments to the -cpu option.

Table 6-4. Relative Performance with Different -cpu Arguments

Machine Type
100, 400

PEB

160,
460, 660

FPX

FPA1

--

--

--

fair

*

fair

good

mathlib

--

--

--

fair

*

good

best

mathchip

--

--

--

fair

*

best

fair

peb

--

best

--

--

--

--

--

160, 460, 660

--

--

best

--

--

--

--

fpx

--

--

--

best

--

--

--

fpa1

--

--

--

--

best

--

--

any

best

fair

poor

poor

poor

poor

fair

Argument

Legend:

MC68020/030,
MC68040
68881182

Code generated with this argument will not run on this machine type.
The compiler selects instructions that do not use the FPA 1 accelerator.
In this case, the code runs exactly the same as code generated for an
MC68020-based or MC68030-based machine.
best, good, fair, poor
These four terms are relative; they compare performance between
different -cpu arguments on one machine, not between machines.
For example, code that is fair for an MC68040-based machine runs
faster than the best code on an MC6820-based or MC68030-based
machine.

*

6.4.9.1 Choosing an Appropriate -cpu Argument: The cpuhelp Utility
The cpuhelp utility provides quick online information about which -cpu argument is appropriate for a particular machine or about which machines a particular -cpu argument will
work on. For information about this utility, type help cpuhelp in an Aegis environment or
man cpu help in a UNIX environment.

Program Development

6-17

6.4.10 -db, -ndb, -dba, -dbs: Debugger Preparation
The -db option is the default.
Use these switches to prepare the compiled file for debugging by the Domain Distributed
Debugging Environment. Domain Pascal stores the debugger preparation information
within the executable object file, so in general, the more debugger information you request,
the longer your executable object file.
If you use the -ndb option, the compiler puts no debugger preparation information into
the •bin file. If you try to debug such a . bin file, the system reports the following error
message:

?(debug) The target program has no debugging information.
If you use the -db option, the compiler puts minimal debugger preparation information

into the .bin file. This preparation is enough to enter the debugger and set breakpoints,
but not enough to access symbols (e.g., variables and constants).
If you use the -dbs option, the compiler puts full debugger preparation information into

the .bin file. This preparation allows you to set breakpoints and access symbols. When
you use the -dbs option, the compiler sets the -opt option. (You can override this with
the -nopt or -opt 0 option.)
The -dba option is identical to the -dbs option except that when you use the -dba option, the compiler sets the -nopt option (even if you specify -opt).
NOTE:

The -dba option overrides anything you specify for the -opt option. When you specify -dba, the -opt option is set to -opt 0,
regardless of what you specified for -opt on the command line for
the compilation. See the "-opt: Optimized Code" section of this
chapter for more details about the optimizations that are set with
-dba.

For more information on these four options, see the Domain Distributed Debugging
Environment Reference.

6.4.11 -exp and -nexp: Expanded Listing File
The -nexp option is the default.
If you compile with the -exp option, the compiler generates an expanded listing file. This
listing file contains a representation of the generated assembly language code interleaved
with the source code.
If you compile with the -nexp option, the compiler does not generate a listing file (unless

you use the -map or -I options).

6-18

Program Development

6.4.12 -frnd and -nfrnd: Floating-Point Rounding
The -nCrnd option is the default.
If you compile with -nCrnd, the compiler generates code that computes floating-point expressions in at least the precision specified by the program. If the compiler detects an opportunity to optimize execution by doing the arithmetic in greater precision, it does so.

The -Crnd option causes floating-point numbers to be rounded to the programmerspecified precision (either 32-bit single precision or 64-bit double precision) at key points
in the execution of the. program, so that programs executing on Domain systems will give
results similar to those obtained on machines that use different floating-point representation. Programs compiled with -Crnd execute more slowly and with less floating-point precision (that is, less mathematical exactness) than those compiled with -nCrnd.
With -nCrnd, floating-point operands may be kept in registers that support more accuracy
than memory does. Consequently, when a register operand is compared with a memory
operand, the result may not be what is expected. This is particularly true of equality comparisons. Consider the following Pascal program:
PROGRAM main;

VAR
x : double;
FUNCTION fetch : double;
BEGIN
fetch .- 1.1;
END;
BEGIN
x := fetch;
IF (x - 0.1) = 1.0 THEN
wri teln (' Pass' )
ELSE
writeln('Fail');
END.
If you compile with -nCrnd, this program fails because the values 0.1 and 1.1 cannot be
represented exactly in base 2 floating-point. Thus, the quantity (x - 0.1) can only be approximated. This value is calculated in an 80-bit register, and then a compare is generated to see if this value is exactly equal to 1.0, which is stored in memory. Since the register has more precision than memory has, the comparison fails.
If you compile with -Crnd. the 80-bit register is stored (and rounded) in a doubleprecision 64-bit temporary memory location. Now when it is compared with, 1.0, which is
also stored in memory. the two values compare as equal.

Program Development

6-19

Floating-point calculations on Apollo workstations run considerably faster if you do not use
the -frnd option. Moreover, using -frnd makes floating-point calculations less precise. If
you find that your results with -frnd differ significantly from your results without it, your
code is exposing the inherent imprecision of floating-point arithmetic. In this case, you
should investigate whether you can rewrite your program so that it produces the same results with and without -frnd. Try to eliminate practices like the following:
•

Equality comparisons of floating-point values.

•

Subtraction of two nearly equal floating-point values. The imprecision in the low
bits of the two numbers can dominate the value of the difference.

•

Expressions that evaluate a function near a singularity. For example:

tan(pi/2.0 - small_delta)
sin(l/small_epsilon)
NOTE:

The -frod option gives a precision that is closer to that required
by the IEEE-7S 4 floating-point standard than that provided by
-nfrod. However, using -frod does not bring a program into
compliance with the IEEE standard. If you want exact conformance to the IEEE standard, use the DomainlOS system call
fpp_$set_rouoding_mode. This routine puts the floating-point
processor in a round-every-computation mode, which gives exact IEEE-7S4 conformance but, like -frod, reduces precision
and increases execution time.

6.4.13 -idir: Search Alternate Directories for Include Files
The -idir option specifies the directories in which the compiler should search for include
files if you specify such files using relative, rather than absolute, pathnames. Absolute pathnames begin with a slash (I), double slash (II), tilde C), or period (.).
Without the -idir option, Domain Pascal searches for include files in the current working
directory. For example, if your working directory is Ilnord/minn and your program includes this directive

%INCLUDE 'mytypes.ins.pas'
Domain Pascal searches for that relative pathname at Ilnord/minn/mytypes. ins. pas. However, when you use -idir, the compiler first searches for the file in your working directory,
and if it doesn't find the file, it looks in the directories you list as -idir arguments. When
it finds the include file, the search ends. This capability is useful if you have include files
stored on multiple nodes or in multiple directories on your node.
For example, consider the following compile command line:
$ pas test -idir lIouest/hawaii

6-20

Program Development

This command line causes the compiler to search for mytypes.ins.pas at lIouest/hawaii/
mytypes.ins.pas if it can't find IInord/minn/mytypes.ins.pas.
You can put up to 63 pathnames following an -idir option. Separate each pathname with a
space.

6.4.14 -imap and -nimap: Generate Symbol Table Maps for Include Files
The -nimap option is the default.
The -imap option tells the compiler to generate map files for files that are %included by
the files that you specify on the command line. The generated map files are the same as
those generated when you use the -map option. -imap implies -map.
See Section 6.4.20 for further details about the -map option and about the symbol table
maps that are generated.

6.4.15 -indexl and -nindexl: Array Reference Index
The -nindexl option is the default.
The -indexl option disables some optimizations and forces the compiler to use 32-bit indexing in subscript calculations. The -nindexl option causes the compiler to use the
source code's array dimension information to determine whether to use 16-bit or 32-bit
indexing.

6.4.16 -info nand -ninfo: Information Messages
The -info 2 option is the default.
The -info option allows you to tell the compiler which, if any, types of information messages to display. The purpose of information messages is to alert you to ways in which
you could improve the efficiency of your code. You specify the types of message by means
of an information message level. The syntax for the -info option is:
-info n
where n is an integer between 0 and 4 that represents the information message level.
-ninfo is equivalent to -info O.
The compiler displays messages for all levels up to and including the level you specify. In
other words, if you specify -info 3, the compiler will display all the messages specified by
-info 3 plus all the messages specified by -info 1 and -info 2.

Program Development

6-21

Domain Pascal provides the following information message levels:
-info 0

This level is equivalent to -ninfo. At this level, the compiler displays no
informational messages.

-info 1

Messages at this level are about the size and alignment of variables and types.

-info 2

Messages at this level describe optimizations performed by the compiler.
-info 2 messages were warning messages prior to SR 1O.

-info 3

If you specify this level, the compiler issues a message in addition to level 2
messages only if all of the following conditions occur:

•

You do not specify the alignment for a variable.

•

The variable is not naturally aligned.

•

The compiler loads or stores from the variable.

All

Use this message level to discover variables for which you could specify the
alignment as natural alignment and thereby make your program run more
efficiently.
-info 4

If you specify this level, you get the same message as you get with -info 3.

However, you get this message even if you do not specify natural alignment for
a variable.
Use this level to discover any variables for which you may want to change
the alignment.
Level 4 messages also indicate if a routine has been expanded inUne. For
example, if you compile a program containing a function named test_pos with
-info 4, you get the following message at compile time:

********

Line 38: [Information 266]
at call site: "test_pos".

routine expanded INLINE

This message indicates that the compiler substituted an expansion of test_pos
at line 38 of your source file, where your source code contained a function
call to the test_pos function. For more information about inline expansion,
see the discussion of the %begin_inline, %end_inline, %begin_noinline, and
%end_noinline directives in the "Compiler Directives" listing of Chapter 4.
Note that using the -info option does not affect the display of warning and error messages.
See Chapter 9 for more details about information, warning, and error messages.

6.4.17 -inlib: Library Files
Use -inlib to tell the compiler to load library files at run time. The -inlib option makes
code available to an executing program without actually binding the code into the output
object file. If your program needs to access code in a library file that has not been specified with the -inlib option, your program will not work as you intended.

6-22

Program Development

The syntax for the -inlib option is:
-inlib pathname
where pathname specifies the library file. The file in pathname must be a binary file created with the -pic option. (For information about -pic, see Section 6.4.1.)
When you use the -inlib option,
1. The compiler puts the pathname of the library in the binary file.
2. The compiler uses global symbols in the library to identify externals which are not
absolute data or absolute procedure references.
3. At run time, the loader loads the library file, and the externals identified in Step
2 are dynamically linked.

6.4.18 -iso and -niso: Standard Pascal
The -niso option is the default.
Domain Pascal implements a few features differently than ISO standard Pascal. The -iso
switch lets you tell the compiler to use standard Pascal rules for some of these features. It
also tells the compiler to turn on the -std switch, which issues error messages for nonstandard language elements.
The -iso option tells the compiler to use ISO rules with the mod operator. Domain Pascal
implements mod using the Jensen and Wirth semantics; see the mod listing in Chapter 4
for details.
In addition, if you compile with -iso, comment delimiters no longer are required to match
up, which means that the following becomes valid:
{This comment starts with one type of delimiter and ends with another.*)
Finally, if you use the -iso option, the compiler flags as an error a goto statement that
jumps into an if/then/else statement.
For example, the following is incorrect under the -iso switch:
label
bad_jump;
if num > 0 then
{statement}
else
bad_jump:
{next statement};
goto bad_jump;

{WRONG}

The preceding structure is permitted under Domain Pascal.

Program Development

6-23

6.4.19 -I and -nl: Listing Files
The -nl option is the default.
The -I option creates a listing file. The listing file contains the following:
•

The source code, including line numbers. Note that line numbers start at 1 and
move up by 1 (even if there is no code at a particular line in the source code).
Further note that lines in an include file are numbered separately.

•

Compilation statistics.

•

A section summary.

•

A count of error messages produced during the compilation.

The format for the -I option is
-I path name
If you specify a pathname following -I, the compiler creates the listing file at pathname.lst.
If you omit a pathname, the compiler creates the listing file with the same name as the
source file. If the source file name includes the .pas suffix, .1st replaces it. If the source

file name does not include .pas, .Ist is appended to the end of the name.
The -nl option suppresses the creation of the listing file. (See also -map and -exp.)

6.4.20 -map and -nmap: Symbol Table Map
The -nmap option is the default.
If you use the -map option, Domain Pascal creates a map file. A map file contains everything in the listing file (-I) plus a special symbolic map. The special symbolic map consists
of two sections.

The first section describes all the routines in the compiled file. For example, here is a
sample first section:
001 EXAMPLE Program(Proc = 00005A,Ecb = 000030,Stack Size = 0)
002 DO_NOTHING Procedure(Proc = OOOOOO,Ecb = 000020,Stack Size = 8)
003 DO_SOMETHING Function(Proc = 00003E,Ecb = OOOOOC,Stack Size = 8)
The preceding data tells you that the compiled file contains a main program (called example), a procedure (called do_nothing), and a function (called do_something). There are
three pieces of data inside each pair of parentheses. The first piece tells you the start address in hexadecimal bytes from the start of a section. The second piece is the offset (in
bytes) of the routine entry point. The third piece is the size (in hexadecimal bytes) of the
stack. The second and third pieces of data probably are of interest only to systems programmers.

6-24

Program Development

For example, in the sample first section, the starting address of the main program was offset 16#SA bytes from the beginning of the .text section. The offset relative to the beginning of the .data section of the main program's routine entry point is 16#30 bytes. Its
stack size is 0 bytes.
The second section lists all the variables, types, and constants in the compiled program.
For example, here is a sample second section:

002
002
001
001
001
001
001
001
001
003

A
A2
BI
BILBOA
Q

R5
S
X
y
Z

Var(-000008/S): CHAR
Var(-000006/S): CHAR
Type= ARRAY[1 .. 2] OF INTEGER16
Const='The rain'
Var(+000002/MICROS): CHAR
Var(+000004/MICROS): DOUBLE
Var(+OOOOOC/MICROS): BI
Var(/MICROS): INTEGER16
Yare/D): INTEGER16
Var(+000010/S): INTEGER16

The map tells you, for example, that RS is a Var (variable) that is stored +000004 bytes
from the beginning of the MICROS section. It also tells you that RS has the data type
double. Also, note that ID means the .data section, and IS means the stack.
If you specify -nmap, Domain Pascal does not create the special symbol map.

6.4.21 -msgs and -nmsgs: Messages
The -msgs option is the default.
If you use the -msgs option, the compiler produces a final compilation report having the

following format:

xx errors, yy warnings, zz info msgs, Pascal compiler variant Rev n.n
where xx, yy, and zz are either "no" or a number, n.n is the version number, and variant
is one of the following:

68K
PRISM
68K=>PRISM
PRISM=>68K
If you use -nmsgs, the compiler suppresses this final report.

6.4.22 -natural and -nnatural: Setting the Environment to Natural Alignment
The -nnatural option is the default.
The -natural option tells the compiler to use natural alignment for laying out data structures that do not have alignment attributes in their declarations and that are not controlled
by ·compiler directives.

Program Development

6-25

The hardware is designed to transfer data most efficiently if the data is naturally aligned.
Thus, if your data is naturally aligned, you can increase the processing speed of your program, even though you may sacrifice some efficiency in memory usage.
NOTE: -natural has the same effect as the %natural_alignment compiler
directive.
See the "Internal Representation of Unpacked Records" and the" Alignment-Extension"
sections of Chapter 3 for more details about natural alignment.

6.4.23 -nclines: COFF Line Number Tables
By default, the compiler variants that generate code for the MC680xO workstations generate COFF line number tables whenever you compile using the -dba or -dbs option. However, the Domain Distributed Debugging Environment does not require these tables, nor
does the Domain traceback (tb) tool. You can use the -nclines option to tell the compiler to suppress the generation of these tables.
Since these tables might require a lot of disk space, you should use the -nclines option if
you do not need the COFF line number tables and you wish to save space.
NOTE:

This option has no effect on the compiler variants that generate
code for the Series 10000 workstations.

6.4.24 -opt: Optimized Code
The -opt 3 option is the default.
The -opt option allows you to specify the kinds of optimization performed on your source
program, by means of an optimization level.
The syntax for the -opt option is:
-opt n
where n is an integer between 0 and 4 that represents the optimization level. If you specify
-opt and omit the optimization level, the level defaults to -opt 3. If you omit the -opt
option completely, the default option, -opt 3, is assumed. The obsolete option -nopt is
equivalent to -opt O.
At -opt 0 the compiler performs very few optimizations. At each higher optimization
level, the compiler performs more optimizations. Each higher level of optimization includes all optimizations performed at the lower levels of optimization.
NOTE:

6-26

Because the compiler does increasingly more work at successive
levels of optimization, it takes longer to compile your program at
each successive optimization level. If you are just beginning to
develop your program, and you are compiling mainly to find syntax errors, you may want to compile using a low optimization level
to reduce the compilation time. When you are ready to test the
execution of your program, you can compile with a higher optimization level to take advantage of all the optimizations.

Program Development

The following is a brief description of the optimizations performed at each optimization
level. Note that we include -dba in the list of optimization levels because it implies
-opt O. For a more detailed discussion of compiler optimization techniques, consult a general compiler textbook.
•

-dba represents the lowest possible optimization level. At this level, the -opt
option is -opt O.
The -dba option tells the compiler to store variables in memory after every statement instead of allowing them to remain in registers. Even with the -dba option
the compiler still does some optimizations. Specifically, the compiler
Rearranges expressions to minimize the number of registers needed to compute
them
Generates faster short range branch instructions in place of long branches where
possible
Computes constant expressions that appear in the source code rather than generating code to compute them
Computes multiple occurrences of the same expression within a statement only one
time rather than many times
Note that the -dba option overrides anything you specify for the -opt option. In
other words, when you specify -dba, the -opt· option is set to -opt 0, regardless
of what you specify for -opt on the command line.
Furthermore, -dba represents a level of optimization even lower than -opt O. If
you want your code to be optimized, and you want to use the debugger on your
program, use the -dbs option rather than -dba. See the section on -dba and
-dbs for details about using these options.
•

-opt 0 performs the optimizations listed above. In addition, the compiler
Permits values to remain in registers across statements (where it is legal to do so,
and if -dba is not also set)
Merges identical sequences of instructions in generated code by eliminating all but
one of them and branching just to that one sequence

•

-opt 1 performs the following additional optimizations:
Eliminates some global common sUbexpressions. A common subexpression is an
expression that appears two or more times in the program, with no intervening assignments to any component of the expression. In such cases, the compiler computes the value of the expression only one time and uses the resulting value to replace other occurrences of the expression.
Eliminates dead code. Dead code is code that cannot be executed because there is
no execution path of the program that leads to the code.

Program Development

6-27

Transforms integer multiplication by a constant into shift and add instructions
rather than using direct multiply (where appropriate)
Performs simple transformations for speed
Merges assignment statements where possible
•

-opt 2 performs the following additional optimizations:
Substitutes constants for reaching definitions (see details below)
When you make an assignment to a variable or use the variable as a parameter in a
function call, the compiler produces a definition of the variable. If there are no
other definitions between the original definition and the use of the variable, then a
particular definition of a variable is said to reach later uses of the variable. If the
definition is an assignment of a constant to the variable, then the compiler can replace uses of the variable that the definition reaches with the constant. As the compiler makes these substitutions it transforms the expressions into constant expressions that can be evaluated during compilation. Thus there is no need to generate
code to compute the value of the expression.
For example, in the statements,
a .- 3
c .- 2

* a;

there are no other definitions of the variable 8 between the original assignment and
the use of 8 in the expression 2 * 8. So the compiler can substitute the value 3 in
the expression 2 * 8. The expression then becomes 2 * 3, which is computed during
compilation. As a result, the program does not perform a multiply when it executes.
Instead, it merely assigns the already computed value 6 to c.
•

-opt 3 is the default optimization level.
At this level, the compiler performs the following additional optimizations:
Redundant assignment statement elimination
Redundant assignment elimination performed at this optimization level may result
in warning messages such as the following:

******** Line 14: [Warning 279]

Value assigned to SMALL_RANGE
is never used; assignment is eliminated by optimizer.

Consider the following example:

program B;
var
it j : integer;
begin
read In ( itj );
if ( i = 0 ) then
j

:= 3;

writeln ( i );
end.

6-28

Program Development

There are no uses of the variable J after the assignment J := 3. Since the value assigned to J is not used, the compiler can eliminate the assignment completely without changing the result computed in the program. In fact, in this particular program, once the assignment is eliminated, the if portion of the statement isn't
needed either, and can be eliminated. If we change the example so that j is used after the assignment, the assignment is no longer eliminated:
program B;
var
i, j : integer;
begin
readln ( i,j );
if ( i = 0 ) then
j

:= 3;

writeln
end.

i, j

);

Global register allocation
Global register allocation allows local variables to have their values placed in machine registers for faster access. In many cases, all definitions and uses of a local
variable may occur in a register, and the compiler never uses or updates the copy
of the variable in the computer's main memory. Keeping variables in registers
makes your program execute faster.
Instruction reordering
Instruction reordering changes the order in which instructions are executed in order to take advantage of possible overlaps in some instruction sequences. For example, some integer instructions can execute at the same time as some floatingpoint instructions, as long as the integer instructions do not depend upon the result
computed by the floating-point instructions.
Removal of invariant expressions from loops
A loop invariant expression is an expression whose value does not change during
the execution of a loop. When the compiler computes invariant expressions outside a loop, it does so only once. Thus the loop executes faster. For example:
for i := 1 to 10 do
begin
j := k * m;
j :=i+j;

end;

Program Development

6-29

The expression k • m is invariant in the above example. The compiler can safely
transform this loop as follows:
temp := k • m;
for i := 1 to 10 do
begin
j := temp;
j

:= i

+

j;

end;
After the invariant expression is removed from the loop, the example does only one
multiply instead of 10 to make the assignment to j.
Strength reduction
Strength reduction is an optimization performed on expressions in loops. The purpose of strength reduction is to reduce execution time in the loop by substituting
equivalent faster operations for slower more expensive ones.
For example, consider the following loop:
for i .- 1 to 10 do
j

.- i

*

5;

In the loop above, i is a counter or induction variable; its value is incremented by a
constant each trip through the loop. The compiler can replace multiplication expressions involving induction variables with cheaper addition operations, and get
faster loop execution. The loop above might be changed to look like this:
{ This operation folds to just 5 }
T$OOOOl:= 1 * 5;
for i:= 1 to 10 do
begin
j := T$OOOOl
T$OOOOl:= T$OOOOl + 5
end;
Strength reduction has replaced the multiplication with an equivalent addition. Notice that a new variable has been introduced, T$OOOO 1. This variable is strength
reduction temporary variable. The optimizer uses this variable to take the place
of i, whose value may be needed at a later point in the program. However, if i is not
used in the loop in expressions that cannot be strength reduced, and it is not used
on a later execution path from the loop, the optimizer may eliminate all assignments to i. Since the assignment elimination is aside effect of strength reduction,
the compiler does not issue a warning message when it does this. As a result, you
may find it difficult to examine induction variables when you are debugging your
program. However, the optimizer eliminates the increment and store of the induction variable in the loop. Of course, you could change your source code yourself,
and achieve the same effect the optimizer produces.

a

6-30

Program Development

More frequently, strength reduction helps to eliminate hidden multiplication operations in array accesses. For example, whenever your code refers to an element
in an array, say A [i), it must calculate an address in order to fetch the correct element of A. The formula for this address calculation is as follows:
(base address of A) + (i - lower bound) • (element size of A)
Notice that there is a multiply that will appear in the generated code, even though
no explicit multiply appears in your source code. Consider the following loop:
for i := 1 to 10 do
A[i] := 0.0;
Even though there are no explicit multiplication operations in the source code, the
array reference introduces a multiplication operation, and an opportunity for
strength reduction, since the array index i is an induction variable. The optimizer
can transform this loop as follows:
T$00001 := (base address of A) + (1 - 1)
for i := 1 to 10 do

*

(4)

begin
T$00001
T$00001

A

:= 0.0;
:= T$00001 + 4;

end;
In this example, T$OOOOI means an indirect reference through the variable
T$OOOOI, which contains the address of the selected array element. Notice that
strength reduction has succeeded in eliminating the multiplication inside the loop
for the array reference, and has also moved the addition of the base address of A to
a point outside the loop. In some cases, the increment of T$OOOOI may be accomplished at the same time the array element is stored, by means of auto-increment
addressing modes in the machine instructions. Again, all references to i may be
eliminated if it is legal to do so in the context of the surrounding program.
A

Live analysis on local variables.
When the compiler performs live analysis of local variables it determines the areas
of a routine where a variable is actively used. For example,
j

:= k;

if ( i = 0 ) then
begin
' - 2',
i .j

.-

3

j;

*

end
else
begin
k:=

i

*

4;

writeln( k );
end;

Program Development

6-31

In this example, j is not used in the else clause.
execution path from the else clause to the end
paths from the else to other parts of the routine.
j to be dead from the statement following the

Furthermore, j is not used on any
of the program, nor on execution
Therefore, the compiler considers
else to the end of the routine.

Within the then clause, there is a use of j. Therefore, the compiler considers j to be
live within the then clause. If there were other uses of j that could be reached from
the then clause, j would be considered live along the paths that lead to those uses.
Live analysis is important because it allows the compiler to allocate a local variable
to a machine register for exactly as long as the variable's value is needed. When the
variable becomes dead, the register can be used for other variables or expression
values. In general, referencing a value in a register is faster than referencing a value
in the computer's main memory. Thus if you use registers efficiently, your programs will run faster.

I

Extensive searches through each routine for global common subexpressions to
eliminate.
Note that the -opt 1 and -opt 2 levels make only limited searches through the code
for global common subexpressions.
Inline expansion of routines specified by %begin_inline and %end_inline directives.
Inline expansion means that the compiler will attempt to generate code for the
function everywhere the function is referenced from within the same source file.
Inline expansion may create a larger object file, since the code for the function is
replicated at each call site. However, inline expansion may result in an increase in
execution speed. Usually, good candidates for inline expansion are small functions
that are frequently executed.
If you use -opt 3 in conjunction with the %begin_inline and %end_inline directives, you can specify exactly which routines are to be expanded inline. These directives have no effect with -opt 0, -opt 1, or -opt 2. For more information about
these directives, see "Compiler Directives" in Chapter 4.

•

-opt 4 performs the following additional optimization:
In addition to performing the same inline expansions as -opt 3, the compiler selects routines for inline expansion whether or not you specify any routine with the
%begin_inline and%end_inline directives. To specify that certain routines are
not to be expanded inline, use the %begin_noinline and %end_noinline directives, which are described in the "Compiler Directives" listing in Chapter 4.

6.4.24.1 Using the Debugger at Higher Optimization Levels
If you use the debugger to debug a program that you compiled using -opt 3 or -opt 4,

you may be unable to examine the values of some local variables at points in the
code where those variables are not actively in use.

6-32

Program Development

~()urce

This happens because the compiler assigns the values of variables to a machine register
rather than the computer's main memory. The optimizer may decide that the main memory location for this variable does not need to be updated, because all uses of the variable
in the source program can legally use the value of the variable that is retained in the machine register. In addition, the optimizer may merge some source statements together, or
eliminate source statements entirely.
Thus, when you are debugging with these optimizations, you may see what appear to be
strange jumps in the control flow of the program. Furthermore, you may be unable to set a
breakpoint at a particular source line because the generated code for that source line has
been optimized away or merged with the code from another source line.
See the Domain Distributed Debugging Environment Reference for more details about the
use of the debugger.

6.4.25 -prasm and -nprasm: Expanded Listing Format
The -prasm option is the default if you are using a compiler variant that generates Series
10000 code and if you are compiling with the -exp option.
The -prasm and -nprasm options give you control over the format of expanded assembler
listings when you use the -exp option. If you use them without the -exp option, they
have no effect.
The -prasm option tells the compiler to use the Series 10000 assembly language format for
the expanded listing it generates. The -nprasm option tells the compiler to use an alternate format for the expanded listing. Most programmers find this format easier to use
when debugging a program.
If you use these options with the compiler variants that generate MC680xO code, they have

no effect.

6.4.26 -slib: Precompilation of Include Files
Because there usually are a number of common tasks most programs must perform,
Domain Pascal programs often contain include files. Frequently used files include
Isys/ins/base.ins.pas and Isys/ins/error.ins.pas. But it would be time-consuming to compile such files every time a program in which they were %included was compiled. The
-slib option allows you to precompile an include file. The %slibrary compiler directive
(described in Chapter 4) allows you to insert that file in your program. Then, the compiler knows that the file already has been compiled and doesn't bother to parse it again.
The syntax for -slib is:
-slib pathname

Program Development

6-33

If you specify a pathname following -slib, the· compiler creates the precompiled file at

pathname. plb. When no pathname is present, and the name of the input program file ends
in •pas, -slib replaces that ending with . plb and creates the file at program_name. plb. If
the input filename does not end in .pas, -slib appends .plb to the name.
For example, suppose you want to precompile the file mystuff.ins.pas. This command
pre compiles it and puts the result in mystuff.ins.plb.
$ pas mystuff. ins -slib

The following restrictions apply to the contents of files that are going to be precompiled:
•

They can contain only declarations.

•

They must not contain routine bodies.

•

They must not declare variables that would result in the allocation of storage in
the default data section, . data.
This means the declarations must either put variables into a named section, or
must use the extern variable allocation clause. See Chapter 3 for more information about named sections, and Chapter 7 for details on extern.

Conditional compilation directives in the files you slib are executed during precompilation.
If you have several files that you want to combine into a single precompiled library, you

can create a container file with a series of %include directives. For example, to combine
some frequently used include files into the single precompiled library Isys/ins/domain. plb,
you can create a file systemstuff.pas which contains the following:

{ Files we often use together. }
%include '/sys/ins/base.ins.pas';
%include '/sys/ins/error.ins.pas';
%include '/sys/ins/vfmt.ins.pas';
Then use -slib as follows to create the precompiled, combined library.
$ pas systemstuff -slib Isys/ins/domain

You can include the new precompiled library in any program. For example:

PROGRAM errortest;
%SLIBRARY'/sys/ins/domain.plb';
BEGIN

END.

6-34

Program Development

6.4.27 -std and -nstd: Nonstandard References
-nstd is the default.
The -std option tells the compiler to compile in the usual way but to issue error messages
for nonstandard language elements (Le, extensions to the ISO standard).
Note that using -std does not otherwise change the way Domain Pascal compiles your program. To tell the compiler to use standard Pascal rules for compiling rather than its usual
rules, you should use the -iso option.
The -nstd option suppresses reporting of nonstandard elements.

6.4.28 -subchk and -nsubchk: Subscript Checking
-nsubchk is the default.
If you use -subchk, the compiler generates additional code at every subscript to check that
the subscript is within the declared range of the array. This extra code slows your program's execution speed.
If you use -nsubchk, the compiler does not generate this extra code.

6.4.29 -version: Version of Compiler
If you use the -version option, the compiler reports its version number.

NOTE: When you use the -version option, do not include the filename on
the command line. If you do, you will get an error message from
the compiler.
The following command line shows the correct use of the
-version option:
$ pas -version

6.4.30 -warn and -nwarn: Warning Messages
-warn is the default.
If you use -warn, the compiler reports all warning messages.
If you use -nwarn, the compiler suppresses reporting warning messages (though it does
report on the total number of warnings that would have been issued).

Program Development

6-35

We strongly recommend that you avoid using -nwarn. Warnings are issued when the compiler believes it knows what the program meant to say, and so thinks it can still generate
the right code. But the compiler isn't always right, and if you use -nwarn, you won't see
the messages that could indicate where the compiler got confused.

6.4.31 -us and -nxrs: Register Saving
-xrs is the default.
This option controls whether the compiler believes that the contents of registers are saved
across a call to an external routine or a call through a procedure-ptr or function-ptr variable. If you use -xrs, the compiler assumes registers are saved, while if you use -nxrs, it
does not assume registers are saved.
In either case, the compiler always saves register contents when it enters a routine and restores those contents to the registers when it exits the routine.
The primary use for this option is when your program contains calls back to subprograms
compiled with pre-SR9.5 compilers. In such a case, you should isolate the portion of your
new code that calls the older subprograms, and separately compile that new code with the
-nxrs option.

6.5 Linking Programs
There are two commands that enable you to link (bind) object modules to form an executable image. The Id utility is the standard UNIX link editor with some Domain enhancements. The bind command invokes the Id utility but offers a somewhat different
command syntax.
NOTE:

We support the bind command primarily for backward compatibility with scripts written to run on older versions of the Domain
system. We recommend you use the Id command for new programs.

6.5.1 The ld Utility
Use the UNIX link editor, Id, to combine several object modules into one executable program. The input object module~ can come from the following sources:

6-36

•

Libraries created by ar (the UNIX archiver)

•

Libraries created by Ibr (the Aegis librarian)

•

Object modules created by the Domain/C, Domain Pascal, or Domain FORTRAN
compilers

Program Development

•

Object modules previously created by Id

•

Object modules created by bind (the Aegis binder)

The Id utility resolves external references and reports external references it can't resolve.
An external reference is a symbol (variable, constant, or routine) that you refer to in one
object file and define in another. You can also use the UNIX utility nm to perform a
check of resolved and unresolved global symbols.
You can execute the output from Id (if there is a start address) or use it as input for a
further Id run. For syntax details on Id and its options, see the SysV Command Reference
and the BSD Command Reference.

6.5.2 The bind Command
The bind command is similar in function to the Id link editor. Use the binder utility to
combine an object file with other object files to which it refers. The main purpose of the
binder is to resolve external references.
The format for the bind command is as follows:

$ bind pthnml [ .. .pthnmN]

[optionl [ .. .optionN]]

A pthnm must be the pathname of an object file (created by a compiler) or a library file
(created by the librarian). See Section 6.6 for more information about creating library
files.
The bind command line can also contain zero or more binder options, the most important
of which is -b. If you use the -b option, the binder generates an executable object file. If
you forget to use the -b option, the binder won't generate an output object file. Refer to
the Domain/OS Programming Environment Reference manual for a complete discussion of
the binder and its options.
For example, suppose you write a program consisting of three source code
files-test_main.pas, mod1.pas, and mod2.pas. To compile the source code, you issue
the following three commands:
$ pas test_main
$ pas modI
$ pas mod2

The Domain Pascal compiler creates test_main.bin, modI.bin, and mod2.bin. To create
an executable object, bind the three together with a command like the following:
$ bind test_main. bin

mod1.bin mod2.bin -b T3

This command creates an executable object file in filename T3.

Program Development

6-37

NOTE:

At SRI0 the compiler generates an object file format which is an
extended version of the COFF (Common Object File Format)
standard. The loader retains knowledge of how to load preCOFF objects; however, it is not possible to bind pre-COFF and
COFF modules together. Be aware that COFF object files will not
run on pre-SRI0 nodes.

Refer to Domain/OS Programming Environment Reference for a complete discussion of the
binder and its options.

6.6 Archiving and Using Libraries
Use the UNIX archiver, ar, to create and update library files. Once created, a library file
can be used as input to the link editor, Id. As with most linkers, Id will optionally bind
only those modules in a library file that resolve an outstanding external reference. For
syntax details on ar and its options, see the Domain/OS Programming Environment Reference.
You can also create library files with the Ibr utility, which is detailed in the Domain/OS
Programming Environment Reference.
NOTE:

At SRI0, the Ibr utility handles only objects generated by SRI0
compilers, SRI0 linkers (bind or Id) or SRI0 archivers (lbr or
ar). The Ibr utility generates library files in the form of UNIX
archive (ar) files. For compatibility, we provide a version of Ibr
that handles objects created between SR9. 5 and SR9. 7-the
Ibr2ar command. You can use Ibr2ar to convert pre-SRI0 Ibr
libraries. See the Domain/OS Programming Environment Reference for details about using Ibr2ar.

In addition to library files, the Domain system also supports user-defined installed libraries,
system-defined installed libraries, system-defined global libraries, and the user-defined
global library. All are detailed in the Domain/OS Programming Environment Reference.
On some operating systems, you must bind language libraries and system libraries with your
own object files. On the Domain system, there is no need to do this as the loader binds
them automatically when you execute the program.

6-38

Program Development

6.7 Executing a Program
To execute a program, simply enter its pathname. For example, to execute program T3,
just enter

$ T3

The operating system searches for a file named T3 according to its usual search rules, then
calls the loader utility. The loader utility is user transparent. It binds unresolved external
symbols in your executable object file with global symbols in the language and system libraries. Then, it executes the program.
By default, standard input and standard output for the program are directed to the keyboard and display. You can redirect these files by using the shell's redirection notation.
For example, to redirect standard input when you invoke T3, type:

$ T3

results

This command uses the> character to redirect standard output for T3 to the file results.

6.8 Debugging Programs in a Domain Environment
The Domain systems support two source level debuggers. The following sections describe
them briefly. For more information refer to the debugging manual and the Domain/OS
Programming Environment Reference manual.

6.8.1 The Domain Distributed Debugging Environment Utility
The Domain Distributed Debugging Environment is a powerful screen-oriented debugger
that provides all the features of other high-level language debuggers. To prepare a file for
debugging, you do not have to do anything special at bind time but you do have to compile with the -db, -dba, or -dbs compiler options. -db provides minimal debugger preparation; -dba and -dbs provide full debugger preparation.
For complete details on the debugger, refer to the Domain Distributed Debugging Environment Reference.

Program Development

6-39

6.8.2 The dbx Utility
dbx is the traditional Berkeley UNIX source language debugger. Although it is usually
available only on BSD systems, the Domain version is available regardless of what environment you are running. However, it is not available on Series 10000 workstations. The
command syntax for invoking dbx is:

#

dbx [options] [ object Jile [coredump] ]

where objectJile is the name of the program you want to debug. If you specify a
coredump filename, or if a file named core exists in the working directory, you can use
dbx to examine the state of a program that has aborted prematurely.

I

For complete details about the dbx utility, refer to the BSD UNIX Programmer's Manual
or the SysV Programmer's Guide, Volume II.

6.9 Program Development Tools
Domain/OS supports several programming tools that aid in program development, debugging, and source management. This section describes briefly the tools listed below. The
description for each tool includes information about where to find further information.
See the Preface for a complete listing of related manuals.
•

Traceback (tb)

•

DSEE (Domain Software Engineering Environment)

•

Domain/Dialogue

•

Domain/PAK (Domain Program Analysis Kit)

6.9.1 Traceback (tb)
If you execute a program and the system reports an error, you can use the tb (traceback)

utility to find out what routine triggered the error. To invoke tb, enter the command
$ tb

immediately after a faulty execution of the program.
For example, suppose you run a program named test_tb that asks for numerical input.
The source code for test_tb is as follows:
program test_tb;
var
n: integer;
begin
write('please enter a number ');
readln(n);
writeln('your number is ' ,n)
end.

6-40

Program Development

However, when you run test_tb, you give it a character string instead of a number, and
the program terminates with an error. If you then invoke tb, the whole sequence might
look like the following:
$ test_tb.bin
please enter a number alta
?(sh) "test_tb.bin" - invalid read data (library/Pascal)
$ tb
8835 (parent 8761, group 8761)
Process
Time
90/10/25.10:07(EDT)
Program
//my_node/my_name/pascal_programs/test_tb.bin
status
050DOOOA: invalid read data (library/Pascal)
"pfm_$error_trap" line 185
In routine
Called from
"error" line 430
Called from
"get_integer" line 1742
Called from
"pas_$read" line 1915
Called from
"test_tb" line 6
"PM_$CALL" line 176
Called from
"pgm_Sload_run" line 903
Called from
"pgm_$invoke_uid_pn" line 1124
Called from
$
After listing identifying information about the process, time and program, the tb utility
reports the error status, which in this case is:
050DOOOA: invalid read data (library/Pascal)

Status

Then, tb shows the chain of calls leading from the routine in which the error occurred all
the way back to the main program block. For example, routine pfm_$error_trap reported
the error. pfm_$error_trap was called by the error routine. The error routine was called
by the get_integer routine. The get_integer routine was called by line 1915 of the
pas_$read routine, which was called by line 6 of the test_tb routine. The test_tb routine
was called by PM_$CALL which was called by pgm_$load_run. Since all of the routines
except test_tb are system routines, it is probable that the error occurred at line 6 of the
test_ tb routine.
See the BSD Command Reference, the SysV Command Reference, and the Aegis Command
Reference for details about the tb utility.

6.9.2 The DSEE Product
The DSEE (Domain Software Engineering Environment) environment is a support environment for software development. DSEE helps engineers develop, manage, and maintain
software projects; it is especially useful for large-scale projects involving several modules
and developers.You can use DSEE for:
•

Source code and documentation storage and control

•

Audit trails

•

Release and Engineering Change Order (ECO) control

•

Project histories

Program Development

6-41

•

Dependency tracking

•

System building

This chapter described a traditional program development cycle (i. e., compiling, building
libraries, binding, debugging); the DSEE product provides some sophisticated enhancements
to this cycle. For information on the optional OSEE product, see Engineering in the DSEE
Environment.

6.9.3 Open Dialogue and Domain/Dialogue
Open Dialogue and Domain/Dialogue are tools for defining the user interface to an application program. Open Dialogue can be used on both Apollo and non-Apollo workstations
and is layered on the UNIX system and the X Window System. Open Dialogue also allows
you to create interfaces that are compliant with the Open Software Foundation (OSF) interface design standards presented in the MOTIF Style Guide. Domain/Dialogue can be
used only on Apollo workstations and is layered on Domain/OS and Graphics Primitives
Resource (GPR).
Both products enable you to separate the user interface from the application code.
For the user interface, this separation means that you can
•

Focus more time and attention on the interface than is possible when it is intertwined with the application code.

•

Develop modular interfaces that are consistent in design from application to application because they are developed with the same set of tools.

•

Use an iterative approach to interface design. A program's user interface can be
rapidly prototyped and modified without affecting the application code. Successive
testing and refinement are relatively easy, making it possible to fine-tune the interface.

•

Develop multiple user interfaces to a program, allowing users to choose a style of
interaction with which they feel most comfortable.

For the application, this separation means that you can
•

Write less code. Because Open Dialogue and Domain/Dialogue handle interactions with the user, the application designer does not have to provide the code for
doing so.

•

Achieve a modular approach to writing code that promotes phased and iterative
application development independent of user interface development.

For details about Domain/Dialogue, see the Domain/Dialogue User's Guide.

6-42

Program Development

For details about Open Dialogue, see
•

Open Dialogue Reference

•

Creating User Interfaces with Open Dialogue

•

MOTIF Style Guide

•

Customizing Open Dialogue

6.9.4 Domain/PAK
Domain/PAK (Domain Performance Analysis Kit) is a collection of the following three programs:
•

DSPST (Display Process Status) looks at the relative use of CPU time by several
processes at the system level.

•

DPAT (Domain Performance Analysis Tool) is an interactive tool that looks at the
performance of programs, including I/O, paging, and system calls, at the procedure level.

•

HPC (Histogram Program Counter) looks at the performance of compute-bound
procedures at the statement level.

Domain/PAK allows you to analyze the performance of a program.

It is particularly useful
for isolating bottlenecks. See Analyzing Program Performance with DomainlPAK for more
details about Domain/PAK.

6.10 Program Development Using the Network File System (NFS)
Domain Pascal is fully compatible with the Network File System (NFS). You can redirect
the binary output of the Pascal compiler to a file on a remote node that you have accessed
using NFS, and you can then run the program on the remote node.
In order to use this feature of Domain Pascal, you must have Domain NFS installed on
your system.
For example, suppose you issue the following NFS mount command to gain access to a
remote node:
$ letc/mount -0 soft faraway:1 lother_node

This command, which you can issue in any shell, gives you access to the entire directory
structure of the remote node Ilfaraway. You can access this directory structure as if it
were a local directory named lother_node.

Program Development

6-43

For instance, to compile the program test.pas and place it in the directory Itmp on the
remote node, issue the command
$ Icom/pas test -b lother_node/tmp/test

You can also place the source listing in a directory on the remote node by using the -I
pathname option.
Then you can run the program as follows:
$ 10ther_Dode/tmp/test.bin

You can also use the remote node directory as your working directory. If you do so, compiler options that use the name of the current working directory work as usual.
For instance, you can use the -I option to generate a listing file, as shown in the following
sequence of commands (the example assumes you are working in a BSD or SysV shell):
% letc/mount -0 soft faraway:1 lother_node
% cp -/test.pas lother_node/test.pas
%

cd lother_node

% Icom/pas test -I

% Is

test. 1st

For more information about Domain NFS, see Using NFS on the Domain Network.

-------88-------

6-44

Program Development

Chapter 7
External Routines and
Cross-Language Communication

This chapter describes how to create and call Pascal modules and how to call FORTRAN
and C routines from a Domain Pascal program. Briefly, this chapter covers the following
topics:
•

Creating Pascal modules

•

Accessing a Pascal variable or routine stored in a separately compiled module

•

Accessing FORTRAN routines from a Pascal program

•

Accessing C routines from a Pascal program

7.1 Modules
It is usually a good idea to break a large Pascal program into several separately compiled
modules. After you compile each module, you can bind the resulting object files into one
executable object file. (See Chapter 6 for details about binding.)
Every program must consist of one main program. It may also contain one or more modules. Chapter 2 contains a description of the main program's format. A main program must
begin with the keyword program. A module begins with the keyword module. It takes the
format shown in Figure 7-1.

External Routines and
Cross-Language Communication

7-1

-

~~

-

~

module heading
declarations
routines

Define part
Label decl part
Const decl part
Type decI part
Var decI part

....

~

~
~

~~

~.
routine heading
declarations
nested routines

....

Begin
action
End;

Figure 7-1. Format of a Module
At run time, the start address of the program is the first statement in the main routine of
the main program.
The format of a module is very similar to the format of the main program shown in
Figure 7-1. The differences between the formats are:
•

A module takes a module heading rather than a program heading. (See the next
section for a description of the module heading.)

•

A module can contain zero or more routines; each routine must have a name.
That is, the main program always contains one main (unnamed) routine, but a
module must consist of named routines only.

•

The declarations part of a module may contain a define part. The "Method 2"
section of this chapter describes the define part.

7 .1.1 Module Heading
The module heading is similar to a program heading except that it starts with the keyword
module instead of program, and that it cannot take a file_list. Therefore, the module
heading takes the following format:

module name [, COde_section_name] [, data_section_name];

Name must be an identifier. The name you pick has no effect on the module.

7-2

External Routines and
Cross-Language Communication

Code_section_name and data_section_name are optional elements of the module heading.
Use them to specify nondefault section names for the code and data in the module. A section is a named contiguous area of memory that shares the same attributes. (See the Domain/OS Programming Environment Reference for details on sections and attributes.) By
default, Domain Pascal assigns all the code in your module to the . text section and all the
data in your module to the .data section. To assign your code and data to nondefault sections, specify a code_section_name and a data_section_name.
Chapter 2 described the format of a main program, this chapter describes the format of a
module, and Chapter 6 detailed the method for compiling and binding modules and main
programs. The following sections explain how to write your source code so that the separately compiled units can communicate with one another.

7.2 Accessing a Variable Stored in Another Pascal Module
Domain Pascal provides four methods for accessing the value of a variable stored in a
separately compiled file. The trick to the first three methods is using the correct variable_allocation_clause when declaring variables. The optional variable_allocation_clause
precedes the data type in a var declaration part as shown below:
var (section_name)

identifier_list 1

[variable _allocation _clause] typename 1 ;

[

For variable_allocation_clause, enter one of the following three identifiers:
•

Define-tells Pascal to allocate the variable in a static data area and make its
name externally accessible.

•

Extern-tells Pascal to not allocate the variable because it is possibly allocated in a
separately compiled module or program.

•

Static-tells Pascal to allocate the variable in a static data area and keep its name
local to this module or program. Use the static clause when a variable needs to
retain its value from one execution of a routine to the next.
For example, the following fragment declares x as a statically allocated variable:

VAR
x : static integer16;
After the execution of the routine in which x is declared, x still retains its value.

External Routines and
Cross-Language Communication

7-3

The following sections demonstrate three of the four methods for accessing a variable
stored in another Domain Pascal module.

7.2.1 Method 1
The following fragments demonstrate the first method for accessing an externally stored
variable:

program Math;
var
x : EXTERN integer16;
BEGIN
writeln(x); {access x}
END.

module Sub2;
var
x : DEFINE integer16

.-

8;

Procedure twoa;
BEGIN
writeln(x); {access x}
END;

This method uses the variable allocation clauses extern and define to make the value of x
available to both Math and Sub2. The extern clause in Math tells the compiler that variable x is probably defined somewhere outside of Math. The define clause in Sub2 tells
the compiler that x is defined within Sub2; the ":= 8" tells the compiler to initialize x to
8. If x is not initialized, the writeln (x) statement generates undefined output.
When you bind, the binder matches the external reference to x in program Math with the
global symbol x defined in module Sub2. Note that you can specify x as an extern in as
many modules as you want; however, you should only define x in one module. If you
define x in more than one module, the binder reports an error.

7.2.2 Method 2
The following fragments demonstrate the second method for accessing an externally stored
variable:

program Math;
var
x : EXTERN integer16;

module Sub2;
var
x : EXTERN integer16;
DEFINE
x := 8;

.BEGIN
writeln(x); {access x}
END.

Procedure twoa;
BEGIN
writeln(x); {access x}
END;

Method 2 introduces the define statement. The define statement is similar to the define
variable allocation clause. The define statement in Sub2 serves two purposes. First, it tell&
the compiler that x is defined in module Sub2. Second, it tells the compiler that the initial
value of x is 8.

7-4

External Routines and
Cross-Language Communication

The define statement takes the following syntax:
define

variable} [ := initial_ValUe}];

[variableN

[:= inilial_valueN];]

Notice that the := initial_value is optional. If you do not provide an initial_value, the
value of variable is undefined; that is, there is no way to predict what the variable's initial
value will be.

NOTE:

Order is crucial. If you use Method 2, the var declaration part
must precede the define statement. (However, see Method 3
later in this chapter.)

Allowing a define statement in module Sub2 along with a corresponding extern clause may
appear contradictory at first. After all, a define statement means "it's defined here" and
an extern clause implies "it's defined somewhere else." However, allowing this practice
can be useful. For example, when you write an %include file, there is no way for you to
know where the %include file is going to end up. If the extern clause is stored in an
%include file that happens to end up in a file with a matching define statement no harm
is done.

7.2.2.1 Initializing Extern Variable Arrays
The "Initializing Array Variables" section in Chapter 3 contained a lengthy section on initializing variable arrays. The following paragraphs provide additional details about initializing an array variable that has the extern variable allocation clause.
Ordinarily the -subchk compiler option causes the compiler to generate code to check that
subscripts are within the defined range of an array. However, the compiler does not generate this extra code if you do not specify initialization data for an extern array variable.
The compiler cannot check subscripts because the upper bound is not known. If there is
data initialization with the extern declaration, the data is ignored until the variable is defined in a file. However, since the upper bound is known, the compiler can perform subscript checking.
When you let the compiler determine the upper bound of the array, make sure that variable declarations do not share the same type declaration. If they do, the first data initialization for that variable sets the size for all other variables in the type declaration. All initialized variables are then checked against that size, just as if you had specified a constant
upper bound.

External Routines and
Cross-Language Communication

7-5

For example, consider the following fragment:

VAR
tablel, table2
table3
table4
DEFINE
tablel
table2
table3
table4

EXTERN array[l .. *] of char;
EXTERN arraY[l .. *] of char;
EXTERN array[l .. *] of char;

:= 'This table sets the size,';
:= 'so this table will be truncated';
.- 'But separate variable declarations';
:= 'solve the problem.';

In the preceding example, variables tablet and table2 share the same anonymous type
declaration. Since tablet precedes table2, Domain Pascal uses the defined size of tablet
to set the size for table2. In this case, tablet is a 25-character string. Therefore, the compiler truncates the string "so this table will be truncated" to its first 25 characters. Variables table3 and table4 are declared separately, so their initializations do not affect each
other.
Domain Pascal issues a warning message when it truncates arrays with a base type of char,
as for table2. However, if the array has a base type other than char, the compiler issues
an error message when it truncates it.

7.2.3 Method 3
The following fragments demonstrate the third method for accessing an externally stored
variable:

program Math;
VAR
x : EXTERN integerl6;

module Sub2;
DEFINE
x;

VAR
x : EXTERN integer16 .- 8;
BEGIN
writeln(x); {access x}
END.

Procedure twoa;
BEGIN
writeln(x); {access x}
END;

Method 3 is similar to Method 2 except that the initialization (:= 8) is done in the var
declaration part rather than in the define statement.

NOTE:

7-6

Order is crucial. If you use Method 3, the define statement must
precede the var declaration part.

External Routines and
Cross-Language Communication

7.2.4 Method4
The following fragment demonstrates this fourth method for accessing an externally stored
variable:

Program Math;
Module Suh2;
VAR (my_sec)
VAR (my_sec)
x
integer16 := 5;
x
integer16;
y
y
real := 6.2;
real;
q
array[l .. 3] of char .- 'cat';
q
array[l .. 3] of char;
BEGIN
writeln(x, y, z);
END.

Procedure twoa;
BEGIN
writeln(x, y, z);
END;

Notice that the variables in each module occupy the same nondefault section name,
my_sec. This means that at run time, the variables x, y, and q from Math occupy the
same memory locations as x, y, and q from Sub2. Therefore, whatever is assigned to x in
Math, can be retrieved in Sub2, and vice versa.
There's no requirement that the variables in Sub2 have the same names as the variables in
Math. However, it does make your program far easier to understand if you do give them
the same names. Taking this philosophy one step further, you could greatly simplify variable declaration by putting a named var declaration part into a separate file and using
%include to put it into every module.
You should preserve the order of declarations from one module to the next. For example,
suppose the variable declarations look like this:

Program Math;
Module Sub2;
VAR (my_sec)
VAR (my_sec)
y
real;
x
integer16:= 5;
x
integer16;
y
real:= 6.2;
q
array[l .. 3] of char : = ' cat' ;
q
array[l .. 3] of char;
If you try to access x or y in Sub2, you get garbage results at run time. That's because
when compiling Sub2, the compiler sees y as being the first four bytes in my_sec. However, when compiling Math, the compiler sees y as being bytes 2 through 5 in my_sec.

External Routines and
Cross-Language Communication

7-7

7.3 Accessing a Routine Stored in Another Pascal Module
Domain Pascal provides two methods for accessing a procedure or function stored in a different module or program. This section explains both methods, but first describes the extern and internal routine options, which are both critical to that description.

7.3.1 Extern
The routine option extern serves exactly the same purpose for routines that the variable
allocation clause extern serves for variables. Namely, it specifies that a routine is possibly
defined in a separately compiled file. By specifying a routine as extern, you can call it
even if it is defined in another file.
Chapter 5 describes the format of routine options. Extern is like any other routine option,
except that when you use extern, you put the routine heading at the end of the main declaration part of the program or module.

7.3.2 Internal
By default, all routine names in modules are global symbols, and all routine names in main
programs are local symbols. A routine name from the main program can never become a
global symbol. However, you can make a routine name from a module into a local symbol
by specifying the routine option internal. See the "Routine Options" section in Chapter 5
for details on the syntax rules of routine options.

7.3.3 Method 1
Figure 7-2 demonstrates the first method for accessing an externally stored routine. In
this example, program math refers to function exponent; however, function exponent is
stored in module math2. Therefore, function exponent is declared as an extern in program math. There is no need to do anything special to module math2 because the compiler automatically makes exponent a global symbol in math2. At bind time, the binder
resolves external symbol exponent with global symbol exponent. To keep exponent local
to module math2, you could change the following line in the source code:
FUNCTION exponent (number, power: INTEGER16) : REAL;
to the line shown below:
FUNCTION exponent (number, power
The sample program follows.

7-8

External Routines and
Cross-Language Communication

INTEGER16)

REAL; INTERNAL;

{**********************************************************************}
PROGRAM math;
VAR

n, p : integer16;
answer : real;
FUNCTION exponent(n,p

integer16)

real; EXTERN; {exponent is defined
outside this file.}

BEGIN
writeln('The main program calls a separately-compiled routine in');
writeln('order to calculate the value of an integer raised to an');
writeln('integer power.');
writeln;
write('Enter an integer -- ');
readln(n);
write('Raised to what power -- '); readln(p);
answer := exponent(n,p);
writeln(n:1, ' raised to the " p:1, ' power i s ' answer:1);
END.
MODULE math2;

{You must bind this module with
program math.}

VAR
number, power, count
run: INTEGER32;

INTEGER16;

FUNCTION exponent (number, power: INTEGER16)
REAL;
BEGIN
writeln('This is module math2');
if power = 0 then exponent := 1;
run := 1;
for count := 1 to abs(power) do
run := run * number;
if power > 0
then exponent .- run
else exponent .- (1 / run);
END;
{**********************************************************************}
Figure 7-2. Method 1 for Accessing an External Routine

External Routines and
Cross-Language Communication

7-9

7.3.4 Method 2
Figure 7-3 demonstrates the second method for accessing an externally-stored routine.

{**********************************************************************}
PROGRAM math;
VAR
n, p : integer16;
answer : real;
FUNCTION exponent(n,p : integer16) : real; EXTERN;
{exponent is defined outside this file.}
BEGIN
writeln('The main program calls a separately-compiled routine in');
writeln('order to calculate the value of an integer raised to an');
writeln('integer power.');
writeln;
write('Enter an integer -- ');
readln(n);
write('Raised to what power -- '); readln(p);
answer := exponent(n,p);
writeln(n:1, ' raised to the " p:1, ' power i s ' answer:1);
END.
MODULE math2;

{You must bind this module with program
math}

DEFINE
exponent;
FUNCTION exponent (number, power: INTEGER16)
VAR
number, power, count : INTEGER16;
run: INTEGER32;

REAL; EXTERN;

FUNCTION exponent;
BEGIN
writeln('This is module math2');
if power = 0 then exponent := 1;
run := 1;
for count := 1 to abs(power) do
run := run * number;
if power > 0
then exponent .- run
else exponent := (1 / run);
END;
{**********************************************************************}
Figure 7-3. Method 2 for Accessing an External Routine

7-10

External Routines and
Cross-Language Communication

Under Method 2 you call external routines exactly as you do in Method 1. Therefore, program math is unchanged from Method 1. However, you must make the following three
changes in module math2:
•

define exponent; - Use a define statement to tell the compiler that exponent is
a global symbol defined in module math2. With one exception, define takes the
syntax described in the" Accessing a Variable Stored in Another Pascal Module"
section earlier in this chapter. The one exception is that you cannot assign an initial value to a procedure or function symbol.

•

function exponent (number, power: INTEGERl6) : REAL; EXTERN; - Copy
the function declaration from program math. Since this line should be an exact
copy of the function declaration in the calling module, you should put this line
into a separate file and use the %include directive to include it in both the module and the program. That way, you only keep one version of the function declaration.

•

function exponent; - Notice that there are no arguments here; only the name of
the function.

Figure 7-4 consists of one main program and two modules. The main program calls two
external routines stored in the two modules. The two modules access some variables that
the main program defines.

External Routines and
Cross-Language Communication

7-11

{**********************************************************************}
Program relativity1;
CONST
speed_of light = 2.997925e8;
{ Both of the following routines are defined in another file: }
Procedure convert_mph_to_light(IN speed_in_mph
real;
OUT fraction_of_c : real); EXTERN;
Function contracted_length(IN rest_length
real;
IN fraction_of_c: real)
real; EXTERN;
VAR
speed_in_mph, fraction_of_c, rest_length: real;
c : DEFINE real := speed of light;
- - {Make the value of c globally known.}
BEGIN
write('Enter the speed of the object (in mph)
');
readln(speed_in_mph);
convert_mph_to_light(speed_in_mph, fraction_of_c);
write('What is the rest length of the object (in meters) -- ');
readln(rest_length);
write('It will be perceived in the rest frame of reference as ');
writeln(contracted_length
(rest_length, fraction_of_c):8:6, ' meters');
END.
Module relativity2;
DEFINE
convert mph_to_light;
Procedure convert_mph_to_light(IN speed in mph
real;
OUT fraction_of_c
real); EXTERN;
VAR
speed_in_mph, speed_in_mps, fraction_of_c, percentage: real;
c : EXTERN real;
{ The following procedure converts a speed (given in miles per hour) }
{ into a percentage of the speed of light.
}
Procedure convert_mph_to_light;
BEGIN
speed_in_mps := (0.44704 * speed_in_mph);
fraction_of_c := speed_in_mps / c;
percentage := (100 * fraction_of_c);
writeln('This speed is " percentage: 8:6, ' percent of c.');
END;
{continued}
{**********************************************************************}

Figure 7-4. Another Example of Calling External Routines

7-12

External Routines and
Cross-Language Communication

{**********************************************************************}
Module relativity3;
DEFINE
contracted_length;
Function contracted_length(IN rest_length
IN fraction_of_c

real;
real)

real; EXTERN;

VAR

rest_length: real;
speed_in_mps : real;
{ This function calculates the relativistic length contraction. }
Function contracted_length;
BEGIN
contracted_length := rest_length * sqrt(1 - sqr(fraction_of_c) );

END;

{**********************************************************************}
Figure 7-4. Another Example of Calling External Routines (Cont.)
Suppose you store program relativityl in file relativityl. pas, module relativity2 in file
relativity2.pas, and module relativity3 in file relativity3.pas. To compile the three files,
enter the following three commands:
$ pas relativity 1
$ pas relativity2
$ pas relativity3

You must now bind them together by entering a command like the following:
$ bind relativity. bin relativity2. bin relativity3. bin -b einstein

Here is a sample execution of the program:
$ einstein
Enter the speed of the object (in mph) -- 4500000
This speed is 0.667121 percent of c.
What is the rest length of the object (in meters) -- 10
It will be perceived in the rest frame of reference as 9.999778 meters

7.4 Calling a FORTRAN Routine from Pascal
Domain Pascal permits you to call routines written in Domain FORTRAN source code. To
accomplish this, perform the following steps:
1. Write source code in Domain Pascal that refers to an external routine. Compile
with the Domain Pascal compiler. Domain Pascal creates an object file.
2.

Write source code in Domain FORTRAN. Compile with the Domain FORTRAN
compiler. Domain FORTRAN creates an object file.

External Routines and
Cross-Language Communication

7-13

3. Bind the object file(s) the Pascal compiler created with the object file(s) the FORTRAN compiler created, using the -b binder option to tell the binder to create
one executable object file.
4. Execute the object file as you would execute any other object file.
The following sections describes steps 1 and 2. For information on steps 3 and 4, see
Chapter 6.
NOTE:

The following sections explain how to call Domain FORTRAN
from Domain Pascal. If you want to learn how to call Pascal from
FORTRAN, see the Domain FORTRAN Language Reference.

7.5 Data Type Correspondence for Pascal and FORTRAN
There is no great difference between making a call to a FORTRAN function or subroutine
and making a call to an extern Pascal routine. However, before passing data between Domain Pascal and Domain FORTRAN, you must understand how Pascal data types correspond to FORTRAN data types. Table 7-1 lists these correspondences.

Table 7-1. Domain Pascal and Domain FORTRAN Data Types
Domain Pascal

Domain FORTRAN

Integer, Integer16
Integer32
Real, Single
Double
Char

Integer· 2
Integer, Integer· 4
Real, Real· 4
Double Precision, Real·S
Character· 1

Boolean

Logical· 1

Set

set emulation calls

User-defined record as shown in
Section 7.5.2
Array
Pointer

Complex, Complex·16
array (with restrictions)
Pointer statement

The integer, real, and character data types in both languages correspond very well to each
other. For example, Pascal's integer16 data type is identical to FORTRAN's integer·2
data type, and a real in one language is exactly the same as a real in the other.
There is a difference in what the keyword integer means in the two languages. Integer in
Domain Pascal is a 2-byte entity, while in Domain FORTRAN, integer is four bytes by
default. To avoid any confusion, you should use the specific integer data types (integerl6,
integer32, integer·2, and integer·4) rather than the generic integer.

7-14

External Routines and
Cross-Language Communication

Unlike Pascal, Domain FORTRAN doesn't actually support a set data type. However, you
can make special set emulation calls from within a Domain FORTRAN program. Therefore, you can pass a set variable as an argument from a Pascal program and use the set
emulation calls within your FORTRAN program.

7.5.1 Boolean and Logical Correspondence
Pascal's boolean data type and FORTRAN's logical*1 data type are identical 1-byte objects. They may be freely passed between programs written in the two languages.
In some instances, however, you may need to use FORTRAN's 4-byte logical (the default
if you omit a size specification in the declaration) or logical*4 (which is equivalent to
logical) to communicate with a Pascal routine. FORTRAN's 4-byte logical takes up four
bytes of memory. The true or false value is set in all four bytes. By default, a Pascal
boolean object consumes only one byte. To make the data types match, therefore, you
should use the long size attribute to create a 4-byte boolean type, as shown in the following fragment:
TYPE

boo14 = [long] boolean;
See the "Size-Extension" section of Chapter 3 for details about the long attribute.

7.5.2 Simulating FORTRAN's Complex Data Type
Unlike FORTRAN, Domain Pascal doesn't support a predeclared complex data type. However, you can easily declare a Pascal record type that emulates complex. In FORTRAN,
complex consists of two single-precision real numbers. Therefore, you could define a complex Pascal record as follows:
TYPE

complex

record
r

imaginary
end;

single;
single;

Similarly, you could define a complex* 16 Pascal record as follows:
TYPE

complex16

record
r

imaginary
end;

double;
double;

External Routines and
Cross-Language Communication

7-1S

7.5.3

Array Correspondence
Single-dimensional arrays (including boolean/logical arrays when you make the adjustments described above) of the two languages correspond perfectly; for example:

In Domain Pascal

In Domain FORTRAN

x
x
x

character*10
x
integer*2 x(50)
real*8
x(20)

Array[1 .. 10] of CHAR
Array[l .. 50] of INTEGER16
Array[1 .. 20] of DOUBLE

The one exception is as follows: you cannot call from Pascal a Domain FORTRAN routine
that has as a parameter a character array of unspecified length. For example, do not
specify an array like the following as a parameter in the Domain FORTRAN routine:
CHARACTER*(*)

x

Multidimensional arrays in the two languages do not correspond very well. The tricky part
is that Pascal represents multidimensional arrays differently than FORTRAN. To represent
arrays in Domain Pascal, the rightmost index varies fastest. For example, Domain Pascal
represents the six elements of an array[1 .. 2, 1..3] in the following order:
1,1
1,2
1,3
2,1
2,2
2,3

However, the leftmost element varies fastest in Domain FORTRAN arrays. Therefore, Domain FORTRAN represents the six elements of an array(2,3) in the following order:
1,1
2,1
1,2
2,2
1,3
2,3

Obviously this can lead to confusion if you pass a multidimensional Pascal array as an argument to a Domain FORTRAN parameter. However, there is a way to avoid this confusion:
declare the array dimensions of the Domain FORTRAN parameter in reverse order. For
example, instead of declaring integer*4 array(2,3), declare integer*4 array(3,2). Following are two more examples:

7-16

Argument in Pascal

Parameter in FORTRAN

x

array[l .. 5, 1 .. 10] of real

real*4

x(10,5)

x

array[l .. 2, 1 .. 3, 1 .. 4] of real

real*4

x(4,3,2)

External Routines and
Cross-Language Communication

7.6 Passing Data Between FORTRAN and Pascal
There are two ways to pass data between a Domain Pascal program and a Domain FORTRAN function or subroutine. You can either establish a common section of memory for
sharing data, or you can pass the data as an argument to a routine. The next section demonstrates the second method, while the following paragraphs demonstrate the first method.
Earlier in this chapter you learned how to use a named section to pass data between two
separately compiled Pascal modules. A named section in Domain Pascal is identical to the
named common area of Domain FORTRAN. If you give a named section the same name
as a named common area, the binder establishes a section of memory for sharing data.
For example, suppose that you want both a Pascal program and a FORTRAN function or
subroutine to access two variables-a 16-bit integer and an 8-byte (double-precision) real
number. In the Domain Pascal program, you can declare the two variables as follows:
VAR (my_sec)

x
d

INTEGER16;
: DOUBLE;

If you want the value of these two variables to be accessible from the Domain FORTRAN

program, declare them as follows in the FORTRAN program:

I NTEGER * 2 x
REAL * 8
d
COMMON /my_sec/ x,d
Remember to preserve the same order of variable declaration in the common statement
that you did in the var declaration part. For example, you will get peculiar run-time results if you declare your common statement as

COMMON /my_sec/ d,x

7.7 Calling FORTRAN Functions and Subroutines
This section demonstrates how to call a Domain FORTRAN function or subroutine from a
Domain Pascal program. Calling Domain FORTRAN from Domain Pascal is straightforward; the only possible complication is that the data types of the arguments and parameters
may not correspond perfectly. (See the "Data Type Correspondence" section earlier in
this chapter for ways to remedy the data type mismatches.)
Domain Pascal supports a variety of parameter types including value parameters, variable
parameters, in, out, and in out parameters. (See Section 5.3.) Domain FORTRAN sup~
ports only one kind of parameter type, and it is equivalent to the in out parameter type in
Domain Pascal. That is, Domain FORTRAN accepts whatever value(s) you pass to it, and
in turn, always passes a value back.

External Routines and
Cross-Language Communication

7-17

7.7.1 Calling a Function
Figure 7-5 and Figure 7-6 show a Domain Pascal program that calls a Domain FORTRAN
function. The call is trivial since Domain Pascal's single data type corresponds perfectly to
the real*4 data type of Domain FORTRAN.
{*********************************************************************}
program pas_to_ftn_hypo_func;
{ NOTE: You must also obtain the FORTRAN program named "hypotenuse." }
After compiling pas_to_ftn_hypo_func and hypotenuse, you must }
{
bind them together.
}
{
{ This Pascal program calls an external function named HYPOTENUSE.
}
{ Compare to pas_to_ftn_hypo_sub, a program that calls a subroutine }
VAR
leg1, leg2 : single;
function hypotenuse (in out leg1, leg2

single)

single; extern;

BEGIN
writeln ('This program calculates the hypotenuse of a right');
writeln ('triangle given the length of its two legs.');
write ('Enter the length of the first leg -- ');
readln (leg1);
write ('Enter the length of the second leg -- ');
readln (leg2);
writeln ('The length of the hypotenuse is: '
, hypotenuse(leg1,leg2):5:2);
END.
{*********************************************************************}
Figure 7-5. An Example of Calling FORTRAN: pas_to_ftn_hypo_func

*********************************************************************
* This is a FORTRAN function for calculating the hypotenuse of a
* right triangle. You don't have to do anything special to this file
* to make it callable by Pascal. In fact, this function could just
* as easily be called by a FORTRAN program.
real*4 function hypotenuse (11 , 12)
real*4 11, 12
{real*4 corresponds to the Pascal data type single.}
hypotenuse = sqrt«ll * 11) + (12 * 12»
end
*********************************************************************
Figure 7-6. An Example of Calling FORTRAN: hypotenuse

7-18

External Routines and
Cross-Language Communication

These programs are available online and are named pas_to_ftn_hypo_func and hypotenuse.

7.7.2 Calling a Subroutine
A function in Pascal corresponds to a function in FORTRAN. A procedure in Pascal corresponds to a subroutine in FORTRAN. In the example in Figure 7-7 and Figure 7-8,
hypotenuse changes from a function to a subroutine, and the Pascal program changes to
reflect that it is expecting an external procedure. Note that the Pascal program could actually be calling a Pascal procedure. There's nothing in the program that designates the language in which the called procedure is written.

{********************************************************************}
program pas_to_ftn_hypo_sub;
{ NOTE: You must also obtain the FORTRAN program named "hypot_sub." }
{
After compiling pas_to_ftn_hypo_sub and hypot_sub, you must }
{
bind them together.
}
{ This Pascal program calls an external subroutine named HYPOTENUSE. }
{ Although program pas_to_ftn_hypo_sub is bound to hypot_sub,which }
{ is a FORTRAN program, we could also bind it to a Pascal module
}
}
{ containing a procedure named HYPOTENUSE.
VAR

legl, leg2, result: real;
procedure hypotenuse (in out legl, leg2, result

real)

extern;

BEGIN

writeln ('This program calculates the hypotenuse of a right');
writeln ('triangle given the length of its two legs.');
write ('Enter the length of the first leg -- ');
read In (legl);
write ('Enter the length of the second leg -- ');
read In (leg2);
hypotenuse(legl,leg2,result);
writeln ('The length of the hypotenuse is:

result:5:2);

END.
{********************************************************************}
Figure 7-7. An Example of Calling FORTRAN: pas_to_ftn_hypo_sub

External Routines and
Cross-Language Communication

7-19

*********************************************************************
* This is a FORTRAN subroutine for calculating the hypotenuse of a
* right triangle.
subroutine hypotenuse (11 , 12, result)
real*4 11, 12, result
result = sqrt«ll * 11) + (12 * 12»
end
*********************************************************************
Figure 7-8. An Example

0/ Calling FORTRAN: hypot_sub

These programs are available online and are named pas_to_ftn_hypo_sub and hypot_sub.

7.7.3 Passing Character Arguments
Passing arguments when two languages' data types match exactly is relatively easy, but passing them when they don't often means you need to do extra work.
If you pass a string of chars from Domain Pascal to Domain FORTRAN, you should add

an extra parameter to the Pascal routine heading. This is because FORTRAN adds an implicit string length argument whenever it passes a character string back to a calling routiqe.

Suppose your Pascal program includes the following:
TYPE

name

= array[1 .. 10] of char;

VAR

first name
len

name;
integer16;

procedure change_name(in out first_name
in out
len

name;
integer16); extern;

change name(first name,len);
{Assume "change_name" is a FORTRAN subroutine.}
This Pascal routine heading includes an "extra" parameter for the length of first_name
that FORTRAN will add when Pascal calls the routine. The length argument must be of
type integer1' because FORTRAN's implicit length argument is an integer*2.
The FORTRAN routine heading does not explicitly include the length argument. For this
example, it would look like this:
subroutine change_name(first_name)
character*10 first_name

7-20

External Routines and
Cross-Language Communication

If you send multiple strings to Domain FORTRAN and you include FORTRAN's implicit

length arguments in the Pascal parameter list, the length parameters must always appear at
the end of the routine heading. That is, it is not correct to list them as string 1, len 1,
string2, len2, etc. For instance:
{ Pascal program fragment. }
TYPE
fn = array[l .. lO] of char;
In = array[1 .. 20] of char;
procedure process_name(in
in
in
in

out
first_name
out
middle initial
out
last_name
out lenl, len2, len3

fn;
char;
In;
integerl6); extern;

process_name (first_name , middle_initial, last_name, lenl, len2, len3);

*

FORTRAN subroutine fragment.
subroutine process_name (first_name, middle_initial, last_name)

character*lO first name
character
middle initial
character*20 last_name

7.7.4 Passing a Mixture of Data Types
The Domain Pascal program in Figure 7-9 and the Domain FORTRAN subroutine in
Figure 7-10 demonstrate passing a variety of data types.

External Routines and
Cross-Language Communication

7-21

{**********************************************************************}
program pas to ftn mixed;
{ NOTE: You-mu'it also obtain the FORTRAN program named "mixed types." }
{
After compiling pas_to_ftn_mixed and mixed_types, you must bind}
{
them together.
}
{ This program demonstrates passing arguments of several different data}
{ types to a FORTRAN subroutine.
}
TYPE

last_names = array[1 .. 10] of char;
two_by_four = array[1 .. 2, 1 .. 4] of integer16;
complex = record
r
real;
imaginary
real;
end;
boolrec
record
bool_var
boolean;
a,b,c
boolean;
end;
VAR

age
lying
name
multi

integer32 := 1000000;
boolrec;
last_names := 'Tucker';
two_by_four := [ [5,8,11,14]
[100, 103, 106, 109] ];
complex := [4.53, 0.98];
c
countl, count2, len: integer16;

procedure print_vals (in age: integer32; in lying: boolrec;
in name: last_names; in multi
two_by_four;
in c : complex);
{ This procedure prints the values of the variables. }
BEGIN
writeln ('Age = " age:5);
writeln ('Lying = " lying.bool_var:5);
writeln ('Name = " name);
writeln ('Multi = ');
for count 1 := 1 to 2 do
begin
for count2 := 1 to 4 do
write(multi[countl,count2]:5);
writeln;
end; {for}
writeln ('Complex
c.r:4:2, ',', c.imaginary:5:2);
END;
{end procedure print_vals}
{continued}
{**********************************************************************}
Figure 7-9. An Example of Calling FORTRAN: pas_to_ftn_mixed

7-22

External Routines and
Cross-Language Communication

{**********************************************************************}
{ Note "extra" len argument in the parameter list of mixed_types.}
procedure mixed_types (in out age : integer32;
in out lying : boolrec;
in out name : last _names;
in out multi : two_by_four;
in out c : complex;
in out len : integer16) ;
extern;
BEGIN {main program}
lying.bool_var := true;
writeln (chr(10) , 'Before calling FORTRAN', chr(10»;
print_vals(age, lying, name, multi, c);
mixed_types (age, lying, name, multi, c, len);
writeln (chr(10), 'After calling FORTRAN', chr(10»;
print_vals(age, lying, name, multi, c);
END.
{**********************************************************************}
Figure 7-9. An Example of Calling FORTRAN: pas_to_ftn_mixed (Cont.)

*********************************************************************
* This is a FORTRAN subroutine for assigning new values to arguments
* passed in from a Pascal program. It demonstrates how to pass a
* variety of data types.
subroutine mixed_types (a,l,n,m,c)
integer*4
a
{ Declare variables.}
logical
1
character*10 n
integer*2
m(4,2), count
complex
c
* Make reassignments.
a = a * 2
1 = .false.
n = 'Carter'
do count = 1,4
m(count,l)
enddo

m(count,l) + 1000

c = (2.0, -2.0)
end
*********************************************************************
Figure 7-10. An Example of Calling FORTRAN: mixed_types

External Routines and
Cross-Language Communication

7-23

These programs are available online and are named pas_to_ftn_mixed and mixed_types.
If you compile, bind, and execute these programs, you get the following output:
Before calling FORTRAN

= 1000000
Lying = TRUE
Name = Tucker
Multi
5
8
11
14
100 103 106 109
Complex = 4.53, 0.98
Age

After calling FORTRAN
Age = 2000000
Lying = FALSE
Name = Carter
Multi
1005 1008 1011 1014
100 103 106 109
Complex = 2.00,-2.00

7.7.5 Passing Procedures and Functions
Passing a Pascal routine to a FORTRAN subprogram is complicated by the fact that FORTRAN expects all arguments to be passed by reference. For this reason, you must pass a
pointer to the Pascal routine, not the routine itself. To do this, you declare the type of
the parameter as a procedure or function pointer, and pass the address of the routine as
the actual argument.
The Pascal program shown in Figure 7-11 passes a function, an unsorted array, and the
size of the array to a FORTRAN subroutine. The function can be either ascend, which
compares two integers for an ascending sort, or descend, which compares two integers for
a descending sort. The FORTRAN subroutine sort_array calls one of the two Pascal functions when it sorts the array.

7-24

External Routines and
Cross-Language Communication

{**********************************************************************}
program pass_func_to_fortran_p(input,output);
{
{
{
{
{

NOTE: To execute this program, you must also obtain the
}
Pascal functions in the module "funcs_for_fortran_p" and the }
FORTRAN program named "sort_array_f". After compiling
}
pass_func_to_fortran_p, funcs_for_fortran_p, and
}
sort_array_f, you must link them together.
}

type
arrtype = array [1 .. 10] of integer32;
proc_ptr_type
Afunction(var x, y :integer32)

integer32;

var
direction, i : integer32;
intarr: arrtype .- [ 27, 19, 34, 65, 7, 9, 2, 12, 75, 1 ];
SIZE : integer32 := 10;
procedure sort_array(in compare : proc_ptr_type;
var size
integer32;
var list: arrtype); extern;
function ascend(var a, b : integer32) : integer32; extern;
function descend(var a, b : integer32) : integer32; extern;
begin
write1n('Enter 1 to sort in ascending order, '
'2 to sort in descending order: ');
read1n(direction);
if direction = 1 then
sort_array (addr (ascend) , SIZE, intarr)
else
sort_array (addr (descend) , SIZE, intarr);
for i := 1 to SIZE do
write1n(intarr[i]);
end.
{**********************************************************************}
Figure 7-11. An Example of Calling FORTRAN: pass_func_to_fortran_p

Pascal can take the address of an external routine, but not of an internal routine. Because
FORTRAN requires us to pass the address of the Pascal routine, we have to declare the
ascend and descend functions extern in the Pascal program and define them in the separately compiled module shown in Figure 7-12.

External Routines and
Cross-Language Communication

7-25

{**********************************************************************}
MODULE funcs_for_fortran_p;
{
{
{
{
{

NOTE: To execute this program, you must also obtain the
Pascal program "pass_func_to_fortran_p" and the FORTRAN
program named "sort_array_f". After compiling
pass_func_to_fortran_p, funcs_for_fortran_p, and
sort_array_f, you must link them together.

}
}
}
}
}

FUNCTION ascend(var a, b : integer32) : integer32;
BEGIN
if a > b then
ascend := 1
else
ascend := 0;
END;
FUNCTION descend(var a, b
BEGIN
if b > a then
descend .- 1
else
descend .- 0;
END;

integer32)

integer32;

{**********************************************************************}
Figure 7-12. An Example of Calling FORTRAN: funcs_for_fortran_p

7-26

External Routines and
Cross-Language Communication

The FORTRAN subroutine is shown in Figure 7-13.
C***********************************************************************
C Program name is "sort_array_f".
C If you use f77, compile with the -WO,-nuc option.
C NOTE: You must also obtain the Pascal program named
"pass_func_to_fortranJ>". After compiling
pass_func_to_fortran_p and sort_arraY_f, you must
link them together.
SUBROUTINE sort_array (compare, size, list)
INTEGER*4 compare, size, list(size)
INTEGER*4 i, temp
LOGICAL out_of_order

C
C
C

out_of_order = .TRUE.
DO WHILE (out_of_order)
out_of_order = . FALSE.
DO 10 i = 1, size-1
IF (COMPARE (list (i) , list(i+1».EQ.1) THEN
out_of_order = . TRUE.
temp = list(i)
list(i) = list(i+1)
list(i+1) = temp
END IF
10
CONTINUE
END DO
RETURN
END
C***********************************************************************
Figure 7-13. An Example of Calling FORTRAN: sort_array_f

External Routines and
Cross-Language Communication

7-27

You can compile, link, and execute this program as follows:
$ pas pass_func_to_fortran_p.pas

No errors, no warnings, no info msgs, Pascal compiler 6SK
$ pas funcs_for_fortran_p.pas

No errors, no warnings, no info msgs, Pascal compiler 6SK
$ lusr/bin/f77 -c -WO,-nuc sort_array_f.f

sort_array_f.f:
$ bind pass_func_to_fortran_p.bin funcs_for_fortran_p.bin sort_array_f.o -b pass

All Globals are resolved.
$ pass

Enter 1 to sort in ascending order, 2 to sort in descending order:
1

1
2
7
9
12
19
27
34

65
75

7.8 Calling a C Routine from Pascal
In addition to allowing you to call FORTRAN routines, Domain Pascal permits you to call
routines written in Domain/C source code. To accomplish this, perform the following steps:
1.

Write source code in Domain Pascal that calls a routine. Compile it with the Domain Pascal compiler. Domain Pascal creates an object file.

2.

Write source code in Domain/C. Compile it with the Domain/C compiler.
Domain/C creates an object file.

3.

Bind the object file(s) the Pascal compiler created with the object file(s) the C
compiler created, using the -b binder option to create one executable object file.

4.

Execute the object file as you would execute any other object file.

The remainder of this chapter describes steps 1 and 2. For information on steps 3 and 4,
see Chapter 6.

NOTE:

7-28

. The following sections explain how to call Domain/C from Domain Pascal. If you want to learn how to call Pascal from C, see
the DomainlC Language Reference.

External Routines and
Cross-Language Communication

7.8.1 Reconciling Differences in Argument Passing
Pascal usually passes arguments by reference, while C usually passes them by value. In order to pass arguments by reference correctly, you must declare your parameters in C to be
pointers so that they can take the addresses Pascal passes in. The examples in the following sections demonstrate how to do this.
If you want to pass your Pascal arguments by value, you must use the val_param or

c_param routine option in your procedure or function heading. See the "val.J'aram-Extension" and "c.J'aram-Extension" sections of Chapter 5 for more details about these routine options.

7.8.2

Case-Sensitivity Issues
When the Domain Pascal compiler parses a program, it makes all identifier names lowercase, regardless of the way you type the names in your source code. In contrast, the 00main/C compiler is case sensitive.
It is important to understand this when you are calling C from Pascal. In order to make
identifier names match up at bind time, you should always use lowercase letters in your C
subprograms. That way, they will match the always-Iowercased identifier names in the Pascal program.

7.8.3 Using Registers
By default, a Pascal function returning the value of a pointer type variable puts that value
in address register AO, whereas, by default, C routines return values in data register DO. If
you want to pass variables through registers, you should use the dO_return routine option
for Pascal routines that call C routines. The dO_return option tells the compiler that any
routines called by the routine with the dO_return option should return values to the DO
register. See the "dO_return-Extension" section of Chapter 5 for details about this routine option.

External Routines and
Cross-Language Communication

7-29

7.9 Data Type Correspondence for Pascal and C
Before you try to pass data between Domain Pascal and Domain/C, you must understand
how Pascal data types correspond to C data types. Table 7-2 lists these correspondences.

Table 7-2. Domain Pascal and Domain/C Data Types
Domain Pascal

Domain/C

char
integer, integer16
integer32
real, single
double
enumerated types
record
variant record
pointer(A)

char
short
int, long
float
double
enum
struct
union
pointer(*)

boolean
set

none
none

[byte] 0 .. 255
0 .. 65335
O. .4295967295

unsigned char
unsigned short
unsigned long

As the table shows, the integer, real, and character data types in both languages correspond very well. For example, Pascal's integer16 data type is identical to C's short data
type, and a double variable in Pascal is the same as a double in C.
However, there are some important differences. Domain/C has no equivalent types for Pascal's boolean or set types, although you can simulate these types.

7.9.1 Passing Integers and Real Numbers
Since the Pascal and C integer and real data types match up so well, it is fairly easy to
pass data of these types between the two languages. Make sure that all arguments agree in
type and size, either by declaration or by casting.
Figure 7-14 shows a Pascal program that solicits the values for two sides of a right triangle.
It then sends those values into the C function shown in Figure 7-15, which computes and
returns the length of the hypotenuse. The arguments for the triangle's sides are 32 bits
each, while the result is 64 bits.

7-30

External Routines and
Cross-Language Communication

{**********************************************************************}
PROGRAM pas_to_c_hypo;
{ NOTE: You must also obtain the C program named "hypot_c". }
{
After compiling pas_to_c_hypo and hypot_c, you must }
{
bind them together.
}
{ This program passes two real arguments to a C function.
}
VAR

legl, leg2 : single;
function hypot_c(in out legl, leg2

single)

double; extern;

BEGIN
writeln('This program calculates the hypotenuse of a right triangle ');
writeln ('given the length of its two sides.');
write ('Enter the lengths of the two sides: ');
readln (legl,leg2);
writeln ('The triangle"s hypotenuse is:

hypot_c(legl,leg2):5:2);

END.
{**********************************************************************}
Figure 7-14. An Example of Calling C: pas_to_c_hypo

/***************************************************************/
/* This is a C function for finding the hypotenuse of a
*/
/* right triangle. The arguments must be declared as pointers.*/
#include 
double hypot_c(a,b)
float *a,*b;
{
double result;
result = sqrt«*a * *a) + (*b * *b»;
return(result);
}
/***************************************************************/
Figure 7-15. An Example of Calling C: hypot_c

These programs are available online and are named pas_to_c_hypo and hypot_c. Following is a sample execution of the bound program.
This program calculates the hypotenuse of a right triangle
given the length of its two sides.
Enter the lengths of the two sides: 3 4
The triangle's hypotenuse is: 5.00

External Routines and
Cross-Language Communication

7-31

7.9.2 Passing Strings
In C, the end of a string is marked by a null character. Therefore, when a Pascal routine
receives a string from C, the string probably includes a terminating null character that
needs to be stripped. Conversely, when a Pascal routine sends a string to a C function, it
should append a null character so that the C function can handle the string properly.
The simplest way to pass strings between Pascal and C routines is to use variable-length
strings on the Pascal side. You can then use the ctop procedure to strip the null character
from a C string, and the ptoc procedure to add a null character to a Pascal string.
The Pascal program in Figure 7-16 passes a variable-length string to the C function capitalize, shown in Figure 7-17, which converts all characters in the string to uppercase.

{**********************************************************************}
PROGRAM pas_to_c_strings;
{This program demonstrates how to pass variable-length strings to }
{and from C routines.
}
TYPE
name
varying [15] of char;
arg = array[1 .. 15] of char;
VAR

first name : name;
last_name
: name;
extern;
PROCEDURE capitalize (in out first_name :arg)
BEGIN
first_name := 'sherlock';
last_name := 'holmes';
write('Before calling C, this is the name:' first_name);
writeln(' ',last_name);
ptoc(first_name);
ptoc(last_name);
capitalize (first_name.body);
capitalize (last_name.body);
ctop(first_name);
ctop(last_name);
write('After calling C, this is the name:' first_name);
writeln(' , ,last_name);
END.
{**********************************************************************}
Figure 7-16. An Example of Calling C: pas_to_c_stringsl

7-32

External Routines and
Cross-Language Communication

/***************************************************************/
/* This function converts all characters in the string */
/* argument to uppercase */
'include 
void capitalize (s1)
char *s1;
{

while (*s1)
{

*s1 = toupper(*s1) ;
s1++;
}
}

/***************************************************************/
Figure 7-17. An Example of Calling C: capitalize

Following is a sample execution of the bound program.
Before calling C, this is the name: sherlock holmes
After calling C, this is the name: SHERLOCK HOLMES
If you use fixed-length arrays rather than varying arrays, you need to handle the null
character explicitly. The Pascal program in Figure 7-18 sends two strings to a C routine

that prompts a user for new values and then sends the new string values back. The C
function in Figure 7-19 strips the trailing null character from the strings.

External Routines and
Cross-Language Communication

7-33

{**********************************************************************}
PROGRAM pas_to_c_strings2;
{ NOTE: You must also obtain the C program named "pass char".
After compiling pas_to_c_strings2 and pass_char, you must
{
{
bind them together.
{ This program shows how to pass character variables to from a C
{ routine.}

}
}
}
}

TYPE

fn
In

array[l .. lO] of char;
array[l .. 15] of char;

VAR
first_name
last_name

fn;
In;

procedure pass_char(in out first name
in out last_name
BEGIN
first_name := 'Sherlock';
last_name := 'Holmes';
write('Before calling C, the name is
writeln(last_name:-l);
pass_char (first_name , last_name);
write('After calling C, the name is'
writeln(last_name:-l);
END.

fn;
In); extern;

first_name:-l,' ');
first_name:-l,' ');

{**********************************************************************}
Figure 7-18. An Example of Calling C: pas_to_c_strings2

7-34

External Routines and
Cross-Language Communication

/**********************************************************************/
/* NOTE: You must also get the Pascal program named pas_to_strings2. */
/*
After compiling pas_to_c_strings2 and pass_char, you must
*/
/*
bind the two together.
*/
#include 
/* This C function takes two strings, prompts the user for new values,*/
/* and strips off the null characters before sending the strings back.*/
pass_char (first_name, last_name)
char *first_name, *last_name;
{

short i, j;
char hold_first [10] , hold_last [15] ;
printf ("\nEnter the first name and last name of a detective:
scanf ("%s%s", hold_first, hold_last);

It);

/* Strip off the null character C automatically appends to any string */
/* and blank out any previously used places in the name strings.
*/
for (i = 0; hold_first [i] != '\0'; i++)
first_name[i] = hold_first[i];
for (j = i; j < 10; j++)
first_name[j] = ' ';
for (i = 0; hold_last[i] != '\0'; i++)
last_name[i] = hold_last[i];
for (j = i; j < 15; j++)
last_name[j] = ' ';
}

/**********************************************************************/
Figure 7-19. An Example 0/ Calling C: pass_char

These programs are available online and are named pas_to_c_strings2 and pass_char.
Following is a sample execution of the bound program.

Before calling C, the name is Sherlock Holmes
Enter the first name and last name of a detective: Jane
After calling C, the name is Jane Marple

~arple

External Routines and
Cross-Language Communication

7-35

7.9.3 Passing Arrays
Single-dimensional arrays (except for boolean arrays) of the two languages correspond
fairly well. The major difference is that in C, array subscripts always begin at zero, while
Pascal allows the programmer to determine the subscript at which the array begins. In order to make arrays match up, you should define your Pascal subscripts to begin at zero.
For example:

In Domain Pascal

In DomainlC

x - array[0 .. 9] of char
char x[10]
x - array[0 .. 49] of integer short x[50]
x = array[0 .. 19] of single float x[20]
With such declarations, the following code fragments access the identical elements in an
array:

In Domain Pascal

In DomainlC

for i := 0 to 9 do
my_array[i] := i;

for (i = 0; i < 10; i++)
my_array[i]
i;

As described earlier, Pascal by default passes arguments by reference, so when it sends an
array argument to a routine, it actually is sending the address of the first element in the
array. C gets that address when you declare the array variable in C to be a pointer. This
means you don't have to specify the size of a single-dimensional array that your C subprogram receives from Pascal.
That is, if your Pascal program includes the followingtype
x

= array [0 .. 9] of integer32;

var
my_array : x;

your C routine heading can look like this:
pass_array (my_array)
long *my_array; I*Notice that there's no indication of the
array's dimensions.
*1
The example in Figure 7-20 and Figure 7-21 shows a Pascal program that loads five userentered scores into a single-dimensional array and then sends that array to a C prpcedure
to compute the average. Notice that the argument size determines the dimension of the
array; the C declaration of the array contains no dimensioning information.

7-36

External Routines and
Cross-Language Communication

{**********************************************************************}
pas_to_c_arrays;
{ NOTE: You must also obtain the C program named "single_dim". }
{
After compiling pas_to_c_arrays and single_dim, you must}
{
bind them together.
}
{ This program passes a one-dimensional array to a C routine.
}
TYPE
scores
array [0 .. 4] of integer;
PROGRAM

VAR

grades

scores;
integer;
single;
result
size
integer := 5;
procedure single_dim(out result
single;
in
size
integer;
in grades
scores); extern;
BEGIN
writeln ('Enter', size:!, ' integer test scores separated by spaces.');
for i := 0 to 4 do
read(grades[i]);
readln;
sing1e_dim(resu1t, size, grades);
writeln ('C computed the average of the test scores, and it is:
result:5:2);
END.
{**********************************************************************}
i, j

Figure 7-20. An Example of Calling C: pas_to_c_arrays

1**********************************************************************1
I*NOTE: You must also get the Pascal program named pas_to_c_arrays
*1
1*
After compiling pas_to_c_arrays and single_dim, you must bind *1
1*
them together.
*1
1* This function computes the average of an array of integers.
*1
sing1e_dim(resu1t,size,grades)
float *resu1t;
short *size, *grades;
{
short i,tota1;
total = 0;
for (i = 0; i < *size; i++)
total += grades[i];
*resu1t = total I 5.0;
}

1* Add up array values *1
1* and then compute
*1
1* average.
*1

1**********************************************************************1
Figure

7-21~

An Example of Calling C: single_dim

External Routines and
Cross-Language Communication

7-37

These programs are available online and are named pas_to_c_arrays and single_dim. Following is a sample execution of the bound program.

Enter 5 integer test scores separated by spaces.
85 92 100 79 96

C computed the average of the test scores, and it is: 90.40
Multidimensional arrays in the two languages also correspond fairly well. Both languages
store such arrays in the same order; that is, the rightmost subscript varies fastest. So these
two arrays would be stored identically:

In Domain Pascal

x = array[0 .. 1,0 .. 2] of integer32;

In DomainlC

long *x[2] [3] ;

7.9.4 Passing Pointers
Passing pointers between Pascal and C is fairly straightforward. In both cases, pointers are
4-byte entities. The example in Figure 7-22 and Figure 7-23 shows a simple linked-list
application. The Pascal program creates the first element of the list and then calls the C
routine append to add new elements to the list. The routine printlist is a Pascal routine
that prints the entire list. In addition to illustrating how to pass pointers, this example also
shows the correspondence of Pascal records to C structures.

7-38

External Routines and
Cross-Language Communication

{**********************************************************************}
PROGRAM pas_to_c_ptrs;
{This program calls an external C function that appends an item}
{to a linked list. The program then prints the contents of the}
{list. You must also compile the C module append and bind it
}
{with pas_to_c_ptrs in order to obtain an executable file.
}
TYPE
link
"'list;
list
record
data : char;
p : link;
end;
VAR

last let
val
base, first

char := 'z';
char;
link;

PROCEDURE append (in base: link;
in val: char); EXTERN;
PROCEDURE printlist;
{printlist prints the data in each member of the linked list }
BEGIN
while base <> nil do
begin
writeln(base .... data);
base: =base'" . p ;
end;
END;
BEGIN {main program}
base:=nil;
new(first);
first .... data := 'a';
{Assign to first element of the list
}
first .... p := base;
{The first element is also the last so
}
{set the pointer to nil
}
base := first;
{Base points to the beginning of the list }
val : = 'b';
append (base,val);
append(base, last_let);
printlist;
{Call procedure to print contents of list.}
END. {main program}
{**********************************************************************}
Figure 7-22. An Example of Calling C: pas_to_c_ptrs

External Routines and
Cross-Language Communication

7-39

/**********************************************************************/
/* C function that appends items to a linked list.
*/
#module pass_pointers_c
#include 
typedef struct
{

char data;
struct list *next;
} list;
void append (base, val)
list **base;
char *val;

/* Note extra level of indirection */
/* because arguments are passed by */
/* reference
*/

{

list *newdata, *last_rec;
last_ree = *base;

/* Point temp variable last_rec at */
/* the beginning of the list.
*/
newdata = (list*)malloc(sizeof(list»;
/* Allocate memory for new element. */
while (last_rec->next != NULL)
last_rec = last_rec->next;

/* Walk to the end of the list.

*/

last_ree->next = newdata;
newdata->data
*val;
newdata->next = NULL;

/* Add new data.

*/

}
/**********************************************************************/
Figure 7-23. An Example of Calling C: append

These programs are available online and are named pas_to_c_ptrs and append. If you
compile and bind the programs, and execute the result, you get this output:

a
b
z

7.9.S Passing Procedures and Functions
You may pass a Pascal procedure or function as an argument to a C function. The Pascal
program shown in Figure 7-25 passes a function, an unsorted array, and the size of the
array to a C function. The function being passed can be either ascend, which compares
two integers for an ascending sort, or descend, which compares two integers for a descending sort. The C function sort_array calls one of the two Pascal functions when it sorts the
array.

7-40

External Routines and
Cross-Language Communication

C expects function arguments to be passed by value. Therefore, the Pascal program declares the first parameter of the C function sort_array to be a function, and declares the
C function with the c_param option. This use of c_param makes Pascal pass the other
parameters by value as well, so that the C function does not declare them as pointers.
(See Section 5.5.12 for information about c_param.)
Figure 7-24 shows the C function.

/**********************************************************************/
/* NOTE: Program name is "sort_array_c". You must also
*
obtain the C program named "pass_func_to_c_p".
*
After compiling pass_func_to_c_p and sort_array_c,
*
you must link them together.
*/

void sort_array(int (*compare)(), int size, int list[])
{
do {
out_of_order = 0;
for (i = 0; i < size-I; i++)
if (compare(list[i], list[i+l]»
out_of_order = 1;
temp = list[i];
list[i] = list[i+l];
list[i+l] = temp;
}
} while (out_of_order);

{

}
/**********************************************************************/
Figure 7-24. An Example of Calling C: sort_array_c

External Routines and
Cross-Language Communication

7-41

{**********************************************************************}
program pass_func_to_c_p(input,output);
{
{
{
{

Program name is "pass_func_to_c_p". To execute
this program, you must also obtain the C program named
"sort_array_c". After compiling pass_func_to_c_p and
sort_array_c, you must link them together.

}
}
}
}

const
SIZE = 10;
type
arrtype = array [1 .. SIZE] of integer32;
var
direction, i : integer32;
intarr : arrtype := [ 27, 19, 34, 65, 7, 9, 2, 12, 75, 1 ];
procedure sort_array(function compare (a, b : integer32)
integer32;
size : integer32;
in out list: arrtype);
options (c_param, extern);
function ascend(a, b
begin
if a > b then
ascend .- 1
else
ascend .- 0;
end;

integer32) : integer32;

function descend(a, b
begin
if b > a then
descend .- 1
else
descend .- 0;
end;

integer32)

integer32;

begin
writeln('Enter 1 to sort in ascending order, '
'2 to sort in descending order: ');
readln(direction);
if direction = 1 then
sort_array (ascend, SIZE, intarr)
else
sort_array(descend,SIZE, intarr);
for i := 1 to SIZE do
writeln(intarr[i]);
end.
{**********************************************************************}

7-42

External Routines and
Cross-Language Communication

You can compile, link, and execute the program as follows:
$ pas pass_func_to_c_p.pas
No errors, no warnings, no info msgs, Pascal compiler 6SK ...
$ Ibin/cc -c sort_array_c.c
$ bind pass_func_to_c_p.bin sort_array_c.o -b pass
All Globals are resolved.
$ pass
Enter 1 to sort in ascending order, 2 to sort in descending order:

2

75
65
34
27
19
12
9
7
2
1

7.9.6 Data Sharing Between C and Pascal
There are two ways to declare global variables in Pascal and C so that the linker can resolve references:
•

Declare the variables so that they are placed in the .data or .bss sections.

•

Declare the variables so that they are placed in named overlay sections.

We describe these two methods in the following sections.

7.9.6.1 Declaring .data and .bss Global Variables
When you use define to define an external variable, the compiler places that variable in
the .data section of the the object file. When you declare a variable as extern, that variable is listed as an unresolved reference in the symbol table. If you want these global variables to be compatible with global variables in C programs, you must compile with Ibin/cc
or use the -bss switch with Icom/cc.
There are several scenarios for declaring and defining variables in Pascal and C. The
three most common are described below:
•

Define a variable in Pascal and allude to it in C. For example, the Pascal
source file might contain the following:

VAR

x: DEFINE INTEGER32 .- 0;

and the C file would contain:
extern int x;

External Routines and
Cross-Language Communication

7-43

In this case, the definition in the Pascal module causes the compiler to allocate
space for x in the .data section. The C declaration produces an undefined reference to x in the symbol table, which is resolved by the linker.
•

Define a variable in C (initialized) and allude to it in Pascal. For example,
the C file would contain:

int x = 10;
and the Pascal source file would declare x as:

VAR x: EXTERN INTEGER32;
In this case, the definition of x in the C module forces the C compiler to allocate
space for x in the .data section. The declaration of x in the Pascal file causes
the compiler to produce an undefined reference to x in the symbol table, which is
resolved by the linker.
•

Define a variable in C (uninitialized) and allude to it in Pascal. For example,
the C file would contain:

int x;
and the Pascal source file would declare x as:

VAR x: EXTERN INTEGER32;
In this case, the un initialized definition of x in the C module causes the C compiler to make a "weakly defined" entry in the symbol table. The declaration of x
in the Pascal file causes the compiler to produce an undefined reference to x in
the symbol table. The linker then places x in the . bss section, initialized to zero,
and resolves the Pascal reference.
It is also possible to define the same variable in C and in Pascal, as long as only one or
neither of the definitions contain initializers. If both definitions contain initializers, the

linker will report an error.
In the following example, we define the global variable xx at the top of the C source file;
the function mainO prints the initial value of xx and then calls the C routine add_threeO
which adds 3 to xx; finally, add_three calls the Pascal procedure sub_two which subtracts 2 from xx.
The Pascal routine is:

PROCEDURE sub_two;
VAR
xx : EXTERN INTEGER32;
BEGIN
xx := xx - 2;
WRITELN('Value of xx after sub_two():' ,xx);
END;

7-44

External Routines and
Cross-Language Communication

The C routines are:
#module global_var_c
#include 
/* Definition of xx */
int xx = 1;
int maine void
{
extern void add_three( void );
printf( "Initial value of xx: % character. *
Domain Pascal sends errors to this
stream. By default, this is the transcript pad, but you can redirect this
stream with the >? character sequence. *

*Getting Started With Domain/OS explains how to redirect I/O.

8.1.5 Interactive 110
Domain Pascal uses the following system for interactive processing of the standard input
(input) and standard output (output) files. Domain Pascal does not actually open input
and output until the program first refers to them. When Domain Pascal finds the first reference to input in your program, it calls reset (input) . Reset expects to fill the file buffer
variable with the first char of a text file, which means that reset (input) can cause a request for input.
For example, consider the following program:

PROGRAM lazy;

{This program is WRONG!}

VAR

c : char;
BEGIN
while not eof(input) do
begin
write('enter a letter or an EOF --');
readln(c);
end;

END.

8-4

Input· and Output

If you run this program, you might expect results like the following:

enter a letter or an EOF -- A
enter a letter or an EOF -- Z
enter a letter of an EOF -- 
However, in reality, the program does not produce those expected results. That's because
the first reference to input is in the eof function. This causes the system to perform a
reset (input) prior to the test for eof. Reset expects to fill the file buffer, so the test for
eof actually results in a request for input, for which, unfortunately, the user is not
prompted. Therefore, running the program results in the following:
A
{here the user is required to enter input for which he/she is not prompted}
enter a letter or an EOF -- Z
enter a letter or an EOF -- 
To eliminate this problem, you must take advantage of a feature of reset known as delayed access. Delayed access means that data will not be supplied to fill the input buffer at
the reset, but rather at the next reference to the file. Since reset initiates delayed access,
and since eof and eoln cause the file buffer to be filled, you must place the first prompt
for input before any tests for eof or eoln. The data you enter in response to the prompt is
retained until you make another reference to the input file.
The following shows how to use delayed access to make the previous example work correctly:

PROGRAM interactive;
VAR

c : char;
BEGIN
write ('enter a letter or an EOF -- ');
while not eof(input) do
begin
readln(c) ;
write ('enter a letter or an EOF -- ');
end;
END.

8.1.6 Stream Markers
When you open a file, the operating system assigns a stream marker to the file. A stream
marker is a pointer that points to the current position inside the open file. As you read
from or write to the file, the operating system moves the stream marker forward in the file.
The stream marker points to the byte (or record) that the system can next access. When
you open the file with the Domain Pascal open procedure, the stream marker initially
points to the beginning of the file. Using lOS calls, you can open the file with the stream
marker initially pointing to the end of file so that you can append to the file.

Input and Output

8-5

I

If you are using lOS calls, you directly control the stream marker. If you are using Domain

Pascal I/O procedures, you control the stream marker indirectly through the procedures
you call.

8.1.7 File Organization
Although Domain/OS supports a variety of file types, the standard I/O library and UNIX
functions allow you to access only ASCII files. These are files that consist of a string of
ASCII characters. (The Domain Pascal ISO Latin-l character set includes these characters.) You can create your own records within such a file by entering a delimiting character, but there is no predefined record structure. Also, you can read and write bytes in
numeric rather than string formats, but it is your responsibility to keep track of how data is
represented.
The default file type created by Domain/OS is unstruct. An unstruct file is an ordinary
text file that is fully compatible with text files produced by programs compiled under a
UNIX system. The system stores a text file consisting of ASCII characters. The operating
system makes no attempt to organize or structure the data in a text file. That is, '908' is
stored in the three bytes it takes to hold the ASCII values of digit '9', digit '0', and digit
'8', rather than structuring it into the value of integer 908.
By default, the maximum length of each line of a text file that Domain Pascal opens is 256
characters. You can change this to a larger length by using the optional buffer_size parameter with the open statement. (See the listing for "Open" in Chapter 4 for details
about the buffer_size parameter.) By "line", we mean all the characters between two
end-of-line characters. No text file can have more than 32767 lines.

8.2 Predeclared Domain Pascal lID Procedures
The encyclopedia of Domain Pascal code in Chapter 4 details the syntax of each of the
predeclared Domain Pascal 110 procedures. This section provides a global view of these
procedures.

8.2.1 Creating and Opening a New File
You can create a permanent file or a temporary file. The operating system deletes a temporary file as soon as the program that created it ends. Permanent files last beyond program execution. In fact, they last until you explicitly delete them.
To create a permanent file, you call the open procedure and specify 'NEW' as the
file_history. This not only creates the file, but opens it for future access as well.
To create a temporary file, you call the rewrite procedure.

8-6

Input and Output

Both open and rewrite take a file or text variable as an argument. In either case, Domain
Pascal creates an unstruct file. If the file variable has the file data type, however, you can
only read and write objects that have the file's base type. For text type files, you can access each byte one at a time.
NOTE:

Pre-SR10 versions of Domain Pascal created special record structured Domain files (called rec files) when you opened a file. For
compatibility with older versions, you can use the current version
of Domain Pascal to manipulate rec files, but you can no longer
create rec files. When you open an existing file, Domain Pascal
checks whether it is a rec or unstruct file and accesses it appropriately. Whenever you open a new file, however, Domain Pascal
creates an unstruct file.

8.2.2 Opening an Existing File
To open an existing file for future access, you call the open procedure and specify either
'OLD' or 'UNKNOWN' as the file_history.
Note that you do not have to explicitly open the shell transcript pad. It is already open.
(See the "Default Input/Output Streams" section earlier in this chapter for details.)

8.2.3 Reading from a File
In order to read from an open file, you must call the reset procedure. Reset tells the system to treat the open file as a read-only file. You can change the open file to a write-only
file with the rewrite procedure.
After calling reset, you are free to call any or all of the three input procedures that Domain Pascal supports, namely, read, readln, and get. All three procedures read information from the specified file and assign it the specified variable(s).

Input and Output

8-7

The following list describes the differences among the three procedures:
•

Get can access both file type files and text type files. Use it to assign the contents
of the next record or character in a file to a file buffer variable.

•

Read can access both file type files and text type files. Use it to read information
from the specified file into the given variables. After reading a record (if a file
type file) or a character (if a text type file), read positions the stream marker to
point to the next record or character in the file.

•

Readln can access text type files only. It is similar to read except that after reading the information, readln sets the stream marker to the character immediately
after the next end-of-line character.

It is often useful to know when the stream marker has reached the end of the line or the
end of the file. You can use eoln to test for the end of line, and eof to test for the end of
file.
Domain Pascal supports the find procedure as an extension to standard Pascal. Use it to
set the stream marker to point to a particular record in a file type file. This procedure
permits you to skip randomly through a file type file, while the other read procedures imply a sequential path.

8.2.4 Writing to a File
In order to write to a file, you must call the rewrite procedure. (If you used rewrite to
open a temporary file, then you don't have to call rewrite again.) The rewrite procedure
tells the system to treat the open file as a write-only file. You can read from this file only
if you call reset.
Once the file has been opened for writing, you can call any of these four standard Pascal
output procedures: write, writeln, put, and page. Write, writeln, and put are the output
mirrors to read, readln, and get. Using write, writeln, or put causes Domain Pascal to
write the specified information from the specified variable(s) to the specified file.
Here are the differences among the four procedures:

8-8

•

Put can access both file type files or text type files. Use it to assign the contents
of the file buffer variable to the next file position, causing the contents to be written to the file.

•

Write can access both file type files and text type files. Use it to write information from the specified variables into the specified file. After writing a record (if a
file type file) or character (if a text type file), write positions the stream marker
to point to the next record or character in the file.

Input and Output

•

Writeln can access text type files only. It is similar to write except that after writing the information, writeln sets the stream marker to the character immediately
after the next end-of-line character.

•

Page can access text type files only. Use it to insert a formfeed (page advance)
into the file.

In addition to the standard Pascal output procedures, Domain Pascal also supports the replace procedure. Use the replace procedure to substitute a new record for an existing record in a file type file. The replace procedure has the distinction of being an output procedure that you can call only when the file has been open for input. In other words, before you call replace, you must first call open and reset to open the file for reading. The
replace procedure is usually used with find. Use find to skip through a file type file looking for a particular record, then use replace to modify the record in its place.

8.2.5 Closing a File
When a program terminates (naturally or as a result of a fatal error), the operating system
automatically "closes" all open files. "Closing" means that the operating system unlocks
the file. When the operating system closes a file type file, it automatically preserves any
changes made to the file. However, when the operating system closes a text type file that
was open for output, there is a possibility that some modifications won't be preserved. To
ensure that all modifications are kept, make sure that the last output operation on the file
is a writeln.
Domain Pascal supports a close procedure whose purpose is to close a specified open file.
Since the operating system does this automatically at the end of the program, you ordinarily don't have to call close. However, it is good programming practice to close all open
files as soon as your program is finished using them. Open files tie up process resources
and may cause your program to needlessly lock a file that another program wants to access.

-------88-------

Input and Output

8-9

Chapter 9
Diagnostic Messages

The majority of this chapter is devoted to detailing compiler errors, warnings, and information messages. However, we start this chapter with a discussion of the errors reported by
the predeclared procedures open and find, and we end with a discussion of run-time error
messages.

9.1 Errors Reported by Open and Find
The open and find procedures are the only two predeclared Domain Pascal routines that
return an error status parameter. This parameter tells you whether or not the call was
successful. If the call was successful, the operating system returns a value of 0 in the error
status parameter. If the call was not successful, the operating system returns a number
denoting the error. Your program is responsible for handling the error. You may wish to
print the error and terminate execution. Or, you may wish to code your program so that it
can take appropriate action when it encounters an error.
This error status parameter is identical to the error status parameter returned by all system
calls. This is more than coincidental since open and find are executed as stream calls at
run time. In the next section, we summarize the error status parameter as it relates to the
open and find procedures. For complete details on using the error status parameter, refer
to Programming with Domain/OS Calls.

Diagnostic Messages

9-1

9.1.1 Printing Error Messages
To print an error message generated by an errant open or find, you must do the following:
•

Put the following two include directives in your program just after the program
heading:
%INCLUDE '/sys/ins/base.ins.pas';
%INCLUDE '/sys/ins/error.ins.pas';
Make sure you put base.ins.pas before error.ins.pas.

•

Declare the error status parameter with the status_$t data type; for example,

VAR
err stat: status St;
- {status_St i~ declared in base.ins.pas}
•

Specify the error status parameter as the all field of the error status variable; for
example,
OPEN(f, pathnamel, 'NEW', err_stat.all);

•

Call the error_Sprint procedure with the error status parameter as its sole argument; for example,
error Sprint(err stat);
{The-error_$print procedure is defined in error.ins.pas}

The following program puts all the steps together:
Program test;
%INCLUDE '/SYS/INS/BASE.INS.PAS';
%INCLUDE '/SYS/INS/ERROR.INS.PAS';

VAR
text;
status_St;
BEGIN
OPEN(f, 'grok', 'OLD', err_stst.all);
Error_$print(err_stat);
END.
The error_Sprint procedure writes the error or warning message to stdout. If there is no
error or warning, error_ Sprint writes the following message to stdout:
status 0 (OS)

9-2

Diagnostic Messages

9.1.2 Testing for Specific Errors
The previous subsection introduced the status_$t data type and its all field. This section
describes another field in status_$t-the code field. The code field of status_$t contains
a number that corresponds to a particular error. To test for a specific error, compare this
code field against expected errors. Table 9-1 lists the common error codes returned by
open and Table 9-2 lists the common error codes returned by find. The symbolic names
come from the Isys/ins/ios.ins.pas file. To use these symbolic names, all you have to do is
list this file as an include file.

Table 9-1. Common Error Codes Returned by open

Code

Symbolic Name

Cause of Error

1

ios_$not_open

You specified a file_history of 'NEW', but the
pathname existed. Alternatively, the type
UID of this existing file differed from the
type UID of the file you were trying to open.

14

ios_ $already_exists

You specified a file_history of 'NEW', but the
pathname already exists.

21

ios_$name_not_found

You specified a file_history of 'OLD', but the
pathname does not exist.

28

ios_ $object_ not_found

You specified a file_history of 'OLD', but the
operating system cannot locate the disk
containing the pathname (indicates network
problems.)

45

ios_$insufficient_rights

The ACL of the pathname prohibits you from
opening the file.

Table 9-2. Common Error Codes Returned by find

Code

Symbolic Name

Cause of Error

1

ios_$not_open

You called find, but without the file being
open.

9

ios_$end_of_file

You specified a record number greater than
the number of records in the file.

Diagnostic Messages

9-3

For example, consider the following program fragment, which tries to first open pathname
my_bookl. If this pathname exists, the program then attempts to open pathname
my_book2.

Program test;
~INCLUDE '/sys/ins/base.ins.pas';
%INCLUDE '/sys/ins/error.ins.pas';
~INCLUDE '/sys/ins/ios.ins.pas';
VAR

fl, f2
st

text;
status_$t;

BEGIN
open(fl, 'my_bookl', 'NEW', st.all);
if st. code = ios_$already_exists then
open(f2, 'my_book2' , 'NEW', st.all);

9.2 Compiler Error, Warning, and Information Messages
When you compile a program, the compiler reports errors, fatal errors, warnings, and information.
A fatal error indicates a problem severe enough to stop compiler execution.
An error indicates a problem severe enough to prevent the compiler from creating an executable object file.
A warning is less severe than an error; a warning does not prevent the compiler from creating an executable object file. The warning message tells you about a possible ambiguity
in your program for which the compiler believes it can generate the correct code.
Information messages do not prevent the compiler from creating an executable object file.
The purpose of the information messages is to alert you to ways in which you could improve the quality of your code. Information messages tell you about the following types of
things:
•

Alignment of variable and type definitions

•

Actions taken by the optimizer

See the "-info nand -ninfo: Information Messages" section of Chapter 6 for more details
about information messages.
The following pages list the common Domain Pascal compiler error, fatal error, warning,
and information messages, and suggest ways to handle them.
In addition, remember the cardinal rule of Pascal debugging: look for missing semicolons.
For example, suppose the compiler reports an error at line 50, but line 50 appears to be a
correct statement. It's quite likely that you forgot a semicolon at line 49.

9-4

Diagnostic Messages

9.2.1 Error, Fatal Error, Warning, and Information Message Conventions
The error, warning, and information messages listed in the rest of this chapter follow these
conventions:
•

Keywords in the message text are all capitals, since that's the way they appear on
your screen. In the accompanying explanatory text, they are lowercase bold, as
they are elsewhere in this manual.

•

Italicized words in the message text indicate values that the compiler fills in when
generating the message. For example, suppose your program contains the following:

PROGRAM err_test;
VAR
num
integer17;
Because the fragment includes an undefined data type (integer17), it triggers Error 23, which reads:
23

ERROR

Identifier has not been declared in routine name_of_routine.

When you compile, identifier and name_of_routine are filled in like this:

(0003)

num: integer17;
******** Line 3: [Error 023]
routine err test.

INTEGER17 has not been declared in

9.2.2 Error, Warning, and Information Messages
Following are Domain Pascal's compiler error, warning, and information messages.
1

ERROR

Unterminated comment.

You started a comment, but you did not close it, or you closed it with the wrong delimiter.
Comment delimiters must match unless you compile with the -iso switch. If you don't
compile with that switch and you start a comment with {, you must end it with }. Similarly, if you start a comment with (., you must end it with .). If you start a comment
with ", you must end it with ".
2

ERROR

Improper numeric constant.

You specified a base that fell outside the legal range of 2 to 16. For example, you cannot
specify a number in base 32. Perhaps you mistakenly specified the integer first and the
base second. (See the "Integers" section in Chapter 2 for an explanation of base.)

3

ERROR

U nterminated character string.

You started a string with an apostrophe ('), but you forgot to end it with an apostrophe.
See Chapter 2 for a definition of string.

Diagnostic Messages

9-5

4

ERROR

Bad syntax (token).

The compiler encountered token when it was expecting to find something else.

6

ERROR

Period expected at end of program (symbol).

You must finish the program with an end statement followed by a period. The final character that the compiler found in your source code is symbol. Typically, symbol is IEOFI
(an end-of-file character) or a semicolon. The most frequent cause of this error is putting
a semicolon rather than a period after the final end.
7

ERROR

Text following end of program (token).

You have put some text other than a comment after the end of the program. The phrase
"END." marks the end of the program. You can put comments after the end of the program, but you cannot put anything else there.

8

ERROR

PROGRAM or MODULE statement expected (token).

The first noncomment in your source code must be either a program heading or a module
heading. The compiler found token instead of a program or module heading. Domain
Pascal also issues this error when there is some sort of mistake in your program or module heading. Chapter 2 describes the program heading. Chapter 7 describes the module
heading.
10

ERROR

Semicolon expected at end of programlmodule statement (token).

You forgot to end your program or module heading with a semicolon. Domain Pascal encountered token when it was expecting a semicolon.
11

ERROR

Improper declarations syntax (token).

Domain Pascal found an unexpected token when processing a declaration part.
12

ERROR

Improper CONST statement syntax (token).

You made a mistake when declaring a constant. See Chapter 2 for the correct format.
Token is the invalid token that Domain Pascal encountered. A possible trigger for this error
is that you tried to declare two identifiers for the same constant value as in the following
example:

CONST
X,Y

13

ERROR

5;

Improper TYPE statement syntax (token).

You made a mistake in the type declaration part of your program. Domain Pascal encountered token when it was expecting something else. See Chapter 2 for the correct format of the type declaration part. A possible trigger for this error is that you used the
wrong symbol to associate the identifier with its type as in the following example:

TYPE
long := integer32;

9-6

Diagnostic Messages

14

WARNING

Datatype cannot be PACKED.

Domain Pascal only recognizes the packed syntax for records, arrays, sets, and file types.
Datatype is a data type that the compiler doesn't recognize when used with packed. Note
that packed only economizes space when used before array and record declarations.

15

ERROR

Improper type specification (token).

You made some mistake when specifying a data type in the var declaration part. Token
identifies the unexpected part of the var declaration part. For example, the following declaration triggers this error because r is a variable, not a data type:
VAR

r : real;
data: array[l.lO]

of r;

See Chapter 2 for a complete description of the var declaration part.

16

ERROR

Improper enumerated constant syntax (message).

All constants in an enumerated type must be valid identifiers. See Chapter 2 for a definition of identifier. Message identifies the first character or token that did not conform to
the rules for identifiers.
17

ERROR

OF expected in SET specification (token).

When you declared a set type or set variable, you forgot to specify the keyword of in between the word set and the base type. Refer to Chapter 3 for information on declaring set
types. Domain Pascal encountered token rather than the keyword of.
18

ERROR

Improper ARRAY specification syntax (token).

You declared an array incorrectly. See Chapter 3 for details on declaring arrays. Token is
the token that Domain Pascal encountered when it expected to find something else.

19

ERROR

Improper RECORD specification syntax (token).

You declared a record incorrectly. See Chapter 3 for details on declaring records. Domain Pascal encountered token when it expected to find something else. A common trigger of this error is a type declaration such as the following:

TYPE
student = record
a
integer32;
b = boolean; {cause of error.
end;
20

ERROR

should be ':'}

Improper pointer specification (token).

You declared a pointer incorrectly. See Chapter 3 for details on declaring pointers. Domain Pascal encountered token when it expected to find something else. The following
type declaration triggers this error, because the up-arrow (A) can only appear before a type
name, not a type specification:

TYPE

Diagnostic Messages

9-7

I

21

ERROR

Improper VAR statement syntax (token).

In a variable declaration, you probably forgot to specify a semicolon after the data type.
Perhaps you specified a comma instead of a semicolon, or perhaps you did not specify any
punctuation mark at all. This error also occurs if you begin an identifier with a digit (0-9)
or dollar sign ($).

22

ERROR

Parameter list must only be specified when the procedure or function is
declared as FORWARD.

You specified the parameter list for this routine in two places: first when you specified forward or extern and second in the routine heading itself. To correct this error, eliminate
the second parameter list.

23

ERROR

Identifier has not been declared in routine name_of_routine.

Several conditions can trigger this error. You might have used identifier in the code portion
of name_of_routine without identifier being accessible to this routine. Study the "Global
and Local Variables" and "Nested Routines" sections in Chapter 2 to learn about the
scope of declared identifiers.
Another possible trigger for this error is that you tried to make a forward call to a procedure without declaring the procedure with the forward attribute. (See the "Routine Attribute List" section in Chapter 5 for details on the forward attribute.)
This error also can occur if you specify a data type that either is invalid or that you've forgotten to define in the type section of your program.

24

ERROR

Multiple declaration of identifier, previous declaration was on line line_number.

You declared identifier (which could be a data type, variable, constant, label, or routine)
more than once.
25

ERROR

Improper MODULE structure (token).

The compiler was expecting to encounter a procedure or function declaration, but found
token instead. Remember, that unlike a program, the action part of a module must always
be contained inside a named routine.
26

ERROR

Number of array subscripts exceeds limit of eight.

Domain Pascal supports arrays of up to eight dimensions.
29

ERROR

Subrange bound (token) is not scalar.

You were trying to declare an array or subrange, but one of the bounds of the subrange
was not a scalar. The scalar types are integer, Boolean, char, enumerated, and subrange.
The token is the token that Domain Pascal encountered when it was searching for a scalar
expression.

9-8

Diagnostic Messages

30

ERROR

Lower bound of subrange (lower_bound ) is not of the same type as the upper
bound (upper_bound).

You were trying to declare an array or subrange, but the data type of lower_bound is not
the same data type as that of upper_bound. The types must match.
31

ERROR

Lower bound of subrange (le/t_scalar) is greater than the upper bound (right_scalar).

You were trying to declare an array or subrange, but you set the value of the left_scalar to
a higher value than the value of the right_scalar. The left_scalar must be lower than the
right_scalar.

32

ERROR

Base type (type) of SET is not scalar.

You tried to declare a nonscalar type as the base type of a set variable or type. The scalar
types are integer, char, Boolean, enumerated, and subrange. Type is the token that Domain Pascal encountered instead of a scalar type.

33

ERROR

SET elements must be positive (-).

You tried to declare a set with a base type of integer or subrange, but Domain Pascal discovered a negative number in the base type.

34

ERROR

SET exceeds limit of 1024 elements ((token).

You cannot declare a set that exceeds 1024 elements. See the "Internal Representation of
Sets" section in Chapter 3 for details.

35

ERROR

Improper use of (identifier), only a TYPE defined name is valid here.

The compiler was expecting a data type, but you specified an identifier instead. Possibly,
you tried to create a pointer variable with improper declarations like the following:
VAR

x

integer;

y

"x;

See the" Standard Pointer Type" section in Chapter 3 for details on setting up pointer
types.

36

ERROR

Multiple declaration of variable in parameter list.

You declared variable more than once in the parameter list of a procedure or function.

37

ERROR

PROCEDURE/FUNCTION name required (token).

You used the keyword procedure or function without specifying a valid identifier immediately after it. See the "Identifiers" section in Chapter 2 for a definition of a valid identifier. Token is either the name of the invalid identifier or the null set (if you did not supply
any name at all).

Diagnostic Messages

9-9

I

38

ERROR

Improper PROCEDURE/FUNCTION declaration (token).

You were probably confusing procedure with function. A function has a data type, and a
procedure does not; therefore, the following declaration triggers this error:

procedure one (r2 : single) : real;

39

ERROR

Improper parameter declaration ( token).

You did not specify the parameter list of your procedure or function in the correct manner. A common cause of this error is using semicolons incorrectly in the parameter list.
(See Chapter 5 for details on parameter lists.) Domain Pascal encountered token when it
was expecting something else (probably a semicolon).

40

ERROR

Colon expected in FUNCTION declaration (token).

You forgot to put a colon before the type specification of the function; for example, compare the right and wrong ways to declare a function:

FUNCTION pyth_theorem(a : integer16)
real; {Wrong!}
FUNCTION pyth_theorem(a : integer16) : real; {Right }
Domain Pascal found token instead of a colon.

42

ERROR

FUNCTION type specification required.

You forgot to specify a data type for the function itself; for example, compare the right
and wrong ways to declare a function:

{wrong} FUNCTION pyth_theorem(a : integer16);
{right} FUNCTION pyth_theorem(a : integer16)

43

ERROR

real;

CASE type is not scalar.

You specified an expression in a case statement that did not have a scalar data type. The
scalar data types are integer, Boolean, char, enumerated, and subrange. For example, the
following case statement triggers this error:
VAR

r : real;
BEGIN
CASE r OF {error: r is real, but should have been
integer or integer subrange.
}
1 : writeln('One');
2 : writeln('Two');
end;

9-10

Diagnostic Messages

44

ERROR

Constant is not of the correct type for the CASE on line number.

You specified a constant in a case statement that was not the same data type as the expression of the case statement. For example, the following case statement triggers this error:

VAR
r

integer16;

CASE r OF
1.5
writeln('One');
2
end;

45

{error: 1.5 is a real;
it should be integer.}

writeln('Two');

ERROR

(Constant) is outside the subrange of the CASE on line number.

In a CASE statement, you specified a constant that was not within the declared range of
the case.
For example, the following case statement triggers this error because the constant 5 is outside the declared subrange 0 to 3.

VAR
x : 0.3;

BEGIN
CASE x OF
5
46

ERROR

. {error}

Constant has already occurred as a CASE constant on line number.

You specified the same constant more than once in the same case statement. For example, the following case statement triggers this error because constant 6 appears twice:

CASE r OF
4

5,6,7
6

writeln('square root is rational');
writeln('square root is irrational');
writeln('even'); {error}

end;

47

ERROR

Token is not a valid option specifier.

You specified token in an OPTIONS clause, but token is not a valid option. See the "Routine Options" section in Chapter 5 for details.

48

ERROR

Include file name must be quoted (token).

You used the %include directive but forgot to put the name of the include file in apostrophes. Token is the token that Domain Pascal found when it was expecting to find an apostrophe.

Diagnostic Messages

9-11

49

ERROR

Too many include files.

Note that this error can be triggered by include files nested within include files. To correct
this error, you can break the program into separately compiled modules.
50

ERROR

Token is not a recognized option.

You specified token as a compiler directive, but token is not a valid compiler directive.
Refer to the "Compiler Directives" listing in Chapter 4 for a description. Possibly, you put
an extra percent sign (%) in your program. Another possibility is that you specified token
on your compile command line as a compiler option. If you do this, the operating system
returns this error message. See Chapter 6 for a complete list of compiler options. Possibly, you caused this error by trying to compile two files at once, and the compiler interpreted the second file as an (invalid) option.

51

ERROR

Include file pathname is not available.

You specified a pathname for an include file, but either it does not exist or network problems prevent the compiler from accessing it.
52

ERROR

Semicolon expected following option specifier (token).

You specified compiler directive %debug or %eject but forgot to specify a semicolon immediately after the directive. See the "Compiler Directives" listing in Chapter 4.

53

ERROR

Multiple declaration of identifier in RECORD field list.

You specified the same field twice in a record declaration. For example, the following record declaration triggers this error because x is declared twice:
r = record
x
Boolean;
x : integer16;
end;

54

ERROR

{error}

Array bound type is not scalar (datatype).

You specified datatype as the index type of an array. However, datatype must be a scalar
data type. The scalar data types are integer, char, enumerated, subrange, and Boolean.
55

ERROR

Improper LABEL statement syntax (token).

Labels must be unsigned integers or identifiers, but Domain Pascal found token instead.
56

ERROR

Multiple definition of element, previous definition was on line number.

You declared the same element (variable, data type, constant, label, procedure, or function) twice.

9-12

Diagnostic Messages

57

ERROR

Improper usage of identifier, only a LABEL name is valid here.

You used identifier as a label, but you had already declared it as a variable, type, or constant. Possibly, you accidentally put a colon (:) immediately following the identifier in the
action part of your program. The colon could cause the compiler to interpret the identifier
as an illegal label. Perhaps you meant to specify a statement like the following:
x :== 8;
but you forgot the equal sign and ended up specifying the following instead:
x : 8;
58

ERROR

Constant is declared as a CONST name, and cannot be assigned a value.

You mistakenly tried to assign a value to a constant. Perhaps you should have declared
constant as a variable rather than as a constant.
59

ERROR

Improper use of identifier, only a VAR name is valid here.

You tried to assign a value to an identifier that is not a valid variable. Possibly, you tried
to assign a value to a type rather than a variable. For example, code like the following
causes this error:

TYPE

int

integer32;

VAR

int;

q

BEGIN
int
q

60

ERROR

..-

8;
8;

{wrong!}
{Right!}

Improper use of identifier, only a VAR or CONST name is valid here.

You tried to assign the value of a data type or label to a variable. Identifier must be a variable or a constant.

61

ERROR

Token is not an ARRAY.

You specified an expression of the format
TOKEN [ • • •

This format is reserved for specifying a particular element of an array; however, token is
not an array variable. Possibly, you were trying to call a procedure or function and used
brackets rather than parentheses.

62

ERROR

Variable is not a pointer variable.

You tried to dereference a variable that was not declared as a pointer variable. (See the
"Pointer Operations" listing of Chapter 4.)

Diagnostic Messages

9-13

63

ERROR

Token is not a RECORD.

Domain Pascal was expecting a record variable, but it found token instead. (See the "Record Operations" listing of Chapter 4.)

64

ERROR

Token is not a field of record.

Domain Pascal was expecting a field of the record variable, but it found token instead.

65

ERROR

Too many subscripts to array_variable.

You declared array_variable as an n-dimensional array, but you have specified more than
n subscripts for the array at this line.

66

ERROR

Kind_ol_declaration declaration must precede internal PROCEDURE and FUNCTIONS declarations.

You put a routine in the middle of a declaration part. A nested routine must come at the
end of a declaration part (not in the beginning or the middle).

67

ERROR

Improper use of identifier, only a FUNCTION name is valid here.

You probably had no intention of calling a function and are puzzled as to why you got this
message. If you used a statement of the form

IDENTIFIER (TOKEN)
then Domain Pascal assumed that you were trying to call a function. Possibly, you were
trying to access an array, but you used parentheses instead of brackets.

68

ERROR

The types of operand1 and op erand2 are not compatible with the operator operator.

You made a mistake such as specifying (21.0 DIV 3.0). (It's a mistake because div only
accepts integer operands.) See Chapter 4 for a complete list of operators and their valid
operands.

69

ERROR

The type of operand is not compatible with the operator operator.

You made a mistake such as specifying an expression like:

(NOT 3.0)
It's a mistake because not only accepts Boolean operands. See the beginning of Chapter 4
for a summary of operators.

70

ERROR

Incompatible operands [operand1, operand2] to the operator operator.

See Table 4-1 for a summary of operators.

9-14

Diagnostic Messages

71

ERROR

Subscript expr to array name_oJ_array is not of the correct type.

See the" Array Operations" listing in Chapter 4.
73

ERROR

Statement expression is not Boolean.

You were using a non-Boolean expression in a manner reserved for Boolean expressions.
For example, the following program fragment triggers this error because variable int is an
integer, not a Boolean:

VAR
int : integer;
b
Boolean;

if int
then .. {error, int is not a Boolean expr. }
if int=9 then .. {no error, int=9 is a Boolean expr.}
if b
then .. {no error, b is a Boolean expr.
}

74

ERROR

FOR statement index variable is not scalar.

The scalar data types are integer, Boolean, char, enumerated, and subrange. If you specify an index variable with a data type other than one of these five types, Domain Pascal
issues this error. See the for listing in Chapter 4.
75

ERROR

FOR statement initial value expression is not compatible with the index variable.

You specified a start_expression of a different data type than the index variable. See the
for listing in Chapter 4.
77

ERROR

FOR statement limit value expression is not compatible with the index variable.

You specified a stop expression of a different data type than the index variable. See the
for listing in Chapter 4.
79

ERROR

Assignment statement expression is not compatible with the assignment variable.

You tried to assign the value of an expression to a variable, but the data type of the value
and the variable were not compatible. In general, the data type of the expression must
match the data type of the variable; however, there are a few exceptions. For example,
you can assign an integer expression to a real variable (though you cannot do the reverse).
In most cases, this error is just a simple programming mistake, but if you do intend to assign a value to a variable of a different data type, refer to the "Type Transfer Functions"
listing of Chapter 4.
81

ERROR

Too many arguments to routine.

You attempted to call routine, but you tried to pass more arguments to routine than it was
expecting. The number of arguments cannot exceed the number of parameters declared in
the parameter list of the routine. See Chapter 5 for details on parameter passing.

Diagnostic Messages

9-15

82

ERROR

Too few arguments to routine.

You attempted to call routine, but you tried to pass fewer arguments to routine than it was
expecting. If you want to pass n arguments to a routine declaring more than n parameters,
you must use the variable routine attribute (which is described in the "Variable" section in
Chapter 5).

83

ERROR

Argument n to routine is not compatible with the declared argument type.

You tried to call routine, but the nth argument in the call does not have the same data
type as the nth parameter. You can suppress this error by using the univ routine attribute.
See Chapter 5 for details on parameter passing.

84

ERROR

Argument n to routine is not within the declared argument subrange.

You tried to pass a subrange expression as the nth argument to call routine, but the value
of the expression was not within the declared range of the subrange.

85

ERROR

Improper use of element, only a PROCEDURE name is valid here.

Domain Pascal assumed you were trying to call a procedure, but element is not a procedure. Any statement having the following format is assumed to be a procedure call:

IDENTIFIER (any thing);

86

ERROR

Unrecognized statement (token).

The compiler could not classify a statement into one of the basic categories of Domain
Pascal statements (such as assignment, procedure call, function call, goto, repeat). Possibly, you misspelled a keyword, or perhaps you forgot to close the previous statement with a
semicolon.
87

ERROR

GOTO label expected (token).

You forgot to specify a label immediately after the keyword goto. Domain Pascal expected
a declared variable, but found token instead. See the goto listing of Chapter 4.
89

I

ERROR

The value of number is outside the range of valid set elements.

You tried to assign a number greater than 1023 to a set. See the "Set Operations" listing
in Chapter 4 for details on assigning values to sets, and see the "Sets" section in Chapter 3
for information on declaring set types and variables.
91

ERROR

Function type must only be specified when the function is declared FORWARD.

You specified a function as forward, but you mistakenly specified the data type of the
function twice. You must only specify the data type of the function once. Specify the
data type when you specify forward. See the "Forward" section in Chapter 5 for an explanation of forward.

9-16

Diagnostic Messages

92

ERROR

(Option) specifier is not valid when defining a procedure/function previously declared to be FORWARD.

If option is forward, then you probably declared forward twice for the same routine. Possibly, you declared a routine as forward, but you also used the routine with both define
and extern. If option is extern, then you probably declared extern twice for the same
routine.

93

ERROR

Improper use of the DEFINE statement.

See Chapter 7 for a complete description of the define statement.
94

ERROR

Improper DEFINE statement structure.

See Chapter 7 for a complete description of the define statement.

95

Multiple declaration of element i n DEFINE statement.

ERROR

You used define to define the same element twice. See Chapter 7 for a complete description of the define statement.

96

ERROR

Constant value cannot be evaluated at compile time.

You specified an expression in a const declaration that the compiler could not reduce to a
constant. For example, the following declarations trigger this error because x is not a constant:
VAR

x

integer;

ax

addr(x) ;

CONST

97

ERROR

Label label is never defined.

You declared a label in the label declaration part of a routine, but you never specified this
label inside the code portion of the routine. Possibly, you declared the label in the label
declaration part of a routine, but specified this label inside the code portion of another
routine. See Chapter 2 for a description of labels, and see the goto listing in Chapter 4
for a description of the goto statement.
98

ERROR

Improper PROCEDURE/FUNCTION structure (token).

Refer to Chapter 2 for the rules on routine structure. Possibly, you put a period instead of
a semicolon at the end of a routine.

99

ERROR

BEGIN expected in routine name_oJ_routine; found "token".

The code portion of a routine must start with the keyword begin. Domain Pascal discovered token instead of begin. Refer to Chapter 2 for the rules on routine structure. Note
that every routine (including the main program) must at least include the keywords begin
and end.

Diagnostic Messages

9-17

100

ERROR

END expected; found "token".

You forgot to mark the finish of a routine with an end statement. Ignore the line number
the error is reported at; the compiler usually does not discover this error until the end of
the program. See Chapter 2 for the rules on program structure.

101

ERROR

Statement separator expected (token) .

Domain Pascal discovered two statements with nothing to separate them. You probably
made one of the following three mistakes: you forgot a semicolon; or, you forgot a closing
end in a compound statement; or, you forgot an else in an if/then/else statement.

102

ERROR

Improper argument list (token).

You forgot to specify a "}" to terminate a type transfer function. See the "Type Transfer
Functions" listing in Chapter 4.

103

ERROR

THEN expected in IF statement (token).

You forgot the then part of an if/then/else statement. For details on then, see the if listing in Chapter 4.

105

ERROR

OF expected in CASE statement «token}).

A case statement must begin with the format

CASE expr OF
but you forgot the keyword of. See the case listing in Chapter 4.

106

ERROR

CASE label expected (token).

In a case statement, you specified a statement without specifying a constant. Possibly, you
forgot to conclude the case statement with end. See the case listing in Chapter 4.

107

ERROR

END/OTHERWISE expected in CASE statement (token).

You probably forgot to conclude a simple statement with a semicolon or a compound statement with an end.

109

ERROR

DO expected in WHILE statement (token).

You forgot to specify the keyword do following the condition in a while statement.

110

ERROR

UNTIL expected in REPEAT statement (token).

Domain Pascal found token instead of until in a repeat statement. Refer to the repeat
listing in Chapter 4.

9-18

Diagnostic Messages

111

ERROR

:= expected in FOR statement (token) .

Domain Pascal found token instead of := in a for statement. Refer to the for listing in
Chapter 4.

112

ERROR

TO or DOWNTO expected in FOR statement (token).

Domain Pascal found token instead of to or downto. Refer to the for listing in Chapter 4.

113

ERROR

DO expected in FOR statement (token) .

Domain Pascal found token instead of do. Refer to the for listing in Chapter 4.

114

ERROR

Improper WITH statement (token).

Refer to the with listing in Chapter 4.

115

ERROR

DO expected in WITH statement (token).

Refer to the with listing in Chapter 4.

116

ERROR

Improper expression (expression).

A variety of situations could have caused this error. Probably Domain Pascal was expecting a keyword, and you either did not enter a keyword, or you did not enter a keyword
that was appropriate to the situation. The inappropriate expression is expression. For example, you can trigger this error by using the keyword if without using the keyword then.
Another possibility is that you forgot a semicolon on the line preceding the line that the
compiler reported the error. Another possibility is that you began an identifier with a digit
or dollar sign ($) rather than a character.

117

ERROR

Identifier expected (token).

Domain Pascal was expecting an identifier and found token instead. Chapter 2 defines
identifiers.

120

ERROR

OF expected in FILE declaration (token).

You used the keyword file without following it with the keyword OF. See Chapter 3 for
details on declaring file types.

121

ERROR

Expression/constant cannot be passed as argument n to routine.

You specified an expression or constant as the nth argument to routine. However, the nth
parameter of routine is declared as var or in out, and you can only pass variables as arguments to such a parameter.

Diagnostic Messages

9-19

122

ERROR

Improper use of identifier.

You probably tried to call a predeclared procedure as a function or a predeclared function
as a procedure. See Chapter 5 for a description of the difference between calling procedures and calling functions.

123

ERROR

Attempted assignment to (variable), a FOR-index variable, or formal parameter
marked as IN.

You either tried to assign a value to variable inside a routine that declared it as in, or you
tried to modify a FOR loop's index variable inside the loop. If you did the former, you
can correct this error by changing the in parameter to in out or var. If your error was
attempting to modify a for loop's index variable, you can eliminate the code inside the
loop that modifies the variable.

124

ERROR

Routine requires TEXT file parameter.

You specified a file of variable as an argument to routine, but routine requires a text variable instead.

125

ERROR

Procedure requires FILE parameter.

You specified an illegal file parameter for open or close. Only identifiers are legal file parameters. FORTRAN programmers might have triggered this error by using an integer as a
file parameter. Possibly, you forgot to specify any file parameter at all.

126

ERROR

Procedure cannot be performed on INPUT file.

The standard input file (input) cannot be an argument to rewrite, put, or page. See the
"Default Input/Output Streams" section in Chapter 8 for details on input.

127

ERROR

Procedure cannot be performed on OUTPUT file.

The standard output file (output) cannot be an argument to reset, get, eof, or eoln. See
the "Default Input/Output Streams" section in Chapter 8 for details on output.

128

ERROR

Argument to identifier is not a pointer reference.

A predeclared procedure (typically new or dispose) requires an argument of a pointer
type.

129

ERROR

Operand operand] is not compatible with (routine).

You tried to read a value into an expression; for example, consider the following statements:
READ(x + 1);
READLN(x + 1);
READLN(x); x := x

9-20

Diagnostic Messages

+ 1;

{wrong}
{wrong}
{right}

130

ERROR

Fraction width specified for operand (element) that is not of a REAL type.

In a write or writeln statement, you specified a two-part field width for a nonreal expression. If the expression is real, you can specify an optional one- or two-part field width,
but if the expression is not real, then you can only specify an optional one-part field
width. See the write listing in Chapter 4 for a complete description of field widths.

131

ERROR

Field width specifier is not permitted.

You can only specify a field width for a write or writeln statement. If you specify a field
width for any other statement, Domain Pascal issues this error. When you call a procedure or function, Domain Pascal interprets any colon (:) inside the call as a field width.

132

ERROR

Field width specifier (token) is not INTEGER.

Domain Pascal was expecting to find an integer field width, but found token instead. Remember, you format real numbers with a two-part field (not a decimal). Note that when
you call a procedure or function, Domain Pascal interprets any colon (:) inside the call as
a field width. So, possibly you triggered this error with an inadvertent colon.

133

ERROR

Type of operand (identifier) is not compatible with the routine operation.

You tried to read or write an aggregate variable (such as an array or record) to or from a
text (unstruct) file. You can correct this mistake by specifying a rec file instead of an unstruct file. If you must use a text file, you can correct the error by specifying a field (if a
record) or an element (if an array) rather than the full aggregate.

134

ERROR

Improper file name in OPEN.

The file name is the second argument to the predeclared open procedure. The name must
be a string constant or string variable. See the open listing in Chapter 4 for details on filenames that you can specify.

135

ERROR

Improper file mode in OPEN.

The file mode is the third argument to the predeclared open procedure. The file mode
must be a character string, a string constant, or a variable whose data type is an array of
char. See the open listing in Chapter 4 for details on file modes.

136

ERROR

Improper status argument in procedure.

You specified a status argument to procedure that had a data type other than integer32.
A common mistake is to misuse a 8tatu8_$t variable. For example, compare the right and
wrong ways to use such a variable in 'an open procedure:

%INCLUDE '/sys/ins/base.ins.pas';
VAR

st
fl, f2

status_$t;
text;

OPEN(fl, 'angerl', 'NEW', 'st);
OPEN(f2, 'anger2', 'NEW', st.all);

{wrong}
{right}

Refer to the open and find listings in Chapter 4 for details on syntax.

Diagnostic Messages

9-21

137

ERROR

Procedure cannot be used on a text file.

The first argument to find or replace must be a variable of type file. You have mistakenly specified a variable of type text. Refer to the find or replace listings in Chapter 4
for details.

138

ERROR

Record number is not integer in FIND.

The second argument to the find procedure is the record number, and this argument must
be an integer expression. Refer to the find listing in Chapter 4 for details on syntax.

139

ERROR

Improper parameter list in PROGRAM statement "1.

You made a mistake in your program heading. If you specified a file list in the program
heading, then make sure that you specified the files as identifiers (and not as strings). For
example, compare the following two file lists:
PROGRAM test(input, output);
{right}
PROGRAM test('input', 'output'); {wrong}

140

ERROR

Compiler failure, unknown tree node.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

141

ERROR

Compiler failure, unknown top node.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

142

ERROR

Compiler failure, no temp space.

Your program requires too much space on the stack. There are several ways you might be
able to eliminate this error.
Try changing dynamic variables that require a lot of space, such as large records and arrays, to static variables. Static variables do not require stack memory. Use the static attribute to allocate a variable in a static data area and keep its name local to the module or
program in which it is declared.
Another way to reduce your program's stack requirements is to reduce the number of temporary variables that it uses. For example, you could
•

Break the subroutines into smaller subroutines that can be separately compiled.
Smaller compilation units require fewer temporary variables and will therefore require less space on the stack during compilation.

•

Try using the same temporary variables in all your program's loops, so that the

compiler does not create additional temporary variables for each loop.
•

9-22

For functions returning large aggregates, use var or in out parameters in a
procedure instead of function return values. Thus, the compiler will not have to
create temporary variables to hold the return values.

Diagnostic Messages

143

ERROR

Compiler failure, lost value of node.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

144

ERROR

Compiler failure, registers locked.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

145

ERROR

Compiler failure, no emit inst.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

146

ERROR

Compiler failure, procedure too large.

The routine you are trying to compile may have exceeded compiler implementation limits.
Try to break the routine into multiple routines and modules and then recompile. If the
problem still persists, please contact either your HP Response Center or your local HP representative.

147

ERROR

Compiler failure, inst disp too large.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

148

ERROR

Compiler failure, obj module too large.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

149

ERROR

Compiler failure, no free space.

The compiler ran out of dynamic memory while compiling your program. Try to break the program into mUltiple routines and modules and then recompile. Also, check the amount of free
disk space on your system (for example, with the Icom/lvolfs command). If you seem to have
enough disk space. contact either your HP Response Center or your local HP representative.

150

ERROR

Compiler failure, short branch optimization.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

151

ERROR

Routine was declared FORWARD on line number and never defined.

You specified routine as forward, but you did not define it in your program. See the
"Forward" section in Chapter 5 for details on forward.

Diagnostic Messages

9-23

152

ERROR

Section name (identifier) conflicts with procedure or data section name.

You specified identifier as a section name for a var declaration part; however, identifier is
a reserved section name. Please pick another name instead, or remove the section name
completely. See the "Putting Variables Into Sections" section in Chapter 3 for details on
naming sections.

153

ERROR

Improper section name specification token.

You were declaring a section name for a group of variables, but you specified token rather
than an identifier as the name of the section. See the "Putting Variables into Sections"
section in Chapter 3 for details on naming sections.

154

ERROR

Conflicting storage allocation specifications.

You declared a variable as static and as belonging to a nondefault section name. It cannot be declared as both at the same time.

155

WARNING

Constant subscript (value_of_constant) to array name_of_array is out of range.

The value_oJ_constant was not within the declared range of name_of_array. You must
either use a different constant or expand the declared range of the array. See the "Arrays" section in Chapter 3 for a description of array declaration.

157

ERROR

Identifier was declared in a DEFINE statement but never defined.

You used identifier in a define statement, but forgot to use it as the name of a procedure,
function, or variable. See Chapter 7 for an explanation of the define statement.

158

ERROR

Improper OPTIONS specification (token).

You made a mistake while declaring OPTIONS for a routine. Probably, you specified token instead of a valid routine attribute. Possibly, you forgot to mark the end of an OPTIONS clause with a semicolon. The valid routine attributes are listed in Chapter 5.

159

ERROR

Duplicate OPTIONS specification (routine_ attribute).

You specified the same routine attribute twice in an OPTIONS clause. You can only specify it once. The "Routine Options" section in Chapter 5 describes the OPTIONS clause.

160

ERROR

Conflicting OPTIONS specification (routine_attribute).

You specified several routine attributes in an OPTIONS clause; however, routine_attribute
cannot appear in the same OPTIONS clause as one of the previous routine attributes. For
example, you cannot specify both forward and extern in the same OPTIONS clause. You
can also trigger this error by mistakenly using the same routine attribute twice. The "Routine Options" section in Chapter 5 describes the OPTIONS clause.

9-24

Diagnostic Messages

161

ERROR

Unrecognized OPTIONS specification (token).

You specified token inside an OPTIONS clause, but token is not a valid routine attribute
(described in Chapter 5).

162

WARNING

Conditional compilation user warning.

You triggered a warning-level problem through misuse of the conditional compiler directives. More specific messages will follow this one. See the "Compiler Directives" listing of
Chapter 4 for details on the conditional compilation directives.

163

ERROR

Conditional compilation user error.

You triggered an error-level problem through misuse of the conditional compiler directives.
More specific messages will follow this one. See the "Compiler Directives" listing of Chapter 4 for details on the conditional compilation directives.

164

ERROR

Conditional compilation syntax error; look at prior" (PreProc)" message.

" (PreProc)" is an abbreviation for the Domain Pascal preprocessor. This error is telling
you that the preprocessor found an error and passed it along to the compiler. The
preprocessor found an error in a conditional compilation directive. (The conditional compilation directives are %var, %if, %then, %else, %config, %elseif, %elseifdef, %enable,
%endif, and %ifdef.) Possibly, you used a conditional compilation variable without having
first declared it (with a %var directive). Another possibility is that you used an operator
other than and, or, and not in a predicate. See the "Compiler Directives" listing in Chapter 4 for details.

165

ERROR

Conditional compilation not balanced.

Probably, you forgot to end an %if directive with the %end directive. (Making this mistake
may trigger several other errors including Error 6: "Period expected at end of program.")
See the "Compiler Directives" listing in Chapter 4 for details.

166

ERROR

Compiler failure, data frame overflow.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

168

ERROR

Compiler failure, register consistency.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

169

ERROR

Compiler failure, no temp created.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

Diagnostic Messages

9-25

170

ERROR

Compiler failure, improper forward label at token.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

171

ERROR

Compiler failure, pseudo pc consistency.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

173

ERROR

Cannot take the address of internal routine identifier.

You cannot pass identifier as an argument to the addr function, because it is an internal
routine. An internal routine is any routine declared in the main program, any routine
nested inside another routine, or any routine specified with the routine option internal.

174

ERROR

Ptr is keyword1 type but operand is a keyword2.

You tried to assign a value that has a data type other than what the pointer is expecting.
Remember that in Domain Pascal, unless you use univJltr, a pointer can only point to a
value of the specified data type. See Chapter 3 for a discussion of pointer types.

175

ERROR

Incompatible function return types.

A pointer to. a function is expecting a value of a particular data type to be returned to it,
but you mistakenly tried to return a value of a different data type to it. See Chapter 3 for
a discussion of pointer types.

176

ERROR

Incompatible VARIABLE arguments options.

Possible, there may be mismatch between a pointer to a procedure or function, and the
pointer value you are actually trying to assign to it.

177

ERROR

Incompatible number of parameters.

Possibly, there is a mismatch between a pointer to a procedure or function, and the
pointer value you are actually trying to assign to it.

178

ERROR

Incompatible ECB options.

Possibly, there is a mismatch between a pointer to a procedure or function, and the
pointer value you are actually trying to assign to it.

179

ERROR

Incompatible parameter passing conventions for parameter identifier.

Possibly, there is a mismatch between the parameter-passing conventions declared for a
pointer to a procedure or function, and the pointer value you are actually trying to assign
to it.

9-26

Diagnostic Messages

180

ERROR

Incompatible types specified for parameter identifier.

Possibly, there is a mismatch between the parameter-passing conventions declared for a
pointer to a procedure or function, and the pointer value you are actually trying to assign
to it.

181

ERROR

INTERNAL option is illegal for PROCEDURE" or FUNCTION" types.

You mistakenly tried to use the routine option internal in a procedure or function pointer.

182

ERROR

Incompatible VAL_PARAM options.

You called a routine that used the valJ)aram routine option inconsistently. For example,
suppose you declare a pointer to a function as follows:
TYPE

func_ptr = "FUNCTION (x:integer): real;
You want funcJ)tr to correspond to an external function that you declare as:

FUNCTION bad_call (x:integer) : real; EXTERN; VAL_PARAM;
However, calling bad_call by passing its address as a funcJ)tr type variable causes an error. The type declaration did not specify val_param, but the function heading did.

183

ERROR

"[" expected; "token" found.

The compiler was expecting to encounter a left bracket" [", but found token instead.

184

ERROR

"]" expected; "token" found.

The compiler was expecting to encounter a right bracket "]", but found token instead.

185

ERROR

Illegal type of constant" token" for variable" identifier".

You were trying to initialize variable identifier, but you mistakenly specified a value token
that did not have the same type as identifier. The compiler will not perform automatic
type transfers for variable initializations in the var declaration part.

188

ERROR

Dynamic variable identifier cannot be initialized.

By default, all variables declared in routines other than the main program will be allocated
dynamically. You cannot initialize dynamic variables in the var declaration part. If you
want to get around this problem, you can use the variable allocation clause static to force
the compiler to store a routine variable nondynamically (statically). If you use static, the
compiler lets you initialize the variable.

190

ERROR

Cannot initialize null array identifier.

You specified a null array (that is, an array that takes up no space in main memory) which
by itself would only cause a warning; however, you mistakenly tried to initialize the null
array.

Diagnostic Messages

9-27

191

WARNING

String initializer too long for name_of _array; truncated to fit.

You tried to initialize name_oJ_array with a string that had too many characters. The
compiler is warning you that you lost one or more characters of the string in the initialization. To avoid this, you should probably use an asterisk in the index expression of the
array. The asterisk tells the compiler to figure out how many characters the string requires
and declares the array accordingly. See the "Defaulting the Size of an Array" section in
Chapter 3 for details.

192

Variable name is not EXTERN; cannot DEFINE it.

ERROR

You declared name in a var declaration part, and you tried to define it in a define statement. You can only specify name in a define statement if you also declare it as an extern
variable. (See Chapter 7 for details.)

194

WARNING

Unbalanced comment; another comment start found before end.

You specified two comment start delimiters without specifying a comment end delimiter in
between them. You can suppress this warning with the -ncomchk compiler option (described in Chapter 6.) Refer to the "Comments" section in Chapter 2 for details on comments.

195

Lower bound must be an integer value for upper bound of ".".

ERROR

You used an asterisk (.) to force the compiler to determine the number of elements in the
array, but you mistakenly specified a noninteger value as the lower bound of the array.
For example, consider the right and the wrong way to use the asterisk:
VAR

x
x
196

WARNING

array['a' .. *] of char .- 'HELLO';
array[ 1 .. * ] of char .- 'HELLO';

{wrong!}
{Right!}

Size of array is zero.

You specified an array whose index makes no sense. For example, you specified an enumerated value for the lower bound and an asterisk for the upper bound. (See Chapter 3
for details on array declaration.)

197

ERROR

Illegal repeat count usage; valid for array elements only.

See the "Using Repeat Counts to Initialize Arrays" section in Chapter 3.
198

ERROR

Illegal type for repeat count (token); must be integer.

See the "Using Repeat Counts to Initialize Arrays" section in Chapter 3 for details on using repeat counts.
199

ERROR

Illegal repeat count value (token); must be greater than zero.

See the "Using Repeat Counts to Initialize Arrays" section in Chapter 3 for details on using repeat counts.

9-28

Diagnostic Messages

200

ERROR

Repeat count too large by number for array.

See the "Using Repeat Counts to Initialize Arrays" section in Chapter 3 for details on using repeat counts.

201

ERROR

OF expected for repeat count.

See the "Using Repeat Counts to Initialize Arrays" section in Chapter 3 for details on using repeat counts.

202

ERROR

Illegal use of "." repeat count for variable array identi/ier.

See the "Using Repeat Counts to Initialize Arrays" section in Chapter 3 for details on using repeat counts.

203

ERROR

":=" expected in record initialization.

You were trying to initialize a record field with a value, but you forgot the assignment
phrase (:=). Perhaps you mistakenly used (=) instead of (:=).

204

ERROR

Too many initializers for record init; field list exhausted at constant value_o/_constant.

If a record has n fields, you tried to initialize more than n fields. You can only initialize n

or less than n fields. See the "Initializing Data in a Record" section in Chapter 3 for details.

205

ERROR

Size of type_transferJunction is not the same as the size of datatype.

You misused a type transfer function. The size (in bytes) of the datatype and the
type _transferJunction must be equal. Chapter 3 details the sizes of all data types.

206

ERROR

:= expected in assignment statement (token).

Probably, you made a mistake on the left side of an assignment statement that involved a
type transfer function.

207

ERROR

Constant cannot be passed as argument n to routine.

You tried to pass a constant as the nth argument to routine; however, the nth parameter in
routine was declared as var, out, or in out. There are three ways to get around this problem. First, you can change var, out, or in out to in. Second, change var, out, or in out
to a value parameter. Third, change the constant to a variable. See Chapter 5 for a complete explanation of parameters.

208

ERROR

Expression (operator = token) cannot be passed as argument n to routine.

You mistakenly tried to pass an expression as the nth argument to routine. The problem is
that the nth parameter of routine is a var, out, or in out parameter. You should probably
change the parameter to become a value parameter. See Chapter 5 for a complete explanation of parameters.

Diagnostic Messages

9-29

209

WARNING

Large (number_of_bytes bytes) copy of argument name_of_arg will be done when
routine is invoked.

You are trying to pass a large data structure (probably an array) as a value parameter.
This is going to take up a lot of CPU time at run time. You should change the value parameter to a variable, in or out parameter. Chapter 5 describes the various kinds of parameters.
210

WARNING

Routine name_of_routine needs number bytes of stack, which approaches the
maximum stack size of max_size bytes.

You are trying to pass a large data structure (probably an array) as a value parameter.
Consequently, your program will probably execute quite slowly. You should change the
value parameter to a var, in, out, or in out parameter. The "Parameter Types" section
in Chapter 5 describes all the parameter types.
211

WARNING

Routine name needs number bytes of stack, which exceeds the maximum stack size
of max_size bytes.

You probably have a large data structure (usually an array) in your code, and you may be
trying to pass the structure as a value parameter. For example, an array like this
VAR

big_array: array[l.lOOOOO

of integer32;

might exceed the maximum stack size.
If you try to run the program, you will probably get an "access violation" error. If the

structure is a value parameter, you should change it to a var, in, out, or in out parameter. The "Parameter Types" section in Chapter 5 describes all the parameter types.
This warning can occur when you compile a program on one type of workstation, but not
occur when you compile on another type. For example, your program might work fine on
a DN460 but when you compile it on a DN330 this warning might occur. This is because
of the difference in virtual address space available on different nodes.
212

ERROR

Function name returns more than 32K bytes.

The data type of the function consumes more than 32K bytes of memory. Probably, the
data type of the function is a large array. Instead of passing the information back through
the function, you should pass it back through a parameter.
213

ERROR

Illegal FOR statement index variable; identifier is a record or an array reference.

Domain Pascal does not permit a component of a record or an element of an array to be
the index-variable in a for statement.
214

ERROR

Size of argument n to routine is not equal to the expected size of number bytes.

You tried to pass a string as the nth argument to routine, but the nth parameter of routine
was expecting a larger or smaller string. You must either change the size of the argument
to match the size of the parameter, or you must declare the parameter as univ. See the
"Univ" section in Chapter 5 for details.

9-30

Diagnostic Messages

228

ERROR

Too many initializers for array init; " " expected, "token" found.

You specified more data for the array than the array can hold. (See Chapter 3 for details
on declaring arrays.)

234

ERROR

Compiler failure, too many nodes.

This program is so large that the compiler cannot optimize it. You can try recompiling
with -opt 0 (see Chapter 6), but we recommend that you reduce the size of the program
by breaking it up into modules. Chapter 7 explains modules.

235

WARNING

Potential illegal use of FOR index variable (identifier) outside of FOR stmt.

Domain Pascal forbids the use of the value of the index-variable after normal termination
of a for loop. The compiler generates this message if a for loop has no premature exits
(exit or goto) and the value of the index-variable is used outside the loop.

236

ERROR

Floating-point constant "number" conversion problem.

Number was so large that the compiler encountered an overflow error when it tried to convert it from a double to a single, from a double to an integer, or from a single to an integer.

237

ERROR

Compiler failure, unexpected data init construct: token.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

238

ERROR

Type _of_routine 1 identifier was previously declared as a type _of_routine2.

You specified identifier as a forward procedure, but in the routine heading, you specified it
as a function. Or, you specified identifier as a forward function, but in the routine heading, you specified it as a procedure. You must declare it as a procedure in both places or
as a function in both places.

240

WARNING

Size of constant (value) is greater than the number of bits (number) in packed field
name ; constant has been truncated.

Value is outside the declared subrange of name. You must specify a value that falls within
the declared range, redeclare name, or omit the keyword packed from the record declaration. (See the "Records" section in Chapter 3 for details on space allocation in packed
and unpacked records.)

241

ERROR

Dividing by zero in a compile-time constant expression.

You tried to divide by zero.

Diagnostic Messages

9-31

242

ERROR

Size of a PROCEDURE or FUNCTION is undeterminable.

You mistakenly specified the name of a routine as an argument to the sizeof function.
See the sizeof listing in Chapter 4 for a list of its legal arguments.

243

WARNING

Variable name was not initialized before this use.

The compiler is warning you of the possibility of a garbage result when using the value of
variable name. To solve this problem, you must assign a value to name. If name was declared as an out parameter, then you should probably change it to an in out parameter.

244

WARNING

UNIV parameter name should not be passed as a value-parameter.

You specified a univ parameter as a value parameter. You should explicitly declare univ
parameters as in, out, in out, or var. (See the "Univ" section in Chapter 5 fordetails on
univ.) At run time, the called routine copies the value parameter. Since the site of the
parameter and the argument might differ, using a univ value parameter might cause runtime problems.

245

ERROR

Compiler Failure, Store Elimination Error

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

246

WARNING

Expression passed to UNIV formal name was converted to newtype.

See the "Univ" section in Chapter 5 for details on this warning message.

247

ERROR

Compiler failure, implementation restriction: Identifier-list contains too many
names.

This is an implementation restriction. You specified too many identifiers in an enumerated
type. (See the "Enumerated Data" section in Chapter 3 for details on declaring enumerated types.)

248

ERROR

Compiler failure, limit exceeded; limitation_message.

The limitation_message explains the problem.

249

ERROR

Too many nested pointer references for debug tables.

This is an implementation restriction. The symbol table (used by the debugger) cannot
process a record containing pointers to other records in a chain longer than 256 elements.

9-32

Diagnostic Messages

250

Name_oJ_statement statement was constant-folded at compile time.

INF02

Several conditions can cause the compiler to constant-fold a statement. One of the more
common is because the Domain Pascal compiler (SR9 and later) recognizes an attempt to
compare a negative number to an unsigned subrange variable. When it recognizes such an
attempt, it optimizes the code and issues a warning message. For example, consider the
following fragment:

VAR
x

O.. 65535;

BEGIN
IF x

= -1 THEN RETURN;

END;
The compiler generates no code for the if/then statement because it knows that a negative
value of x is not possible.
When the compiler notes such a contradiction, it issues warning messages. These messages
come from the following three groups:
(IFIWHILEICASE) statement was constant-folded at
compile-time.
Comparison is false
Comparison is true

<= becomes
> becomes <>
>= becomes =
< becomes <>
For example, suppose you compile the following program:
Program warning_test;
VAR
x : 0.100;
BEGIN
write('Enter an integer--'); readln(x);
if x <= 0 then writeln('hi');
END.
The compiler issues the following two warning messages:

<= becomes =
and
IF statement was constant-folded at compile-time.
The first message tells you that the compiler is going to optimize the if/then statement.
The second message tells you that the compiler is going to code the <= as an = because a
< condition is not possible.

Diagnostic Messages

9-33

If you write the if/then statement in the program as

if x < 0 then writeln('hi');
the compiler prints a "Comparison is false" warning message because it is apparent to the
compiler that there is no way that x < 0 can ever be true. In such a case, the compiler
generates no code for the then part of the statement.
251

ERROR

Conflicting use of section name (name_ol_section).

You specified name_ol_section as both a code section name and a data section name. It
cannot be both. See the "Section" section in Chapter 5 for details.
252

ERROR

Compiler failure, invalid use of multiple sections and non-local goto to label

name_ol_label.
The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

253

E:RROR

Compiler failure, bad address constant.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

254

ERROR

Compiler failure, invalid use of multiple sections and up-level referencing in routine At.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

255

INF02

<= becomes

=.

See the description of INF02 message number 250.
256

INF02

> becomes <>.

See the description of INF02 message number 250.
257

INF02

Comparison is false.

See the description of INF02 message number 250.
258

INF02

Comparison is true.

See the description of INF02 message number 250.

9-34

Diagnostic Messages

259

>= becomes =.

INF02

See the description of INF02 message number 250.
260

< becomes <>.

INF02

See the description of INF02 message number 250.
262

ERROR

Value-parameter name was not specified in call to FUNCTION or PROCEDURE
identifier declared OPTIONS(VARIABLE).

You forgot to specify a value for the argument corresponding to parameter name. You
would get run-time access violations since the called procedure copies value parameters
into temporary storage, and the procedure has a variable number of parameters. You can
correct this problem in one of two ways. You can assign a value to the argument, or you
can change the value parameter to a var, in, or in out parameter.
263

ERROR

Only records may have variant tags.

Variant tags give you the capability to create records with variable sizes. For example,
consider the following:

TYPE
emp_stat
(exempt, nonexempt);
workerpointer
Aworker;
worker = record
first_name
array[l.lO of char;
last name
array[1.14 of char;
next_emp
workerpointer;
CASE emp_stat OF
exempt
(salary
integer16);
nonexempt : (wages
single;
plant
array[1.20 of char);
end;
VAR

current_worker : workerpointer;
The emp_stat field is a variant tag field because it uses different amounts of storage depending on its value. The function sizeof and the procedures new and dispose can use
variant tags-for example, NEW (current_worker, exempt)-but only when such tags are
part of a record variable. This error occurs if you try to use a variant tag that is not part
of a record.
~64

ERROR

Too many variant tags specified for record.

You used more variant tags in the routines new, dispose, and sizeof than are present in
the record type variable. (See the "Variant Records" section of Chapter 3 for a description of variant tags.)

Diagnostic Messages

9-35

265

ERROR

Type of tag name incompatible with variant.

The value you supplied when specifying a variant tag field is not one of the choices listed
in the field declaration of the record variable. (See the "Variant Records" section of
Chapter 3 for a description of variant tags.)
266

ERROR

No variant with value of tag name exists.

The value you supplied for a variant tag in the routines new, dispose, or sizeof is not one
of the choices listed in the field declaration of the record variable. For example, you
would get this error if you used the record declaration listed at ERROR message number
263, and then included this line in your program:

NEW (current_worker , salaried)
The error would occur because salaried is not one of the choices for the variant tag
emp_stat. (See the "Variant Records" section of Chapter 3 for a description of variant
tags.)
267

WARNING

Token] should not be followed by token2; the token] will be ignored.

This usually appears when you have a misplaced semicolon. You might have put a semicolon (tokenJ) before the reserved word else (token2).
268

WARNING

Missing operator or statement terminator; inserted token to continue parsing.

The compiler generates this message when it is attempting to recover from errors and so
continue parsing. It acts as if the missing token (usually a semicolon) were present, generates this message, and then goes on. To eliminate this message, insert the necessary delimiter(s) in your program and recompile.
269

ERROR

Variables in libraries must be external.

The variables declared in a precompiled library file must be accessible to a program that
uses the file. However, if your precompiled library contains static and/or define variables,
the calling program cannot access those variables because they are not explicitly external.
Such variables are not permitted. To eliminate this error, eliminate the static or define
identifier from the library precompilations.
270

ERROR

Compiled library failure, illegal object type.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.
271

ERROR

File is not a library pathname.

Pathname, which is supposed to specify a precompiled source library file, either is not a
precompiled library at all, or is a precompiled library file whose data has been corrupted.
Verify pathname. If it is incorrect, make the appropriate fix to your code. If it is correct,
precompile it again to try to get rid of the corrupted data.

9-36

Diagnostic Messages

272

ERROR

Library is incompatible because it was generated by a more recent version of compiler.

Library files are not guaranteed to be upward compatible. For example, if you use libraries produced by the newest compiler in a program compiled with an older compiler, they
may be incompatible. To make them compatible, you can do either of the following: use
the newer compiler to compile your source program, or, use an older compiler to produce
the libraries.

273

ERROR

Bodies of PROCEDUREs/FUNCTIONs may not be declared in LIBRARY MODULES.

The routines defined in a precompiled library file must be accessible to a program that
uses the file. However, such routines are not accessible unless they are marked with the
extern attribute (described in Chapter 7). A routine in your precompiled library file was
not marked extern.

274

ERROR

FORWARD PROCEDURE/FUNCTION declarations are not allowed in LIBRARY
MODULES.

Forward declarations of. procedures or functions are not allowed in a precompiled library
file because such routines are not accessible to a program that uses the file. Rewrite your
code to eliminate the forward declaration and recompile.

275

ERROR

INTERNAL

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.

276

ERROR

":" not permitted after OTHERWISE.

You put a colon (:) after the keyword otherwise in a Domain Pascal case statement.
Otherwise is a clause, not a label, so it does not take a colon.
277

ERROR

Labels not permitted at MODULE level.

Since a module (described in Chapter 7) consists of named routines only, a label can only
be declared within the scope of one of those routines. That is, there is no "main program"
in a module with which a label at module level can be associated. However, you declared
a label at module level. To correct this error, declare the label within the scope of the
program block, or inside one of the routines in the module.

Diagnostic Messages

9-37

278

WARNING

Identifier has already been used in another context in current scope.

Pascal forbids the redeclaration of a name that has already been used within a program
block. For example, the following code fragment declares a constant ten at program level.
Within procedure bo, ten is used to initialize variable hold. Ten then is illegally
redeclared as a variable of type real.

PROGRAM illegal;
CONST ten := 10;
PROCEDURE bo;
VAR hold
integer.- ten;
ten
real;

279

INF02

{ This is illegal! }

Value assigned to identifier is never used; assignment is eliminated by optimizer.

If identifier's value has side effects, such as in a function call or in a reference to variables
with the device attribute, the value still is computed, and the_ optimizer only eliminates the
assignment to identifier. However, if there are no side effects, the optimizer also eliminates the value's computation.

You can eliminate this warning by eliminating the value assignment to identifier. However,
there are times when you need to call a function, but are not interested in the value it returns and so don't use that value. In that case, use the discard procedure to explicitly
eliminate the value assignment. See Chapter 4 for a description of the discard procedure
and Chapter 3 for information about the device attribute.

280

WARNING

Current semantics for subrange of CHAR is incompatible with SR9.

Earlier versions of the compiler (SR9 and before) incorrectly use 16 bits to store a subrange of char. However, SR9. 5 and later versions of the compiler use only eight bits to
store the subrange. The difference in the number of bits the compiler versions use can
introduce incompatibilities among compilation units and data files.

281

FATAL

Too many compilation errors-compilation terminated.

The errors in your program have caused an access violation in the compiler and so compilation cannot continue. Correct the problems already indicated and recompile.
283

ERROR

EXTERN PROCEDURES/FUNCTIONS may not be DEFINED in PROGRAM
name.

A main program (which contains the program heading) may reference externally declared
routines, but it may not define any global entry points. Your program tried to define one
or more such points.
284

ERROR

FILE parameters may not be passed by value paramname.

Pascal- forbids passing a file variable as a value parameter. To eliminate this error, change
paramname's declaration to var. The "Parameter Types" section in Chapter 5 describes all
the parameter types.

9-38

Diagnostic Messages

285

ERROR

GOTO transfers control to a structured statement outside of its scope token.

Your code includes an erroneous goto into a structured statement. Structured statements
include case, while, repeat, for, and with.
286

ERROR

Maximum line length (argument 5 to OPEN) must be an INTEGER.

You gave a value that is not an integer for the buffer_size argument to the open statement. The value must be an integer. See the listing for open in Chapter 4 for more details.
287

ERROR

Maximum line length (argument 5 to OPEN) may only be specified for TEXT files.

An open statement may only include the buffer_size argument if you are opening a text
file. However, you included the argument for an open of some other file type.
288

ERROR

Base types of token] and token2 are incompatible.

This error occurs if you try to use the pack or unpack built-in procedures on two arrays
that have different base data types. Those types must be the same. For example, if one is
an array of integer32, the other must be an array of integer32.
289

WARNING

Must overflow bounds of array (tokenl) in order to match PACKED array.

This error can occur if you are using the pack or unpack built-in procedures. For every
element in the packed array there must be a corresponding element in the unpacked array.
See the listings for pack and unpack in Chapter 4 for more details.
290

ERROR

Index of VARYING must be a positive integer < 65536.

In a varying[x] of char, declaration, you specified a negative value or a value larger than
65535 for x.
291

ERROR

Data type of VARYING strings must be CHAR.

In a varying [x] of TYPE declaration, you specified a type other than char for TYPE.
292

ERROR

Improper VARYING specification syntax (EXPRESSION).

This error can be caused by a variety of syntax errors (for example, missing '[').
293

ERROR

Argument ACTUAL ARGUMENT to FORMAL ARGUMENT is not a VARYING
string.

The formal argument is declared as a variable length string, but you passed it some other
type of value.

Diagnostic Messages

9-39

294

ERROR

PROCEDURE may not be called in this context (token).

You used a procedure name in a context where a value must be returned, such as the following: A := X(P(A», where P is a procedure. It is illegal to use a procedure name (token) in the argument list of a call to another routine. This is because all of a routine's arguments must have or resolve to values. While a function returns a value, aprocedure
does not.
295

Modulus must be >= zero (token).

ERROR

You specified a MOD operation, A mod B, where B is less than zero. This error can only
occur if you compile with the -iso option.
296

ERROR

Length of constant string exceeds maximum of 1024 characters.

A string constant may not exceed 1024 characters.
297

ERROR

Only an integer constant is valid here (EXPRESSION).

There are a number of instances where only integer constants are allowed. For example,
you may use only an integer constant to specify an ASCII character in Domain Pascal's
syntax for embedding special characters in string constants.
298

ERROR

Argument to token attribute conflicts with value already specified for this type.

You specified conflicting attribute types in an attribute list. For example,

TYPE
int = [word, longl -32768 .. 32767;
The code in this example specifies two conflicting size attributes for into
299

WARNING

Specified token attribute conflicts with attributes of base type.

You specified an attribute for an object that is not consistent with the attributes you specified
previously. For example,

TYPE
int = [word] -32768 .. 32767
long_int = [long] int;
The word attribute for the subrange -32768 .. 32767 tells the compiler to allocate 2 bytes of
space for int types, but long tells the compiler to allocate 4 bytes for long_int, which is an int
type.
300

Size of token 1 bits is invalid for specified type.

FATAL

You specified an invalid number of bits for an object. (See the "Size-Extension" section of
Chapter 3 for details about size attributes.) For example,

TYPE
number = integer32;
VAR

bad : [byte] number;
The size attribute, byte, specifies 8 bits, but an integer 32-type variable requires at least 32 bits.

9-40

Diagnostic Messages

301

WARNING

Size of array element rounded up from token 1 to token2 bits.

In packed arrays, if the element size is less than 16 bits, then the element is padded up to the
nearest power of 2 bits. Thus, in the following example,

array1: PACKED ARRAY [low .. high] OF 0 .. 7;
4 bits would be allocated for each array element.
304

INFO 1

Actual alignment of array elements (token1) is less than natural alignment (token2).

You probably specified an array of records, and the array's elements are not naturally aligned.
See the "Internal Representation of Packed Records" and the "Alignment-Extension" section
of Chapter 3 for more information about declaring records so that they will be naturally aligned.
305

INFO 1

Actual alignment of token 1 (token2) is less than natural alignment (token3).

A value is naturally aligned if it begins at an address that is a multiple of its size in bytes. For
example, a 2-byte value is naturally aligned if it starts on a 2-byte address boundary. Similarly,
an 8-byte value is naturally aligned if it starts on an 8-byte boundary. This message tells you that
token} 's alignment is less than natural alignment.
306

INFO 1

Size of variable (token 1) rounded up to token2 bytes.

The size of all simple data types must be at least one byte. Therefore, if you specify a size which
is a number of bits that is not evenly divisible by 8, the size will be rounded up to the next byte.
307

INFO 1

Size of function result rounded up to token 2 bytes.

The size of all simple data types must be at least one byte. Suppose you declare a function, foo,
that returns an integer. If you specify a number of bits that is not evenly divisible by 8 as the size
for the result of foo, the compiler rounds the result of foo up to the next byte. For example, if
you specify the result of 100 as follows:

FUNCTION foo: [bit (20)] integer;
the compiler rounds the result of
308

FATAL

100

to 24 bits, the next byte.

Compiler failure, no case for object type.

The error is in the compiler, not in your code. Please contact either your HP Response Center or
your local HP representative.
309

INF03

Unnaturally aligned load/store (token1) diminishes code quality.

A value is naturally aligned if it begins at an address that is a multiple of its size in bytes. For
example, a 2-byte value is naturally aligned if it starts on a 2-byte address boundary. Similarly,
an 8-byte value is naturally aligned if it starts on an 8-byte boundary. Most computers are
designed to transfer data most efficiently if the data is naturally aligned. This message tells you
that your code is inefficient because it causes the compiler to load and store data that is not
naturally aligned.

Diagnostic Messages

9-41

310

WARNING

Alignment of argument is less than expected by formal parameter token 1.

You passed an argument as a formal parameter that was aligned on a boundary lower than the
boundary expected for the formal parameter. The default alignment for formal parameters is
natural alignment. Therefore, unless you specify the alignment for formal parameters to be
something else, arguments passed to them should be naturally aligned.
312

ERROR

Illegal to redefine token 1 (token 2).

The name of a user-defined attribute list may not conflict with a predeclared attribute or option.
316

ERROR

token 1 is inappropriate in this context.

You declared an attribute incorrectly.
319

WARNING

Alignment of field (token1) is dependent on the current default alignment environment.

The alignment of the fields changes, according to the state of the %word_alignment or %natu:,
ral_alignment compiler directives. See the "Compiler Directives" listing for these directives in
Chapter 4 for more information.
320

WARNING

Alignment of array elements is dependent on the current default alignment environment.

The alignment of array elements changes, according to the state of the %word_alignment or
%natural_alignment compiler directives. See the "Compiler Directives" listing for these directives in Chapter 4 for more information.
321

WARNING

Unrecognized option (%token1); assuming %token2.

You misspelled a compiler directive, and the compiler is substituting %token2. For example, if
the compiler finds %insert which is not legal in Domain Pascal, the compiler substitutes %inelude and warns you.
322

ERROR

Parameter token1 conflicts with FORWARD or EXTERN declaration of this routine.

You changed the definition of a parameter when you repeated definitions in a routine declared
with forward or extern. See the "Routine Options" section of Chapter 5 for more details about
routine options.
323

ERROR

Function return type conflicts with FORWARD or EXTERN declaration of this
routine.

You changed the definition of a function return type when you repeated function definitions in a
function declared with forward or extern. See the "Routine Options" section of Chapter 5 for
more details about routine options.

9-42

Diagnostic Messages

324

ERROR

OPTIONS declaration conflicts with FORWARD or EXTERN declaration of this
routine.

You changed the definition of a routine's routine options when you repeated routine definitions
in a routine declared with forward or extern. See the "Routine Options" section of Chapter 5
for more details about routine options.

325

ERROR

Number of parameters in FORWARD or EXTERN declaration is different than in
this declaration.

You changed the number of parameters when you repeated routine declarations in a routine
declared with forward or extern. See the "Routine Options" section of Chapter 5 for more
details about routine options.

326

ERROR

ALIGNO may not be passed to UNIV formal parameter token!.

You cannot use the align function with a univ formal parameter. See the" Align" listing in
Chapter 4 for more details about the align function.

327

ERROR

Null string is illegal.

ISO Pascal does not permit the string null string (' ').
NOTE: This is an error only if you compile with the -std option.

328

ERROR

Type of FILE may not be or contain a FILE type.

It is illegal to have a FILE OF x, where x is itself a file type (e.g. FILE OF TEXT).

329

ERROR

token1 contains a FILE type.

It is illegal to do an aggregate assignment of a record or array to another record or array of the
same type if it contains a file type.

330

ERROR

token1 is PACKED.

You cannot pack token1 in this context. See the "Packed Arrays" sections of Chapter 3 for
details about packed arrays.

331

ERROR

token1 is not PACKED.

You must pack token 1 in this context. See the "Packed Arrays" sections of Chapter 3 for details
about packed arrays.

Diagnostic Messages

9-43

332

ERROR

Tag field of variant selector may not be passed by reference as parameter token 1.

NOTE: This is an error only if you compile with the -std option.

333

ERROR

No assignment to function variable (token 1).

ISO requires at least one assignment to the function variable in a function's body.
NOTE: This is an error only if you compile with the -std option.

334

ERROR

Return type of FUNCTION (token1) must be simple.

ISO does not allow structured types to be the return types of functions.
NOTE: This is an error only if you compile with the -std option.

335

ERROR

Function identifier (token 1) may not be used as a pointer variable.

A function that returns a pointer may not be dereferenced:
TYPE

i_ptr = Ainteger;
FUNCTION x : i_ptr;
BEGIN
NEW(x) ;
XA

.-

5;

{THIS IS AN ILLEGAL STATEMENT}

END;
NOTE: This is an error only if you compile with the -std option.

336

ERROR

At least one parameter must follow a file variable argument to READ/WRITE.

ISO requires that READ/WRITE have at least one thing to read or write.
NOTE: This is an error only if you compile with the -std option.

337

ERROR

All values of tag type (token1) must appear as case constants.

NOTE: This is an error only if you compile with the -std option.

338

ERROR

FOR index variable (token1) must be declared in the routine in which it is used.

NOTE: This is an error only if you compile with the -std option.
ERROR

Incompatible routine OPTIONS.

The options clause in the procedure or function parameter you specified is incompatible with the
options clause of the formal type signature.

9-44

Diagnostic Messages

348

WARNING

No path exists to this statement.

The program never reaches this statement; therefore, the compiler does not generate any
code for it. Sometimes a goto statement triggers this warning.

349

ERROR

Alignment stack overflow.

You may not have more than 255 "push~alignment directives in a source file before the corresponding "pop_alignment directives. See the "Compiler Directives" listing in Chapter 4 for
information about these directives.

350

ERROR

Alignment stack underflow.

You cannot have more "pop_alignment directives than "push_alignment directives. See the
"Compiler Directives" listing in Chapter 4 for information about these directives.

351

ERROR

Unmatched %PUSH_ALIGNMENT directive.

This error indicates that you have more "push_alignment directives than %pop_alignment directives. The compiler ignores the extra directive. See the "Compiler Directives"
listing in Chapter 4 for information about these directives.

352

ERROR

Type of index constant (constant) does not match array declaration.

You tried to initialize an array with constant. constant is not the same data type as was
declared for the array. The types must match.

353

ERROR

Index constant (constant) is not within array bounds.

constant was not within the declared range of the array. You must either use a different
constant or expand the declared range of the array.

354

ERROR

" :=" is expected after index constant.

An assignment operator (:=) must appear after the index constant(s) and before the value used
to initialize the constant.

355

ERROR

Array elements may not be initialized more than once.

You cannot initialize an array component more than once in a single array initialization statement.

356

INF04

Size of record is number in word and number in natural alignment environment.

You declared a record whose alignment varies with the alignment environment. Porting an
application from one machine to another may cause problems if new alignment rules are used.

Diagnostic Messages

9-45

357

WARNING

Span between elements of array (number bytes) does not match size of base type
typename (number bytes).

This warning appears if, in a word-alignment environment, you define a record that can have
different sizes in different environments, and you then define an array of those records in a
natural-alignment environment. If you do not correct this error, your program will produce
unpredictable results.
358

ERROR

Reference outside bounds of array number also falls outside of stack frame.

You have an array reference that falls outside the allocated area for that particular routine. Even
though it is usually a poor programming practice, it is sometimes desirable to access beyond an
array declaration. But in this case you've made a reference to data that also falls outside the
stack frame.
359

ERROR

Expression overflows parse stack; please simplify your expression.

The expression stack of the compiler overflowed. You need to break the complex expression
into smaller pieces.
360

WARNING

Routine not expanded INLINE at call site (indefinite cause): routine_name.

This warning appears if you request inline expansion for a routine, but the compiler cannot
expand the function inline because of a problem with the function call. See the discussion of
%begin_inline and %end_inline under "Compiler Directives" in Chapter 4 for information
about inline expansion.
361

WARNING

Routine not expanded INLINE (indefinite cause): routine_name.

This warning appears if you request inline expansion for a routine, but the compiler cannot
expand the function inline because of a problem with the routine to be expanded. See the
%begin_inline and %end_inline entries under "Compiler Directives" in Chapter 4 for information about inline expansion.
362

INF04

Routine expanded INLINE at call site: routine_name.

This informational message appears if you specify an optimization level of 4 and the compiler
selects for inline expansion a function that you have not requested inline expansion for. See the
%begin_inline and %end_inline entries under "Compiler Directives" in Chapter 4 for information about inline expansion.
363

WARNING

Routine not expanded INLINE at call site (recursion): routine_name.

This warning appears if you request inline expansion for a recursive routine (a routine that calls
itself). Recursive routines cannot be expanded inline. See the %begin_inUne and end_inUne
entries under "Compiler Directives" in Chapter 4 for information about inline expansion.

9-46

Diagnostic Messages

3 64

WARNING

Routine not expanded INLINE at call site (caller + callee too large): routine_name.

This warning appears if you request inline expansion for a routine, but the caller and callee
routine together contain too many statements. You also get this warning if the caller and callee
together have more than 255 variables, or if the callee's stack frame contains more than 24K
bytes. See the %begin_inline and %end_inline entries under "Compiler Directives" in Chapter
4 for information about inline expansion.

3 65

WARNING

Routine not expanded inline at call site (callee contains unexpanded procedure):

routine_name
This warning appears if you request inline expansion for a routine that has a nested routine that
makes uplevel references and there is more than one call site. For uplevel references to work
correctly, there must be only one call site for a routine that has any number of nested routines
that make uplevel references. If all nested routines are expanded in turn into the outermost
routine, this problem disappears. See the %begin_inline entry under "Compiler Directives" in
Chapter 4 for information about inline expansion.

366

WARNING

Routine not expanded inline at call site (parameter is proc): routine_name.

This warning appears if you request inline expansion for a routine that has a routine as a parameter. Routines with routines as parameters cannot be expanded inline. See the %begin_inline
and %end_inline entries under "Compiler Directives" in Chapter 4 for information about inline
expansion.

368

WARNING

Routine not expanded inline at call site (psect mismatch): routine_name.

This warning appears if you request inline expansion for a routine, but you have placed the caller
and the callee in different procedure sections by means of a section routine attribute. The caller
and callee must both occupy the same procedure section. See the %begin_inline and %end_inline entries under "Compiler Directives" in Chapter 4 for information about inline expansion;
see Section 5.7.1 for information about section.

369

WARNING

Routine not expanded INLINE (file variable): routine_name.

This warning appears if you request inline expansion for a routine that has a parameter of type
file. Routines with file type parameters cannot be expanded inline. See the %begin_inline
discussion under "Compiler Directives" in Chapter 4 for information about inline expansion.

370

WARNING

Routine not expanded INLINE (record variable): routine_name.

This warning appears if you request inline expansion for a routine that has a parameter of type
record that contains a file type. Routines with records that have file type fields cannot be
expanded inline. See the %begio_inline discussion under "Compiler Directives" in Chapter 4
for information about inline expansion.

Diagnostic Messages

9-47

371

WARNING

Routine not referenced, code deleted: routine_name.

You declared a routine that is not external and has no callers within the current compilation unit.
The compiler has deleted the code for the routine.

374

ERROR

Unable to convert floating point constant to integer: token.

The compiler encountered an overflow error when it tried to convert the floating-point constant
to an integer.

375

Call passes argument block of number bytes (implementation limit is 2K).

ERROR

On a Series 10000 system, you may not pass an argument under the c_param option that contains more than 2K bytes-for example, a very large record. If possible, pass a pointer to the
record, or pass it as a reference argument.

376

ERROR

References to atomic/volatile objects must be properly aligned.

Under normal circumstances the Series 10000 compiler generates, loads, and stores to and from
memory in such a way as to avoid alignment traps. However, if the reference in question is
atomic, the compiler insists on having the datum at least word aligned.

377

ERROR

Unmatched inline directive.

You must match an %end_inline to every %begio_inline and an %end_ooinline to every %begin_noinline. You cannot nest inline directives. You must close one inline scope before opening another. See the "Compiler Directives" listing in Chapter 4 for information about these
directives.

385

Auto-padding of strings is restricted to number bytes.

ERROR

You are assigning all the elements of a string to a larger array of char. Domain Pascal limits you
to 4096 bytes. Auto-padding for larger arrays is not allowed.

388

WARNING

Loop structure deleted.

The compiler has deleted a loop. This loop has both of the following characteristics:
•

The exit condition is not dependent on the code within the loop.

•

The loop has no side effects; that is, it contains no calls and does not update a
variable that is subsequently used.

You should pay particular attention to this warning, as the compiler may have noticed a subtle
bug in your code.

9-48

Diagnostic Messages

400

WARNING

Expression will fault at runtime - divide by zero.

You have a divide-by-zero expression. An evaluation of this expression will cause a run-time
fault.

40 1

WARNING

Expression will fault at runtime - argument is outside function domain.

You have an expression whose value is undefined. An example of this is the natural log of a
negative number. The compiler is informing you that an evaluation of this expression will cause a
run-time fault.

402

WARNING

Expression will fault at runtime - floating-point overflow.

You have an expression that causes floating-point arithmetic to overflow. An evaluation of this
expression will cause a run-time fault.

403

WARNING

Expression will fault at runtime - floating-point underflow.

You have an expression that causes floating-point arithmetic to underflow.
this expression will cause a run-time fault.

404

WARNINO

An evaluation of

Expression will fault at runtime - negative to non-integer power.

You have an expression that raises a negative to a real power. This is an undefined operation.
An evaluation of this expression will cause a run-time fault.

Diagnostic Messages

9-49

9.3 Run-Time Error Messages
Run-time error messages are notoriously difficult to decipher, mainly because any number
of programming errors can cause them. This section attempts to describe the more common run-time errors, reasons why your program may have caused them, and some general
approaches for getting rid of them.
Run-time errors fall into two broad categories:
•

Operating system errors, described in Section 9.3.3

•

Floating-point errors, described in Section 9.3.4

9.3.1 Causes of Run-TIme Errors
Operating system run-time errors most commonly occur when your program attempts to
access a forbidden area of memory. There are several ways in which a program can do
this:
•

If your program tries to write to an area of memory that has been allocated but is

read-only, such as a library or your program text, it causes an access violation.
•

If your program tries to access an area of memory that has not been allocated at

all, it causes a "reference to illegal address" error.
•

If your program writes over a part of the stack frame that contains data the function needs in order to return to the caller, it causes a stack unwind error.

•

If your program tries to write to a guard segment-a small area of memory on

each side of a stack frame-it causes a guard fault.
Figure 9-1 shows the main areas of memory a program uses and the errors caused by invalid uses of these areas.

9-S0

Diagnostic Messages

Static memory

Type of error

Program text
Access violation
Read-only

Static data
Out-of-bounds address
Read-write
Unallocated
storage

-

Illegal address

.

'---~
Libraries
Access violation
Read-only

Dynamic memory
Guard area

Guard fault

Stack frame
Read-write

Stack unwind error
Out-of-bounds address

Guard area

Guard fault

Figure 9-1. System Memory and Run-Time Errors

Diagnostic Messages

9-51

9.3.2 Debugging Run-Time Errors
If you get a run-time error after your program compiles with a warning message, the warn-

ing message may tell you what and where the problem is. However, if the program compiles with no warnings, you need to determine what line of your program is causing the
error before you can determine what the error is and how to fix it. Two Domain/OS tools
can provide this information:
•

The traceback tool, tb

•

The Domain Distributed Debugging Environment (Domain/DOE)

Getting a traceback is usually the best way to begin to find the cause of a run-time error.
The command tb tells you what line of your source code caused the error. The command
tb -full provides information about the address that caused the. error and the contents of
the machine registers. For more information about tb, see Section 6.9.1.
If the information provided by tb is not enough to enable you to find the problem, you

need to invoke the debugger. For information about using the debugger, refer to the Domain Distributed Debugging Environment Reference Manual.

9.3.3 Operating System Error Messages
access violation (OS/fault handler)
Your program attempts to access address space that is allocated in the process, but is not accessible to your program-for example, global read-only address space. An invalid address, such as
zero or a negative number, also causes this error.
An access violation is most commonly caused by stray pointers. For example, you can cause an
access violation by assigning a value to a record field before you have allocated storage for the
record.

Apollo-specific fault (UNIX/signal)
If you do a full traceback, this error will probably resolve to another error, such as "reference to

out-of-bounds address." For information, refer to the discussion of that error.

Bus error
If you do a traceback, this BSD and SysV environment run-time error will resolve to another

error, such as "odd address error." For information, refer to the discussion of that error.

guard fault (OS/MST manager)
Your program attempts to access one of the guard segments surrounding the program stack. (A
guard segment is an area that sits on either side of sections of memory.) This error is usually
caused by exceeding the stack size. One solution is to increase the stack size with the following
command line:
bind objectJiles -stacksize decimal_number

9-52

Diagnostic Messages

The bind utility is described in Section 6.5.2 and in the Domain/OS Programming Environment
Reference.
Another solution is to check whether you are walking off the end of an array into the guard
region.
This error can also be caused by an infinitely recursive call or by a stray pointer that happened to
land on a guard segment.
Memory fault
If you do a traceback, this SysV environment run-time error will probably resolve to "access
violation," "guard fault," "reference to illegal address," or "reference to out-of-bounds address. " For information, refer to the discussions of these errors.

odd address error (OS/fault handler)
Your program attempts to access an address that is odd (that is, not divisible by 2). You may not
access an odd address.
This error occurs only on Series 10000 systems and on older M680xO machines such as the
DN300.
This problem is most commonly caused by stray pointers.
reference to illegal address (OS/MST manager)
Your program attempts to access address space that isn't allocated at all; it is not mapped into
memory.
This problem is most commonly caused by a stray pointer or by an array reference that gets into
an invalid area of memory.
reference to out-of-bounds address (OS/MST manager)
Your program references address space that is allocated but lies beyond the end of the mapped
object.
This problem is most commonly caused by running off the end of an array.
Segmentation fault
If you do a traceback, this BSD environment run-time error will probably resolve to "access
violation," "guard fault," or "reference to illegal address." For information, refer to the discussions of these errors.

unable to unwind stack because of invalid stack frame (process manager/process
fault manager)
Somehow, somewhere, the run-time stack has been trashed (most likely by your program going
astray) and is unusable.
This problem is commonly caused by an infinitely recursive program, or by an array assignment
that runs off the end of the array into the stack frame. It can also be caused by stray pointers and
by mismatched arguments.

Diagnostic Messages

9-53

9.3.4 Floating-Point Errors
This section gives brief explanations of some common floating-point errors. We discuss
only errors whose meaning is not obvious; we omit other common errors, such as division
by zero or floating-point overflow, that are easy to understand. For complete information
about floating-point calculations on Domain/OS systems, consult the Domain FloatingPoint Guide.

Floating exception
If you do a traceback, this BSD and SysV environment run-time error will resolve to another
error, such as "floating point operand error." For information, refer to the discussion of that
error.

floating point operand error

(OS/fault handler)

One of the operands in an expression is invalid; that is, it does not represent a real number or is
otherwise not an acceptable value for that particular operation. An example is to give a negative
number as argument to a built-in logarithm function.

floating point branch/set on unordered condition (OS/fault handler)
This error means that you got a QNAN signal (Quiet Not-A-Number). The bit pattern for the
floating point variable has all exponent bits set (to 1) and also had the MSB (most significant bit)
of the fraction set. Such a bit pattern should never occur as the result of an arithmetic operation
on legitimate floating-point values. It can result from uninitialized variables, from type transfers,
from an operand error, or from operations with NAN (Not-A-Number) inputs.

floating point signalling not-a-number (OS/fault handler)
This error, a Signaling NAN (SNAN), is like a QNAN except that the MSB of the fraction is not
set (0), but at least one bit in the fraction is set (to 1). An SNAN is never created as the result of
an operation. Any arithmetic operation on an SNAN will give this error.'

----88----

9-54

Diagnostic Messages

Appendix A
Reserved Words and
Predeclared Identifiers

This appendix lists the reserved words and predeclared identifiers in Domain Pascal.
Reserved words, listed in Table A-1, are names of statements, data types, and operators.
You can use reserved words only with their reserved meanings (and within strings and comments). You cannot use a reserved word as an identifier.

Table A-i. Reserved Words
and

end

not

set

array

file

of

then

begin

for

or

to

case

function

packed

type

const

goto

procedure

until

div

if

program

var

do

in

record

while

downto

label

repeat

with

else

mod

Reserved Words and
Predeclared Identifiers

A-I

Table A-2 lists the predeclared identifiers. These identifiers name types, functions, procedures, values, and files. You can redefine predeclared identifiers; however, doing so means
that you can no longer use the identifier for its original meaning within the scope of the
redefinition.

Table A-2. Predeclared Identifiers
exp
extern

next
nil

set_sr
sin

false

odd

single

append

find

open

sizeof

arctan

firstof

ord

sqr

arshft

forward

otherwise

sqrt

boolean

get

out

static

char

in_range

output

string

chr

input

page

substr

close
eos

integer

pred

integer16

ptoe

suce
text

ctop

integer32

put

true

define

internal

read

trune

disable

lastof

readln

univ

discard

In

real

univ_ptr

dispose

lshft

replace

val_param

double

max

reset

varying

enable

maxint

return

write

eof

min

rewrite

writeln

eoln

module
new

round

xor

abs
addr
align

exit

rshft

----88----

A-2

Reserved Words and
Predeclared Identifiers

Appendix B
ISO Latin-l rrable

Domain Pascal uses the ISO DIS 8859/1 Character set, commonly known as Latin-I, for
character data representation. The Latin-l set also includes all ASCII characters in their
standard positions. Table B-1 shows the decimal, octal, and hexadecimal values for all
ISO Latin-l characters.
You can use Latin-l characters in comments or character strings, but are limited to using
ASCII letters A-Z and a-z (decimal positions 65-90 and 97-122, respectively), digits, underscores U, and dollar signs ($) in identifiers. This adheres to existing Pascal standards.

NOTE:

The characters with decimal numbers 128 through 131 are missing from the table. These values are reserved for future standardization and are not available to programmers.

ISO Latin-l Table

B-1

Table B-1. ISO Latin-1 Codes

oct

dec

hex

0
1
2
3
4
5
6
7
10
11
12
13
14
15
16
17
20
21
22
23
24
25
26

0
1
2
3
4
5
6
7
8

0

10
11
12
13
14
15
16
17
18
19
20
21
22

27

30
31
32
33
34
35
36
37

1
2
3

character

NUL
SOH
STX
ETX
EOT
ENQ
ACK
BEL

"@

AA
"B

A

TAB
LF

B

VT

C

10
11
12
13
14
15
16

FF
CR
SO
SI
DLE
DC1
DC2
DC3
DC4
NAK
SYN

AC
AD
AE
AF
AG
AH
AI
AJ
AK
AL
AM
AN
AO
Ap
AQ
AR
AS
AT
AU
AV

23

17

ETB

"W

24
25
26
27
28
29
30
31

18
19
lA
1B
lC

CAN
EM
SUB
ESC
FS
GS
RS
US

9

4

5
6

7
8
9

D

E
F

ID

IE
IF

BS

AX
Ay
AZ
A[
AI

.]

....

A

-

oct

dec

hex

character

40
41
42
43
44
45
46
47
50
51
52
53
54
55

32
33
34
35
36
37
38

20
21
22
23
24
25
26

space
!
"
#

39

27

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

28
29
2A
2B
2C
2D
2E
2F
30
31
32
33
34
35
36
37
38
39
3A
3B
3C
3D
3E
3F

56

57
60
61
62
63
64
65
66
67
70
71
72
73
74
75
76
77

$

%
&

,

(
)

*
+

,

·

/

0
1
2
3
4
5
6
7
8
9

··

,·

<

=
>

?
(Continued)

B-2

ISO Latin-1 Table

Table B-1. ISO Latin-1 Codes (Cont.)

oct

dec

hex

100
101
102
103
104
105
106
107
110
111
112
113
114
115
116
117
120
121
122
123
124
125
126
127
130
131
132
133
134
135
136
137

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

40
41
42
43
44
45
46
47
48
49
4A
4B
4C
4D
4E
4F
50
51
52
53
54
55
56
57
58
59
SA
5B
5C
5D
5E
SF

character

@

A
B
C
D
E
F
G
H
I

J
K
L
M
N
0
P

Q
R
S

T
U

V
W
X

y
Z

[
\
]
"

-

oct

dec

140
141
142
143
144
145
146
147
150
151
152
153
154
155
156
157
160
161
162
163
164
165
166
167
170
171
172
173
174
175
176
177

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

hex

60
61
62
63
64
65
66
67
68
69
6A
6B
6C
6D
6E
6F
70
71
72
73
74
75
76
77
78
79
7A
7B
7C
7D
7E
7F

character

,
a
b
c
d
e
f
g

h

.

1

j
k

1
m
n
0

P
q
r

s
t
u
v
w
x

Y
z

{

I

}

del

(Continued)
ISO Latin-1 Table

B-3

Table B-1. ISO Latin-1 Codes (Cont.)

oct

dec

hex

character

204
205
206
207
210
211
212
213
214
215
216
217
220
221
222
223
224
225
226
227
233
234
235
236
237
240
241
242
243
244
245
246

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
155
156
157
158
159
160
161
162
163
164
165
166

84
85
86
87
88
89
8A
8B
8C
8D
8E
8F
90
91
92
93
94
95
96
97
9B
9C
9D
9E
9F
AO
A1
A2
A3
A4
AS
A6

IND
NEL
SSA
ESA
HTS
HTJ

VTS
PLD
PLU
RI
SS2
SS3
DCS
PU1
PU2
STS
CCH
MW

SPA
EPA
CSI
ST
OSC
PM
APC
NBSP
i
¢

£
Xl

¥

I

oct

247
250
251
252
253
254
255
256
257
260
261
262
263
264
265
266
267
270
271
272
273
274
275
276
277
300
301
302
303
304
305
306

dec

hex

167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

A7
A8
A9

©

AA

a

AB

AC
AD
AE
AF
BO
B1
B2
B3
B4
B5
B6
B7
B8
B9
BA
BB
BC
BD
BE
BF
CO
C1
C2
C3
C4
C5
C6

character

§

..

«

..,

SHY
®

0

±
2

3

,

J.l

fJ

.

,
1
Q

»
1/4
1/2

3/.4

i

A
A
A
A

A
A
.IE

(Continued)
B-4

ISO Latin-l Table

Table B-1. ISO Latin-1 Codes (Cont.)

oct

dec

hex

307
310
311
312
313
314
315
316
317
320
321
322
323
324
325
326
327
330
331
332
333
334
335
336
337
340
341
342
343
344
345
346

199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230

C7
C8
C9
CA
CB
CC
CD
CE
CF
DO
D1
D2
D3
D4
D5
D6
D7
D8
D9
DA
DB
DC
DD
DE
DF
EO
E1
E2
E3
E4
E5
E6

character

<;
13

E
E
E
I
f
I
i
f)

N

a
6

a
6
6
x

0

U

-0
0
D
Y
P

B

oct

dec

hex

347
350
351
352
353
354
355
356
357
360
361
362
363
364
365
366
367
370
371
372
373
374
375
376
377

231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

E7
E8
E9
EA
EB
EC
ED
EE
EF
FO
F1
F2
F3
F4
F5
F6
F7
F8
F9
FA
FB
FC
FD
FE
FF

a

character
C

e
e
e

e
i
i
1
i
(}

fi
6
6
0
6

0
(3

il
U
ii
ii

Y
P
Y

a
a
a
a
a
re

--88-ISO Latin-l Table

B-5

Appendix C
Extensions to Standard Pascal

This appendix describes Domain Pascal's extensions to ISO standard Pascal.

e.l

Extensions to Program Organization
Chapter 2 describes the elements that make up a Pascal program. This section describes
the extensions to standard Pascal.

C.l.l Identifiers
Although an identifier must begin with a letter, you can include underscores
signs ($) in the name. For example, mailing_$lists is a legal identifier.

U

or dollar

C.1.2 Integers
You can specify integers in any base from 2 to 16. To do so, use the following syntax:

base#value
For base, enter an integer from 2 to 16. For value enter any integer within that base. If
the base is greater than 10, use the letters A through F (or a through f) to represent digits
with the values 10 through 15.
For example, consider the following integer constant declarations:

half- life := 5260;
' - 16#lc6;
hexagrams .luck
:= 2#10010;
' - 8#723;
wheat
.-

/*
/*
/*
/*

default
hexadecimal
binary
octal

(base
(base
(base
(base

10)
16)
2)
8)

*/
*/
*/
*/

Extensions to Standard Pascal

C-l

C.l.3 Comments
You can specify comments in any of the following three ways:
{ comment}
(. comment .)
"comment"
(The spaces before and after the comment delimiters are for clarity only; you don't have
to include these spaces.) For example, here are three comments:
{ This is a comment. }
(* This is a comment. *)
"This is a comment."
Unlike standard Pascal, the comment delimiters of Domain Pascal must match. For example, a comment that starts with a left brace doesn't end until the compiler encounters a
right brace. Therefore, you can nest comments, for example:
{ You can (*nest*) comments inside other comments. }
The Domain Pascal compiler ignores the" text of the comment, and interprets the first
matching delimiter as the end of the comment.
Standard Pascal does not permit nested comments. If you want to use unmatched comment
delimiters, as standard Pascal allows, you must compile with the -iso switch. Chapter 6
describes that switch.
Finally, Domain Pascal permits you to put compiler directives inside comment delimiters.
However, if you do so, you cannot use spaces; see the listing for "Compiler Directives" in
Chapter 4 for details.

C.l.4 Sections
Domain Pascal allows you to assign code and data in your program to a nondefault section.
A section is a named contiguous area of main memory.

C.l.S Declarations
You can declare the label, const, type, and var declaration parts in any order. You can
specify the declaration parts an unlimited number of times.
In addition to label, const, type, and var declaration parts, you can also declare a define
part, which is detailed in Chapter 7, an attribute part, which is detailed in Chapter 3, and
a routine options part, which is detailed in Chapter S.

I

C-2

Extensions to Standard Pascal

C.I.6 Constants
You can set a constant equal to a real, integer, string, char, or set expression. The constant can also be the pointer expression nil. The expression can contain the following types
of terms:
•

A real number, an integer, a character, a string, a set, a Boolean, or nil

•

A constant that has already been defined in the const declaration part (note that
you cannot use a variable here)

•

Any predefined Domain Pascal function (for example, chr, sqr, Ishft, sizeof), but
only if the argument to the function is a constant, or, in the case of sizeof, an
array.

•

A type transfer function

You can optionally separate these terms with any of the following operators:
Data Type of Operand

Operator
+, -,

•

Integer, real, or set
Real

/

mod, diy, I, &,

-

Integer

For example, the following const declaration part defines ten constants:

CONST
x
y

10;
100;

z

x + y;

current_year
leap_offset
bell
BEL
alert
pathname
pathname_len

1994;

(current_year mod 4);
chr(7);
7

'WARNING' (BEL, BEL)
'//et/go_home';
sizeof(pathname);

C.I.7 Labels
In standard Pascal, only integers can be used as labels. In Domain Pascal, you can use
both identifiers and integers as labels.

Extensions to Standard Pascal

C-3

C.2 Extensions to Data Types
Chapter 3 describes the data types supported by Domain Pascal. This section describes the
extensions that Domain Pascal supports.

C.2.1 Initializing Variables in the Var Declaration Part
Domain Pascal lets. you initialize variables in the var declaration part. You can initialize
integer, real, Boolean, char, subrange, set, enumerated, array, record, and pointer variables with an assignment statement following the data type; for example:
VAR

x
r
a

integer:= 17;
real:= 5.3E-14;
array[1 .. 7] of char := 'Wyoming';

For arrays in particular, Domain Pascal supports many extensions for simplifying initialization. See Chapter 3 for details.

C.2.2 Integers
Domain Pascal supports the following two nonstandard predeclared integer data types:
•

Integer16 - Use it to declare a signed 16-bit integer. (Integer and integer16
have identical meanings.)

•

Integer32 - Use it to declare a signed 32-bit integer. A signed 32-bit integer
variable can be any value from -2147483648 to +2147483647.

C.2.3 Reals
Domain Pascal supports the following two nonstandard predeclared real data types:
•

Single - Same as real.

•

Double - Use it to declare a signed double-precision real variable. Domain Pascal represents a double-precision real number in 64-bits. A double-precision real
variable has approximately 16 significant digits.

C.2.4 Pointer Types
In addition to the standard pointer type, Domain Pascal supports a univ_ptr type and a
special pointer type that points to procedures and functions.

C-4

Extensions to Standard Pascal

The predeclared data type univytr is a universal pointer type. A variable of type
univ_ptr can point to a variable of any type. You can use a univytr variable in the following contexts only:
•

Comparison with a pointer of any type

•

Assignment to or from a pointer of any type

•

Formal or actual parameter for any pointer type

•

Assignment to the result of a function

Domain Pascal supports a special pointer data type that points to a procedure or a function. By using procedure and function data types, you can pass the addresses of routines
obtained with the addr predeclared function. (See the addr listing of Chapter 4 for a description of this function.) You may only obtain the addresses of top-level procedures and
functions; you cannot obtain the addresses of nested or explicitly declared internal procedures and functions. (See Chapter 5 for details about internal procedures.)

C.2.S Variable-Length Strings
Domain supports variable-length strings, which are declared with the varying type specifier.
Unlike fixed-length arrays, the size of variable-length strings can change dynamically during program execution.

C.2.6 Named Sections
By default, Domain Pascal stores all variables declared in· the var declaration part at the
program or module level to the . data section. However, Domain Pascal enables you to assign variables to sections other than . data. Named variable sections are synonymous with
named common blocks in FORTRAN.

C.2.7 Variable and Type Attributes
Domain Pascal supports attributes for variables and types. These attributes supply additional
information to the compiler when you declare a variable or a type.
The volatile, atomic, and device attributes enable you to turn off certain optimizations
that would otherwise ruin programs that access device registers or shared memory locations.
The address attribute associates a variable with a specific virtual address. Alignment and
size attributes enable you to enhance your program's performance by specifying methods
for storage allocation. Domain Pascal supports the following alignment attributes: aligned,
natural. Domain Pascal supports the following size attributes: bit, byte, word, long,
quad.
Domain Pascal supports an attribute declaration that allows you to define attributes.

Extensions to Standard Pascal

C-S

C.2.S Aligned Record and Unaligned Record
Domain Pascal supports aligned record and unaligned record data types that you can use
to make sure that records receive the same layout in all alignment environments.

C.3 Extensions to Code
Chapter 4 describes the action part (the executable block) of a Pascal program. This section describes the extensions.

C.3.1 Exponentiation Operator
Domain Pascal supports an exponentiation operator in the following form:

mantissa· • exponent.

C.3.2 Bit Operators
Domain Pascal supports four bit operators for bitwise and, not, xor, and or operations.
These operators perform Boolean operations by comparing the bits in each bit position of
two integer arguments. For details on these operators see the "Bit Operators" listing in
Chapter 4.

C.3.3 Boolean Short-Circuit Operators
Domain Pascal supports the and then and or else operators. You can use and then and
or else to guarantee that Domain Pascal will evaluate Boolean expressions in the order that
you write them. They also guarantee "short-circuit" evaluation; that is, at run time, the
system will only evaluate as many expressions as is necessary. For details, see the and and
the or listings in Chapter 4.

C.3.3 Bit-Shift Functions
Domain Pascal supports the following three bit-shift functions:
•

rshft, which shifts the bits in an integer a specified number of spaces to the right.

•

arshft, which shifts the bits in an integer a specified number of spaces to the right
and preserves the sign of the integer.

•

Ishft, which shifts the bits in an integer a specified number of spaces to the left.

For syntax details, see the rshft, arshft, and Ishft listings in Chapter 4.

C-6

Extensions to Standard Pascal

C.3.4 Compiler Directives
Domain Pascal supports the compiler directives shown in Table 4-11.
You can place a directive anywhere in your program. To use a directive, specify its name
in a comment or as a statement. For example, all of the following formats are valid:
{%directive}
(. %directive·)
%directive
If you specify a directive within a comment, the percent sign must be the first character
after the delimiter. (Spaces count as characters.)

Domain Pascal supports a predeclared conditional variable, _BFMT__COFF, whose value
is set to true whenever the compiler is generating COFF (Common Object File Format)
files.
Domain Pascal supports a pair of predeclared conditional variables that you can use to find
out whether the compiler is generating code for the 68000 family of workstations or for the
Series 10000 workstation. These variables are: _ISP__M68K (for 68000 code generation) and _ISP__A88K (for Series 10000 code generation).

C.3.S Addr Function
Domain Pascal supports an addr function that returns the virtual address of the specified
variable or routine. For syntax details, see the addr listing of Chapter 4.

C.3.6 Align Function
Domain Pascal supports an align function that copies an expression to memory and aligns
it to match the specification of a formal parameter of an external routine.

C.3.7 Max and Min Functions
Domain Pascal supports a max and a min function for finding the larger and smaller of
two operands, respectively.

C.3.8 Discard Procedure
Domain Pascal supports a discard procedure for explicitly discarding the computed value
of an expression. It usually is used with a function (which in standard Pascal must return a
value) for which the value is not needed. The optimizer may eliminate the computation
and issue a warning message if the return value isn't used, but discard explicitly throws
away the computed value and so eliminates the warning message.

Extensions to Standard Pascal

C-7

C.3.9 Routines for Variable-Length Strings
Domain Pascal supports four routines for manipulating variable-length strings:
append

Concatenates two or more strings. The destination string must be a
variable-length string.

ctop

Adjusts the current length of a variable-length string based on the
presence of a terminating null character.

ptoc

Appends a terminating null character to the body of a variable-length
string.

substr

Finds a substring in a variable-length or fixed-length string.

C.3.10 1/0 Procedures
Domain Pascal supports the 1/0 procedures of standard Pascal, plus the following four procedures:
•

Open, which opens permanent files for I/O access.

•

Close, which explicitly closes an open file.

•

Find, which locates a specific element in a record-structured file.

•

Replace, which modifies an existing element in a record-structured file.

As in standard Pascal, you can create a temporary file with the rewrite procedure; however, by using the open procedure, you can create a permanent file. (Here, "permanent"
means a file that exists even after the program terminates.)
When a program terminates, the operating system automatically closes any open files. However, because an open file can clog system resources, Domain Pascal provides a close procedure that allows you to close a file from within your program.
The find procedure locates records from a record-structured fiie. Records here refer to
the elements in a file whose file variable was declared as a file of data type. By using replace in combination with find, you can replace an existing record.
From a Domain Pascal program, you can easily access Input Output Stream calls (known
as lOS calls) and formatting calls (known as VFMT calls).
For syntax details, see the open, close, find, and replace listings in Chapter 4. For an
overview of 1/0 (including lOS calls and VFMT calls), see Chapter 8.

C-8

Extensions to Standard Pascal

C.3.12 Loops
Domain Pascal supports for, while, and repeat, which are the three looping statements of
standard Pascal. Domain Pascal also supplies the following two additional statements for
further control within a loop:
•

A next statement for skipping over the current iteration of a loop

•

An exit statement for unconditionally jumping out of the current loop

For syntax details, see the next and exit listings of Chapter 4.

C.3.13 Range of a Specified Data Type
Domain Pascal supports
•

A firstof function for returning the first possible value of a specified scalar data
type

•

A lastof function for returning the last possible value of a specified scalar data
type

For syntax details, see the firstof and lastof listings in Chapter 4.

C.3.14 Integer Subrange Testing
By default, Domain Pascal does not check the value of input data to see that it falls within
the defined range of a variable declared as a subrange of integers. To determine whether
or not a specified value is within the defined integer subrange, you can use the in_range
function. For syntax details, see the in_range listing in Chapter 4.

C.3.1S Extensions to Read and Readln
In addition to allowing input into any real, integer, char, or subrange variable, as standard
Pascal allows, Domain Pascal's read and readln also allow input to a Boolean or enumerated variable.

C.3.16 Premature Return from Routines
As in standard Pascal, Domain Pascal returns control to the calling routine after executing
the last line in the called routine. If you want to return to the· calling routine before
reaching the last line, you can issue a return statement. For syntax details, see the return
listing in Chapter 4.

Extensions to Standard Pascal

C-9

C.3.17 Memory Allocation of a Variable
Domain Pascal supports a sizeof function. This function returns the size (in bytes) that a
data type (predeclared or user-defined), variable, constant, or string inhabits in main
memory.

C.3.18 Extensions to With
Domain Pascal supports the standard format of with as well as the following alternative
format:
with vl:identifierl, v2:identifier2, ... vN:identifierN do
stmnt;
An identifier is a pseudonym for the record variable v. To specify a record, use the identifier instead of the record variable v. Furthermore, to specify a field in a record, use identifier.field_name rather than v.field_name.
For example, given the following record declaration
basketball_team

record
mascot
height
end;

array[1 .. 15] of char;
single;

consider the following three methods of assigning values:
readln(basketball_team.mascot);
readln(basketball_team.height);
WITH basketball_team DO
begin
readln(mascot);
readln(height);
end;
WITH basketball_team : B DO
begin
readln(B.mascot);
readln(B.height);
end;

{Not using WITH.}

{Using standard WITH.}

{Using extension to WITH.}

The with extension is useful for working with long record names when two records contain
fields that have the same names.

C-IO

Extensions to Standard Pascal

C.3.19 Type Transfer Functions
Domain Pascal supports type transfer functions which enable you to change the type of a
variable or expression within a statement. To perform a type transfer function, use any
user-created or standard type name as if it were a function name in order to "map" the
value of its argument into that type.
With one exception, the size of the argument must be the same as the size of the destination type. (Chapter 3 describes the size of each data type). This size equality is required
because the type transfer function does not change any bits in the argument. Domain Pascal just "sees" the argument as a value of the new type. The one exception is that integer
subranges are compatible.

C.3.20 Extensions to Write and Writeln
Domain Pascal allows you to specify a negative field width for chars, strings, and arrays of
chars. Also, if you specify a one-part field width for a real number, Domain Pascal adds
or removes leading blanks. See the listing for write and writeln in Chapter 4 for details.

C.4 Extensions to Routines
Chapter 5 describes procedures and functions. The term "routine" means either procedure
or function. Also, the term "argument" refers to the data passed to a routine while "parameter" means the templates for the data to be received.
The following subsections describe Domain Pascal's extensions to routine calling.

C.4.1 Direction of Data Transfer
In standard Pascal, you cannot specify the direction of parameter passing. However, Domain Pascal supports extensions to overcome this problem. You can use the following keywords in your routine declaration:
•

In - This keyword tells the compiler that you are going to pass a value to this
parameter, and that the routine is not allowed to alter its value. If the called routine does attempt to change its value (that is, use it on the left side of an assignment statement), the compiler issues an "Assignment to IN argument" error.

•

Out - This keyword tells the compiler that you are not going to pass a value to
the parameter, but that you expect the routine to assign a value to the parameter.
It is incorrect to try to use the parameter before the routine has assigned a value
to it, although the compiler does not issue a warning or error in this case.

Extensions to Standard Pascal

C-ll

If the called routine does not attempt to assign a value to the parameter, the compiler may issue a "Variable was not initialized before this use" warning. This· could
occur if your routine only assigns a value to the parameter under certain conditions. If that is the case, you should designate the parameter as var instead of
out.

In some cases, the compiler cannot determine whether all paths leading to an out
parameter assign a value to it. If that happens, the compiler does not issue a
warning message.
•

In out - This keyword tells the compiler that you are going to pass a value to the
parameter, and that the called routine is permitted to modify this value. It is incorrect to call the routine before assigning a value to the parameter, although the
compiler does not issue a warning or error in this case. The compiler also doesn't
complain if the called routine does not attempt to modify this value.

C.4.2 Universal Parameter Specification
By default, Domain Pascal and standard Pascal check to: ensure that the argument you pass
to a routine has the same data type as the parameter you defined for the routine. As an
extension, you can tell Domain Pascal to suppress this type checking. You do this by using
the keyword univ prior to a type name in a parameter list. By using univ, you can pass
an argument that has a different data type than its corresponding parameter.
Univ is especially useful for passing arrays.

C.4.3 Routine Options
Standard Pascal supports a forward option. Domain Pascal supports the forward option,
and also supports the following routine options:

C-12

•

Extern - By default, Pascal expects a called routine to be defined within the
source code file where it is called. The extern option tells the compiler that the
routine is possibly defined outside of this source code file.

•

Internal - By default, all routines defined in modules become global symbols.
But, if you declare the routine with the internal option, the compiler makes the
routine a local symbol.

•

Variable - By default, you must pass the same number of arguments to a routine
each time you call the routine. However, by using the variable option in a routine declaration,. you can pass a variable number of arguments to the routine.

•

Abnormal - This option warns the compiler that a routine can cause an abnormal transfer of control.

Extensions to Standard Pascal

•

VaI_param - By default, Domain Pascal passes arguments by reference. However, by using the vaI_param option, you tell Domain Pascal to pass arguments by
value.

•

N osave - This option indicates that the contents of data registers D2 through D7,
address registers A2 through A4, and floating-point registers FP2 through FP7 will
not be saved when a called assembly language routine finishes and returns to the
Domain Pascal program. However, two registers are preserved: AS, which holds
the pointer to the current stack area, and A6, which holds the address of the current stack frame.

•

Noreturn - This option specifies an unconditional transfer of control; once a routine marked noreturn is called, control can never return to the caller.

•

DO_return - By default, a Pascal function returning the value of a pointer type
variable puts that value in address register AO. DO_return tells the compiler to put
the value in AO and data register DO.

•

AO_return - Specifying AO_return tells the compiler to put any values returned
from a called routine into AO and also to load return values to the calling routine
from AO.

•

Cyaram - Specifying C_param implies DO_return and val_param and also tells
the compiler to pass record data types by value, rather than by reference.

Domain Pascal supports a routine_option declaration part that allows you to define your
own names for groups of routine options. Furthermore, Domain Pascal provides a special
name, default_routine_options, that allows you to define the default routine options for
every routine in a module.

C.4.4 Routine Attribute List
You can specify a routine attribute list when you declare a routine. Within the routine attribute list, .you can specify a nondefault section name.
A "section" is a named contiguous area of an executing object. (Refer to the Domain/OS
Programming Environment Reference for full details on sections.) By default, the compiler
assigns code to the . text section and data to the . data section. Thus, by default, all code
from every routine in the program is assigned to . text, and all data from every routine in
the program is assigned to .data.
However, Domain Pascal permits you to override the default of .text and .data on a
routine-by-routine basis. (You can also override the defaults on a variable-by-variable or
module-by-module basis.) This makes it possible to organize the run-time placement of
routines so that logically related routines can share the same page of main memory and
thus reduce page faults. Conversely, you can declare a rarely called routine as being in a
separate section from the frequently called routines.

Extensions to Standard Pascal

C-13

C.S Modularity
Domain Pascal allows you to break your program into separately compiled source files. After compiling all the source files, you can bind the resulting objects into one executable
object file. Chapter 7 documents the details.

C.6 Other Features of Domain Pascal
Domain Pascal supports many other features, such as the ability to call routines written in
other Domain languages. However, the remaining features are all implementationdependent features, and not actual extensions.

----88----

C-14

Extensions to Standard Pascal

Appendix D
Deviations from Standard Pascal

This appendix describes Domain Pascal's deviations from ISO standard Pascal, and documents the sections in the ISO standard document to which Domain Pascal does not completely adhere.

D.I Deviations from the Standard
Domain Pascal does not include certain features of standard Pascal, and this list documents
the deviations:
•

Standard Pascal does not limit the length of identifiers; Domain Pascal limits identifiers to 4096 characters.

•

In standard Pascal the file list in the program heading is optional; Domain Pascal
ignores the file list in the program heading.

•

Standard Pascal does not limit the number of dimensions for arrays; Domain Pascal allows arrays of up to eight dimensions only.

•

Standard Pascal supports packed arrays, packed records, and packed sets.
Domain Pascal does not support packed sets, but you can get around this restriction by putting small sets in packed records. See Section 3.9.2 for further information on packing small sets within a packed record.

•

Standard Pascal requires that certain errors in code generate run-time faults. Examples of such errors include dereferencing NIL pointers and exceeding the
bounds of an array. However, if your program contains one of these errors, but
the statement with the erroneous code has no effect elsewhere in the program, the
optimizer may eliminate the code from your program. In this case, the run-time
fault will not occur.

Deviations from Standard Pascal

D-l

D.2 Deviations from Specific Sections of the Standard
The following section lists the sections in the ISO standard document (ISO 7185-1982) to
which Domain Pascal does not completely adhere and the ways in which Domain Pascal
does not adhere.
6.1.2

You may redeclare NIL.

6.1.5

You are not required to include a sequence of digits after a period in
a floating-point number.

6.1.8

You are not required to leave a blank between a number and a wordtype operator. For example, Domain Pascal accepts the following:

result := 10mod 1;
6.2.2

The following type of declaration works under Domain Pascal:

TYPE

rec

record
ptr
DlY_var

Amy_var;
integer

end;
my_var = rec;

6.4.3.3

There is no requirement that all values of a tag-type in a record appear as case constants.
Domain Pascal does not detect a reference to an inactive variant field.
Also, it does not mark variant fields as inactive when a new variant
tag becomes active.

6.4.5

Subranges of the same type that are defined with different ranges are
considered identical.
Domain Pascal considers structurally identical types to be identical.
For example, the following are identical under Domain Pascal:

TYPE

first = array[1 .. 20] ofinteger32;
second = array[1 .. 20] of integer32;
Also, Domain Pascal ignores the keyword packed, so structurally identical sets are considered identical.

D-2

Deviations from Standard Pascal

6.4.6

You may assign structured types containing a file component to each
other.
You may make an assignment from an integer expression that includes
a value outside one of the variables' declared subranges. Also, you
may pass an integer argument that is outside the corresponding parameter's declared subrange. In addition, Domain Pascal considers sets
of different subranges from the same enumerated type to be compatible for assignment and as parameters.

6.5.5

Domain Pascal does not detect when a field variable passed as a var
parameter is modified. It also does not detect a modification to a file
variable when a reference to the buffer exists.

6.6.3.3

You may pass the selector of a variant or a component of a packed
variable as a var parameter. Also, Domain Pascal accepts a procedure
call like the following where x is declared in the procedure heading as
being a var parameter:

proc_name ( (x) ) ;

6.6.3.5, 6.6.3.6
Domain Pascal treats integer and subrange of integer as identical.

6.6.3.6

Domain Pascal considers the following to be identical:
VAR

VAR

a
b

integer;
integer;

a,b

integer;

6.6.5.2

Domain Pascal does not detect a put of an undefined buffer variable
at compile time. It does not consider a read of an enumerated type to
be an error, or an assignment from a file variable of an enumerated
type followed by a get to be an error. You may write an integer expression that includes a value outside one of the variables' declared
subranges. Also, you may make an assignment from an integer expression that includes a value outside one of the file variables' declared
subranges.

6.6.5.3

You may dispose a pointer that is active because it has been
dereferenced as a parameter or in a with block. In addition, Domain
Pascal does not report an error if you use a pointer variable after you
have disposed of it or if you dispose of a dangling pointer (that is, a
pointer with an address assigned to another pointer).

Deviations from Standard Pascal

D-3

You also may use a record allocated with a long form of new as an
operand in an expression or as a variable in an assignment statement.
You may pass as an argument a variable that was allocated with new
and that uses variant tags.
Domain Pascal does not report an error if you use different tags for a
variable in new and dispose. It also does not detect the activation of
a variant on a variable that new allocated with a different tag, or if
your program includes illegal variant tags in a dispose.

6.6.5.4

The pack procedure accepts a normal array where packed is expected, and a packed array where a normal array is expected.
In pack, Domain Pascal does not detect an uninitialized component in
the unpacked array. Similarly, in unpack, Domain Pascal does not
detect an uninitialized component in the packed array.

6.6.6.2

On some workstations, the sqr function does not detect overflow.

6.6.6.3

On some workstations, trunc and round do not detect overflow.

6.6.6.4

Succ, pred, and chr do not detect overflow.

6.7.2.2

Domain Pascal does not detect an overflow or underflow on integer
arithmetic. Also, it allows you to supply a negative value for j in an
expression like the following:
i mod j

D-4

6.7.2.4

Domain Pascal does not detect operations on overlapping sets with
incompatible elements.

6.8.1

Domain Pascal permits jumps between branches of a case statement
and from one structured statement into the middle of another.

6.8.3.5

Domain Pascal does not detect the lack of a case statement constant
corresponding to a run-time case value.

6.8.3.9

Domain Pascal does not detect an underflow of an assignment from
pred to a for statement index variable. Also, it does not issue an error if there is an overflow in the final value of a for statement index
variable.

Deviations from Standard Pascal

Domain Pascal does not detect the possibility that an inner block will
change the value of a for statement's index variable. Also, Domain
Pascal allows a non-local variable, a formal parameter, or a value parameter to be used as a for statement's index variable. You also can
use a program level global variable as the index variable for a for
statement that resides in an inner block.
6.9.1

Domain Pascal does not detect an overflow of a subrange boundary
for a read statement.

6.9.3.1

You may supply a nonpositive field width or a nonpositive fractionaldigits field width to a write or writeln.

6.10

You don't have to declare input and output in a program heading to
use them in the program. You can, however, repeat parameters in a
program heading such as
program testing (output, output);
or redeclare program parameters as some type other than a file. Also,
you don't have to declare program parameters in the var declaration
part of your program.

----88----

Deviations from Standard Pascal

D-S

Appendix E
Systems Programming Routines

Domain Pascal includes several routines designed specifically for systems programmers' use.
Systems programmers are those who need to do very low-level work in their programs and
who need direct access to specific registers and bits within those registers. They frequently
write some programs in Pascal and some in assembly language.
If you are a systems programmer, you might use these routines when writing device drivers,
or when doing other low-level manipulations of the hardware status register.

E.l Overview
Table E-1 briefly describes the available systems programming routines. all of which are
extensions to standard Pascal. A more complete explanation follows the table.

Table E-1. Systems Programming Routines
Routine

Action

disable

Turns off the interrupt enable in the hardware status register.

enable

Turns on the interrupt enable in the hardware status register.

set_sr

Saves the current value of the hardware status register and then
inserts a new value.

Systems Programming Routines

E-l

E.2 Restrictions for Use
All the routines described in this appendix generate privileged instructions and may only be
executed from supervisor mode. If you try to run a program using one of these routines
while in user mode, you get a privilege-violation error.

E-1

Systems Programming Routines

Disable Turns off the interrupt enable in the hardware status register. (Extension)

FORMAT
disable

{disable is a procedure.}

ARGUMENT
Disable takes no arguments.
DESCRIPTION
Disable is a built-in procedure for systems programmers' use. It turns off the interrupt enable in the hardware status register and should be used with its complementary procedure
enable.
By turning off the interrupt enable, disable allows you to prevent an interrupt from coming
in while the program is in a critical section. After the critical section finishes, you should
use enable to turn the interrupt enable back on.
The disable-enable pair look like this in code:

disable;
{ Critical section.
}
{ No interrupts allowed while this section is executing. }
enable;
If you mistakenly use only disable, your program win essentially grind to a halt since no

interrupt signals will be able to get to it. You should only use the disable-enable pair
around very small sections of code.

Systems Programming Routines

E-3

Enable Turns on the interrupt enable in the hardware status register. (Extension)

FORMAT
enable

{enable is a procedure.}

ARGUMENT
Enable takes no arguments.

DESCRIPTION
Enable is a built-in procedure for systems programmers' use. It turns on the interrupt enable in the hardware status register and usually is used with its complementary procedure
disable.
By turning on the interrupt enable, enable allows your program to receive interrupts. Usually, disable will have been used to prevent the reception of interrupts during a critical
section of code. After the critical section finishes, enable lets the interrupts flow.
The disable-enable pair look like this in code:
disable;
{ Critical section.
}
{ No interrupts allowed while this section is executing. }
enable;
Because the interrupt enable is turned on by default, there is no effect if you mistakenly
use only enable in your program.

E-4

Systems Programming Routines

Set sr Saves the current value of the hardware status register and then inserts a new one.
(Extension)

FORMAT

oldsr := set_sr(newsr);

{set_sr is a function.}

ARGUMENT

oldsr

The old value of the hardware status register.

newsr

The new value of the hardware status register.

DESCRIPTION
Set_sr is a built-in function for systems programmers' use. It reads the hardware status
register (SR) and replaces its current value with newsr. The original value then is assigned
to oldsr. This translates to assembly language code something like this:
move.w
move.w
move.w

SR,dO
newsr,SR
dO,oldsr

The function eliminates six instructions in a time-critical path.

-------88-------

Systems Programming Routines'

E-S·

Appendix F
Optimizing Floating-Point
Performance on MC68040-Based
Domain Workstations

This appendix describes how to obtain the best floating-point performance on the new Domain MC68040-based workstations, such as the HP Apollo 9000 Series 400 Model 425t or
433s.
NOTE:

The performance improvements described in this appendix are
estimates for typical floating-point applications based on standard hardware configurations and standard software configurations. The performance improvements on your system, if any,
will probably be different from (though along the lines of) the
improvements described here.

The Motorola MC68040 microprocessor chip features floating-point performance almost an
order of magnitude greater than that of its predecessor, the 68030/68882. Floating-pointintensive application binaries that currently run on Domain platforms will experience an
immediate and dramatic performance increase when run on the new Domain 68040-based
platforms. The increase is usually in the range of two to six times over the performance of
the DN4500 Personal Workstation.
Floating-point arithmetic on 68040-based Domain platforms is nearly identical to floatingpoint arithmetic on 68020/68881-based and 68030/68882-based platforms, with only minor differences. Also, how you compile an application affects floating-point performance
on the two platforms. In the following sections, we describe these functional and performance differences and tell you how to maximize floating-point performance on the
68040-based Domain workstations.

Floating-Point Performance on MC68040-Based Workstations

F-l

We discuss the following topics:

F.1

•

Instruction emulation

•

How to determine if an application relies heavily on instruction emulation

•

How instruction emulation affects performance

•

What steps to take for your application

•

What it means if you get different results on the 68040 and the 68020/68030

Instruction Emulation
The 68040 has an on-chip floating-point unit that directly supports only a subset of the
68881/68882 architecture. Floating-point functionality that is not directly supported in
hardware is provided through system traps; these system traps invoke a kernel routine that
emulates the missing functionality. The emulation routine supports some instructions in the
68881/68882 instruction set and some data types.
Because software emulation is inherently slower than direct hardware execution, emulated
instructions execute more slowly than hardware instructions. To maximize floating-point
performance, you should either compile your application so that it has no emulated instructions, or determine that it does not have enough of them to degrade the performance of
the code. We describe how to do this in the following sections.

F.2

How to Determine If an Application Relies Heavily on
Instruction Emulation
The only applications with emulated instructions are those that were compiled with the
-cpu 3000 option. (We now call this option ..;cpu rnathchip. For information about the
-cpu option, see Section 6.4.9.) Applications that may contain emulated instructions include
•

FORTRAN applications

•

Pascal applications

•

C applications that are compiled with the -D_BUILTINS option (/bin/cc) or the
-def _BUILTINS option (/corn/cc) or that include the file 

The emulated instructions correspond to the following arithmetic intrinsic functions listed in
Table F-1.

F-2

Floating-Point Performance on MC68040-Based Workstations

Table F-l. Emulated Intrinsic Functions

FORTRAN

C

Pascal

SIN, DSIN

sinO

sin

COS,DCOS

cosO

cos

TAN,DTAN

tan 0

--

ATAN,DATAN

atanO

arctan

EXP, DEXP

expO

exp

ALOG,DLOG

logO

In

ALOGI0, DLOGI0

log100

--

AINT, DINT

--

--

If an application does not use any of these intrinsics, then it will run nearly optimally on
both the 68040 and the 680xO/6888x when compiled with -cpu mathchip.

Applications that are compiled with -cpu any, the old default -cpu argument, do not contain any emulated instructions. However, use -cpu any only if your code must run on all
existing Domain 680xO-based workstations because this argument imposes a severe performance penalty, usually a greater penalty than that caused by instruction emulation.
Intrinsic functions other than those listed in Table F-l (such as ASIN, ACOS, and hyperbolic functions) are always performed by run-time libraries that use only hardwareexecuted floating-point instructions. For example, if your FORTRAN program calls the
SINH intrinsic, the, compiler never generates the FSINH instruction; instead, it generates a
call to the ftn_$dsinh routine.

F.3

How Instruction Emulation Affects Performance
As a rule of thumb, the 68040 will emulate an instruction at least as fast as a 68882 running at the equivalent clock frequency would execute it directly. What we call a performance penalty on 68040-based systems is actually unrealized performance potential, not performance degradation. Unchanged and un-recompiled applications will almost always realize some performance increase on the 68040 above what 68030-based and 68020-based
systems delivered.
We cannot predict what kinds of performance increases you can obtain by recompiling
your application for the 68040 unless we know the details of your application. We can
offer some general guidelines, however. The following subsections describe the performance ratio for an application on a 68040-based system when you recompile with various
-cpu arguments.

Floating-Point Performance on MC68040-Based Workstations

F-3

F.3.1

Changing from -cpu 3000 (-cpu mathchip) to -cpu mathlib or -cpu
mathlib_srlO
If your application makes intensive use of SIN, COS, TAN, ATAN, EXP, or LOG, and is

currently compiled with -cpu 3000, then the performance boost from recompiling with
-cpu mathlib or -cpu mathlib_srlO will probably be between one and three times, with
most applications improving about 1.5 times. This boost results from removing emulated
instructions from your code.

F.3.2

Changing from -cpu any to -cpu mathlib or -cpu mathlib_srlO
If your application is currently compiled with -cpu any, regardless of the intrinsics used,

then the performance boost from recompiling with -cpu mathlib or -cpu mathlib_srlO
will probably be approximately two times, with some applications improving up to four
times. This boost is due to the superior performance of inline floating-point instructions.

F.3.3

Changing from -cpu any to -cpu mathchip (-cpu 3000)
If your application makes intensive use of SIN, COS, TAN, ATAN, EXP, or LOG, and is

currently compiled with -cpu any, then the performance boost from recompiling with -cpu
mathchip will probably be between 0.7 times and four times, with most applications improving about 1.3 times. The use of inline floating-point instructions improves performance, but inline emulated instructions degrade performance. We derive this estimate by
combining the previous figures.
NOTE:

F.4

In the worst case, performance may actually degrade when you
recompile an application from -cpu any to -cpu mathchip.
However, the same recompilation may significantly improve performance on 68020-based and 68030-based systems.

What Steps to Take for Your Application
You have two separate decisions to make:

F.4.1

•

Whether to recompile

•

If you recompile, which -cpu argument to use

Should You Recompile?
When you decide whether to recompile for the 68040, you should consider not only the
performance to be gained on the 68040, but also the effect the recompilation will have OIl
68020-based and 68030-based systems. Consider the proportion of pre-68040 and 68040
systems your application runs on today, and what you expect in the future. Targeting the

F-4

Floating-Point Performance on MC68040-Based Workstations

pre-68040 systems may yield better performance for the customer today, but recompiling
for the 68040 now may well yield big dividends as the percentage of 68040-based installed
Domain workstations increases.
If you compiled your application with -cpu any, then you are probably incurring a severe

performance penalty on all 68020-based, 68030-based, and 68040-based systems. You
should recompile unless you have to support older Apollo architectures (for example, the
DN460 workstation or the PEB).
If you compiled your application with -cpu 3000 or one of its equivalents, then you should

recompile if you think your application performs much instruction emulation on the 68040.

F.4.2

If You Recompile, Which -cpu Argument Should You Use?
If your application needs to run optimally only on 68040-based systems, then compile with

-cpu mathIib.
If your application needs to run optimally on 68020-based and 68030-based systems, but
you don't care about its performance on the 68040, then compile with -cpu mathchip. If

you previously compiled your application with -cpu 3000 (equivalent to -cpu mathchip),
you do not need to recompile.
If your application needs to run well on 68020-based, 68030-based, and 68040-based systems, and you think it does not perform much instruction emulation on the 68040, then
you may compile with either -cpu mathchip, -cpu mathlib_srlO, or -cpu mathlib. If
you think your application performs much instruction emulation on the 68040, then recompile with -cpu mathlib_srlO or -cpu mathlib. Use -cpu mathlib_srlO if your code must
run on 68020-based and 68030-based systems with a Domain/OS release earlier than
SR10.3; otherwise, use -cpu mathlib.

Figure F-l shows how to decide which argument is most suited to your application.

Floating-Point Performance on MC68040-Based Workstations

F-S

Must run well
on 020, 030,
and 040

J.-----II~

Figure F-l. Which -cpu Argument Is Best for Your Application?

F-6

Floating-Point Performance on MC68040-Based Workstations

F.S

If You Get Different Results on the 68040 and the 68020/68030
When you run a large floating-point application on a 68040-based Domain workstation,
the results may differ slightly from those on 68020-based and 68030-based platforms.
The differences are caused by the algorithms used to approximate trigonometric and transcendental math functions. Having two different sets of results does not mean that one is
correct and the other incorrect, because floating-point intrinsic functions are inherently
approximations. One math function can give two different results on two different platforms, yet both results can be acceptably precise approximations of the true result and are
therefore both "correct."
Two different platforms can both comply with the IEEE-754 standard for floating-point
arithmetic, yet applications executed on these two platforms may not behave identically
because the IEEE standard does not cover many common math functions. Therefore,
each new implementation may yield slightly different behavior.
Inevitably, a few applications will yield extremely different results on the 68040, or may
malfunction with various floating-point exceptions, such as overflow or divide-by-zero.
Experience shows that these cases are almost always caused by applications that use some
platform-specific feature; the application fails to run properly when executed on another
platform that does not support that feature.
For example, the extended-precision capability of the 6888x-based platforms enables intermediate results in floating-point registers to exceed the maximum magnitude of doubleprecision. Thus a variable declared as double-precision can, during an application's execution, assume much larger values than on a machine that does not support extendedprecision registers. Applications that use this feature will probably fail on the 68040, even
though the 68040 supports extended-precision registers. The reason is that the 68040 relies on run-time libraries; therefore, values in floating-point registers are stored to memory
in single-precision or double-precision format much more often than on the 6888x.
The Series 10000 workstations and the Domain Floating-Point Accelerator. (FPA) do not
support extended-precision registers. If your application runs correctly on either of these
platforms, it will probably run correctly on the 68040.
For more information about floating-point results on different Domain platforms, see the
Domain Floating-Point Guide.

----88----

Floating-Point Performance on MC68040-Based Workstations

F-7

Index
Symbols are listed at the beginning of the index.

Symbols
. (period ), and record field names, 4-158
(exclamation point), as bitwise and operator,
4-3
; (semicolon)
in compiler directives, 4-43 to 4-44
in statements, 4-188
(colon)
in case statement, 4-36
in otherwise clause of case, 4-37
in record declarations, 3-19
:= (colon and equal sign), to initialize variables

in declaration, 3-4
" (double quotes), as comment delimiter, 2-3
to 2-4, 6-11
, (single quote)
as character constant delimiter, 3-12
as string delimiter, 2-4 to 2-6

o (parentheses)
with asterisk (.), as comment delimiter,
2-3 to 2-4, 6-11
in enumerated declarations, 3-13
with mathematical expressions, 2-2
as section name delimiters, 3-52
using to organize complex expressions,
4-81
[] (square brackets)
in array declaration, 3-38
in array initialization, 3-39
in record initialization, 3-21
and set assignment, 4-173
[} (braces), as comment delimiters, 2-3 to 2-4.
6-11

& (ampersand)

as bitwise and operator, 4-3
distinguished from and operator, 4-18
# (pound sign), in non-decimal base numbers.
2-2
$ (dollar sign), in identifier names. 1-4
% (per cent sign), with compiler directives,
4-43
+ (plus sign)
as addition operator. 4-3
as set union operator, 4-3, 4-174
- (minus sign)
as set exclusion operator, 4-3. 4-175
as subtraction operator, 4-3
• (asterisk)
as array boundary in declaration, 3-42
in filenames, 4-130
as mUltiplication operator, 4-3
with parentheses 0, as comment delimiter,
2-3 to 2-4
in repeat counts, 3-40
as set intersection operator, 4-3, 4-175
(double asterisk), as exponentiation operator,
4-3
/ (slash), as division operator, 4-3
(caret)
dereferencing a procedure or function
pointer, 4-145
with pointer type declarations. 3-50
= (equal sign)
as mathematical operator, 4-3
in record declarations, 3-19
as set equality operator, 4-3, 4-176
in type declarations, 2-13
< (less than)
as mathematical operator, 4-3
redirecting standard input, 6-39
<= (less than or equal sign)
as mathematical operator, 4-3
as set subset operator, 4-3, 4-176

*.

A

Index

1

<> (less than or greater than sign)
as mathematical operator, 4-3
as set inequality operator, 4-3, 4-176
> (greater than)
as mathematical operator, 4-3
redirecting standard output, 6-39
>= (greater than or equal sign)
as mathematical operator, 4-3
as set subset operator, 4-3
as set superset operator, 4-176 ·to 4-177
- (tilde), as bitwise and operator, 4-3
_ (underscore), in identifier names, 1-4

A
AO_return routine option, 5-20
Abbreviating record names, 4-211 to 4-214
Abnormal routine option, 5-19
Abs function, 4-6, 4-12
sample program, 4-12
Absolute value, 4-12
-ae compiler option, 6-9
Access. See Scope
Access violation, 9-50, 9-52
Accessing
data that is not naturally aligned, 3-74 to
3-75
elements in variable-length strings, 3-45
files, delayed, 8-5
routines in Pascal modules, 7-8 to 7-13
variables, in other Pascal modules, 7-3 to
7-8
Accuracy, and expansion of operands, 4-5
Action part
of a program, 4-1
of a routine, 4-188
Actual parameters. See Arguments
Addition, 4-3
Addr function, 4-13 to 4...;.15
sample program, 4-14 to 4-15
using with pointers to routines, 3-50
Address, using addr function to obtain, 4-13 to
4-15
for procedure and function pointers, 4-145
Address attribute, 3-59

2,

Index

Addresses
manipulating with pointers, 4-144 to 4-146
manipulating with type transfer functions,
4-144 to 4-145
Align function, 4-16 to 4-17
sample program, 4-17
Aligned, records, 3-33 to 3-35
byte, 3-23
default, 3-23
longword, 3-23
natural, 3-23, 3-33
shortword, 3-23
word, 3-23, 3-33
Aligned attribute, 3-63 to 3-76
inheritance of, 3-68
list of uses, 3-64
portability issues, 3-64
using to prevent padding, 3-69 to 3-72
using to suppress information messages,
3-74
using with %natural_alignment directive,
3-70 to 3-72
using with arrays of records, 3-66 to 3-67
using with pointers, 3-75 to 3-76
Alignment
align function, 4-16 to 4-17
array elements, 3-47
attributes. See Alignment attributes
Boolean variables, 3-11
byte aligned record fields, 3-26
of character data types, 3-13
default, for records, 3-26
definition, 3-23
integers, 3-5
messages, compiler option to display, 6-9
minimum, definition, 3-23
mode, 4-58
natural
align function, 4-16 to 4-17
compiler option, 6-25 to 6-26
definition, 3-23
%natural_alignment directive, 4-57
portability of records, 3-64
for record fields, 3-29 to 3-38
See also Natural alignment
packed records, 3-35
pointer type data, 3-52
%pop_aUgnment directive, 4-58
pre-SR10, 4-57
%push_alignment directive, 4-58
real data types, 3-7 to 3-10
records, 3-26
in arrays, 3-31 to 3-32

Alignment (continued)
of sets, 3-16 to 3-17
specifying with attributes, 3-62 to 3-76
variable-length strings, 3-44
word, %word_alignment directive, 4-57
Alignment attributes, 3-62 to 3-76
aligned
format, 3-63 to 3-64
overriding defaults with, 3-64
portability issues, 3-64
uses, list, 3-64
format, 3-63 to 3-64
inheritance of, 3-68
natural
format, 3-63 to 3-64
overriding defaults with, 3-64
portability issues, 3-64
use, 3-64
and natural alignment, 3-64 to 3-68
using to ensure same layout in all environments, 3-72 to 3-73
using to inform compiler of alignment,
3-74 to 3-75
using to pass pointers to unaligned objects,
3-76 to 3-78
using to prevent padding, 3-69 to 3-72
using to suppress information messages,
3-74
using with %natural_alignment directive,
3-70 to 3-72
using with pointers, 3-75 to 3-76
Allocating space, with new procedure, 4-117 to
4-122
Allocation. See Alignment; Internal representation
-alnchk compiler option, 6-9
Ampersand (&)
as bitwise and operator, 4-3
distinguished from and operator, 4-18
And operator, 4-3, 4-18 to 4-20
sample program, 4-20
And then operator, 4-3, 4-18 to 4-20
Anonymous data types, and parameters, 5-2
Apostrophe ('). See Single quote
Append procedure, 4-21 to 4-22
sample program, 4-21 to 4-22
Appending
null byte to string, 4-149 to 4-151
records to a file with put, 4-152 to 4-154

ar, UNIX archiver, 6-38 to 6-39
Archiving, library files, 6-38 to 6-39
Arctan function, 4-6, 4-23 to 4-24
sample program, 4-24
Arguments
alignment, align function, 4-16 to 4-17
arrays as, 4-27
difference from parameters, 5-1
passing arrays with un iv, 5-10
passing by reference, 5-3, 5-6 to 5-7
passing by value, 5-3, 5-6 to 5-7
vat'param routine option, 5-19
passing conventions, 5-3 to 5-5
passing from packed records, 3-21
pointers to routines as, 5-11 to 5-13
pointers to unaligned objects, 3-76
using in out keywords to specify direction,
5-7 to 5-9
sample program, 5-9
using univ to pass different data type, 5-10
to 5-11
using variable option to vary number of,
5-17 to 5-18
sample program, 5-18
variable and value parameters, sample program, 5-6
See also Parameters
Arithmetic, expressions
expansion of integers, 4-5
mixing integers with reals, 4-5
using parentheses, 2-2
Arithmetic right shift, 4-29 to 4-30
Arrays, 3-37 to 3-48
as arguments, 4-27
assigning values to, 4-25 to 4-27
bit, 3-62
-bounds_violation compiler option, 6-10
to 6-11
correspondence
in C, 7-36 to 7-38
in FORTRAN, 7-16
in FORTRAN example, 7-21 to 7-24
declaring, 3-37 to 3-38
defaulting the size of, 3-42
deviation from standard Pascal, D-1
first value, 4-87
how to use, 4-25 to 4-28
indexes
compiler option, 6-21
and pack procedure, 4-139 to 4-141
and unpack procedure, 4-200 to
4-202
:

Index

3

Arrays (continued)
initializing, 3-38 to 3-43
with default size, 3-42
extern, 7-5 to 7-6
individual components, 3-39 to 3-40
mixing methods, 3-43
multiple components with a single expression, 3-39
order of, 3-41
using repeat counts, 3-40 to 3-41
integers, byte, 3-62
internal representation of, 3-45 to 3-49
last value, 4-106
operations, 4-25 to 4-28
and pack procedure, 4-139 to 4-141
packed, 3-45
internal representation, 3-47 to 3-48
passing as arguments with univ, 5-10
of records, 3-31 to 3-32, 4-160 to 4-161
sample program, 4-28
and unpack procedure, 4-200 to 4-202
variable-length, 3-44 to 3-45
and write procedure, 4-216

Attributes
alignment. See Alignment attributes
routine. See Routine attributes
variables and types. See Attributes for variables and types
Attributes for variables and types, 3-53 to 3-78
address, 3-59
alignment, 3-62 to 3-76
inheritance of, 3-68
atomic, 3-56 to 3-57
attribute declaration part, 3-78
device, 3-57 to 3-59
format, 3-53 to 3-55
inheritance, 3-76 to 3-77
list of, 3-53
overview, 3-53 to 3-55
size, 3-60 to 3-62
summary, 3-55
syntax, 3-53 to 3-55
user-defined, 3-78
volatile, 3-56

Arshft function, 4-6, 4-29 to 4-30
sample program, 4-30
ASCII
values in identifiers, 2-1
See also ISO Latin-1
Assembly language
preserving registers, 5-19 to 5-20
systems programming routines, E-1 to E-5

B
-b compiler option, 6-9 to 6-10
Begin (reserved word), 4-31 to 4-32
sample program, 4-31 to 4-32
%begin_inline directive, 4-52 to 4-53, 6-32
%begin_noinline directive, 4-53 to 4-54, 6-32

Assigning values
to arrays, 4-25 to 4-27
to arrays of records, 4-160
to pointers with nil, 4-125
to set variables, 4-173

_BFMT_COFF conditional variable, 4-46

Asterisk, double (* *), as exponentiation operator, 4-3

Binary output, compiler option, 6-9 to 6-10

Asterisk (*)
as array boundary in declaration, 3-42
double (* *), as exponentiation operator,
4-3
in filenames, 4-130
as multiplication operator, 4-3
with parentheses (), as comment delimiters,
2-3 to 2-4, 6-11
in repeat counts, 3-40
as set intersection operator, 4-3, 4-175

Binding. See Linking

Binary numbers
bit operators, 4-33 to 4-35
See also Shifting bits
Bind command, 6-36, 6-37 to 6-39
Bit
arrays, 3-62
attribute, 3-60 to 3-62
operations. See Shifting bits
operators, 4-33 to 4-35
sample program, 4-35
table, 4-3

Atomic attribute, 3-56 to 3-57

Bit precision, controlling with type transfer functions, 4-197 to 4-199

Attribute declaration part, 3-78

Blanks, in prompt-strings, 4-130

4

Index

Boolean data types, 3-10 to 3-11
alignment of, 3-11
and operator, 4-18 to 4-20
and then operator, 4-18 to 4-20
arrays of, 3-46
correspondence, with FORTRAN logicals,
7-15
defining constants, 3-11
first value, 4-87
initializing, 3-10 to 3-11
internal representation of, 3-11
last value, 4-106
and logical not, 4-126 to 4-127
and logical or, 4-134 to 4-136
and logical or else, 4-134 to 4-136
and repeat/until statement, 4-161 to
4-162
and succ value, 4-191
and while statement, 4-208 to 4-210
and write procedure, 4-219 to 4-220
-bounds_violation compiler option, 6-10 to
6-11
Braces ({}), as comment delimiters, 2-3 to 2-4,
6-11
Brackets, square ([])
in array declaration, 3-38
in array initialization, 3-39
in record initialization, 3-21
and set assignment, 4-173
Branching. See Transferring control
.bss variables, 7-43 to 7-45
Byte
alignment, specifying with aligned attribute,
3-63
attribute, 3-60 to 3-62
byte aligned record fields, 3-26
integers, array, 3-62

c
C, calling from Pascal. See Calling C from Pascal
C_param routine option, 5-3, 5-21
Calling assembly language routines. See Assembly language
Calling C from Pascal, 7-28 to 7-46
aO_return routine option, 5-20
c-param routine option, 5-21
case sensitivity issues, 7-29 to 7-30

creating overlay sections, 7-45 to 7-46
ctop procedure, 4-61
dO_return routine option, 5-20
.data and .bss globals, 7-43 to 7-45
data sharing, 7-43 to 7-46
data type correspondence, 7-30 to 7-46
passing arrays, 7-36 to 7-38
sample program, 7-37
passing integers and real numbers, 7-30 to
7-31
sample program, 7-31
passing pointers, 7-38 to 7-40
sample program, 7-39 to 7-40
passing procedures and functions, 7-41 to
7-43
sample program, 7-41 to 7-42
passing strings, 4-61, 4-149 to 4-151,
7-32 to 7-35
sample program, 7-32 to 7-33, 7-34
to 7-35
ptoc procedure, 4-149 to 4-151
reconciling differences in argument passing,
7-29 to 7-30
Calling FORTRAN from Pascal, 7-13 to 7-28
aO_return routine option, 5-20
calling a function, 7-18 to 7-19
sample program, 7-18
calling a subroutine, 7-19 to 7-20
sample program, 7-19 to 7-20
dO_return routine option, 5-20
data type correspondence, 7-14 to 7-17
passing a mixture of data types, 7-21 to
7-24
sample program, 7-21 to 7-24
passing character arguments, 7-20 to 7-21
passing data, 7-17
passing procedures and functions, 7-24 to
7-28
sample program, 7-25 to 7-28
Caret (")
dereferencing a procedure or function
pointer, 4-145
with pointer type declarations, 3-50
Case sensitivity, 2-6
calling C from Pascal, 7-29
and identifiers, 2-1
Case statement, 4-36 to 4-38
sample program, 4-38
Changes to Domain Pascal, summary, iv to v
Changing data types, with type transfer functions, 4-197 to 4-199

Index

5

Character
formatting with VFMT calls, 8-2 to 8-3
null, in variable-length strings, 3-46, 4-205
Character data types, 3-11 to 3-13
alignment of, 3-13, 3-35
assigning to arrays, 4-26
correspondence, in FORTRAN, 7-20 to
7-21
declaring variables, 3-11
defining constants, 3-12
first value, 4-87
as for loop index variables, 4-89
initializing variables, 3-12
internal representation of, 3-13
last value, 4-106
string, . 3-38
See also Strings
and succ value, 4-191
and write procedure, 4-216
Characters
end-of-line, 4-75
ISO Latin-1, table, B-1 to B-5
Chr function, 4-39 to 4-40
sample program, 4-40
Cleanup handlers, and abnormal option, 5-19
Close procedure, 4-41 to 4-42, 8-9
sample program, 4-41 to 4-42
Closing files, 8-9
definition, 4-41
flushing the buffer, 4-41
See also Close procedure
Code
encyclopedia, 4-12 to 4-58
extensions to standard, C-6 to C-11
generation types, 4-46
optimized. See Optimized code
COFF (Common Object File Format), 4-46,
6-38
Colon (:)
in case statement, 4-36
in otherwise clause of case, 4-37
in record declarations, 3-19
Colon and equal sign (:=), to initialize variables
in declaration, 3-4
-comchk compiler option, 6-11
Comments, 2-3
using -comchk compiler option, 2-4, 6-11
delimiters, and compiler directives, 2-3

6

Index

extension to standard, C-2
nesting, 2-3
Common blocks. See Data sections
Common Object File Format (COFF), 6-38
Compatibility
alignment, 4-57
binding, 6-36
files, 8-7
files opened, 3-49
UNIX files, 3-48
Compiler directives, 4-43 to 4-58
%natural_alignment, using with alignment
attributes, 3-70 to 3-72
overriding alignment, 3-64
predicates, 4-46
table of, 4-44 to 4-45
Compiler optimizations. See Optimized code
Compiler options, 6-5 to 6-36
-ac, 6-9
-alnchk, 6-9
-b and -nb, 6-9 to 6-10
-bounds violation and -no bounds violation:- 6-10 to 6-11
-comchk and -ncomchk, 6-11
-compress and -ncompress, 6-12
-cond and -ncond, 6-12
-config, 6-12 to 6-14
sample program, 6-13
-cpu, 6-14 to 6-17, F-2 to F-7
list of arguments, 6-16
selecting the right argument, 6-17
-db, 6-18
-dba, 6-18
-dbs, 6-18
-exp and -nexp, 6-18
-frnd and -nfrnd, 6-19 to 6-20
-idir, 6-20 to 6-21
-imap and -nimap, 6-21
-indexl and -nindexl, 6-21
-info, 6-21 to 6-22
-inlib, 6-22 to 6-23
-iso and -niso, 6-23
-I and -nl, 6-24
-map and -nmap, 6-24 to 6-25
-msgs and -nmsgs, 6-25
-natural and -nnatural, 6-25 to 6-26
-nclines, 6-26
-ndb, 6-18
-opt, 6-26 to 6-33
-pic, 6-9
-prasm and -nprasm, 6-33
-slib, 6-33 to 6-34

Compiler options (continued)
-std and -nstd, 6-35
-subchk and -nsubchk, 6-35
-version, 6-35
-warn and -nwarn, 6-35 to 6-36
-xrs and -nxrs, 6-36
alignment messages, 6-9
array bounds violation, 6-10 to 6-11
array indexing, 6-21
binary output, 6-9 to 6-10
comment checking, 6-11
compressing object file data, 6-12
conditional compilation, 6-12
conditional processing, 6-12 to 6-14
sample program, 6-13
debugger preparation, 6-18
expanded listing file, 6-18
Series 10000 format, 6-33
floating-point rounding, 6-19 to 6-20
information messages, 6-21 to 6-22
library files, 6-22 to 6-23
listing files, 6-24
memory addressing, 6-9
message summary, 6-25
natural alilgnment, 6-25 to 6-26
nonstandard Pascal, messages about, 6-35
optimized code, 6-26 to 6-33
See also Atomic attribute; Optimized
code; Volatile attribute
precompilation of include files, 6-33 to
6-34
register saving, 6-36
searching alternate directories for include
files, 6-20 to 6-21
standard Pascal, implementation, 6-23
subscript checking, 6-35
suppressing COFF line number tables, 6-26
symbol table map, 6-24 to 6-25
for include files, 6-21
target workstation selection, 6-14 to 6-17
version of compiler being used, 6-35
warning messages, 6-35 to 6-36
Compiler variants, 6-3
Compiling, 6-4 to 6-5
compiler options, table of, 6-6 to 6-8
compiler output, 6-4 to 6-8
conditional
for Series 10000, 4-46
messages, 9-4
list, 9-5 to 9-49
object file names, 6-5
See also Compiler directives; Compiler options

Complex data types, simulating FORTRAN's,
7-15
Compound statement
begin (reserved word), 4-31 to 4-32
definition, 4-188
end (reserved word), 4-71 to 4-72
sample program, 4-31 to 4-32
-compress compiler option, 6-12
Concatenation, strings
with append procedure, 4-21 to 4-22
sample program, 4-21 to 4-22
-cond compiler option, 6-12
Conditional action. See Transferring control
Conditional branching. See Case statement; If
statement
Conditional compilation, compiler option, 6-12
Conditional processing
with compiler directives, 4-43 to 4-58
compiler option, 6-12 to 6-14
sample program, 6-13
terminating with %exit directive, 4-52
-config compiler option, 6-12 to 6-14
compiler directives used with, 4-45 to 4-46
same as %enable directive, 4-50
sample program, 6-13
%config directive, 4-50 to 4-51
Const declaration part, 2-12 to 2-13
Constants
Boolean, defining, 3-11
with case statement, 4-36
character, defining, 3-12
declaring, 2-12 to 2-13
as expressions, 1-4
extensions to standard Pascal, C-3
initializing arrays to, 3-40
integers
defining, 3-5
range of, 3-5
See also Integer data types; Integers
nil, 2-12
See also Nil (reserved word)
pi, 3-6
predeclared, maxint, 3-5
real, defining, 3-7
Control, transferring. See Transferring control
Conventions
documentation, viii to ix
files, 3-48
preserving registers, 5-19 to 5-20

Index

7

Converting numbers, real to integer, 4-170
Converting types, with type transfer functions,
4-197 to 4-199
Copying, unpacked array to packed array,
4-139 to 4-141, 4-200 to 4-202
Cos function, 4-6, 4-59 to 4-60
sample program, 4-59 to 4-60
-cpu compiler option, 6-14 to 6-17
list of arguments, 6-16
and MC68040 floating-point performance,
F-2 to F-7
selecting the right argument, 6-17
Cpu help utility, 6-17
Creating files, 4-130 to 4-133, 8-6 to 8-7
compatibility with previous releases, 3-49
program example, 4-132 to 4-133
See also Open procedure
Cross-Language communication. See Calling C
from Pascal; Calling FORTRAN from Pascal; External routines
Ctop procedure, 4-61
sample program, 4-149 to 4-150

D
DO_return routine option, 5-20
Data registers. See Registers
.data section, 2-10, 3-52, 3-53, 5-24 to 5-26
compressed data, 6-12
and data attributes, 3-77 to 3-78
and %slibrary directive, 4-56
variables, 7-43 to 7-45
Data sections, 3-52 to 3-53
correspondence
in C, 7-43 to 7-46
in FORTRAN, 7-17
.data as default, 3-52
and data attributes, 3-77 to 3-78
example, 7-7
extension to standard, C-2
Data type correspondence
C and Pascal, 7-30 to 7-46
table, 7-30

8

Index

FORTRAN and Pascal
arrays, 7-16
Booleans and logicals, 7-15
passing data between, 7-17
simulating FORTRAN complex type,
7-15
table, 7-14
Data types, 3-1 to 3-78
anonymous, 5-2
arrays, 3-37 to 3-48
See also Arrays
Boolean, 3-10 to 3-11
See also Boolean data types
character, 3-11 to 3-13
string, 3-38
See also Character data types; Strings
checking, 5-13
complex, simulating FORTRAN's, 7-15
correspondence
C and Pascal, 7-30 to 7-46
FORTRAN, 7-14 to 7-17, 7-21 to
7-24
sample FORTRAN program, 7-21 to
7-24
declaring, 2-13 to 2-14
sample program, 3-3
enumerated, 3-13 to 3-14
See also Enumerated data types
extensions to standard, C-4 to C-6
file, 3-48 to 3-49
function pointer, 3-50 to 3-51
integers, 3-3 to 3-6
See also Integer data types
mixing integers with reals in expressions,
4-5
overview, 3-1 to 3-3
pointers, 3-49 to 3-52
See also Pointers
procedure pointer, 3-50 to 3-51
real numbers, 3-6 to 3-9
See also Real number data types
records, 3-17 to 3-37
See also Record data types
returning size of, 4-181 to 4-183
sections, assigning variables to, 3-52 to
3-53
sets, 3-15 to 3-17
See also Set data types
string, definition, 3-38
subrange data, 3-14 to 3-15
See also Subrange data types
univytr, 3-50

Data types (continued)
unsigned, 3-9 to 3-10
using univ to pass arguments with varying,
5-10 to 5-11
variant record, 3-19 to 3-20
-db compiler option, 6-18
-dba compiler option, 6-18
optimizations generated with, 6-27
-dbs compiler option, 6-18
dbx utility, 6-40
dde command. See Domain Distributed Debugging Environment
Deallocating storage, with dispose procedure,
4-64 to 4-65
%debug directive, 4-54 to 4-55
Debugger preparation, compiler options, 6-18
Debugging, 6-39 to 6-40
dbx utility, 6-40
using %debug, 4-54 to 4-55
Domain Distributed Debugging Environment
utility, 6-39
run-time errors, 9-52
Declaration part, 2-11 to 2-15
const, 2-12 to 2-13
label, 2-11
order, 1-4
type, 2-13 to 2-14
var, 2-14 to 2-15
Declarations, extensions to standard, C-2
Declaring
arrays, packed, 3-45
attributes for variables and types, 3-78
character variables, 3-11
constants, 1-4, 2-12 to 2-13
data sections, 3-53
data types, 2-13 to 2-14
sample program, 3-3
enumerated variables, 3-13
fields in records, 3-17
file variables, 3-48
files in program heading, deviation from
standard, D-l
fixed record data type, 3-17 to 3-19
labels, 2-11
parameters in routines, 5-2
pointers, 3-49
real variables, 3-6

records
fixed, 3-17 to 3-19
maximizing efficiency, 3-29 to 3-38
packed, 3-21, 3-36
syntax note, 3-19
variant, 3-19 to 3-20
routine options, 5-21 to 5-24
set variables, 3-15
text files, 3-48
variable-length string, 3-44
variables, 2-14 to 2-15
in include files, 7-7
See also Initializing
Decrementing, for loop index variable, 4-89
Default
alignment
definition, 3-23
example, 3-69
overriding with natural attribute, 3-64
for record data types, 3-26
simple data types. See individual data
types
.data section, 2-10, 3-52
file type, 8-6
1/0 streams, 8-3 to 8-4
table, 8-4
library pathnames, 4-56
optimizations
suppressing with atomic attribute, 3-56
suppressing with volatile attribute,
3-56
routine options, defining and using, 5-22 to
5-24
size of text files, 4-131
storage of variables in .data, 3-52
. text section, 2-10
Default_routine_options, 5-22 to 5-24
Define
clause
using with C programs, 7-43 to 7-45
definition, 7-3
statement
definition, 7-11
example, 7-10
syntax, 7-5
Delayed access, 8-5
Deleting, file contents with rewrite, 4-168 to
4-169
Dereferencing pointers, 4-144 to 4-146
Development. See Program development
Deviations from standard Pascal, D-l to D-5

Index

9

Device attribute, 3-57 to 3-59
inheritance, 3-76 to 3-77
Diagnostic messages, 9-1 to 9-54
See also Errors
Disable procedure, E-3
Discard procedure, 4-62 to 4-63
sample program, 4-62 to 4-63
Discarding, return value of an expression, 4-62
to 4-63
Display, writing to, sample program, 4-220
Dispose procedure, 4-64 to 4-65
sample program, 4-119 to 4... 122
Div operator, 4-3, 4-66 to 4-67
sample program, 4-67
Division, 4-3
Do. See For statement; While statement
Documentation
conventions, viii to ix
related, v to vi
Dollar sign ($), in identifier names, 1-4
Domain/C. See Calling C from Pascal
Domain/Dialogue, 6-42 to 6-43
Domain Distributed Debugging Environment,
6-39
and run-time errors, 9-52
Domain FORTRAN. See Calling FORTRAN
from Pascal
Domain/PAK (Domain Performance Analysis
Kit), 6-43
Domain Software Engineering Environment
(DSEE), 6-41 to 6-42
Double, data type, 3-6
See also Real number data types
Double asterisk (* *), as exponentiation operator, 4-3
Double quotes ("), as comment delimiter, 2-3
to 2-4
Downto. See For statement
DPAT (Domain Performance Analysis Tool),
6-43
DSEE .(Domain Software Engineering Environment),6-41 to 6-42
DSPST (Display Process Status), 6-43

10

Index

E
e constant, and exp function, 4-79
Efficiency
alignment issues, 3-64, 4-16
declaring record fields, 3-29 to 3-38
Domain/PAK (Domain Performance Analysis Kit), 6-43
with in range function, 4-104
and iniernal routine option, 5-17
and natural alignment, 3-74 to 3-75
using packed arrays, 3-45
using sections, 3-52 to 3-53
on Series 10000, 3-75, 4-16, 4-57
%eject directive, 4-55
Eliminating, warnings with discard statement,
4-62 to 4-63
Else. See If statement
%else directive, 4-47
%elseif predicate %then directive, 4-47 to 4-48
%elseifdef predicate %then directive, 4-49
Empty statement, definition, 4-188
%enable directive, 4-50
same as -config option, 4-50
Enable procedure, E-4
Encyclopedia of Domain Pascal code, 4-12 to
4-58
End
of file, 4-73 to 4-74
of line, 4-75
End (reserved word), 4-71 to 4-72
sample program, 4-31 to 4-32
End-of-line character, 4-75
%end_inline directive, 4-52 to 4-53, 6-32
%end_noinline directive, 4-53 to 4-54, 6-32
%endif directive, 4-48
Enumerated data types, 3-13 to 3-14
declaring, 3-13
first value, 4-87
and in_range, 4-104 to 4-105
internal representation of, 3-13 to 3-14
last value, 4-106
and succ value, 4-191
and write procedure, 4-219 to 4-220
Eof function, 4-73 to 4-74
sample program, 4-74
Eoln function, 4-75 to 4-76
sample program, 4-75 to 4-76

Equal sign (=)
as mathematical operator, 4-3
in record declarations, 3-19
as set equality operator, 4-3, 4-176
in type declarations, 2-13
Equality, of sets, 4-176
Erasing, file contents with rewrite, 4-168 to
4-169
%error 'string' directive, 4-51
Errors, 9-1 to 9-54
compiler messages, 9-4 to 9-50
definition, 9-4
error status parameter, 9-1
list of messages, 9-5 to 9-49
message conventions, 9-5
misuses of in out parameters, 5-9
reported by open and find, 9-1 to 9-4
printing, 9-2 to 9-4
testing for, 9-3 to 9-4
returned by find, table, 9-3
returned by open, table, 9-3
run-time, 9-50 to 9-54
floating-point, 9-54
operating system, 9-52 to 9-53
Example. See Sample programs
Exclamation point (I), as bitwise or operator,
4-3
Exclusion, operation with sets, 4-175
Executing programs, 6-39
%exit directive, 4-52
Exit statement, 4-77 to 4-78
sample program, 4-77 to 4-78
-exp compiler option, 6-18
Exp function, 4-6, 4-79 to 4-80
sample program, 4-79 to 4-80
Expanded listing file
compiler option, 6-18
Series 10000 format, compiler option, 6-33
Expansion of operands, 4-5
Exponentiation, 4-3
operator, 4-3
Expressions
constant, declaring, 2-12 to 2-13
See also Constants
definition, 4-81 to 4-82
mixing integers with reals in expressions,
4-5

mixing signed and unsigned operands, 4-6
order of precedence, 4-4
using parentheses in arithmetic, 2-2
in write and writeln procedures, 4-215
Extensions, list of, C-1 to C-14
Extern
clause
using with C programs, 7-43 to 7-45
definition, 7-3
initializing arrays, 7-5 to 7-6
routine option, 5-17
accessing routines in Pascal modules,
7-8
example, 7-9, 7-12
See also External routines
External routines, 7-1 to 7-46
accessing routines in other Pascal modules,
7-8 to 7-13
extern, 7-8
internal, 7-8
using data sections to access variables, example, 7-7
data type correspondence
C and Pascal, 7-30 to 7-46
FORTRAN and Pascal, 7-14 to 7-17
with size attributes, 3-62
modules, 7-1 to 7-3
accessing variables in other Pascal
modules, 7-3 to 7-8
example, 7-7
heading, 7-2 to 7-4
using registers, 5-20
See also Calling C from Pascal; Calling
FORTRAN from Pascal
Extracting substrings, 4-189 to 4-190

F
Fatal errors, definition, 9-4
Fields
for write and writeln procedures, 4-215 to
4-220
See also Declaring; Record data types
File data types, and 1/0 stream IDs, 8-3
Files, 3-48 to 3-49
closing, 4-41 to 4-42, 8-9
See also Close procedure
COFF (Common Object File Format),
4-46, 6-38
compatibility, with previous releases, 3-49
creating, 4-130 to 4-133, 8-6 to 8-7
program example, 4-132 to 4-133
See also Open procedure

Index

11

Files (continued)
delayed access, 8-5
deleting contents with rewrite, 4-168 to
4-169
documentation convention, 3-48
and find procedure, 4-83 to 4-86
library
binding, 6-3
compiler option, 6-22 to 6-23
listing in program heading, 2-10
deviation from standard, 0-1
map, 6-24 to 6-25
for include files, 6-21
object file names, 6-5
opening, 4-130 to 4-133
existing, 8-7
See also Open procedure
new, 8-6 to 8-7
program example, 4-132 to 4-133
organization, 8-6
reading, 8-7 to 8-8
See also Get procedure; Read proce~
dure; Reset procedure
rec, 3-49, 8-7
replace procedure, 4-163
separately compiled, 7-3 to 7-8
temporary, 4-41, 4-131
text, definition, 3-48
UNIX compatible, 3-48, 8-6
unstruct, 3-49, 8-6
write and writeln procedures, 4-215 to
4-220
writing, 8-8 to 8-9
See also Stream marker
Find procedure, 4-83 to 4-86
errors reported by, 9-1 to 9-4
errors returned by, table, 9-3
sample program, 4-84 to 4-86

Formal parameters. See Parameters
Format
converting with VFMT calls, 8-2 to 8-3
of real numbers, 3-7 to 3-10
program
illustration, 2-8
sample program, 2-9
routine headings, 2-16
See also Internal representation; Syntax
Formfeed
inserting in a file, 4-142
inserting with %eject directive, 4-55
FORTRAN, calling from Pascal. See Calling
FORTRAN from Pascal
Forward routine option, 5-16 to 5-17
sample program, 5-16
-frnd compiler option, 6-19 to 6-20
Function, pointer data type, 3-50 to 3-51,5-11
to 5-13
Functions
attribute list, 5-24 to 5-26
calling, 5-3
nested, and section attribute, 5-26
parameter list, 5-1 to 5- 3
parameter types, 5-5 to 5-13
passing from Pascal to C, 7-41 to 7-43
passing from Pascal to FORTRAN, 7-24 to
7-28
passing pointers, to unaligned objects, 3-76
predeclared, mathematical, 4-5 to 4-8
returning pointer variables to registers, 5-20
routine options, 5-15 to 5-21
See also Routine options
using as parameters, 5-13 to 5-15
using section attribute to gain efficiency,
5-24 to 5-26
See also Routines

Finding. See Returning; Testing
Firstof function, 4-87 to 4-88
and pred's value, 4-147
sample program, 4-88
Floating-point
numbers. See Real number data types
performance on MC68040, optimizing, F-1
to F-7
registers. See Registers
rounding, compiler option, 6-19 to 6-20
run-time errors, 9-54
For statement, 4~89 to 4-91
sample program, 4-90 to 4-91

12

Index

G
Get procedure, 4-92 to 4-94, 8-7 to 8-8
sample program, 4-93 to 4-94
similarities to read, 4-93
getpas utility, 1-2 to 1-4
Goto statement, 4-95 to 4-98
compared with exit, 4-77
compared with next, 4-123
and nested routines, 4-97
sample program, 4-97 to 4-98
GPIO drivers, using -pic to compile, 6-9

Greater than (»
as mathematical operator, 4-3
redirecting standard output, 6-39
Greater than or equal sign (>=)
as mathematical operator, 4-3
as set superset operator, 4-3, 4-176 to
4-177
Guard fault, 9-50, 9-52 to 9-53

H
Hardware fault, on Series 10000, 3-74 to 3-76
Headings
module, 7-2 to 7-4
program, deviation from standard, 0-1
routine, 2-16
HPC (Histogram Program Counter), 6-43

In_range function, 4-104 to 4-105
sample program, 4-105
%include directive, 4-55
compared to %slibrary directive, 4-56
See also Include files
Include files
and %exit directive, 4-52
and %ifdef directive, 4-49
maps of symbol tables for, compiler option,
6-21
nested, 4-55
precompilation of, compiler option, 6-33
searching alternate directories, compiler option, 6-20 to 6-21
variable declarations in, 7-7
Incrementing, for loop index variable. 4-89
Index variables
in arrays, 4-25
in for loops, 4-89
-index) compiler option, 6-21

I
Identifiers
definition, 2-1
deviation from standard Pascal, 0-1
dollar sign ($) in names, 1-4
extension to standard, C-1
length of, 2-1
predeclared, list, A-2
underscore U in names, 1-4
-idir compiler option, 6-20 to 6-21
%if predicate %then directive, 4-47
If statement, 4-99 to 4-101
different from case statement, 4-37
sample program, 4-100 to 4-101
%ifdef predicate %then directive, 4-49
Illegal address, 9-50, 9-53
-imap compiler option, 6-21
In operator, 4-102 to 4-103
sample program, 4-102 to 4-103
as set subset operator, 4-3
In Out parameters, 5-7 to 5-9
misuses of, 5-9
sample program, 5-9
In parameters, 5-7 to 5-9
misuses of, 5-9
sample program, 5-9

-info compiler option, 6-21 to 6-22
Information messages
compiler option, 6-21 to 6-22
definition, 9-4
list. 9-5 to 9-49
Inheritance, of attributes for variables and types.
3-76 to 3-77
Initializing
arrays, 3-38 to 3-43
with default size. 3-42
extern, 7-5 to 7-6
individual components of, 3-39 to
3-40
mixing methods. 3-43
multiple components of, 3-39
order. 3-41
using repeat counts. 3-40 to 3-41
Boolean data types, 3-10 to 3-11
character variables, 3-12
integer data types. 3-4 to 3-5
pointers, 3-51
real number data types. 3-6 to 3-7
records, 3-21 to 3-22
sets. 3-15 to 3-16
-inlib compiler option, 6-22 to 6-23
Inline expansion, 6-32
%begin_inline and %end_inline directives.
4-52 to 4-53
%begin_noinline and %end_noinline directives, 4-53 to 4-54

Index

13

Input. See 1/0
Input procedures. See Get procedure; Read,
readln procedure; Reset procedure; Stream
marker
Input/Output. See 1/0
Insert files. See Include files
Integer data types, 3-3 to 3-6
alignment of, 3-5 to 3-6
arithmetic right shift, 4-29 to 4-30
bit operators, 4-3, 4-33 to 4-35
byte integers, 3-62
declaring, 3-4
defining integer constants, 3-5
expansion of operands, 4-5
first value, 4-87
initializing, 3-4 to 3-5
internal representation of, 3-5 to 3-6
last value, 4-106
left shift, 4-109 to 4-110
mixing with reals in expressions, 4-5
right shift, 4-171 to 4-172
and succ value, 4-191
unsigned, 3-9 to 3-10
and write procedure, 4-217 to 4-218
Integer16. See Integer data types
Integer32. See Integer data types
Integers
definition, 2-2
expressing in other bases, 2-2
extension to standard, C-1
range of, 3-5
in sets, 3-15
rounding to nearest, 4-170
truncating to, 4-195 to 4-196
See also Integer data types
Interactive 1/0, 8-4 to 8-5
Internal representation
arrays, 3-45 to 3-49
Boolean variables, 3-11
character variables, 3-13
integers, 3-5 to 3-6
packed arrays, 3-47 to 3-48
pointers, 3-51 to 3-55
real numbers, 3-7 to 3-10
records
packed, 3-35 to 3-38
unpacked, 3-22 to 3-32
set data types, 3-16 to 3-17

14

Index

subranges, 3-14 to 3-15
variable-length strings, 3-44
variables in sections, 3-52
Internal routine option, 5-17
accessing routines in other Pascal modules,
7-8
example, 7-9
Intersection, operation with sets, 4-175
1/0, 8-1 to 8-9
default streams, 8-3 to 8-4
table, 8-4
Domain/OS, background, 8-1 to 8-6
file organization, 8-6
file variables, 8-3 to 8-6
interactive, 8-4 to 8-6
predeclared procedures, 8-6 to 8-9
overview, 4-8
procedures, extensions to standard Pascal,
C-8
stream· calls (lOS), 8-1 to 8-6
stream markers, 8-5 to 8-6
VFMT (variable format) calls, 8-2 to 8-3
lOS (Input Output Stream) calls, 8-1 to 8-2
-iso compiler option, 6-23
ISO Latin-I, 2-4 to 2-6
characters, table, B-1 to B-5
embedding unprintable characters, 2-4 to
2-6
using chr function to obtain character,
4-39 to 4-40
ISO standard Pascal
deviations from, list, 0-1 to 0-5
extensions to, list of, C-1 to C-14
_ISP_A88K conditional variable, 4-46
_ISP_M68K conditional variable, 4-46

J
Jumping. See Transferring control

K
Keyboard
reading from, sample program, 4-220
using device attribute with, 3-57 to 3-59
Keywords, list of, 4-11, A-I to A-2

L
-I compiler option, 6-24
Label declaration part, 2-11

Labels, 1-4
declaring, 2-11
extension to standard, C-3
and goto statement, 4-95
Lastof function, 4-106
sample program, 4-88
Layout, of records, 3-26 to 3-27
maintaining, 3-64
See also Alignment; Internal representation
Id utility, 6-36 to 6-37
Left shift, 4-109 to 4-110
Length
finding with sizeof function, 4-181
of identifiers, 2-1
line, 8-6
variable, strings, 3-44 to 3-45
Less than «)
as mathematical operator, 4-3
redirecting standard input, 6-39
Less than or equal sign «=)
as mathematical operator, 4-3
as set subset operator, 4-3, 4-176
Less than or greater than sign (<»
as mathematical operator, 4-3
as set inequality operator, 4-3, 4-176
Library files
binding, 6-3, 6-37
compatibility, 6-38
compiler option to load, 6-22 to 6-23
creating with archiver, 6-38 to 6-39
including in your program, 4-56
precompiled, 4-56, 6-33
and %slibrary directive, 4-56
Limits
array dimensions, 3-37
characters in lines of text files, 2-7
elements in sets, 3-16
identifier length, 2-1
length of varying array of char, 3-44
line length, 8-6
lines in file, 8-6
lowest negative integer, 4-12
parameters in a list, 5-1
pathnames with -idir, 6-21
set storage size, 3-16
size of text files, 4-131
smallest record size, 3-26
subranges in sets, 3-15

Lines
end of, 4-75 to 4-76
and readln, 4-155 to 4-157
and writeln, 4-216 to 4-220
length, 8-6
maximum in file, 8-6
Linked list
and dispose procedure, 4-65
last record, 4-125
sample program, 4-119 to 4-122, 7-39 to
7-40
Linking, 6-36 to 6-38
bind command, 6-37 to 6-39
Id utility, 6-36 to 6-37
modules, example, 7-13
with other Pascal modules, example, 7-4
%list directive, 4-55 to 4-56
Listing files
compiler option, 6-24
and %eject directive, 4-55
and %list directive, 4-55
Ln function, 4-6, 4-107 to 4-108
sample program, 4-107 to 4-108
Logarithms, 4-79 to 4-80, 4-107 to 4-108
Logical operators
and, 4-18 to 4-20
sample program, 4-20
and then, 4-18 to 4-20
distinct from bit operators, 4-34
not, 4-126 to 4-127
or, 4-134 to 4-136
or else, 4-134 to 4-136
table, 4-3
Long, attribute, 3-60 to 3-62
Longword
alignment
specifying with aligned attribute, 3-63
See also Alignment
boundary, definition, 3-23
Loops. See Exit statement; For statement; Next
statement; Repeat statement; While statement
Low-level calls. See Systems programming routines
Lowercase and uppercase. See Case sensitivity
Lshft function, 4-6, 4-109 to 4-110
sample program, 4-109 to 4;.4 10

Index

15

M
-map compiler option, 6-24 to 6-25
Map files
compiler option, 6-24 to 6-25
for include files, compiler option, 6-21
Markers, stream. See Stream marker
Mathematical
functions, predeclared, 4-5 to 4-8
operations
mixing integers with reals, 4-5
mixing signed and unsigned, 4-5
operators, 4-2 to 4-8
div, 4-66
mod, 4-115
precedence, 4-4
table of, 4-3
Max function, 4-111 to 4-112
sample program, 4-111 to 4-112
Maximum. See Limits
Maxint, defined, 3-5
MC68020/MC68030 microprocessor, generating

code for, 6-15, 6-16, 6-17
MC68040 microprocessor
generating code for, 6-16, 6-17
optimizing floating-point performance, F-1
to F-7
Membership in a set, determining with in operator, 4-102 to 4-103
Memory, and run-time errors, 9-50 to 9-51
Messages
compiler, list of, 9-5 to 9-49
preventing, with aligned attribute, 3-64
printing with %error directive, 4-51
printing with %warning directive, 4-51 to
4-52
run-time errors, 9-50 to 9-54
summary of, compiler option, 6-25
suppressing with alignment attributes, 3-74
Min function, 4-113 to 4-114
sample program, 4-114
Minimum
size for data types, 3-61
See also Limits
Minus sign (-)
as set exclusion operator, 4-3, 4-175
as subtraction operator, 4-3

16

Index

Mod operator, 4-3, 4-115 to 4-116
sample program, 4-116
Modules, 7-1 to 7-3
accessing variables in other Pascal modules,
7-3 to 7-8
extension to standard, C-14
heading, 7-2 to 7-4
using include files, 7-7
order of declarations, 7-7
-msgs compiler option, 6-25
Multiplication, 4-3
Boolean, 4-18 to 4-20
Multiprocessing
atomic attribute, 3-56 to 3-57
suppressing optimizer with volatile, 3-56

N
Name compatibility, 5-13
Names
data sections, 3-52 to 3-53
example, 7-7
dollar sign ($) in identifier, 1-4
library pathnames, 4-56
object files created by compiler, 6-5
procedures and functions, 2-16
program, 2-10
of records, abbreviating, 4-211 to 4-214
underscore U in identifier, 1-4
Natural alignment
compiler option, 6-25 to 6-26
definition, 3-23, 3-64 to 3-68
dereferencing pointers, 3-75 to 3-76
and efficiency, 3-74 to 3-75
memory allocation, for records, 3-27 to
3-29
%natural_alignment directive, 4-57
portability of records, 3-64
pre-SR10, 4-57
records, 3-29 to 3-38
align function, 4-16 to 4-17
in arrays, 3-31 to 3-32
example, 3-65
specifying with attributes, 3-62 to 3-76
with aligned attribute, 3-64, 3-67
with natural attribute. 3-64 to 3-65.
3-66 to 3-67
Natural attribute
inheritance of, 3-68
portability issues, 3-64
using to suppress information messages,
3-74

Natural attribute (continued)
using with %natural_alignment directive,
3-70 to 3-72
using with arrays of records, 3-66 to 3-67

-nl compiler option, 6-24

-natural compiler option, 6-25 to 6-26

-nmsgs compiler option, 6-25

Natural logarithms, 4-79 to 4-80, 4-107 to
4-108

-nnatural compiler option, 6-25 to 6-26

%natural_alignment directive, 4-57
using with alignment attributes, 3-70 to
3-72

-niso compiler option, 6-23
-nmap compiler option, 6-24 to 6-25

-no_bounds_violation compiler option, 6-10 to
6-11
%nolist directive, 4-55 to 4-56
Noreturn routine option, 5-20

-nb compiler option, 6-9 to 6-10

Nosave routine option, 5-19 to 5-20

-nclines compiler option, 6-26
-ncomchk compiler option, 6-11

Not operator, 4-3, 4-126 to 4-127
sample program, 4-127

-ncompress compiler option, 6-12

-nprasm compiler option, 6-33

-ncond compiler option, 6-12
-ndb compiler option, 6-18
Negation operator, 4-3
Nested
comments, 2-3
for loops, example, 4-90 to 4-91
include files, 4-55
loops, and exit statement, 4-77
routines, 2-19 to 2-21
sample program, 2-20
and section attribute, 5-26
Nested routines, with goto statement, 4-97
Network File System (NFS), 6-43 to 6-44
New procedure, 4-117 to 4-122
sample program, 4-119 to 4-122
-nexp compiler option. 6-18
Next statement, 4-123 to 4-124
and for loops, 4-90
and repeat loops, 4-161
sample program, 4-124
and while loops, 4-208
-nfrnd compiler option. 6-19 to 6-20
~FS

(Network File System), 6-43 to 6-44

-nstd compiler option, 6-35
-nsubchk compiler option, 6-35
Null character
with ctop procedure, 4-61
in variable-length strings, 3-46, 4-205
Numbers
bases permitted, 1-4
floating-point. See Real number data types
formatting with VFMT calls. 8-2 to 8-3
integers
range of, 3-5
See also Integer data types; Integers
non-decimal. 2-2
range of. in sets, 3-15
real. See Real number data types
single-precision. See Real number data
types
-nwarn compiler option, 6-35 to 6-36
-nxrs compiler option, 6-36

o
Object file names, created by compiler. 6-5
Octaword, alignment. specifying with aligned
attribute, 3-63

Nil (predeclared constant), 4-125

Odd function, 4-6, 4-128
sample program, 4-128

Nil (reserved word), 4-125
pointer expression, 2-12

Odd numbers. testing for, 4-128

'lil pointer, and calling dispose procedure. 4-65

Of. See Case statement

-nimap compiler option, 6-21

Online sample programs. 1-2 to 1-4
See also Sample programs

-nindexl compiler option, 6-21

Open Dialogue. 6-42 to 6-43

Index

17

Open procedure, 4-130 to 4-133, 8-6 to 8-9
errors reported by, 9-1 to 9-4
errors returned by, table, 9-3
sample program, 4-132 to 4-133
Opening
existing files, 8-7
new files,· 8-6 to 8-7
See also Open procedure
Operators
bit, 4-3
mathematical
div, 4-66
mod, 4-115
table of, 4-3
order of precedence, 4-4
-opt compiler option, 6-26 to 6-33
Optimization techniques. See Optimized code
Optimized code
compiler option, 6-26 to 6-33
discarding unused return values, 4-62 to
4-63
and exit statement, 4-77
and goto statement, 4-77
with noreturn option, 5-20
suppressing optimizations using atomic attribute, 3-56 to 3-57
suppressing optimizations using device attribute, 3-57 to 3-59
suppressing optimizer with volatile, 3-56
Options. See Compiler options; Routine options
Or else operator, 4-3
Or operator, 4-3, 4-134 to 4-136
sample program, 4-136
Ord function, 4-137 to 4-138
sample program, 4-138
Order
declaration parts, 1-4
of declarations, extension to standard, C-2
declarations in modules, 7-7
define statement, 7-5, 7-6
precedence of operators, 4-4
Ordinal values
finding. next with succ function, 4-191 to
4-192
finding preceding with pred function,
4-147 to 4-148
returning with ord function, 4~137 to
4-138

18

Index

Otherwise, extension to case statement, 4-36 to
4-38
Out parameters, 5-7 to 5-9
misuses of, 5-9
sample program, 5-9
Out-of-bounds address, 9-53
Output. See I/O
Output procedures. See Find procedure; Page
procedure; Replace procedure; Stream
marker
Overlay section, definition, 3-52
See also Data sections

p
Pack procedure, 4-139 to 4-141
sample program, 4-140 to 4-141
Packed
arrays, 3-45
internal representation, 3-47 to 3-48
using unpack procedure, 4-200 to
4-202
records
definition, 3-21
internal representation, 3-35 to 3-38
manipulating fields, 3-21
sets, 3-15
deviation from standard Pascal, D-1
Padding
in arrays of Boolean, 3-46
inserting in records, with attributes and directives, 3-32, 3-67
with %natural alignment directive, 3-70
to 3-72 in records, 3-26 to 3-27
eliminating, 3-31, 3-64, 3-69 to 3-72
strings, 4-27
in variable-length strings, 3-46, 4-204
Page advance, inserting in a file, 4-142
Page procedure, 4-142 to 4-143, 8-8 to 8-9
sample program, 4-143
Parameters
difference from arguments, 5-1
error status, 9-1
list, 5-1 to 5-3
list of types, 5-5
misuses of in out, 5-9
passing by value, val_param routine option, 5-19
procedures and functions as parameters,
5-13 to 5-15

Parameters (continued)
routine pointers as, 5-11 to 5-13
type checking, 5-11
universal specification with univ, 5-10 to
5-11
using in out keywords to specify direction,
5-7 to 5-9
sample program, 5-9
using variable option to vary number of,
5-17 to 5-18
sample program, 5-18
var and out, 5-8
variable and value, 5-6 to 5-7
sample program, 5-6
Parentheses ()
with asterisk (*), as comment delimiter,
2-3 to 2-4, 6-11
in enumerated declarations, 3-13
with mathematical expressions, 2-2
as section name delimiters, 3-52
using to organize complex expressions,
4-81
pas command, 6-4 to 6-5
Passing, pointers to unaligned objects, 3-76
Pathname, of file to open, 4-130
PEB (Performance Enhancement Board), referencing with address attribute, 3-59
Per cent sign (%), with compiler directives,
4-43
Performance. See Efficiency
Period (.), and record field names, 4-158
-pic compiler option, 6-9
Plus sign (+)
as addition operator, 4-3
as set union operator, 4-3, 4-174
Pointers, 3-49 to 3-52
alignment attributes and, 3-75 to 3-76
correspondence, in C, 7-38 to 7-40
data type checking, 5-13
declaring, 3-49
and dispose procedure, 4-64 to 4-65
function, 3-50 to 3-51
dereferencing, 4-145
initializing, 3-51
internal representation of, 3-51 to 3-55
linked list example, 4-119 to 4-122
list of pointer data types, 3-2
and new procedure, 4-117 to 4-122
nil, 4-125

predeclared with univJtr, 3-50
procedure, 3-50 to 3-51
dereferencing, 4-145
univJJtr, 3-50
using, 4-144 to 4-146
%pop_alignment directive, 4-58
Portability, and natural alignment, 3-64
Pound sign (#), in non-decimal base numbers,
2-2
-prasm compiler option, 6-33
Precedence, of operators, 4-4
Precompilation of include files, compiler option,
6-33 to 6-34
Precompiled library files, 4-56
Pred function, 4-147 to 4-148
sample program, 4-148
Predeclared identifiers, list, A-2
Predicates
%config directive, 4-50
declaring with %var, 4-50
definition, 4-46
example, 4-46
predeclared, 4-46
setting with %enable, 4-50
Printing
inserting page advance in a file, 4-142
messages with %error directive, 4-51
messages with %warning directive, 4-51 to
4-52
with write and writern procedures, 4-215
to 4-220
Procedure, pointer data type, 3-50 to 3-51,
5-11 to 5-13
Procedures
attribute list, 5-24 to 5-26
calling, 5-3
110, predeclared, 8-6
list of, 4-8
nested, and section attribute, 5-26
parameter list, 5-1 to 5-3
parameter types, 5-5 to 5~13
passing from Pascal to C, 7-41 to 7-43
passing from Pascal to FORTRAN, 7-24 to
7-28
passing pointers, to unaligned objects, 3-76
predeclared
110, 8-6
list of, 4-8
systems programming, 4-10, E-1 to
E-5

Index

19

Procedures (continued)
routine options, 5-15 to 5-21
See also Routine options
using as parameters, 5-13 to 5-15
using section attribute to gain efficiency,
5-24 to 5-26
See also Routines
Program
declarations, 2-11 to 2-15
heading, 2-10 to 2-11
organization, overview, 2-7 to 2-17
Program development
archiving, 6-38 to 6-39
compiler options, 6-5 to 6-36
compiling, 6-4 to 6-5
debugging, 6-39 to 6-40
executing, 6-39
linking, 6-36 to 6-38
steps, 6-1 to 6-3
systems programming, 4-10, E-1 to E-5
tools, 6-40 to 6-43
using the Network File System (NFS) , 6-43
to 6-44
Ptoc procedure, 4-149 to 4-151
sample program, 4-149 to 4-150
%push_aJignment directive, 4-58
Put procedure, 4-152 to 4-154, 8-8 to 8-9
sample program, 4-153 to 4-154

Q
Quad, attribute, 3-60 to 3-62
Quadword, alignment, specifying with aligned
attribute, 3-63
Quotation marks. See Double quote; Single
quote

R
Range
of array dimensions, 3-37
of integers, 3-5
of integers in sets, 3-15
of real numbers, 3-6
of unsigned, 3-9 to 3-10
See also Limits

20

Index

Read, readln procedure, 4-155 to 4-157, 8-7
to 8-8
sample program, 4-156 to 4-157
similarities to get, 4-93
Reading files. See Find procedure; Get procedure; Read procedure; Reset procedure
Real number data types, 3-6 to 3-9
alignment of, 3-7 to 3-10
declaring real variables, 3-6
defining constants, 3-7
initializing, 3-6 to 3-7
internal representation of, 3-7 to 3-10
mixing with integers in expressions, 4-5
and write procedure, 4-218 to 4-219
Real numbers, 2-2
definition, 2-2
See also Real number data types
Rec files, 8-7
Record data types, 3-17 to 3-37
alignment, 3-26
in arrays, 3-31
default, 3-26
minimum, 3-23 to 3-25
natural, 3-23
pre-SRI0, 4-57
allocation of space, 3-26
argument passing, from packed records,
3-21
assigning values to, 4-158
declaring
fixed, 3-17 to 3-19
variant, 3-19 to 3-20
fixed, 3-17 to 3-19
format for field, 3-17
initializing data, 3-21 to 3-22
internal representation of, 3-22 to 3-32
layout, 3-26 to 3-27
memory allocation, 3-27 to 3-29
packed, internal representation of, 3-35 to
3-38
passing fields as parameters, 4-16 to 4-17
portability, 3-64
size of, 3-26
with sizeof function, 4-182
unpacked and packed, definition, 3-21
using, 4-158 to 4-160
variant, 3-19 to 3-20, 4-159 to 4-160
with statement, 4-211 to 4-214
Recursion, 5-26
sample program, 5-26

Referencing
objects with address attribute, 3-59
pointers to unaligned objects, 3-75 to 3-76
variable-length strings, 3-44
Registers
aO_return routine option, 5-20
dO_return routine option, 5-20, 7-29
hardware status, E-3, E-4, E-5
using nosave routine option, 5-19 to 5-20
and optimization techniques, 6-26 to 6-33
saving, compiler option, 6-36
.
systems programming routines, 4-10, E-1
to E-5
using address attribute to reference, 3-59
using device attribute to map, 3-57 to
3-59
Related manuals, v to vi
Repeat count, using to initialize arrays, 3-40 to
3-41
Repeat statement, 4-161 to 4-162
contrasted to while, 4-210
sample program, 4-161 to 4-162
Replace procedure, 4-163, 8-8 to 8-9
sample program, 4-84 to 4-86
Reserved words, list of, A-1
Reset procedure, 4-164 to 4-165, 8-7 to 8-8
sample program, 4-165
Return statement, 4-166 to 4-167
sample program, 4-166 to 4-167
Returning
character with specified ASCII code, 4-39
to 4-40
first value of variable or type, 4-87
larger of two expressions, 4-111 to 4-112
last value of variable or type, 4-106
ordinal value, 4-137 to 4-138
predecessor of ordinal, 4-147 to 4-148
prematurely with return statement, 4-166
to 4-167
size of data objects, 4-181 to 4-183
smaller of two expressions, 4-113 to 4-114
successor of ordinal, 4-191 to 4-192
Revisions, to manual, iv to v
Rewrite procedure, 4-168 to 4-169, 8-6
sample program, 4-169
Right shift, 4-171 to 4-172
arithmetic, 4-29 to 4-30

Round function, 4-6, 4-170
sample program, 4-170
Rounding numbers, and write, writeln procedures, 4-219
Routine attributes
attribute list, 5-24 to 5-26
section, 5-24 to 5-26
Routine options, 5-15 to 5-21
aO_return, 5-20
abnormal, 5-19
c-param, 5-21
dO_return, 5-20
extern, 5-17
accessing routines in Pascal modules,
7-8
example, 7-9. 7-12
forward. 5-16 to 5-17
sample program, 5-16
internal, 5-17, 7-8
example, 7-9
list. 5-15
noreturn, 5-20
nosave, 5-19 to 5-20
syntax, 5-15
user defined, 5-21 to 5-24
val_param, 5-19
variable, 5-17 to 5-18
sample program, 5-18
Routine_option declaration part, 5-21 to 5-24
Routines. 5-1 to 5-26
accessing routines in other Pascal modules,
7-8 to 7-13
attribute list, 5-24 to 5-26
calling, 5- 3
declaration part. 2-16
extensions to standard, C-11 to C-13
external. See External routines
function pointers, 3-50 to 3-51
dereferencing. 4-145
heading. 2-16
in out parameters, 5-7 to 5-9
sample program, 5-9
in parameters, 5-7 to 5-9
sample program. 5-9
modules, 7-1 to 7-3
nested, 2-19 to 2-21
and goto statement, 4-97
sample program, 2-20
and section attribute, 5-26
options. See Routine options
out parameters, 5-7 to 5-9
sample program, 5-9

Index

21

Routines (continued)
overview, 2-15 to 2-17
parameter list, 5-1 to 5-3
parameter types, 5-5 to 5-13
passing from Pascal to C, 7-41 to 7-43
passing from Pascal to FORTRAN, 7-24 to
7-28
passing pointers to, 5-11 to 5-13
passing pointers to unaligned objects, 3-76
procedure pointers, 3-50 to 3-51
dereferencing, 4-145
recursion, 5-26
sample program, 5-26
systems programming, 4-10, E-1 to E-5
univ (universal parameter specification),
5-10 to 5-11
using as parameters, 5-13 to 5-15
using section attribute to gain efficiency,
5-24 to 5-26
value parameters, 5-6 to 5-7
sample program, 5-6
variable parameters, 5-6 to 5-7
sample program, 5-6
Rshft function, 4-6, 4-171 to 4-172
sample program, 4-30
Run-time errors
deviation from standard Pascal, 0-1
error messages, 9-50 to 9-54

s
Sample programs, 1-2 to 1-4
abs_example, 4-12
addr_example, 4-14 to 4-15
align_example, 4-17
and_example, 4-20
append, 7-40
append_example, 4-21 to 4-22
arctan_example, 4-24
array_example, 4-28
arshft_example, 4-30
begin_end_example, 4-31 to 4-32, 4-71 to
4-72
bit_operators_example, 4-35
build_a_linked_list, 4-119 to 4-122
capitalize, 7-33
case_example, 4-38
chr_example, 4-40
close_example, 4-41 to 4-42
confiLexample, 6-13 to 6-14
cos_example, 4-59 to 4-60
discard_example, 4-62 to 4-63

22

Index

div_example, 4-67
eof_example, 4-74
eoln_example, 4-75 to 4-76
exit_example, 4-77 to 4-78
exp_example, 4-79 to 4-80
find_and_replace_example, 4-84 to 4-86
firstof_lastof_example, 4-88
for_example, 4-90 to 4-91
forward_example, 5-16 to 5-17
funcs _for_fortran-P, 7-26
get_example, 4-93 to 4-94
goto_example, 4-97 to 4-98
hypot_c, 7-31
hypot_sub, 7-20
hypotenuse, 7-18
if_example, 4-100 to 4-101
in_example, 4-102 to 4-103
in_out_example, 5-9
in_range_example, 4-105
labeled, 2-9
In_example, 4-107 to 4-108
Ish ft_example, 4-109 to 4-110
max_example, 4-111 to 4-112
min_example, 4-114
mixed_types, 7-23
mod_example, 4-116
nestinLexample, 2-20
next_example, 4-124
not_example, 4-127
odd_example, 4-128
open_example, 4-132 to 4-133
or_example, 4-136
ord_example, 4-138
pack_example, 4-140 to 4-141
page_example, 4-143
pas_to_c_arrays, 7-37
pas_to_c_hypo, 7-31
pas_to_c-ptrs, 7-39
pas_to_c_strings, 7-32
pas_to_c_strings2, 7-34
pas_to_ftn_hypo_func, 7-18
pas_to_ftn_hypo_sub, 7-19
pas_to_ftn_mixed, 7-21 to 7-24
pass_char, 7-35
pass_func_to_c-p, 7-42
pass_func_to_fortran-p, 7-25
pass_routine-ptrs, 5-12
pred_example, 4-148
ptoc_and_ctop_example, 4-149 to 4-151
put_example, 4-153 to 4-154
read_example, 4-156 to 4-157
recursive_example, 5- 26
repeat_example, 4-161 to 4-162
reset_example, 4-165

Sample programs (continued)
return_example, 4-166 to 4-167
rewrite_example, 4-169
round_example, 4-170
sample_types, 3-3
set_example, 4-177 to 4-178
sin_example, 4-180
single_dim, 7-37
size of_example , 4-183
sort_array_c, 7-41
sort_array_f, 7-27
sqr_example, 4-184 to 4-185
sqrt_example, 4-186 to 4-187
substr_example, 4-190
succ_example, 4-192
trunc_example, 4-195 to 4-196
ttf_example (type transfer functions),
4-199
unpack_example, 4-201 to 4-202
value.J>arameter_example, 5-7
var.J>arameter_example, 5-6 to 5-7
variable_attribute_example, 5-18
while_example, 4-209 to 4-210
with_example, 4-213 to 4-214
write_example, 4-220
xor_example, 4-222
See also by statement name

Set data types, 3-15 to 3-17
alignment, 3-35
assigning values to, 4-173
declaring, 3-15
determining membership with in operator,
4-102 to 4-103
equality of, 4-176
exclusion, 4-175
initializing, 3-15 to 3-16
internal representation of, 3-16 to 3-17
intersection of, 4-175
operations, 4-173 to 4-178
sample program, 4-177 to 4-178
packed, 3-15
deviation from standard Pascal, D-1
size of, 3-16
subsets, 4-176
supersets, 4-176
table of operators, 4-174
union of, 4-174
union operator (+), 4-3
Set_sr function, E-5
Shifting bits
arithmetic right shift, 4-29 to 4-30
left shift, 4-109 to 4-110
right shift, 4-171 to 4-172

Scope
of attributes, 3-78
of routine options, 5-22
of variables
global and local, 2-17 to 2-19
nested routines, 2-19 to 2-21

Short-circuit operators
and then, 4-3, 4-18 to 4-20
definition, 4-19
or else, 4-3, 4-134 to 4-136

Searching alternate directories for include files,
compiler option, 6-20 to 6-21

Side effects, discarding unused return values,
4-62 to 4-63

Section routine attribute, 5-24 to 5-26

Sign bit
and arshft function, 4-29
and rshft function, 4-171

Sections
definition, 3-52
extension to standard, C-2
putting variables into, 3-52 to 3-53
example, 7-7
See also Data sections
Semicolon (;)
in compiler directives, 4-43 to 4-44
in statements, 4-188
Series 10000
alignment and, 3-74
conditional compilation, 4-46, 4-57
and natural alignment, 3-64
predeclared conditional variable, 4-46

Shortword boundary, definition, 3-23

Simple data types
list of, 3-1
See also Data types
Sin function, 4-6, 4-179 to 4-180
sample program, 4-180
Single, data type. See Real number data types
Single· quote (')
as character constant delimiter, 3-12
as string delimiter, 2-4 to 2-6
Single-precision numbers. See Real number data
types

Index

23

Size
of array elements, 3-46, 3-47
of arrays, 3-37
deviation from standard Pascal, 0-1
initializing default, 3-42
attributes, 3-60 to 3-62
minimum for data types, 3-61
of records, 3-26
packed, 3-35
of sets, 3-16
See also Sizeof function
Sizeof function, 4-181 to 4-183
sample program, 4-183
Skipping a loop interation, with next statement,
4-123 to 4-124
Slash (I), as division operator, 4-3
-slib compiler option, 6-33 to 6-34
%slibrary directive, 4-56
Software development. See Program development
Spaces, in prompt-strings, 4-130
Spreading source code across lines, 2-6 to 2-7
Sqr function, 4-6, 4-184 to 4-185
sample program, 4-184 to 4-185
Sqrt function, 4-6, 4-186 to 4-187
sample program, 4-186 to 4-187
Square brackets ([])
in array declaration, 3-38
in array initialization, 3-39
and set assignment, 4-173
Square root function, 4-186 to 4-187
Squaring a number, 4-184 to 4-185
Stack frame, run-time error, 9-50, 9-53 to
9-54
Stack pointer, 5-20
Stack unwind error, 9-50, 9-53 to 9-54
Standard input. See I/O
Standard output. See I/O
Standard Pascal
deviations from, 0-1 to 0-5
extensions, list of, C-1 to C-14
implementation, compiler option, 6-23
messages about nonstandard usages, compiler option, 6-35
Statement, definition, 4-188

24

Index

Static
clause, definition, 7-3
variables, initializing, 3-4, 3-7
-std compiler option, 6-35
Stopping. See Terminating
Storage
allocating with new procedure, 4-117 to
4-122
de allocating with dispose procedure, 4-64
to 4-65
dynamic, within routines, 3-4
packed records, 3-36
specifying with size attributes, 3-60 to 3-62
static, initializing variables, 3-4, 3-7
See also Internal representation; Size
Stream marker, 8-5 to 8-6
advancing with get, 4-92 to 4-94
advancing with put, 4-152 to 4-154
advancing with read and readln, 4-155 to
4-157
advancing with write, 4-215 to 4-220
and end-of-line character, 4-75
setting to beginning of file with reset,
4-164 to 4-165
setting with find procedure, 4-83 to 4-86
setting with rewrite, 4-168 to 4-169
Streams
lOs and file variables, 8-3
lOS (Input Output Stream) calls, 8-1 to
8-2
String, predefined array type, 3-38
See also Strings
Strings, 2-4 to 2-6
C correspondence, 7-32 to 7-35
sample program, 7-32 to 7-35
concatenating with append, 4-21 to 4-22
sample program, 4-21 to 4-22
definition, 2-4, 3-38
embedding unprintable characters, 2-4 to
2-6
extracting substrings, 4-189 to 4-190
finding length of, 4-181 to 4-183
internal representation, 3-44
null character in variable-length, 4-205
operations, 4-204 to 4-207
padding, 4-27
passing from C to Pascal, 4-61
passing from Pascal to C, 4-149 to 4-151
and single quotes, 2-4
and sizeof function, 4-181
variable-length, 3-44 to 3-45
and write procedure, 4-216

Structured data types
alignment of, in packed records, 3-35
list of, 3-2
See also Data types
-subchk compiler option, 6-35
Subrange data types, 3-14 to 3-15
internal representation of, 3-14 to 3-15
Subscripts
in arrays, 4-25
checking, compiler option, 6-35
Subsets, 4-176
Substr function, 4-189 to 4-190
sample program, 4-190
Substrings, 4-189 to 4-190
Subtraction, 4-3
Succ function, 4-191 to 4-192
sample program, 4-192
Summary of technical changes, iv to v

module heading, 7-2
natural attribute, 3-63
packed arrays, 3-45
pas command, 6-4
pointers, 3-49
procedure pointers, 3-51
repeat counts, 3-40
routine options, 5-15
sets, 3-15
size attributes, 3-60
unaligned record, 3-34
variable-length strings, 3-44
variant records, 3-19
See also name of command
System calls
error status parameter, 9-1
lOS (Input Output Stream) calls, 8-1 to
8-2
VFMT (variable format) calls, 8-2 to 8-3
Systems programming routines, 4-10, E-1 to
E-5

Supersets, 4-176 to 4-177
Suppressing
COFF line number tables, compiler option,
6-26
type checking. See Type checking
Switches. See Attributes for variables and types;
Compiler options; Routine options
Symbolic map
compiler option, 6-24 to 6-25
for include files, compiler option, 6-21
Symbols, using internal to make routines local,
5-17
Syntax
-config option, 6-12
-cpu option, 6-14
-info option, 6-21
-inlib option, 6-23
-I option, 6-24
-slib option, 6-33
aligned attribute, 3-63
aligned record. 3-33
attributes for variables and types, 3-53
case statement, 4-36
data sections, 3-52
file variables, 3-48
fixed records, 3-17
function pointers, 3-51
initializing, pointers, 3-51
initializing data, records, 3-21

T
Tag fields. See Record data types
Tangent function, 4-23
Target workstations
predeclared conditional variables, 4-46
selecting, compiler option, 6-14 to 6-17
tb utility, 6-40 to 6-41
Technical changes, summary, iv to v
Terminating
a for loop, 4-90
a group of statements with end, 4-71 to
4-72
a loop with exit, 4-77 to 4-78
program
with noreturn option, 5-20
with return statement, 4-166
See also Transferring control
Testing
for end of file, 4-73 to 4-74
for end of line, 4-75 to 4-76
for open and find errors, 9-3 to 9-4
whether integer is odd, 4-128
Text, files, 3-48
definition, 3-48
See also Files
.text section, 2-10, 5-24 to 5-26

Index

2S

Then. See If statement

Universal parameter specification, 5-10 to 5-11

Tilde C), as bitwise negation operator, 4-3

Universal pointer type, 3-50

To. See For statement

UNIX
ar archiver, 6-38 to 6-39
compatible text files, 8-6
debugging with dbx, 6-40
file compatibility, 3-48

Tools. See Utilities
Traceback (tb) utility, 6-40 to 6-41
and run-time errors, 9-52
Transferring control
abnormally, 5-19
with case statement, 4-36 to 4-38
exit statement, 4-77 to 4-78
with go to statement, 4-95 to 4-98
with next statement, 4-123 to 4-124
noreturn routine option, 5-20
out of for loop, 4-90
with return statement, 4-166 to 4-167

Unpack procedure, 4-200 to 4-202
sample program, 4-201 to 4-202

Trigonometric functions, predeclared, 4-5 to
4-8
arctan, 4-23 to 4-24
cos, 4-59 to 4-60
sin, 4-179 to 4-180

Until. See Repeat statement

Trune function, 4-6, 4-195 to 4-196
sample program, 4-195 to 4-196
Truncating, reals to integers, 4-195 to 4-196
Truth tables
bit operators, 4-33 to 4-35
logical and operator, 4-18
logical or operator, 4-134
Type checking
parameters, 5-11
for subranges with in_range, 3-14
suppressing with univ parameter type, 5-10
to 5-11
Type declaration part, ,2-13 to 2-14
Type transfer functions, 4-197 to 4-199
and manipulating addresses, 4-144 to
4-145
sample program, 4-199

Unstruct files, 3-48, 3-49
definition, 8-6
Up-arrow ("). See Caret (")
Uppercase and lowercase. See Case sensitivity
User interfaces
Domain/Dialogue, 6-42 to 6-43
Open Dialogue, 6-42 to 6-43
Utilities
cpuhelp, 6-17
dbx, 6-40
debugging, 6-39 to 6-40
Domain/Dialogue, 6-42 to 6-43
Domain Distributed Debugging Environment, 6-39
Domain/PAK (Domain Performance Analysis Kit), 6-43
DSEE (Domain Software Engineering Environment), 6-41 to 6-42
getpas, 1-2 to 1-4
Open Dialogue, 6-42 to 6-43
for program development, overview, 6-40
to 6-43
traceback, 6-40 to 6-41

Val_param routine option, 5-3, 5-19

UASC files. See Unstruct files
Unaligned, records, 3-33 to 3-35

U,

in identifier names, 1-4

Union, operation with sets, 4-174
Univ, 5-10 to 5-11
Univ.J>tr, 3-50

26

Unsigned types, 3-9 to 3-10

v

u
Underscore

Unpacked arrays
and pack procedure, 4-139 to 4-141
and unpack procedure, 4-200 to 4-202

Index

Value parameters. See Parameters
Var declaration part, 2-14 to 2-15
%var directive, 4-50
Variable parameters. See Parameters
Variable routine option, 5-17 to 5-18
sample program, 5-18

Variable-Length strings
and ctop procedure, 4-61
operations, 4-204 to 4-207
and ptoc procedure, 4-149 to 4-151
and sizeof function, 4-181
and write procedure, 4-216
Variables
arrays, 3-37 to 3-48
See also Arrays
Boolean, 3-10 to 3-11
See also Boolean data types
character type, 3-11 to 3-13
See also Character data types
correspondence, in C, 7-43 to 7-46
declaring, 2-14 to 2-15
file, 3-48 to 3-49
See also Files
global
overview, 2-17 to 2-19
sample program, 2-18 to 2-19
initializing, 3-4 to 3-5
integers, 3-3 to 3-6
See also Integer data types
local
overview, 2-17 to 2-19
sample program, 2-18 to 2-19
real numbers, 3-6 to 3-9
See also Real number data types
record type, 3-17 to 3-37
See also Record data types
sets, 3-15 to 3-17
See also Set data types
subrange data, 3-14 to 3-15

VFMT (variable format) calls, 8-2 to 8-3
Volatile attribute, 3-56
inheritance, 3-76 to 3-77

w
-warn compiler option, 6-35 to 6-36
%warning 'string' directive, 4-51 to 4-52
Warnings
compiler option, 6-35 to 6-36
definition, 9-4
list of messages, 9-5 to 9-49
While statement, 4-208 to 4-210
sample program, 4-209 to 4-210
Widths, of fields for write and writeln, 4-215
to 4-220
With statement, 4-211 to 4-214
extension to standard, example, C-10
sample program,4-213 to 4-214
Word
alignment
example, 3-71
specifying with aligned attribute, 3-63
%word_alignment directive, 4-57
attribute, 3-60 to 3-62
%word_alignment directive, 4-57
Workstation selection, compiler option, 6-14 to
6-17
list of arguments, 6-16

Variants, compiler, 6-3

Write, writeln procedures, 4-215 to 4-220,
8-8 to 8-9
compared to put procedure, 4-153
flushing buffer before closing, 4-153
sample program, 4-220

Varying, type specifier, 3-44
See also Strings, variable-length

Writing, files. See Put procedure; Replace procedure

Variant records, 3-19 to 3-20
with sizeof function, 4-182
using, 4-159 to 4-160

Varying array
first value, 4-87
last value, 4-106

x

Version, of compiler, 6-3
compiler option, 6-35

Xor function, 4-6, 4-221 to 4-222
sample program, 4-222

-version compiler option, 6-35

-xrs compiler option, 6-36

----88----

Index

27

Reader's Response
Please take a few minutes to give us the information we need to revise and improve our manuals from your point
of view.
Document Title: Domain Pascal Language Reference
Order No.: 000792-AOl

User Profile
Your Name _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Title _ _ _ _ _ _ _ _ _ _ _ _ _ _ __
Company____________________________________________
Address

------------------------------------------(~--~) ------------------

Telephone number

When you use the HP/Apollo system, what job(s) do you perform?

D
D

Programming
System Administration

D
D

Application End User
D Hardware Engineering
Other
(describe) ___________________

Characterize your level of experience in using the HP/Apollo system:

D
D

D

Experienced user (2+ yrs.)

New user (6 mos. or less)

Moderately experienced user (6 mos.-2 yrs.)

What programming languages do you use with the HP/Apollo system?

Distribution
How do you know what manuals are available to support the products you're using or want to use?

What is a major concern for you in ordering books?

How would you evaluate this book?
Excellent

Poor

Average

Completeness

1

2

3

4

5

Accuracy

1

2

3

4

5

2

3

4

5

Usability
1
Additional Comments:

I
I
I
I
II
III

II

11

II

II
I
I
I
I
_ _ _ foiL _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ I

111111
BUSINESS REPLY MAIL
FIRST CLASS

PERMIT NO. 78

CHELMSFORD. MA 01824

POSTAGE WILL BE PAID BY ADDRESSEE

Apollo Systems Division
A Subsidiary of Hewlett-Packard Company
Technical Publications
P.O. Box 451
Chelmsford, MA 01824

fold

NO POSTAGE
NECESSARY
IF MAILED
IN THE
UNITED STATES

Reader's Response
Please take a few minutes to give us the information we need to revise and improve our manuals from your point
of view.
Document Title: Domain Pascal Language Reference
Order No.: 000792-AO 1

User Profile
Your Name _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Title _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __
Company___________________________________________________
Address ______________________________________________________________________
Telephone number

<-> - - - - - - - -

When you use the HP/Apollo system, what job(s) do you perform?

o

o

Programming
System Administration

o

0
0

Application End User
Hardware Engineering
Other
(describe) _ _ _ _ _ _ _ _ _ _ _ _ _ _ __

Characterize your level of experience in using the HP/Apollo system:

o

D

Experienced user (2+ yrs.)

o

Moderately experienced user (6 mos.-2 yrs.)

New user (6 mos. or less)

What programming languages do you use with the HP/Apollo system?

Distribution
How do you know what manuals are available to support the products you're using or want to use?

What is a major concern for you in ordering books?

rIow would you evaluate this book?
Excellent

Average

Poor

Completeness

1

2

3

4

5

Accuracy

1

2

3

4

5

2

3

4

5

Usability

1
Additional Comments:

No posta2e necessary if mailed in the U.S.

I

'I

I:

f

Ir

- - - -fold
---------------------------------NO POSTAGE
NECESSARY
IF MAILED
IN THE
UNITED STATES

BUSINESS REPLY MAIL
FIRST CLASS

PERMIT NO. 78

CHELMSFORD. MA 01824

POSTAGE WILL BE PAID BY ADDRESSEE

Apollo Systems Division
A Subsidiary of Hewlett-Packard Company
Technical Publications
P.O. Box 451
Chelmsford, MA 01824

fold

Flin-

HEWLETT
a!~ PACKARD

Order Number 000792-AOl

111111111111 11111 11111111 111111111111111 1111111 1111111111111
~

9

e e

7

9

2

-

A

e

1

~



Source Exif Data:
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.3
Linearized                      : No
XMP Toolkit                     : Adobe XMP Core 4.2.1-c041 52.342996, 2008/05/07-21:37:19
Create Date                     : 2015:11:16 11:26:42-08:00
Modify Date                     : 2015:11:16 10:47:11-08:00
Metadata Date                   : 2015:11:16 10:47:11-08:00
Producer                        : Adobe Acrobat 9.0 Paper Capture Plug-in
Format                          : application/pdf
Document ID                     : uuid:fc60b43b-9530-b047-8fab-b80ef4300b19
Instance ID                     : uuid:a7b52416-e835-6e47-93fe-3b35566ada24
Page Layout                     : SinglePage
Page Mode                       : UseNone
Page Count                      : 611
EXIF Metadata provided by EXIF.tools

Navigation menu