121636-003 PLM-86 Users Guide Oct82

Download as pdf or txt
Download as pdf or txt
You are on page 1of 263

PL IM-a6 USER'S GUIDE

Copyright © 1980, 1981, 1982 Intel Corporation


Intel Corporation, 3065 Bowers Avenue, Santa Clara, California 95051 Order Number: 121636-003
PL/M-86 USER'S GUIDE

Order Number: 121636-003

Copyright © 1980, 198t, 1982 Intel, Corporation


I Intet Corporation, 3065 S-Qwers Avenue, Santa Clara, CA 95051 I
Additional copies of this manual or other Intel literature may be obtained from:

Literature Department
Intel Corporation
3065 Bowers Avenue
Santa Clara, CA 95051

The information in this document is subject to change without notice.

Intel Corporation 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. Intel Corporation assumes
no responsibility for any errors that may appear in this document. Intel Corporation makes no commitment
to update nor to keep current the information contained in this document.

Intel Corporation assumes no responsibility for the use of any circuitry other than circuitry embodied in
an Intel product. No other circuit patent licenses are implied.

Intel software products are copyrighted by and shall remain the property of Intel Corporation. Use, dupli-
cation or disclosure is subject to restrictions stated in Intel's software license, or as defined in ASPR
7-104.9(a)(9).

No part of this document may be copied or reproduced in any form or by any means without the prior
written consent of Intel Corporation.

The following are trademarks of Intel Corporation and its affiliates and may be used to identify Intel
products:
BXP Insite iSBC MULTICHANNEL
CREDIT intel iSBX MULTIMODULE
i Intelevision iSXM Plug-A-BubbIe
PICE Intellec Library Manager PROMPT
ICE Intellink MCS RMX/80
iCS iOSP Megacbassis RUPI
im iPDS MICROMAINFRAME System 2000
iMMX iRMX MULTI BUS UPI

A711/882/5K DD
ii
REV. REVISION HISTORY DATE

-001 Original issue. 11/80

-002 Added information on DWORD and SELECTOR 8/81


data types, new built-in functions, segmentation
control extensions.

-003 Added built-ins BLOCK I/O, FLAGS, (flags regis- 10/82


ter), and NIL (pointer value, and extended iAPX 186
instructions.

iii
HOW TO USE THIS MANUAL

This manual gives instructions for programming in PL/M-86 and for using the
PL/M-86 compiler to prepare programs for iAPX 86 microcomputer systems. It is
primarily a reference manual for use when you are writing or compiling
PL/M-86 programs; however, it also contains some introductory information to help
you familiarize yourself with PL/M-86 as you start to use it.

The manual assumes you are familiar with basic programming concepts, including
structured programming. The manual, however, does define the language completely,
assuming no prior knowledge of PL/M-86.

Following the description of the language, the manual provides instructions for
compiling your PL/M-86 programs, linking the compiled code, and executing the
final program. It also explains how to interpret compiler output, including error
messages.

Finally, the appendixes provide quick reference information plus supplementary


instructions for interfacing PL/M-86 modules to modules written in other languages
and to your own operating system software.

Manual Organization
This manual contains four kinds of information:
• Introductory and general reference information, including installation instruc-
tions
• Language information, for when you are programming in PL/M-86
• Operating instructions for the compiler and descriptions of compiler controls
• Interfacing information you need if you supply some of your own systems software
in place of that supplied by Intel (e.g., a non-Intel operating system), or if you
are interfacing PL/M-86 modules to modules written in other languages such as
ASM86.

If you are a manager evaluating PL/M-86 to determine whether it fits your needs,
you will find most of the information you need in Chapter 1, which is an overview of
the product.

To get started with PL/M-86, first read this Preface (How to Use this Manual) and
Chapter 1. (If you are familiar with assembly languages but not with high-level
languages, see section 1.2 for a discussion of the advantages of a high-level language
such as PL/M.) Then install the compiler (see instructions in the appendix for your
specific operating system) and try compiling, linking, and running the sample program
at the end of Chapter 1 to verify that the software operates properly.

After that, if PL/M is a new language to you, study and run the sample program in
Chapter 12. Finally, skim through the manual from Chapter 2 to the end and try
writing and running a few programs of your own. Once you have become familiar
with PL/M-86, you will find this manual useful as a complete reference. For a quick
reference, see the PL/M-86 Pocket Reference (order number 121622).

v
If you wish to transport existing PL/M-80 programs to your iAPX 86 application
system, refer to Appendix D for a list of the differences between PL/M-80 and
PL/M-86. This appendix indicates the areas of your programs that may require
modification.

Once you have coded your programs, you are ready to compile, link, and run them.
Refer to Chapter II for information on how to use compiler controls; refer to your
specific host-system appendix for compiler operating instructions. Chapter 14 helps
you interpret error messages you may receive when compiling or running your
programs. For a detailed explanation of the linking process, refer to the iAPX 86
Utilities User's Guide (order number 121616).

If you are coding some of your application software in another language such as
ASM86, refer to Appendix F for the information you need. If you are interfacing to
your own operating system or providing your own file/device drivers, refer to Appen-
dix G for instructions.

Notational Conventions

Section Numbers

All chapters and appendixes are section-numbered for easy cross-referencing. For
instance, heading number 5.3 denotes Chapter 5, section 3. When the text of one
section refers to another section, the reference is made by number; e.g., "as described
in 7.1." Figures and tables are also numbered to aid in cross-referencing; e.g., "in
table 3-1," "see figure 14-1."

Notation for Computer Dialogue

Interactive computer dialogue in this manual consists of commands you enter, which
are immediately echoed on the console display, and the text displayed by the opera-
ting system, the PL/M-86 compiler, and other Intel-supplied programs. The text you
enter is shown in reverse type (white on a black background), and the text displayed
by Intel programs is shown in normal black type. The notation (cr) stands for the
RETURN key on the console keyboard.

Syntax Notation

In the syntax notation for this manual, the following conventions apply:
• Keywords, letter symbols, and punctuation symbols that you use verbatim in your
programs-the terminal symbols of the language-are represented in monospace
type, in which every character has the same width, just as they do in output
media such as CRT console displays and printouts. All letters in terminal symbols
are shown in uppercase in the notation; however, you may use either uppercase
or lowercase for these symbols in your programs. For example:

E WHILE PROCEDURE
( TO LITERALLY
DO END
are terminal symbols.
• Terms standing for language elements or constructs that are defined elsewhere
in this notation-in other words, nonterminal symbols-are represented in itali-
cized lowercase letters in non-monospace type, in which the width of a character
varies. For example:

digits variable
sign expression
binary-digit statement

are nonterminal symbols.


• When two adjacent items must be concatenated, they appear with no space
between them. A blank space between two items indicates that the two items may
be separated by one or more logical-blanks. For example:

digits. digits[ E[sign]digits]

specifies that the first set of digits, the. symbol, and the second set of digits must
be concatenated, with no blanks between them. Likewise, the E symbol, the sign
if included, and the third set of digits must be concatenated. Blanks are permitted
only between the second set of digits and the E symbol.
• Optional constructs are enclosed in square brackets. For example, in the construct
represented by

digits. digits[ E[sign]digits]

the first and second sets of digits and the . symbol are required, and the entire
part following the second set of digits is optional. If this optional part is included,
the sign may still be omitted.
• Optional constructs that can be repeated a number of times are marked by a
three-dot ellipsis following the closing square bracket. For example:

binary-digit [binary-digitj ... B

stands for a concatenated sequence of one or more binary-digits followed immedi-


ately by a B symbol.
• Alternative constructs are represented as vertically adjacent items separated by
extra vertical spacing and enclosed between curly braces that are taller than a
single line of type. When these braces appear, choose anyone of the constructs
enclosed between the braces. For example:

digits
binary-digit [binary-digitj ... B
octa/-digit [ octal-digitj ... Q
hex-digit [hex-digitj ... H

indicates that the construct described may have anyone of the four forms listed
between the large braces.
• Text enclosed between the character sequence /* and the sequence * /, when
these symbols are in light, non-monospace type, is a prose definition of the given
construct. Such definitions are used when symbolic definitions would be more
cumbersome. For example:

/* any uppercase or .lowercase letter of the alphabet * /


is used to avoid listing 52 separate characters vertically between braces.

vii
• The start of a new line in the notation does not mean you must start a new line
at that point in your program; however, you may do so for readability. For
example, when you use the construct:

D 0 variabJe= expression T 0 expression;


statement list
END

you need not include a carriage return after the second expression, but, in many
programs, doing so makes the statement more readable.

(See Appendix C for the BNF notation for the PL/M-86 language.)

viii
CONTENTS I
CHAPTER 1 PAGE PAGE
INTRODUCfION Based Variables ......................................................... 3-15
Product Definition .... ............. ....... ........ ..... ..... ... ........ 1-1 Location References and Based Variables ........... 3-17
The PL/M-86 Language ........................................... 1-1 The AT Attribute ...................................................... 3-17
Using a High-Level Language .............................. 1-1
Why PL/M? .......................................................... 1-2 CHAPTER 4
The Structure of a PL/M-86 Program ..................... 1-2 EXPRESSIONS AND ASSIGNMENTS
PL/M-86 Statements ................................................ 1-3 Operands ................................................. ...... ............. 4-1
Declaration Statements ......................................... 1-3 Constants ............... ..... ............................ ................ 4-1
Executable Statements ........... ............... ................ 1-4 Variable and Location References ........................ 4-2
Built-In Procedures and Variables ........................ 1-4 Subexpressions ....................................................... 4-2
Expressions .......... ,. .......... ..... ... .... ............... ..... ....... 1-4 Compound Operands ............................................. 4-2
Input and Output ................................................... 1-5 Arithmetic Operators '................................................ 4-3
The Program Development Process .......................... 1-5 The +, -, *, and / Operators ............................. 4-3
An Introductory Sample Program .... ........................ 1-6 The MOD Operator ............................................... 4-4
Relational Operators ................................................. 4-4
CHAPTER 2 LogicalOperators ...................................................... 4-5
LANGUAGE ELEMENTS Expression Evaluation ............................................... 4-6
PL/M-86 Character Set ........................................... 2-1 Precedence of Operators: Analyzing an
Tokens, Separators, and the Use of Blanks .............. 2-2 Expression .............................. ........ ................ 4-6
Identifiers and Reserved Words ............................... 2-3 Compound Operands Have Types ........................ 4-8
Constants ................................................................... 2-3 Relational Operators Are Restricted .... ................ 4-9
Whole-Number Constants ..................................... 2-3 Order of Evaluation of Operands ......................... 4-9
Floating-Point Constants ............... ........................ 2-4 Choice of Arithmetic: Summary of Rules ............... 4-10
Character Strings .................................................. 2-5 Special Case: Constant Expressions ..... ................ 4-11
Comments .................................................................. 2-5 Assignment Statements ............................................. 4-12
Implicit Type Conversions ....................... ............. 4-13
CHAPTER 3 Constant Expression ................. .......... ........ ...... ..... 4-13
DATA DECLARATIONS, TYPES, AND Multiple Assignment ............................................. 4-14
BASED VARIABLES Embedded Assignments ........................................ 4-14
Variable Declaration Statements .............. ..... ........... 3-1
Examples ................................................................ 3-2 CHAPTERS
Results .................................................................... 3-3 ARRAYS AND STRUCTURES
Combining DECLARE Statements ..................... 3-3 Arrays ........................................................................ 5-1
Initializations ............................................................. 3-4 Subscripted Variables ........................................... 5-1
The Implicit Dimension Specifier .... ..... .... ..... ....... 3-6 Structures .................................................................. 5-2
Names for Execution Constants: The Use of Arrays of Structures .............................................. 5-3
DATA ............................................................. 3-6 Arrays Within Structures ...................................... 5-3
Types of Declaration Statements .............................. 3-7 Arrays of Structures with Arrays
Compilation Constants (Text Substitution): Inside the Structures ........................ ............. 5-3
The Use of LITERALLY ............................. 3-7 References to Arrays and Structures ....................... 5-4
Declarations of Names for Labels ........................ 3-8 Fully Qualified Variable References .................... 5-4
Results .. ............. ....... ................................... ........... 3-9 Unqualified and Partially Qualified
Declarations for Procedures ...... ............ ................ 3-9 Variable References ....................................... 5-4
Data Types ................................................................. 3-10
BYTE, WORD, and DWORD Variables: CHAPTER 6
Unsigned Arithmetic ..................................... 3-10 FLOW CONTROL STATEMENTS
INTEGER Variables: Signed Arithmetic ............ 3-11 DO and END Statements: DO Blocks ..................... 6-1
REAL Variables: Floating-Point Arithmetic ....... 3-11 Simple DO Blocks ................................................. 6-2
Examples of Binary Scientific Notation ............... 3-12 DO CASE Blocks .................................................. 6-3
POINTER Variables and Location References... 3-13 DO WHILE Blocks ............................................... 6-4
The @ Operator ............................................ 3-13 Iterative DO Blocks ............................................... 6-5
The "Dot" Operator ....... ....... ........................ 3-15 ~e IF Statement ...................................................... 6-7
SELECTOR Variables .......................................... 3-J5 Nested IF Statements ........................................... 6-8

ix
CONTENTS (Cont'd.)

Sequential IF Statements ..................................... . 6-10 Functions ............... ... .................. .... ..... ........... 9-11
GOTO Statements ................................................... . 6-il The SKIPB/SKIPW and SKIPRB/SKIPRW
The CALL and RETURN Statements ................... . 6-12 Functions ............ ....... .......................... ... ........ 9-11
The XLAT Procedure ........................................... 9-12
CHAPTER 7 The SETB and SETW Procedures ....................... 9-12
BLOCK STRUCTURE AND SCOPE Miscellaneous Built-Ins ............................................. 9-13
Names Recognized Within Blocks .......................... . 7-1 The MOVE Procedure .......................................... 9-13
Restrictions on Multiple Declarations ................. . 7-2 The TIME Procedure ............................................ 9-13
Extended Scope: The PUBLIC and The MEMORY Array.......................................... 9-14
EXTERNAL Attributes ................................. .. 7-4 The LOCKSET Function ...................................... 9-14
Scope of Labels and Restriction on GOTOs ........... . 7-6 Interrupt-Related Procedures ................................... 9-15
The SET$INTERRUPT Procedure ..................... 9-15
CHAPTER 8 The INTERRUPT$PTR Function ....................... 9-15
PROCEDURES POINTER and SELECTOR-Related Functions ..... 9-16
Procedure Declarations .8-1 The BUILD$PTR Function .................. ................ 9-16
Parameters ............................................................ . 8-2 The SELECTOR$OF Function ............................ 9-16
Typed Versus Untyped Procedures ..................... . 8-3 The OFFSETSOF Function .................................. 9-16
Activating a Procedure-Function References The NIL Function ................................................. 9-16
and CALL Statements ...................................... 8-4
Indirect Procedure Activation ............................. . 8-5
Exit from a Procedure: The RETURN Statement .. 8-5
The Procedure Body ................................................. . 8-6 CHAPTER 10
The Attributes: PUBLIC and EXTERNAL, PLfM-86 FEATURES INVOLVING
INTERRUPT, REENTRANT ....................... . 8-7 iAPX 86 HARDWARE
Interrupts and the INTERRUPT Attribute ....... . 8-8 iAPX 86 Hardware-Dependent Statements ............. 10-1
Activating an Interrupt Procedure The ENABLE and DISABLE Statements .......... 10-1
with a CALL Statement ............................... . 8-9 The CAUSE$INTERRUPT Statement ............... 10-1
Reentrancy and the REENTRANT Attribute ... . 8-10 The HALT Statement ........................................... 10-1
The iAPX 86 Hardware Flags .................................. 10-1
CHAPTER 9 Optimization and the Hardware Flags ................. 10-1
BUILT-IN PROCEDURES, FUNCTIONS, The CARRY, SIGN, ZERO, and PARITY
AND VARIABLES Functions ................ ... .......... ....... ....... ..... ..... ... 10-2
Obtaining Information About Variables ................. . 9-1 The PLUS and MINUS Operators ...................... 10-2
The LENGTH Function ..................................... .. 9-1 Carry-Rotation Functions ...................................... 10-3
The LAST Function ............................................. . 9-2 The DEC Function ................................................ 10-3
The SIZE Function ............................................. .. 9-2 The iAPX 86 Hardware Registers ............................ 10-3
Explicit Type and Value Conversions ..................... . 9-3 The FLAGS Variable ............................................ 10-3
The LOW, HIGH, and DOUBLE Functions ..... . 9-4 The STACKPTR and STACKBASE Variables.. 10-4
The FLOAT Function ......................................... .. 9-5 iAPX 86 Hardware I/O ............................................ 10-4
The FIX Function ................................................. . 9-5 The INPUT and INWORD Functions ................ 10-4
The INT Function ................................................ . 9-5 The OUTPUT and OUTWORD Arrays .............. 10-5
The SIGNED Function ........................................ . 9-6 The BLOCKINPUT and BLOCKINWORD
The UNSIGN Function ....................................... . 9-6 Procedures ...................................................... 10-5
The ABS and lABS Functions ............................ . 9-7 TheBLOCKOUTPUTandBLOCKOUTWORD
Shift and Rotate Functions ...................................... . 9-7 Procedures ...................................................... 10-5
Rotation Functions ROL and ROR ..................... . 9-7 The REAL Math Facility......................................... 10-6
Logical-Shift Functions SHL and SHR .............. . 9-8 Built-ins Supporting the REAL Math Unit ............. 10-8
Algebraic-Shift Functions SAL and SAR ........... . 9-8 The SET$REALSMODE Procedure ................... 10-8
String Manipulation Procedures .............................. . 9-9 The GET$REAL$ERROR Function ................... 10-8
The MOVB and MOVW Procedures .................. . 9-10 Saving and Restoring the REAL Status .............. 10-9
The MOVRB and MOVRW Procedures ............ . 9-10 The SAVE$REAL$STATUS Procedure ......... 10-9
The CMPB and CMPW Functions ..................... . 9-10 The RESTORE$REALSSTATUS
The FINDBjFINDW and FINDRB/FINDRW Procedure ................................ ........... ..... ... 10-10

x
CONTENTS (Cont'd.) I
CHAPTER 11 CHAPTER 13
COMPILER CONTROLS PLfM-86 EXTENDED
Introduction to Compiler Controls ... ...... ............ ...... 11-1 SEGMENTATION MODELS
The MOD86/MODI86 Control............................... 11-2 Introduction ......... .................. ..... ... ...... .... ...... ...... ... ... 13-1
The LEFIMARGIN Control,................................... 11-2 Extended Segmentation ........................................ 13-1
Object File Controls ................................ ............ ...... 11-3 Subsystems ................................................................ 13-2
INTVECTOR/NOINTVECTOR ........................ 11-4 Open and Closed Subsystems ............................... 13-3
OVERFLOW/NOOVERFLOW ......................... 11-4 The EXPORTS List .............................................. 13-4
OYfIMIZE ............................................................ 11-4 Placement of Controls .................................... ....... 13-6
OYfIMIZE(O) ............................................... 11-5
OYfIMIZE(I) ............................................... 11-5 CHAPTER 14
OP'fIMIZE(2) ............................................... 11-6 ERROR MESSAGES
OP'fIMIZE(3) ............................................... 11-8 Source PL/M-86 Errors ............................................ 14-1
OBJECT/NOOBJECT ......................................... 11-16 Fatal Command Tail and Control Errors ................. 14-20
Object Module Sections ................................ 11-16 Fatal Input/Output Errors ........................................ 14-20
DEBUG /NODEBUG ...................................... ~.... 11-17 Fatal Insufficient Memory Errors ............................ 14-20
TYPE/NOTYPE ................................................... 11-18 Fatal Compiler Failure Errors .................................. 14-20
Program Size Controls ... ..... ..... ........ ........ ... ... ....... 11-18
The SMALL Case ......................................... 11-18 APPENDIX A
TheCOMPACTCase ................................... 11-20 PLfM-86 RESERVED WORDS AND
The MEDIUM Case ...................................... 11-21 PREDECLARED IDENTIFIERS
The LARGE Case ......................................... 11-22
RAM/ROM Control..................................... 11-23 APPENDIXB
Listing Selection and Content Controls .. ... .... .......... 11-24 PROGRAM CONSTRAINTS
PRINT/NOPRINT ................................. ~ ............ 11-24
LIST/NOLIST ..................................................... 11-24 APPENDIXC
CODE/NOCODE ................................................. 11-25 GRAMMAR OF THE PLfM-86 LANGUAGE
XREF/NOXREF' .................................................. 11-25
SYMBOLS/NO~YMBOLS ................................ 11-25 APPENDIXD
Listing Format Controls ............................................ 11-26 SUMMARY OF DIFFERENCES
PAGING/NOPAGING ....................................... 11-26 BETWEEN PLfM-80 AND PLfM-86
PAGELENGTH .................................................... 11-26
PAGEWIDTH ....................................................... 11-26 APPENDIXE
TITLE .................................................................... 11-27 ASCII CODES
SUBTITLE ............................................................ 11-27
EJECT ................................................................... 11-27 APPENDIXF
Sample Program Listing ....................................... 11-28 LINKING TO MODULES WRITTEN IN
Symbol and Cross-Reference Listing ................... 11-28 OTHER LANGUAGES
Compilation Summary .......................................... 11-31
Source Inclusion Controls. ......................................... 11-32 APPENDIXG
INCLUDE ............................................................. 11-32 RUN-TIME INTERRUPT PROCESSING
SAVE/RESTORE ................................................ 11-32
Conditional Compilation Controls ............................ 11-33 APPENDIXH
IF/ELSE/ELSEIF/ENDIF ................................. 11-33 COMPILER INVOCATION AND
SET/RESET ......................................................... 11-35 ADDmONAL INFORMATION
COND/NOCOND ............................................... 11-36 FOR SERIES III USERS
APPENDIX I
COMPILER INVOCATION AND
CHAPTER 12 ADDITIONAL INFORMATION
SAMPLE PROGRAM FOR iRMX 86 USERS

xi
TABLES

TABLE TITLE PAGE TABLE TITLE PAGE


2-1 PL/M-86 Special Characters ................... 2-1 F-l Summary of iAPX 86 Register
3-1 Declaration Elements ................................ 3-1 Usage ..................................................... F-5
4-1 Operators' Precedence .............................. 4-6 F-2 Registers Used to Hold Simple Data
4-2 Summary of Expression Rules ................. 4-10 Types ...................................................... F-5
9-1 Explicit Type and Value Conversions ...... 9-3 F-3 Summary of PL/M-86 Segment
11-1 Compiler Controls ..................................... 11-2 Names ....................................................... F-6
11-2 Controls by Categories .............................. 11-3 G-l Exception and Response Summary .......... G-5

ILLUSTRATIONS I
FIGURE TITLE PAGE FIGURE TITLE PAGE

l-la Sample Program: Module Sort 11-4 Sample Program Showing the
(module 1 of 2) ...................................... 1-7 OPTIMIZE(3) Control......................... 11-14
1-1 b Sample Program: Module Sort 11-5 Program Listing ........................................ 11-29
(module 2 of 2) .................................. .... 1-8 11-6 Cross-Reference Listing ............................ 11-30
3-1 Successive Byte References of a 11-7 Compilation Summary .............................. 11-31
Structure .... .... .... .... ........... ................. .... 3-18 11-8 Sample Program Showing the
7-1 Inclusive Extent of Blocks ........................ 7-2 SET(DEBUG=) Control..................... 11-34
7-2 Outer Level of Block SORT ..................... 7-3 11-9 Sample Program Showing the NOCOND
7-3 Sample Program Modules Illustrating Control................................................... 11-36
Valid GOTO Usage .............................. 7-7 12-1 Sample Program: Record Sort ................. 12-2
7-4 Valid GOTO Transfers ............................. 7-9 F-l Stack Layout at Point Where a
10-1 The iAPX 86 Hardware Flags Non-Interrupt Procedure is
Register ..... ..... .... .... ....... ......................... 10-4 Activated ............................................... F-2
10-2 The REAL Error Byte .............................. 10-7 F-2 Stack Layout During Execution of a
10-3 The REAL Mode Word ............................ 10-7 Non-Interrupt Procedure Body............. F-3
11-1 Sample Program Showing the G-l Stack Layout at Point Where an
OPTIMIZE(O) Control......................... 11-9 Interrupt Procedure Gains Control...... G-2
11-2 Sample Program Showing the G-2 Stack Layout During Execution of
OPTIMIZE(l) Control............. ............ 11-11 Interrupt Procedure Body..................... G-3
11-3 Sample Program Showing the G-3 Memory Layout of Real Save Area ......... G-IO
OPTIMIZE(2) Control......................... 11-13

xii
CHAPTER 11
INTRODUCTION

This chapter introduces the PL/M-86 language and explains the process of develop-
ing software for your iAPX 86 application system using PL/M-86.

1. 1 Product Definition
PL/M is a high-level language for programming various families of microprocessors.
It was designed by Intel Corporation to meet the software requirements of computers
in a wide variety of systems and applications work.

The PL/M-86 compiler is a software tool that translates your PL/M-86 source
programs into relocatable iAPX 86 object modules. You can then link these to other
modules coded in PL/M, assembly, or other high-level languages. The compiler
provides a listing output, error messages, and a number of compiler controls to aid in
program development and debugging. The compiler runs on an Intel microcomputer
development system.

To perform the steps following compilation, use the iAPX 86-based software devel-
opment utilities - LINK86, LIB86, CREF86, LOC 86, and OH 86. Debug your
programs using an applications debugger and the ICE-86 or ICE-88 (In-Circuit
Emulator). For firmware systems, you then use the Universal Prom Programmer
(UPP) with its Universal Prom Mapper (UPM) software to transfer your programs
to PROM.

1.2 The PL/U-86 Language


Using a High-Level Language

High-level languages more closely model the human thought process than lower-level
languages such as assembly language. They therefore are easier and faster to write,
since one fewer translation step is required from concept to code. High-level language
programs are also more likely to be correct, since there is less occasion to introduce
error.

Programs in a high-level language are easier to read and understand, and thus easier
to modify. As a result, you can develop high-level language programs in a much
shorter period of time-programs that are easier to maintain throughout the life of
the product. Thus, high-level languages result in lower costs for both developing and
maintaining programs.

In addition, programs in a high-level language are easily transferred from one proces-
sor to another. Programs that can be transferred between processors without modifi-
cation are said to be portable.

If PL/M-86 is your first high-level language, you probably want to know how
programming in a high-level language differs from assembly language programming.
When you use a high-level language:
• You need not know the instruction set of the processor you are using.
• You need not be concerned with the details of the target processor, such as n~gis­
ter allocation or assigning the proper number of bytes for each data item-the
compiler takes care of these things automatically.

1-1
Introduction PLfM-86 User's Guide

• You use keywords and phrases that are closer to natural English.
• You can combine many operations (including arithmetic and Boolean opera-
tions) into expressions; thus, you can perform a whole sequence of operations
with one statement.
• You can use data types and data structures that are closer to your actual problem.
For instance, in PL/M-86 you can program in terms of Boolean expressions,
characters, and data structures, in addition to bytes and words.

The introductory example at the end of this chapter (section 1.6) illustrates these
points. Compare this PL/M program with an assembly-language program you might
write to solve the same problem.

Coding programs in a high-level language involves thinking differently from coding


in assembly language. This level is actually closer to the level of thinking you use
when you are planning your overall system design.

Why PL/M?
Many high-level programming languages are available today. Some of them have
been around far longer than PL/M. So, once you have decided to use a high-level
language, you might ask: How does PL/M differ from other high-level languages?
What advantages does it have? When is it the right language to use?

Here are some characteristics of PL/M:


• It has a block structure and control constructs that aid-in fact, encourage and
enforce-structured programming.
• It has facilities for such data structures as structured arrays and pointer-based
dynamic variables.
• It is a typed language-that is, the compiler does data type compatiblility and
range checking to help you detect logic errors in your programs at compile time.
• Its data structuring facilities and control statements are designed in a logically
consistent way. Thus, PL/M is a good language for expressing algorithms for
systems programming.
• Its control constructs make program correctness relatively easy to verify.
• It is a standard language used on Intel microcomputers, so PL/M programs are
portable across Intel's processors.

PL/M was designed for programmers (generally systems programmers) who need
access to the microprocessor's features-features such as indirect addressing and direct
I/O for optimum use of all system resources.

What about the differences between PL/M and older, more established languages
like FORTRAN, BASIC, and COBOL? PL/M has many more features than BASIC
and is a more general-purpose language than either FORTRAN (best suited for
scientific applications) or COBOL (tailored for business data processing). Addition-
ally, PL/M differs from these other languages in its typing and block structure.

1.3 The Structure of a PL/M-86 Program


PL/M-86 is a block-structured language: every statement in a program is part of at
least one block-i.e., a well-defined group of statements that begins with a DO state-
ment or a procedure declaration and ends with an END statement.

1-2
PL/M-86 User's Gtdde IntroduetioD

A module is a labeled simple DO-block; that is, a module must begin with a labeled
DO statement and end with an END statement. Between those end points (i.e., within
that DO-block), other statements provide the definitions of data and processes that
make up the program. These statements are said to be part of the block, contained
within the block, or nested within the block. A module can contain other blocks but
is never itself contained within another block.

(The reason for saying usimple" DO-block is that DO-blocks are of three other
varieties, which are explained in Chapter 6.)

NOTE
The word EOF in PL/M-86 is a reserved word indicating the end of the file.
It should not be used as an identifier because the remainder of the module it
is used in will be ignored at compile-time.

Every PL/M-86 program consistg of one or more modules, separately compiled, each
consisting of one or more blocks. There are two kinds of blocks: DO-blocks and
procedure definiton blocks.

A procedure definition block is a set of statements beginning with a proceduredecla-


ration and ending with an END statement. Other declarations and executable state-
ments can go between these endpoints, and are used later when the procedure is
actually invoked or called into execution. The definition block is really a further
declaration of everything the procedure will use and do. Since it is only executed
later, the definition block is considered simply another form of declaration rather
than being viewed as immediately executable.

1.4 PL/M-86 Statements

There are two types of statements in PL/M-86: declarations and executable state-
ments.

Declaration Statements
A simple example of a declare statement is:

DECLARE WIDTH BYTE;


This introduces the identifier WIDTH and associates it with the contents of one byte
(8 bit~) of memory. The programmer need not know the location of the byte-i.e., its
actual address in memory-but will simply refer to the content of this byte using the
name WIDTH.

A group of statements intended to perform a function (i.e., a subprogram or subrou-


tine) can be given a name by declaring them to be a procedure:

ADDER_UPPER: PROCEDURE (BETA);


The statements that define the procedure then follow. This block of PL/M-86 state-
ments is invoked from other points in the program, and may involve passing param-
eters to it and returning a value. When a procedure has finished executing, control is
returned immediately to the main program. This capability is the major feature
permitting modular program construction.

1-3
Introduction PLfM-86 User's Guide

Executable Statements

An example of an executable statement is:

CLEARANCE = WIDTH + 2;
Here, we have two identifiers, CLEARANCE and WIDTH. Both must be declared
prior to this executable statement, which produces machine code to retrieve the
WIDTH value from memory. Once you obtain the WIDTH value, add 2 to it and
store the sum 'in the memory location for CLEARANCE.

For most purposes, the PL/M-86 programmer need not think in terms of memory
locations. CLEARANCE and WIDTH are variables, and the assignment statement
assigns the value of the expression WIDTH + 2 to the variable' CLEARANCE. The
compiler automatically generates all the machine code necessary to retrieve data from
memory, to evaluate the expression retrieved, and to store the result in the proper
location.

The following is a list of all PL/M-86 executable statements and the chapters in
which they are fully discussed:

Assignment Statement Chapter 4


Simple DO Statement Chapter 6
DO CASE Statement Chapter 6
DO WHILE Statement Chapter 6
Iterative DO Statement Chapter 6
END Statement Chapter 6
IF Statement Chapter 6
GOTO Statement Chapter 6
Null Statement Chapter 6
CALL Statement Chapter 8
RETURN Statement Chapter 8
ENABLE Statement Chapter 10
DISABLE Statement Chapter 10
CAUSE$INTERRUPT Statement Chapter 10
HALT Statement Chapter 10

Built-In Procedures and Variables

PL/M-86 provides a large repertoire of built-in procedures and variables. These


procedures provide such functions as shifts and rotations, data type conversions, and
string manipulation. The built-in procedures and variables are described in
Chapter 9.

Expressions

We have already seen simple expressions. A PL/M-86 expression, made up of operands


and operators, resembles a conventional algebraic expression.

Operands include numeric constants (such as 3.78 or 105) and variables (as well as
other types discussed in Chapters 3 and 4). The operators include + and - for
addition and subtraction, * and / for multiplication and division, and MOD for modulo
arithmetic.

As in an algebraic expression, elements of a PLJM-86 expression may be grouped


with parentheses.

1-4
PL/M-86 User's Guide Introduction

An expression is evaluated using unsigned integer arithmetic, signed integer arith-


metic, and/or floating-point arithmetic depending on the types of operands in the
expression (see Chapters 3 and 4).

Input and Output

PL/M-86 does not provide formatted I/O capabilities like those of FORTRAN,
BASIC, or COBOL. PL/M-86 does provide built-in functions for direct I/O which
do not require operating system run-time support. For single-byte or single-word
I/O, these functions are INPUT, INWORD, OUTPUT, and OUTWORD. For block
I/0, they are BLOCKINPUT, BLOCKINWORD, BLOCKOUTPUT, and
BLOCKOUTWORD.

INPUT causes the program to read the 8-bit quantity found in one of the 64K input
ports of the iAPX 86. A reference to OUTPUT causes the program to place an
8-bit quantity into one of the 64K output ports of the iAPX 86.

INWORD and OUTWORD have the same effects as INPUT and OUTPUT except
that they handle 16-bit (WORD) quantities instead of 8-bit (BYTE) quantities.

BLOCKINPUT causes the program to read a string of 8-bit quantities found in one
of the iAPX 86 input ports. BLOCKOUTPUT places a string of 8-bit quantites into
one of the iAPX 86 output ports.

BLOCKINWORD and BLOCKOUTWORD have the same effects as BLOCKINPUT


and BLOCKOUTPUT except that they handle strings of 16-bit quantities instead of
strings of 8-bit quantities.

For more information on these I/O functions, see Chapter 9.

1.5 The Program Development Process

The PL/M-86 compiler is part of an integrated set of tools that make up the total
iAPX 86 development solution for your microcomputer system.

The steps in the software development process are as follows:


1. Define the problem completely.
2. Outline the proposed solution in terms of hardware and software. Once this is
done, you may begin designing your hardware.
3. Design the software for your system. This important step may consist of several
sub-steps, including breaking down the task into modules, choosing the program-
ming language, and selecting the algorithms to be used.
4. Code your programs and prepare them for translation using a text editor.
S. Translate your PL/M program code using the PL/M-86 compiler.
6. If necessary, use the text editor to correct any compile-time errors, then recom-
pile.
7. Using the iAPX 86-based LINK86 (with the BIND option), link the resulting
object module to the necessary support libraries and locate your object code. For
detailed instructions see the iAPX 86,88 Family User's Guide.
8. You can then run your programs and debug them with a debugger such as the
ICE-86 debugger.

1-5
Introduction PL/M-86 User's Gaide

1.6 An Introductory Sample Program

Figure 1-1 shows the listing of a sample PL/M-86 program divided into two modules.
This program contains many undefined words and constructs that will be explained
in the upcoming chapters. The programs appear here: 1) to show what a small
PL/M-86 program looks like separated into two modules, and 2) to explain, step by
step, how to compile, link, and run programs on your development system.

The interactive computer dialogue in this section consists of commands you enter,
which are immediately echoed on the console display, and text displayed by the
operating system, the PL/M-86 compiler, and other Intel-supplied programs. The
text you enter is shown in reverse type (white on a black background), and the text
displayed by Intel programs is shown in normal black type. The notation <cr) stands
for the RETURN key on the console keyboard. Note that the operating system prompt
(indicating that it is ready to accept a command) and, for some systems, the name of
the loader (e.g., RUN on the Series III) are not included. See the appendix for your
specific operating system for details.

The main program, to be compiled as a module named "M," does little but define
some data and then call the procedure named SORTPROC. This procedure is dermed
in the other module, which is to be compiled with the name SORTMODULE. To
prepare this sample program for execution, first type it in using a text editor.

Then, compile each module separately. For example, if the file PROGIA.SRC
contains the module SORTPROC, then you would invoke the compiler with the
command:

The compiler responds on the console with a sign-on message:

system-id P LIM - 8 6 COM P I LER Vx.Y


where
system-id is the name of your operating system.
x.y is the version number of the compiler.

This is followed by the console sign-off message:

PL/M-86 COMPILATION COMPLETE. nWARHIHGS, mERRORS


where
nand m represent, respectively, the number of warnings and nonfatal
errors encountered during compilation.

This process would then be repeated with the file PROGIB.SRC, which contains the
module M.

Next, link the resulting object modules using the LINK86 command

LINK86 displays the sign-on message

system-id 8 0 8 6 LIN KER Vx.Y


processes your program and returns control to the operating system.

1-6
PLfM-86 User's Guide Introduction

Finally, you can execute your program with the command

: : = ~, ( = r >

system-id PL/M-86 V2.1 COMPILATION OF MODULE SORTMODULE


OBJECT MODULE PLACED IN :Fl:PROGIA.OBJ
COMPILER INVOKED BY: :Fl:PLM86.86 :Fl:PROGIA.SRC

SORTMODULE: DO; /*Beginning of module*/


2 1 SORTPROC: PROCEDURE (PTR, COUNT, RECSIZE, KEYINDEX) PUBLIC;
3 2 DECLARE PTR POINTER, (COUNT, RECSIZE, KEYINDEX) WORD;

/* Parameters:
PTR is pointer to first record
COUNT is nwnber of records to be sorted.
RECSIZE is number of bytes in each record - maximum
is 128.
KEYINDEX is byte position within each record of a
BYTE scalar
to be used as sort key.*/
4 2 DECLARE RECORD BASED PTR(I) BYTE,
CURRENT(128) BYTE,
(I,J) WORD;
5 2 SORT: DO J = 1 TO COUNT-I;
6 3 CALL MOVB(@RECORD(J*RECSIZE),@CURRENT, RECSIZE);
7 3 I=J;
8 3 FIND: DO WHILE 1>0 AND
RECORD«I-l)*RECSIZE + KEYINDEX»
CURRENT(KEYINDEX);
9 4 CALL MOVB(@RECORO«I-l)*RECSIZE),
@RECORD(I*RECSIZE), RECSIZE)i

HI 4 1=1+1;
11 4 END FIND;
12 3 CALL MOVB(~CURRENT, @RECORD(I*RECSIZE), RECSIZE)i
13 3 END SORT;
14 2 END SORTPROCi
15 1 END SOR'rMODULE; /*End of Module* /

MODULE INFORMATION:

CODE AREA SIZE 0ldA5H 1650


CONSTANT AREA SIZE 000IQH 0D
VARIABLE AREA SIZE 0~84H 1320
MAXIMUM STACK SIZE 000CH 12D
310J LINES READ
o PROGRAM WARNINGS
o PROGRAM ERRORS
DICTIONARY SUMMARY:

27KB MEMORY AVAILABLE


3KB MEMORY USED (11%)
0KB DISK SPACE USED

END OF PL/M-86 COMPILATION

Figure I-Ia. Sample Program: Module Sort (module I of 2)

1-7
Introduction PL/M-86 User's Guide

system-id PL/M-8~ V2.1 COMPILATION OF MODULE M


OBJECT l'-10DULE PLACED IN :Fl:PROGlB.OBJ
COMPILER INVOKED BY: :Fl:PLM86.86 :F1:PROGIB.SRC

M: DO; /*Beginning of module*/

/* Program to sort two sets of records, using SORTPROC */


2 1 SORTPROC: PROCEDURE (PTR, COUNT, RECSIZE, KEYINDEX) EXTERNAL;
3 2 DECLARE PTR POINTER, (COUNT, RECSIZE, KEYINDEX) WORD;
4 2 END SORTPROC; /* End of usage declaration */

5 1 DECLARE SET1(50) STRUCTURE(ALPHA WORD,


BETA(12) BYTE,
GAMMA INTEGER,
DELTA REAL,
EPSILON BYTE);

/* Key of Nth record in SET1 is SET1(N) .BETA(0}, the 3rd byte


in the record. */

6 1 DECLARE SET2(500) STRUCTURE (ITEMS (21) INTEGER,


KEY BYTE);

/* Key of Nth record in SET2 is SET2(N) .KEY, the 43rd byte in


the record. */

/* Data is read to initialize the records. */

7 1 CALL SORTPROC{@SET1, LENGTH (SET1) , SIZE(SET1{1», 2);


8 1 CALL SORTPROC(@SET2, LENGTH (SET2) , SIZE(SET2(1», 42);

/* Data is written out from the records. */

9 1 END M; /* End of module */

MODULE INFORMATION:

CODE AREA SIZE 0029H 41D


CONSTANT AREA SIZE 0000H 0D
VARIABLE AREA SIZE 5816H 22550D
MAXIMUM STACK SIZE 000AH 10D
32 LINES READ
o PROGRAM WARNINGS
o PROGRAM ERRORS
DICTIONARY SUMMARY:

27KB MEMORY AVAILABLE


3KB MEMORY USED (11%)
0KB DISK SPACE USED

Figure I-lb. Sample Program: Module Sort (module 2 of 2)

1-8
CHAPTER 2
LANGUAGE ELEMENTS

PL/M-86 programs are written free-form, meaning there is no significance to where


a statement is placed on an input line, and blanks can be freely inserted between the
elements of the program.

2.1 PL/M-86 Character Set


The character set used in PLfM-86 is a subset of the ASCII character set, as follows:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789

along with the special characters

=./{)+-'*, < ) :;@$-

and the blank or space; plus the tab, carriage-return, and line-feed characters.

The rules in this section apply to everything in a PLfM-86 program except character
string constants (section 2.4), and comments (section 2.5).

If a PL/M-86 program contains any character that is not in the set above, the compi-
ler treats it as an error (or, in some cases, a warning only; see Chapter 14).

Uppercase and lowercase letters are not distinguished from each other except in string
constants. For example, xyz and XYZ are interchangeable. In this manual, all
PL/M-86 code is in uppercase letters to help distinguish it from explanatory text.

Blanks are not distinguished from each other except in string constants. The compiler
treats any unbroken sequence of blanks as a single blank.

Special characters and combinations of them have particular meanings in a


PL/M-86 program, as described in the remainder of this mariual.

Here is a concise glossary of special characters and combinations:

Table 2-1. PL/M-86 Special Characters


Symbol Name Use

= equal sign Two distinct uses:


(1) assignment operator
(2) relational test operator
assign embedded assignment operator
@ at-sign location reference operator
dot Three distinct uses:
(1) decimal point
(2) structure member qualification
(3) address operator

/ slash division operator


r beginning-of-comment delimiter
*/ end-of-comment delimiter

2-1
Laagage Elements PL/M-86 User's GuitIe

TaMe 2-1. PLfM-86 Special Characters (Cont'd.)


Symbol Name Use

( left paren left delimiter of lists, subscripts, and some expressions


) right paren right delimiter of lists, subscripts, and some expressions
+ ptus addition operator or unary ptus operator
- minus subtraction or unary minus operator
apostrophe string delimiter
* asterisk multiplication operator, implicit dimension specifier
< less than relational test operator
> greater than relational test operator
<= less or equal relational test operator
>= greater or equal relational test operator
= equal relational test operator
<> notequai relational test operator
: colon label delimiter
; semicolon statement delimiter
, comma list element delimiter

- underscore significant character in identifier


$ dollar sign non-significant character in numbers or identifiers

2.2 Tokens, Separators, and the Use of Blanks


Just as an English sentence is made up of words-the smallest meaningful units of
English-so a PLjM-86 statement is made up of tokens. Every token belongs to one
of the following classes:
• Identifiers
• Reserved words
• Simple delimiters (all of the special characters, except the dollar sign, are simple
delimiters. )
• Compound delimiters-these combinations of two special characters:
< > <= >= j* *j
• Numeric constants
• Character string constants

For the most part, it is obvious where one token ends and the next one begins. For
example, in the assignment statement:

EXACT-APPROX*(OrrSET-3)/SCALE;
EXACT, APPROX, OFFSET, and SCALE are identifiers, 3 is a numeric constant,
and all the other characters are simple delimiters.

Sometimes a simple or compound delimiter does not occur between two identifiers,
reserved words, or numeric const~nts--e.g., DECLAREABYTE. In these cases, a
blank must be placed between them as a separator. (Instead of a single blank, any
unbroken sequence of blank characters may be used.)

Also, a comment (see section 2.5) ~ay be used as a separator.

2-2
PL/M-86 User's Guide Language Elements

Blanks may be inserted freely around any token without changing the meaning of the
PL/M-286 statement. Thus~ the assignment statement:
EXACT - APPRDX • ( OFFSET - 3 ) / SCALE;
is equivalent to:
EXACT-APPRDX*(DFFSET-3)/SCAlE;

2.3 Identifiers and Reserved Words


Identifiers are used to name variables, procedures, symbolic constants, and statement
labels. Identifiers may be up to 31 characters in length. The first character must be
alphabetic, and the remainder may be either alphabetic, numeric, or the
underscore (_).

Embedded dollar signs are totally ignored by the compiler, and may be used freely
to improve the readability of an identifier or constant (although the $ may not be the
first character). An identifier or constant containing a dollar sign is exactly equiva-
lent to the same identifier with the dollar sign deleted.

Examples of valid identifiers are:


INPUT_COUNT
X
GAMM
LONGIDENTIFIER WITHNUMBER3
LONG$$$IDENTIFIER$$$NUMBER$$$3
INPUT$COUNT
INPUTCOUNT

The long identifiers are identical (to the compiler). The last two examples are inter-
changeable, but are different from the first.

Certain reserved words must not be used as identifiers because they are actually part
of the PL/M-86 language. These are listed in Appendix A.

There is also a set of predeclared identifiers naming built-in procedures and variables.
You are permitted to declare these names for your own purposes, but when you do
so the built-in value or procedure becomes inaccessible. Appendix A lists these
identifiers.

2.4 Constants
A constant is a value that does not change during your program's execution. There
are three types of constants: whole-number constants, floating-point constants, and
character strings.

Whole-Number Constants
Whole-number constants can be binary, octal, decimal, or hexadecimal. The compiler
recognizes these by a suffix of B, 0 (or Q), D, 'or H. Numbers without a suffix are
considered decimal. If a constant contains characters invalid in the designated number
base, it will be flagged as an error.

For example, the maximum whole-number WORD constant is:


216 -1 = 1111$111I$llll$llllB = 177777Q = 65535D = OFFFFH

2-3
Language Elements PLfM-86 User's Guide

The first character of a hexadecimal number must be a numeric digit to avoid looking
like an identifier. For example, the hexadecimal representation for 163 must be written
OA3H rather than A3H, which would be taken as an identifier.

Examples of valid whole-number constants:

12AH 2 33Q 1010B 55D OBF3H 65535 7770 3EACH OF76C05H

Examples of invalid whole-number constants:

12AF Hexadecimal digits used without an H suffix, hence invalid in the


default decimal interpretation.

12AD Here the final D could be a suffix but the A is not a decimal digit.
If hexadecimal is intended, a final H is needed.

l1A2B 'A' and '2' are not valid binary digits. If hexadecimal is intended,
a final H is necessary.

2ADGH 'G' is not a valid hexadecimal digit.

A whole-number constant can be a BYTE, WORD, DWORD, or INTEGER value


depending on its size and context, as explained in Chapter 3. INTEGER context
means a signed value from -32768 to +32767. POINTER context means the three
restricted cases that allow an actual numeric address; the maximum value for these
is 1,048,575 (see section 3.4).

Note that a minus sign in front of a constant is not part of the constant. An INTEGER
value may be negative, but the range of whole-number constants is non-negative.

Floating-Point Constants

The presence of a decimal point in a decimal constant creates a floating-point constant,


i.e., a number of type REAL. Only decimal REALs are allowed.

At least one decimal digit (e.g., 0) must precede the decimal point. A fractional part
is optional after the decimal point, as is the base-ten exponent, which is indicated by
the letter E. This exponent must have at least one digit. Note that no fractional
exponents are possible. The largest REAL constant value is 3.37 X 10+ 38, and the
smallest REAL is 1.17 X 10-38 •

Examples of valid REAL constants:

5.3 176.0 1.88 3.14159 0.15 16. 222.2

53.0E-I 1.760E2 O.188El 314159E-5 1.5E-l 1.6E+ 1 2.222E+2

The exponents in the third and sixth examples are the same; plus signs don't change
the meaning.

Examples of invalid REAL constants:

6 No decimal point
1.3AH Hexadecimal not allowed in REALs
10.OlIB Binary not allowed in REALs
7.52Q Octal not allowed in REALs
4.8EIAHJ2 Only decimal constants in exponents-no hexadecimal, no
expressions, no fractions

2-4
PL/M-86 User's Guide Language Elements

Character Strings

Character strings are denoted by printable ASCII characters enclosed within


apostrophes. To include an apostrophe in a string, write it as two apostrophes; e.g.,
the string "'Q' comprises 2 characters, an apostrophe followed by a Q. Spaces are
allowed but line-feeds are not. The compiler represents character strings in memory
as ASCII codes, one 7-bit character code to each 8-bit byte, with a high-order zero
bit. Strings of length 1 translate to single-byte values. Strings of length 2 translate to
double-byte values, and those of length 3 or 4 translate to double-word values. For
example:

'A' is equivalent to 41 H
'AG' is equivalent to 4147H
'AGR' is equivalent to 414752H
'AGRX' is equivalent to 41475258H

(See ASCII code table in Appendix F.)

Therefore, character strings can be used only as BYTE, WORD, or DWORD values
since strings longer than 4 characters would exceed the 32-bit capacity of a DWORD
value. As constants, however, longer character strings are stored as a sequence of
bytes and can be used in a PLfM-86 program (see Chapter 3).

The maximum length of a string constant is 255 characters. It can be used only as
an initialization for an array or as part of a location reference pointing to where that
string constant is stored.

2.5 Comments
Explanatory comments may be interleaved with PLfM-86 program text to improve
readability and provide program documention. A PLfM-86 comment is a sequence
of characters delimited on the left by the character pair j* and on the right by the
character pair * f. These delimiters instruct the compiler to ignore any text between
them and to consider such text not a part of the program proper.

A comment may contain any printable ASCII character and may also include space,
carriage-return, line-feed, and tab characters.

A comment may not be embedded inside a character string Constant, i.e., it will become
part of the string and the compiler won't recognize it. Apart from this, it may appear
anywhere that a blank character may appear-that is, anywhere except embedded
within a token. Thus, comments may be freely distributed throughout a PLfM-86
program.

Here is a sample PLfM-86 comment:

f*This procedure copies one structure to another. *f

In this manual, comments are presented in uppercase and lowercase to help distin-
guish them visually from program code, which is always presented in uppercase.

2-5
CHAPTER 3
DATA DECLARATIONS, TYPES,
AND BASED VARIABLES

Four types of objects can be declared to have symbolic names: variables, constants,
labels, and procedures. One declaration must be available for each name used in a
block-no more, no less. This declaration may appear at the beginning of the block,
or in an enclosing outer block. Multiple declarations of the same name in the same
block are invalid.

Only after being declared and defined can names for the four elements above be used
in executable statements. For variables, constants, and labels, such usage is, in essence,
an operational definition. For a procedure, the set of statements between its declara-
tion and its end statement constitutes its definition.

In addition to the item's name, a declaration tells its type, attributes, and/or location.
These terms will be clarified in the course of this chapter.

Table 3-1 shows the general appearance of declarations, e.g., required or optional
elements.

3.1 Variable Declaration Statements


A DECLARE statement is a non-executable statement that introduces some object
or collection of objects, associates names (and sometimes values) with them and
allocates storage if necessary. The most important use of DECLARE is for declaring
variables.

A variable may be a scalar-that is, a single quantity-an array, or a structure.

A scalar variable is a single object whose value is not necessarily known at compile
time and may change during the execution of the program. You therefore refer to it
by declaring a name to be used in the program. This name is known as an identifier.

Table 3-1. Declaration Elements


Declaration
Statements Must Use Can Use
For

Variable type: linkage attributes:


Names BYTE, WORD, DWORD, PUBLIC or EXTERNAL
INTEGER, POINTER,
SELECTOR, REAL, or
STRUCTURE
location attributes:
AT (location reference)
variable initialization attribute:
INITIAL (value-list)

Execution type, as above, and linkage attributes as above


Constant constant initialization
Names attribute: DATA (value-list)

Label Names LABEL linkage attributes as above

Compilation LITERALLY 'string'


Constant
Names

3-1
Data Declarations, Types, aDd Based Variables PLJM-86 User's Guide

An array is a list of scalars all named by the same identifier, differentiated from each
other by the use of subscripts, e.g., A( 0), a( I ), A( 123), and so on.

A structure is a list of scalars and/or arrays that all use the same main identifier and
that can be differentiated from each other by their own member-identifiers (field
names). For example, EMPLOYEES. NAME could refer to the NAME field within
the structure EMPLOYEES. .

Such variables (arrays and structures) are discussed in greater detail in Chapter 5.

Types are described in section 3.4.

Examples

The following statements declare scalars:

DECLARE APPROX REAL:


DECLARE (OLD, HEW) BYTE;
DECLARE POINT WORD, VAl12 BYTE;
The first example declares a single scalar variable of type REAL, with the identifier
(name) APPROX. The second example declares two scalars, OLD and NEW, both
of type BYTE. This kind of statement is called a "factored declaration." It is
equivalent to the sequence:

DECLARE OLD BYTE;


DECLARE HEW BYTE;
except that the factored declaration guarantees the bytes will be contiguous; separated
declaration statements do not.

The third example declares two scalars of different types: POINT is of type WORD,
and VAL 12 is of type BYTE.

The following statements declare arrays:

DECLARE DOMAIN (128) BYTE;


DECLARE GAMMA (19) DWORD;
The first statement declares the array DOMAIN, with 128 scalar elements, each of
type BYTE. These elements are distinguishable by subscripting the name DOMAIN,
using the range 0 to 127 for the subscripts. For example, the third element of
DOMAIN can be referred to as DOMAIN(2). The first element of every array has
subscript o.

The second statment declares the array GAMMA, with 19 scalar elements of type
DWORD. The subscripts for this array can range from 0 to 18.

The next statement declares a structure with two scalar members:

DECLARE RECORD STRUCTURE (KEY BYTE, INFO WORD);


The two members are a BYTE scalar that can be referred to as RECORD. KEY and
a WORD scalar that can be referred to as RECORD.INFO. The word named by
RECO RD .INFO is the second and third bytes of this structure.

Further discussion of structures appears in sections 3.4 and 3.6, and. in Chapter 5.

3-2
PL/M-86 User's Guide Data Declarations, Types, and Based Variables

Results
The two results of a valid variable declaration are:
1. The name is given a unique address.
2. The variable is considered to have the attributes declared.

This means that all subsequent uses of the variable in the block where it is declared
will refer to the same address (except for based variables, discussed in section 3.5).

A valid variable declaration also requires all references to the variable to conform to
the rules for the current attributes, i.e., those having priority in the current block.
Thus, the compiler can flag a large variety of errors that are caused by incompatible
declarations within the current block.

Combining DECLARE Statements


A separate DECLARE statement is not required for each and every declaration.
Instead of writing the two DECLARE statements:

DECLARE CHR BYTE INITIAL ('A')j


DECLARE COUNT INTEGERj
we may write both declarations in a single DECLARE statement, as follows:

DECLARE CHR BYTE INITIAL ('A'), COUNT INTEGER;


This declare statement contains two "declaration elements," separated by the comma.
Every DECLARE statement contains at least one declaration element. If it contains
more than one, they are separated by commas.

Previously, most examples have shown only one declaration element in each
DECLARE statement. A declaration element is the text for declaring one identifier
(or one factored list of identifiers). In the example above, the text
CHR BYTE INITIAL ('A') is one declaration element, and the text
COUNT INTEGER is another.

Another way of combining declaration elements is called a factored declaration.


For example:

DECLARE A BYTE, B BYTE;


DECLARE C WORD, D WORD;
DECLARE E DWORD, F DWORD;
can be combined as

DECLARE (A,B) BYTE, (C,D) WORD, (ElF) DWORD;


In each factored declaration, the allocated locations will be contiguous; elements
declared in a non-factored declaration statement may not be.

Variables declared in a "factored" declaration that are not based, and not used as
parameters-that is, variables within a parenthesized list-are stored contiguously in
the order specified. (If a based variable occurs in a parenthesized list, it is ignored
when storage is allocated.)

The declaration elements appearing in a single DECLARE statement are completely


independent of each other, as if they were declared in separate DECLARE
statements.

3-3
Data Declarations, Types, and Based Variables PL/M-86 User's Guide

3.2 Initializations
Initialization is necessary for every constant and variable name that is used (read)
before it is filled (written) during execution since there are no default values. Either
kind of name can, of course, be initialized by an assignment statement such as:
PI = 3.1415927; /' PI must first be declared REAL. '/
VAR13 = 10; /' VAR13 must be declared earlier, not real. 1/

However, the PL/M-86 language provides a means for having the compiler set up
these values during the compilation rather than using both instruction space and
execution time in your program to do so.

There are two kinds of compile-time initializations: INITIAL, used with variables,
and DATA, used for constants. (DATA is explained in greater detail later in this
section.) In each case, the initialization attribute is placed after the type in the
declaration. For example:
DECLARE FAMILY WORD INITIAL (2);
INITIAL causes initialization to occur during program loading for variables that
have storage allocated for them. Such variables can subsequently be changed during
execution, like any other variable. (They will not be reinitialized on a program restart.)

The following rules apply to both INITIAL and DATA:


• INITIAL and DATA may not be used together in the same declaration.
• INITIAL may only appear in declarations at the outer level of a module. DATA,
however, may appear in declarations at any level.
• No initializations are permitted with based variables (discussed in section 3.5),
formal parameters (discussed in section 8.1) or with the EXTERNAL attribute
(discussed in section 7.2).
• Either initialization may follow use of the AT attribute (discussed in section 3.6),
but if this causes multiple initializations, the result cannot be predicted.

The general form of the INITIAL attribute is:

I NIT I AL (value-list)

where
value-list is a sequence of values separated by commas.

Values are taken one at a time from the value list and used to initialize the individual
scalars being declared. The initialization is performed in the same manner as an
assignment. Initial values for members of an array or structure must be specified
explicitly. (See also section 9.4 for built-in procedures you can use to initialize BYTE
and WORD strings at run-time.)

Each value may be a string of up to four characters (e.g., 'A', 'NO'), or a


restricted expression, as explained below. (Byte arrays can accommodate longer strings
since each element can represent one character.)

A restricted expression is one of the following three possibilities:


• For REAL variables only: a single floating-point constant, with no operator of
any kind, to be used only to initialize a REAL scalar.
• For POINTER variables only: a location reference formed with the @ operator,
which must refer to a variable that has already been declared. (Location
references are discussed in section 3.4.)

3-4
PL/M-86 User's Guide Data Declarations, TYIk->S, and Based Variables

• For all other types: a constant expression containing no operators except + or -.


A constant expression has only whole-number constants as operands, e.g.,
2048-256+5, as explained in Chapter 4. The expression is evaluated as if it
were being assigned to the scalar being initialized, using the rules of that chapter.

NOTE
For compatibility with programs written in PLjM-80, PLjM-86 allows the
restricted expression to be an expression containing a location reference
formed with the '~dot" operator.

The declaration:

DECLARE THRESHOLD BYTE -INITIAL (48);


declares the BYTE scalar THRESHOLD in the usual way, and also initializes it to
a value of 48.

The declaration:

DECLARE EVEN (S) BYTE INITIAL (2, 4, 6, 8, 10);


declares the BYTE array EVEN and initializes its five scalar elements to 2, 4, 6, 8,
and 10, respectively.

The declaration:

DECLARE COORD STRUCTURE (HIGH$BOUND WORD,


VALUE (3) BYTE,
LOW$BOUND BY1E) INITIAL (302, 3, 6, 12, 0);
declares the structure COORD and initializes it as follows:

COORD.HIGH$BOUND to 302
COORD.VALUE(O) to 3
COORD.VALUE(1) to 6
COORD.VALUE(2) to 12
COORD.LOW$BOUND to o
If a string appears in the value list, it is taken apart from left to right and the pieces
are stored in the scalars being initialized. One character is stored in each BYTE
scalar, two in each WORD scalar, and four in each DWORD scalar. For example:

DECLARE GREETING (5) BYTE AT (,HI) INITIAL ('HELLO');


causes GREETING(O) to be initialized with the ASCII code for H, GREETING(l)
with the ASCII code for E, and so on.

So far, all the examples have shown value lists that match up one-for-one with the
scalars being declared. It is permissible for the value list to have fewer elements than
are being declared. Thus:

DECLARE DATUM (100) BYTE INITIAL (3, S, 7, 8);


is permissible. The first four elements of the array DATUM are initialized with the
four elements in the value list, and the remainder of the array is left uninitialized.
However, the value list may not have more elements than are being declared.

3-5
Data Declaratio~ Types, and Based Variables PL/M-86 User's Guide

The Implicit Dimension Specifier


Often, when you initialize an array, you want the array to have the same number of
elements as the value list. This can be done conveniently by using the
implicit dimension specifier in place of an ordinary dimension specifier (a parenthe-
sized constant). The implicit dimension specifier has the form:
( it )

This may also be used to define an external array whose precise number of elements
is either unknown or insignificant. Thus the declaration:

DECLARE FAREWELL (f) BYTE PUBLIC INITIAL ('GOODBYE, NOW')j


declares a public BYTE array, FAREWELL, with enough elements to contain the
string 'GOODBYE, NOW' (namely 12), and initializes the array elements with th~
characters of the string. To reference this array in another program module, you can
declare it as follows:

DECLARE FAREWELL (I> BYTE EXTERNAL;


(See Chapter 7 for more information about PUBLIC and EXTERNAL attributes.)
Note that the INITIAL and DATA value-lists must not be present when the implicit
dimension specifier is used with an external array; otherwise, INITIAL and DATA
value-lists are required. Also, the LENGTH, LAST, and SIZE built-ins (see
section 9.1) may not be used on an external array that was declared with the implicit
dimension specifier.

The implicit dimension specifier may not be used in the following cases:
• After the parenthesized list of identifiers in a factored declaration.
• To specify an array whose elements are structures.
• To specify an array that is a member of a structure.

The implicit dimension specifier may be used with any value list-it is not restricted
to strings.

Names for Execution Constants: The Use of DATA


As discussed above, a variable is the name of a single data item intended to be used
and altered by your program. If it isn't altered during execution, it's a constant.

For example, the formula for the circumference of a circle as the product of its radius
and two pi could be written in PL/M-86 as:

C • R • 2.0 I 3,14159;
in which C and R would be variables. Their declarations would of course have to
precede the above executable statement, and could appear as:

DECLARE (C, R) REAL;


If pi were used often enough, you might wish to simplify the writing of statements
using it to declare a symbolic name with that value:

DECLARE PI REAL DATA (3.1415927);

3-6
PL/M-86 User's Guide Data Declarations,Types, and Based Variables

An array of constants would require a list of values, for example:

DECLARE FIBONACCI(S) BYTE DATA (0,1,1,2,3,5,8,13,21);


The form and use of the DATA initialization is identical to that of INITIAL except
for these four differences:
• DATA causes storage to be allocated in the program's constant data segment.
The content and meaning of the name cannot be changed during execution. The
name should never appear on the left-hand side of an assignment statement. (This
is not the case with INITIAL.)
• Data initializations can be used in declarations at any block level in the program.
(INITIAL can only appear at the module level, that is, inside the DO-block that
is the module itself, but outside any sub-blocks that the module may contain.)
• If the keyword DATA is used in a PUBLIC declaration when compiling with the
ROM option (see section 11.4), DATA must also be used in the EXTERNAL
declaration of program modules that reference it. However, no value list is then
permitted since the data is defined elsewhere. (INITIAL cannot be combined
with EXTERNAL.)
• Use of the AT attribute, as explained in section 3.6. This attribute forces a name
to be associated with a specific memory location, which can defeat the purpose
of the DATA initialization. (This will not happen with INITIAL unless you
explicitly redefine your own variables and location using multiple AT's.)

3.3 Types of Declaration Statements

Compilation Constants (Text Substitution): The Use of LITERALLY

If your program were large enough to have many declarations, you might choose to
declare a compilation constant to save time at the keyboard:

DECLARE DC LITERALLY 'DECLARE';


Thereafter, during compilation, every time DC appears alone (not as part of a word),
the full string DECLARE will be substituted by the compiler. Subsequent
declarations can thus be written:

DC AREA REAL;
DC SIZE WORD;
A declaration using the reserved word LITERALLY defines a parameterless "macro"
for expansion at compile-time. You declare an identifier to represent a character string,
which will then be substituted for each occurrence of the identifier in subsequent text.
This expansion will not take place in strings or constants. The form of the
declaration is:

DEC LARE identifier LIT ERA LLY \ string' ;

where
identifier is any valid PL/M-86 identifier.
string is a sequence of arbitrary characters from the PL/M-86 set,
not exceeding 255 in length.

3-7
Data Declarations, Types, and Based Variables PL/M-86 User's Guide

The following example illustrates another use of this facility:

DECLARE TRUE LITERALLY 'OFFH', FALSE LITERALLY '0';


DECLARE ROUGH BYTE;
DECLARE ex, Y, DELTA, FINAL) REAL;

ROUGH • TRUE;
DO WHILE ROUGH;
X • SMOOTH ex, Y, DELTA);
/* SMOOTH is a procedure declared elsewhere. */
IF eX-FINAL) ( DELTA THEN ROUGH = FALSE;
END;

This example of a LITERALLY declaration defines the boolean values TRUE and
FALSE in a manner consistent with the way PL/M-86 handles relational operators
(see section 4.3). This kind of literal substitution for fixed values often makes a
program more readable.

Another use of the LITERALLY declaration is the declaration of quantities that are
fixed for one compilation, but are subject to change from one compilation to the next.
Consider the example below:

DECLARE BUFFERSSIZE LITERALLY '32';


DECLARE PRINTSBUFFEReBUFFERSSIZE) WORD;

PRINTSBUFFERCBUFFERSSIZE - 10) • 'G';

A future change to BUFFER$SIZE can be made in one place, at the first declara-
tion, and the compiler will propagate it throughout the program during compilation.
Thus, the programmer is saved the tedious and error-prone process of searching the
program for the occurrences of ~'32" that are buffersize references and not 32's that
are used in other contexts.

Declarations for Names of Labels

A label marks the location of an instruction as opposed to a data item. Labels are
permitted only on executable statements, not on declarations.

There are two ways to declare a name as a label. Explicit label declarations are used
mainly to allow for module-to-module references, which are discussed in detail in
Chapter 9. The three possible forms for explicit label declarations look like this:

DECLARE PART3 LABEL:


DECLARE START1 LABEL PUBLICj ,- for intermodule reference -,
DECLARE PHASE2 LABEL EXTERHALj ,- for intermodule reference -,

The rules for the latter two are discussed in Chapter 9.

The more common label declaration, implicit, is even simpler: the name is placed at
the very beginning of the executable statement it is supposed to point to. For example:

START2: ALPHA • 127;

3-8
PL/M-86 User's Guide Data Declarations, Types, and Based Variables

This statement defines the label START2 as pointing to the location of the
PL/M-86 instruction shown. If this block has no explicit declaration of START2,
i.e., no statement like:

DECLARE START2 LABEL;


then the compiler takes the definition of START2 as an implicit declaration as well
as a definition. It is as if the declaration had occurred at the start of the last simple
DO or procedure -statement. (If there is an explicit declaration, then the actual
placement of the label remains simply a definition.)

Labels are used to indicate significant instructions or the starting point of instruction
sequences. Labels can be useful reference points for understanding the parts of a
program, or targets for the transfer of control during execution (as discussed under
GOTO and CALL in Chapters 7 and 8).

Results
The results of a valid label declaration are:
l. The declared name can be used to point to an executable instruction.
2. The use of the declared name as a variable in its block is disallowed.
3. If the label is also defined in its block by appearing in an executable statement,
then the address of that statement is assigned as the value of the label.

Declaration for Procedures

As illustrated earlier, the declaration of a procedure begins by giving its name, with
a statement of the form:

name: PROCEDURE
followed optionally by parameters, type and/or attributes. The definition of the
procedure then follows, i.e., the set of statements declaring items used in the proce-
dure (including any parameters) and the executable statements of the procedure itself.
The definition ends with an END statement, optionally including the procedure name
from the declaration.

The complete declaration of a procedure includes all the statements from the
PROCEDURE statements through the END statement. This whole
definition/declaration must appear before the procedure name is used in an execut-
able statement, just as variable and constant names must be declared before their
use.

The only exceptions arise when the full definition appears in another module where
it is declared PUBLIC, or when a procedure has been declared REENTRANT. In
the first case, if a separate module intends to make use of that public definition, it is
required to:
1. Decla the procedure a aving the EXTERNAL attribute (so the Linker will
se h for it).
2. eclare each formal parameter he procedure uses so the compiler can verify
~_____________/,,/ correct usage when this module in okes the procedure.

3. End this local declaration with an END statement.

3-9
Data Declarations, Types, and Based Variables PL/M-86 User's Guide

For example:

SUMMER: PROCEDURE (A, B) EXTERNAL;


-DECLARE A WORD, B BYTE;
END SUMMER;
The full details for intermodule references appear in Chapter 7, and the discussion of
procedure definition and usage appears in Chapter 8.

3.4 Data Types


The concept of data types applies not only to variables, but to every value processed
by a PL/M-86 program. This includes values returned by procedures and values
calculated by processing expressions.

PL/M-86 performs calculations using three different kinds of arithmetic: unsigned,


signed, or floating-point, depending on the data types involved.

Arithmetic and other expressions using the different types are discussed in detail in
Chapter 4.

BYTE, WORD, and DWORD Varibles: Unsigned Arithmetic

The value of a BYTE variable is an 8-bit binary number ranging from 0 to 255 and
occupying one byte of iAPX 86 memory (two bytes when passed as a parameter on
the stack, see Appendix F). The value of a WORD variable is a 16-bit binary number
ranging from 0 to 65535 and occupying two contiguous bytes of iAPX 86 memory
(the least significant 8 bits are stored in the lower address). The value of a DWORD
variable is a 32-bit binary number ranging from 0 to 4,294,967,295 and occupying
two contiguous words of iAPX 86 memory (the least significant 16 bits are stored in
the lower address). Values of DWORD, WORD, and BYTE variables are treated as
unsigned binary integers.

NOTE
Support for *, /, and MOD operations on DWORD is located in the
PLM86.LIB support library. You must link to this library before executing
any program that performs these operations on DWORD types. (The
DWORD routines in this library form only one segment: a code segment
called LQYLM86_LIB_CODE. Since this is read-only code, it may be
burned into ROM.)

Unsigned integer arithmetic is used to perform any arithmetic operation on DWORD,


WORD, and BYTE variables. All of the PL/M-86 operators may be used with them
(see Chapter 4). Arithmetic and logical operations on such variables yield a result of
type BYTE, WORD, or DWORD, depending on the operation and the operands.
Relational operations always yield a "true" or "false" result of type BYTE.

With unsigned arithmetic, if a large value is subtracted from a smaller one, the result
is the two's complement of the absolute difference between the two values. For
example, if a BYTE value of 1 (00000001 binary) is subtracted from a BYTE value
of 0 (00000000 binary), the result is a BYTE value of 255 (11111111 binary).

Also, the result of a division operation is always truncated (rounded down) to a whole
number. For example, if a WORD value of 7 (0000000000000111 binary) is divided
by a BYTE value of 2 (00000010 binary), the result is a WORD value of 3
(00000000000000 11 binary).

3-10
PL/M-86 User's Guide Data Declarations, Types, and Based Variables

When declaring a variable that may be used to hold or produce a negative result, it
is advisable to make it either INTEGER or REAL. If it is supposed to hold or produce
a non-integer, it must be REAL. Making use of the appropriate data types can help
avoid unexpected incorrect results from arithmetic operations (see Chapter 4).

INTEGER Variables: Signed Arithmetic

INTEGER variables represent 16-bit signed integers ranging from - 32768 to


+ 32767 and occupying two contiguous bytes of iAPX 86 memory (the least
significant 8 bits are stored in the lower address). Internally, an INTEGER value is
represented in two's complement notation with the following format:

MAGNITUDE

15 14 o

The sign bit is 0 if the INTEGER value is positive or zero, and I if the value is
negative. The magnitude is given in two's complement notation.

Arithmetic operations on INTEGER variables use signed integer arithmetic to hold


an INTEGER result. Thus, addition and subtraction always produce mathematically
correct results if overflow does not occur. (See also the OVERFLOW control in section
11.3.) Relational operations are signed arithmetic comparisons that yield a "true" or
"false" result of type BYTE.

However, as with BYTE, WORD, and DWORD operands, division produces only an
INTEGER result. The result is rounded toward zero, i.e., down if it is positive, up if
it is negative.

Only the arithmetic and relational operators may be used with INTEGER operands.
Logical operators are not allowed (see Chapter 4).

REAL Variables: Floating-Point Arithmetic

The value of a REAL variable is a signed floating-point number that occupies four
contiguous bytes of iAPX 86 memory, which may be viewed as 32 contiguous bits in
the short-real format. The bits are divided into fields as follows:

I I
31
SIGN

30
EXPONENT I
23 22
S1GNIFICAND

The byte with the lowest address contains the least significant 8 bits of the
significand, and the byte with the highest address contains the sign bit and the most
significant 7 bits of the exponent field.

The sign bit is 0 if the REAL value is positive or zero, and I if the REAL value is
negative.

The exponent field contains a value "offset" by 127-in other words, the actual
exponent can be obtained from the exponent field value by subtracting 127. This field
is all O's if the REAL value is zero.

The significand contains the binary digits of the fractional part of the REAL value
when this part is represented in "binary scientific" notation (see below). This field is
all 0' s if the REAL value is zero.

3-11
Data Declarations, Types, and Based Variables PL/M~ User~s Guide

Operations on REAL operands use signed floating-point arithmetic to yield a result


of type REAL. The implementation guarantees that the result of each operation is
the closest possible floating-point number to the exact mathematical real-number result
(if overflow or underflow does not occur). The relational operators and the arithmetic
operators +, -, *, and / may be used with REAL operands: the MOD operator and
the logical operators are not allowed. Arithmetic operations yield a result of type
REAL, and relational operations yield a "true" or "false" result of type BYTE.

The utility of the REAL data type is extended by the PL/M-86 compiler's practice
of holding intermediate results in the 8087's temporary-real format. This format
preserves 64 bits of precision and the full range of representable numbers. The
exponent in this format is 15 bits instead of 8 in the short-real format.

This greater range of exponent greatly reduces the likelihood of underflow and
overflow, and eliminates roundoff as a source of error until the final assignment of
the result is performed. These advantages arise because" underflow, overflow, and
roundoff errors are more probable for intermediate computations than for the final
result. For example, an intermediate underflow result might later be multiplied by a
very large factor, providing a final result of acceptable magnitude.

Examples of Binary Scientific Notation

1. Consider the following binary number (which is equivalent to the decimal


value 10.25):
1010.01B
The "." in this number is a binary point. The same number can be represented
as:
1.0100lB * 23
This is "binary scientific" notation, with the binary point immediately to the
right of the most significant digit. The digits 0 I 00 1 are the fractional part, and
3 is the exponent. This value would be represented as follows:
• The sign bit would be 0, since the value is positive.
• The exponent field would contain the binary equivalent of 127 + 3 = 130.
• The leftmost digits of the fraction field would be 01001, and the remainder
of this field would be all O's.
The complete 32-bit representation would be
o 10000010 01001000000000000000000
and the contents of the four contiguous memory bytes would be as follows:
highest address: 0 I 00000 1
00100100
00000000
lowest address: 00000000
Note that the most significant digit is not actually represented, since by
definition it is a "1" unless the REAL value is zero. If the REAL value is
zero, the entire 32-bit representation is all O's.

2. Consider the fraction 1/16, or 0.0625. In binary, it is


1.0000B * 2-4
The actual exponent, - 4, would be repre~ented as 123 (127 - 4), and the fraction
field would contain all O's.

3-12
PL/M-86 User's Guide Data Declarations, Ty~ and Based Variables

The largest possible value for a valid exponent field is 254, which corresponds to
an actual exponent of 127. The largest possible absolute value for a positive or
negative REAL value is therefore
1.1111111111111111111111IB * 2127
or approximately 3.37 * 1038•
The lowest permissible exponent field value for a non-zero REAL value is I,
which corresponds to an actual exponent of -126. The smallest possible absolute
value for a positive or negative REAL value is therefore
1.0B * 2- 126
or approximately 1.17 * 10-38 •

POINTER Variables and Location References


The value of a PO INTER variable is the address of an iAPX 86 storage location and
is made up of a base selector portion and an offset portion. The bits are divided as
follows:

SELECTOR OFFSET

31 1615 o

Among other uses, POINTER variables are important as bases for based variables
(see section 3.5).

Only the relational operators may be used with POINTER operands, yielding a ~~true"
or "false" result of type BYTE. No arithm", ..ic or logical operations are allowed (see
Chapter 4).

There are only a few ways to create or change the value of a POINTER variable,
that is, the address that the variable points to:
I. The variable can be initialized when declared, using INITIAL or DATA with an
address created with a whole-number constant as described in section 3.2.
2. The variable can be assigned a whole-number constant as described in
Chapter 4.
3. The variable can be assigned an address created via the @ operator (described
below). This is the safest and most commonly used method.
4. The variable can be assigned the value of a POINTER variable or function.
5. The variable can be assigned a value generated by the BUILD$PTR or NIL
functions (described in section 9.6).

.
The @ Operator
A '~location reference" is formed by using the @ operator. A location reference has a
value of type POINTER-that is, a location address. An important use of location
references is to suPI'IY values for POINTER variables.

The basic form of a location reference is:

• variable-ref

where
variable-ref is the name of some variable.

The value of this location reference is the actual run-time location of the variable.

3-13
Data Declarations, Types, and Based Variables PL/M·86 User's Guide

The variable.refmay also refer to an unqualified array or structure name. The pointer
value is the location of the first element or member of the array or structure.

For example, suppose that we have the following declarations:

DECLARE RESULT REAL;


DECLARE XNUM(100) BYTE;
DECLARE RECORD STRUCTURE (K~Y BYTE,
INFO(2S) BYTE,
HEAD POINTER);
DECLARE LIST(128) STRUCTURE (KEY BYTE,
INFO(2S) BYTE,
HEAD POINTER);
The @RESULT is the location of the REAL scalar RESULT, while @XNUM(5) is
the location of the 6th element of the array XNUM. @XNUM is the location of the
beginning of the array, that is, the location of the first element (element 0).

The RECORD structure declares a byte called KEY followed by 25 bytes called
INFO(O), INFO(l), and so on, followed by the POINTER variable named HEAD.
Since KEY, INFO, and. HEAD are all declared part of the RECORD structure,
their contents must be referred to as RECORD. KEY, RECORD.lNFO(O),
... , RECORD.INFO(24), and RECORD.HEAD.

The addresses of these elements of the RECORD structure can be referred to using
the @ operator. @RECORD.HEAD is the location of the POINTER scalar
RECORD. HEAD, while @RECORD is the location of the structure, which is the
same as that of the BYTE scalar RECORD. KEY. @RECORD.INFO is the location
of the first element of the 25-byte array RECORD. INFO, whereas
@RECORD.lNFO(7) is the location of the 8th element of the same array.

LIST is an array of structures. The location reference @LIST(5).KEY is the location


of the scalar LIST(5).KEY. Note that @LIST.KEY is illegal since it does not identify
a unique location, i.e., the KEY of which LIST.

The location reference @LIST(0).INFO(6) is the location of the scalar


LIST(O).INFO(6). Also, @LIST(O).INFO is the location of the first element of the
same array, i.e., the location of the array itself.

A special case exists when the identifier used as "variable-ref" is the name of a proce-
dure. The procedure must be declared at the outer level of the program module. No
actual parameters may be given (even if the procedure declaration includes formal
parameters). The value of the location reference in this case is the location of the
entry point of the procedure. (Further discussion of procedures appears in Chapter 8
and Appendixes F and G.)

Storing Strings and Constants via Location References. Another form of location
reference is:

• ( constant list>

where
constant list is a sequence of one or more constants separated by commas
and enclosed by parentheses.

When this type of location reference is made, space is allocated for the constants, the
constants are stored in this space (contiguously, in the order given by the list), and
the value of the location reference is the location of the first constant.

3-14
PLjM-S6 User's Guide Data DeclaratioM, Types, and Based Variables

Strings may be included in the list. For example, if the operand:

,('NEXT VALUE')
appears in an expression, it causes the string 'NEXT VALUE' to be stored in memory
(one character per byte, thus occupying 10 contiguous bytes of storage). The value
of the operand is the location of the first of these bytes-in other words, a pointer to
the string.

The "DOT" Operator


For compatibility with PL/M-80 programs, a "dot" operator is provided. The dot
operator (.) is similar to the @ operator, but produces an address of type WORD that
represents an offset to the current data segment (for variables) or to the current code
segment (for procedures). This address should be used with caution, since it will not
always produce correct results in a PL/M-86 program that contains more than one
data segment or more than one code segment. See section 3.5 for indirect variable
references and section 8.2 for indirect procedure calling.

SELECTOR Variables

The value of a SELECTOR variable is equivalent to the base portion of a POINTER,


and may also be used as the base of a based variable (see section 3.5). The bits are
divided as follows:

SELECTOR

31 16

Only the relational operators may be used with SELECTOR operands, yielding a
"true" or "false" result of type BYTE. No arithmetic or logical operations are allowed
(see Chapter 4).

There are only three ways to create or change the value of a SELECTOR variable:
1. The variable can be initialized when declared, using INITIAL or DATA with a
whole-number constant as described in section 3.2.
2. It can be assigned a whole-number constant as described in Chapter 4.
3. It can be assigned a SELECTOR variable or function, or the build-in function
SELECTOR$OF (see section 9.7).

The results of the @ and dot operators may not be assigned to SELECTOR variables
directly. They must first be converted to SELECTOR type with the built-in function
SELECTOR$OF (see section 9.7).

3.5 Based Variables


Sometimes a direct reference to a PL/M-86 data element is either impossible or
inconvenient. This happens, for example, when the location of a data element must
remain unknown until it is computed at run time. In such cases, it may be necessary
to write PL/M-86 code to manipulate the locations of data elements themselves.

To permit this type of manipulation, PL/M-86 uses ~'based variables." A based


variable is one that is pointed to by another variable called its "base." This means
the base contains the address of the desired (based) variable.

3-15
Data Declantions, Types, and Based Variables PL/M-86 User's Guide

A based variable is not allocated storage by the compiler. At different times during
the program run it may actually refer to different places in memory, since its base
may be changed by the program.

A based variable is declared by first declaring its base, which must be of type
POINTER, SELECTOR, or WORD, and then declaring the based variable itself:

DECLARE I BYTE;
DECLARE ITEM$PTR POINTER;
DECLARE ITEM BASED ITEM$PTR BYTE;

Given these declarations, a reference to ITEM is, in effect, a reference to whatever


BYTE value is pointed to by the current value of ITEM$PTR. This means that the
sequence:

ITEM$PTR • ,I;
ITEM • 77Hj

will load the BYTE value of 77 (hex) into the variable I.

A variable is made BASED by inserting in its declaration the word BASED and the
identifier of the base (which must already have been declared).

The following restrictions apply to bases:


• The base must be of type POINTER, SELECTOR, or WORD. However, use a
base of type WORD with caution since it does not contain a full iAPX 86 address.
WORD-based variables are addressed relative to the current DS register (see
section 11.3).
• The base may not be subscripted-that is, it may not be an array element.
• The base may not itself be a based variable.

The word BASED must immediately follow the name of the based variable in its
declaration, as in the following examples:

DECLARE (AGESPTR, INCOMESPTR, RATINGSPTR, CATEGORYSPTR)


POINTERj
DECLARE AGE BASED AGESPTR BYTE;
DECLARE (INCOME BASED INCOMESPTR, RATING BASED RATIHGSPTR)
WORD;
DECLARE (CATEGORY BASED CATEGORYSPTR)(100) WORDj

In the first DECLARE statement, the POINTER variables AGE$PTR,


INCOME$PTR, RATING$PTR, and CATEGORY$PTR are declared. They are
used as bases in the next three DECLARE statements.

In the second DECLARE statement, a BYTE variable called AGE is declared. The
declaration implies that whenever AGE is referenced by the running program, its
value will be found at the location given by the value of the POINTER variable
AGE$PTR at the same time.

The third DECLARE statement declares two based variables, both of type WORD.

The fourth DECLARE statement defines a lOO-element WORD array called


CATEGOR Y, based at CATEGORY$PTR. This means that when any element of
CATEGORY is referenced at run time, the value of CATEGORY$PTR at that same
time is the location of the array CATEGORY, i.e., its first element.

3-16
PL/M-86 User's Guide Data Declarations, Types, and Based Variables

The other elements follow contiguously. The parentheses around the tokens
CATEGORY BASED CATEGOR YSPTR are optional. They help to make the
statement more readable, but may be omitted.

Location References and Based Variables


An important use of location references is to supply values for bases. Thus, the @
operator, together with the based variable concept, gives PL/M-86 a very powerful
facility for manipulating pointers.

For example, suppose that we have three different REAL variables:


NORTHSERROR, EASTSERROR, and HEIGHTSERROR. We want to be able
to refer to them at different times by means of the single identifier ERROR. This
can be done as follows:

DECLARE (HORTHtERROR, EASTSERROR, HEIGHTSERROR) REALj


DECLARE ERRORSPTR POINTER;
DECLARE ERROR BASED ERRORSPTR REAL;
ERRORSPTR = ,NORTHSERRORj
At this point, the value of ERRORSPTR is the location of NORTHSERROR. A
reference to ERROR will, in effect, be a reference to NOR THSERROR. Later in
the program, we can write:

ERRORSPTR • ,HEIGHTSERROR;
Now a reference to ERROR will, in effect, be a reference to HEIGHTS ERROR. In
the same way, we can cause the value of the pointer to be the location of
EASTSERROR, and a reference to ERROR will be a reference to EASTSERROR.

This technique is useful for manipulating complicated data structures and for passing
locations to procedures as parameters. Examples are given in Chapter 8.

3.6 The AT AHribute


The AT attribute has the form:

A T ( location)

where
location must be a location reference formed with the @ operator, or
a single whole-number constant in the range 0 to 1,048,575.

It must refer to a non-based variable that has already been declared. If there is a
SUbscript expression, it must be a constant expression containing no operators except
+ and-.
The following are examples of valid AT attributes:

AT (4096)
AT (,BUFFER)
AT (,BUFFER(128»
AT (,HAMESCIHDEX + 1»

3-17
Data Declarations, Types, and Based Variables PL/M-86 User's Guide

In the last example, INDEX represents a whole-number constant that has been previ-
ously declared with a "LITERALLY" declaration. The compiler replaces this name
with the declared whole-number constant, thus satisfying the restrictions given above.

NOTE
For compatibility with programs written in PLfM-80, PLfM-86 allows the
location in an AT attribute to be an expression containing a location refer-
ence formed with the "dot" operator. (See Appendix D.)

The affect of an AT attribute is to cause the address of a variable to be the location


specified by location. The first non-based variable in a factored declaration will have
the address specified by location. Other variables in the same declaration will, in
sequence, refer to successive locations thereafter.

For example, the declaration:

DECLARE (CHARtA, CHARSB, CHARSC) BYTE AT (,BUFFER);


causes the BYTE variable CHAR$A to refer to the location of BUFFER. The varia-
bles CHAR$B and CHAR$C are located in the next two bytes after CHAR$A.

The declaration:

DECLARE T (10) STRUCTURE (X(3) BYTE,


Y(3) BYTE,
Z(3) BYTE) AT (,DATASBUFFER)j
sets up structure references to 90 bytes. They are organized such that each of the ten
members of T refers to 9 bytes-the first three use the name X, the second three Y,
and the last three Z. Figure 3-1 may help you visualize this structure.

The declaration above, using the AT attribute, causes the beginning of the structure
T-namely the scalar T(O).X(O)-to be located at the same location as a previously
declared variable called DATA$BUFFER. The other scalars making up the structure
will follow this location in logical order: T(O).X(l), T(0).X(2), and so on up to
T(9).Z(2), the last scalar, which is located in the 89th byte after the location of
DATA$BUFFER.

However, no memory locations for these 90 scalars are allocated by this declaration.
It is up to the programmer to know what else, if anything, will be stored in the memory
space starting at @DATA$BUFFER.

T(O).X(O)
T(O).X(1)
T(O).X(2)
T(O).Y(O)
T(O).Y(1)
T(O).Y(2)
T(O).Z(O)
T(O).Z(1)
T(O).Z(2)
T(1).X(O)
T(1).X(1)
T(1).X(2)
T(1).Y(O)
T(1).Y(1)
ANDSOON

Figure 3-1. Successive Byte References of a Structure 121636-29

3-18
PL/M-86'User's Guide Data Declarations, Types, and Based Variables

The following rules apply to the AT attribute:


• It cannot be used with variables that are baseq, EXTERNAL, or parameters.
• It can be used with the PUBLIC attribute, in which case it must immediately
follow the word PUBLIC. However, the location in this case may not be a location
reference to a variable that is EXTERNAL.

The AT attribute can be used to make variables "equivalent," providing more than
one way of referring to the same information. For example:

DECLARE DATUM WORD;


DECLARE ITEM BYTE AT <,DATUM);

causes ITEM to be declared a BYTE variable at the same location that has just been
allocated for the WORD variable DATUM. The result is that any reference to ITEM
is, in effect, a reference to the low-order byte of DATUM (because WORD values
are stored with the low-order 8 bits preceding the high-order 8 bits).

The following is another example using the A T attribute:

DECLARE VECTOR (6) BYTE;


DECLARE SHORT$VECTOR STRUCTURE (FIRST (3) BYTE,
SECOND (3) BYTE)
AT (,VECTOR);
Here we first declare a six-element BYTE array, VECTOR. Then we declare a
structure of two three-BYTE arrays, SHORT$VECTOR.FIRST and
SHORT$VECTOR.SECOND.

The first scalar of this structure-SHORT$VECTOR.FIRST(O)-is located at the


same location as the first element of the array VECTOR.

Thus, we have two different ways of referring to the same six bytes. For example, the
fifth byte in the group can be referenced as either VECTOR( 4) or
SHORT$VECTOR.SECOND(l ).

When a variable is declared with the AT attribute, the PL/M-86 Compiler does not
optimize the machine code generated to access that variable except under
OPTIMIZE(3).

3-19
CHAPTER 4
EXPRESSIONS AND ASSIGNMENTS

A PL/M-86 expression consists of scalar operands (values) combined by means of


the various arithmetic, logical, and relational operators. Examples are:

A+B
A+B-C
A*B + C/D
A*(B + C) - (D - E)/F

where +, -, *, and / are arithmetic operators for addition, subtraction, multiplica-


tion, and division, and A, B, C, D, E, and F represent operands. The parentheses
serve to group operands and operators, as in ordinary algebra.

This chapter presents a complete discussion of the rules governing PL/M-86 expres-
sions. Although these rules may appear complex, bear in mind that most of the
expressions used in actual programs are simple and easy to understand. In particular,
when the operands of arithmetic and relational operators are all of the same type,
the resulting expression is easy to understand.

4. 1 Operands
Operands are the building blocks of expressions. An operand is something with a
value at run time that can be operated upon by an operator. Thus, in the examples
above, A, B, C, etc., might be the identifiers of scalar variables which have values at
run time.

Numeric constants and fully qualified variable references may appear as operands in
expressions. The following sections describe all of the types of operands that are
permitted.

Constants

Any numeric constant may be used as an operand in an expression. Its type must be
appropriate, as discussed below.

A numeric constant that contains a decimal point is of type REAL. A numeric


constant that does not contain a decimal point is called a whole-number constant.

A whole-number constant may be found in either signed context or unsigned context


(see section 4.6). In signed context a whole-number constant is treated as an
INTEGER value.

In unsigned context, a whole-number constant is treated as a BYTE value if it is


equal to or less than 255, as a WORD value if it is greater than 255 and equal to or
less than 65,535, and as a DWORD value if it is greater thari 65,535 and equal to or
less than 4,294,967,295. A single whole-number constant may also be treated as a
POINTER or SELECTOR value (see Chapter 3).

A string constant containing not more than four characters may also be used as an
operand. If it has only one character, it is treated as a BYTE constant whose value is
the eight-bit ASCII code for the character. If it is a two-character string, it is treated

4-1
ExpressioDS and Assignments PL/M-86 User's Guide

as a WORD constant whose value is formed by stringing together the ASCII codes
for the two characters, with the code for the first character forming the most
significant eight bits of the sixteen-bit number.

If it is a three- or four-character string, it is treated as a DWORD constant whose


value is formed by stringing together the ASCII codes for all of the characters. In a
three-character string, the most significant 16 bits of the 32-bit number are formed
of 8 high-order zeroes, then the code for the first character. In a four-character string,
the code for the first two characters forms the most significant 16 bits of the number.

Strings of more than four characters are called string constants. They are illegal. as
operands in expressions, and may appear in only two contexts: as initialization values
for an array or as part of a location reference that points to where the string constant
is stored (see Chapter 3).

Variable and Location References

As we have seen, a fully qualified variable reference refers unambiguously to a single


scalar value. (Partially qualified references, discussed in Chapter 5, have very
restricted uses). Any fully qualified variable reference may be used as an operand in
an expression. When the expression is evaluated, the reference is replaced by the
value of the scalar.

In addition to the kinds of variable reference described previously, there is another


kind called a "function reference."

A function reference is the name of a "typed procedure" that has previously been
declared, along with any parameters required by the procedure declaration. The value
of a function reference is the value returned by the procedure.

For example, in the statement:

• J + ABS(L)j

the absolute value of L will be returned by the function ABS and then added to the
value of J before being stored in I. If L is - 27, the result is exactly as if you had
written:

• J + 27j

For a complete discussion of procedures and function references, see Chapter 8.

Location references are described in Chapter 3.

Subexpressions
A subexpression is simply an expression enclosed in parentheses. A subexpression
may be used as an operand in an expression. This is the same as saying that paren-
theses may be used to group portions of an expression together, just as in ordinary
algebraic notation.

Compound Operands

All the operand types described above are primary operands. An operand may also
be a value calculated by evaluating some portion of the total expression. For example,
in the expression

4-2
PLJM-86 User's Guide Expressions and Assignments

A + B*C

(where A, B, and C are variable references), the operands of the * operator are B
and C .. The operands of the + operator are A and the compound operand B * C-or
more precisely, the value obtained by evaluating B * C. Notice that this expression
is evaluated as if it had been written

A + (B * C)
This analysis of an expression to determine which operands belong to which
operators, and which groups of operators and operands form compound operands, is
discussed in section 4.5.

4.2 Arithmetic Operators


There are five principal arithmetic operators in PL/M-86 (two others are described
in Chapter 10). The five principal operators are

+-* / MOD
All of these operators are used as in ordinary algebra to combine two operands. Each
operand may have a BYTE, WORD, DWORD, INTEGER, or REAL value (except
that REAL operands are not allowed with the MOD operator). Arithmetic
operations on POINTER and SELECTOR variables are not allowed.

The +, - ,., and / Operators

The operators +, - ,*, and / perform addition, subtraction, multiplication, and division
on operands of any type except POINTER and SELECTOR. The following rules
govern these operations (see also table 4-2).
1. If both operands are of the same type, the result is of the same type as the
operands, with only one exception: if both operands are of type BYTE, the * and
/ operations produce results of type WORD. The type of arithmetic depends on
the type of operands, as discussed in Chapter 3.
2. Only three combinations of mixed operand types are allowed. A BYTE operand
can be combined with a WORD operand, a BYTE operand can be combined
with a DWORD operand, and a WORD operand can be combined with a
DWORD operand. In the first two cases, the BYTE operand is extended by 8
high-order zero bits to produce a WORD value, or by 24 high-order zero bits to
produce a DWORD value. Similarly, a WORD operand is extended by 16 high-
order zero bits to produce a DWORD value. Then the operation is performed as
though both operands are of the same type.
3. If one operand is a whole-number constant, and the other is a DWORD, WORD,
or BYTE operand, the whole-number constant is treated as a BYTE value. if it
is equal to or less than 255, a WORD value if it is greater than 255 and equal to
or less than 65,535, and a DWORD value if it is greater than 65,535. Then the
operation is performed under rule I or rule 2 above. If the whole-number constant
exceeds 4,294,967,295, the operation is invalid.
4. If one operand is a whole-number constant and the other is an INTEGER
operand, the whole-number constant is treated as a positive integer value. Then
the operation is performed as if both operands were INTEGER operands. If the
whole-nurrtber constant exceeds 32,767, the operation is invalid.
5. If one operand is a whole-number constant and the other is of type REAL,
POINTER, or SELECTOR, the operation is invalid.

4-3
Expressions and Assignments PLfM-86 User's Guide

6. If both operands are whole-number constants, the operation depends on the


context in which it occurs, as explained in section 4.6.

The result of division by 0 is undefined, except for REAL values-see Appendix G.

A unary "-" operator is also defined in PL/M-86. It takes a single operand, to


which it is prefixed. In other words, a minus sign that has no operand to the left of it
is taken to be a unary minus.

Its effect is that (- A) is equivalent to (0- A), where A is any operand. The 0 is a
BYTE value if A is of type BYTE, WORD, or DWORD, an INTEGER value if A
is of type INTEGER, or a REAL value if A is of type REAL. If A is a whole-number
constant, its type and the unary "-" operation depend on the context as explained
in section 4.6.

Finally, a unary "+" operator is defined for the sake of completeness. As in ordinary
algebra, a unary" +" has no effect, and ( + A) is exactly equivalent to (A).

The MOD Operator

MOD performs exactly the same as /, except as follows:


• REAL operands are not allowed-only BYTE, WORD, DWORD, and
INTEGER operands can be used.
• The result is not the quotient, but the remainder left after integer division. The
result has the same sign as the operand on the left side of the MOD operator.

For example, if A and B are INTEGER variables with values of 35 and 16, respec-
tively, then A MOD B yields an INTEGER result of 3, and - A MOD B yields - 3.

Unlike the / operator, the MOD operator must be separated from surrounding letters
and digits by blanks or other separators.

4.3 Relational Operators


Relational operators are used to compare operands of the same type. They work with
all types. They are

< less than


> greater than
<= less than or equal to
>= greater than or equal to
<> not equal to
equal to

Relational operators are always binary operators, taking two operands, to yield a
BYTE result, as follows:

If both operands are of the same type, unsigned arithmetic is used to compare two
BYTE values, two WORD values, or two DWORD values; signed arithmetic is used
to compare two INTEGER values or two REAL values; and POINTER or
SELECTOR values are compared for equality or inequality according to the ordering
of iAPX 86 locations.

4-4
PLfM-86 User's Guide Expressions and Assignments

NOTE
If segments are overlapped in your program and you compare POINTER or
SELECTOR values for inequality, the accuracy of your results is not
guaranteed.

As with the arithmetic operators, the only legal mixed combinations of operand types
are BYTE/WORD, BYTE/DWORD, and WORD/DWORD. Whole-number
operands are treated as BYTE, WORD, DWORD, or INTEGER values as explained
in the rules of section 4.2.

If the specified relation between the operands is "true," a BYTE value of OFFH (or
1111$1111B) results. Otherwise, the result is a BYTE value of OOH (or OOOO$OOOOB).
Thus, in all cases, the result is of type BYTE, with all 8 bits set to 1 for a "true"
condition, or to 0 for a "false" condition. For example:

(6)5) result is OFFH ("true")


(6<=4) result is DOH ("false")

Values of "true" and "false" resulting from relational operations are useful in
conjunction with DO WHILE statements and IF statements, as will be seen in Chapter
6. (In the context of a DO WHILE statement or IF statement, only the least signif-
icant bit of a "true" or "false" value is used.)

4.4 Logical Operators


There are 4 logical (boolean) operators in PL/M-86:

NOT AND OR XOR

These operators are used with BYTE, WORD, DWORD, or whole-number constant
operands to perform logical operations on 8, 16, or 32 bits.

NOT is a unary operator, taking one operand only. It produces a result of the same
type as its operand: each bit of the result is the ones complement of the corresponding
bit of the original value.

The remaining operators each take 2 operands, and perform bitwise "and," "or," and
"exclusive or," respectively. The bits of an AND result are 1 only where the corre-
sponding bit in each operand is 1. The bits of an OR result are 1 where the corre-
sponding bit of either operand was a I, and 0 only where both operands have a O.
The bits of an XOR result are 0 only where the corresponding bits of the operand
are the same, i.e., both 1 or both 0; the result has a 1 wherever one operand has a I
and the corresponding bit of the other operand is O.

If both operands are of the same type, the result is the same type as the operands.

As with the arithmetic and relational operators, the only legal mixed combinations
of operand types are BYTE/WORD, BYTE/DWORD, and WORD/DWORD (see
rule 2 under section 4.2). Whole-number operands are treated as BYTE, WORD, or
DWORD values as explained in rule 3 of section 4.2.

Examples are:

NOT 1l.001l00B result is OOllOOllB


10101010B AND IIOOllOOB result is 1000 I OOOB
10101010B OR 11001100B result is III 0 III OB
10101010B XOR 11001100B result isOllOOIlOB

4-5
Expressions and Assignments PL/M-86 User's Guide

Also, notice that "true" and "false" values resulting from relational operations can
be combined meaningfully by means of logical operators.

NOT(6)5) result is OOH ("false")


(6)5) AND (1) 2) result is OOH ("false")
(6)5) OR (1)2) result is OFFH ("true")
(LIM = Y)XOR(Z<2) result is OFFH ("true") if LIM = Y or if Z
<2, but result is OOH ("false") if both
relations are "true" or both "false."

Note that in the statement:

A = (NOT B)

parentheses must be used as indicated. Failure to do so will result in a syntax error.

4.5 Expression Evaluation

Precedence of Operators: Analyzing an Expression

Operators in PLfM-86 have an implied- order (stated below) which determines how
operands and operators are grouped and analyzed during compilation.

The PLfM operators are listed in table 4-1 from highest to lowest precedence, meaning
those which take effect first are listed first. Operators in the same line are of equal
precedence and are evaluated as encountered in a left to right reading of an
expression.

The order of evaluation in an expression is controlled first by parentheses, then by


operator precedence, -and finally by left to right order.

The compiler first evaluates operands and operators enclosed in paired parentheses
as subexpressions, working from innermost to outermost pairs of parentheses. The
value of the sub expression is then used as an operand in the remainder of the
expression.
Table 4-1. Operators' Precedence
Operator
Operator Interpretation
Class

Precedence () -Controls order of evaluation: expressions within


parentheses are evaluated before the action of any
outside operator on the parenthesized items

Unary +,- Single positive operator, single negative operator

Arithmetic ·,/,MOD Multiplication, division, modulo (remainder) division,


+,- addition, subtraction

Relational <,<=,<>,=,>=,> Less than, less than or equal to, not equal to, equals,
greater than or equal to, greater than

Logical NOT Logical negation


AND Logical conjunction
OR,XOR Logical inclusion disjunction,
Logical exclusive disjunction

4-6
PL/M-86 User's Guide Expressions and Assignments

(Parentheses are also used around both subscripts and the parameters of function or
procedure references. These are not subexpressions, but they too must be evaluated
before the remainder of the expressions or references can be evaluated at a higher
level.)

When you have more than one operator in an expression, you can evaluate the results
by beginning with the one having the highest precedence. If the operators are of equal
precedence, evaluate them left to right.

EXAMPLE REASON

(A + B)*C is not the same as


A+B*C Parentheses form subexpressions
A + B * C means the same as
A+(B*C) Operator precedence
A/B*C means the same as
(A/B)*C Left to right, equal precedence

The application of the precedence ranking can also be seen in the following examples:

A + B*C is equivalent to A + (B * C)
A+B-C*D is equalivent to (A + B) - (C * D)
A+B+C+D is equivalent to «A + B) + C) + D
A/B*C/D is equivalent to «A / B) * C) / D
A>B AND NOT B<C-I is equivalent to (A>B) AND(NOT(B«C- 1))

In the last four examples above, we see the application of the ··left-to-right" rule for
operators with the same precedence. In the second, third, and fifth examples, the left-
to-right rule for operators of equal precedence makes no difference in the value of
the expression. But in the fourth example, the left-to-right rule is critical.

A further example will show the action of the rules of precedence on a longer
expression

(- B + SQRT ( B*B - 4.0 * A * C»/(2.0 * A)


We will assume A, B, and C are variables of type REAL, and SQRT is a procedure
of type REAL which returns the square root of the value passed to it as a parameter.

In this case, the parameter is the expression 8* B - 4.0* A*C. Floating point constants
(4.0, 2.0) are used rather than whole-number constants (4,2) because it is invalid to
combine whole-number constants with REAL variables.

As the full expression is analyzed below, association of operands with operators is


indicated by brackets drawn over each operator and its operand(s).

The compiler first analyzes the portions of the expressions within the innermost
parentheses, then the procedure parameter above and the subexpression 2.0 * A, also
called a compound operand since its result is used in evaluating the whole expression.
I I
., r---1 ,-----,
(- B + SQRT(B*B - 4.0 * A * C»/ (2.0 * A)
In a left-to-right scan, the two operands of the first * operator are both equal to the
value of B. The operands of the second * operator are 4.0 and the value of A. The
operands of the third * operator are the results of the second evaluation (i.e., the
compound operand 4.0* A) and the value of C. The operands of the fourth * operator
are 2.0 and the value of A.

4-7
Expressions and Assignments PL/M-86 User's Guide

The subexpression 2.{)* A is now completely analyzed, but the parameter expression
still contains a minus ( - ) operator that has not been analyzed. The operands of this
operator are the result of evaluating B*B and the result of evaluating 4.0* A *C. Once
this is done, the parameter expression is analyzed and its value can be calculated.

This value does not become an operand in the overall expression. It is passed to the
procedure SQRT, which returns the square root of the parameter. This returned value
then becomes an operand in the remainder of the full original expression:

(- B + "returned value") f (2.0 * A)


Now that the innermost subexpressions have been analyzed and evaluated, what
remains is a division whose left operand must be evaluated further. This outer
subexpression is - B + the returned square root: there are two operators. The first
is a unary minus ( - ) and its operand is the value of B. The second is the binary plus
(+) operator, with two operands: the value of - B and the value of
SQRT(B*B-4.0*A*C). -B has the same meaning as O-B, which is to be added
to the now-known value of the square root indicated. The final operator is division
(f), whose two operands are fully known: the valueof( - B+SQRT(B*B-4.0*A*C»
and the value of (2.0* A).

Three important points must be emphasized about expression evaluation, as discussed


in the next three sections.

Compound Operands Have Types

The first point is that compound operands (as shown between brackets above) have
types just as primary operands do. All of the primary operands used in the example
above were of type REAL, causing the resulting compound operands to be of type
REAL also. It is always valid for all the operands in an arithmetic expression to be
of the same type, and the result is of that type. (The only exception is that combining
BYTE values can validly create a WORD value.)

But, in an expression containing mixed data types, most combinations are not allowed.
Again, the only exception involved BYTE, WORD, and DWORD values; these may
be mixed as operands in expressions, whether constants or variables.

Mixing any other types in arithmetic, logical, or relational expressions is invalid. For
example, if F and G are INTEGER variables and Hand K are REAL variables,
then the expression.s F > K, H + G are invalid.

Due to operator precedence, some combinations can validly occur in the same
expression without being directly combined. In the following logical expression

F>GANDH<K

the subexpression F > G yields a byte value, as does the subexpression H < K. Then
the byte values are ANDed together. This expression is legal despite an apparent
mixing of types, as follows:

G and H could not be the operands for two reasons:


I. The relational operators are of higher precedence than the AND operator.
2. Only BYTE, WORD, or DWORD operands are legal with logical operators.

4-8
PL/M-86 User's Guide Expressions and Assignments

Relational Operators Are Restricted

The second point is: in the absence of parentheses denoting a subexpression, the result
of a relational operation (comparison) is not allowed to become an operand in another
relational operation.

The algebraic meaning of A ~ X ~ B is well-defined on paper, but in PL/M-86 the


expression

A <=X<=B

is invalid because the second < = operator would have to use the result of the first
< = operator as one of its operands.

The valid PL/M-86 way to achieve the desired meaning is

A<=XANDX<=B

Parentheses could have created a valid expression; for example:

(A <= X)<=B

but the result does not have the desired meaning: A < = X becomes a byte of value
o if A is greater than X, OFFH if not. Thus, if A is 0, X is 1, and B is 2:
(0<=1)<=2
becomes (OFFH)<= 2
yields FALSE, contrary to the original intention

Order of Evaluation of Operands

The third point to be made from the analytical example is that the binding of opera-
tors and operands is not the same thing as the order in which operands are evaluated.

As we have just seen, the rules of analysis completely and unambiguously specify
which operands are bound to each operator. In the expression

A + B*C
we know that Band C are the operands of the * operator, while A and the value of
B*C are the operands of the + operator. Obviously Band C must be evaluated before
the * operation can be carried out. Also, the compound operand B*C mllst be
evaluated before the + is carried out.

But it is not obvious whether B will be evaluated before C or vice versa. Indeed, A
could be evaluated before either B or C, and its value stored until the + operation is
performed.

The rules of PL/M-86 do not specify the order in which subexpressions or operands
are evaluated in each statement. This flexibility allows the compiler to optimize the
object code it produces, as discussed in Chapter 11. In most cases, the order of
evaluation makes no difference.

However, certain embedded assignments (section 4.7) or function references (section


8.2) have the side effect of changing the value of an operand in the same expression.
Due to the variability of evaluation order, this side effect can lead to undesired results.
You should avoid such usage.

4-9
Expressions and Assignments PL/M-86 User's Guide

4.6 Choice of Arithmetic: Summary of Rules


As discussed in Chapter 3, PLfM-86 uses three distinct kinds of arithmetic: unsigned,
signed, and floating-point. Whenever an arithmetic or relational operation is carried
out, PLfM-86 uses one of these types of arithmetic, depending on the types of the
operands.

Table 4-2 is a summary of the rules for which type of arithmetic is used in each case.
The table also shows the type of the result in each case (for arithmetic operations).
The notes following the table give additional information.

Table 4-2. Summary of Expression Rules

Kind of Arithmetic
Variable Type Operand Type Result Notes
Arithmetic Operation

DWORD, Unsigned BYTEw/BYTE + or- BYTE range: 0-255


WORD, * or / or MOD WORD range: 0-65535
and BYTE

BYTEw/WORD any WORD A byte operand is first extended with


becomes 8 high-order zeroes to a word value.
WORDw/WORD

BYTE w/DWORD any DWORD A byte operand is first extended with


becomes 24 high-order zeroes to a dword value.
DWORD w/DWORD

WORD w/DWORD any DWORD A wor-d operand is first extended with


becomes 16 high-order zeroes to a dword value.
DWORD w/DWORD

BYTE wI + or- BYTE Constant treated as byte.


whole-number * or / or MOD WORD Constant treated as word.
constant<256

BYTE or WORD wI any WORD Constant treated as word.


whole-number
constant<65,536

BYTE or WORD wI any DWORD Constant treated as dword.


whole-number
constant> 65,535

DWORDwl any DWORD Constant treated as dword.


whole-number
constant<4,294,967,295

INTEGER Signed INTEGER w/lNTEGER any INTEGER range: -32768 to +32767

INTEGER w/whole any INTEGER Constant treated as a positive


number constant INTEGER value.
becomes INTEGER wI Note: unary minus may be applied to
positive INTEGER this positive INTEGER value.

REAL Floating REALw/REAL +or-or* REAL -


Point or I

POINTER and SELECTOR variables can only appear in relational expressions, e.g., PTR11 = PTR22, which results in a BYTE value
of 0 for FALSE or OFFH for TRUE. POINTER values are compared as full iAPX 86 addresses. SELECTOR values are compared as
16-bit unsigned numbers.

NOTE: The above are the only permitted combinations of operations and operands. All other combinations are invalid; for example,
INTEGER with BYTE, REAL with WORD, and so forth. However, explicit conversions may be coded in-line using the built-in
PL/M-86 functions described in Chapter 9.

4-10
PL/M-86 User's Guide Expressions and Assignments

Special Case: Constant Expressions

The rules already given explain expressions like

A + 3 *B

where we have a single whole-number constant. However, if we have an expression


like

3-5+A

we must consider which kind of arithmetic will be used to evaluate 3 - 5, since both
operands are whole-number constants.

The answer, in this case, depends on the type of operand A. If A is of type BYTE,
WORD, or DWORD, we say that 3 - 5 is in "unsigned context." Unsigned arith-
metic is used to evaluate 3 - 5, giving a BYTE result of 254. Unsigned arithmetic
is then used to add this to A.

If A is of type INTEGER, we say that 3 - 5 is in "signed context." Signed arith-


metic is used to evaluate 3 - 5, giving an INTEGER result of - 2. Signed arithmetic
is then used to add this to A.

If A is of type REAL, POINTER, or SELECTOR, the expression is illegal.

Any compound operand, sUbexpression, or expression that contains only wholenum-


ber constants as primary operands is called a constant expression. Note that this
applies only to whole-number constants less than 65,536 (all DWORD arithmetic is
performed at run-time). Floating-point constants are of type REAL and are treated
exactly like the values of REAL variables.

In this expression:

3 - 5 +500 + A

3 - 5 is a constant expression that forms part of the larger constant expression


3 - 5 + 500.

If the constant expression is not the entire expression, then its value is an operand in
the expression. The context is created by the other operand of the same operator.

If the other operand is of type BYTE, WORD, or DWORD, then each wholenumber
constant is treated as a BYTE value if it is equal to or less than 255, as a WORD
value if it is greater than 255 and equal to or less than 65,535, and as a DWORD
value if it is greater than 65,535. If the constant exceeds 4,294,967,295 it is illegal.
Unsigned arithmetic is used. In the example above, suppose the operand A has a
BYTE value. Then the constant expression 3 - 5 + 500 is in unsigned context. The
constants 3 and 5 are treated as BYTE values, and 500 is treated as a WORD value.
The operation 3 - 5 gives a BYTE result of 254, and this is extended to a WORD
value of 254 before adding 500, resulting in a WORD value of 754. It is exactly as
if the expr~ssion had been written as:

754 +A

4-11
Expressions and Assignments PLfM-86 User's Guide

Now suppose that A has an INTEGER value. In this case, the constant 3 - 5 + 500
is in signed context, and all three constants are treated as INTEGER values. This
time, signed arithmetic is used for the operation 3 - 5, which results in an INTEGER
value of - 2. Then 500 is added, and the INTEGER result is 498. It is as if the
expression had been written as:

498 +A

To summarize, if the context is created by a BYTE, WORD, or DWORD operand,


the constant expression is in unsigned context. If the context is created by an
INTEGER operand, the constant expression is in signed context. Note that if the
context is created by a REAL, POINTER, or SELECTOR operand, the constant
expression is illegal.

If the constant expression is the entire expression, then it is one of the following:
• Constant expression as right-hand part of an assignment statement: context is
created by the variable to which the expression is being assigned. Rules are given
below in section 4.7.
• Constant expression as subscript of an array variable: evaluated as if being
assigned to a WORD variable (see section 4.7).
• Constant expression in the IF part of an IF statement: evaluated as if being
assigned to a BYTE variable (see sections 6.2 and 4.7).
• Constant expression in a DO WHILE statement: evaluated as if being assigned
to a BYTE variable (see sections 6.1 and 4.7).
• Constant expression as "start," "step," or "limit" expression in an iterative DO
statement: evaluated as if being assigned to a variable of the same type as the
index variable in the same iterative DO statement (see sections 6.1 and 4.7).
• Constant expression in a DO CASE statement: evaluated as if being assigned to
a WORD variable (see sections 6.1 and 4.7).
• Constant expression as an actual parameter in a CALL statement or function
reference: evaluated as if being assigned to the corresponding formal parameter
in the procedure declaration (see sections 8.2 and 4.7).
• Constant expression in a RETURN statement: evaluated as if being assigned to
a variable of the same type as the (typed) procedure that contains the RETURN
statement (see section 4.7).

4.7 Assignment Statements


Results of computations can be stored as values of scalar variables. At any given
moment, a scalar variable has only one value-but this value may change with
program execution. The PL/M-86 assignment statement changes the value of a
variable. Its simplest form is:

variable=expression;

where expression is any PL/M-86 expression, as described in the preceding sections.


This expression is evaluated, and the resulting value is assigned to (that is, stored in)
variable. This variable may be any fully qualified variable reference except a function
reference. The old value of the variable is lost.

4-12
PL/M-86 User's Guide Expressions and Assignments

For example, following execution of the statement:

RESULT • A + B;
the variable RESULT will have a new value, calculated by evaluating the expression
A + B.

Implicit Type Conversions

In an assignment statement, if the type of the value of the right-hand expression is


not the same as the type of the variable on the left side of the equal sign, then either
the assignment is illegal or an implicit type conversion occurs. Except for constant
expressions, only byte, word, or dword values are converted automatically. Chapter 9
presents eight built-in functions you can invoke to perform explicit conversions for
use in expressions or assignments. The following paragraphs spell out the rules for
the implicit conversions:

Expression with a BYTE value. WORD variable on the left: the BYTE value is
extended by 8 high-order zero bits to convert it to a WORD value. DWORD variable
on the left: the BYTE value is extended by 24 high-order zero bits to convert it to a
DWORD value.

If the variable on the left is of any type except BYTE, WORD, or DWORD, the
assignment is illegal.

Expression with a WORD value. BYTE variable on the left: The 8 high-order bits of
the WORD value are dropped to convert it to a BYTE value. DWORD variable on
the left: the WORD value is extended by 16 high-order zero bits to convert it to a
DWORD value.

If the variable on the left is of any type except BYTE, WORD, or DWORD, the
assignment is illegal.

Expression with a DWORD value. BYTE variable on the left: the 24 high-order bits
of the DWORD value are dropped to convert it to a BYTE value. WORD variable
on the left: the 16 high-order bits of the DWORD value are dropped to convert it to
a WORD value.

If the variable on the left is of any type except BYTE, WORD, or DWORD, the
assignment is illegal.

Expression with an INTEGER value. No implicit conversions are performed. If the


variable on the left is of any type except INTEGER, the assignment is illegal.

Expression with a REAL value. No implicit conversions are performed. If the


variable on the left is of any type except REAL, the assignment is illegal.

Expression with a POINTER value. No implicit conversions are performed. If the


variable on the left is of any type except POINTER, the assignment is illegal.

Expression with a SELECTOR value. No implicit conversions are performed. If the


variable on the left is of any type except SELECTOR, the assignment is illegal.

Constant Expression

BYTE variable on the left: The constant expression is evaluated in unsigned context.
If the resulting value is less than or equal to 255, it is treated as a BYTE value and
no conversion is necessary. If the reSUlting value is greater than 255, it is converted
to type BYTE by dropping all except its 8 low-order bits.

4-13
Expressions and Assignments PL/M-86 User's Guide

WORD variable on the left: The constant expression is evaluated in unsigned context.
If the resulting value is equal to or less than 65,535, it is treated as a WORD value,
and no conversion is necessary. If the resulting value is greater than 65,535, -it is
converted to type WORD by dropping all except its 16 low-order bits.

DWORD variable on the left: The constant expression is evaluated in unsigned context.
No conversion is necessary.

INTEGER variable on the left: The constant expression is evaluated in signed context
to yield an INTEGER value. No conversion is necessary.

POINTER variable on the left: If the constant expression consists of nothing but a
single whole-number constant, the constant is treated as a POINTER value. The
whole-number constant must not be greater than 1,048,575. If the constant expres-
sion consists of anything more than a single whole-number constant, the assignment
is illegal. This is one of the three cases in which a whole-number constant can be
treated as a POINTER value. The other two cases are described in sections 3.1 and
3.6.

SELECTOR variable on the left: If the constant expression consists of nothing but a
single whole-number constant, it is treated as a SELECTOR value. The whole-number
constant must not exceed 65,535. If the constant expression consists of anything more
than a single whole-number, the assignment is illegal. This is one of two cases where
a whole-number constant can be treated as a SELECTOR value. The other case is
described in section 3.1.

REAL variable on the left: The assignment is illegal unless all values on the right are
REAL. However, the FLOAT function described in section 9.2 can be used to convert
the constant expression to a REAL value which can be assigned to that variable.

Multiple Assignment

It is often convenient to assign the same value to several variables at the same time.
This is accomplished in PL/M-86 by listing all the variables to the left of the equal
sign, separated by commas. The variables LEFT, CENTER, and RIGHT can all be
set to the value of the expression INIT + CORR with the single assignment
statement:

LEFT, CENTER, RIGHT • IHIT + CORR;


The variables on the left-hand side of a multiple assignment must be all of the same
type, with one exception: variables of types BYTE, WORD, and DWORD may be
mixed. When this is done, the conversion rules given above are applied separately to
each assignment.

The order in which the assignments are performed is not predictable. There-
fore, if a variable on the left side of a multiple assignment also appears in
the expression on the right side, the results are undefined.

Embedded Assignments

A special form of assignment can be used within PL/M-86 expressions. The form of
this "embedded assignment" is:

variable: =expression

4-14
PLfM-86 User's Guide Expressions and Assignments

and may appear anywhere an expression is allowed. The expression (everything to


the right of the : = assignment symbol) is evaluated and stored into the variable on
the left. Parentheses are strongly recommended, therefore, to specify the limits of an
embedded assignment within an assignment statement. The value of the embedded
assignment is the same as that of its right half. For example, the expression:

ALT + (CDRR := TCORR + PCORR) - (ELEV := HT/SCALEl


results in exactly the same value as:

ALT + (TCORR + PCORR) - (HT/SCALE)

The only difference is the side-effect of storing the intermediate results


TCORR + PCORR and HT/SCALE into CORR and ELEV, respectively. These
names for intermediate results can then be used at a later point in the program without
calculating their values. The names must have been declared earlier.

~
The rules of PL/M-86 do not specify the order in which subexpressions or
operands are evaluated. When an embedded assignment changes the value
of a variable that also appears elsewhere in the same expression, the results
cannot be predicted. The results depend on too many factors, e.g., the optim-
ization level you specify to the compiler (as discussed in Chapter 11).
As an example of this ambiguity, if you write:
A - (X:-X+4) + V·V + X;
you could mean either of the following interpretations:
A1 - eX+4) + V·V + (X+4);
A2 - (X+4) + V·V + X;
You should avoid this ambiguity by removing the embedded assignment from
the expression and using a separate assignment statement to achieve the
desired effect. For example, each of the above is unambiguously achieved by
the following:
(1) X· X + 4;
A1 - X + V·V + X;
( 2) X
A2 .- X + 4;
X + V·V + X 4;
( 3) A3 . X + 4 + V·V + X;
X - X + 4;

NOTE
Before using floating-point (REAL) arithmetic or assignments, refer to
Chapters 3 and 10 and Appendixes F and G, which explain many features
and restrictions that affect the result of such operations.

4-15
CHAPTER 5
ARRAYS AND STRUCTURES

5.1 Arrays
As mentioned briefly in Chapter 3, it is often desirable to use a single identifier to
refer to a whole group of scalars, and to distinguish the individual scalars by means
of a "subscript," i.e., a value enclosed in parentheses. The scalars are all the same
type. Such a list is called an array.

It is declared by using a "dimension specifier." The dimension specifier is a nonzero


whole-number constant enclosed in parentheses. The value of the constant specifies
the number of array elements (individual scalar variables) making up the array. For
example:

DECLARE ITEMS (100) BYTE;


causes the identifier ITEMS to be associated with 100 array elements, each of type
BYTE. One byte of storage is allocated for each of these scalars.

The elements of an array are stored contiguously, with the Oth element in the lowest
location and the last element in the highest location. (No storage is allocated for a
based array, but the elements are considered to be contiguous in memory.)

The declaration:

DECLARE (WIDTH, LENGTH, HEIGHT) (100) REAL;


is equivalent to the following sequence:

DECLARE WIDTH (100) REAL;


DECLARE LENGTH (100) REAL;
DECLARE HEIGHT (100) REAL;
(except that contiguous storage is guaranteed for variables declared in a single paren-
thesized list, while variables declared in consecutive declarations are not necessarily
stored contiguously).

This causes each of the three identifiers, WIDTH, LENGTH, and HEIGHT, to be
associated with 100 array elements of type REAL, so that 300 elements of type REAL
have been declared in all. For each of these scalars, four contiguous bytes of storage
are allocated.

Subscripted Variables

To refer to a single element of a previously declared array, you use the array name
followed by a subscript enclosed in parentheses. This construct is called a
"subscripted variable."

For example, given the DECLARE statement:

DECLARE ITEMS (100) BYTE;


you can refer to each byte as an individual item using ITEMS(O), ITEMS(1),
ITEMS(2), and so on up to ITEMS(99).

5-1
Arrays and Strnctures PLfM-86 User's Guide

Notice that the first element of an array has subscript O-not 1. Thus, the subscript
of the last element is 1 less than the dimension specifier.

If we want to add the third element of the array ITEMS to the fourth, and store the
result in the fifth, we can write the PLfM-86 assignment statement:

ITEMS(4) = ITEMS(2) + ITEMS(3);

Much of the power of a subscripted variable lies in the fact that the subscript need
not be a whole-number constant, but can be another variable, or in fact any
PLfM-86 expression that yields a BYTE, WORD, or INTEGER value. Thus, the
construction:

VECTOR(ITEMS(3) + 2)

refers to some element of the array VECTOR. Which element it is depends on the
expression ITEMS( 3) + 2. This value in turn depends on the value stored in
ITEMS( 3), the fourth element of array ITEMS, at the time when the reference is
processed by the running program.

If ITEMS(3) contains the value 5, then ITEMS(3} + 2 is equal to 7 and the refer-
ence is to VECTOR(7}, the eighth element of the array VECTOR.

The following sequence of statements will sum the elements of the lO-element array
NUMBERS by using an "index variable" named I, which takes on values from
o to 9:
DECLARE SUM BYTE;
DECLARE NUMBERS(10) BYTE;
DECLARE I BYTE;
SUM = 0;
DO I • 0 TO 9;
SUM • SUM + NUMBERS(I);
END;
Subscripted array variables are permitted anywhere PLfM-86 permits a variable.
They may also appear on the left side of an assignment statement if the array elements
are of a scalar type.

5.2 Structures
Just as an array allows one identifier to refer to a collection of elements of the same
type, a structure allows one identifier to refer to a collection of structure members
that may have different types. Each member of a structure has a member identifier.

The following is an example of a structure declaration:

DECLARE AIRPLANE STRUCTURE (SPEED REAL, ALTIT~DE REAL);


This declares two REAL scalars, both associated with the identifier AIRPLANE.
Once this declaration has been made, the first scalar can be referred to as
AIRPLANE. SPEED and the second as AIRPLANE.ALTITUDE. These names are
also called the "members" of this structure.

A structure may have many members; see Appendix B for the correct limit. The
members of a structure are stored contiguously in the order in which they are
specified. (No storage is allocated for a based structure, but the members are
considered to be contiguous in memory.)

5-2
PL/M-86 User's Guide Arrays and Structures

Individual structure members may not be based and may not have any attributes, as
discussed in Chapter 3.

Arrays of Structures

We have already seen arrays of scalars. PL/M-86 also allows arrays of structures.
The following DECLARE statement creates an array of structures which can be used
to store SPEED and ALTITUDE (as in the previous example) for twenty
AIRPLANEs instead of one:

DECLARE AIRPLANE (20) STRUCTURE (SPEED REAL, ALTITUDE REAL);

This declares twenty structures associated with the array identifier AIRPLANE, each
distinguished by subscripts from 0 to 19. Each of these structures consists of two
REAL scalar members. Thus, storage is allocated for 40 REAL scalars.

To refer to the ALTITUDE of AIRPLANE number 17, one would write


AIRPLANE( I7).ALTITUDE.

Arrays Within Structures

An array may be used as a member of a structure, as in the following DECLARE


statement:

DECLARE PAYCHECK STRUCTURE (LASTSNAME(15)BYTE,


FIRSTSNAME(15)BYTE,
MI BYTE,
AMOUNT REAL);
This structure consists of the following members: two I5-element BYTE arrays,
PAYCHECK.LAST$NAME and PAYCHECK.FIRST$NAME; the BYTE scalar
PAYCHECK.MI; and the REAL scalar PA YCHECK.AMOUNT.

To refer to the fourth element of the array PAYCHECK.LASTNAME, we would


write PAYCHECK.LASTNAME(3).

Arrays of Structures with Arrays Inside the Structures

Given that an array can be made up of structures, and a structure can have arrays as
members, we can combine the two constructions to write:

DECLARE FLOOR (30) STRUCTURE (OFFICE (55) BYTE);


The identifier FLOOR refers to an array of 30 structures, each of which contains
one array of 55 BYTE scalars. This could be thought of as a 30-by-55 matrix of
BYTE scalars. To reference a particular scalar value-say element 46 of structure
25-we would write FLOOR(25).OFFICE(46). Note thatthe scalar elements of each
OFFICE array are stored contiguously, and the OFFICE arrays themselves are
elements of the FLOOR array and are stored contiguously.

5-3
Arrays and Structures PL/M-86 User's Guide

We can alter the PAYCHECK structure declaration above to make it an array of


structures, as follows:

DECLARE PAYROLL (100) STRUCTURE(LASTSHAMEC1S)BYTE,


FIRSTSHAME(1S) BYTE,
MI BYTE,
AMOUNT REAL);
Now we have an array of 100 structures, each of which can be used during program
execution to store the last name, first name, middle initial, and amount for one
employee. LAST$NAME and FIRST$NAME in each structure are I5-BYTE arrays
for storing the names as character strings. To refer to the Kth character of the first
name of the Nth employee, we would write:

PAYROLLCN-1).FIRSTSHAME(K-1)
where Nand K are previously declared variables to which we have assigned appro-
priate values. This might be convenient in a routine for printing out payroll
information.

5.3 References to Arrays and Structures


In the preceding sections, we saw numerous examples of variable references. A
variable reference is simply the use, in program text, of the identifier of a variable
that has been declared.

A variable reference may be "fully qualified," "partially qualified,"or "unqualified."

Fully Qualified Variable References

A fully qualified variable reference is one that uniquely specifies a single scalar. For
example, if we have the declarations:

DECLARE AVERAGE REAL;


DECLARE ITEMS (100) BYTE;
DECLARE RECORD STRUCTURE (KEY BYTE, INFO WORD);
DECLARE NODE (25) STRUCTURE (SUBLIST (100) BYTE, RANK BYTE);
then AVERAGE, ITEMS(5), RECORD.INFO, AND NODE(21).SUBLIST(32) are
all fully qualified variable references: each refers unambiguously to a single scalar.

It-should be noted that qualification may only be applied to variables that have been
appropriately declared. A subscript may only be applied to an identifier that has been
declared with a dimension specifier. A member-identifier may only be applied to an
identifier declared as a structure identifier. The compiler flags violations of these
rules as errors.

Unqualified and Partially Qualified Variable References

Unqualified and partially qualified variable references are allowed only in location
references, as discussed in Chapter 3, and in the built-in procedures LENGTH, LAST,
and SIZE, as discussed in Chapter 9.

5-4
PL/M-86 User's Guide Arrays and Structures

An unqualified variable reference is the identifier of a structure or array, without any


member-identifier or subscript. For example, with the above declarations, ITEMS
and RECORD are unqualified variable references. An unqualified variable reference
is a reference to the entire array or structure. @ITEMS is the location of the entire
array ITEMS-that is, the location of its first byte. Similarly, @RECORD is the
location of the first byte of the structure RECORD.

A partially qualified variable reference fails to refer uniquely to a single scalar even
using a subscript and/or member-identifier with an identifier. For example,
NODE(I5) and NODE(I2).SUBLIST are partially qualified variable references,
given the above declarations.

When used with the @operator, such references are taken to mean the first byte that
could fit the description. Thus @NODE(I5) is the location of the first byte of the
structure NODE(I5), which is itself an element of the array NODE. Similarly,
@NODE(I2).SUBLIST is the location of the first byte of the array
NODE(12).SUBLIST, which is itself a member of the structure NODE(12), which
in turn is an element of the array NODE.

Note that @NODE.SUBLIST is not permitted because it is completely ambiguous:


in a location reference referring to an array made up of structures, a subscript must
be given before a member-identifier can be added to the reference. The rule is differ-
ent for partially qualified variable references in connection with the built-in proce-
dures LENGTH, LAST, and SIZE, as explained in Chapter 9.

5-5
CHAPTER 6
FLOW CONTROL STATEMENTS

This chapter describes statements that alter the sequence of execution of PL/M-86
statements and the group statements into blocks.

6. 1 DO and END Statements: DO Blocks


Procedures and DO blocks are the basic building units of modular programming in
PL/M-86. (Procedures are discussed in Chapter 8.)

The present chapter discusses all four kinds of DO-blocks. Each begins with a DO
statement and includes all subsequent statements through the closing END state-
ment. The four kinds are
• The simple DO block; for example:

DO; '*
statement-O;
all statements executed, each in order *'
statement-1 ;
statement-2;

END;
• The DO CASE block; for example:

DOC A5 E selecLexpression;
case-O-statement; '* e x act 1 yon est ate men t e x e cut e d - */
case-1-statement; / * 5 e 1 e c ted b y the e x pre 5 5 ion '5 val u e */

END;
• The DO WHILE block; for example:

DOW HI l E expression_true;
statement-O; /' all ex e cut e d as Ion gas e-x pre 5 5 ion i
statement-1; /' t rue J non e when e x pre 5 5 ion i 5 f a 1 5 e.
5 *'
*/

ENDi
• The iterative DO block; for example:

D0 counter • start-expr T 0 limit-expr B V step-expr;


statement-O; / * all 5 tat e men t 5 e x e cut e dan u mb e r *'
/ * 0 f tim e 5 d e pen din 9 0 nco mpar i son */
statement-1;
/' of counter with limit_expr. *'
ENDi

6-1
Flow Control Statements PL/M-86 User's Guide

The last two blocks are also referred to as DO-loops because the executable state-
ments within them may be executed repeatedly (in sequence) depending on the
expressions in the DO statement.

As discussed with earlier charts, any DO statement may have multiple labels on it,
and the last (only) of these may appear between the word END and the next
semicolon. For example:

A: B: C: D: EM: DOj

EHD EM /' indicates end of block EMj ' /


/' A, B, C, D also end here. '/

As mentioned in Chapter 3, the placement of declarations is restricted. Except for


use in procedures, declarations are permitted only at the top of a simple DO block,
before any executable statements of the block. (This DO can, of course, be nested
within other DOs or procedures. Chapter 7 discusses the scope of declared names.)

Each DO block can contain any sequence of executable statements, including other
DO blocks. Each block is considered by the compiler as a unit, as if it were a single
executable statement. This fact is particularly useful in the DO CASE block and the
IF statement, both discussed in this chapter.

The discussions that follow describe the normal flow of control within each kind of
DO block. The normal exit from the block passes through the END statement to the
statement immediately following. These discussions assume that none of the state-
ments in the block causes control to bypass that process. A GO TO statement with
the target outside the block would be one such bypass. (GOTOs are discussed later
in this chapter.)

Simple DO Blocks

A simple DO block merely groups, as a unit, a set of statements that will be executed
sequentially (except for the effect of GOTOs or CALLs):

DO;
statement-O;
statement-1 ;
statement-n
END;
For example:

DO;
NEWSVALUE • OLDSVALUE + TEMP;
COUNT • COUNT + 1
END;

This simple DO block adds the value of TEMP to the value of OLD$VALUE and
stores it in NEWSVALUE. It then increments the value of COUNT by one.

6-2
PL/M-86 User's Guide Flow Control Statements

DO blocks may be nested within each other as shown in the following example:

able: DO;
statement-O;
statement-1 ;
baker: DO;
statement-a;
statement-b;
statement-c;
END baker;
statement-2;
statement-3;
END able;

The first DO statement and the second END statement bracket one simple DO block.
The second DO statement and the first END statement bracket a different DO block
inside the first one. Notice how indentation (using tabs or spaces) can be used to
make the sequence readable, so that it can be seen at a glance that one DO block is
nested inside another. It is recommended that this practice be followed in writing
PL/M-86 programs. See Appendix B for the number of DO blocks that can be nested.

A simple DO block can delimit the scope of variables, as discussed in Chapter 7.

DO CASE Blocks

A DO CASE block begins with a DO CASE statement, and selectively executes one
of the statements in the block. The statement is selected by the value of an expres-
sion. The maximum number of cases is given in Appendix B. The form of the
DO CASE block is:

DOC AS E selecLexpression;
statement-O;
statement-1 ;
statement-n;
END;

In the DO CASE statement, express;onmust yield a BYTE, WORD, or INTEGER


value. If it is a constant expression, it is evaluated as if it were being assigned to a
WORD variable. The value of expression must lie between 0 and n (call this value
K). K is used to select one of the statements in the DO CASE block, which is then
executed. The first case (statement-O) corresponds to K =0, the second (statement-
1) corresponds to K = 1, and so forth. Only one statement from the block is selected.
This statement is then executed only once. Control then passes to the statement
following the END statement of the DO CASE block.

If the run-time value of the expression in the DO CASE statement is less


than 0 or greater than n (where n + 1 is the number of statements in the
DO CASE block), then the effect of the DO CASE statement is undefined.
This may have disastrous effects on program execution. Therefore if there is
any possibility that this out-of-range condition may occur, the DO CASE
block should be contained within an IF statement that tests the expression
to make sure that if bas a value that will produce meaftIDgh.1 results.

6-3
Flow Control Statements PL/M-86 User's Guide

An example of a DO CASE block is:

DO CASE SCORE;
/ .. case 0
SAFETIES ..
CONVERSIONS=CONVERSIONS+1;
SAFETIES + 1 ;
/
/ .. case
case
1
2


I
I
FIELDGOALS FIELDGOALS + 1 ; /
/ . case
case
3


I
I

.
4 • I

END;
TOUCHDOWNS=TOUCHDOWNS+1;
I •
/
case
case
5
6 ·
• I
/

When execution of this CASE statement begins, the variable SCORE must be in the
range 0-6. If SCORE is 0, 4, or 5 then a null statement (consisting of only a semicolon,
and having no effect) is executed; otherwise the appropriate statement is executed,
causing the corresponding variable to be incremented.

A more complex DO CASE block is the following:

SELECT = COUNT-5;
IF SELECT (=2 AND SELECT )=0 THEN
DO CASE SELECT;
x = X + 1; II Case 0 II

DO; II Begin Case 1 1/


X = Y + 10;
Y Y + 1i
END; IIEnd Case 1 *1
DO I = LASTSHI+1 TO TOP-6 II Begin Case 2 II
Z(I) = XIY+1
W(J) Z(I)IZ(J)
V(J) = W(I)-Z(I)
END; II End Case 2 1/

END; IIEnd DO CASE block 1/


ELSE CALL ERROR;
If we assume SELECT and COUNT are INTEGER variables, negative values could
occur. The DO CASE block is placed within an IF statement to guarantee that if the
value of SELECT is less than 0 or greater than 2, execution of the DO CASE block
will not be attempted. Instead, a procedure called ERROR (declared previously) will
be activated. IF statements are discussed in section 6.2.

This example illustrates the use of a simple DO block as a single PL/M-86 state-
ment. The DO CASE statement can select Case 1 or Case 2 and cause multiple
statements to be executed. This is only possible because they are grouped as a simple
DO block, which acts as a single statement.

DO WHILE Blocks

DO WHILE and IF statements examine only the least significant bit of the value of
the expression. If the expression is relational, e.g., A<B, the result will have a value
of OOH or OFFH, but this is incidental; it may have any BY'FE or WORD value. If
the value is an odd number (least significant bit = 1), it will be considered "true."
If it is even (least significant bit = 0), it will he considered "false."

6-4
PLjM..86 User's Guide Flow Control Statements

A DO WHILE block begins with a DO WHILE statement, and has the form:

DO WHILE expression; 1* expression must yield *1


/* BYTE or WORD value *1
statement-O;
statement-1 ;

statement-n;
E HD;

The effect of this statement is as follows:


1. First the BYTE or WORD expression following the reserved word WHILE is
evaluated. If the rightmost bit of result is 1, then the sequence of statements up
to the END is executed.
2. When the END is reached, expression is evaluated again, and again the sequence
of statements is executed only if the value of the expression has a rightmost bit
of 1.
3. The block is executed over and over until expression has a value whose rightmost
bit is o. Execution then skips the statements in the block and passes to the state-
ments following the END statement.
Consider the following example:

AMOUNT • 1;
DO WHILE AMOUNT (= 3;
AMOUNT • AMOUNT + 1;
END;
The statement AMOUNT = AMOUNT + 1 is executed exactly 3 times. The
value of AMOUNT when program control passes out of the block is 4.

Iterative DO Blocks
An iterative DO block begins with an iteration statement and executes each state-
ment in order in the block, repeating the entire sequence as described in this section.
The form of the iterative DO block is:

D 0 counter • start-expr T 0 limit-expr B Y step-expr ;


statement-O
statement-1

END
The BY step-expr phrase is optional; if omitted, a step of 1 is used.

The counter must be a non-subscripted variable of type BYTE, WORD, or INTEGER.


The start-expr, limit-expr, and step-expr may be any valid PL/M-86 expressions also
of these types. However, if counter or any of these expressions has type INTEGER,
then all must be INTEGER, as explained in Chapter 4.

An example of an iterative DO block is:

DO I • 1 TO 10;
CALL BELL;
END;

6-5
Flow Control Statements PL/M-86 User's Guide

where BELL is the name of a procedure that causes a bell to be rung. The bell is
rung ten times.

Another example shows how the index-variable can be used within the block:

AMOUNT • OJ
DO I • 1 TO 10;
AMOUNT • AMOUNT + I;
END;

The assignment statement is executed 10 times, each time with a new value for I.
The result is to sum the numbers from 1 to 10 (inclusive) and leave the sum (namely,
55) as the value of AMOUNT.

The next example uses step-expr:

'·Compute the product of the first H odd integers .,


PROD • 1;
DO I • 1 TO C2*N-1) BY 2;
PROD • PROD·I;
END;

The type of counter affects two important factors in the execution flow of iterative
DOs:
a. When step-expr is evaluated.
b. What causes execution to exit the DO block.

The following steps constitute the general execution sequence of an iterative DO block,
with BYTE, WORD, or INTEGER variables and expressions in the DO itself. Type
is mentioned only for steps where it matters, i.e., where the actions or consequences
are different for different types. Where the INTEGER case is different, it is described
in parentheses. The discussion following this description summarizes all the rules and
their results.
1. The start-expr is evaluated and assigned to counter.
2. The limit-expr is evaluated and compared with counter. (If these are INTEGER
type, then step-expr is also newly evaluated at this time.)
a. If counter is greater than limit-expr, execution exits the DO and passes to the
statement following the next END (unless step-expris a negative INTEGER;
if so, the exit occurs only if counter is less than limit-expr.)
b. Otherwise, the statements within the DO block are executed in order until
the END statement is reached.
c. At the END, a step-exprof type BYTE or WORD is newly evaluated.
3. The counter is incremented by the value of step-expr. For BYTE or WORD
counters, if the new value is less than the old value (due to modulo arithmetic as
explained below), the loop is exited immediately.
Otherwise, control returns to step 2 above.

(An 8-bit byte can represent numbers no larger than 1111111lB (255 decimal). The
largest number a 16-bit word can represent is I111111111111111B, which is 65535
decimal. If you add 1 to these values, you get o. Thus, the new counter can be less
than the old.)

6-6
PLfM-86 User's Guide Flow Control Statements

These rules and their consequences can be summarized in two broad cases:
A. If you start with a non-negative step-expr, then the loop is exited as soon as any
one of the following becomes true:
1. The new counter is greater than the new limit-expr.
2. An INTEGER step-expr becomes negative AND the new counter is still less
than the new limit-expr.
3. A BYTE or WORD step-expr causes a lower counter than the one just used.
B. If you start with a negative INTEGER step-expr, then the loop is exited as soon
as either of the following two conditions occurs:
1. The new counter is less than the new limit-expr.
2. The new step-expr becomes non-negative AND the new counter is greater
than the new limit-expr.

Upon exit from the iterative DO block:


1. In all cases step-exp has been reevaluated.
2. In all but one case limit-expr has been re-evaluated. When a non-INTEGER
counter has just "gone over" and become smaller, Iimit-expr is unchanged from
its value during the last loop.
3. In all cases counter has been changed, but the step value that was added to it
varies. If INTEGER, counter has been incremented by the former step value
before it was re-evaluated. For BYTE or WORD counters, the newer step has
been used.

The following distinctions can be important:


In every case, start-expr is evaluated only once and Iimit-expr is evaluated before
any execution.
• An INTEGER step-expr is evaluated in step 2; other step-exprs are evaluated in
step 3.
With a counter of BYTE or WORD, there is no such thing as a negative step.
For example, if step-expr is - 5, 251 is used. Furthermore, stepping down to a
limit-exprthat is less than start-expr is not possible because the loop will be exited
immediately.

6.2 The IF Statement


The IF statement provides conditional execution of statements. It takes the form:

I F expression THE H statement-a j


E L S E statement-b; I • 0 P t ion a 1 • I

The reserved word THEN and the statement following it are required and are called
the "THEN part." The reserved word ELSE and the statement following it are
optional, and are called the "ELSE part."

The IF statement has the following effect: first expression is evaluated as if it were
being assigned to a variable of type BYTE. If the result is "true" (rightmost bit is 1)
then statement-a is executed. If the result is "false" (rightmost bit is 0), then
statement-b is executed. Following execution of the chosen alternative, control passes
to the next statement following the IF statement. Thus, of the two statements
(statement-a and statement-b) one and only one is executed.

6-7
Flow Control Statements PL/M-S6 User's Guide

Consider the following program fragment:

IF HEW) OLD THEH RESULT • HEW;


ELSE RESULT • OLD;

Here, RESULT is assigned the value of NEW or the value of OLD, whichever is
greater. This code causes exactly one of the two assignment statements to be executed.
RESULT always gets assigned some value, but only one assignment to RESULT is
executed.

In the event that statement-b is not needed, the ELSE part may be omitted entirely.
Such an IF statement takes the form:

IF expression THE H statement-a;

Here, statement-a is executed if the value of expression has a rightmost bit of 1.


Otherwise, nothing happens, and control immediately passes on to the next statement
following the IF statement.

For example, the following sequence of PL/M-86 statements will assign to INDEX
either the number 5, or the value of THRESHOLD, whichever is larger. The value
of IN IT will change during execution of the IF statement only if THRESHOLD is
greater than 5. The final value of INIT is copied to INDEX in any case:

IHIT • 5;
IF THRESHOLD) IHIT THEH IHIT • THRESHOLD;
IHDEX • INIT;

The power of the IF statement is enhanced by using DO blocks in the THEN and
ELSE parts. Since a DO block is allowed wherever a single statement is allowed,
each of the two statements in an IF statement may be a DO block. For example:

IF A • B THEH
DO;
EQUALSEVEHTS • EQUALSEVENTS + 1;
PAIR$VALUE • A;
BOTTOM • B;
END;
ELSE
DO;
UHEQUAL$EVENTS • UNEQUAL$EVEHTS + 1;
TOP • A;
BOTTOM • B;
END;

DO blocks nested within an IF statement can contain further nested DO blocks, IF


statements, variable and procedure declarations, and so on.

Nested IF Statements
Any IF statement (including the ELSE part, if any) may be considered a single
PL/M-86 statement (although it is not a block). Thus, the statement to be executed
in a THEN or an ELSE clause may in fact be another IF statement.

6-8
PL/M-86 User's Guide Flow Control Statements

An IF statement inside a THEN clause is called a "nested" IF. Nesting may be


carried to several levels without needing to enclose any of the nested IF statements
in DO blocks, as in the following construction:

I F expression-1 THE Ii
IF expression-2 THE H
I F expression-3 THE H statement-a;

Here we have three levels of nesting. Note that statement-a will be executed only if
the values of all three expressions are ·'true.," Thus, the above is equivalent to:

I F (expression-1) AHD (expression-2) AHD (expression-3)


THE H statement-a;

Notice that the above example of nesting does not have an ELSE part. When using
nested IF statements, it is important to understand the following important rule of
PLJM-86:

A set of nested IF statements may have only one ELSE part, and it belongs to the
innermost (that is, the last) of the nested IF statements.

This rule could also be restated as:

When an IF statement is nested within the THEN part of an outer IF statement, the
outer IF statement may not have an ELSE part.

In other words, the construction:

I F expression-1 THE H
I F expression-2 THE H statement-a
E L S E statement-b i

is legal and means that if the values of both expression-1 and expression-2 are "true,"
then statement-a will be executed. If the value of expression-1 is "true" and the value
of expression-2 is "false," then statement-b will be executed. If the value of
expression-1 is "false," neither statement-a nor statement-b will be executed, regard-
less of the value of expression-2.

The construction above is equivalent to:

I F expression-1 THE H
DO:
I F expression-2 THE H statement-a;
E L S E statement-b i
E HD i

This construction is much more readable and offers less opportunity for error.

If the intention is for the ELSE part to belong to the outer IF statement, then the
nesting must be done by means of a DO block:

I F expression-1 THE H
DO i
I F expression-2 THE H
statement-a;
E HD i
E L S E statement-b;

Note that the meaning of this construction differs completely from the previous one.

6-9
Flow Control Statements PLfM-86 User's Guide

Finally, consider the following:

I F expression-1 THE H
I F expression-2 THE H
I F expression-3 THE H statement-a;
E L S E statement-b;
E L S E statement-c; /* illegal statement */
E L S E statement-d; /* illegal statement * /

This construction is illegal because only one ELSE part is allowed. If the intention is
for the ELSE parts to match the IF parts as indicated by the indenting, the nesting
must be done with DO blocks, as follows:

I F expression-1 THE H
DO;
I F expression-2 THE H
DO; I F expression-3 THE H statement-a;
EL SE statement-b;
E H D;
E L S E statement-c;
EHD;
E L SE statement-d;

Sequential IF Statements
Consider the following example. An ASCII-coded character is stored in a BYTE
variable named CHAR. If the character is an A, we want to execute statement-a. If
the character is a B, we want to execute statement-b. If the character is a C, we want
to execute statement-c. If the character is not A, B, or C, we want to execute
statement-x. The code for doing this could be written as follows, using IF statements
that are completely independent of one another:

IF CHAR • \ A' THE H statement-a;


IF CHAR • \ B' THE H statement-b;
IF CHAR • \ C' THE H statement-c;
IF CHAR() \ A' AHD CHAR () \ B' and CHAR () \ C' THE H statement-x;

This sequence is inefficient because all four IF statements (six tests in all) will be
carried out in every case, which is wasteful when one of the earlier tests succeeds.

We need to test for 'A' in all cases. But we need to test for 'B' only if the test for 'A'
- fails and we need to test for 'C' only if both previous tests fail. Finally, if the tests
for 'A', 'B', and 'C' all fail, no further tests are needed-we must execute
statement-x. To improve the code, we rewrite it as follows:
I F C H A R • \ A' THE H statement-a;
E L S ElF CH A R • 'B' THE H statement-b;
E L S ElF CH A R • 'C' THE H statement-c;
E L S E statement-x;

6-10
PL/M-86 User's Guide Flow Control'Statements

Notice that this sequence is not a case of "nested IF statements" as described in the
preceding section. IF statements are said to be nested only when one IF statement is
inside the THEN part of another. Here, we have IF statements inside the ELSE parts
of other IF statements. This construction is called "sequential IF statements." It is
equivalent to the following:

I F CHAR • 'A' THE N statement-a;


ELSE DO;
IF CHAR • 'B' THEN statement-b;
ELSE DO;
I F CHAR • 'c' THE N statement-c;
E L 5 E statement-x;
END;
END;
Sequential IF statements are useful whenever a set of tests is to be made, but you
want to skip the remaining tests whenever one of the tests succeeds. This construction
works in such cases because all the remaining tests are in the ELSE part of the current
test.

6.3 GOTO Statements


A GO TO statement alters the sequential order of program execution by transferring
control directly to a labeled statement. Sequential execution then resumes, beginning
with the "target" statement. The GO TO statement has the following form:

GOT 0 label;
For example:

GOTO ABORT;
The appearance of label in a GOTO statement is not a "label definition"-it is a
label reference.

The reserved word GOTO can also be written GO TO, with an embedded blank.

For reasons discussed in Chapter 7, GOTO statements are restricted. The only possi-
ble GOTO transfers are the following:
• From a GO TO statement in the outer level of some block to a labeled statement
in the outer level of the same block.
• From a GOTO statement in an inner block to a labeled statement in the outer
level of an enclosing block (not necessarily the smallest enclosing block). However,
if the inner block is a procedure block, the transfer may only be to a statement
in the outer level of the main program module.
• From any point in one program module to a labeled statement in the outer level
of the main program module. To jump to such a label, you must declare the label
to have "extended scope," i.e., declare it PUBLIC in the main module and
EXTERNAL in the module containing the GOTO.

The use of GOTOs is necessary in some situations. However, in most situations where
control transfers are desired, the use of an iterative DO, DO WHILE, DO CASE,
IF, or a procedure activation (see Chapter 8) is preferable. Indiscriminate use of
GOTOs will result in a program that is difficult to understand, correct, and maintain.

6-11
Flow Control Statements PL/M-86 User's Guide

6.4 The CALL and RETURN Statements


The CALL and RETURN statements are mentioned here only for completeness,
since they do control the flow of a program. However, they are not discussed in detail
until Chapter 8.

The CALL statement is used to activate an untyped procedure (one that does not
return a value).

The RETURN statement is used within a procedure body to cause a return of control
from the procedure to the point from which it was activated.

6-12
CHAPTER 7
BLOCK STRUCTURE AND SCOPE

This chapter is intended to clarify the meaning of outer level and the concept of
scope, including the use of the linkage attributes, PUBLIC and EXTERNAL.

The outer level of a block means statements (or labels) contained in the block but
not contained in any nested blocks. The term "exclusive extent" also has this meaning.
The inner level, or "inclusive extent," includes this outer level and all nested blocks
as well.

A block "at the same lever' as another block means both are contained by exactly
the same outer blocks.

The scope of an object means those parts of a program where its name, type, and
attributes are recognized (i.e., handled according to a given declaration). An object
means a variable, label, procedure, or symbolic (named) constant (i.e., a compilation
constant or execution constant as discussed in Chapter 3). A program is the complete
set of modules that are ultimately executed as a unit.

These definitions are explained further by the text and examples that follow.

7. 1 Names Recognized Within Blocks


Throughout this manual we have seen that PL/M-86 is a block-structured language,
enabling you to implement your design for solving a problem, processing data, or
controlling hardware.

You create blocks of code containing declarations followed by executable statements.


You order and nest the blocks in such a way as to simplify and clarify the flow of
data and control. (The maximum nest is 18 blocks deep.) A collection of these blocks
that performs a single function, or a small set of related functions, is usually compiled
as one module, as discussed in Chapter 1.

Beyond the advantages of modularity, simplicity, and clarity, the nesting of blocks
serves another very basic purpose: names declared at an outer level are known to all
statements of all nested blocks as well.

You can always declare a new meaning for any such name within a nested simple-DO
or procedure block, thereby cutting off its earlier meaning for this block. But if you
don't choose this option, its meaning is established by a single declaration at an outer
level. (The only objects that don't require declarations prior to use are labels and re-
entrant procedures.)

In figure 7-1, everything inside the solid line constitutes the inclusive extent of block
MMM (in this case, module MMM). KK is known throughout this block, including
within all nested blocks.

Everything inside the dashed line constitutes the inclusive extent of block SORT.
JJ and II are known throughout this block, but not outside it, that is, not before the
label SORT or after the END SORT statement.

Everything inside the dotted line constitutes the inclusive extent of block FIND. Since
this is not a simple-DO or procedure block, declarations are not allowed. All prior
declarations shown are available for use within FIND.

7-1
Block Structure and Scope PLfM-86 User's Guide

MMM: DO; '·Beginning of module·'


DECLARE RECORD (128) STRUCTURE
(KEY BYTE,
INFO WORD);
DECLARE CURRENT STRUCTURE
(KEY BYTE,
INFO WORD);
DECLARE KK BYTE:
KK = 127;
'·Instructions here would read in data.·'

SO R T :
r----------------------------
DO;
DECLARE (JJ,II) INTEGER;
DO JJ = 1 TO 127;
CURRENT.KEY = RECORD(JJ).KEY;
CURRENT.INFO = RECORD(JJ).INFOj
· . !-.1•••=: .. ~ .J. i ............................................ .
FIND: . DO WHILE II > 0 AND .
RECORD(II-1).KEY > CURRENT.KEY;
· RECORD(II).KEY = RECORD(II-1).KEY;
· RECORD(II). INFO = RECORD(II-1).INFOj:
II = 11-1;
: END FIND; :
c
RECOR D( i' i )" : k' EY•.~ •• if R'R' E'N T' : K' E'Y' ; ........................ .
RECORD(II),INFO = CURRENT. INFO;
END;
END SORT;
-----------------------------
'·Instructions here would write out
data from the records,·'
END MMM; '·End of module·'

Figure 7-1. Inclusive Extent of Blocks

See also figure 7-2.

The shaded area is the exclusive extent (the outer level) of block SORT. The unshaded
area within SORT is the exclusive (and inclusive) extent of block FIND. To the
instructions within the FIND block, SORT's exclusive extent is an outer level. The
outermost level (or module level) is the area outside the solid lines enclosing the
SORT block.

Restrictions on Multiple Declarations

In any given block, a known name cannot be redeclared at the same level as its
original declaration. A new declaration is permitted inside a nested simple-DO or
procedure block, where it automatically identifies a new object despite the existence
of the same name at a higher level. The new object will be the only one known by
this name within its block, and it will be unknown outside its block, where the prior
name maintains its meaning. These observations also apply when a name is redeclared
in another block at the same level as. the block containing the original deClaration.

7-2
PL/M-86 User's Guide Block Structure and Scope

MMM: DO; /*Beginning of module*/


DECLARE RECORD (128) STRUCTURE
(KEY BYTE,
INFO WORD);
DECLARE CURRENT STRUCTURE
(KEY BYTE,
INFO WORD);
DECLARE KK BYTE:
KK = 127;
/*Instructions here ~ould read in data.*/

SORT:

DO WHILE II > 0 AND


RECORDCII-1).KEY> CURRENT.KEY;
RECORD{II).KEY = RECORD{II-1).KEY;
RECORDCII).INFO = RECORDCII-1). INFO;
11=11-1;
END FIND;

/fInstructions here would ~rite out


data from the records. f /
END MMM; /fEnd of module f /

Figure 7-2. Outer Level of Block SORT

When a name is declared only in a separate block at the same level, there is no way
to access it except in that block where it is declared. The definition is not at an outer
level to the block in which you are now programming. Any local declaration you
supply will establish a new separate object whose values bear no relation to those of
the other.

The reason for these rules, as for many in programming, is that there must be no
ambiguity about what address/location is meant by each name in the program. The
declaration rules above give you freedom to choose whatever names seem appropriate
within a given block, without interfering with exterior uses of them. But when you
re-declare a name, its outer-level meaning is inaccessible until execution exits the
block containing the new declaration. For example:

A: DO;
DECLARE X, Y, Z BYTE;
L1: X-2;
Y-X;
Z- X;

7-3
Block Structure and Scope PL/M-86 User's Guide

B: DO,
DECLARE X, Y BYTE;
X- 3 ;
Y .. X ;
L2: Z=X;

EHD B;
L3 : '·At this point, X=2, Y-2, Z=3, because the
value of the redeclared X was use d t 0 f ill
Z*'
'·If statement L2 were outside the loop labeled
B, then Z would be 2 because the outer X
value would be used.·'

7.2 Extended Scope: The PUBLIC


and EXTERNAL Attributes
These attributes permit you to extend the scope of names for all objects except
modules; a module name may not be declared with either attribute.

By ""extend the scope," we mean make the names available for use in modules other
than the one where they are defined. (The names are already available to nested
blocks in this module.) To be specific, this includes names for variables, labels,
procedures, and execution constants.

For example, the statement:

DECLARE FLAG BYTE PUBLIC;

causes a byte to be allocated, named FLAG, and its address made known to any other
module where the following declaration occurs:

DECLARE FLAG BYTE EXTERHAL;

Similarly, if one module has a procedure declaration block that begins:

SUMMER: PROCEDURE (A,B) WORD PUBLIC;


DECLARE (A,B) BYTE;
. '·other declarations can go here·'
. '·executable statements go here,
defining the procedure·'

EHD SUMMER;

then any other module may invoke SUMMER if it first declares:

SUMMER: PROCEDURE (A,B) WORD EXTERNAL;


,fA,B can be any names·'
DECLARE (A,B) BYTE;
!fbut these names must match them,f!
!fand each type must match its public definitionf!
END SUMMER;

7-4
PLfM-86 User's Guide Block Structure and Scope

Since no ambiguity of location or definition is permissible, the use of PU BLI C and


EXTERNAL must follow a strict set of rules, as follows:

I. These attributes may only be used in a declaration at the outermost level of a


module, i.e., never in a nested block.

2. Only one may appear on any declaration, and only once. Thus:

DECLARE ZETA BYTE PUBLIC EXTERNAL; l*error*1


DECLARE RHO WORD PUBLIC PUBLIC; I*error *1
and similar constructs are all invalid.

3. Names may be declared PUBLIC, at most, once. The PUBLIC declaration is


the defining declaration: the address it creates is used in each procedure or module
where the same name is declared EXTERNAL. Clearly you must not create
more than one PUBLIC address for any name.

4. Names may be declared EXTERNAL only if they are also declared PUBLIC in
a different module of the program. The EXTERNAL attribute is essentially a
request to use a PUBLIC address. An EXTERNAL without a PUBLIC is a
dead letter. Lack of a definition elsewhere will result in a link-time error.

5. Where the name is declared EXTERNAL, it must be given the same type as
where it is declared PUBLIC. Any contradiction of type would violate the inten-
tion to use the location(s) and content(s) defined elsewhere. If the name is declared
PUBLIC and has the DATA attribute, all EXTERNAL declarations must also
use DATA.

6. Similarly, names declared EXTERNAL must not be given a location (using the
AT clause), or an initialization (using DATA or INITIAL). Such usage would
contradict the fact that names are being defined in another module. However, in
the module where this name is declared PUBLIC, the use of AT, DATA, or
INITIAL is allowed.

7. Neither PUBLIC nor EXTERNAL may be applied to a name that is based. For
example:

DECLARE PTR1 POINTER;


DECLARE V1 BASED PTR1 PUBLIC;
is invalid. The reason: by definition, V I has no home of its own; its location is
always determined by PTRI. Thus, to declare VI PUBLIC or EXTERNAL does
not permit the correct assignment of addresses. PTR I, on the other hand, always
contains the current address of V I. Declaring the base, in this case PTR I, to be
PUBLIC and EXTERNAL is always permissible since it permits valid results.

NOTE
The PL/M-86 compiler will generate external records only for items that
are actually referenced in the program.

(Four additional restrictions on the use of PUBLIC and EXTERNAL procedures


appear in Chapter 8.)

7-5
Block Structure and Scope PL/M-86 User's Guide

Following these rules will permit consistent and reliable execution of programs using
names with extended scope. A PUBLIC definition occurring in one module will then
be used by all related references to that name in separate modules; that is, references
which declare the name' EXTERNAL. The diagram below illustrates this:

(It 0D1 : DO
DECLARE V1 BYTE PUBLIC;

EHD MOD1;

MOD2: DO;
DECLARE V1 BYTE EXTERHAL;
GG4: PROCEDURE PUBLIC;

EHD GG4;
EHD MOD2;

Both references to V 1 will use the same definition (location) for VI, namely, the
definition in module MODI. Similarly, if any module needed to call procedure QQ4,
it would first need a declaration like this:

GG4: PROCEDURE EXTERHAL


EHD GQ4 ;
so that a subsequent CALL QQ4 would correctly pass control to that procedure in
module MOD2.

7.3 Scope of Labels and Restrictions on GOTOs


Labels are subject to exactly the same rules of scope discussed above.

One consequence is that a label is unknown outside the block where it is declared. As
discussed in Chapter 1, a label is either declared explicitly at the beginning of a
simple-DO or procedure block, or the compiler considers it to be declared there as
soon as it is defined by use anywhere in the block. Therefore, the discussion of what
names are known in which blocks applies directly to labels as well as to other names.

The label on a block is not part of the block it names. For example, the name on the
DO enclosing the module itself is not part of that DO; it merely names it. For nested
blocks, a label is again not part of the block it names, but belongs instead to the outer
level as part of that first enclosing block.

If a name used as a label on a block is defined inside that block, it will name a new
thing, be it label, variable, or constant. There will be no confusion with the outer
label name. This fact leads to important restrictions on the use of the GOTO state-
ment:
1. It is impossible for a GOTO to transfer control from an outer block to a labeled
statement inside a nested block.
2. Moreover, a GOTO can transfer control from one block to another in the same
module only if the target block encloses the one containing the GOTO (and only
if the name of that target label is not declared in the nested block.)

7-6
PL/M-86 User's Guide Block Structure and Scope

Furthermore, a label with the PUBLIC attribute is permitted only in the main module.
(This has the interesting consequence of forcing all other transfers of control-that
is, those not involving a return to the main module-to use procedure calls. This
favors the development of orderly, modularized, traceable programs.)

In fact, only four GOTO transfers are possible, as follows:


I. From one point in a block to another statement also in the same level of the same
block
2. From an inner, nested DO-block (not a nested procedure) to a statement in the
outer level of any enclosing block
3. From a procedure to a statement in the outer level of the main program in the
same module
4. To a main-program label that is declared PUBLIC, from any point in any module
that declares that label EXTERNAL

(Recall that only labels at the outer level of a main program may be declared
PUBLIC.)

Given the program structure and declarations shown in figure 7-3, the only valid
GOTO transfers are shown in figure 7-4. A single-headed arrow means the transfer
is valid only in the direction shown. A double-headed arrow means that a GO TO can
be used in either direction.

MAIN: DOj
DECLARE (LAB33, LAB77) LABEL PUBLICj
DECLARE IT BYTEj

LAB33:
DOj

ENDj

LAB77:
DO WHILE IT > 0;

ENDj

END MAlHi

Figure 7-3. Sample Program Modules Illustrating Valid GOTO Usage

7-7
Block Structure and Scope PLfM-86 User's Guide

MOD1: DO;
P 1: PROCEDURE;
DECLARE (LAB33,LAB77) LA~EL EXTERNAL;
L 1: • • • ,
DO;
DECLARE KO BYTE;
P2: PROCEDURE

L2: .,

END P2;
L3 : . ,

END P1;
END MOD1;

/I10D2: DO;

P4: PROCEDURE;
DECLARE (LAB33,LAB77) LABEL EXTERNAL;

L4:

L5 : i
DO;
L6:

ENDj

L7:

END P4j
L8 :
END MOD2j

Figure 7-3. Sample Program Modules Illustrating Valid GOTO Usage (Cont'd.)

7-8
PLjM-86 User's Guide Block Structure and Scope

Figure 7-4 illustrates legal GOTO transfers that are the only transfers permitted
among the given labels in figure 7-3.

LAB33

OR

LAB77

Figure 7-4. Valid GOTO Transfers 121636-1

7-9
CHAPTER 8
PROCEDURES

A procedure is a section of PL/M-86 code that is declared without being executed,


and then activated from other parts of the program. A function reference or CALL
statement activates the procedure, causing the procedure code to be executed (even
if it is physically located elsewhere). Program control is then transferred from the
point of activation to the beginning of the procedure code, and the code is executed.
Upon exit from the procedure code, program control is passed back to the statement
immediately after the point of activation.

The use of procedures forms the basis of modular programming. It facilitates making
and using program libraries, eases programming and documentation, and reduces the
amount of object code generated by a program. The following sections review how to
declare and activate procedures.

8. 1 Procedure Declarations

You must declare procedures, just as you must declare variables. Thereafter, any
reference to a procedure must occur within the scope defined by the procedure decla-
ration. Also, a procedure may not be used (called, or invoked in an expression) until
after the END statement of the procedure declaration (unless re-entrant-see
section 8.5).

A procedure declaration consists of three parts: a PROCEDURE statement, a


sequence of statements forming the "procedure body," and an END statement.

The following is a simple example:

DOOR.CHECK:PROCEDUREj
IF FRONT.DOOR.LOCKED AND SIDE.DOOR.LOCKED
THEN CALL POWER.ONi
ELSE CALL DOOR.ALARMi
END DOOR.CHECKi
where POWER$ON and DOOR$ALARM are procedures declared elsewhere in the
same program.

NOTE
The name in a PROCEDURE statement has the same appearance as a label
definition-but it is not considered a label definition, and a procedure name
is not a label. PROCEDURE statements may not be labeled.

The name is a PL/M.::86 identifier, which is associated with this procedure. The scope
of a procedure is governed by the placement of its declaration in the program text,
just as the scope of a variable is governed by the placement of its DECLARE state-
ment (see Chapter 7 for a detailed description). Within this scope, the procedure can
be activated by the name used in the PROCEDURE statement.

A procedure declaration, like a DO block, controls the scope of variables as described


in Chapter 7. Also, like a simple DO block, a procedure declaration may contain
DECLARE statements, which must precede the first executable statement in the
procedure body.

8-1
Procedures PL/M-86 User's Guide

As in a DO block, the identifier in the END statement has no effect on the program,
but helps legibility and debugging. If used, it must be the same as the procedure
name.

The parameter list and the type are discussed in the following two sections.

Parameters
Formal parameters are non-based scalar variables declared within a procedure
declaration; their identifiers appear in the parameter list in the PROCEDURE
statement. The identifiers in the list are separated by commas and the list is enclosed
in parentheses. No subscripts or member-identifiers are allowed in the parameter list.

If the procedure has no formal parameters, the parameter list (including the
parentheses) is omitted from the PROCEDURE statement.

Each formal parameter must be declared as a non-based scalar variable in a


DECLARE statement preceding the first executable statement in the procedure body.
However, procedure parameters are not stored according to the same rules as other
declared variables. In particular, do not assume that a parameter is stored
contiguously with other variables declared in the same factored variable declaration.

When a procedure that has formal parameters is activated, the CALL statement or
function reference contains a list of actual parameters. Each actual parameter is an
expression whose value is assigned to the corresponding formal parameter in the
procedure before the procedure begins to execute.

For example, the following procedure takes four parameters, called PTR, N, LOWER,
and UPPER. It examines N contiguously stored BYTE variables. The parameter
PTR is the location of the first of these variables. If any of these variables is less than
the parameter LOWER or greater than the parameter UPPER, the ERRORSET
procedure (declared elsewhere in the program) is activated:

RANGE$CHECK: PROCEDURE(PTR,H,LOWER,UPPER)i
DECLARE PTR POIHTERi
DECLARE (H,LOWER,UPPER,I)BYTEi
DECLARE ITEM BASED PTR(1)BYTE;
DO I .. 0 TO N-1i
IF (ITEM(I) < LOWER) OR (ITEM(I) > UPPER)
THEN CALL ERRORSET;
I'ERRORSET is a procedure declared eisewhere'l
END;
END RANGE$CHECK;
Notice that the array ITEM is declared to have only one element. Since it is a based
array, a reference to any element of ITEM is really a reference to some location
relative to the location represented by PTR. In writing the procedure
RANGE$CHECK, we must supply a dimension specifier above zero for ITEM so
that references to ITEM can be subscripted. But it does not matter what the dimen-
sion specifier is. We arbitrarily use 1 here.

Having made this declaration, suppose that we have 25 variables stored contiguously
in an array called QU ANTS. We want to check that all of these variables have values
within the range defined by the values of two other BYTE variables, SMALL and
LARGE.

8-2
PL/M-86 User's Guide Procedures

We write:

CALL RANGE.CHECK C,QUANTS, 25, SMALL, LARGE);

When this call statement is processed, the following sequence occurs:


• The four actual parameters in the CALL statement-®QUANTS, 25, SMALL,
and LARGE-are assigned to the formal parameters PTR, N, LOWER, and
UPPER, which were declared within the procedure RANGE$CHECK. Since
ITEM is based on PTR and the value of PTR is @QUANTS, every reference to
an element of ITEM becomes a reference to the corresponding element of
QUANTS.
• The executable statements of the procedure RANGE$CHECK are executed, and
if any of the values are less than the value of SMALL or greater than the value
of LARGE, the procedure ERRORSET is activated.
• Finally, control returns to the statement following the CALL statement.

Notice how the use of a based variable, with the base passed as a parameter, allows
the procedure to have its own unchanging name (ITEM) for a set of variables which
may be a different set each time the procedure is activated.

When a procedure has more than one parameter, PL/M -86 does not guarantee
the order in which actual parameters will be evaluated when the procedure
is activated. If one actual parameter changes another actual parameter, the
results are undefined. This can occur if an expression used as an actual
parameter contains an embedded assignment or function reference which
changes another actual parameter for the same procedure. See the next
caution also.

Typed Versus Untyped Procedures

The RANGE$CHECK procedure (shown above) is an untyped procedure. No type


is given in the PROCEDURE statement, and it does not return a value. An untyped
procedure is activated by using its name in a CALL statement, as explained in
section 8.2.

A typed procedure, also called a junction, has a type in its PROCEDURE statement:
BYTE, WORD, DWORD, INTEGER, REAL, POINTER, or SELECTOR. Such
a procedure returns a value of this type, which is used in an expression or stored as
the value of a variable. The procedure is activated by using its name as an operand
in an expression; this special type of variable reference is called a ""function
reference. "

When the expression is processed at run time, the function reference causes the
procedure to be executed. The function reference itself is then replaced by the value
returned by the procedure. The expression containing the function reference is then
evaluated, and program execution continues in normal sequence.

Like an untyped procedure, a typed procedure may have parameters.. They are handled
as described in the previous section.

The body of a typed procedure must always contain a RETURN statement with an
expression, as explained later in this chapter.

8-3
Procedures PLfM-86 User's Guide

The body of a typed procedure may contain code (such as an assignment


statement) that changes the value of some variable declared outside the
procedure. This is called a "side effect."
Recall that PLfM-86 does not guarantee the order in which operands in an
expression are evaluated. Therefore, if a function used in an expression
changes the value of another variable in the same expression, the value of
the expression depends on whether the function reference or the variable is
evaluated first.
If the analysis of the expression does not force one of these operands to be
evaluated before the other, then the value of the expression is undefined.
This situation can be avoided by using parentheses to segregate any typed
procedure that has a side effect, or by using this procedure in an assignment
statement first to create an unambiguous sequence.

8.2 Activating a Procedure-Function References


and CALL Statements

The two forms of procedure activation depend on whether the procedure is typed or
untyped. An untyped procedure is activated by means of a CALL statement, which
has the form:

CAL L name

or:

CAL L name (parameter list);

An example is the following:

CALL REORDER (,RANKSTABLE,3);


(An alternate form of the CALL statement is discussed later.)

A typed procedure is activated by means of a function reference, which is an operand


in an expression. A function reference has the form:

name

or

name (parameter list)

This occurs as an operand in an expression, as in the following example:

TOTAL • SUBTOTAL + SUMSARRAY (,ITEMS,COUHT);


where SUM$ARRA Y is a previously declared typed procedure. The value added to
SUBTOTAL will be the value returned by SUM$ARRAY using the actual param-
eters (@ITEMS, COUNT). See the cautionary note in section 8.1.

8-4
PL/M-86 User's Guide Procedures

In both forms of procedure activation, the elements of the parameter list are called
"actual parameters" to distinguish them from the uformal parameters" of the proce-
dure declaration. At the time of activation, each actual parameter is evaluated and
the result is assigned to the corresponding formal parameter in the procedure decla-
ration. Then, the procedure body is executed. Any PL/M-86 expression may be an
actual parameter if its type is the same as that of the corresponding formal
parameter.

The actual parameter list in a procedure activation must also match the formal
parameter list in the procedure declaration-that is, it must contain the same number
of parameters of the same type in the same order. If the procedure is declared without
a formal parameter list, then no actual parameter list can be used in the activation.

As in expression evaluation and assignment statements (see Chapter 4), a few type
conversions are performed automatically when necessary in activating and returning
from a procedure. The built-in explicit type conversion procedures of Chapter 9 can
also be used to force the value of an expression to a desired type.

Indirect Procedure Activation

The CALL statement, in the form shown _above, activates an untyped procedure by
its name. It is also possible to activate an untyped procedure by its location. This is
done by means of a CALL statement with the form:

CAL L identifier [.member-identifier][(parameter lisl)];

The identifier may not be subscripted, though it may be a structure reference. It must
be a fully qualified POINTER or WORD type variable reference, and its value is
assumed to be the location of the entry-point of the procedure being activated.

NOTE
Calls through 32-bit POINTERs will be translated into "long" calls while
those through 16-bit WORDs or POINTERs (in the SMALL case) will be
translated into "short" calls (relative to the current code segment). The
compiler will issue a warning if the wrong addressing type is used to gain a
procedure address for later indirect calls.

A normal CALL uses the name of the procedure; the compiler checks to make sure
that the correct number of parameters is supplied and performs automatic type
conversion on the actual parameters.

When the CALL statement uses a location, the compiler does not check the number
of parameters or perform type conversion. If the number of parameters is wrong or
if an actual parameter is not of the same type as the corresponding formal parameter,
the results are unpredictable.

8.3 Exit from a Procedure: The RETURN Statement


The execution of a procedure is terminated in one of three ways:
• By execution of a RETURN statement within the procedure body. A typed
procedure must terminate with a RETURN statement that has an expression.
• By executing a GOTO to a statement outside the procedure body. The target of
the GOTO must be at the outer level of the main program (see Chapter 7).
• By reaching the END statement that terminates the procedure declaration.

8-5
Procedures PLfM-86 User's Guide

The" RETURN statement takes one of two forms:

RETURN;
or

RET URN expression;

The first form is used in an untyped procedure. The second form is used in a typed
procedure. The value of expression becomes the value returned by the procedure. It
is evaluated as if it were being assigned to a variable of the same type as used on the
PROCEDURE statement.

"8.4 The Procedure Body


The statements within the procedure body may be any valid PL/M-86 statements,
including CALL statements and nested procedure declarations.

Examples
1. The following is a typed procedure declaration:

AVG: PROCEDURE (X,Y) REAL;


DECLARE (X,Y) REAL;
RETURN (X + Y)/2.0;
END AVG;
This procedure could be used as follows:

LOW • 3.0;
HIGH • 4.0;
MEAN • AVG (SMALL, LARGE);
The affect would be to assign the value 3.5 to MEAN.
2. The following is an untyped procedure:

ADUT: PROCEDURE (ITEM);


DECLARE ITEM WORD;
IF ITEM • DFFH THEN COUNTER • COUNTER + 1;
RETURN;
END ADUTj
Here COUNTER is some variable declared outside the procedure, i.e., it is a
"global" variable. This procedure could be activated as follows:

CALL AOUT (UNKNOWN);


If the value of the variable UNKNOWN is greater than or equal to OFFH, the
value of COUNTER will be incremented.
3. This example demonstrates an important use of based variables:

SUM.ARRAY: PROCEDURE (PTR,N) BYTE;


DECLARE PTR POINTER,
ARRAY BASED PTR(1) BYTE,
(N,SUM,I)BYTE;

8-6
PL/M-86 User's Guide Procedures

SUM-Oj
DO I - 0 TO H;
SUM - SUM + ARRAV(I);
E HD;
RETURN SUM;
END SUM.ARRAV;
This procedure returns the sum of the first N + I elements (from the Oth to the
Nth) of a BYTE array pointed to by PTR. Notice that ARRAY is declared to have
I element. Since it is a based variable, no space is allocated for it. It must be declared
as an array (with a non-zero dimension) so that it can be subscripted in the iterative
DO block. The choice of I as the constant in the dimension specifier is arbitrary and
does not restrict the value of N that may be supplied when the procedure is activated.

The procedure could be used as follows to sum the elements of a IOO-element BYTE
array named PRICE, and to assign the sum to the variable TOTAL:

TOTAL - SUM.ARRAV(,PRICE,99);

8.5 The Attributes: PUBLIC and EXTERNAL,


INTERRUPT,REENTRANT
The PUBLIC and EXTERNAL attributes can be included in PROCEDURE state-
ments to give procedures extended scope. Extended scope is discussed in Chapter 7.

A procedure declaration with the PUBLIC attribute is called a "defining declara-


tion." A procedure declaration with the EXTERNAL attribute is called a "usage
declaration." Most of the rules for PUBLIC and EXTERNAL appear in Chapter 7.
The following additional rules apply to the use of the EXTERNAL attribute in a
procedure declaration:
1. The EXTERNAL attribute may not be used in the same PROCEDURE state-
ment as a PUBLIC or REENTRANT attribute (see below). Note, however, that
the defining declaration of a procedure may have the REENTRANT attribute.
2. A usage (EXTERNAL) declaration of a procedure should have the same number
of parameters as the defining (PUBLIC) declaration. Variable types and dimen-
sion specifiers should match up in the same sequence in both declarations. The
names of the parameters need not be the same. Note that a discrepancy between
the parameter lists in the defining declaration and in a usage declaration will not
be automatically detected. (See Chapter II for a description of the TYPE control
to detect such an error at module linkage time.)
3. The procedure body of a usage declaration may not contain anything except the
declarations of the formal parameters. The formal parameters must be declared
with the same types as in the defining declaration.
4. No labels may appear in a usage declaration.

NOTE
The PL/M-86 compiler will only generate external records for items that
are actually referenced in the program.

For example, we can alter the procedure AVG (from example I above) by giving it
the PUBLIC attribute:

AVG: PROCEDURE (X,V) REAL PUBLIC;


DECLARE (X,V) REAL;
RETURN (X + V)/2.0;
EHD AVG;

8-7
Procedures PL/M-86 User's Guide

In another module, we can have a usage declaration:

AVG: PROCEDURE (X,V) REAL EXTERNAL;


DECLARE (X,V) REAL;
END AVG;
Now, in the module with the usage declaration, we can reference AVG in an execut-
able statement:

MIDDLE • AVG (FIRST, LATEST);


thereby activating the procedure AVG as declared in the first module.

Interrupts and the INTERRUPT Attribute

The INTERRUPT attribute allows you to define a procedure to handle some condi-
tion signaled by an iAPX 86 interrupt, e.g., from a peripheral device. A procedure
with this attribute is activated when the corresponding interrupt signal is received in
the iAPX 86-based system. The PLJM-86 statement CAUSE$INTERRUPT
(constant) can also be used to initiate an interrupt signal (see Chapter 10).

Note that the following discussion applies only to interrupt procedures; interrupt tasks
are discussed in Appendix G.

The INTERRUPT attribute can be used only in declaring an untyped procedure with
no parameters at the outermost level of a program module. It must be declared
PUBLIC or EXTERNAL (and optionally REENTRANT). The form is

INTERRUPT n
where n is any decimal number from 0 to 255. Each number can only be used once
in a program. Each such procedure is then referred to as an interrupt procedure.
Such a procedure is necessary if you wish to provide non-default handling of excep-
tion conditions arising in floating-point arithmetic (see appendixes F and G).

The following discussion of the iAPX 86 interrupt mechanism clarifies how interrupt
procedures work. Additional information can be found in Appendix G.

The iAPX 86 interrupt mechanism has two states: enabled or disabled. The ENABLE
statement allows interrupts to- take affect and the DISABLE statement prevents them
from having any affect. The HALT statement also enables interrupts. (The state of
the iAPX 86 interrupt mechanism upon initialization is determined by the operating
system.)

When some peripheral device sends an interrupt to the iAPX 86 CPU, it is ignored
if the interrupt mechanism is disabled. If interrupts are enabled, the interrupt is
processed as follows:
1. The CPU completes any instruction currently in execution.
2. The CPU sends an "acknowledge interrupt" signal, then the interrupting device
sends its interrupt number.
3. The interrupt mechanism is disabled. This prevents any other device from
interfering.
4. Control passes to the interrupt procedure whose number matches the number
sent by the peripheral device. If no such procedure has been established, the results
are undefined, since the vector that transfers control may be uninitialized.

8-8
PLJM-86 User's Guide Procedures

5. When the procedure is through (by executing a RETURN or reaching the END
of the procedure), the interrupt mechanism is enabled so other devices may be
serviced, and control returns to the point where the interrupt occurred.
It is possible (as with other untyped procedures) for the procedure to terminate
by executing a GOTO with a target outside the procedure in the outer level of
the main program module. In this case, control will never be returned to the point
where the program was interrupted, and interrupts will not be enabled
automatically.

The following is an example of an interrupt procedure for a hypothetical system where


a peripheral device initiates an interrupt whenever the temperature of a device exceeds
a certain threshold. The interrupt procedure turns on the annunciator light, updates
a status word, and returns control to the program:

HITEMPj PROCEDURE INTERRUPT PUBLIC:


CALL ANNUNCIATOR(1)j
/* This will result in an output
from the iAPX 8086 to ~urn on
ann u n c i is tor 1 i g h t numb e r 1, the
high-temperature warning. */

ALERT • ALERT OR 00000010Bj


/* This puts a 1 in one of the
bit positions of ALERT, which
contains a bit pattern represent-
ing current alerts. */

END HITEMPj

Activating an Interrupt Procedure with a CALL Statement

A procedure with the INTERRUPT attribute may also be activated by means of a


CALL statement, like any other untyped procedure. However, when this is done, the
programmer must bear in mind that interrupts are not automatically disabled upon
activation of the procedure. If interrupts are enabled when the CALL is executed,
then unless the procedure has a DISABLE as its first executable statement, it will
run with interrupts enabled and should have the REENTRANT attribute (see next
section).

IWARNING I
If using an interrupt procedure that will call another interrupt procedure,
you must manually extend the length of the -stack storage, as the compiler
allocates only enough space to save one procedure. See Appendix G and use
the LINK and LOC sequence (the Family Utilities User's Guide) for more
information.

In every other respect, an interrupt procedure activated by a CALL statement is like


any other procedure so activated.

NOTE
Unlike PL/M-80, PL/M-86 interrupt routines activated with a CALL state-
ment do not alter the interrupt enable status. This means that termination
of the procedure by means of a RETURN statement or the END statement
will not automatically enable interrupts.

8-9
Procedures PL/M-86 User's Guide

Section 6 of Chapter 9 discusses the built-in function INTERRUPT$PTR, which


returns the interrupt entry point, given an interrupt procedure name, and also the
built-in procedure SET$INTERRUPT, which sets an interrupt vector given the
interrupt procedure name and number.

The CAUSE$INTERRUPT statement causes a software interrupt to the vector


specified in the statement:

CA USE $ I H T ERR UP T(constant) 1

where constant is in the range 0 to 255.

Reentrancy and the REENTRANT Attribute

The REENTRANT attribute allows a procedure to suspend execution temporarily,


restart with new parameters, and then later complete the original execution success-
fully as if there had been no interruption.

This ability is desirable in two circumstances: (1) if your procedure (PROCl) activates
itself (called direct recursion), or (2) if your procedure activates another procedure
(PROC2) that will reactivate PROCI before PROCI has finished its original
processing (called indirect recursion).

Without the REENTRANT attribute, storage for procedure variables is allocated


statically, in fixed locations within the Data Segment of the object module.
Re-entering such a procedure would write over the earlier contents of such locations
making it impossible to complete the original, suspended execution.

When you use the attribute REENTRANT in declaring a procedure, its variables
are not stored with other variables in the data section, but are stored on the stack.
Thus preserved, each set can be used independently by each invocation of the proce-
dure.

Multiple sets of variables may therefore need to be stored on the stack during recur-
sive use of such procedures. You must be sure to specify (at relocation and link time)
a stack size large enough for all such storage needed by all multiple invocations that
may be active at one time.

A procedure with the REENTRANT attribute may be activated before it is declared.


This permits direct recursion, where the procedure activates itself, and indirect
recursion, where the procedure activates a second procedure and the second proce-
dure activates the first--or activates a third procedure, which activates a fourth, etc.,
with the resulLJhat the first procedure is activated before it terminates.

'Fhe following rules summarize the use of the REENTRANT attribute:


• Any procedure that may be interrupted and is also activated from within an
interrupt procedure should have the REENTRANT attribute.
Note that this may apply to an interrupt procedure that runs with interrupts
enabled because it contains an ENABLE statement. If there is any possibility
that it will be interrupted by its own interrupt, it should have the REENTRANT
attribute. This situation is equivalent to recursion.
• Any procedure that is directly recursive (activates itself) should have the
REENTRANT attribute.
• Any procedure that is indirectly recursive (activates another procedure and is
activated itself as a result) should have the REENTRANT attribute.

8-10
PL/M-86 User's Guide Procedures

• Any procedure that is activated by a reentrant procedure should also have the
REENTRANT attribute.

In other words: if there is any possibility that a procedure can be activated while it is
already running, it should be reentrant.
• The REENTRANT attribute cannot be used in the same declaration as the
EXTERNAL attribute. (It may be used with the PUBLIC attribute.)
• The REENTRANT attribute may only be used in a PROCEDURE statement
at the outer level of a module (discussed in Chapter 7).
• A procedure declaration with the REENTRANT attribute may not have another
procedure declaration nested inside it.

8-11
CHAPTER 9
BUILT-IN PROCEDURES,
FUNCTIONS. AND VARIABLES

Built-in procedures, functions, and variables act as if they were declared in an all
encompassing global block invisible to the programmer.

These identifiers are subject to the rules of scope. This means the name of a built-in
procedure or variable can be declared to have a local meaning within the program.
Within the scope of such a declaration, the built-in is unavailable. This distinguishes
these identifiers from reserved words, listed in Appendix A, which cannot be used as
identifiers in declarations.

No built-in procedure may be used within a location reference. No built-in variable


may be used within a location reference, except as specifically noted in the following
sections.

9. 1 Obtaining Information About Variables


PL/M-86 has three built-in procedures that take variable names as actual parameters
and return information based on the declarations of the variables: LENGTH, LAST,
and SIZE.

The LENGTH Function

LENGTH is a WORD function that returns the number of elements in an array. It


is activated by a function reference with the form:

LEN GTH ( variable-ref)


where
variable-ref must be a non-subscripted reference to an array.

The array may be a member of a structure; it may not be an EXTERNAL array


using the implicit dimension specifier (see section 3.2).

The WORD value returned is the number of elements in the array-that is, it is
equal to the dimension specifier in the array declaration.

If the array is not a structure member, then the reference must be an unqualified
variable reference. If the array is a structure member, then the reference is a partially
qualified variable reference (see section 5.3). For example, given the declaration:

DECLARE RECORD STRUCTURE (KEY BYTE,


INFO(3) WORD);
then LENGTH(RECORD.INFO} is a valid function reference and returns a WORD
value of 3.

If the array is a member of a structure, and the structure is an element of an array,


a special case arises. Given the declaration:

DECLARE LIST (4) STRUCTURE (KEY BYTE,


INFO (3) WORD);

9-1
Built-ID Procedures, Functions, and Variables PL/M-86 User's Guide

then all of the following function references are correct and return the value 3.

LENGTH(LIST(O).IHFO)
LEHGTH(LIST(1).IHFO)
LEHGTH(LIST(2). INFO)
LEHGTH(LIST(3).IHFO)
In other words, the subscript for the array LIST is irrelevant wheha member-identifier
is supplied, since the arrays within the structures are all the same length. PL/M-86
allows a "shorthand" form of partially qualified variable reference in the LENGTH,
LAST, and SIZE function references. For example:

LEHGTH(LIST.IHFO)
is a valid function reference and returns the value 3.

The LAST Function

LAST is a WORD function that returns the subscript of the last element in an array.
It is activated by a function reference with the form:

LAS T (variable-ref)

where
variable-ref must be a non-subscripted reference to an array.

The array may be a member of a structure; it may not be an EXTERNAL array


using the implicit dimension specifier (see section 3.2).

The WORD value returned is the subscript of the last element of the array. Note
that for a given array, LAST will always be one less than LENGTH.

As in the LENGTH function, a Hshorthand" form of partially qualified variable


reference is allowed in the case where the array is a member of a structure and the
structure is an array element.

The SIZE Function

SIZE is a WORD function that returns the number of bytes occupied by an array or
structure. It is activated by a function reference with the form:

5 I Z E ( variable-ref)

where
variable-ref is a fully qualified, partially qualified, or unqualified refer-
ence to any scalar, array, or structure. The variable-ref may
not be an EXTERNAL declaration that uses the implicit
dimension specifier (see section 3.2).

The WORD value returned is the number of bytes required by the object referenced.

If the reference is fully qualified, it refers to a scalar, and the value is the number of
bytes required for the scalar. If the reference is unqualified, it refers to an entire
structure or array, and the value is the total number of bytes required for the struc-
ture or array.

9-2
PL/M-86 User's Guide Built-In Procedures, Functions, and Variables

If the reference is partially qualified, it refers either to a structure member that is an


array, or to an array.element that is a structure. The value is the number of bytes
required for the array or structure.

As in the LENGTH function, a "shorthand" form of partially qualified variable


reference is allowed in the case where the array or scalar is a member of a structure
and the structure is an array element.

9.2 Explicit Type and Value Conversions


The ten functions in this section provide explicit conversion from one type to another
and from signed values to or from absolute magnitudes.

Explicit type-conversion functions are invoked as

function-name ( expression)

where
function-name has a type and expression has a value.

In table 9-1, each function name is followed by its type, the expression type expected,
the purpose of the function, and the nature of the value it returns to the expression
that invoked it.

Table 9-1. Explicit Type and Value Conversions


Parameter
Procedure Type ExpreSSion Function Result Returned
Name Type

BYTE Converts WORD value BYTE value unchanged


LOW- BYTE
WORD to BYTE value Low-order byte of WORD

WORD DWORD Converts DWORD Low-order word of DWORD


value to WORD value

BYTE Converts WORD value o(zero)


HIGH BYTE
WORD to BYTE value High-order byte of WORD

WORD DWORD Converts DWORD High-order word of DWORD


value to WORD value

DOUBLE WORD BYTE Converts BYTE value WORD value, by appending 8


to WORD value high-order zero bits

DWORD WORD Converts WORD value DWORD value, by appending 16


to DWORD value high-order zero bits
DWORD DWORD value unchanged

FLOAT REAL INTEGER Converts INTEGER Same value of type REAL


value to REAL value

FIX INTEGER REAL Converts REAL value INTEGER value modulo 32768,
to INTEGER value i.e., within range ± 32767
(rounds toward zero)

BYTE Converts BYTE or Corresponding INTEGER value


INT INTEGER WORD WORD to INTEGER; within range 0 to 32767
interprets parameter as
positive

9-3
Built-In Procedures, Functions and Variables PL/M-86 User's Guide

Table 9-1. Explicit Type and Value Conversion (Cont'd.)


Parameter
Procedure Type Expression Function Result Returned
Name Type

INTEGER BYTE Converts a WORD BYTE value is extended with 8


SIGNED WORD value to an INTEGER high-order zeros; WORD value
value unchanged

UNSIGN WORD INTEGER Converts an INTEGER The bit pattern is unchanged but
value to a WORD value can now be used in WORD
expressions

ABS REAL REAL Converts negative Absolute value of expression


value to positive supplied. If positive, returned
unchanged; if negative,
- (expression) is returned

lABS INTEGER INTEGER Converts negative Absolute value of expression


value to positive supplied. If positive, returned
unchanged; if negative,
-(expression) is returned

The LOW, HIGH, and DOUBLE Functions

LOW and HIGH are BYTE functions that convert WORD values to BYTE values,
or WORD functions that convert DWORD values to WORD values. They are
activated by function references with the forms:

LOW (expression)
H I GH ( expression)

where
expression has a DWORD, WORD, or BYTE value.

If expression has a DWORD value, LOW returns the value of the low-order (least
significant) word of the expression value whereas HIGH returns the value of the
high-order (most significant) word of the expression value.

If expression has a WORD value, LOW returns the value of the low-order (least
significant) byte of the expression value whereas HIGH returns the value of the high-
order (most significant) byte of the expression value.

If expression has a BYTE value, then LOW will return this value unchanged.
However, HIGH will return o.

DOUBLE is a WORD function that converts a BYTE value to a WORD value, or a


DWORD function that converts a word value to a DWORD value. It is activated by
a function reference with the form:

D 0 UB L E expression

where
expression has a BYTE, WORD, or DWORD value.

9-4
PL/M-86 User's Guide Built-In Procedures, Functions and Variables

If expression has a BYTE value, the function appends 8 high-order zero bits to convert
it to a WORD value and returns this WORD value. If expression has a WORD
value, the function appends 16 high-order zero bits to convert it to a DWORD value
and returns this value. If expression has a DWORD value, the function returns it
unchanged.

The FLOAT Function

FLOA T is a REAL function that converts an INTEGER value to a REAL value. It


is activated by a function reference, with the form:

FLO AT ( expression)

where
expression has an INTEGER value.

FLOAT converts the INTEGER value to the corresponding REAL value and returns
this REAL value.

The FIX Function

FIX is an INTEGER function that converts a REAL value to an INTEGER value.


It is activated by a function reference with the form:

F I X ( expression)

where
expression has a REAL value.

FIX rounds the REAL value to the nearest INTEGER. If both INTEGERs are
equally near, FIX rounds to the even one. The resulting INTEGER value is then
returned. Thus, FIX(1.4) would result in the INTEGER value 1, FIX( -1.8) in -2,
FIX(3.5) in 4, and FIX(6.5) in ~.

If the result calculated by FIX is not within the implemented range of INTEGER
values, the result is undefined.

NOTE
FIX is affected by your choice of rounding mode-see section 10.5. The above
examples assume the default mode, which is "round to nearest or even."

The INT Function

T is an INTEGER function that converts a BYTE or WORD value to an INTEGER


value. It is activated by a function reference with the form:

I HT ( expression)

where
expression has a BYTE or WORD value.

INT interprets the BYTE or WORD value as a positive number and returns the
corresponding INTEGER value.

If the result calculated by INT is not within the implemented range of INTEGER
values, the result is undefined.

9-5
Built-In Procedures, Functions and Variables PL/M-86 User's Guide

The SIGNED Function

SIGNED is an INTEGER function that converts a BYTE or WORD value to an


INTEGER value. It is activated by a function reference with the form:

S I G HE D (expression)

where
expression has a WORD or BYTE value.

If expression has a BYTE value, it will be extended by 8 high-order zero bits to


produce a WORD value.

SIGNED interprets the WORD value as a 16-bit two's-complement number and


returns the corresponding integer value.

This means that if the highest-order (most significant) bit of the WORD valued is a
0, SIGNED interprets the WORD value as a positive number and returns the corre-
sponding INTEGER value. For example:

SIGHED (0000$0000SOOOOS0100B)

returns an INTEGER value of 4.

But if the highest-order bit of the WORD value is aI, SIGNED returns a negative
INTEGER value whose absolute magnitude is the two's complement of the WORD
value. For example:

S I GHED( 1111 S 1111 S 1111 S 11 OOB)

returns an INTEGER value of -4.

The UNSIGN Function

UNSIGN is a WORD function that converts an INTEGER value to a WORD value.


It is activated by a function reference with the form:

UHS I G H (expression)

where
expression has an INTEGER value.

UNSIGN converts the INTEGER value to a WORD value.

If the INTEGER value is positive, then the WORD value will be numerically the
same as the INTEGER value. But if the INTEGER value is negative, then the
WORD value will be the two's complement of the absolute magnitude of the
INTEGER value. For example:

UHSIGH(-4)

returns a WORD value of

1111$ 1 1 1 1 S 1 1 1 1 S 1 1 0 0 B

9-6
PLfM-86 User's Guide Built-In Procedur~ Functions and Variables

The ABS and lABS Functions

ABS is a REAL function that returns the absolute value of a REAL value. It is
activated by a function reference with the form:

A B S ( expression)

where
expression has a REAL value.

If the value of expression is positive, ABS returns it unchanged. If the value of


expression is negative, ABS returns - (expression).

lABS is an INTEGER function that returns the absolute value of an INTEGER


value. It is activated by a function reference with the form:

I AB S ( expression)

where
expression has an INTEGER value.

If the value of expression is positive, lABS returns it unchanged. If the value of


expression is negative, lABS returns - ( expression).

9.3 Shift and Rotate Functions


In shift and rotate operations, a value is handled as a pattern of 8 bits (for a BYTE
value), 16 bits (for a WORD or INTEGER value), or 32 bits (for a DWORD value).
The pattern is moved to the right or left by a specified number of bits called the
"bit count."

In a shift, bits moved off one end of the pattern are lost, and zero bits move into the
pattern from the other end (except in the case of SAR-see below). In a rotate, bits
moved off one end move onto the other end.

Rotation Functions ROL and ROR

ROL and ROR are functions whose type depends on the type of the expression given
as an actual parameter. They are activated by function references with the forms:

R 0 L (pattern, count)
R 0 R (pattern, count)

where
pattern and count are expressions with BYTE, WORD, or DWORD values.

If count has a WORD or DWORD value, all but the 8 low-order bits will be dropped
to produce a BYTE value. If the value of count is 0, no rotation occurs.

The value of pattern is handled as an 8-bit, 16-bit, or 32-bit binary quantity that is
rotated to the left (by ROL) or to the right (by ROR). The type of pattern determines
whether a byte, word, or dword rotate is performed. The number of bit positions by
which it is rotated is specified by count.

9-7
Built-In Procedures, Functions and Variables PLfM-86 User's Guide

The following are examples of the action of these procedures:

R 0 R ( 1 0 0 1 1 1 0 1 B , 1) returns a value of 1100111 OB.


ROL( 1001110 1B, 2) returnsavalueofOl110110B.
R 0 R ( 1 1 0 1 0 1 1 0 1 0 0 1 1 0 1 0 B, 9) returns a value of 0100110101101011 B.

Logical-Shift Functions SHL and SHR

SHL and SHR are functions whose type depends on the type of the expression given
as an actual parameter. They are activated by function references with the forms:

5 H L (pattern, count)
5 H R (pattern, count)

where
pattern and count are expressions with BYTE, WORD, or DWORD values.

If count has a WORD or DWORD value, all but the 8 low-order bits will be dropped
to produce a BYTE value. If the value of count is 0, no shift occurs.

The value of pattern may be either a BYTE, WORD, or DWORD value and will not
be converted. If it is a BYTE value, the function will return a BYTE value. If pattern
is a WORD value, the function will return a WORD value; if it is a DWORD value,
the function will return a DWORD value.

The value of pattern is shifted left (by SHL) or right (by SHR), with the bit count
given by count.

A shift operation can force a I-bit out of the pattern. For example:

SHL(1000$0001B,1)

becomes 0000$0010, losing the former high-order bit, and:

SHR(1000$0001B,1)

becomes 0100$0000, losing the former low-order bit.

If the specified pattern and count do not cause such a "lost information" shift, then
a shift of one bit position has the effect of multiplication by 2 for a left shift, or
division by 2 for a right shift. For example, suppose that VAR is a BYTE variable
with a value of 8. This is represented as 0000$1000. SHL(VAR,l) will return
0001$0000, which represents 16, while SHR(VAR,l) will return 0000$0100, which
represents 4.

Algebraic-Shift Functions SAL and SAR

SAL and SAR are INTEGER functions. They are activated by function references
with the forms:

5 A L (pattern, count)
5 A R (pattern, count)

where
pattern is an expression with an INTEGER value.
count is an expression with a BYTE, WORD, or DWORD value.

9-8
PLjM-86 User's Guide Built-In Procedures, Functions and Variables

If count has a WORD or DWORD value, all but the 8 low-order bits will be dropped
to produce a BYTE value. If the value of count is 0, no shift occurs.

SAL and SAR treat the INTEGER value of pattern as a bit pattern. This pattern is
shifted to the left or to the right.

In a left shift (SAL), O-bits move into the pattern from the right (as in SHL and
SHR).

In a right shift (SAR), either zero bits or one bits move into the pattern from the
left. If the original value of pattern is positive, the sign bit (leftmost bit) is a 0, and
zero bits move in from the left. If the original value is negative, the sign bit is aI,
and one bits move in from the left.

This means, in some instances, that just as with the logical shifts, an algebraic shift
of one bit position can have the effect of multiplication by 2 for a left shift or division
by 2 for a right shift. For example, suppose that VAL is an INTEGER variable with
a value of -8. This value is represented as IIII$IIII$IIII$IOOOB. SAL(VAL,I)
will return IIII $1111 $1111 $OOOOB, which represents - 16, while SAR( VAL, I) will
return IIII$IIII$IIII$IIOOB, which represents -4.

9.4 String Manipulation Procedures


The term "string" is used here in a broader sense than previously. The "character
strings" mentioned in sections 2.4, 3.1, and 4.4 are BYTE strings.

Considered more broadly, a string is any contiguously stored set of BYTE values or
WORD values. We can regard a string as if it were a BYTE or WORD array, and
refer to the BYTE or WORD values as "elements."

We will use the word "index" to refer to the position of a given element within a
string. The index is like the subscript of an array reference. Thus, the index of the
first element of a string is 0, the index of the second element is I, etc.

In the following descriptions, the "location" of a string always means the location of
its first element. In each string-manipulation procedure, the location of a string is
specified by a parameter called "source" or "destination," which is an expression
with a POINTER value. Thus, the source points to the lowest element. For MOVB
and MOVW, this is the first element to be processed. For MOVRB and MOVR W,
it is the last element to be processed, as discussed below.

The "length" of a string is the number of elements it contains. In each string-


manipulation procedure, the number of elements to be processed is specified by a
parameter called "count," which is an expression with a WORD or BYTE value.

NOTE
If the source or destination string address is in SELECTOR or WORD form,
use the @ operator of a variable based on the address. Otherwise, the built-in
function BUILD$PTR can be used to construct the pointer-parameter for
the string built-in.

The string-manipulation procedures (with the exception of XLAT) are available in


pairs. One of each pair is for BYTE strings and the other is for WORD strings.

9-9
Built-In Procedur~ Functions and Variables PL/M-86 User's Guide

The MOVB and MOVW Procedures

MOVB is an untyped procedure that copies a BYTE string from one location to
another. It is activated by a CALL statement with the form:

CAL L M0 V B ( source, destination, count) j

where
source and destination are expressions with POINTER values.
count is an expression with a BYTE or WORD value.

The string elements are copied in ascending order-that is, element 0 is copied first,
then element 1, etc. This is significant if the source string and the destination string
overlap. If the value of destination is higher than the value of source, and the two
strings overlap, elements in the overlap area will be overwritten before they are copied.
This can be avoided by using MOVRB instead of MOVB.

MOVW is the same as MOVB except that it copies a WORD string instead of a
BYTE string.

The MOVRB and MOVRW Procedures

MOVRB is the same as MOVB except that the elements in the source string are
copied to the destination string in descending order. This is significant when the two
strings overlap. If the value of "destination" is higher than the value of "source," and
an overlap exists, elements in the overlap area will not be overwritten until after they
have been copied. However, if the value of "source" is higher than the value of
"destination," then elements in the overlap area will be overwritten before they are
copied.

MOVRW is the same as MOVRB except that it copies a WORD string instead of a
BYTE string.

NOTE
If two strings overlap, a procedure such as the following can be used to make
the correct choice between MOVB and MOVRB, so that elements in the
overlap area will not be overwritten until after they have been copied.
MOVBYTES: PROCEDURE (SRC, DST, CNT) j
DECLARE (SRC, OST) POINTER, CNT WORDj
IF SRC ) OST THEN CALL MOVB (SRC, OST, CNT)j
ELSE CALL MOVRB (SRC, OST, CNT)j
END MOVBYTESj
This procedure can be activated without the need to consider whether overlap may
occur or whether source or destination is higher.

The CMPB and CMPW Functions

CMPB is a WORD function that compares two BYTE strings. It is activated by a


function reference with the form:

CMP B ( source 1, source2, count)

where
source1 and source2 are expressions with POINTER values.

9-10
PL/M-86 User's Guide Built-In Procedures, Functions and Variables

count is an expression with a WORD value.

CMPB compares two BYTE strings of length countwhose locations are source1 and
source2.

If every element in the string at source1 is equal to the corresponding element in the
string at source2, CMPB returns a WORD value of OFFFFH. Otherwise, it returns
the index (position within the strings) of the first pair of elements found to be unequal.

CMPW is the same as CMPB except that it compares two WORD strings instead of
two BYTE strings.

The FINDB/FINDW and FINDRB/FINDRW Functions

FINDB is a WORD function that searches a BYTE string to find an element that
has a specified value. It is activated by a function reference of the form:

F I HDB ( source, target, count)

where
source is an expression with a POINTER value.
target is an expression with a BYTE or WORD value. If target has
a WORD value, the 8 high-order bits will be dropped to
produce a BYTE value.
count is an expression with a WORD value.

FINDB examines each element of the source string (in ascending order) until it finds
an element whose value is equal to the BYTE value of target-or until count elements
have been searched without any of them matching target. If the search is successful,
FINDB returns the index of the first element of the string that matches target. If the
search is unsuccessful, FINDB returns a WORD value of OFFFFH.

FINDW is the same as FINDB except that it searches a WORD string instead of a
BYTE string. If the target parameter has a BYTE value, it is extended by 8 high-
order zero bits to produce a WORD value.

FINDRB is the same as FINDB except that it searches the source string in descending
order. Thus, if the search is successful, FINDRB returns the index of the last (highest
subscript) element that matches the BYTE value of target.

FINDRW is the same as FINDRB except that it searches a WORD string instead
of a BYTE string (in descending order).

The SKIPB/SKIPW and SKIPRB/SKIPRW Functions

SKIPB is the "converse" of FINDB (see above). Instead of searching for the first
element in the BYTE source string that matches the BYTE value of target, SKIPB
searches for the first element that does not match.

In every other respect, the operation is exactly the same as FINDB.

SKIPW is the "converse" of FINDW (see above). Instead of searching for the first
element in the WORD source string that matches the WORD value of target, SKIPW
searches for the first element that does not match.

In every other respect, the operation is exactly the same as FINDW.

9-11
Built-In Procedures, Functions and Variables PLfM-86 User's Guide

SKIPRB is the "converse" of FINDRB (see above). Instead of searching for the last
element in the BYTE source string that matches the BYTE value of target, SKIPRB
searches for the last element that does not match.

In every other respect, the operation is exactly the same as FINDRB.

SKIPR W is the "converse" of FINDR W (see above). Instead of searchirig for the
last element in the WORD source string that matches the WORD value of target,
SKIPR W searches for the last element that does not match.

In every other respect, the operation is exactly the same as FINDRW.

The XLAT Procedure

XLAT is an untyped procedure that uses a translation table to "translate" a BYTE


string to produce another BYTE string. It is activated by a CALL statement of the
form:

CAL L XL AT ( source, destination, count, table) ;

where
source, destination, and table are expressions with POINTER values.
count is an expression with a WORD value.

XLAT "translates" the BYTE elements in the source string, placing the translated
elements in the destination string. The value of table is assumed to be the location of
a BYTE string of up to 256 elements. This string is used as a translation table.

The value of an element in the source string is used as an index for the translation
table. The index selects one" element from the translation table; this element is then
copied into the destination string.

For example, if the fifth element in the source string is 202, then 202 is used as an
index for the translation table. The 203rd element of the table is copied into the fifth
. position in the destination string.

The elements of the source string are translated into the destination string in
ascending order.

The SETB and SETW Procedures

SETB is an untyped procedure that sets each element of a BYTE string to a single
specified value. It is activated by a CALL statement with the form:

CAL L 5 E T B ( newvalue, destination, count> ;

where
newvalue is an expression with a BYTE or WORD value. If it has a
WORD value, the 8 high-order bits are dropped to produce
a BYTE value.
destination is an expression with a POINTER value.
count is an expression with a BYTE or WORD value.

SETB assigns the BYTE value of newvalue to each element of a BYTE string.

9-12
PL/M-86 User's Guide Built-In Procedures, Functions and Variables

SETW is the same as SETB except that it assigns a single WORD value to each
element of a WORD string instead of a BYTE string.

If newvalue has a BYTE value, it will be extended by 8 high-order zero bits to produce
a WORD value.

9.5 Miscellaneous Built-Ins


The MOVE Procedure
MOVE is an untyped procedure that is provided for compatibility with PL/M-80
programs. It is activated by a CALL statement with the form:

CAL L M0 VE ( count, source, destination) ;


where
count, source, and
destination are expressions with WORD or BYTE values.

If any of these parameters has a BYTE value, it will be extended by 8 high-order


zero bits to produce a WORD value.

The values of source and destination are assumed to be the WORD-type addresses of
the source string and the destination string. The operation differs from MOVB as
follows:
• All three parameters must have either BYTE or WORD values, and will be
converted to WORD values if they are BYTE values. POINTER values for source
and destination are not allowed and therefore the values cannot be supplied by
means of the @ operator. Thus, MOVE can only handle strings whose locations
can be expressed as WORD addresses.
• Note that the parameters are in a different order than the one used by the other
built-in string functions.
• If the source and destination strings overlap, the results are always undefined.

The TIME Procedure

The untyped procedure TIME causes a time delay specified by its actual parameter.
It is activated by a CALL statement with the form:

CAL L TIM E (expression);


where the expression is converted, if necessary, to a WORD quantity. The length of
time measured by the procedure is a multiple of 100 microseconds. If the actual
parameter evaluates to n, then the delay caused by the procedure is 1DOn microse-
conds. For example, the statement:

CALL TIME (45);


causes a delay of 4.5 milliseconds. Since the maximum delay offered by the
procedure is about 6.55 seconds, longer delays must be obtained by repeated activa-
tions. The following block takes one second to execute:

DO I • 1 TO 40;
CALL TIME (250);
EHD;

9-13
Built-In Procedures, Functions and Variables PLfM-86 User's Guide

The TIME procedure is based on iAPX 86 CPU cycle times, and assumes that the
system is running at 5 MHz (8 MHz for the iAPX 186) without interruptions.

The MEMORY Array

MEMORY is a BYTE array of unspecified length which represents an uninitialized


(free) segment of iAPX 86 storage. References to MEMORY may be subscripted.
The maximum subscript allowed depends on both the system environment and. the
program. References to MEMORY, either subscripted or unqualified, may be used
in location references. For example, @ MEMORY is the location of the beginning of
free memory space, i.e., byte 0 of the memory segment.

A reference to MEMORY may not be used as an actual parameter for the LENGTH,
LAST, and SIZE procedures. However, some systems provide service routines you
can use to learn the size of free memory.

The LOCKSET Function

The LOCKSET function permits a programmer to implement a simple software


synchronization lock. It is a BYTE procedure called by a function reference with the
form:

L 0 CK 5 E T ( lockptr, newvalue)

where
lockptr is an expression with a POINTER value.
newvalue is an expression with a BYTE or WORD value. If newvalue
has a WORD value, the 8 high-order bits will be dropped to
produce a BYTE value.

The action of LOCKSET is as follows: the lockptr parameter is used as a pointer to


a BYTE variable; the value of newvalue is assigned to this variable, and LOCKSET
returns the original value of the variable. During this transaction, the iAPX 86 CPU
prevents any other process from accessing the same memory location.

To see how this facility can be used, consider a system having more than one
iAPX 86 processor using the same memory, and consider a program in one of these
processors. Suppose that this program uses memory locations that are also used by
other processors in the system.

Within certain "critical" regions of our program, we want to ensure that no other
processor will access the shared memory locations. To achieve this, we declare a BYTE
variable called LOCK and establish a convention that if LOCK =0, any processor in
the system may access the shared memory locations. But if LOCK = 1, no processor
may access the shared memory locations unless it was the one that set LOCK to 1.

Now, if we write the function reference LOCKSET(@LOCK,I), the value 1 is


assigned to LOCK. Furthermore, if the value returned by LOCKSET is 0, then LOCK
was not already set and this processor is the one that set it. We are now allowed, by
convention, to enter the critical region of our program and access the shared memory
locations. At the end of the critical region, we must release the lock by writing
LOCK=O.

But, if LOCKSET returns a value of 1, then LOCK was already set and this proces-
sor was not the one that set it. By convention, we must wait until a
LOCKSET( @LOCK, 1) function reference returns a value of 0 before assessing the
shared memory locations.

9-14
PL/M-86 User's Guide Built-In Procedur~ Functions and Variables

Thus, our program could contain the following construction:

If Begin critical regionfl

DO WHILE LOCKSETC,LOCK,11;
If Do nothing but repeat until LOCK SET returns Ofl
ENDj

If Now LOCK has been set to 1 by this processorfl

If Critical region of program, where


shared memory locations are accessedfl

LOCK-O;
IIEnd critical regionfl

In the simplest case just described, only one software lock is used. It is represented
by the variable LOCK. But, if more than one set of memory locations needed protec-
tion at different times, we could establish as many different software locks as neces-
sary, with each lock using a different BYTE variable.

Also, note that a software lock can be used for other purposes than protecting memory
locations. LOCKSET provides a mechanism that can be used to implement various
types of synchronization in a multiprocessor system.

9.6 Interrupt-Related Procedures


The two capabilities described in this section permit programs to set interrupt vectors
and learn the entry point of an interrupt-handling procedure.

The SET$INTERRUPT Procedure

This procedure permits a program in execution to set an interrupt vector to point to


the interrupt entry point of a separately compiled interrupt handling routine, or to
alter such vectors dynamically. See also section 8.3 and Appendix G.

The procedure is invoked by a CALL of the form:

CAL L SET S I HTERR UPT (constant, name)

where name is the interrupt procedure name, and constant is an interrupt number,
i.e., a whole-number constant between 0 and 255.

The INTERRUPT$PTR Function

This built-in function returns the interrupt entry point. Its form is:

I HTERR UPTS PTR (name)

It is typically used in an assignment statement, for example:

IHT$ARRAY(4) • IHTERRUPTSPTR (HAHDLER_PROC_4)

9-15
Built-In Procedures. Functions and Variables PLfM-86 User's Guide

The interrupt entry point is not accessible without using this function, since the @
operator refers to the procedure entry point instead. These differences are discussed
in greater detail in Appendix G.

9.7 POINTER and SELECTOR-Related Functions


The following built-in functions permit programs to manipulate POINTER and
SELECTOR values that serve as location addresses in iAPX 86 memory. (For more
information on POINTER and SELECTOR, see section 3.4.)

The BUILD$PTR Function

BUILD$PTR is a POINTER function that takes a SELECTOR value (the base


portion) and a WORD value (the offset portion), and returns a POINTER value. It
is activated by a function reference with the form:

B U I L D • P T R (base, offset)

where
base is an expression with a SELECTOR value.
offset is an expression with a WORD value.

The SELECTOR$OF Function

SELECTOR$OF is a SELECTOR function that returns the base portion of a


POINTER. It is activated by a function reference with the form:

S E LEe TOR $ 0 F ( pointer)

where
pointer is an expression with a POINTER value.

The OFFSET$OF Function

OFFSET$OF is a WORD function that returns the offset portion of a POINTER.


It is activated by a function reference with the form:

OFF SET $ 0 F ( pointer)

where
pointer is an expression with a POINTER value.

The NIL Function

NIL is a POINTER function that returns a pointer with all bytes set to zero. It is
activated by a function reference with the form:

NIL

The pointer value NIL points to no object at all. You may assign the value NIL to a
pointer to indicate, for instance, the end of a linked list.

9-16
PLfM-86 User's Guide Built-In Procedures, Factions and Variables

Note that pointer values generated with the NIL function cannot be used to derefer-
ence data values. For example, if your program contains the following statements:

DECLARE P POINTER;
DECLARE B BASED P BYTE;
P - NIL;
then any subsequent references to B are invalid and will cause a trap.

NOTE
Usage of the NIL pointer can lead to undesirable results.
In the SMALL case, a NIL pointer is defined to be DS:O, which is not distin-
guishable from a valid pointer to the first variable in the data segment (DS).
For example:

$SMALL
M:DO;
DECLARE P POINTER INITIAL (,P);
DECLARE B BYTE;
B - (P-NIL); 1* will assign TRUE (OFFH) to B *1
END;
In all other cases, the NIL pointer is defined to be 0:0, which is not distin-
guishable from a valid pointer to a variable located at absolute address O.
For example:

$LARGE
M:DO;
DECLARE Q BYTE AT (0);
DECLARE B BYTE;
B - (,Q-NIL); 1* will assign TRUE (OFFH) to B*I
END;

9-17
CHAPTER 10
PL/M-86 FEATURES INVOLVING
iAPX 86 HARDWARE

The PL/M-86 features described in this chapter make use, directly or indirectly, of
the iAPX 86 hardware.

10.1 iAPX 86 Hardware-Dependent Statements


The ENABLE and DISABLE Statements

These two statements enable and disable the iAPX 86 interrupt mechanism. They
have the forms

ENABLE;
DISABLE;
ENABLE generates an STI instruction, causing the iAPX 86 to enable interrupts.
DISABLE generates a CLI instruction, causing the iAPX 86 to disable interrupts.

The CAUSE$INTERRUPT Statement

The CAUSE$INTERRUPT statement causes a software interrupt to be generated.


It takes the form:

CA USE • I NT ERR UP T (constant>;

where
constant is a whole-number constant in the range 0 to 255.

CAUSE$INTERRUPT generates an INT instruction with the constant as the inter-


rupt type, causing the iAPX 86 to transfer control to the appropriate interrupt vector
(see section 8.5 and Appendix G).

The HALT Statement

The HALT statement has the form:

HALT;
It generates an STI instruction followed by an HLT instruction, causing the iAPX
86 to come to a halt with interrupts enabled (see section 8.5).

10.2 The iAPX 86 Hardware Flags


Optimization and the Hardware Flags

To produce an efficient machine-code program from a PL/M-86 source, the


PL/M-86 compiler performs extensive optimizations of the machine code. This means
that the exact sequence of machine code produced to implement a given sequence of
PL/M-86 source statements cannot be predicted.

10-1
PL/M-86 Features Involving iAPX 86 Hardware PL/M-86 User's Guide

Consequently, the state of the iAPX 86 hardware flags cannot be predicted for any
given point in the program. For example, suppose that a source program contains the
following fragment:

SUM· SUM + 250;

where
SUM is a BYTE variable.

Now, if the value of SUM before this assignment statement is greater than 5, the
addition will cause an overflow and the hardware CARRY flag will be set.

If there were no optimization of the machine code, one could follow this assignment
statement with one of the PL/M-86 features described in the following sections and
be sure that the feature would operate in a certain fashion depending on whether or
not the addition caused the CARRY flag to be set. However, because of the optimi-
zation, some machine code instructions may, occur immediately after the addition and
change the CARRY flag. One cannot safely predict whether this will happen or not.

Accordingly, any PL/M-86 feature that is dependent on the CARRY flag (or any of
the other hardware flags) may cause the program to run incorrectly. These features
must therefore be used with caution, and any program that uses them must be checked
carefully to make sure that it operates correctly.

The CARRY, SIGN, ZERO, and PARITY Functions

These four built-in BYTE functions return the logical values of the iAPX 86 hardware
flags. These functions take no parameters, and are activated by function references
with the following forms

CARRY
ZERO
SIGH
PARITY
An occurrence of one of these activations (in an expression) generates a test of the
corresponding condition flag. If the flag is set ( = 1), a value of OFFH is returned. If
the flag is clear ( = 0), a value of 0 is returned.

The PLUS and MINUS Operators


In addition to the arithmetic operators described in section 4.2, PL/M-86 has two
more: PLUS and MINUS.

PLUS and MINUS perform similar to + and -, and have the sam~ precedence.
However, they take into account the current setting of the iAPX 86 CPU hardware
CARRY flag in performing the operation.

10-2
PL/M-86 User's Gtdde PLJM-86 Features Involving iAPX 86 Hardware

Carry-Rotation Functions

SCL and SCR are rotation functions whose type depends on the type of the expres-
sion given as an actual parameter. They are activated by function references with the
forms:

S C L (pattern, count> ;
S CR (pattern, count> i

where
pattern and count are expressions with BYTE or WORD values.

If count has a WORD value, all but the 8 low-order bits will be dropped to produce
a BYTE value. If the value of count is 0, no shift occurs.

The value of pattern is handled as an 8-bit or 16-bit binary quantity that is rotated to
the left (by SCL) or to the right (by SCR), similar to the ROL and ROR functions
described in Chapter 9. The type of pattern determines whether a byte or word rotate
is performed. The number of bit positions by which it is rotated is specified by count.

The bit rotated off one end of pattern is rotated into the CARRY flag, and the old
value of CARRY is rotated to the other end of pattern. In effect, SCL and SCR
perform 9-bit rotations on 8-bit values and 17-bit rotations on 16-bit values.

For example, if the value of CARRY is 0, then

SCL(lIOOIOIOB, 2) returns a value of OOIOIOOIB and CARRY is set to 1


SCR( 1100 I 0 lOB, 1) returns a value of 0 II 00 10 I B and CARRY remains 0

The DEC Function

DEC is a BYTE function that uses the value of the hardware CARRY flag
internally. It is activated by a function reference with the form:

DEC ( expression) ;

where
expression is converted, if necessary, to a BYTE value.

The procedure performs a decimal adjust operation on the actual parameter value
and returns the result of this operation.

10.3 The iAPX 86 Hardware Registers


The FLAGS Variable
FLAGS is a WORD variable that provides access to the iAPX 86 hardware flags
register (see figure 10-1). The iAPX 86 hardware flags register is a 16-bit register
that contains the hardware flags that are altered by the execution of various
instructions.

The FLAGS register is assigned to change the setting of the various flags. It can also
be read to determine the current flag settings.

Note that the IOPL and IF flags can only be altered when you are executing in
protection mode at level o.

10-3
PLfM-86 Features Involving iAPX Hardware PL/M-86 User's Guide

Ix 'OFIDFIIFITFISFIZFlxIAFlx IPFlxlCFI

I ~L CARRY FLAG
L - (RESERVED)
PARITY FLAG
(RESERVED)
' - - - - - - - - AUXILIARY CARRY FLAG
' - - - - - - - - - - (RESERVED)
' - - - - - - - - - - - ZERO FLAG
' - - - - - - - - - - - - - SIGN FLAG
L -_ _ _ _ _ _ _ _ _ _ _ _ _ SINGLE-STEP TRAP FLAG

' - - - - - - - - - - - - - - - - INTERRUPT ENABLE FLAG


L -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ DIRECTION FLAG

' - - - - - - - - - - - - - - - - - - - OVERFLOW FLAG


L -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ (RESERVED)

Figure 10-1. The iAPX 86 Hardware Flags Register 945-2

The STACKPTR and STACKBASE Variables

STACKPTR and STACKBASE are WORD variables. They provide access to the
iAPX 86 hardware stack pointer and stack base registers, i.e., SP and SS.

When setting these registers (that is, using STACKPTR or STACKBASE on the left
side of an assignment), care must be exercised because this action removes control of
the stack from the compiler. Thus, the compile-time checks on stack overflow and
the compiler's assumptions about the run-time status of the stack may be invalid.

10.4 iAPX 86 Hardware I/O


Single byte or word input is performed as a function invocation in an expression on
the right-hand side of an assignment statement. Single' byte or word output is achieved
by filling the appropriate element of the output array corresponding to the desired
output port of the iAPX 86 CPU.

Multiple byte or word input is performed as a procedure invocation, reading in a


string from an iAPX 86 CPU port and storing it in a user-specified memory location.
Multiple byte or word output is also performed as a procedure invocation, using a
CALL statement to send a string from memory into an iAPX 86 CPU port.

The INPUT and INWORD Functions

INPUT is a BYTE function and IN WORD is a WORD function. They are activated
by function references with the forms:

I HPUT ( expression)
I HW0 RD (expression)

where
expression has a BYTE or WORD value.

The value of expression specifies one of the input ports of the iAPX 86 CPU. The
value returned by INPUT is the BYTE quantity found in the specified input port.
The value returned by INWORD is the WORD quantity found in the specified input
port.

10-4
PLfM-86 User's Guide PLfM-86 Features Involving iAPX Hardware

The OUTPUT and OUTWORD Arrays

OUTPUT is a BYTE array and OUTWORD is a WORD array. Each array has
65536 elements, corresponding to the number of output ports on the iAPX 86 CPU.

A reference to OUTPUT or OUTWORD may only appear as the left part of an


assignment statement or embedded assignment; anywhere else it is illegal. The
right-hand side of the assignment must have a BYTE or WORD value.

The effect of an assignment to an element of OUTPUT is to place the BYTE value


of the expression on the right side of the assignment into the corresponding output
port. (Since OUTPUT is a BYTE array, the value of the expression will be converted
automatically to a type BYTE if necessary.)

The effect of an assignment to an element of OUTWORD is to place the WORD


value of the expression on the right side of the assignment into the corresponding
output port.

The BLOCKINPUT and BLOCKINWORD Procedures

BLOCKINPUT and BLOCKINWORD are untyped procedures. They are activated


by CALL statements with the forms:

CAL L B L 0 CK I HPUT (port, destination, count) ;


CAL L B L 0 C K I HW0 RD (port, destination, count) ;

where
port and count are expressions with WORD values.
destination is an expression with a POINTER value.

The value of port specifies one of the input ports of the iAPX 86 CPU. The value of
count specifies the length of the BYTE or WORD string found in the specified port,
and destination is the location (in memory) where this string is to be stored.

The BLOCKOUTPUT and BLOCKOUTWORD Procedures

BLOCKOUTPUT and BLOCKOUTWORD are untyped procedures. They are


activated by CALL statements with the forms:

CAL L B L 0 C K0 UT PUT (port, source, count) ;


CAL L B L 0 C K0 UTWO RD (port, source, count> ;

where
port and count are expressions with WORD values.
source is an expression with a POINTER value.

The value of port specifies one of the output ports of the iAPX 86 CPU. The value
of count specifies the length of the BYTE or WORD string output to the specified
port, and source is the location (in memory) where this string is currently stored.

10-5
PL/M-86 Features Involving iAPX Hardware PL/M-86 User's Guide

10.5 The REAL Math Facility


REAL math support for PL/M-86 is provided by the 8087 Numeric Data Extension.
From the program's point of view, The REAL Math Facility consists of the
following:
• The REAL stack, used to hold operands and results during REAL operations.
• The REAL Error Byte (see figure 10-2), consisting of 7 exception flags initial-
ized to all O's. (The reserved bit is set to 1 by the 8087.)
The first six bits in this byte correspond to the possible errors that can arise
during REAL operations (see Appendix G). When an error occurs, the facility
sets the corresponding bit to 1. A program can invoke a built-in procedure
(described in section 10.7) that reads and clears the REAL Error Byte.
The exception/error categories are discussed in Appendix G.
• The REAL mode word (see figure 10-3), consisting of 16 bits initialized to
03FFH.
1. Bits 0-7 determine whether the corresponding error condition is to be handled
by using the default recovery described below or by using the programmer-
supplied exception procedure. (See Appendix G for details on writing these.)
When the bit is 1, the default is used; when it is 0, the user routine is used.
In either case, the facility records the error by setting the corresponding bit
of the REAL Error Byte. For most uses, the default recovery is appropriate
and less work.
This mode word is often called a mask; i.e., it lets some signals through (for
interrupt processing), but not others. If one of the bits 0-5 is a 0, the corre-
sponding error is said to be· unmasked. (See section 10.7 on how to set the
mode word.)
If the interrupt is enabled (IEM = 0), one of the masked bits is 0, and the
corresponding error occurs during floating point processing, then the REAL
math facility interrupts the host CPU. The 8087 interrupt number is depend-
ent on the internal configuration. The exception condition is thus reported
and control is passsed to the user-written error handling routine. This situa-
tion is called an unmasked error. Sections 8.2 and Appendix G discuss aspects
of interrupt procedures.
Conversely, a "masked error" means the mode bit corresponding to that error
is 1. Masked errors do not cause an interrupt, but are handled as described
in Appendix G.
Bits 13, 14, and 15 are reserved and are not for PL/M-86 use.
Bits 8-12 provide options for controlling precision, rounding, and infinity
representation (see figu~e 10-3).
2. All intermediate results are held in an internal format of 64-bit precision.
The most-significant 24 bits of the final result are returned (plus sign and
7-bit exponent) is the PL/M-86 answer, and rounded, if needed, according
to the user-specified control. The default precision setting preserves extended
precision and operates slightly' faster than the other.
3. Rounding introduces an error of less than one unit in the last place to which
the result was rounded. Statistically, the default provides the most accurate
and unbiased estimate of the "true result," i.e., the 64-bit result. In all
rounding modes except "round down," subtracting a number from itself yields
+ 0; round down yields - O. 00

;~ M_~ommE ~~ ~CTIYE~~O+
4.

121945-4
o

10-6
PLjM-86 User's Guide PLjM-86 Features Involving iAPX Hardware

7 o

I I I I I
PE UE OE ZE DE liE I EXCEPTION FLAGS (1 = EXCEPTION HAS OCCURRED)

I~
INVALID OPERATION
DENORIIALIZED OPERAND
ZERODIVIDE
OVERFLOW
UNDERFLOW
PRECISION
' - - - - - - - - - - - - - - (RESERVED)
.......- - - - - - - - - - - - - - INTERRUPT REQUEST

Figure 10-2. The REAL Error Byte 121636-2

15 7 0

~=~~~~I~~~I~=R~C=~~=p~C=~I-E~M-I~~.I-p~M~1~~~1~~~1~~~1~~~1~~~1~~~~~(1=~~~~~~
I II L ~~~RA~
DENORMALIZED OPERAND
ZERODIVIDE
OVERFLOW
UNDERFLOW
PRECISION
L..-_ _ _ _ _ _ _ _ _ _ _ _ (RESERVED)
L......_ _ _ _ _ _ _ _ _ _ _ _ _ _ INTERRUPT.ENABLE MASK(1J(lEM)

1.------------------ PRECISION CONTROL!»


' - - - - - - - - - - - - - - - - - - - - - - - ROUNDING CONTROL(3)
L......_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ INFINITY CONTROL(4)

' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (RESERVED)

(1) Interrupt-Enable Mask:


o = Interrupts Enabled
1 = Interrupts Disabled (Masked)

(2) Precision Control:


00 = 24 bits
01 = (reserved)
10 = 53 bits
11 = 64 bits

(3) Rounding Control:


00 = Round to Nearest or Even
01 = Round Down (toward - 0 )
10 = Round Up (toward -(0)
11 = Chop (Truncate Toward Zero)

(4) Infinity Control:


o = Projective
1 = Affine

Figure 10-3. The REAL Mode Word 121636·3

The full extent of the 8087's numeric and operational capabilities are discussed in
the 8086 Family User's Manual Supplement for the 8087 Numeric Data Processor.

10-7
PL/M-86 Features Involving iAPX Hardware PL/M-86 User's Guide

10.6 Built-ins Supporting the REAL Math Unit


The INIT$REAL$MATH$UNIT Procedure

INIT$REAL$MA TH$UNIT is a built-in untyped procedure activated by a CALL


statement, as follows:

CALL IHIT$REALSMATHSUHIT;
This call is required as the first access to the REAL math facility (the 8087 Numeric
Data Extension).

The effect of this call is to initialize the REAL math unit for subsequent operations.
This includes setting a default value into the control word, namely 03FFH or
0000001111111111 in binary. The effect of this setting is to mask all exceptions and
interrupts, to set precision to 64 bits, and to cause rounding to even. This means no
interrupts will occur from the REAL Math Facility regardless of what errors are
detected.

Procedures activated after this call has taken effect do not need to do such
initialization.

The SET$REAL$MODE Procedure

This procedure should only be invoked if you wish to change the default mode word
(for example, to unmask the invalid exception).

SET$REAL$MODE is a built-in untyped procedure, activated by a CALL


statement with the following form:

CALL SETSREAL$MODE (modew~d);

where
modeword is an expression with a WORD value.

The value of modeword becomes the new contents of the REAL mode word (see
figure 10-3). The suggested value for modeword is 033EH, that is, 0000001100111110
in binary. This value provides maximum precision, default rounding, and masked
handling of all exception conditions except invalid, which can alert you to errors of
initialization or stack usage. See Appendix G for facts and references on writing an
interrupt handling procedure.

The GET$REAL$ERROR Function

GET$REAL$ERROR is a built-in BYTE function activated by a function reference


with the following form:

GET$REALSERROR
The BYTE value returned is the current contents of the REAL error byte (see figure
10-1). This function also clears the error byte in the REAL math facility.

10-8
PL/M-86 User's Guide PL/M-86 Features Involring iAPX Hardware

Saving and Restoring REAL Status


If an interrupt procedure performs any floating-point operation, it will change the
REAL status. If such an interrupt procedure is activated during a floating-point
operation, the program will be unable to continue the interrupted operation correctly
after returning from the interrupted procedure. Therefore, it is first necessary for any
interrupt procedure that performs a floating-point operation to save the REAL status
and subsequently restore it before returning. The built-in procedures
SA VE$REAL$STATUS and RESTORE$REAL$ST ATUS make this possible.
SAVE$REAL$STA TUS initializes the 8087.

These procedures can also be used in a multi-tasking environment where a running


task using the 8087 may be preempted by another task that also uses the 8087. The
preempting task must call SAVE$REAL$STA TUS before it executes any state-
ments that affect the 8087, i.e., before calling SET$REAL$MODE and before any
arithmetic or assignment of REALs (other than GET$REAL$ERROR, if needed).

New vectors will be required for the interrupt handlers appropriate to each new task,
e.g., to handle unmasked exception conditions. These vectors must be initialized by
the operating system.

After its processing is complete and it is ready to terminate, the preempting task must
call RESTORE$REAL$STATUS to reload the state information that applied at the
time the former running task was preempted. This enables that' task to resume
execution from the point where it relinquished control.

NOTE
REAL functions without REAL parameters should not call
GET$REAL$ERRORS or SAVE$REAL$STATUS before executing at
least one floating-point instruction. To do so may result in loss of processor
synchronization.

The SAVESREALSSTATUS Procedure


SAVE$REAL$STA TUS is a built-in untyped procedure activated by a CALL
statement with the form:

CALL SAVE.REAL.STATUS (/ocaUon);


where
location is a pointer to a memory area of 94 bytes where the REAL
status information will be saved.

The REAL status is saved at the specified location, and the REAL stack and error
byte are reinitialized.

If the state of the REAL math unit is unknown to this procedure when it is called,
as in the case mentioned above for preempting tasks, then you do not want to do an
initialization because that will destroy existing error flags, masks, and control settings.
The action appropriate to these circumstances (except for error-recovery routines,
discussed in Appendix G) is to issue:

CALL SAVE.REAL.STATUS C,locatlon_1);


before any REAL math usage, and

CALL RESTORE.REAL.STATUS Cllocatlon_1);

10-9
PL/M-86 Features Involving iAPX Hardware PL/M-86 User's Guide

prior to the procedure's return. The save automatically reinitializes the math unit and
the error byte.

This protects the status of preempted tasks or prior procedures and establishes a known
initialization state for the current procedure's actions. iAPX 86 interrupts are disabled
during the save.

[¥~I
The iAPX 86 processor must be able to acknowledge 8087 interrupts or loss
of synchronization will occur.

The RESTORE$REAL$STATUS Procedure


RESTORE$REAL$STATUS is a built-in untyped procedure activated by a CALL
statement with the form:

CAll RESTDRE$REAl$STATUS (/ocaHon);

where
location is a pointer to a memory area where the REAL status infor-
mation was previously saved by a call to the
SAVE$REAL$STATUS procedure.

This procedure should be called prior to returning from an interrupt procedure where
the real math unit's status was saved using SAVE$REAL$STATUS.

10-10
·1~_ ______________________ __1_1~
COMPILERC_H_A_P_TE_R
CONTROLS

11. 1 Introduction to Compiler Controls


The exact operation of the compiler may be controlled by a number of controls that
specify options such as the type of listing to be produced and the destination of the
object file. Controls may be specified as part of the command invoking the compiler,
or as control lines appearing as part of the source input file.

A control line is a source line containing a dollar sign ($) in the left margin. Normally,
the left margin is set at column one, but this may be changed with the LEFTMARGIN
control. Control lines are introduced into the source to allow selective control over
sections of the program. For example, it may be desirable to suppress the listing for
certain sections of the program, or to cause page ejects at certain places.

A line is considered a control line by the compiler if there is a dollar sign in the left
margin, even if it appears to be part of a PL/M-86 comment or character string
constant.

On a control line, the dollar sign is followed by a sequence of controls. These controls
must be separated from each other by one or more blanks.

The following are examples of control lines:

$MOCODE XREF
$ EJECT CODE

There are two types of controls: primary and general. Primary controls must occur
either in the invocation command or in a control line which precedes the first noncon-
trol line of the source file. Primary controls may not be changed within a module.
General controls may occur either in the invocation command or on a control line
located anywhere in the source input, and may be changed freely within a module.

A large number of controls are available, but you may only need to specify a few of
them for most compilations because a set of defaults is built into the compiler. The
controls are summarized in alphabetic order in table II-I.

A control consists of a control-name which, depending on the particular control, may


be followed by a parenthesized control parameter.

The following are examples of controls:

LIS T
NOXREF
DBJECTCPROG2.0JB)

Table 11-2 lists the controls in the order in which they are discussed in this chapter,
which is approximately in order of importance or usage. Primary controls have an
asterisk attached. Sample invocation lines for most compiler controls are provided on
a foldout page in your specific operating-system appendix.

11-1
Compiler Controls PL/M-86 User's Guide

Table 11-1. Compiler Controls


Primary Control Names Abbreviation Default Section

DEBUG/NODEBUG DB NODEBUG 11.4


INTVECTOR/NOINTVECTOR IV INTVECTOR 11.4
MOD86/MOD186 none MOD86 11.2
OBJECT/NOOBJECT OJ OBJ ECT(source-file. OBJ) 11.4
OPTIMIZE OT OPTIMIZE(1) 11.4
PAGING/NOPAGING PI PAGING 11.6
PAGELENGTH PL PAGELENGTH(60) 11.6
PAGEWIDTH PW PAGEWIDTH(120) 11.6
PRINT/NOPRINT PR PRINT(source-file.LST) 11.5
RAM/ROM none ROM 11.4
SMALL/COMPACT/MEDIUM/LARGE SM/CP/MD/LA LARGE 11.4
SYMBOLS/NOSYMBOLS SB NOSYMBOLS 11.5
TITLE TT module name 11.6
TVPE/NOTVPE TV TYPE 11.4
XREF/NOXREF XR NOXREF 11.5

General Control Names Abbreviation Default Section

CODE/NOCODE CO NOCODE 11.5


COND/NOCOND none COND 11.8
EJECT EJ - -11.6
IF/ELSEIF/ELSE/ENDIF none - 11.8
INCLUDE IC - 11.7
LEFTMARGIN LM LEFTMARGIN(1 ) 11.3
LISTINOLIST U LIST 11.5
OVERFLOW/NOOVERFLOW OV NOOVERFLOW 11.4
SAVE/RESTORE SA/RS - 11.7
SET/RESET none RESET (0) 11.8
SUBTITLE ST no subtitle 11.6

11.2 The MOD86/MOD186 Control


MOD86 and MOD 186 are primary controls with the form:

MOD8S
MOD18S
Default: MOD 8 S

The MOD86 control specifies that the object module will contain instructions for
execution on the iAPX-86 processor.

The MOD186 control allows the compiler to generate an extended set of instructions
in the object module for use on the iAPX-186 processor.

11.3 The LEFTMARGIN Control


This is the only control for specifying the format of the source input. It is a general
control with the form:

L EFT MAR G I H( column)


Default: L EFT /WI ARG I H( 1 )

where
column is a non-zero, unsigned integer specifying the left margin of
the source input.

11-2
PLfM-86 User's Guide Compiler Controls

Table 11-2. Controls by Categories


Section Category Controls·

11.2 Code Generation *MOD86/MOD186

11.3 Input Format LEFTMARGIN

11.4 Object File *INTVECTOR/NOINTVECTOR


OVERFLOW/NOOVERFLOW
*OPTIMIZE
*OBJECTINOOBJECT
*DEBUG/NODEBUG
*TYPE/NOTYPE
*SMALL/COMPACT/MEDIUM/LARGE
*ROM/RAM

11.5 Listing Content *PRINT/NOPRINT


LIST/NOLIST
CODE/NOCODE
*XREF/NOXREF
*SYMBOLS/NOSYMBOLS

11.6 Listing Format *PAGING/NOPAGING


*PAGELENGTH
*PAGEWIDTH
*TITLE
SUBTITLE
EJECT

11.7 Source Inclusion and


Control Status INCLUDE
SAVE/RESTORE

11.8 Conditional Compilation IF/ELSEIF/ELSE/ENDIF


SET/RESET
COND

* denotes primary control.

All characters to the left of this position on subsequent input lines are not processed
by the compiler (but do appear on the listing). The first character on a line is in
column 1.

The new setting of the left margin takes effect on the next input line. It remains in
effect for all input from the source file and any INCLUDE files until it is reset by
another LEFTMARGIN control.

Note that a control line is one that contains a dollar sign in the column specified by
the- most recent LEFTMARGIN control.

11.4 Object File Controls


These controls determine what type of object file is to be produced and on which
device it is to appear. The controls are discussed in the following order:

INTVECTOR/NOINTVECTOR
OVERFLOW /NOOVERFLOW
OPTIMIZE
OBJECT /NOOBJECT
DEBUG/NQDEBUG
TYPE/NOTYPE
Program Size Controls
RAM/ROM

11-3
Compiler Controls PL/M-86 User's Guide

INTVECTOR/NOtNTVECTOR

These are primary controls. They have the form

IHTVECTOR
HOIHTVECTOR
Default: I HTV ECTOR

Under the INTVECTOR control, the compiler creates an interrupt vector consisting
of a 4-byte entry for each interrupt procedure in the module. For Interrupt n, the
inten:upt vector entry is located at absolute location 4* n. See Chapter 8 and Appen-
dix G for further discussion.

Alternatively, it may be desirable to create the interrupt vector independently, using


either PLfM-86 or assembly language. In this case, the NOINTVECTOR control is
used and the compiler does not generate any interrupt vector. The implications of
this are discussed in Appendix G.

OVERFLOW I NOOVERFLOW

These are general controls. They have the form:

OVERFLOW
HOOVERFLOW
Default: H0 0 VERFLO W

These controls specify whether overflow is to be detected in performing signed


(INTEGER) arithmetic. If the NOOVERFLOW control is specified, no overflow
detection is implemented in the compiled module and the results of overflow in signed
arithmetic are undefined. If the OVERFLOW control is specified, overflow in signed
arithmetic results in a nonmaskable Interrupt 4, and it is the programmer's respon-
sibility to provide an interrupt procedure to handle the interrupt. Failure to provide
such a procedure may result in unpredictable program behavior when overflow occurs.

If this control is nested within a program statement, overflow detection will begin
when the next complete statement is evaluated.

Note that the use of the OVERFLOW control results in some expansion of the object
code.

OPTIMIZE

This is a primary control. It has the form:

OPT I ,., I ZE(n)


Default: 0 P T I ,., I Z E ( 1 )

where
n may be 0, 1,2, or 3.

This control governs the kinds of optimization to be performed in generating object


code.

11-4
PLfM-86 User's Guide Compiler Controls

OPTIMIZE(O) is the only level of optimization that does not optimize code
between program lines. Thus, it is the only one that gives guaranteed results
when your programs are debugged with a debugger such as the ICE 86
debugger.

OPTIMIZE(O)
OPTIMIZE(O)specifies only '~folding" of constant expressions.

Folding means recognizing, during compilation, operations that are superfluous or


combinable, and removing or combining them so as to save memory space or execu-
tion time. Examples include addition with a zero operand, multiplication by one, and
logical expressions with "true" or "false" constants. Also, in the statement:

A • 6 + 3 + A;

the compiler will add 6 and 3, producing code to add 9 to A.

OPTIMIZE(l)
OPTIMIZE( 1) specifies strength reduction, elimination of common subexpressions,
short-circuit evaluation of some Boolean expressions, and the above optimizations of
level (0).

Strength reduction means substituting quick operations in place of longer operations,


e.g., shifting left by 1 instead of multiplying by 2. This instruction requires less space
and executes faster. The addition of identical subexpressions may also generate left
shift instructions.

Elimination of common sub expressions means that if an expression reappears in the


same block, its value is re-used rather than being recomputed. The compiler also
recognizes commutative forms of subexpressions, e.g., A + Band B + A are seen to
be the same. Intermediate results during expression evaluation are saved in registers
and/or on the stack for later use. For example:

A • B + C*D/3;
C • E + D*C/3;

The value of C*D/3 will not be recomputed for the second statement.

Optimizing the evaluation of Boolean expressions uses the fact that in certain cases
some of the terms are not needed to determine the value of the expression. For
example, in the expression:

( A ) B AHD I ) J )

if the first term (A> B) is false, the entire expression is false, and it is not necessary
to evaluate the second term. The use of PL/M-86 built-in procedures does not change
this optimization. However, if a user-function or an embedded assignment is part of
the expression, this short evaluation is not done. For example:

( A ) B AHD ( UFUH (A) ) J »


is evaluated in full.

11-5
Compiler Controls PL/M-86 User's Guide

OPTIMIZE(2)
OPTIMIZE(2) specifies all of the above, plus the following:
• Machine code optimizations (e.g., short jumps, moves)
• Elimination of superfluous branches
• Re-use of duplicate code
• Removal of unreachable code and reversal of branch-condition

Optimizing machine code means saving space by using shorter forms for identical
machine instructions. This is possible because the iAPX 86 has multiple forms for
some of its instructions. For example:

MOV RESLT1, AX; ,- move accumulator value to location RESLT1 -,

can be generated in 3 bytes as A30800, or in 4 bytes as B9060800. The former choice


saves a byte of storage for the program. Similarly, jumps that the compiler can recog-
nize as within the same segment or even closer, within 127 bytes, permit the use of
fewer byte instructions.

Elimination of superfluous branches means optimizing consecutive or multiple


branches into a single branch example. For example:

JZ LAB 1 j /- Jump on zero to LAB1 -/


JMP LAB2j /' unconditional jump to LAB2 '/
LAB1:

LAB2:
will be transformed into:

JHZ LAB2i /' Jump on non-zero to LAB2 '/


LAB1:

LAB2:
Similarly, multiple branches like the following are eliminated:

LABO: JMP LAB1

lAB 1 : JMP LAB2

lAB2:
and transformed into:

lABO: JMP lAB2

lAB 1 : JMP LAB2

lAB2:

11-6
PL/M-86 User's Guide CompHer Controls

Reuse of duplicate code can refer to identical code at the end of two converging
paths. In such a case, the code is inserted in only one path, and a jump to that path
is inserted in the other path. For example:

DECLARE A BYTE, SPOT POINTER;


IF A .
DECLARE S BASED SPOT STRUCTURE (B BYTE, C BYTE);
1 THEN
S. C .
INPUT (OF7H) AND 07 F H;
ELSE
S. C .
INPUT (OF9H) and 07 F H;

Before After

CMP A, 1 H CMP A,1H


JZ &+SH J NZ ,1
JMP ,1
IN OF7H IN OF7H
AND AL , 7FH JMP ,2
MOV BX, SPOT
MOV S [BX+1Hl, AL
JMP ,2
,1 : IN OF9H ,1 : IN OF9H
AND AL , 7FH ,2: AND AL, 7FH
MOV BX, SPOT MOV BX, SPOT
MOV S [BX+1Hl, AL MOV S [BX+1Hl, AL
,2:

Reuse of duplicate code can also refer to machine instructions immediately preceding
a loop-instructions that are identical to those ending the loop. A branch can be
generated to re-use the code generated at the beginning of the loop. For example:

Before After

ADD AX, BX LABO: ADD AXJ BX


MOV AN S , AX MOV ANS,AX
LABO: MOV AL , DUM1 MOV AL J DUM1
CMP AL , DUM2 CMP AL , DUM2
JNZ LAB1 JNZ LAB1

ADD AX,B X JMP LABO


MOV AN S , AX LAB 1 :
JMP LABO
LAB1:

This is safe so long as LABO is not the target of a jump instruction. The compiler
normally handles a whole procedure at a time, and is thus aware of such a condition.
The optimization cannot be safely applied to labels in the outer level of the main
program module. This optimization will not change your program and will save code
space.

The optimization that removes unreachable code takes a second look at the generated
object code and finds areas which can never be reached due to the control structures
created earlier.

11-7
Compiler Controls PLfM-86 User's Guide

For example, if the following code were generated before optimization:

MOV AX , A
RCR AL , 1
JB ,1
JMP ,2
, 1: MOV AX , OFFFFH
OUTW OF6H
JMP ,2
MOV AX , B
ADD A, AX
JMP ,3
,2:

,3 : ......
. . . . ..
then the removal of unreachable code would produce:

MOV AX, A
RCR AL,1
JB
JMP
,1,2
,1: MOV AX, OFFFFH
OUTW OF6H
JMP ,2
,2 :
,3 :
This can be further optimized by reversing the branch condition in the third
instruction and removing the unnecessary JMP @2:

MOV AX, A
RCR AL, 1
JHB ,2
,1: MOV AX, OFFFFH
OUTW OF6H
,2:

,3 :

OPTIMIZE(3)
OPTIMIZE(3) includes all of the above optimizations. It also optimizes indetermi-
nate storage operations (e.g., those using based variables or variables declared with
the AT attribute). The assumption validating this new optimization is that based
variables (or AT variables) are not overlaying other user-declared variables.

On this optimization level, all Boolean expressions are short-circuited except those
containing embedded assignments. (For a description of how this optimization occurs,
see OPTIMIZE(1 ).)

11-8
Compiler Controls

The benefits of this optimization level include more efficient use of code space because
the user guarantees that needed values are not overlaid.

The first guarantee is a consequence of user caution in variable-declaration and usage.


For example, the sequence:

DECLARE (I,J) WORD;


DECLARE THETA (19) AT e,I);
DECLARE A BASED J (10)
STRUCTURE (F1 BYTE F2 WDRD); 1

J •• I ;

A(I).F1 • 7;
A(I).F2 • 99;
THETA(I) • 31;

violates this caution and guarantee because it causes the values being used as pointers
and subscripts to be overlaid. The compiler normally takes steps to avoid the diffi-
culties implied here. But, in OPTIMIZE(3), these steps are omitted due to the implicit
user guarantee that such situations have been avoided.

Figures 11-1 through 11-4 illustrate the levels of optimization described above.

system-id PL/M-86 V2.1 COMPILATION OF MODULE EXAMPLES_OF_OPTIMIZATIONS


OBJECT MODULE PLACED IN :Fl:EXMPLE.OBJ
COMPILER INVOKED BY: :Fl:PLM86.86 :F1:EXMPLE.SRC NOPAGING COMPACT CODE OPTIMIZE(0)

EXAMPLES OF OPTIMIZATIONS: DO;


2 1 DECLARE (A,B,C) WORD, D(100) WORD, (PTR 1, PTR_2) POINTER,
ABASED BASED PTR 1 (10) WORD;
3 1 DO WHILE D(A+B) < D(A+B+l);
4 2 IF PTR 1 = PTR 2 THEN DO;
6 3 A =-A * 2; -
7 3 ABASED (A) = ABASED(B);
8 3 ABASED (B) = ABASED(C);
9 3 END;
10 2 ELSE A = A + 1;
11 2 END;
12 1 END EXAMPLES_OF_OPTIMIZA'l'IONS;
STATEMENT # 3

00013 8BEC MOV BP,SP


00132 FB STI
@1:
1313133 8B1E0139~ MOV BX,A
9907 031E921HJ ADD BX,B
099B D1E3 SHL BX,l
0130D 8B36909fcJ MOV SI,A
fcJ011 fcJ3360290 ADD SI,B
0915 D1E6 SHL SI,l
0017 8B879690 MOV AX,D[BX]
001B 3B84fcJ800 CMP AX,D[SI+2H]
fcJ01F 7203 JB $+5H
0921 E97700 JMP @2

Figure 11-1. Sample Program Showing the OPTIMIZE(O) Control

11-9
Compiler Controls PL/M-86 User's Guide

; STATEMENT # 4
0024 C406CE00 LES AX,PTR- 1
0028 06 PUSH ES ; 1
0029 C416D200 LES DX,PTR_2
002D 8CC7 MOV DI,ES
002F 5E POP SI 1
0030 B104 MOV CL,4H
0032 8BD8 MOV BX,AX
0034 D3EB SHR BX,CL
0036 03F3 ADD SI,BX
0038 8BDA MOV BX,DX
003A D3EB SHR BX,CL
003C 03FB ADD DI,BX
003E 3BF7 CMP SI,D!
0040 7507 JNZ $+9H
0042 240F AND AL,0FH
0044 80E20F AND DL,0FH
oIr:J 47 3AC2 CMP AL,DL
0049 7403 JZ $+5H
004B E94100 JMP @3
STATEMENT it 6
004E 8B1360000 MOV AX,A
0052 D1E0 SHL AX,l
01r:J54 891360000 MOV A,AX
STATEMENT it 7
0058 8B360200 MOV SI,B
005C D1E6 SHL SI,l
005E 8B3E00013 MOV DI,A
0062 D1E7 SHL DI,l
0064 C41ECE00 LES BX,PTR_1
0068 268B00 MOV AX,ES: [BX] .ABASED[SI]
006B C41ECE00 LES BX,PTR 1
006F 268901 MOV ES:[BXT.ABASED[DI],AX
; STATEMENT it 8
0072 8B360400 MOV SI,C
0076 D1E6 SHL SI,l
0078 8B3E0200 MOV 01,8
0!67C D1E7 SHL 01,1
007E C41ECE00 LES BX,PTR_1
01482 268B00 MOV AX , ES: [BX] • ABAS ED [S I ]
0085 C41ECE00 LES BX,PTR_1
00d9 268901 MOV ES:[BX] .ABASED[DI],AX
; STATEMENT It 10
008C E90900 JMP @4
@3:
1608F 8B0ti0000 MOV AX,A
0093 40 INC AX
ItH694 8906000" MOV A,AX
STATEMENT It 11
@4:
0098 E96dFF JMP @l
@2:
STATEMENT # 12

Figure 11-1. Sample Program Showing the OPTIMIZE(O) Control (Cont'd.)

11-10
PL/M-86 User's Guide Compiler Controls

l-tOOULE INFORMATION:

CODE AREA SIZE 131cJ9BH 1550


CONSTANT AREA SIZE 130~H3H 13D
VARIABLE AREA SIZE 0~D6H 214D
MAXIMUM STACK SIZE 13002H 20
12 LINES READ
ij PROGRAM WARNINGS
13 PROGRAM ERRORS

DICTIONARY SUMMARY:

27KB MEMORY AVAILABLE


3KB MEMORY USED (11%)
~KB DISK SPACE USED

END OF PL/M-86 COMPILATION

Figure 11-1. Sample Program Showing the OPTIMIZE(O) Control (Cont'd.)

systeffi-id PL/M-B6 V2.1 COMPILATION OF MODULE EXAMPLES OF OPTIMIZATIONS


OBJECT MODULE PLACED IN :Fl:EXMPLE.OBJ - -
COMPILER INVOKED BY: :Fl:PLM86.86 :Fl:EXMPLE.SRC NOPAGING COMPACT CODE OPTIMIZE(I)

EXAMPLES OF OPTIMIZATIONS: DO;


2 1 DECLARE (A,B,C) WORD, 0(100) WORD, (PTR 1, PTR_2) POINTER,
ABASED BASED PTR 1 (113) WO~D;
3 1 DO WHILE D(A+B) < D(A+B+l);
4 2 IF PTR 1 = PTR 2 THEN DO;
6 3 A =-A * 2; -
7 3 ABASED (A) = ABASED(B);
8 3 ABASED (B) = ABASED(C)i
9 3 END;
113 2 ELSE A = A + 1;
11 2 END;
12 1 END EXAMPLES_OF_OPTIMIZATIONS;
STATEMENT # 3

0000 8BEC MOV BP,SP


0002 FB STI
@1:
01303 8BIE013130 MOV BX,A
131307 8B1360200 MOV AX,B
0913B 03D8 ADD BX,AX
0900 DIE3 SHL BX,l
0f30F 8B8Ff3600 MOV CX,D[BX]
01313 3B8F0~f30 CMP CX,D[BX+2H]
0917 7203 JB $+5H
131319 E968f3~ JMP @2
STATEMENT # 4
001C C4f36CE013 LES AX,PTR_l
130213 06 PUSH ES ; 1
131321 C416D200 LES DX,PTR_2
~1325 aCC7 MOV DI,ES
131327 5E POP SI 1
131328 BHJ4 MOV CL,4H

Figure 11-2. Sample Progratn. Showing the OPTIMIZE(I) Control

11-11
Compiler Controls PL/M-86 U ..."s GIiIe

902A 8BD8 ROV BX,AX


992C D3EB SUR BX,CL
902E 83F3 AOD SI,BX
kf030 8BDA MOV BX,DX
9932 D3EB SHR BX,CL
11'''34 83FB ADD DI,BX
0"36 3B!'7 CMP SI,D1
""38 7587 Jt!lZ $+9H
iS3A 248F AIm AL,flFH
4UJ3C 8C1E2"F AND DL,8m
U93F 3AC2 CI'IP AL,O£.
""41 7403 JZ $+5H
0(143 E937(19 JMP @3
STATEMENT I 6
flfrJ46 8B068fiHJ9 KOV AX,A
flCl4A 01E9 SHL AX,l
0"4C 8906"""" HOV A,AX
; STATEMENT I 7
""58 8B3602"" MOV SI,B
""54 D1E6 SHL 51,1
0956 01E0 SHL AX,l
"958 C4lECE"9 LES BX,PTR 1
""5C 268B08 MOV CX,ES:[BX] .ABASEO[SI]
0~5F 8BF0 MOV SI,AX
0061 268908 MOV ES:[BX].ABASEO[SI] ,CX
; STATEMENT t 8
"064 8B36049" MOV SI,C
9968 01E6 SHL SI,l
"06A 8B3E0200 MOV OI,B
096E DIE7 SHL 01,1
0070 C41ECE00 LES 8X,PTR 1
"ft.174 26880111 MOV AX,ES:[BX].ABASED[SI]
0077 268901 MOV ES:[BX] .ABASED[DI] ,AX
; STATEMENT # 10
007A E904~0 JMP @4
@3:
0070 FF96009" INC A
STATEMENT # 11
@4:
9981 E97FFF JMP @1
@2:
STATEMENT # 12

MODULE INFORMATION:

CODE AREA SIZE 0984H 132D


CONSTANT AREA SIZE 000UH 90
VARIABLE AREA SIZE 0"D6H 214D
MAXIMUM STACK SIZE 0U02H 2D
12 LINES READ
o PROGRAM WARNINGS
" PROGRAM ERRORS

DICTIONARY SUMMARY:

27KB MEMORY AVAILABLE


3KB MEMORY USED (11%)
0KB DISK SPACE USED

Figure 11-2. Sample Program Showing the OPTIMIZE(I) Control (Cont'd.)

11-12
PL/M-86 User's GaRIe Compiler Contt,ols

system-id PL/M-86 V2.1 COMPILATION OF MODOLE EXAMPLES OF OPTIMIZATIONS


OBJt:CT MODULE PLACED IN :Fl:EXMPLE.OBJ - -
COMPILER INVOKED BY: :Fl:PLM86.86 :Fl:EXMPLE.SRC NOPAGING COMPACT CODE OPTIMIZE(2)

EXAMPLES OF OPTIMIZATIONS: DO;


2 1 DECLARE (A,B,C) WORD, 0(1.08) WORD, (PTR 1, PTR_2) POINTER,
ABASED BASED PTR 1 (l0) WORD;
3 1 DO WHILE D(A+B) < D(A+B+l);
4 2 IF PTR 1 = PTR 2 THEN DO;
6 3 A =-A * 2; -
7 3 ABASED (A) = ABASED(S);
8 3 ABASED (B) = ABASED(C);
9 3 END;
10 2 ELSE A = A + 1;
11 2 END;
12 1 END EXAMPLES_OF_OPTIMIZATIONS;
; STATEMENT t 3

8BEC MOV BP,SP


FB STI
@1:
0003 8BIE3~16~ MOV BX,A
0007 A13203 MOV AX,B
0160A 0308 ADD BX,AX
000C DIE3 SHL ax,l
0160E 8B8F0600 HOV CX,D[BX]
0012 3B8F0800 CMP cx , D [BX +2H]
0016 7361 JAE @2
; STATEMENT t 4
1601B C406CE00 LES AX,PTR_l
001C 06 PUSH ES ; 1
001D C416D2016 LES DX,PTR 2
0021 8CC7 MOV DI,ES -
01623 5E POP 51 1
0024 B104 MOV CL,4H
0026 8BD8 MOV BX,AX
0028 03EB SHR BX,CL
~02A 03F3 ADD SI,BX
002C 8BDA MOV BX,DX
0~2E 03EB SHR BX,CL
0030 03FB ADD OI,BX
3332 3BF7 CMP SI,DI
3034 7507 JNZ $+9H.
0336 243F AND AL,0FH
0038 80E20F AND DL,0FH
003B 3AC2 CMP AL,DL
003D 7534 JNZ @3
STATEMENT # 6
303F Al1313013 MOV AX,A
0042 D1E0 SHL AX,l
0Cc144 A30000 MOV A,AX
STATEMENT # 7
31647 8B3602130 MOV SI,B
304B D1E6 SHL SI,l
304D DIE13 SHL AX,l
004E' C41ECE130 LES BX,PTR 1
01653 268B08 MOV cX,Es:TBX].ABASED[SI]
0056 8BFtIJ MOV SI,AX
0058 268908 MOV ES: [BX] .ABASED[SI] ,CX

Figure 11-3. Sample Program Showin~ the O~E(l) Control

11-13
Compiler Controls PL/M-86 User's Guide

S'TATEMENT i 8
I,H'58 8B3604101rJ MOV SI,C
005F D1E6 SHL SI,l
0061 8B3E0200 MOV DI,B
0065 D1E7 SIlL 01,1
01007 C41ECE00 LES BX,PTR 1
0166B 268B00 MOV AX,ES:[BX] .ABASED[SI]
906E 268901 MOV ES:[BX}.ABASED[DI] ,AX
; 'STATEMENT i 10
0071 E890 JMP @1
@3:
0073 FF060000 INC A
STATEMENT i 11
0077 EB8A JMP @1
@2:
STATEMENT i 12

MODULE INFORMATION:

CODE AREA SIZE 0079H 1210


CONSTANT AREA SIZE 0000H 00
VARIABLE AREA SIZE 00D6H 2140
MAXIMUM STACK SIZE 0002H 20
12 LINES READ
o PROGRAM WARNINGS
o PROGRAM ERRORS
DICTIONARY SUMMARY:
27KB MEMORY AVAILABLE
3KB MEMORY USED (11%)
0KB DISK SPACE USED

END OF PL/M-86 COMPILATION

Figure 11-3. Sample Program Showing the OPTIMIZE(2) Control (Cont'd.)

system-id PL/M-86 V2.1 COMPILATION OF MODULE EXAMPLES OF OPTIMIZATIONS


OBJECT MODULE PLACED IN :Fl:EXMPLE.OBJ - -
COMPILER INVOKED BY: :Fl:PLM86.86 :F1:EXMPLE.SRC NOPAGING COMPACT CODE OPTIMIZE(3)

EXAMPLES OF OPTIMIZATIONS: DO;


2 1 DECLARE (A,B,C) WORD, 0(100) wORD, (PTR 1, PTR_2) POINTER,
ABASED BASED PTR 1 (10) WORD; -
3 1 DO WHILE D(A+B) < D(A+B+l);
4 2 IF PTR 1 = PTR 2 THEN DO;
6 3 A =-A * 2; -
7 3 ABASED (A) = ABASED(B);
8 3 ABASED (B) = ABASED(C);
9 3 END;
10 2 ELSE A = A + 1;
11 2 END;
12 1 END EXAMPLES_OF_OPTIMIZATIONSi

Figure 11-4. Sample Program Showing the OPTIMIZE(3) Control

11-14
PL/M-86 User's Guide Compiler Controls

STATEMENT # 3
fHJ00 8BEC MOV BP,SP
0002 FB STI
@1:
13003 8B1E001313 MOV BX,A
01307 A102130 MOV AX,B
01613A 0308 ADD BX,AX
0130C 01E3 SHL BX,l
0130E 8B8F06130 MOV CX,D[BX]
01612 3B8F08130 CMP CX,D[BX+2H]
131316 733D JAE @2
; STATEMEWf # 4
0018 C41ECE1313 LES BX,PTR_1
1301C 8CC6 MOV SI,ES
0i61E 3B36D4013 CMP SI,PTR 2+2H
131622 7504 JNZ $+6H -
01324 3BIED2013 CMP BX,PTR 2
0028 7525 JNZ @3 -
STATEHENT # 6
0162A Al1301313 MOV AX,A
0132D DIE13 SHL AX,l
0162F A300130 MOV A,AX
STATEMENT # 7
13032 8B3E02130 MOV DI,B
01336 D1E7 SHL DI,l
131338 01E13 SHL AX,l
0163A 268B0~ MOV CX,ES: [BX].ABASED[DI]
0030 96 XCHG AX,SI
0163E 268908 MOV ES: [BX] .ABASED [SI] ,CX
; STATEMENT # 8
131341 8B36134130 MOV SI,C
0i645 01E6 SHL SI,l
01347 268B138 MOV CX,ES:[BX] .ABASED[SI]
004A 268909 MOV ES: [BX] .ABASED[DI] ,ex
; STATEMENT # 113
0134D EBB4 JMP @1
@3:
004F FF136130130 INC A
STATEMENT # 11
0053 EBAE JMP @1
@2:
STATEMENT # 12

MODULE I r.J FORt-1AT I ON :

CODE AREA SIZE 0055H 85D


CONSTANT AREA SIZE 13kHJ0H 00
VARIABLE AREA SIZB 00D6H 214D
MAXIMUM STACK SIZE 00i3I6H 0D
12 LINES READ
0 PROGRAM WARNINGS
13 PROGRAM ERRORS

DICTIONARY SUMHARY:

27KB MEMORY AVAILABLE


3KB MEMORY USBD (11%)
~KB DISK SPACE USED

ElJD OF PL/M-86 COMPILATION

Figure 11-4. Sample Program Showing the OPTIMIZE(3) Control (Cont'd.)

11-15
Compiler Controls PL/M-86 User's Guide

OBJECT I NOOBJECT

These are primary controls. They have the form:

OBJECT
oB J E CT ( pathname)
HOOBJECT
Default: 0 B J E C T ( source-file. 0 B J )

The OBJECT control specifies that an object module is to be created during the
compilation. The pathname is a standard operating system pathname that specifies
the file to receive the object module. If the control is absent or if an OBJECT control
appears without a pathname, the object module is directed to the same file name used
for source input, but with the extension OBJ.

The NOOBJECT control specifies that an object module is not to be produced.

Object Module Sections


The output of the compiler is an object file containing the compiled module. This
object module may be linked with other object modules and located using LINK86
and LOC86. A knowledge of the makeup of an object module is not necessary for
PL/M-86 programming, but it can aid you in understanding the controls for program
size, linkage, and location.

The object module output by the compiler contains five sections.


• Code Section
• Constant Section (absent in LARGE case and in ROM-see below)
• Data Section
• Stack Section
• Memory Section

As explained later in this chapter, these sections can be combined in various ways
into "memory segments" for execution, depending on the size of the program
(SMALL, COMPACT, MEDIUM, or LARGE).

Code Section. This section contains the object code generated by the source program.
If either the LARGE control or the ROM control is used, this section also· contains
the information that would otherwise be in the constant section.

In addition, the code section for the main program module contains a "main program
prologue" generated by the compiler. This code precedes the code compiled from the
source program, and sets the CPU up for program execution by initializing-various
registers and enabling interrupts.

Constant Section. This section contains all variables initialized with the DATA
attribute, as well as all REAL constants and all constant lists. If the LARGE or
ROM controls are used, this information is placed in the code section and no constant
section is produced.

Data Section. All variables are allocated space in this section except parameters,
based variables, and variables that are located with an AT attribute, initialized with
the DATA attribute, or local to a REENTRANT procedure.

11-16
PLfM-86 User's Guide Compiler Controls

Further, if a nested procedure refers to any parameter of an enclosing procedure,


then during execution all parameters of the enclosing procedure will be placed in the
data segment. The compiler reserves enough space during compilation to prepare for
this.

Stack Section. The stack section is used in executing procedures, as explained in


Appendixes F and G. It is also used for any temporary storage used by the program
but not explicitly declared in the source module (such as temporary variables
generated by the compiler).

The exact size of the stack is automatically determined by the compiler except for
possible multiple incarnations of reentrant procedures. The user can override this
computation of stack size and explicitly state the stack requirement during the
relocation process.

NOTE
When using reentrant procedures or interrupt procedures the user must be
careful to allocate a stack section large enough to accommodate all possible
storage required by multiple incarnations of such procedures. The stack size
can be explicitly specified during the relocation and linkage process.

The stack space requirement of each procedure is shown in the listing produced by
the SYMBOLS or XREF control. This information can be used to compute the
additional stack space required for reentrant or interrupt procedures.

Memory Section. This is the area of memory referenced by the built-in PL/M-86
identifier MEMORY. Its maximum allowable size depends on the size control used
in compilation (SMALL, COMPACT, MEDIUM, or LARGE) as explained below.

The compiler generates a memory section of length zero, and it is your responsibility
to specify the actual (run-time) space required during the linkage and relocation
process. The iAPX 86,88 Family Utilities User's Guide can assist you in this.

DEBUG/NODEBUG
These are primary controls. They have the form

DEBUG
NDDEBUG
Default: NOD E BUG

The DEBUG control specifies that the object module is to contain the statement
number and relative address of each source program statement, information about
each local symbol (including based symbols and procedure parameters), and block
information for each procedure. This information may be used later by a debugger
such as the ICE 86 debugger.

OPTIMIZE(O) is the only level of optimization that does not optimize code
between program lines. Thus, it is the only one that gives guaranteed results
when your programs are debugged with a debugger such as the ICE 86.

11-17
Compiler Controls PL/M-86 User's Guide

TYPE I NOTYPE
These are primary controls. They have the form

TYPE
HOTYPE
Default: T YP E

The TYPE control specifies that the object module is to contain information on the
variable types output in symbol records. This information may be used later for type
checking by the iAPX 86 Linker, or by a debugger such as the ICE 86 debugger.

The NOTYPE control specifies that such type definitions are not to be placed in the
object module.

Program Size Controls

These controls specify the memory size requirements of the program that is to contain
the module being compiled. They affect the operation of the compiler in various ways
and impose certain constraints on the source module being compiled.

These controls also influence how locations are referenced in the compiled program,
which leads to certain programming restrictions for each size control.

Note that for maximum efficiency of the object code, the smallest possible size should
be used for any given program. Also note that all modules of a program must be
compiled with the same size control. These are primary controls. They have the form:

SMALL
COMPACT
MEDIUM
LARGE
Default: SMA LL

Extensions to these controls are discussed in Chapter 13.

NOTE
Usage of the NIL pointer can lead to undesirable results (see section 9.7).

The SMALL Case


When modules compiled with the SMALL control are linked, the code sections from
all modules are combined and are allocated space within one segment. The segment
address for this segment is kept in the CS register. The constant, data, stack, and
memory sections from all modules are allocated space within a second segment. The
segment address for this second segment is kept in the DS register, with an identical
copy in the SS register.

Therefore, the SMALL control may be used if the total size of all code sections does
not exceed 64 K, and the total size of all constant, data, stack, and memory sections
does not exceed 64K.

11-18
PLJM-86 User's Guide Compiler Controls

Since there is only one segment for code, the segment address for this segment (CS
register) is never updated during program execution. Likewise, since there 'is only one
segment for constants, data, stack, and memory sections, the segmen.t address for this
segment (DS and SS registers) is never updated (except when an interrupt occurs, as
explained in Appendix G). Therefore, when any location is referenced, only a 16-bit
offset is calculated and then used in conjunction with the appropriate segment address.
POINTER values are therefore 16-bit values in the SMALL case, and this leads to
the following restrictions.
I. POINTER variables may not be initialized with, or assigned, whole-number
constants, for example:

DECLARE RR POINTER INITIAL (2277); !*invalid under SMALL*!


DECLARE 55 POINTER;
SS = 100; !*invalid under SMALL*!
2. The @ operator must not be used with a variable that was located at an absolute
address that was specified by a whole-number constant, for example:

DECLARE JO BYTE AT (100») PO POINTER;


PO = ,JOj !*invalid under SMALL*!
This restriction does not apply if the absolute address in the declaration is created
by the @ operator with a variable, for example:

DECLARE UKE BYTE) NAGE POINTER;


DECLARE SKI BYTE AT (lUKE);
HAGE = ,SKI; !*valid*!
3. The PUBLIC attribute must not be used with a variable located at an absolute
address specified by a whole-number constant. As above, this restriction does not
apply when @ is used:

DECLARE SHOMEH BYTE PUBLIC AT (100); !*invalid·!


DECLARE IKYO BYTE;
DECLARE SAHKYOBYTE PUBLIC AT (,IKYO); I*valid*!
This restriction arises because external variables are assumed to be in the DATA
segment.
4. Restrictions 1 and 2 apply also to WORD variables when used as offset pointers
and to the use of the dot operator.
5. The @ and dot operators may not be used with variables based on SELECTOR,
for example:

DECLARE SEL SELECTOR;


DECLARE R BASED SEL BYTEj
DECLARE PO POINTER;
PO • ,R 1* invalid under SMALL *!

6. If the built-in function SELECTOR$OF is used, it will always return the value
of the DS register. If BUILD$PTR is used, it will ignore the SELECTOR
expression (see section 9.7).

PLjM-80 Compatibility. The SMALL control is the most likely choice when compil-
ing a program written in PL/M-80. The compiler produces error messages to flag
violations of any of the restrictions or to flag the use of the new reserved keyboards

11-19
Compiler Controls PLfM-86 User's Guide

(DWORD, INTEGER, REAL, POINTER, SELECTOR, and CAUSEINTER-


RUPT) as programmer-defined identifiers. Otherwise, complete upwards
compatibility is provided by PL/M-86.

NOTE
Care must be used with the dot operator under conditions other than SMALL
and RAM.

The COMPACT Case


A program compiled with the COMPACT control has four segments: code, data,
stack, and memory. Each of these is the result of combining the same-type sections
from all modules, and each has a maximum size of 64K bytes. The constant sections
from all modules are grouped with the data segment unless the ROM control is used,
which causes all constant sections to be merged into the CODE segment instead.
Since the code, data, and stack segments are fully defined by the time the program
is loaded, the segment base addresses in the CS and SS registers are never changed.
(The DS register may change when an interrupt occurs, as explained in Appendix F.)

All code and a few prologue constants are addressed relative to CS. All data except
absolute data (declared with the AT (constant) attribute) are addressed relative to
DS. The stack is addressed relative to SS. ES is not initialized and can change during
execution. References to any location require only a 16-bit offset address against
these segment base addresses.

The sole programming restriction in the COMPACT case is that PUBLIC variables
may not be declared AT an absolute location, for example:

DECLARE ANVIL BYTE PUBLIC AT (100);


is not allowed. This restriction does not apply when the "location" within the AT
attribute is formed with the @ operator, i.e., DECLARE ANVIL BYTE PUBLIC
AT (@HAMR); is valid. However, the phrases "@ MEMORY" and "MEMORY"
are not allowed in defining a PUBLIC variable.

Programming Restrictions in the COMPACT Case. The following restrictions must


be observed:
1. When an exported procedure is indirectly activated, a POINTER variable must
be used in the CALL statement, for example:

SCOMPACT(SUBSYS HAS MOD1, MOD2, MOD3; EXPORTS PROC)


MOD1: DO
DECLARE P POINTER, W WORD;
PROC: PROCEDURE PUBLIC;

END PROC;
P-,PROC; CALL P; 1* POINTER must be used */
W-.PROC; CALL W; 1* not allowed */
END MOD1;

11-20
PL/M-86 User's Guide Compiler Controls

2. When a procedure that is not exported is indirectly activated, a WORD variable


must be used. Note that WORD variables do not range over the entire iAPX 86
address space but are restricted to offsets within the current code segment, for
example:

DECLARE P POINTER, W WORD;


LPROC: PROCEDURE; 1* local *1

END LPROC;
P=,LPROC; CALL P; 1* not allowed *1
W=.LPROC; CALL W; 1* WORD must be used*1

The MEDIUM Case


In a program compiled with the MEDIUM control, a separate segment is used for
the code section of each compiled module. Therefore, the total space required for
code may exceed 64K, although the maximum size of anyone code section is still
limited to 64K.

The constant, data, stack, and memory sections of all modules are combined and are
allocated space within a single segment.

At any moment during program execution, one segment of code is the "current"
segment, and its segment address is kept in the CS register .. This segment address is
updated whenever a PUBLIC or EXTERNAL procedure is activated, since this may
involve a new code segment.

The segment address for the segment containing constants, data, stack, and memory
sections is kept in the OS register (with an identical copy in the SS register) and is
never changed (except when an interrupt occurs, as explained in Appendix G).

With the MEDIUM option, a POINTER value is a four-byte quantity containing a


segment address and an offset. Therefore, the first three restrictions of the SMALL
case do not apply. However, the MEDIUM case introduces two minor restrictions on
indirect procedure activation.

Programming Restrictions in the MEDIUM Case. The following restrictions must be


observed:
1. When a PUBLIC or EXTERNAL procedure is indirectly activated, a POINTER
variable must be used in the CALL statement, for example:

DECLARE P POINTER, W WORD;


PROC: PROCEDURE PUBLIC;

END PROC;
P·,PRDC; CALL P; I*recommended where an indirect
call must be used*1

11-21
Compiler Controls PL/M-86 User's Guide

2. When a procedure that is not PUBLIC or EXTERNAL is indirectly activated,


a WORD variable must be used. This is consistent with PL/M-80, and is not
recommended in the PL/M-86 programs because WORD variables do not range
over the entire iAPX 86 address space (but are restricted to offsets within an
assumed segment), for example:

DECLARE P POIHTER,-W WORDj


LPROC: PROCEDUREj /*local*/

END LPROCj
P=,LPROCj CALL Pj /*not allowed*/

W=.LPROCj CALL Wj /*not recommended, but


allowed*/

3. A variable that is absolutely located (by using the AT attribute with a numeric
constant) may not have the PUBLIC attribute. For example:

DECLARE B BYTE PUBLIC AT(100)j

is not allowed.
Restrictions 1 and 2 arise from the fact that the code segment address may change
during program execution. Restriction 3 is the same as Restriction 3 in the
SMALL case, and arises for the same reason.

The LARGE Case


In a program compiled with the LARGE control, a separate segment is used for the
code section (with constants) from each compiled module. Thus the total space
required for code and constants may exceed 64K, but the total for the code section
(with constants) from anyone module is limited to 64K.

A separate segment is used for the data section from each compiled module. Thus
the total space required for data sections may exceed 64K, although the size of any
one data section is limited to 64K.

The stack sections from all modules are combined in one segment, and the memory
sections for all modules are combined in another segment. Thus the total space
required for stack is limited to 64K, and the total space required for memory is also
limited to 64K.

At any moment during program execution, one code segment and one data' segment
are "current." Code and data segments are paired, so that the current code and data
segments are always from the same module. The compiler implements this pairing by
placing the segment address for the data segment in a reserved location in the code
section. During program execution, the segment addresses for the current code and
data segments are kept in the CS and DS registers, respectively, and are updated
whenever a PUBLIC or EXTERNAL procedure is activated, as this may involve new
code and data segments.

The stack segment address is kept in the SS register.

11-22
PL/M-86 User's Guide Compiler Controls

Programming Restrictions in the LARGE Case. These first two are the same as
Restrictions 1 and 2 in the MEDIUM case, and arise for the same reason.
1. When a PUBLIC or EXTERNAL procedure is indirectly activated, a POINTER
variable must be used in the CALL statement, for example:

DECLARE P POINTER, W WORD;


PROC: PROCEDURE PUBLIC;

END PROC;
P=,PROC; CALL P; /*recommended where an indirect
call must be made*/

W=.PROC; CALL W ; /*not allowed*/


2. When a procedure that is not PUBLIC or EXTERNAL is indirectly activated,
a WORD variable must be used. This is consistent with PL/M-80, and is not
recommended in PL/M-86 programs because WORD variables do not range over
the entire iAPX 86 address space (but are restricted to offsets within an assumed
segment), for example:

DECLARE P POINTER, W WORD;


LPROC: PROCEDURE; /*local*/

END LPROC;
P=,LPROC; CALL P; /*not allowed*/

W-. LPROC; CALL W; /*not recommended, but


allowed*/

RAM/ROM Control
This primary control directs the object-module placement of all constants, both
user-defined and compiler-generated. Its form is:

RAM
ROM
Default: RAM (except in LARGE model)

The default setting places the CONSTANT section within the DATA segment in all
segmentation models (sizes) except LARGE, in which constants are placed in the
CODE segment instead.

The ROM setting places constants in the CODE segment. Under this setting, the
INITIAL attribute on a variable produces a warning message. The dot operator is
not advised for variable references under the ROM option since constants and varia-
bles will be relative to different segment registers. If SMALL is also specified, then
pointers will be four bytes instead of two. (See also Appendix F.)

If the keyword DATA is used in a PUBLIC declaration when compiling with the
ROM control, DATA must also be used in the EXTERNAL declaration of program
modules that reference it. However, no value list is then permitted since the data is
defined elsewhere.

11-23
Compiler Controls PL/M-86 User's Guide

11.5 Listing Selection and Content Controls


These controls determine what types of listings are to be produced and on which
device they are to appear. The controls are discussed in the following order:

PRINT /NOPRINT
LIST /NOLIST
CODE/NOCODE
XREF /NOXREF
SYMBOLS/NOSYMBOLS

A sample listing is discussed at the end of this section.

PRINT INOPRINT

These are primary controls. They have the form:

P R I HT
P R I HT (pathname)
HOPRIHT
Default: P R I HT (source-file. L S T )

The PRINT control specifies that printed output is to be produced. Pathname is a


standard operating system pathname that specifies the file to receive the printed
output. Any output-type device, including a disk file, may also be given. If the control
is absent, or if a PRINT control appears without a pathname, printed output is sent
to a file that has the same name as the source file but with the extension LST.

The NOPRINT control specifies that no printed output is to be produced, even if


implied by other listing controls such as LIST and CODE.

LIST I NOLIST

These are general controls. They have the form:

LIS T
HOLIST
Default: LIS T

The LIST control specifies that listing of the source program is to resume with the
next source line read.

The NOLIST control specifies that listing of the ,source program is to be suppressed
until the next occurrence, if any, of a LIST control.

When LIST is in effect, all input lines (from the source file or from an INCLUDE
file), including control lines, are listed. When NOLIST is in effect, only source lines
associated with error messages are listed.

Note that the LIST control cannot override a NOPRINT control. If NOPRINT is
in effect, no listing whatsoever is produced.

11-24
PLfM-86 User's Guide Compiler Controls

CODE I NOCODE

These are general controls. They have the form:

CODE
HOCODE
Default: HOC 0 DE

The CODE control specifies that listing of the generated object code in standard
assembly language format is to begin. This listing is placed at the end of the program
listing on the listing file.

The NOCODE control specifies that listing of the generated object code is to be
suppressed until the next occurrence, if any, of a CODE control.

Note that the CODE control cannot override a NOPRINT control.

XREF/NOXREF

These are primary controls. They have the form:

XREF
HOXREF
Default: N0 XREF

The XREF control specifies that a cross-reference listing of source program identi-
fiers is to be produced on the listing file.

The NOXREF control suppresses the cross-reference listing.

Note that the XREF control cannot override a NOPRINT control.

SYMBOLS I NOSYMBOLS

These are primary controls. They have the form:

SYMBOLS
HOSYMBOLS
Default: H0 S Y MB 0 L S

The SYMBOLS control specifies that a listing of all identifiers in the PL/M-86 source
program and their attributes is to be produced on the listing file.

The NOSYMBOLS control suppresses such a listing.

Note that the SYMBOLS control cannot override a NOPRINT control.

11-25
Compiler Controls PL/M-86 User's Guide

11.6 Listing Format Controls


Format controls determine the format of the listing output of the compiler. The
controls are discussed in the following order:
PAGING/NOPAGING
PAGELENGTH
PAGEWIDTH
TITLE
SUBTITLE
EJECT

PAGING/NOPAGING

These are primary controls. They have the form:

PAGING
NOPAGING
Default: P AG I HG

The PAGING control specifies that the listed output is to be formatted onto pages.
Each page carries a heading identifying the compiler and a page number, and
possibly a user specified title.

The NOPAGING control specifies that page ejecting, page heading, and page
numbering are not to be performed. Thus, the listing appears on one long ''''page'' as
would be suitable for a slow serial output device. If NOPAGING is specified, a page
eject is not generated if an EJECT control is encountered.

PAGELENGTH

This is a primary control. It has the form:

P AGE L E HGT H (length)


Default: P AGE LEN GT H ( 6 0 )

where
length is a non-zero, unsigned integer specifying the maximum
number of lines to be printed per page of listing output. This
number is taken to include the page headings appearing on
the page.

The minimum value for length is 5.

PAGEWIDTH

This is a primary control. It has the form:

P AGE WID T H (width)


Default: P AGE WID T H ( 1 2 0 )

where
width is a non-zero, unsigned integer specifying the maximum line
width, in characters, to be used for listing output.

The minimum value for width is 60; the maximum value is 132.

11-26
PLfM-86 User's Guide Compiler Controls

TITLE

This is a primary control. It has the form:

TIT LE ( , title' )
Default: TIT LE (' module name' )

where
title is a sequence of printable ASCII characters that are enclosed
in quotes.

The sequence, truncated on the right to fit, if necessary, is placed in the title line of
each page of listed output.

The maximum length allowed for title is 60 characters, but a narrow pagewidth may
restrict this number further. For example:

TITLE('TEST PROGRAM 4')

SUBTITLE

This is a general control. It has the form:

SUB TIT LE( , subtitle' )


Default: no subtitle

where
subtitle is a sequence of printable ASCII characters that are enclosed
in single qUQtes.

The sequence, truncated on the right to fit, if necessary, is placed in the subtitle line
of each page of listed output.

The maximum length allowed for subtitle is 60 characters, but a narrow pagewidth
may restrict this number further. For example:

SUBTITLE('TEST PROGRAM 4')


When a SUBTITLE control appears before the first non control line in the source
file, it causes the specified subtitle to appear on the first page and all subsequent
pages until another SUBTITLE control appears.

A subsequent SUBTITLE control causes a page eject, and the new subtitle appears
on the next page and all subsequent pages until the next SUBTITLE control.

EJECT

This is a general control. It has the form:

EJECT

I t causes printing of the current page to terminate and a new page to be started. The
control line containing the EJECT control is the last one printed on the old page.

11-27
Compiler Controls PL/M-86 User's Guide

Sample Program Listing

During the compilation process, a listing of the source input is produced. Each page
of the listing carries a numbered page-header that identifies the compiler, prints a
time and date as designated by the host operating system, and optionally gives a title
and a subtitle, and/or a date (see figure 11-5).

The first part of the listing contains a summary of the compilation, beginning with
the compiler identification and the name of the source module being compiled. The
next line names the file receiving the object code. Then, the command line used to
invoke the compiler is reproduced. The listing of the program itself is shown in figure
11-5.

The listing contains a copy of the source input plus additional information. Two
columns of numbers appear to the left of the source image. The first column provides
a sequential numbering of PL/M-86 statements. Error messages, if any, refer to these
statement numbers. The second column gives the block nesting depth of the current
statement.

Lines included with the INCLUDE control are marked with an equal sign (=) just
to the left of the source image. If the included file contains another INCLUDE control,
lines included by this nested INCLUDE are marked with an "= I". For yet another
level of nesting, "= 2" is used to mark each line, and so forth up to the compiler's
limit of five levels of nesting. These markings make it easy to see where included text
begins and ends.

Should a source line be too long to fit on the page in one line, it will be continued on
the following line. Such continuation lines are marked with a hyphen (-) just to the
left of the source image.

The CODE control may be used to obtain the iAPX 86 assembly code produced in
the translation of each PL/M-86 statement. This code listing appears interspersed in
the source text. in six columns of information in a pseudo-assembly language format:
l. Location counter (hexadecimal notation)
2. Resultant binary code (hexadecimal notation)
3. Label field
4. Opcode mnemonic
5. Symbolic arguments
6. Comment field

Not all six of these columns will appear on anyone line of the code listing. Compiler
generated labels (e.g., those which mark the beginning and ending of a DO WHILE
loop) are preceded by an AT sign (@). The comments appearing on PUSH and POP
instructions indicate the stack depth associated with the stack instruction.

Symbol and Cross-Reference Listing

If specified by the XREF or SYMBOLS control, a summary of all identifier usage


appears following the program listing.

Depending on whether the SYMBOLS or XREF control was used to request the
identifier usage summary, six or seven types of information are provided in the symbol
or cross-reference listing. These are as follows:
1. Statement number where identifier was defined
2. Relative address associated with identifier

11-28
PLfM-86 User's Guide Compiler Controls

systeill-id PL/M-86 V2.1 COMPILATION OF MODULE STACK


OBJECT MODULE PLACED IN :F1:STACK.OBJ
COMPILER INVOKED BY: :F1:PLM86.86 :Fl:STACK.SRC NOPAGING CODE XREF
TITLE(STACK MODULE)

STACK: DO;
/* This module implements a BYTE stack with push and pop */
2 1 DECLARE S(100) BYTE, /*Stack Storage*/
T BYTE PUBLIC INITIAL(-1); /*Stack Index*/

3 1 PUSH: PROCEDURE (B) PUBLIC; /*Pushes B onto the stack*/


4 2 DECLARE B BYTE;
5 2 S(T:=T+l) = B; /*Increment T and store B*/
6 2 END PUSH;

7 1 POP: PROCEDURE BYTE PUBLIC; /*Returns value popped from stack*/


8 2 RETURN S«T:=T-1)+1); /*Decrement T, return S(T+l)*/
9 2 END POP;
10 1 END STACK; /*Module ends here*/
STATEMENT # 3

PUSH PROC NEAR


0000 55 PUSH BP
0001 8BEC MOV BP,SP
STATEl1ENT # 5
0003 8A066400 MOV AL,T
01007 FEC0 INC AL
0009 B400 MOV AH,0H
01608 881666400 MOV T,AL
000F 8BD8 MOV BX,AX
0011 8A4604 MOV AL,[BP].B
0014 88870000 MOV S(3X] ,AL
STATEMENT # 6
0018 50 POP BP
0019 C20200 RET 2H
PUSH ENDP
STATEMENT # 7
POP PROC NEAR
001C 55 PUSH BP
0161D 8BEC l"iOV BP,SP
STATEMENT # 8
IiHHF BA066400 MOV AL,T
0023 FECS DEC AL
0025 B400 MOV AH,0H
0027 881666400 MOV T,AL
002B 8B08 MOV BX,AX
00:lD 8A870100 MOV AL,S[BX+1H]
01631 50 POP BP
0032 C3 RErf
STATEI1ENT # 9
POP ENDP
; STATEMENT # 10
DEFN ADDR SIZE NAME, ATTRIBU'fES, AND REFERENCES

Figure 11-5. Program Listing

11-29
Compiler Controls PL/M-86 User's Guide

3. Size of object identified (in bytes)


4. The identifier
5. Attributes of the identifier (including expansion for LITERALLYsand scoping
information for local variables and parameters)
6. Statement numbers where identifier was referenced (XREF control only)
7. Statement numbers where identifier was assigned a value (XREF control only)

Notice that a single identifier may be declared more than once in a source module
(i.e., an identifier defined twice in different blocks). Each such unique object, even
though named by the same identifier, appears as a separate entry in the listing.

The address given for each object is the location of that object relative to the start of
its associated section. The object's attributes determine which section is applicable.

Identifiers in the SYMBOLS or XREF listing are given in alphabetical order with
the following exception: members of structures are listed, in order of declaration,
immediately following the entry for the structure itself. Indentation is used to
differentiate between these entries.

The XREF listing differentiates between items 6 and 7 by adding the character to
statement numbers where a value is assigned. For example, if statement 17 read:

+ 1;

the list of statement numbers would include 17 and 17*, indicating a reference and
an assignment in statement 17.

The AUTOMATIC attribute indicates that the identifier was declared as a parame-
ter or as a local variable in a REENTRANT procedure and therefore is allocated
dynamically on the stack.

Figure 11-6 is an example of the cross-reference listing.

P /M-86 COMPILER STACK MODULE


CROSS-REFERENCE LISTING

DEFN ADDR SIZE NAME, ATTRIBUTES, AND REFERENCES

4 0004H 1 B.
·· BYTE IN PROC (PUSH) PARAMETER
AUTOMATIC 4 5

PUSH ·
7 001CH 23 POP. PROCEDURE BYTE PUBLIC STACK=0002H
PROCEDURE PUBLIC STACK=0004H
3 0000H 28
·
2
1
0000H
0000H
100 S.
· · .. . . .
STACK.
BYTE ARRAY(100)
PROCEDURE STACK=0000H
5* 8

2 0064H 1 T.
·· BYTE PUBLIC INITIAL
5 5* 8 8*

Figure 11-6. Cross-Reference Listing

11-30
PLfM-86 User's Guide Compiler Controls

Compilation Summary

Following the listing (or appearing alone if NO LIST is in effect) is a compilation


summary. Eight pieces of information are provided:
• Code area size gives the size in bytes of the code section of the output module.
• Constant area size gives the size in bytes of the constant section of the output
module.
• Variable area size gives the size in bytes of the data section of the output module.
• Maximum stack size gives the size in bytes of the stack section allocated for the
output module.
• Lines read gives the number of source lines processed during compilation.
• Program warnings give the number of warning messages issued during
compilation. .
• Program errors give the number of error messages issued during compilation.
• Dictionary summary gives the amount of memory available for the dictionary,
the amount of memory that it actually used, and the amount of disk space that
it occupied.

Figure 11-7 is an example of the compilation summary. Refer to Chapter 13 for an


explanation of the various object module sections.

MODULE INFORMATION:

CODE AREA SIZE fHJ33H 510


CONSTANT AREA SIZE 000i6H 3D
VARIABLE AREA SIZE IIJ065H 1010
MAXIMUM STACK SIZE 00i/J4H 4D
14 LINES READ
o PROGRAM WARNINGS
o PROGRAM ERRORS
DICTIONARY SUMMARY:

27KB MEMORY AVAILABLE


3KB MEMORY USED (11%)
0KB DISK SPACE USED

END OF PL/M-86 COMPILATION

Figure 11-7. Compllation Summary

11-31
Compiler Controls PLfM-86 User's Guide

11.7 Source Inclusion Controls


These controls allow the input source to be changed to a different file. The controls
are:

INCLUDE
SAVE/RESTORE

INCLUDE
INCLUDE is a general control, with the form:

I HC L UDE ( pathname)

where
pathname is a standard operating system pathname specifying a file.

An INCLUDE control must be the rightmost control in a control line or in the


invocation command.

The INCLUDE control causes subsequent source lines to be input from the specified
file. Input will continue from this file until an end-of-file is detected. At that time,
input will be resumed from the file which was being processed when the INCLUDE
control was encountered.

An included file may itself contain INCLUDE controls. Note that such nesting of
included files may not exceed a depth of five.

SAVE/RESTORE
These are general controls. They have the form:

SAVE
RESTORE
These controls allow the settings of certain general controls to be saved on a stack
before an INCLUDE control switches the input source to another file, and then
restored after the end of the included file. However, SAVE and RESTORE can be
used for other purposes as well. The controls whose settings are saved and restored
are:

LIST /NOLIST
CODE/NOCODE
OVERFLOW /NOOVERFLOW
LEFTMARGIN
COND/NOCOND

The SAVE control saves all of these settings on a stack. This stack has a maximum
capacity of five sets of control settings, which corresponds to the maximum nesting
depth of five for the INCLUDE control.

The RESTORE control restores the most recently saved set of control settings from
the stack.

11-32
PL/M-86 User's Guide Compiler Controls

11.8 Conditional Compilation Controls


These controls allow selected portions of the source file to be skipped by the compiler
if specified conditions are not met. Figure 11-8 shows an example program using the
conditional compilation controls, while figure 11-9 shows the same example with
NOCOND being used.

The controls are:

IF /ELSEIF /ELSE/ENDIF
SET/RESET
COND/NOCOND

IF IELSE/ELSEIF IENDIF
These controls provide the actual conditional capability using conditions which are
based on the values of switches.

These controls cannot be used in the invocation of the compiler, and each must be
the only control on its control line.

An IF control and an ENDIF control are used to delimit an "IF element," which can
have several different forms. The simplest form of IF element is:

S I F condition
text
SEHDIF
where
condition is a limited form of PL/M expression in which the only
operators allowed are OR, XOR, NOT, AND, <, < =, =,
> =, and >, and the only operands allowed are switches and
whole-number constants in the range 0 to 255. If the switch
did not appear_ in a set control, a value of "false" (0) is
assumed. Parenthesized subexpressions are not allowed.
Within these restrictions, condition is evaluated according to
the PL/M-86 rules for expression evaluation. Note that
condition must be followed by a carriage return.
text is text which will be processed normally by the compiler if
the least significant bit of the value of condition is aI, or
skipped if the bit is a O. Note that text may contain any
mixture of PL/M-86 source and compiler controls. If the text
is skipped, any controls within it are not processed.

The second form of IF element contains an ELSE element:

$IF condition
text 1
.ELSE.
text 2
.EHDIF
In this construction, text 1 will be processed normally if the least significant bit of
the value of condition is aI, while text 2 will be skipped. If the bit is a 0, text 1 will
be skipped and text 2 will be processed normally.

Note that only one ELSE element is allowed within an IF element.

11-33
Compiler Controls PLfM-86 User's Guide

PL/M-86 COMPILER EXAMPLE

system-id PL/M-86 V2.1 COMPILATION OF MODULE EXAMPLE


OBJECT MODULE PLACED IN :F1:CEX.OBJ
COMPILER INVOKED BY: :F1:PLM86.86 :F1:CEX.SRC SET(DEBUG=3)

EXAMPLE: DO;

2 1 DECLARE BOOLEAN LITERALLY 'BYTE', TRUE LITERALLY '0FFH',


FALSE LITERALLY '~';
3 1 PRINT$DIAGNOSTICS: PROCEDURE (SWITCHES, TABLES) EXTERNAL;
4 2 DECLARE (SWITCHES, TABLES) BOOLEAN;
5 2 END PRINT$DIAGNOSTICS;

6 2 DISPLAY$PROMPT: PROCEDURE EXTERNAL; END DISPLAY$PROMPT;

8 2 AWAIT$CR: PROCEDURE EXTERNAL; END AWAIT$CR;

$IF DEBUG = 1
CALL PRINT$DIAGNOSTICS (TRUE, FALSE);
$ RESET (TRAP)
$ELSEIF DEBUG = 2
CALL PRINT$DIAGNOSTICS (TRUE, TRUE);
$ RESET (TRAP)
$ELSEIF DEBUG = 3
10 1 CALL PRINT$DIAGNOSTICS (TRUE, TRUE);
11 1 CALL PRINT$DIAGNOSTICS (TRUE, TRUE);
$ SET (TRAP)
$ENDIF

$IF TRAP
12 1 CALL DISPLAY$PROMPT;
13 1 CALL AWAIT$CRi
$ENDIF

14 1 END EXAt1PLE;

MODULE INFORMATION:

CODE AREA SIZE 0017H 23D


CONSTANT AREA SIZE 0000H 0D
VARIABLE AREA SIZE fHHJ0H 0D
MAXIMUM STACK SIZE 00id6H 6D
30 LINES READ
" PROGRAM WARNINGS
" PROGRAM ERRORS

DICTIONARY SUMMARY:

27KB MEMORY AVAILABLE


3KB MEMORY USED (11%)
0KB DISK SPACE USED

ENU OF PL/M-d6 COMPILATION

Figure 11-8. Sample Program Showing the SET(DEBUG=) Control

11-34
PLfM-86 User's Guide Compiler Controls

The most general form of IF element allows one or more ELSEIF elements to be
introduced before the ELSE element (if any):

S I F condition 1
text 1
S E L S ElF condition 2
text 2
S E L S ElF condition 3
text 3

S E L S ElF condition n
textn
SELSE
textn + 1
SENDIF

where any of the ELSEIF elements may be omitted, as may the ELSE element.

The conditions are tested in sequence. As soon as one of them yields a value with a 1
as its least significant bit, the associated text is processed normally. All other text in
the IF element is skipped. If none of the conditions yields a least significant bit of 1,
the text in the ELSE element (if any) is processed normally and all other text in the
IF element is skipped

SET/RESET
These are general controls. The SET control has the general form":

SET ( switch assignment list)

where
switch assignment list consists of one or more switch assignments separated by
commas.

A switch assignment has the form:

switch

or:

switch = value
where
switch is a name which is formed according to the PL/M-86 rules
for identifiers. Note that a switch name exists only at the
compiler control level, and therefore you may have a switch
with the same name as an identifier in the program; no
conflict is possible. However, note that a PL/M-86 reserved
word may not be used as a switch name.
value is a whole-number constant in the range 0 to 255. This value
is assigned to the switch. If the value and the equal sign ( = )
are omitted from the switch assignment, the default value
OFFH ("true") is assigned to the switch.

11-35
Compiler Controls PL/M-86 User's Guide

The following is an example of a SET control line:

$SET(TEST,ITERATIDH=3}
This example sets the switch TEST to "true" (OFFH) and the switch ITERATION
to 3. Note that switches do not need to be declared.

Figure 11-8 is an example of a program that was compiled using the SET control.

The RESET control has the form:

RES ET ( switch list>


where
switch list consists of one or more switch names that have already
occured in SET controls.

Each switch in the switch list is set to "false" (0).

CONO/NOCONO
These controls determine whether text within an IF element will appear in the listing
if it is skipped. These general controls have the form:

eOHD
HoeOHD
Default: C 0 HD

The COND control specifies that any text that is skipped is to be listed (without
statement or level numbers). Note that a COND control cannot override a NOLIST
or NOPRINT control, and that a COND control will not be processed if it is within
text which is skipped.

The NOCOND control specifies that text within an IF element which is skipped is
not to be listed. However, the controls that delimit the skipped text will be listed,
providing an indication that something has been skipped. Note that a NOCOND
control will not be processed if it is within text that is skipped.

Figure 11-9 is an example of a program that was compiled using the NOCOND
control.

system-id PL/M-86 V2.1 COMPILATION OF MODULE EXAMPLE


OBJECT MODULE PLACED IN :Fl:CEX.OBJ
COMPILER INVOKED BY: :Fl:PLM86.86 :Fl:CEX.SRC SET(DEBUG=3) NOCOND

EXAt1PLE: DO;

2 1 DECLARE BOOLEAN LITERALLY 'BYTE', TRUE LITERALLY '~FFH',


FALSE LITERALLY '0'; .
3 1 PRINT$DIAGNOSTICS: PROCEDURE (SWITCHES, TABLES) EXTERNAL;
4 2 DECLARE (SWITCHES, TABLES) BOOLEAN;
5 2 END PRINT$DIAGNOSTICS;

6 2 DISPLAY$PROMPT: PROCEDURE EXTERNAL; END DISPLAY$PROMPT;


Figure 11-9. Sample Program Showing the NOCOND Control

11-36
PLJM-86 User's Guide Compiler Controls

8 2 AwAIT$CR: PROCEDURE EXTERNAL; END AWAIT$CRi

$IF DEBUG = 1
$ELSEIF DEBUG = 3
10 1 CALL PRINT$DIAGNOSTICS (TRUE, TRUE) ;
11 1 CALL PRINT$DIAGNOSTICS (TRUE, TRUE) ;
$ SET (TRAP)
$ENDIF

$IF TRAP
12 1 CALL DISPLAY$PROMPTi
13 1 CALL At'lAIT$CR;
$ENDIF

14 1 END EXAMPLE;

MODULE INFORMATION:

CODE AREA SIZE 0~17H 230


CONSTANT AREA SIZE 0000H 00
VARIABLE AREA SIZE 0000H 0D
MAXIMUM STACK SIZE 0006H 60
30 LINES READ
o PROGRAM WARNINGS
o PROGRAM ERRORS
DICTIONARY SUMMARY:

27KB MEMORY AVAILABLE


3KB MEMORY USED (11%)
0KB DISK SPACE USED

END OF PL/M-86 COMPILATION

Figure 11-9. Sample Program Showing the NOCOND Control (Cont'd.)

11-37
• 8 CHAPTER 12
SAMPLE PROGRAM

In the sample program given in figure 12-1, we first declare a procedure called
SORTPROC which implements the following sorting method (assume that the records
are all in memory, stored as an array of structures). The key for each record is a
member of the structure.

Now we go through the array from the second record (record number 1) upwards.
When we reach any given record (the "current" record), we will already have sorted
the preceding records. (The first time through, when we look at record number 1,
record number 0 is the only preceding record.)

We take the current record, store it temporarily in a buffer, and look backwards
through the preceding records until we find one whose key is not greater than that of
the current record. Then we put the current record just after this record.

This procedure makes only the following assumptions about the records it is to sort:
• Each record occupies a contiguous set of storage locations. Therefore, by using
based variables, each record can be handled as a sequence of bytes, even though
the parts of a record are not necessarily BYTE scalars.
• The records themselves are also stored contiguously, so the entire set of records
can be regarded as a single sequence of bytes. The location of the first byte of
the first record is specified by the POINTER parameter PTR.
• All records are the same size; that is, each occupies the same number of bytes.
This size is specified by the WORD parameter RECSIZE and may not exceed
128.
• In each record, the value of one byte is used as the sort key. Within each record,
this byte is always in the same relative position, that is, the first byte in the
record, or the third, etc. This relative position (or offset) is specified by the
WORD parameter KEYINDEX, which resembles an array subscript; that is, it
is 0 if the key is the first byte in the record, 1 if the key is the second byte, etc.
• The number of records is specified by the WORD parameter COUNT.

The following is a detailed explanation of the program.

After the PROCEDURE statement and the declaration of the parameters, we declare
a based BYTE array called RECORD. This array is based on the parameter PTR,
which points to the beginning of the first record to be sorted. Therefore, a reference
to a scalar element of RECORD will be a reference to some byte within the set of
records to be sorted as long as the subscript used with RECORD is less than the total
number of bytes in all the records (i.e., the subscript must be less than
COUNT * RECSIZE).

Note that a dimension specifier of 1 is used in declaring RECORD. We need to use


a nonzero dimension specifier here in order to use subscripts later in the procedure.
However, the value of the dimension specifier is unimportant because RECORD is a
based array and does not have any actual storage allocated to it. The value 1 is chosen
arbitrarily.

Next, we declare CURRENT, an array of 128 BYTE elements; this array will be
used to store the "current" record. Note that the dimension (size) of the array
CURRENT is what establishes the maximum size of the records that this procedure
can handle. We have chosen 128 here, but, in principle, any dimension could be
specified.

12-1
Sample Program PLfM-86 User's Guide

SERIES-III PL/M-86 V2.l COMPILATION OF MODULE SORTMODULE


OBJECT MODULE PLACED IN :F1:PROG12.0BJ
COMPILER INVOKED BY: :F1:PLM8G.86 :Fl:PROG12.SRC

SORT$MODULE: DO; /* Beginning of module. */

2 1 SORTPROC: PROCEDURE (PTR, COUNT, RECSIZE, KEYINDEX);


3 2 DECLARE PTR POINTER, (COUNT, RECSIZE, KEYINDEX) WORD;

/* Parameters:
PTR is pOinter to first record.
COUNT is number of records to be sorted.
RECSIZE is number of bytes in eacn record, max is 128.
KEYINDEX is byte position witnin each record of a BYTE scalar
to be used as sort key. */

4 2 DECLARE RECORD- BASED PTR(l} BYTE,


CURRENT (128) BYTE,
( I, J) flORD;
5 2 SORT:
DO J = 1 TO COUNT-1;
6 3 CALL MOVB(@RECORD(J*RECSIZE), @CURRENT, RECSIZE);
7 3 I = J;
8 3 DO WHILE I > 13
AND (RECORD«I-l)*RECSIZE+KEYINDEX) >
CURRENT(KEYINDEX»;
9 4 CALL MOVB(@RECORD«I-1)*RECSIZE), @RECORD(I*
RECSIZE), RECSIZE);
10 4 I = 1-1;
11 4 END;
12 3 CALL MOVB(@CURRENT, @RECORD(I*RECSIZE), RECSIZE);
13 3 END SORT;

14 2 END SORTPROC;

/* Program to sort two sets of records, usin~ SORTPROC. */

15 1 DECLARE SET1 (513) STRUCTURE


(ALPHA WORD,
BETA (12) BYTE,
GAMMA INTEGER,
DELTA REAL,
EPSILON BYTE);

16 1 DECLARE SET2 (5(30) STRUCTURE


(ITEMS (21) INTEGER,
VOLTS REAL,
KEY BYTE);

/* Data is read in to initialize the records. */

17 1 CALL SORTPROC (eSET1, LENGTH(SET1), SIZE{SET1{13}),


SIZE (SET1 (13) .ALPHA»;
18 1 CALL SORTPROC(@SET2, LENGTH(SET2), SIZE(SET2(0}},
.SET2 (13) .KEY - .SET2 (13});
/* Data is written out from the records. */

19 1 END SORT$MODULE; /* End of module. */

Figure 12-1. Sample Program: Record Sort

12-2
PL/M-86 User's Guide Sample Program

MODULE INFORMATION:

CODE AREA SIZE 00CEH 206D


CONSTANT AREA SIZE 00~0H 00
VARIABLE AREA SIZE 606AH 246820
MAXIMUM STACK SIZE 0'H1EH 140
54 LINES READ
o PROGRAM WARNINGS
o PROGRAM ERRORS
DICTIONARY SUMMARY:

27KB MEMORY AVAILABLE


3KB MEMORY USED (11%)
0KB DISK SPACE USED

END OF PL/M-86 COMPILATION

Figure 12-1. Sample Program: Record Sort (Cont'd.)

The WORD variables I and J are used to control the DO WHILE iterative DO loops.
J is the index variable of the DO statement, and is always the subscript of the current
record. (When J becomes greater than 127, the sort is done.) I is the index variable
used to control the DO WHILE block; I-I is always the subscript of a previously
sorted record. In this program, I and J are also used to calculate subscripts for the
based array RECORD.

In the statement following the iterative DO, we used the built-in procedure MOVB
to copy a sequence of byte values from one storage location to another. (See
Chapter 9 for details.)

In the first activation of MOVB, the parameter @RECORD(J*RECSIZE) is the


location of the beginning of the Jth record, and @CURRENT is the location of the
beginning of the array CURRENT. Thus, the effect of this CALL statement is to
copy the Jth record into the array CURRENT.

To understand the DO WHILE statement, consider that RECORD«(I-I)*RECSIZE)


would be the first byte of the (I-I)st record, so RECORD«(I.:I)*RECSIZE +
KEYINDEX) is the byte that is to be used as the sort key of the (I--I)st record.
Similarly, CURRENT (KEYINDEX) is the sort key of the "current" record into
the position of the Ith record.

To illustrate the way this procedure can be used, it is a set in a program that declares
two sets of records, SET 1 and SET2, and sorts them. Comments are inserted in place
of the code that would be used in a working program to read data into the records
and write it out after they are sorted.

SETI is a set of 50 structures, each of which represents one record. Each structure
contains a WORD scalar, an array of 12 BYTE scalars, an INTEGER scalar, a
REAL scalar, and another BYTE scalar. We want to sort the records using the first
element of the 12-byte array as the sort key. Since the key is the second element
within the structure, its offset is just the number of bytes occupied by the first element
of the structure. Therefore, we will use the built-in function SIZE to calculate the
offset of the key and use that as the value of the parameter KEYINDEX.

SET2 is a set of 500 structures, each containing an array of 21 INTEGER scalars, a


REAL scalar, and a BYTE scalar that is to be used as the key. This time, the key is
deep within the structure. We can calculate the offset of the key manually, but this

12-3
Sample Program PLfM-86 User's Guide

is both error prone and inflexible. If the elements within the structure are changed,
then we must remember to recalculate the offset of the key. A better method is to let
the compiler calculate the offset for us. This can be accomplished by subtracting the
location of the key element from the location of the start of the record. The result of
this subtraction is the offset of the key, which becomes the value of the parameter
KEYINDEX.

In the two CALL statements used to activate SORTPROC, we used the built-in
function LENGTH to determine the number of records that are to be sorted, and we
used the built-in function SIZE to calculate the number of bytes occupied by each
record. These two values are used for the COUNT and RECSIZE parameters for an
activation of SORTPROC. See Chapter 9 for complete details on built-in functions.

NOTE
To generate and output reasonable sort data, user-supplied routines must be
added to this program in the areas indicated.

12-4
CHAPTER 13
PL/M-86 EXTENDED
SEGMENTATION MODELS

13.1 Introduction
Program segmentation is a technique used to optimize the object code produced by
the compiler. It allows for easier, more efficient memory addressing.

The simplest way to compile PLfM-86 code is to use the program size controls
(SMALL, COMPACT, MEDIUM, and LARGE) outlined in Chapter 11. However,
PLfM-86 provides extended segmentation facilities to take full advantage of the
segmented iAPX 86 architecture and to simplify the development of very large
programs. This chapter discusses the segmentation control options available to you.

Each compilation produces an object module composed of several sections (see section
11.4). At link time, the sections from separately compiled modules are combined into
segments depending on compiler-generated attributes and your input to the iAPX 86
Linker. Once combined into a segment, all constituent sections can be addressed from
the same iAPX 86 segment register. The compiler uses this segment addressability to
improve the code produced for data references and procedure calls. The primary
purpose of the segmentation controls is to tell the compiler how separately compiled
code and data will be located in memory.

Most PLfM-86 programmers need not be concerned about memory addressing


techniques on the iAPX 86 because the SMALL, COMPACT, MEDIUM, and
LARGE controls transparently handle the mechanics of program segmentation. If
needed, a description of iAPX 86 memory concepts is given in the Introduction to·
the iAPX 86.

By making the variety of segmentation schemes open to you virtually unlimited, these
controls can reduce the storage required for pointers and the code required to refer-
ence external variables and procedures.

Extended Segmentation

You can use segment controls to create a large program where each module is
compiled with the same segmentation control, or you can use the extended controls
to partition your program into a number of loosely-coupled subsystems.

A subsystem is a collection of tightly-coupled, logically-related modules that obey


the same model of segmentation. A program is made up of one or more subsystems.
(If you only use the simple controls to compile your program modules, then your
program consists of one subsystem.) If appropriate, the subsystems within a program
can use different segmentation models. Calls and data references within a subsystem
are long or short depending on the segmentation model selected for the subsystem.
All calls between subsystems are long and most data references require 32-bit
pointers.

Optimized code is obtained by breaking LARGE programs (greater than 64K bytes
of code, data, or both) into COMPACT subsystems having less than 64K bytes of
code and less than 64K bytes of data. References between modules in the same
subsystem can then use more efficient 16-bit addresses. (Only references outside a
subsystem need to use the full 32-bit address.) Use of these extensions also allows
easier access to the 16 megabyte address space.

13-1
PLfM-286 Extended Segmentation Models PL/M-86 User's Guide

13.2 Subsystems
By carefully constructing subsystems, you can minimize references to outside resources
(code and data) and, in return, receive highly optimized code for all internal resource
references. This section describes how to create subsystems using the extended
segmentation controls.

Note that all modules in your program should be compiled with the same set of
subsystem definitions so the compiler will make consistent assumptions about the
location of externals. If inconsistent subsystem definitions are used when compiling
modules, the iAPX 86 Linker (LINK86) will generate an error.

Each subsystem in a PL/M-86 program has one segmentation control, which takes
one of the following forms:

1) $ model ( subsytem-id
\
[submode~ HAS module-list [{ '1; HAS module-list
E XP 0 R T 5 public-list
lJ)
...

2) $ model q submode/;] E X P 0 R T S public-list)

3) $ model ( submodel [ ; E X P 0 R T S public-list])

where
model specifies the model of segmentation that the subsystem will
follow (COMPACT and LARGE are allowed, but
LARGE subsystems will not provide optimized code). All
modules in the subsystem must be compiled with the same
segmentation model.

subsystem-id specifies a unique name for each subsystem, and can be


up to 31 characters long. The subsystem-id is required by
all closed subsystems (see below).

submodel specifies the placement of constants. The submodel can be


either

- C 0 H5 T I H COD E - (for burning into ROM; default


case for LARGE)
- C 0 H 5 T I H DA T A - (for efficient access to constants
in programs that are loaded into
RAM; default case for
COMPACT)

HAS module-list specifies all the modules that make up the subsystem. A
HAS list is required by all closed subsystems (see below).
Each identifier in the module-list is the name of a module,
which can be up to 31 characters long.

E X P 0 R T 5 public-list lists the constants, procedures, and variables exported by


this subsystem. Any object not named in an EXPORTS
list will be local to its subsystem and should not be accessed
from outside the subsystem. Each identifier in the
public-list is the name of a public object, which can be up
to 31 characters long.

13-2
P~/M-86 User's Guide PLfM-286 Extend£d Segmentation Models

In most applications of the subsystem controls, the- HAS and EXPORTS lists will
have several dozen entries apiece. To accommOdate lists of this length, a subsystem
control may be continued over more than one control line. (The continuation lines
must be contiguous, and each must begin with a dollar sign ($) in the first column).
Also, note that any number of HAS and EXPORTS lists may appear in a control, in
any order, allowing you to format your subsystem specification so it can be easily
read and maintained.

Consider the following subystem definition:

SCOMPACT(Room -CONST IN CODE- HAS Chair, Door, Window}


SCOMPACTCDiner HAS Booths, Waitress, Jukebox;
S EXPORTS Lunches}
SLARGECAllocate EXPORTS CodeSize, DataSize,
$ MemSize, FreeSpace)

This sample program contains three subsystems: Room, Diner, and Allocate. Room
and Diner use the COMPACT model of segmentation while Allocate uses the LARGE
model. Constants are stored with the code in Room and Allocate. The Room sub-
system, which contains the modules Chair, Door, and Window, is apparently the main
program because it exports no objects. Allocate supplies four objects: CodeSize,
DataSize, MemSize, and FreeSpace.

Open and Closed Subsystems

The subsystems that make up your PL /M-86 program may be either open or closed.
The subsystem definition for an open subsystem does not have a subsystem name and
does not list the modules it contains; in short, it does not contain a HAS list. Modules
can be added to this subsystem at any time without changing the subsystem
definition. Each program may have only one open subsystem.

The subsystem definition· for a closed subsystem contains a subsystem name and a
HAS list, which specifies all the modules in the subsystem.

In an open subsystem, only the submodel and EXPORTS modifiers are permitted.
By omitting the subsystem name, you automatically create an open subsystem that
contains all modules not claimed in another subsystems's HAS list. (Note that use of
the simple segmentation controls also creates an open subsystem.)

One advantage of using an open subsystem is that it simplifies dealing with a


COMPACT program whose code has grown too large. When your program exhausts
its 64K code size, take a subset of YOHr modules and put them into a closed sub-
system, leaving the rest of the modules in the open subsystem.

For example, assume that the following modules from your original program
(ATTACH, OPEN, CLOSE, ERRORS, ALLOCATE, FREE) were compiled with
this simple control:

$COMPACT

If you factor out the modules ALLOCATE and FREE from the original program,
creating SUBSYS I, its subsystem definition would be:

$COMPACT CSUBSYS1 HAS ALLOCATE, FREE}

13-3
PLfM-286 Extended Segmentation Models PLfM-86 User's Guide

Now, suppose that the modules remaining in the open subsystem reference entry points
AllocBuff and FreeBuff in SUBSYSl. These must be exported from SUBSYSI as
follows:

$COMPACT (SUBSYS1 HAS ALLOCATE, FREE;


$ EXPORTS AllocBuff, FreeBuff>

or

$COMPACT (SUBSYS1 HAS ALLOCATE; EXPORTS AllocBuff;


$ HAS FREE; EXPORTS FreeBuff>
The second form illustrates how multiple HAS and EXPORTS lists can be used to
document the items exported from each module; it also illustrates the use of a
continuation line.

Likewise, if a routine in SUBSYS 1 references the procedure F atalError in the module


ERRORS, the definition of the open subsystem would then be:

$COMPACT (EXPORTS FatalError>


No data structures need to be changed, because data reference values can still be 16
bits. All procedures except AllocBuff and FreeBuff will still use the short call and
return mechanism.

The EXPORTS List

A symbol included in a subsystem's EXPORTS list must be declared PUBLIC in one


of the modules in that subsystem. The symbol, called an exported symbol, may be
referenced by modules in other subsystems. A public symbol defined within a sub-
system but not listed in its EXPORTS list is called a domestic symbol. It should be
referenced only by modules within the same subsystem.

A procedure should be exported only if it must be referenced outside the defining


subsystem, because accessing exported procedures will generally require more code
and time than is normally required for domestic procedures.

Exported procedures have the following characteristics:


• They use the long form of call and return.
• They save and restore the caller's DS register upon entry and exit.
• They reload DS with their associated data segment upon entry.

However, because short pointers are used in the SMALL (RAM) model of segmen-
tation, care must be used when you call procedures that have pointer parameters and
are exported from a subsystem. In these cases, the compiler will always use the value
of the current DS register as the selector portion of the long pointer. This means that
passing a pointer to arty data items declared in the SMALL module will produce the
proper result, but the following restrictions must be observed for the special cases:
I. If the actual parameter is the NIL pointer, DS:O will be passed to the exported
procedure. Consequently, the procedure will execute differently if called from a
SMALL module than it will if called from a COMPACT, MEDIUM,.or LARGE
module. For example:

tCOMPACT (FOO HAS H; EXPORTS FOO)


$SMALL

13-4
PL/M-86 User's Guide PL/M-186 Extended Segmentation Models

M: DO;
DECLARE PTR POINTER;
FOO: PROCEDURE (P) EXTERNALj
DECLARE P POINTER;
END FOO;
CALL FOO (NIL); 1* Wrong, will pass DS:O *1
PTR • NIL;
CALL FOO (PTR); 1* Wrong, will pass DS:O *1
END M;
.COMPACT (FOO HAS N; EXPORTS FOO)
H: DO;
FOO: PROCEDURE (P) PUBLIC;
DECLARE P POINTER;
DECLARE B BYTE;
B • (P·NIL); /* Will assign FALSE
(OOOH) to B if FOO i5
called from SMALL;
Will assign TRUE
(OfFH) to B
otherwise *1
END FOO;
CALL FOO (HIL); 1* Right, will pass
o: 0 f I

END Ni

2. If the actual parameter is a pointer to a procedure, the compiler will extend the
short pointer with DS then pass the value of DS:( offset of procedure) to the
exported procedure. This situation should be avoided because the result of any
reference through such a pointer is undefined. For example:

.COMPACT (FOO HAS H; EXPORTS FOO)


.SMALL
M: DO;
DECLARE PTR POINTER;
DECLARE TABLE (10) BYTE;
FDO: PROCEDURE (P) EXTERNALj
DECLARE P POINTER;
END FOO;
BAZ: PROCEDURE;
EHD BAZ;
CALL fOo (,BAZ); /t Wrong, will pass
DS:offset-of-BAZ *1
PTR • ,BAZ;
CALL FOO (PTR); ,t Wrong, will pass DS:PTR *'
CALL Foo (,TABLE); It Right, will pass
pointer to TABLE *'
13-5
PL/M-286 Extended Segmentation Models PL/M-86 User's Guide

PTR • ,TABLE;
CALL FOO (PTR); '* Right, will pass pointer
to TABLE *'
END M;

Placement of Controls

The segmentation controls have special restrictions associated with their placement.
These rules are as follows:
Only the definition of the open subsystem (with no submodel and no EXPORTS
list) may be placed on the invocation line; definitions of all other subsystems
must occur inside the source program.
• The definition of the open subsystem (if present) must be the last segmentation
control specified.
• Only the open subsystem can be without a HAS list.

The subsystem definitions for your entire program may be included in the compila-
tion of each module using the INCLUDE control. The compiler will extract -the
information' it needs to compile correctly and efficiently each module's intrasub-
system and intersubsystem references.

13-6
CHAPTER
ERROR MESSAGES
141

The compiler may issue five varieties of error messages:


• Source PL/M-86 errors
• Fatal command tail and control errors
• Fatal input/output errors
• Fatal insufficient memory errors
• Fatal compiler failure errors

The source errors are reported in the program listing; the fatal errors are reported on
the console device.

14.1 Source PL/M-86 Errors


Nearly all of the source PL/M-86 errors are interspersed in the listing at the point
of error and follow the general format:

* * * ERR 0 R mmm I H nnn (L I NE ppp) J HEAR ' aaa' J message

or:

* * * WAR N I NG mmm I H nnn (L I HE ppp) J HEAR ' aaa' J message

where
mmm is the error number from the list below.
nnn is the source statement number where the error occurs.
ppp is the actual source line number where the error occurs.
aaa is the source text near where the error is detected.
message is the error explanation from the list below.

A prefix of W means the message is a warning only, and object code was not
suppressed. Errors not so prefixed prevent object code generation.

Source error message list:

1. IHVALID CONTROL

See Chapter II. Example:

.NXCODE; '* probably intended NOCODE *'


2. ILL EGA L USE 0 F P R I !WI AR Y CO" T R 0 L AFT E R
HOH-CONTROL LINE

Primary controls may appear as control lines in your source program, but
they must come first. No other statements may precede them. See
Chapter 11.

14-1
Error Messages PLfM-86 User's Guide

3. fit ISS I NG C 0 HT R0 L PAR Afit E T E R

Certain controls, e.g., INCLUDE, require you to specify a parameter. See


Chapter 11.

4. I HVALID C 0 HT R 0 L PAR AMET E R

One example is an illegal pathname for a control like OBJECT. See


Chapter 11.

5. I HVALID C 0 HT R 0 L FOR MAT

See Chapter 11 for correct formatting of control lines. An example that


could cause this error is:

$LIST (MVPROG.LST);

because no pathname is expected on this control. It could also be caused


if an INCLUDE was followed by another control on the same line.

(W) 6. ILL EGA L P R I NT CON T R 0 L, I GH0 RED

PRINT (:CI:) would be an example, since you cannot print to the console
input device. See Chapter 11.

7. I NVALID PAT HNAME

See the operating instructions for your specific host system.

(W) 8. ILLEGAL PAGELENGTH, IGHORED

See section 11.6.

(W) 9. ILLEGAL PAGEWIDTH, IGNORED

See section 11.6.

(W) 10. RESPECIFIED PRIMARY CONTROL, IGNORED


See section 11. 1.

11. MISPLACED ELSE DR ELSEIF CONTROL

See section 11.8.

12. MIS P LAC E DEN D I F CON T R 0 L

See section 11.8.

14-2
PL/M~6 User's Guide Error Messages

13. MIS S I "G E" D I F CO" T R0 L

See section 11.8.

14. S WIT CH N AMET DOL 0 H G (3 1 ) J T RUN CAT E D

See section 11.8.

15. MIS SIN GOP ERA TOR

See section 11.8.

(W) 16. I N V A LID CON S TAN T J Z E R 0 ASS UME D

See section II.8.

17. INVALID OPERAND

See section II.8.

19. LIMIT EXCEEDED: SAVE NESTING (5)

See section 1l.8.

2Q LIMIT EXCEEDED: INCLUDE NESTING (5)

For example, if you include a file named A, which includes a file named
B, and so on, this error will arise when the limit is exceeded.

21. MISPLACED RESTORE CONTROL

RESTORE can only work if there has been a prior SA VE. See
section 11.7.

22. UNE X P E CTED END 0 F CON T R 0 L

A segm.entation control was expecting a continuation line or a')'.

23. S Vfit B 0 LEX 1ST SIN M0 RET HAN 0 N E HAS LIS T

A module name may occur in only one HAS list.

24. SUB S V S T E MAL REA D V D E FIN E D

The subsystem name has already been defined.

14-3
Error Messages PL/M-86 User's Guide

25. HAS 0 REX P 0 R T LIS T RES PEe I F. lED

You cannot have more than one of each in a sub-system control.

26. ILL EGA L P LIM IDE NT I FIE R

Identifier does not meet the rules for PL/M identifiers. See section 2.3.

(W) 28. I H V ALID P L M86 C H ARAe T E R JIG NOR ED

Look near the text flagged for an invalid character, or one that IS
inappropriate in context. Delete it or retype the statement.

(W) 29. UN P R I H TAB LEe H ARAe T E R JIG NOR E D

Retype the line in question using valid characters.

30. NAME 0 R S T R I HG TOO L 0 HG J T RUN CAT E D

Match your intended variable type with the length of the flagged item.
For the correct maximum. lengths, see Chapters 2 and 3.

31. ILLEGAL CONSTANT TYPE

This might reflect missing operators, e.g., A=4T instead of4+T. See
Chapter 2 for the list of v)llid types.

32. I NV ALID C HAR ACT E R I H CON 5 TAN T

For example, 107B and OABCD will cause this error because neither can
be valid in any PL/M-86 interpretation; 7 is not a binary numeral, B may
not occur in decimal or octal, and neither string ends in H. See Chapter
2.

33. R E CUR 5 I VE MAC ROE XPAN 5 I 0 H

Here is an example causing this error:

DECLARE A LITERALLY 'B'i


DECLARE B LITERALLY 'A'i

B-4i 1* error discovered here *1

No type can be assigned to variables declared circularly, i.e., solely in


terms of each other.

14-4
PL/M-86 User's Gaitte Error Messages

34. LIM I T E XC E E D ED: !WI A CR 0 H EST I HG (5)

This error occurs when too many DECLARE statements refer back
through each other to the one that actually supplies a type. For example:

DECLARE A LITERALLY 'B';


DECLARE B LITERALLY 'C';

DECLARE Y LITERALLY 'Z';


DECLARE Z BYTE IHTITIAL (77);

A-7; 1* error discovered here *1

35. L I !WI I T E X C E E DE D: SOU R CELI H E L E HGT H (1 28 )

A source line longer than 128 characters was read.

36. CON S TAN T TOO L A RGE FOR T YP E

DECLARE A BYTE INTITIAL (259) would be an example because the


maximum byte constant is 255.

37. I N V A LID REA LCD N S TAN T

Examples: 1.7F or 1.7. See Chapter 3.

(W) 38. REA LCD N S TAN TUN D E R FLO W

An underflow occurred when conversion into floating-point was attempted.

(W) 39. REA LCD N S TAN T 0 V E R FLO W

An overflow occurred when conversion into floating-poiI1t was attempted.

4Q NULL STRING NOT ALLOWED

Strings of length zero (e.g., 4' ") are not supported.

41. DELETED: "<tokens)"

The compiler deleted the following tokens while attempting to recover from
a syntax error.

42. INS E RTED: .. < t 0 ken s ) II

The compiler inserted the following tokens while attempting to recover


from a syntax error.

14-5
Errot Messages PL/M-86 User's Guide

43. 5 TAT E ME H T 5 F 0 l LOW MOD U lEE HD

Information follows logical end-of-module.

44. C 0 H 5 T A H T TOO l A R GE

For example, a constant with the value 999,999,999,999.

(W) 45. JI1 ISM ATe H ED B l 0 CKID E H T I FIE R

See section 6.1. If a label is supplied in an END statement, the label must
match the first unmatched DO statement above the EN D. Sometimes the
error involves a module name confused with a procedure name. See also
Chapters I and 7.

46. D U P LIe ATE PRO CE D U RE HAM E

Procedure names must be unique. See section 8.1.

47. lIM I T E X CE ED ED: PRO C E D U RES (253)

Too many procedures in this module. Break it into smaller modules.

48. D U P L I CAT EPA R A III E T E R HAM E

A parameter must be declared exactly once. This message indicates that


the flagged parameter already has a definition at this block level, as in:

YAR: PROCEDURE (YAR77 J YAR78)j


DECLARE YAR77 BYTE;
DECLARE YAR77 BYTE;

Perhaps a different spelling was intended.

49. NOT AT MOD UL E LEV E L

The flagged attribute or initialization can only be valid at the module


level, not in a procedure. See Chapters 1., 3, 7, and 8.

50. D U P L I CAT EAT T RIB UTE

Attributes should be specified, at most, once. This'message means the


compiler has found a declaration like:

DECLARE B BYTE EXTERHAL EXTERHAL;

51. ILLEGAL INTERRUPT VALUE

Interrupt numbers must be whole-number constants between 0 and 255.


Thus -7 or 272 would be invalid. See section 8.5.

14-6
PL/M-286 User's Guide Error Messages

52. I H T ERR U P T WIT H PAR A MET E R S

No parameters are allowed in interrupt procedures. See section 8.5.

53. I H T ERR U P T WIT H T Y P E D PRO C E D U R E

Interrupt procedures must be untyped. See section 8.5.

54. I H V A LID DIM E H S I 0 H

See section 5.1.

55. S TAR DIM E H S I 0 H WIT H S T RU C T U R E

Star dimensions (*) are for initialization. See section 3.2.

56. S TAR DIM E H S I 0 H WIT H S T RU C T UREM E MB E R

Star dimension( *) must not be used with structures. See section 3.2.

57. CO H F L I CT WIT H PAR AM E T E R

Attributes may not be used with parameters.

58. D U P L I CAT E DEC L A RAT I 0 H

The flagged item already has a definition declared at this block level.

59. ILL EGA L PAR A MET E R T Y P E

Parameters may not be declared of type structure or array. See


section 8.1.

60. D U P L I CAT E LAB E L

Each label must be unique within its block or scope. Otherwise, GOTOs
and CALLs would have ambiguous targets. See sections 6.3 and 8.2.

61. DUPLICATE MEMBER HAME

For example, in the case:

DECLARE AIR STRUCTURE (F4 BYTE, F4 BYTE);

subsequent references to AIR.F4 would be ambiguous. See sections


5.2 and 5.3.

14-7
Error Messages PL/M-S6 User's Guide

62. UNDEC L ARE D PAR Afit E T E R

A parameter named in the procedure statement did not get defined in the
body of the procedure. See sections 8.1 and 8.2.

63. CON F LIe TIN GAT T RIB UTE S

Certain attributes are not allowed when declaring a parameter, e.g.,


PUBLIC, EXTERNAL, DATA, INITIAL, AT, or BASED.

64. LIM I T E XC E E DED: D0 B L 0 C KS

See Appendix B for correct limit.

65. ILL EGA L PAR AMET ERA T T RIB UTE

Certain attributes are not allowed when declaring a parameter,· e.g.,


PUBLIC, EXTERNAL, DATA, INITIAL, AT, or BASED.

66. UHDE FIN E DBA S E

A variable was declared BASED using an undeclared identifier.

67. INVALID ATTRIBUTE FOR BASE

A base must be a non-subscripted scalar of type POINTER, WORD, or


SELECTOR. It is not permitted to have the attribute BASED. See
section 3.5.

68. MIS P LAC E D DEC L ARAT ION

You can intersperse declarations and procedures, but not declarations and
executable statements. See Chapter 1.

69. I HVALID BAS E WIT H LAB E LOR fit AC R 0

BASED may not be used with LABEL or LITERALLY types.

70. I HVALID D I fit E H5 I 0 H WIT H LAB E LOR MAC R 0

LABEL or LITERALLY may not be dimensioned.

71. INITIALIZATION LIST REQUIRED

A list of initial values is required if the INITIAL attribute is used, if the


non-external * dimension form is used, or if the non-external DATA
attribute is used.

14-8
PLjM-86 User's Guide Error Messages

72. BAS E D C0 H F LIe T 5 WIT HAT T RIB UTE S

Examples of attributes conflicting with base inel ude AT, DATA,


INITIAL, PUBLIC, and EXTERNAL. See section 3.5.

73. E X E CUT A B L EST ATE ME H T S I HEX T E R Ii A L

An EXTERNAL procedure, being defined elsewhere, may not contain


executable statements. See Chapter 7 and section 8.5.

74. MIS S I HG RET UR H FOR T Y P E D PRO C E D U RE

A typed procedure must return a value; thus, its RETURN statement


must specify one.

75. I H V A LID Ii EST E D R E E H T R A Ii T PRO CE D U RE

Reentrant procedures may not contain nested procedures. See section 8.5.

76. LIM I T E X C E E DE D: FA C TOR ED LIS T (6")

Too many variables were named in a factored declaration. Break it into


several declarations.

77. LIM I T E X CE E DE D: S T R U CT UR EEL E MEli T S (6")

Too many elements were declared in a structure.

78. MIS S I H G PRO CE D U R E HAM E

Every procedure must have a name. See section 8.1.

79. MU L TIP L E PRO C E D U R E LAB E L S

Procedures must have exactly one name; no more, no less. See section 8.1.

80. DEC L A RAT I 0 H SMA Y HOT BEL ABE LED

Labels may not be used on declaration statements.

81. STAR DIM WITH FACTORED LIST NOT ALLOWED

Star dimensions (*) are for initializations. See section 3.2.

82. S I Z E E X CE E D S 6 .. K 'B Y T E S

Storage for the declared item exceeds 64K bytes.

14-9
Error Messages PLjM-86 User's Guide

(W) 83. PRO C E D U R E CO H T A I H S HOE X E CUT A B L EST ATE ME H T S

84. WAR H I H G: 0 A TAU SED WIT HAT; I HIT I A LAS SUM E 0

A variable may not be declared using both the DATA attribute and the
A T attribute. See section 3.2.

85. WAR H I H G: I HIT I A L USE D WIT H ROM 0 PT I 0 H

Variables declared with INITIAL are not initialized until load-time. Thus,
if your program is burned into ROM, these initializations will never occur.
See section 3.2.

88. LIM I T E X C E E 0 ED: PRO GRAM TOO COM P LEX

The program has too many complex expressions, cases, etc. Break it into
smaller procedures.

89. COM P I L ERE R R 0 R: BAD ERR 0 R R E CD V E R Y

An unrecoverable error occurred. Trying a different copy of the compiler


on a different drive might reveal that the first copy had been damaged or
went bad. Contact Intel.

91. PROGRAM TOO COMPLEX

The program has too many complex expressions, cases, etc. Break it into
smaller procedures.

93. LIM I T E X C E E 0 ED: PRO GRAM TOO COM P LEX

The program has too many complex expressions, cases, and procedures.
Break it into smaller modules.

95. COM P I L ERE R R 0 R: PAR S E B U F FER 0 V E R FLO W

See source error message number 89.

96. LIM I T E X C E E 0 ED: B L 0 C K H EST I HG (1 8 )

The program has too many nested DO blocks. Break it into smaller
procedures.

97. COM P I L ERE R R 0 R: S T A C K U H DE R FLO W

See source error message number 89.

14-10
PL/M-86 User's Guide Error Messages

98. LIM I T E X C E E D ED: S TAT E MEN T TOO COM P LEX

The statement is too large for the compiler. Break it into several smaller
statements.

99. COM P I L ERE R R 0 R: S EM ANT I C UN D E R FLO W

See source error message number 89.

100. S T R I NG C 0 H S TAN T TOO LON G

String constants used as scalars may have a maximum of 4 characters.

101. UNSUBSCRIPTED ARRAY

In the context of the flagged statement, the array reference requires a


subscript. See sections 3.4 and 8.2, and Chapter 5.

(W) 102. U H QUA L I FIE D S T R U C T U R E

This statement was ambiguous as to which struct.ure or member was


intended. See sections 3.4 and 8.2, and Chapter 5.

103. HOT A N A R RAY

Subscripts are permitted only on identifiers declared as arrays. Check


spelling consistency. See Chapter 5.

I 04. MU L TIP L E SUB S CRIP T S

For any array TING, references of the form TING(2,4) or TING(3,7,9,6)


are invalid because of multiple subscripts. Only references of one subscript
are valid, e.g., TING(5). See section 5.1.

105. HOT A S T RU CT UR E

For example, a reference of the form GNU.F], where GNU was not
declared a structure. See Chapter 5.

106. U HD E FIN E DID E N T I FIE R

Every identifer must be declared. See Chapter 3.

] 07. U ND E FIN E D ME MB E R

For example, KAPI.HORN, where KAPI is a valid, declared structure


but HORN is an undeclared member of the structure. See
Chapter 5.

14-11
Error Messages PL/M-86 User's Guide

I m~. ILL EGA LIN DEXT YP E

Only expressions of type BYTE. WORD, and INTEGER can be used.


Sec section 5.1.

I 09. NOT A LAB E L

The identifier following GOTO must be a label~ the flagged item was
declared otherwise.

I 10. MISS I NG RET URN V AL UE

A typed procedure must return a value; thus. its RETURN statement


must specify one. See section 8.2.

111. INVALID RETURN WITH UNTYPED PROCEDURE

An untyped procedure does not return a value; thus, its RETURN state-
ment may not specify one. See section 8.2.

I I 2. I NVALID I ND IRE CTTY P E

Only WORD or POINTER scalars can be used for indirect calls. This
excludes WORD or POINTER expressions, BYTE, DWORD,
INTEGER, or REAL scalars, all structures, and all arrays. See
section 8.2.

I 13. I NVALID PAR AMET E R CO UHT

The number of actual parameters supplied in a CALL must be equal to


the number of formal parameters declared in the procedure. See section
8.2. (See also Chapter 9 for the requirements of built-ins.)

114. QUALIFIED PROCEDURE NAME

Procedure names may not be qualified.

I 15. I HVALID F UHC T ION REF ERE HC E

Typed procedures can be invoked only by use in an expression, not by a


CALL. See sections 8.1 and 8.2.

1 16. I HVALID CAS E E XPRE S S I 0 H T YP E

Case expressions must be of type BYTE, WORD, or INTEGER.

117. LIMIT EXCEEDED: CASES

See Appendix B for correct limit.

14-12
PL/M-86 User's Guide Enor Messages

118. T Y P E CON F L I C T

See section 4.6.

119. INVALID BU'ILT-IN REFERENCE

Built-in reference was qualified with a member name, or OUTPUT /


OUTWORD did not appear on the left side of an assignment.

120. I N V A LID PRO C E D UR ERE FER EN CE

Untyped procedures must be invoked by a CALL statement; references to


such procedures are not permitted in expressions. See sections 8.1 and 8.2.

121. INVALID LEFT-HAND SIDE OF ASSIGNMENT

An example is PROCEDURE=4 or INWORD(7)=9. See sections


3.2 and 4.7.

122. I N V A LID REF ERE N CE

Invalid label reference.

123. Not used

12~ PROCEDURE HAME REQUIRED

Procedure name is required for SET$INTERRUPT and INTER-


RUPT$PTR built-ins.

125. PRO CE D UR E HAM E 0 H L Y

Parameters are not allowed on the procedure name in SET$INTERRUPT


and INTERRUPT$PTR.

126. BAD INTERRUPT NUMBER

Interrupt numbers must be whole-number constants between 0 and 255.


Thus, -7 and 272 would be invalid. See section 8.5.

127. CON S TAN T 0 H L Y

In this instance, a constant is required.

128. A RRAY RE QUI RED

Some built-ins need an array name. See section 9.1.

14-13
Error Messages PL/M-86 User's Guide

129. Not used

13Q INVALID RESTRICTED OPERAND

For example, PLfM-86 reserved words and predeclared identifiers would


be invalid. See Appendix A and section 9.1.

131. INVALID RESTRICTED OPERATOR

Only + and - may be used in restricted expressions.

132. REA L CON S TAN T E XPRE S SID N

A constant expression with REALs is not allowed.

133. REF ERE NCERE QUI RED

A variable reference is required for LENGTH, LAST, and SIZE.

134. V A R I A B L ERE QUI RED

The operand to LENGTH, LAST, and SIZE must be a variable.

135. VA L U E TOO LA RGE

A value is too large for its contextually determined type.

136. A B SOL UTE POI NT E R WIT H S H 0 RT POI NT E RS

The NIL pointer was used in the SMALL (RAM) case.

137. I N V A LID RES T RIC TED E XPRE S SID N

Only addresses or constant types are allowed in restricted expressions.

138. PUB L I CAT EXT ERN A L

For example:

DECLARE DARTH BYTE EXTERNAL;


DECLARE VADER BYTE PUBLIC AT (.DARTH);

See sections 3.2 and 7.2.

139. PUB L I CAT A B SOL UTE

Absolute locations for PUBLICs are supported only under the LARGE
option. See Chapter 11.

14-14
PLfM-86 User's Guide Error Messages

14Q PUBLIC AT MEMORY

PUBLIC AT @ MEMORY is not supported by SMALL.

141. AT BASED VARIABLE

Based variables cannot be used in AT clauses. See section 3.5.

142. ILL EGA L FOR WAR D REF ERE H CE

An AT expression cannot have a forward reference.

143. V A R I A B LET Y PER E QUI RED I H A HAT E X PRE S SID H

The expression must be AT a variable.

144. LIM I T E X C E E DED: D A TAD R S T A CK S E GME H T TOO


LARGE

See Appendix B for correct limit.

145. LIMIT EXCEEDED: CODE DR CoNST SEGMEHT TOO


LARGE

See Appendix B for correct limit.

146. LIM I T E X CE E D ED: TOO MA H V EXT E R HAL S

See Appendix B for correct limit.

147. LABEL HOT AT LOCAL DR MODULE LEVEL

See sections 6.3 and 7.3.

148. A B SOL UTE ADD RES S REF ERE H C E I H SMA L L

See section 11.3.

149. ILL EGA L MOD UL E HAM ERE FER E N CE

Module names cannot be referenced.

(W) 150. USE 0 F I I . II WIT H FAR PRO C E D URE

A subsequent indirect call made through the respective address/pointer


generates the wrong type of call. See section 11.4.

14-15
Error Messages PL/M-86 User's Guide

(W) 151. USE 0 F "," WIT H S H 0 R T PRO C ED U R E

See source error message number 150.

152. I H V A LID I I . I. 0 R .. ," 0 PER A H D

Must be used with a variable, procedure, or constant list.

153. I H V A LID RET U R H I H MA I H PRO GRAM

A main program must have no returns. See section 8.3.

154. S TAR DIM E H SID H E D EXT E R HAL WIT H L E HGT H, LAS T ,


or SIZE

The LENGTH, LAST, and SIZE built-in' functions cannot be used with
variables declared with a star (*) and the EXTERNAL attribute.

155. PUB L I C S Y MB 0 LEX P 0 R TED FRO M A HOT HER


SUBSYSTEM

A PUBLIC symbol in this module is also exported by another subsystem.


See Chapter 13_

156. L 0 HGPO I H T ERR E QUI RED FOR T HIS C 0 H S T R U C T

A model with long pointers is required.

157. MEMORY MAY HOT BE USED WITH LEHGTH, LAST,


or SIZE

The LENGTH, LAST, and SIZE built-in functions cannot be used with
declared with * and the EXTERNAL attribute.
vari~bles

158. ILL EGA L I HIT I A LIZ A TID H 0 F A HEX T E R HAL

An external variable cannot be initialized.

159. ILLEGAL IHTERRUPT PROCEDURE REFEREHCE

An interrupt procedure cannot be invoked with the CALL statement.

160. I H T ERR U P T PRO C ED U RES MUS T BE PUB L I C

An interrupt procedure must also be given the PUBLIC attribute.

161. Not used

14-16
PL/M-86 User's Guide Error Messages

162. LIMIT EXCEEDED: PROGRAM COMPLEXITY

Too many complex expressions, cases, etc. Break it into smaller


cedures.

163. COM P I L ERE R R 0 R: 5 E MAN TIC U ND E R FLO W

See source error message number 89.

164. COM P I L ERE R R 0 R: I N V A LID NOD E

See source error message number 89.

165. COMPILER ERROR: INVALID OPERATOR

See source error message number 89.

166. COM P I L ERE R R 0 R: I N V A LID T R EE

See source error message number 89.

167. COMPILER ERROR: SCOPE STACK UNDERFLOW

See source error message number 89.

168. LIM I T EX C E E DE D: PRO GRAM COM P LEX I T Y

Too many complex expressions, cases, etc. Break it into smaller


cedures.

169. COM P I L ERE R R 0 R: I N V A LID R E COR D

See source error message number 89.

170. I NV A LID DOC A S E B L 0 C K J A T LEA 5 TON E CAS E


REQUIRED

See section 6.1.

171. LIM I T EX CE E D ED: N UMB E R 0 F ACT I V E CAS E S

See Appendix B for correct limit.

172. LIM I T E X C E E D ED: N EST I NG 0 F T Y P E D PRO CE D U R E


CALLS

See Appendix B for correct limit.

14-17
Error Messages PLfM-86 User's Guide

173. LIM I T E XC E E DE D: HUM B E R 0 f ACT I VE PRO C E DURES


OR DO CASE GROUPS

See Appendix B for correct limit.

174. ILL EGA L HE S T I HG 0 f B L 0 C KS» E HDS HOT B AL AHC E D

For every DO, an END is needed. See section 6.1.

175. COM P I L ERE R R0 R: I HVALID 0 PER ATID H

See source error message number 89.

176. LIM I T E XCE E DE D: REA LEX PRE S SID H COM P LEX I T Y

The REAL stack has eight registers. Heavily nested use of REAL functions
with REAL expressions as parameters could get excessively complex. See
Appendix F.

177. COM P I L ERE R R0 R: REA L S T AC K UHDE RfLO W

See source error message numbers 89 and 176.

178. LIM I T E XCE E DED: BAS I C B L 0 CK COM P LEX I T Y

You have a very long list of statements without labels, CASEs, IFs,
GOTOs, RETURNs, etc. Either break the procedure into several smaller
procedures, or add labels to some of your statements.

179. LIM I T E XCE E DE D: S TAT E ME HT S I Z E

The statement is too large for the compiler. Break it into several smaller
statements.

199. LIMIT EXCEEDED: PROCEDURE COMPLEXITY OF


OPTIMIZE(2) (terminal error)

The combined complexity of statements, user labels, and compiler-


generated labels is too great. Simplify as much as possible, perhaps break-
ing the procedure into several smaller procedures.

20Q ILLEGAL IHITIALIZATIOH Of MORE SPACE THAH


DECLARED

The number of initialization values exceeds the number of declared


elements. See section 3.2.

201. I HVALID LAB E L: UHDE f I HE D

No definition for this label was found. See sections 3.3 and 6.3.

14-18
PL/M-86 User's Guide Error Messages

202. LIM I T E XC E E DED: HUM B E R 0 F EXT E RHAL I T EMS

See Appendix B for correct limit.

203. COM P I L ERE R R0 R: BAD LAB E LAD D RES S

See source error message number 89.

20~ LIMIT EXCEEDED: CODE SEGMENT SIZE

See Appendix B for correct limit.

205. COM P I L ERE R R0 R: BAD COD E G E HER ATE D

See source error message number 89.

206. LIM I T E XC E E DED: DAT A S E G MEN T S I Z E

See Appendix B for correct limit.

251. COM P I L ERE R R0 R: I HVALID 0 B J E C T

See source error message number 89.

252. COM P I L ERE RR 0 R: S ELF HAM ELI HK

See source error message number 89.

253. COM P I L ERE R R 0 R: S ELF AT T R L I HK

See source error message number 89.

254. LIM I T EX C E E DE D: PRO GRAM COM P LEX I T Y

The program has too many complex expressions, cases, and procedures.
Break it into smaller modules.

255. LIM I T E XC E E DE D: S YMB 0 L S

See Appendix B for correct limit.

NOTE
If a terminal error is encountered, program text beyond the point of error is
not compiled. A terminal error message will appear at the point of error in
the program listing.

14-19
Error Messages PL/M-86 User's Guide

14.2 Fatal Command Tail and Control Errors


Fatal command tail errors are caused by an improperly specified compiler invocation
command or an improper control. The errors that may occur here are as follows:

ILLEGAL COMMAND TAIL SYNTAX OR VALUE


UNRECOGNIZED CONTROL IN COMMAND TAIL
INCLUDE FILE IS NOT A DIRECT ACCESS FILE
INVOCATION COMMAND DOES NOT END WITH <cr)<LF)
INCORRECT DEVICE SPECIFICATION
SOURCE FILE NOT A DIRECT ACCESS FILE
SOURCE FILE NAME INCORRECT
SOURCE FILE EXTENSION INCORRECT
ILLEGAL COMMAND TAIL SYNTAX
MISPLACED CONTROL: WORKFILES ALREADY OPENED

14.3 Fatal Input/Output Errors


Fatal input/output errors occur when the user incorrectly specifies a pathname for
compiler input or output. These error messages are of the form:

PL/M-86 ERROR -
F I LE :
NAME:
ERROR:
COMPILATION TERMINATED

14.4 Fatal Insufficient Memory Errors


The fatal insufficient memory errors are caused by a system configuration with not
enough RAM memory to support the compiler.

The errors that may occur due to insufficient memory are as follows:

NOT ENOUGH MEMORY FOR COMPILATION


DYNAMIC STORAGE OVERFLOW
NOT EN~UGH MEMORY

14.5 Fatal Compiler Failure Errors


The fatal compiler failure errors are internal errors that should never occur. If you
encounter such an error, please report it to Intel Corporation, 3065 Bowers Avenue,
Santa Clara, California 95051, Attn: Software Marketing Department. The errors
falling into this class are as follows:

89. COM P I LERE RR0 R: BAD ERR 0 R REC0 VERY


95. COM P I LERE RR0 R: PAR S E BUF FER 0 VERFLO W
97. COM P I LERE RR0 R: S T ACK UN DERFLO W
99. COM P I LERE RR0 R: S EMAN TIC UNDERFLO W
163. COM P I LERE RR0 R: S EM ANT I C UN DE RFLO W
164. COM P I LERE RR0 R: I NVALID NOD E
165. COMPILER ERROR: INVALID OPERATOR
166. COMPILER ERROR: INVALID TREE
167. COMPILER ERROR: SCOPE 'STACK UNDERFLOW
169. COM P I LERE RR0 R: I NVALID RECOR D
175. COM P I LERE RR0 R: I HVALID 0 PER AT ION

14-20
PLjM-86 User's Guide Error Messages

177. COM P I L ERE R R 0 R: REA L S T AC K UHDE R FLO W


203. COM P I L ERE R R 0 R: BAD LAB E LAD DRES S
205. COM P I L ERE R R 0 R: BAD COD E G ENE RAT E D
210. COM P I L ERE R R 0 R: 0 B J E CT MOD ULEG E HER AT I 0 HER R 0 R
211. COMPILER ERROR: DEBUG SEGMENT SIZE OVERFLOW
212. COM P I L ERE R R 0 R: ILL EGA L F I XUP
251. COM P I L ERE R R 0 R: I NVALID 0 B J E C T
252. COM P I L ERE R R 0 R: S ELF NAMEL INK
253. COM P I L ERE R R 0 R: S ELF AT T R L I HK

14-21
APPENDIX A
PL/M-86 RESERVED WORDS
AND PREDECLARED IDENTIFIERS

These are the reserved words of PL/M-86. They may not be used as identifiers.

ADDRESS INITIAL
AND INTEGER
AT INTERRUPT
BASED LABEL
BY LITERALLY
BYTE MINUS
CALL MOD
CASE NOT
CAUSEINTERRUPT OR
DATA PLUS
DECLARE POINTER
DISABLE PROCEDURE
DO PUBLIC
DWORD REAL
ELSE REENTRANT
ENABLE RETURN
END SELECTOR
EOF STRUCTURE
EXTERNAL THEN
GO TO
GOTO WHILE
HALT WORD
IF XOR

These are the identifiers for the built-in procedures and predeclared variables. If one
of these identifiers is declared in a DECLARE statement, the corresponding built-in
procedure or predeclared variable becomes unavailable within the scope of the
declaration.

ABS INPUT
ADJUSTRPL INT
BLOCKINPUT INTERRUPTPTR
BLOCKINWORD INWORD
BLOCKOUTPUT LAST
BLOCKOUTWORD LOCKSET
BUILDPTR LENGTH
CARRY LOW
CMPB MEMORY
CMPW MOVB
DEC MOVE
DOUBLE MOVRB
FINDB MOVRW
FINDRB MOVW
FINDRW NIL
FINDW OFFSETOF
FIX OUTPUT
FLAGS OUTWORD
FLOAT PARITY
GETREALERROR RESTOREREALSTATUS
HIGH ROL
lABS ROR
INITREALMATHUNIT SAL

A-I
PLfM-86 Resened Words and Predeclared Identifiers PLfM-86 User's Guide

SAR SIZE
SAVER EAlSTATU S SKIPB
SCl SKIPRB
SCR SKIPRW
SElECTOROF SKIPW
SETB STACKBASE
SETINTERRUPT STACKPTR
SETW TIME
SHl UNSIGN
SHR XLAT
SIGNED ZERO

A-2
PROGRAM
BI
APPENDIX
CONSTRAINTS

Certain fixed size tables within the compiler constrain various features of a user
program to certain maximums. These limits are summarized below:

MAXIMUM:

Nesting of LITERALLY invocations .............................................. . 5


Nesting of INCLUDE controls ........................................................ . 5
N umber of nested procedures and DO cases .......... ,....................... .. 7
N umber of labels on a statement ..................................................... . unlimited
Nesting of blocks ............................................................................... . 18
Number of nested typed procedures ................................................ .. 20
N umber of elements in a factored list .............................................. . 64
Number of members in a structure ................................................. .. 64
Structure size ..................................................................................... . 64K-I

N umbers of characters in a line ...................................................... .. 128


Length of a string constant ............................................................... . 255
Number of DO blocks in a procedure ............................................. .. 255
N umber of cases in a DO CASE block ........................................... .. 255
Number of active cases ..................................................................... . 255
Number of EXTERNAL items ........................................................ . 255
Number of procedures in a module ................................................. .. 253
Segment Size ........... :......................................................................... . 64K-I

NOTE
The PL/M-86 compiler has a symbol capacity of approximately 5000
symbols. Of these, 800 are held in memory when the compiler has a partition
size of 96K. Any symbols over this amount will spill onto the workfiles disk,
causing performance degradation. (If this happens, the compiler will display
a message to the console.) To increase performance, look at the dictionary
summary (found in the compilation summary) to determine the amount of
additional memory needed to avoid spilling to the disk. If another 64K of
memory is added to the compiler's partition (either by adding more memory
to the system or by increasing its share of available memory), a total of 2300
symbols will then be held in memory. For large programs or programs with
many symbols, providing the compiler with more memory to work in will
improve its performance.

B-1
APPENDIX C
GRAMMAR OF THE
PL/M-86 LANGUAGE

This appendix lists the entire syntax of the PL/M-86 language Backus Naur Form
(BNF). Since the semantic rules are not included here, this syntax permits certain
constructions that are not actually allowed. The terminology used in the BNF syntax
has been designed for convenience in constructing concise and rigorous definitions.
Its appearance differs substantially from the main body of the manual.

The notations used here are slightly extended from standard BNF notations. An
ellipsis (. .. ) indicates that the syntactic element preceding it may be repeated indefi-
nitely. Braces ({ }) indicate that only one of the items stacked vertically within
them may be used. Brackets ([ ]) indicate that whatever appears within them may
be omitted. When items are stacked vertically within brackets, only one of the items
may be used.

The nonterminals in the syntax that follows are listed in alphabetical order after
section C.5.3. Each nonterminal is tagged with the section number (within this
appendix) where its primary definition may be found.

c. 1 Lexical Elements

C. 1. 1 Character Sets
<character>:: = <apostrophe>
I <non-quote character>

<non-quote character>:: = <letter>


I <decimal digit>
$
<special character>
blank

<letter>:: = <upper case letter>


I <lower case letter>

<upper case letter>::=AI BI·CIDIEI FIG I HIIIJ I KI LI MIN 101 PlaiR IS ITI UIV IWIXIYI Z
<lower case letter>::=al bl cl dl e If Ig I h Ii Ij I kill min 101 plq I r Is It I u Iv I w I x I YIz
<decimal digit>::=OI11213141516171819
<special character>:: = + I-I *1/1 < I > 1= I: I; 1.1,1 (I)I@I_
<apostrophe>:: ='

C.1.2 Tokens
<token>:: = <delimiter>
I <identifier>
<reserved word>
<numeric constant>
<string>

C-I
Grammar of the PL/M-86 Language PL/M-86 User's Guide

C.1.3 Delimiters
<delimiter>:: = <simple delimiter>
I <compound delimiter>

<simple delimiter>:: = + I - 1* 1/1 < I > I = I: I ; I. I , I (I) I @


<compound delimiter>:: = < >
I <=
1>=

C.1.4 Identifiers and Reserved Words

<identifier>:: = <letter> [ <letter>


<decimal digit>
J. .
$

<reserved word>see list, Appendix A

C.1.5 Numeric Constants


<numeric constant>:: = <binary number>
I <octal number>
<decimal number>
<hexadecimal number>
<floating point number>

<binary number>: : ~ <binary digit> [ <binary:i9it> ] ... B

<octal number>::~<octal digit> [<octalsdi9it> ] "'l~}

<decimal number>::~<decimal digit> [<decimalsdigit> ] [D]

<hexadecimal number>:: ~ <decimal digit> [<hexadec~mal digit> ] H

<floating point number>:: = <digit string> <fractional part> [<exponent part> ]


<fractional part>:: =.[ <digit string>]
<exponent part>:: =E [+ I - ]<digit string>
<digit string>::~<decimal digit> [decima~digit> ]

<binary digit>: : = 0 11
<octal digit>:: = <binary digit> 12 131415 1617
<decimal digit>:: = <octal digit> I 8 I 9
<hexadecimal digit>:: = <decimal digit> I A I B I C I 0 I ElF

C.1.6 Strings
<string>:: = <string body element>
I

<string body element>:: = <non-quote character>


I "

C-2
PL/M-86 User's Guide Grammar of the PL/M-86 Language

C.1.7 PL/M Text Structure: Tokens, Blanks, and Comments


<pl/m text>:: = <token> ]
[ <separator>

<separator>:: = blank
I <comment>

<comment>::= /* [<character>] ... */

C.2 Modules and the Main Program


<compilation>:: = <module> [EOF]
<module>::=<module name>: <simple do block>
<module name>:: = <identifier>

C.3 Declarations
<declaration>:: = <declare statement>
I <procedure definition>

C.3.1 DECLARE Statement


<declare statement>:: = DECLARE <declare element list>;
<declare element list>:: = <declare element>[, <declare element> ] ...
<declare element>:: = <factored element>
I <unfactored element>

<unfactored element>:: = <variable element>


I <literal element>
I <label element>

<factored element>:: = <factored variable element>


I <factored label element>

C.3.2 Variable Elements


<variable element>:: = <variable name specifier>
[<array specifier>] <variable type>
[ <variable attributes> ]

<variable name specifier>:: = <non-based name>


I <based name>BASEO<base specifier>

<non-based name>:: = <variable name>


<based name>:: = <variable name>
<variable name>:: = <identifier>
<base specifier>:: = <identifier> [.<identifier> ]

<variable attributes>:: = [PUBLIC] [<Iocator>][ <initialization>]


I [EXTERNAL][ <constant attribute>]

<locator>:: =AT( <expression»

C-3
Grammar of the PL/M-86 Language P~/M-86 User's Guide

<constant attribute>::=DATA

<array specifier>:: = <explicit dimension>


I <implicit dimension

<explicit dimension>::=( <numeric constant> )


<implicit dimension>::=( *)

<variable type>:: = <basic type>


I <structure type>

<basic type>:: = INTEGER


I REAL
I POINTER
SELECTOR
BYTE
WORD
DWORD

C.3.3 Label Element


<label element>:: = <identifier> LABEL [PUBLIC ]
EXTERNAL

C.3.4 Literal Elements


<literal element>:: = <identifier> LITERALLY <string>

C.3.S Factored Variable Element


<factored variable element>::=( <variable name specifier>
[. <variable name specifier> ] ... )
[<explicit dimension>] <variable type>
[<variable attributes>]

C.3.6 Factored Label Elements


<factored label element>:: = «identifier> [.<identifier>] ...) LABEL(PUBLIC ]
~XTERNAL

C.3.7 The Structure Type


<structure type>:: = STRUCTURE «member element>[, <member element> ] ...)
<member element>:: = <member name> [<explicit dimension>] <basic type>
<member name>:: = <identifier>
I «identifier>[, <identifier> ] ...)

C.3.S Procedure Definition


< procedure definition>: : = <procedure statement>
[<declaration> ... ][<unit> ... ] <ending>

<procedure statement>:: = <procedure name> :PROCEDURE


[ <formal parameter list> ][ <procedure type> ]
[<procedure attributes>];

C-4
PLfM-86 User's Guide Grammar of the PLfM-86 Language

<procedure name>:: = <identifier>


<procedure type:: = <basic type>
<basic type>:: = INTEGER
I REAL
I POINTER
SELECTOR
BYTE
WORD
DWORD

<formal parameter list>:: =( <formal parameter> (, <formal parameter> ] ... )


<formal parameter>:: = <identifier>

< procedure attributes>:: = < interrupt>}


{ EXTERNAL

<interrupt> }
PUBLIC
{
REENTRANT

C.3.9 Attributes
C.3.9.1 AT
<locator>: : = AT ( <expression> )

C.3.9.2 INTERRUPT
<interrupt>:: = INTERRUPT <numeric constant>

C.3.9.3 Initialization
<initialization>:: =
jINITIAL}
DATA
( <initial value> (,<initial value>] ... )

<initial value>:: = <expression>


I <string>

C.4 Units
<unit>: : = <conditional clause>
I <do block>
<basic statement>
<label definition> <unit>

<basic statement>:: = <assignment statement>


I <call statement>
I <goto statement>
<null statement>
<return statement>
<iAPX 286 dependent statement>

<scoping statement>:: = I <simple do statement>


I . <do-case statement>
<do-while statement>
< iterative do statement>
<end statement>
< procedure statement>

<label definition>:: = <identifier>:

C-5
Grammar of the PL/M-86 Language PL/M-86 User's Guide

C.4.1 Basic Statements

C.4.1.1 Assignment Statement


<assignment statement>:: = <left part >=<expression>;
<left part>:: = <variable reference> [, <variable reference>]

C.4.1.2 CALL Statement


<call statement>:: = CALL <simple variable>[ <parameter list>];
<parameter list>::= «expression> [,<expression>l ... )
<simple variable>:: = <identifier>
I <identifier>. <identifier>

C.4.1.3 GOTO Statement


<goto statement>:: =
l I
GOTO
GO TO
<identifier> ;

C.4.1.4 Null Statement


<null statement>::=;

C.4.1.5 RETURN Statement


<return statement>:: = <typed return>
I <untyped return>

<typed return>:: = RETURN <expression> ;


<untyped return>:: = RETURN;

C.4.1.6 iAPX 86 Dependent Statements


<iAPX 86 dependent statement>:: = <disable statement>
I <enable statement>
<halt statement>
<cause interrupt statement>

<disable statement>:: = DISABLE;


<enable statement>:: = ENABLE;
< halt statement>:: = HALT;
<cause interrupt statement>:: = CAUSE$INTERRUPT (numeric constant);

C.4.2 Scoping Statements

C.4.2.1 Simple DO Statement


<simple do statement>:: = DO;

C.4.2.2 DO-CASE Statement


<do-case statement>:: = DO CASE <expression> ;

C-6
PLfM-86 User's Guide Grammar of the PLJM-86 Language

C.4.2.3 00-WHILE Statement


<do-while statement>:: = DO WHILE <expression> ;

C.4.2.4 Iterative 00 Statement


<iterative do statement>:: = DO <index part> <to part> [ <by part>];
<index part>:: = <index variable> = <start expression>
<to part>::= TO <bound expression>
<by part>::= BY <step expression>
<index variable>:: = <simple variable>
<start expression>::= <expression>
<bound expression>:: = <expression>
<step expression>:: = <expression>

C.4.2.5 END Statement


<end statement>:: = END [<identifier>];

C.4.2.6 Procedure Statement


<procedure statement>:: = <procedure name> : PROCEDURE
[<formal parameter list>][ <procedure type>]
[<procedure attributes>] ;

C.4.3 Conditional Clause


<conditional clause>:: = <if condition> <true unit>
I <if condition> <true element> ELSE <false element>

<if condition>: : = IF <expression> THEN


<true element>:: = [<label definition> ... ] <do block>
I [<label definition> ... ] <basic statement>

<false element>:: = <unit>


<true unit>::= <unit>

C.4.4 DO Blocks
<do block>::= <simple do block>
I <do-case block>
<do-while block>
<iterative do block>

C.4.4.1 Simple DO Blocks


<simple do block>::= <simple do statement>[<declaration> ... ][ <unit> ...)<ending>
"<ending>:: =[ <label definition> ... )<end statement>

C.4.4.2 DO-CASE Blocks


<do-case block>:: = <do-case statement> {<unit> ... } <ending>

C.4.4.3 00-WHILE Blocks


<do-while block>::=<do-while statement> [ <unit> ... ) <ending>

C.4.4.4 Iterative 00 Blocks


<iterative do block>:: = <iterative do statement> [<unit> ... ]<ending>

C-7
Grammar of the PL/M-86 Language PL/M-86 User's Guide

c.s Expressions
C.S.1 Primaries
<primary>:: = <constant>
I <variable reference>
<location reference>
<subexpression>

<subexpression>:: = ( <expression> )

c.s.t.t Constants
<constant>:: = <numeric constant>
I <string>

C.S.t.2 Variable References


<variable reference>:: = <data reference>
I <function reference>

<data reference>:: = <name>[ <subscript>][ <member specifier>]


<subscript>:: = ( <expression> )
<member specifier>:: = . <member name>[ <subscript>]
<function reference>:: = <name>[ <actual parameters>]
<actual parameters>:: = ( <expression> (, <expression> ]. ..)
<member name>:: = <identifier>
<name>:: = <identifier>

C.S.t.3 Location References


<location reference>:: = <constant list>

{~rV'ri'ble reference>

<constant list>: : = «constant>[, <constant> ] ... )

C.S.2 Operators
<operator>: : = <logical operator>
I <relational operator>
I <arithmetic operator>

<logical operator>:: = AND


I OR
NOT
XOR

<relational operator>:: = < I > I <= I >= I <> I =


<arithmetic operator>:: = + I - I PLUS I MINUS I * 1/1 MOD

C.S.3 Structure of Expressions


<expression>:: = <logical expression>
I <embedded assignment>

C-8
PL/M-86 User's Guide Grammar of the PL/M-86 Language

<embedded assignment>:: = <variable reference> : = <logical expression>


<logical expression>:: = <logical factor>
I <logical expression> <or operator> <logical factor>

<or operator>:: = OR
I XOR

<logical factor> :: = <logical secondary>


I <logical factor> <and operator> <logical secondary>

<and operator>:: = AND


<logical secondary>:: = [<not operator>] < logical primary>
<not operator>:: = NOT
<logical primary>:: = <arithmetic expression>
[<relational operator> <arithmetic expression>]

<relational operator>:: = < I > I <= I >= I <> 1=

<arithmetic expression>:: = <term>


I <arithmetic expression> <adding operator> <term>

<adding operator>:: = + 1- I PLUS I MINUS


<term>:: = <secondary>
I <term> <multiplying operator> <secondary>

<multiplying operator>:: = * 1/1 MOD


<secondary>::=r<unary minus>l<primary>
L<unary plus> J
<unary minus>:: = -
<unary plus>:: = +

NONTERMINALS SECTION

<actual parameters> ......................................................................,......... ................ C.S.1.2


<adding operator> ......... ..... ...... ....... ........ .... ......... .................... ..... .... ........ ........ ...... C.S.3
<and operator> ........................................................................................................ C.S.3
<apostrophe> .......................................................................................................... C.l.l
<arithmetic expression> ................................................................................. ... ...... C.S.3
<arithmetic operator> ........................... ,. ..................... ................. ..... ... .......... ......... C.S.2
<array specifier> ............. .... ........ ......... .... ....... ........... .............. ....... ..... ....... .... .... ..... C.3.2
<assignment statement> ..... ... ..... ..... .... ....... ...... ... .............. .... .............. ... ................ C.4.l.1
<base specifier> ...................................................................................................... C.3.2
<based name> ......................................................................................................... C.3.2
<basic statement> .............. ...... ................ ... ... ................................ ...... ....... ....... ..... C.4
<basic type> ........................ ........... ..... ............. .... ....................... ......... ..... .............. C.3.2
<binary digit> .... ......... ......... .... ......... ....... ..... ... ................................ ..... ........ ....... ..... C.l.S
<binary number> ..................................................................................................... C.l.S
<bound expression> ................................................................................................ C.4.2.4
<by part> ............................................................................................................,..... C.4.2.4
<call statement> ....................... ... ... ...... ....... ...... ... ............................. ........ .............. C.4.l.2
<character> ..... ........... ..... .... .... ......... .... ...... ..... ................................ ......... ........... ..... C.l.l
<comment> ........................................... ,............................................................,..... C.l.7
<compilation> .......................................................................................................... C.2
<compound delimiter> .... ..................... ..... ...... ........... .................. .............. ...... ........ C.l.3
<conditional clause> ................................................................................................ C.4.3
<constant list> ............... ...... ... ........ ........... ....... .............................. ...... .......... .... ..... C.S.l.3
<constant> ............................................ ,. ...................... .................. ........... ....... ....... C.S.l.1
<data reference> ....................... ... ....... ............ ................................... ...... ............... C.S.l.2

C-9
Grammar of the PLfM-86 Language PLfM-86 User's Guide

<decimal digit> ......................................................................................................... C.1.S


<decimal number> ................................................................................................... C.1.S
<declaration> ........................................................................................................... C.3
<declare element list> ............................................................................................. C.3.l
<declare element> .... ...... ... ... ........ ..... ... ... .......... ... .... ..... ............ ... ... ... ..... .... .... ........ C.3.l
<declare statement> ................................................................................................ C.3.l
<delimiter> ............................................................................................................... C.l.3
<digit string> .................................................................................................... ........ C.l.S
<disable statement> ... ..... ............. ............ ... ......... ..... ... ..... ........ ........ ........... ... .... .... C.4.l.6
<do block> ............................................................................................................... C.4.4
<do-case block> ...................................................................................................... C.4.4.2
<do-case statement> ............................................................................................... C.4.2.2
<do-while block> ....... ........... ............ .... .... ....... ... .......... ...... .... ...... ........... ............ .... C.4.4.3
<do-while statement> ............. ...... .......... ......... ..... ......... ...... ...... .......... ..... .... ....... .... C.4.2.3
<embedded assignment> ..... ... ........ ........ ..... ...... ................ .......... ...... ...... ............... C.S.3
<enable statement> ................ ...... ........ .... ....... ..... ......... ...... ...... ......... ............. .... .... C.4.1.6
<end statement> .... ............... .... ... .... ........... .......... ...... ....... ......... ......... .... ... ......... .... C.4.2.S
<ending> .......... ............... ........ ...... ........... ..... ........ ......... .... ..... ...... ...... ........... ....... ... C.4.4.1
<explicit dimension> ................................................................................................ C.3.2
<exponent part> ..... ................ ................. ........... ............ .... .......... ................. .......... C.1.S
<expression> .......... ................ ......... ..... ........ ...... ........... ......... ....... ......... ..... ........ .... C.S.3
<factored element> ... ............. ......... ......... .......... ........... ....... ......... .......... ..... ........... C.3.1
<factored label element> ......................................................................................... C.3.6
<factored member> .............. ........... ......... ............ ...... ........ ........ ......... ................ .... C.3.7
<factored variable element> ............ ............ ......... ...... ........... ........ .............. ............ C.3.S
<false element> ........................ ....... ............ ......... ......... ....... ... ...... ..... ........ ......... .... C.4.3
<floating point number> ............. .............. ....... ......... ............ ...... ............................. C.1.S
<formal parameter list> ... .............................. ....... ..... .......... ............... ..................... C.3.8
<formal parameter> .................... ...... ........ ..... ....... ..... .... ..... ........... .... ....... ... ............ C.3.8
<fractional part> ........... ................ ............................................. .... .......................... C.1.S
<function reference> ................................ ........................................................... .... C.S.1.2
<goto statement> ... .................................................. ..................... .......................... C.4.l.3
<halt statement> ...................................................................................................... C.4.1.6
<hexadecimal digit> ..................................................................................... ........ .... C.l.S
<hexadecimal number> ................ ........................................................................... C.l.S
<identifier> ................................................ ..................................... ...................... .... C.l.4
<if condition> .................................................................. .......................................... C.4.3
<implicit dimension> ................................................................................................ C.3.2
<index part> ............................................................................................................. C.4.2.4
<index variable> ...................................................................................................... C.4.2.4
<initial value> ........................................................................................................... C.3.9.3
<initialization> .......................................................................................................... C.3.9.3
<interrupt> ............................................................................................................... C.3.9.2
<iterative do block> ..................................................................................... ............ C.4.4.4
<iterative do statement> .......................................................................................... C.4.2.4
<label definition> ..................................................................................................... C.4
<label element> ....................................................................................................... C.3.3
<Ieftpart> ...................... :......................................................................................... C.4.l.l
<letter> ..................................................................................................................... C.l.l
<linkage> ................................................................................................................. C.3.8
<literal element> ...................................................................................................... C.3.4
<Iocati<?n reference> ................................................................................................ C.S.l.3
<locator> .................................................................................................................. C.3.9.1
<logical expression> ............................................................................................... C.S.3
<logical factor> ........................................................................................................ C.S.3
<logical operator> .................................................................................................... C.S.2
<logical primary> ..................................................................................................... C.S.3
<logical secondary> ................................................................................................ C.S.3
<lower case letter> ...................................................................................... ............ C.l.1
<member element> .................................................................................................. C.3.7

C-IO
PL/M-86 User's Guide Grammar of the PL/M-86 Language

<member name> ...................................................................................................... C.3.7


<member specifier> .... ....... ..... ..... ....... .... ... ............. .... .......... ........................ ........... C.S.1.2
<module name> ....................................................................................................... C.2
<module> ................................................................................................................. C.2
<multiplying operator> ...... ....... ... ............. .... ..... ..... ..... ...... ..... .... ....... ... .... ......... ...... C.S.3
<name> .................................................................................................................... C.S.1.2
<non-based name> .... ...... .... .... .... ........ ... ... ... ....... ........ ........ ............ ........ .......... ... ... C.3.2
<non-quote character> .. ... ... .... .... ...... ..... ... ... ..... ..... ..... ........... ... ...... ............. ...... ..... C.1.1
<not operator> ....................................................................,. ...... .................. ..... ...... C.S.3
<null statement> ...................................................................................................... C.4.1.4
<numeric constant> ................................................................................................. C.1.S
<octal digit> ... ............. ....... ..... ..... ........ ... ..... ................ .... ....... ...... ........ ... ..... ..... ...... C.1.S
<octal number> .... ..... ........ ........ ............. ....... ..... ..... ..... ........... ..... ........... ...... ..... ... ... C.1.S
<operator> .. ......... ..... ........ ............ ....... .............. ..... ..... ........ ......... .................. ... ... ... C.S.2
<or operator> .... ... ........ ..... ..... ...... ........ ... ... ........ .......... ........... .... .................. ..... ...... C.S.3
<parameter list> ....................................................................................................... C.4.1.2
<pl/m text> ... ..... ... ............ .... ........ ..... ... ..... ......... ..... .... ....... ..... ............. ..... .... ........... C.1.7
<primary> ................................................................................................................. C.S.1
<procedure attributes> ............................................................................................ C.3.S
<procedure definition> ............................................................................................ C.3.S
<procedure name> .................................................................................................. C.3.S
<procedure statement> .... ..... ........ ...... ..... .............. ..... ...... ..... ..... .... .......... ... ..... ...... C.3.S
<procedure type> ...... ....... ...... ..... ...... ..... ............. ... ..... ..... ...... ........... ........ ... ........... C.3.S
<relational operator> ........ ........ ......... ..... ........ ... .......... ...... ........... ........ ......... .......... C.5.2
<reserved word> ............. .................................. ...................................................... C.1.4
<return statement> .................................................................................................. C.4.1.S
<scoping statement> ............................................................................................... C.4
<secondary> ............................................................................................................ C.5.3
<separator> ..................... .... .... .............. .... ........ ........ .... ......... ...... ... ....... ... ... ..... ...... C.1.7
<simple delimiter> ....................... ...................... ...................................................... C.1.3
<simple do block> .... ................................................... ............................................ C.4.4.1
<simple do statement> ..................... ...................... ................................................. C.4.2.1
<simple variable> ......................................................... " .......................................... C.4.1.2
<special character> ......... ........................................................................................ C.1.1
<start expression> ........... ................................. ...................................................... C.4.2.4
<step expression> ............................ ...................... ........................................... ...... C.4.2.4
<string body element> ............................................ ........................................... ...... C.1.6
<string> .................................................................................................................... C.1.6
<structure type> ...................................................................................................... C.3.7
<subexpression> ......................... ................................ ............................................ C.S.1
<subscript> .............................................................................................................. C.5.1.2
<term> ...................................................................................................................... C.5.3
<to part> ..... ..... ... ...... .... ...... .......... .......... ........... ..... .... ...... .... ........ ....... .... ..... ..... ...... C.4.2.4
<token> .................................................................................................................... C.1.2
<true element> .... ........ ........ ...... .... ..... .... .................... ...... ....... ...... .......... .... .... ... ...... C.4.3
<true unit> ................................................................................................................ C.4.3
<typed return> ......................................................................................................... C.4.1.S
<unary minus> .................. ....................................................................... .......... ...... C.S.3
<unary plus> ............................................................................................................ C.S.3
<unfactored element> ................. ...................................................................... ...... C.3.1
<unfactored member> ............................................................................................. C.3.7
<unit> ....................................................................................................................... C.4
<untyped return> .......................................................... ;.......................................... C.4.1.S
<upper case letter> ....... .......................................................................................... C.1.1
<variable attributes> ................................................................................................ C.3.2
<variable element> ... ... ...... ........... .......... ...... ........... ..... ........... ..... .... .... .... .......... ...... C.3.2
<variable name specifier> ....................................................................................... C.3.2
<variable name> ................................ ..................... ........................................... ...... C.3.2
<variable reference> .................... ............................................................................ C.5.1.2
<variable type> ........................................................................................................ C.3.2

C-ll
APPENDIX
PL/M-80 AND PL/M-86
01

D. 1 General Comparison
PLfM-86 may be regarded as an extension of the PLfM-80 language, described in
Intel document 9800268. PL/M-86 differs from PL/M-80 in three principal respects:
• Floating-point arithmetic and signed integer arithmetic are provided. These are
supported by two new data types, REAL and INTEGER.
• The extended addressing capability of the iAPX 86 is supported by two new data
types, POINTER and SELECTOR, for storage of iAPX 86 locations, and a new
location reference operator, @.
• The set of built-in procedures is greatly expanded.

In addition, the PLfM-80 reserved word ADDRESS is replaced by the PLfM-86


reserved word WORD. Thus where PLfM-80 has only the two data types, BYTE
and ADDRESS, PLfM-86 has seven: BYTE, WORD, DWORD, INTEGER, REAL,
POINTER, and SELECTOR.

The PLfM-86 rules for expression evaluation are more complete than those of
PLfM-80, to make proper use of the extended capabilities. There are also various
other differences which stem from the ones noted here. In particular, an iterative DO
block operates differently if its index variable is an INTEGER variable.

D.2 Compatibility of PL/M-80 Programs and the


PL/M-86 Compiler
PLfM-80 programs that operate correctly on an 8080 can be recompiled with the
PLfM-86 compiler to produce code that will run on an iAPX 86. The PL/M-80
source code must first be edited as follows:
• All identifiers in the PL/M-80 source code must be examined and changed if
they are PLfM-86 reserved words. The PLfM-86 reserved words that might occur
as identifiers in a PLfM-80 source program are WORD, DWORD, INTEGER,
REAL, POINTER, SELECTOR, and CAUSEINTERRUPT (since these are
not reserved words in PLfM-80).
• It is not necessary to change ADDRESS to WORD; ADDRESS is a PLfM-86
reserved word with the same meaning as WORD.

Note that where PLfM-86 programs would normally have POINTER variables and
location references formed with the @ operator, PLfM-80 programs have ADDRESS
(WORD) variables and location references formed with the "dot" operator.
PLfM-80 usage is therefore slightly less restricted than normal PL/M-86 usage, since
arithmetic operations are allowed on WORD values. To provide upward compatibil-
ity, the PLfM-86 compiler in general supports PL/M-80 usage. However, some
restrictions are imposed, affecting the types of expressions allowed in the AT attrib-
ute, the INITIAL and DATA initializations, and location references. See also the
discussions of size controls and the dot and @ operators in this manual.

(In fact, all of these constructions are formally permitted by the PL/M-86 language,
but their use in PLfM -86 programs is not recommended for most purposes, since
they will not always produce correct results in a program where POINTER values
also appear.)

0-1
I

. ~
APPENDIX EI
ASCII CODES

ASCII HEX PL/M-86 ASCII HEX PL/M-86


CHARACTER CHARACTER? CHARACTER CHARACTER?
NUL 00 no @ 40 yes
SOH 01 no A 41 yes
STX 02 no B 42 yes
ETX 03 no C 43 yes
EOT 04 no 0 44 yes
ENQ 05 no E 45 yes
ACK 06 no F 46 yes
BEL 07 no G 47 yes
BS 08 no H 48 yes
HT 09 no I 49 yes
LF OA no J 4A yes
VT 08 no K 48 yes
FF OC no L 4C yes
CR 00 no M 40 yes
SO OE no N 4E yes
SI OF no 0 4F yes
OLE 10 no P 50 yes
OCI 11 no Q 51 yes
OC2 12 no R 52 yes
OC3 13 no S 53 yes
OC4 14 no T 54 yes
NAK 15 no U 55 yes
SYN 16 no V 56 yes
ET8 17 no W 57 yes
CAN 18 no X 58 yes
EM 19 no Y 59 yes
SUB 1A no Z 5A yes
ESC 18 no [ 58 no
FS 1C no \ 5C no
GS 10 no ] 50 no
RS 1E no /\(.) 5E no
US 1F no - 5F yes
space 20 yes \
60 no
! 21 no a 61 yes
" 22 no b 62 yes
# 23 no c 63 yes
$ 24 yes d 64 yes
% 25 no e 65 yes
& 26 no f 66 yes
27 yes 9 67 yes
( 28 yes h 68 yes
) 29 yes i 69 yes
* 2A yes j 6A yes
.+- 28
2C
20
yes
yes
yes
I
m
k 68
6C
60
yes
yes
yes
2E yes n 6E yes
I 2F yes 0 6F yes
0 30 yes p 70 yes
1 31 yes q 71 yes
2 32 yes r 72 yes
3 33 yes s 73 yes
4 34 yes t 74 yes
5 35 yes u 75 yes
6 36 yes v 76 yes
7 37 yes w 77 yes
8 38 yes x 78 yes
9 39 yes y 79 yes
: 3A yes z 7A yes
; 38 yes { 78 no
< 3C yes I 7C no
= 3D yes } 70 no
> 3E yes --- 7E no
? 3F no DEL 7F no

E-l
APPENDIX F
LINKING TO MODULES WRITTEN
IN OTHER LANGUAGES

This appendix describes the calling conventions used by iAPX 86 family languages.
These calling conventions are standardized so that a module written in PLfM-86 can
freely call procedures, subroutines, and subprograms in other modules written in other
iAPX 86 family languages.

As a PLfM-86 programmer calling PLfM-86 procedures and functions from


PLfM-86, you do not need the information in this appendix. You need to know infor-
mation about parameters and arguments as described in Chapter 8.

As a PLfM-86 programmer calling ASM86 subroutines, you need to know the calling
conventions of stack and register usage described in this appendix. You also need to
know the corresponding data types listed at the end of this appendix in order to write
a subroutine that can pick up the data your PLfM-86 program passes to it. Refer to
the ASM86 Macro Assembler Operating Instructions for more information about
linking to ASM86 programs and for examples of linking such programs to PLfM-86
programs.

The easiest way to ensure compatibility between assembly-language subroutines that


are linked to PLfM-86 programs or procedures is to write a dummy procedure in
PLfM-86. This procedure would have the same argument list and the same attributes
as the desired assembly language subroutine. The PLfM-86 procedure would then be
compiled with the correct size control and with the CODE control specified. This will
produce a pseudoassembly listing of the generated iAPX 86 code, which may then be
copied as the prologue and epilogue of the assembly language subroutine.

F. 1 -Introduction
Since PLfM-86 allows you to write and compile separate PLfM-86 modules that can
be linked together at a later time, you can solve a big problem with a solution composed
of separately-tested modules that are linked together after they are internally bug-
free. Not all modules have to be in PLfM-86-you can choose the appropriate
languages for each module. Be sure to link the modules properly with the iAPX 86
Linker (LINK86) to satisfy references to externals. Since the iAPX 86 family
languages follow the same calling sequence (described in the following section), control
will pass to a called module correctly. However, the called module might not be able
to deal intelligently with the data passed to it since languages treat some data
structures differently.

By specifying arguments in a reference to an external procedure, you pass data to the


external procedure. The number of arguments and the order in which you specify
them must match the number and order of the corresponding parameters in the
external procedures declaration (see Chapter 8).

All arguments for parameters are passed on the iAPX 86 stack or the 8087 register
stack in the order in which they were specified. Functions that return values return a
simple-type value (except REAL values) in a register, or a REAL value on the top
of the 8087 register stack.

F-l
Linking to Modules Written in Other Languages PL/M-86 User's Guide

F.2 Calling Sequence


The calling sequence for each procedure activation places the procedure's actual
parameters (if any) on the stack then activates the procedure with a CALL
instruction.

Parameters are placed on the iAPX 86 stack or the 8087 register stack in left-to-
right order. Since the stack grows from higher locations to lower locations, the first
parameter occupies the highest position on the stack, and the last parameter occupies
the lowest position. Note that a BYTE parameter occupies two bytes on the stack;
the lower byte holds the value, the higher byte is undefined. A POINTER parameter
in the SMALL(ROM), COMPACT, MEDIUM, and LARGE cases consists of a
selector and an offset. The 16-bit selector is pushed first, followed by the 16-bit offset.

The leftmost seven REAL parameters are passed on the top of the 8087 stack. If
more than seven REAL parameters are present, the rest (after the leftmost seven)
are passed on the iAPX 86 stack.

After the parameters are passed, the CALL instruction places the return address on
the stack. In the SMALL and COMPACT cases with local procedures, this is a
16-bit offset (the contents of the IP register) and occupies two contiguous bytes on
the stack.

In the MEDIUM and LARGE cases, and for procedures exported from COMPACT,
the type of the return address depends on whether the procedure is local or public.
The return address for a local procedure, like any return address for the SMALL
case, is a 16-bit offset and occupies two contiguous bytes on the stack. For a public
procedure in the MEDIUM or LARGE case, and for procedures exported from a
subsystem, the return address is a POINTER value consisting of a selector and an
offset; it is passed in the same way a POINTER parameter is passed. The 16-bit
segment selector (contents of the CS register) is pushed first, then the 16-bit offset
(IP register contents) is pushed.

Control is passed to the code of the procedure by updating the IP register. In


MEDIUM and LARGE cases, and for procedures exported from a subsystem, the
CS register is also updated.

Figure F-l shows the stack layout at the point where the procedure gains control.

HIGHER
I-----------t......-. STACK MARKER (BP REG. CONTENTS)
LOCATIONS
PARAMETER 0
PARAMETER 1
EACH PARAMETER OCCUPIES 2 OR 4
BYTES-SEE TEXT

PARAMETER N

ABSENT IN SMALL OR COMPACT


RETURN SEGMENT SELECTOR PROGRAM OR LOCAL PROCEDURE

RETURN OFFSET
~g~::'ONS t---------~~ STACK POINTER (SP REG. CONTENTS)

121945·5

Figure F-l. Stack Layout at Point Where a Non-Interrupt Procedure is Activ~ted

F-2
PL/M-86 User's Guide Linking to Modules \yritten in Other Languages

F.3 Procedure Prologue


In compiling the procedure itself, the compiler inserts at the beginning a sequence of
code called the prologue. This code accomplishes the following:
I. If the procedure has the PU BLIC attribute and the program size is LARGE, or
if it is exported from a subsystem, the contents of the OS register are placed on
the stack. The OS register is then updated with a value that is found in the
current code segment (i.e., the segment containing the procedure). (The OS
register contains the segment selector for the current data segment; thus, this
step implements the pairing of code and data segments in the LARGE case. It is
not needed in the SMALL, COMPACT, and MEDIUM cases because the data
segment does not change.)
2. If any parameter of the procedure is referenced by a nested procedure, all param-
eters are removed from the stack and placed in space reserved for them in the
data segment.
3. The stack marker offset (BP register contents) is placed on the stack, and the
current stack pointer (SP register contents) is used to update the BP register.
4. If the procedure has the REENTRANT attribute, space is reserved on the stack
for any variables declared within the procedure (this does not include based
variables, variables with the OA TA attribute, or variables with the AT
attribute ).

Control then passes to the code compiled from the executable statements in the
procedure body. Figure F-2 shows the stack layout at this point.

PARAMETER 0
HIGHER PARAMETER 1
LOCATIONS ABSENT IF ANY PARAMETER IS
REFERENCED WITHIN A NESTED PROCEDURE
}
PARAMETERN

RETURN SEGMENT SELECTOR ABSENT IN SMALL OR COMPACT


} PROGRAM OR LOCAL PROCEDURE

RETURN OFFSET

OLD DATA SEGMENT ONLY IN PUBLIC PROCEDURE IN


SELECTOR } LARGE PROGRAM

- f-4 OLD STACK MARKER


......... NEW STACK MARKER (BP REG. CONTENTS)
LOCAL VARIABLES

} ON!. V IN REENTRANT PROCEDURE

THIS SPACE MAY BE STACK POINTER MAY CHANGE


USED DURING PRO- DURING PROCEDURE EXECUTION
CEDURE EXECUTION

LOWER
LOCATIONS

121945-6

Figure F-2. Stack Layout During Execution of a Non-Interrupt Procedure Body

F-J
Linking to Modules Written in Other Languages PL/M-86 User's Guide

F.4 Procedure Epilogue


To return from the procedure, the compiler inserts a code sequence called the epilogue.
This accomplishes the following:
1. If the compiler has used stack locations for temporary storage or local variables
during procedure execution, the stack pointer (SP register) is loaded with the
stack marker (BP register contents). This has the effect of discarding the
temporary storage.
2. The old stack marker is restored by popping the stored value from the stack into
the BP register.
3. If the procedure has the PUBLIC attribute and the program size is LARGE or
it is exported from a subsystem, the old data segment selector is restored by
popping the stored value from the stack into the DS register.
4. If the program size is SMALL, the stored return address (a 16-bit offset) is
popped into the IP register. Any parameters stored on the stack are discarded.

If the program size is MEDIUM or LARGE and the procedure is local, a return is
performed using the same actions described above. If the program size is MEDIUM
or LARGE and the procedure is public, the stored return-address offset from the
stack is popped into the IP register and the return-address selector is popped into the
CS register. Any parameters not stored on the stack are discarded.

F.5 Register Usage


Table F-l provides a summary of iAPX 86 register usage.

In addition, the 8087 stack contains the first seven REAL arguments passed by the
calling program. The 8087 status word is unknown and need not be saved; if it is
changed, the 8087 mode word must be saved on entry and restored before exit.

If an assembly language subroutine alters the DS or SS registers, and expects to be


called by a PL/M-86 program, it must save the contents of these registers upon entry
and restore them before returning to the PLfM-86 program.

PLfM-86 uses the BP register to address the stack. If it uses the BP register, a called
assembly language subroutine must save the contents of this register upon entry and
restore its contents before returning control to the PLfM-86 program. Before return-
ing, the called subroutine must also adjust the SP register to remove all
parameters from the iAPX 86 stack.

The AX, BX, CX, DX, SI, DI, and ES registers do not need to be preserved. A called
assembly language subroutine can freely use these registers.

An assembly language program calling a PLfM-86 procedure cannot expect the


contents of the general-purpose registers, except BP and SP, to be preserved. If they
are needed, they must be saved prior to calling the PLfM-86 procedure.

Table F-2 summarizes the iAPX 86 registers used to hold simple data types that are
returned by typed procedures.

F-4
PL/M-86 User's Guide Linking to Modules Written in Other Languages

F.6 Segment Name Conventions


Table F-3 summarizes the segmentation of a subsystem under the program size
controls by giving the name of the segment where each type of program section is
stored for each model.

Table F-l. Summary of iAPX 86 Register Usage

Register Must Preserve Usage

No Return BYTE (AL), WORD, OWORO


AX
INTEGER, and SELECTOR values
BX No Return POINTER offset values
CX No -
OX No Return OWORO values
SP Yes· Stack pointer
BP Yes Stack marker
SI No -
DI No -
FLAGS No -
CS Yes Called procedure's code segment
OS Yes Caller's data segment
SS Yes Caller's stack segment
ES No Return POINTER segment selector

• SP must be adjusted so that all arguments are removed from the stack upon return.

Table F-2. Registers Used to Hold Simple Data Types

Procedure Type Register

BYTE AL
WORD AX
OWORO OX:AX
INTEGER AX
POINTER (SMALL)· BX
POINTER (COMPACT) ES:BX
POINTER (MEDIUM) ES:BX
POINTER (LARGE) ES:BX
SELECTOR AX
REAL Top of
RMU stack

* Under the ROM option, the result is returned in ES:BX.

F-5
Linking to Modules Written in Other Languages PLjM-86 User's Guide

Table F-3. Summary of PL/M-86 Segment Names


Model SubModel Code Data Const Stack

SMALL IN DATA CODE DATA CONST STACK

IN CODE CODE DATA CONST STACK

COMPACT IN DATA CODE DATA CONST STACK

IN CODE CODE DATA CONST STACK

COMPACT IN DATA sCODE sDATA CONST STACK


(subsystem)

IN CODE sCODE sDATA CONST STACK

MEDIUM IN DATA meODE DATA CONST STACK

IN CODE meODE DATA CONST STACK

LARGE IN DATA meODE mDATA mDATA STACK

IN CODE meODE mDATA meODE STACK

LARGE IN DATA meODE mDATA mOATA STACK


(subsystem)

IN CODE meODE mDATA meODE STACK

NOTES:
sCODE denotes a segment name composed of the subsystem name and CODE.
sDATA denotes a segment name composed of the subsystem name and DATA.
meODE denotes a segment name composed of the module name and CODE.
rnDATA denotes a segment name composed of the module name and DATA.

F.7 Floating-Point Linkage


This section deals with the issues of choosing the linkage specifications appropriate
to your use of the REAL math facility: no use, PLJM-S6 use only, or use of routines
not written in PLJM-S6. What is appropriate also depends on whether execution will
use an actual S087 chip or an emulator.

These linkage specifications make available to your program the libraries of floating-
point functions. The circumstances determining whiCh library is appropriate are given
in table F-4. The libraries themselves are discussed briefly below the table.

The interface libraries do the following:


• SOS7.LIB resolves external references inserted by the translator of an iAPX S6
program so that floating-point instructions will correctly invoke the 80S7 chip.
SOS7.LIB is the library of floating-point functions written for the chip itself rather
than for the Emulator.
• ES087.LIB resolves such references to invoke the Emulator software instead of
the actual SOS7 chip.

F-6
PL/M-86 User's Guide Linking to Modules Written in Other Languages

Emulation is performed by E8087 or PE8087.


• E8087 is the actual library of emulation routines, which provide every function
and feature of an actual 8087 chip except speed. Emulation is invoked automat-
ically as needed, using interrupts 20 through 31. The full Emulator occupies about
16K bytes of code space.
• PE8087 is a subset of E8087. The REAL arithmetic performed by PL/M-86
programs does not require the complete set of routines in the full Emulator. The
partial Emulator occupies about 8K bytes of code space.

NOTE
The 8087 Emulator processes exceptions exactly as the 8087 does. However,
if your iAPX 86/8087 implementation includes some external interrupt
masking device such as an 8259A, the effect of this external device cannot
be simulated by the 8087 Emulator. With the Emulator, an Interrupt 16 will
occur after the execution of any instruction when the (emulated) interrupt is
active and the iAPX 86 interrupt is enabled, even" if the 8259A is disabled.

(For examples of how to link interface libraries with your program, see specific host-
system appendix.)

To locate the 8087 Emulator at a specifi~d memory location:


• Locate the read-only code by referring to class AQMCODE in the LOC86
invocation.
• Locate the read-write data area by referring to class AQMDATA.

Table F-4. Linkage Choices for REAL..:Math Usage


Link-List Should Include the
Use of Emulator or Specifications Below (Not
REAL Math Facility Actual Chip Used Necessarily in the Order
Shown) After Object Modules

NONE NEITHER (none)

All Floating Point EMULATOR ESOS7.LlB, PESOS7


in PLfM-S6 ONLY

With Some Modules EMULATOR ESOS7.LlB, ESOS7


that Use Floating Point
NOT in PLfM-S6

ANY ACTUAL SOS7 CHIP SOS7.LlB

F-7
APPENDIX G
RUN-TIME INTERRUPT PROCESSING

G. 1 General Information
An interrupt is initiated when the CPU receives a signal on its "maskable interrupt"
pin from some peripheral device or when control is transferred to an interrupt vector
by the CAUSE$INTERRUPT statement. (If your program runs under an operating
system that traps interrupts, the information in this appendix may not be applicable
to you.)

Note that the CPU does not respond to this signal unless interrupts are enabled. The
compiler does not generate any code to enable or disable interrupts at the start of
your main program.

NOTE
If you require your program to begin with interrupts disabled, simply start
with the instruction DISABLE. Since the iAPX 86 processor does not allow
an interrupt to occur until the first machine instruction following the enable
instruction has been processed, the resulting code sequence will not allow any
maskable interrupt to occur.

If interrupts are enabled and vectored through an interrupt gate, the following actions
take place:
1. The CPU completes any instruction currently in execution.
2. The CPU issues an "acknowledge interrupt" signal and waits for the interrupting
device to send an interrupt number.
3. The CPU flag registers are placed on the stack (occupying two bytes of stack
storage).
4. Interrupts are disabled by clearing the IF flag.
S. Single stepping is disabled by clearing the TF flag.
6. The CPU activates the interrupt procedure corresponding to the interrupt number
sent by the interrupting device.
7. When that procedure terminates, the stack is automatically restored to the state
it was in when the interrupt was received, and control returns to the point where
it was interrupted.

The mechanism for this activation and restoration are described below.

G.2 The Interrupt Vector


If the NOINTVECTOR control is not used, an interrupt vector entry is automati-
cally generated by the compiler for each interrupt procedure. Collectively, the inter-
rupt vector entries form the interrupt vector. If NOINTVECTOR is used, the
programmer must supply the interrupt vector as explained in section 6-4.

The interrupt vector is an absolutely located array of POINTER values beginning at


location O. Thus the nth entry is at location 4*n and contains the location of a proce-
dure declared with the INTERRUPT n attribute.

G-I
Run-Time Interrupt Processing PLfM-86 User's Guide

Note that the first and second bytes of each entry contain an offset, while the second
two bytes contain a segment address. The entries are always four-byte pointers, and
the segment address is always used in transferring to the interrupt procedure, even if
the program size is SMALL.

The CPU uses the interrupt vector entry to make a long indirect call to activate the
appropriate procedure. At this point, the current code segment address (CS register
contents) and instruction offset {IP register contents) are placed on stack.

At the point where the procedure is activated, the stack layout is as shown in
figure G-l.

G.3 Interrupt Procedure Prologue and Epilogue


An interrupt procedure begins by declaring its name and nature. For example:

HANDLER: PROCEDURE INTERRUPT 4;


This alerts the compiler to create a code prologue appropriate to a routine that will,
in general, be invoked by interrupts.

At the beginning of each interrupt procedure, the interrupt procedure prologue inserted
by the compiler accomplishes the following:
1. Pushes the CPU registers to the stack in the following order-AX, ex, DX, BX,
(SP and BP on the iAPX 186 only), SI, and DI.
2. Pushes the ES register contents onto the stack.
3. Pushes the DS register contents onto the stack.
4. Loads the DS register with a new data segment address taken from the current
code segment (i.e., the segment containing the interrupt procedure).
5. Pushes the BP register contents onto the stack.
6. Loads the stack marker (BP register) with the address taken from the current
stack pointer (SP register).
7. If the procedure is REENTRANT, reserves space on the stack for any local
variables declared in the procedure.

However, if the procedure is REENTRANT and contains local variables, steps 5, 6,


and 7 will be replaced by the ENTER instruction (see the iAPX 86 Programmer's
Reference Manual).

HIGHER
FLAG REG. CONTENTS 2 BYTES

L:;A1TIONS RETURN SEGMENT SELECTOR PRESENT REGARDLESS OF

~~ ~----------------~
PROGRAM SIZE
1-;:)
en 8 RETURN OFFSET
~----------------~....-... STACK POINTER

LOWER
LOCATIONS

121945-5

Figure G-l. Stack Layout at Point Where an Interrupt Procedure Gains Control

0-2
PL/M-86 User's Guide Run-Time Interrupt Processing

NOTE
The compiler may make temporary use of the DS register in some cases
(e.g., string built-ins), but always restores it. Care must be taken when writing
your own interrupt procedure in assembly language to note this possibility.

After the interrupt procedure prologue is executed (at the point where the code
compiled from the procedure body gains control), the stack layout is as shown in
figure G-2.

The return from the procedure body is called the interrupt procedure epilogue; it
restores the stack to the state it was in before the interrupt occurred. The interrupt
procedure epilogue contains the following steps:

8. If stack locations were used for temporary storage or local variables, loads the
stack pointer (SP register) with the current stack marker (BP register). This
discards the temporary storage.
9. Pops the stack into the BP register, restoring the old stack marker.
10. Pops the stack into the OS register.
11. Pops the stack into the ES register.
12. Pops the stack into the CPU registers in the following order-OI, SI (BP on the
iAPX 186 only), BX, OX, CX, AX. Note that the SP register value is discarded
by the POP A instruction on the iAPX 186.
13. Executes an IRET instruction to return from the interrupt procedure. This restores
the IP, CS, and the flag register contents from the stack.

HIGHER
LOCATIONS
FLAG REG. CONTENTS
I ~BYTES

RETURN SEGMENT SELECTOR PRESENT REGARDLESS OF


(IN INTERRUPTED PROGRAM) } PROGRAM SIZE

RETURN OFFSET

AX REG. CONTENTS
CX REG. CONTENTS
OX REG. CONTENTS
BX REG. CONTENTS
186
1SP REG. CONTENTS
>- CPU STATUS INFORMATION
BP REG. CONTENTS
a:: SI REG. CONTENTS
w 01 REG. CONTENTS
I-
Z ES REG. CONTENTS
::J
o(.) OS REG. CONTENTS

:.::
~
(.)
<I:
'-- OLD STACK MARKER
l- . . . . . - NEW STACK MARKER (BP REG. CONTENTS)
V)

LOCAL VARIABLES

} ONLY IN REENTRANT PROCEDURE

THIS SPACE MAY BE


USED DURING PRO-
CEDURE EXECUTION STACK POINTER MAY CHANGE
DURING PROCEDURE EXECUTION
LOWER
LOCATIONS

121636-4

Figure G-2. Stack Layout During Execution of an Interrupt Procedure Body

G-3
Run-Time Interrupt Processing PL/M-86 User's Guide

If the procedure is REENTRANT and has local variables, steps 8 and 9 will be
replaced by the LEAVE instruction (see the iAPX 186 Programmer's Reference
Manual).

At this point, the stack has been restored to the state it was in before the interrupt
occurred, and processing continues normally.

G.4 Writing Interrupt Vectors Separately

In some cases it may be desirable to write the interrupt vector separately (in
PL/M-86 or assembly language). This can be done by using NOINTVECTOR to
prevent generation of an interrupt vector by the compiler. The separately created
interrupt vector can then be linked into the program.

Creation of a separate explicit interrupt vector requires some care. The @ operator
in PL/M-86 provides access to a procedlJre's normal (i.e., called) entry point, not to
its interrupt entry point. The interrupt entry point first saves the status of the inter-
rupted program before invoking the interrupt procedure through its normal entry
point. The exact length of these operations depends on the compilation options chosen,
the attributes of the interrupt procedure, and the version of the compiler being used.
The built-in function INTERRUPTSPTR can be used during execution to return the
actual interrupt entry point. Discussion of this function appears in Chapter 9.

The usefulness of a separate created interrupt vector can be seen by considering an


example.

Suppose that two modules for a multimodule program are developed separately. Both
use interrupt procedures, but at the time when the modules are written the assign-
ment of interrupt numbers to the various interrupt procedures has not been
determined.

The two modules are therefore compiled with the NOINTVECTOR control. When
this is done, the n in an INTERRUPT n attribute is ignored-since normally it would
only be used to put the procedure's entry in the proper location within the interrupt
vector.

Later, when the program is linked together, a separately created interrupt vector can
be linked in. Within this interrupt vector, the placement of the entry for a given
interrupt procedure determines which interrupt vector, the placement of the entry for
a given interrupt procedure determines which interrupt number will activate that
procedure.

G.S Exception Conditions in REAL Arithmetic

As indicated in section 10.4, six exception conditions apply to normal numeric


operations:
• Invalid operation
• Denormalized operand

0-4
PL/M-86 User's Guide RUD-Time mterrupt Processing

• Zero divide
• Overflow
• Underflow
• Precision

These exceptions are discussed in order below. In each case, only a few of the possible
causes are described because most are not likely to occur with PL/M-86 usage. If
you want to perform sophisticated numeric processing of extreme precision and flexi-
bility, see the iAPX 86,88 User's Manual.

The six exceptions and their default responses are summarized in table G-l.

As the following sections indicate, the masked, default response to most exceptions
will provide the least abrupt, most appropriate action for PL/M-86 applications. Many
real math exceptions that occur in other processors will not occur with the 8087
because of the extended range of intermediate results it holds. The "soft" recovery of
gradual underflow (described under the denormal exception), also extends the range
of permissible execution rather than reporting a hard-failure condition.

Programmers who use the recommended setting of the REAL Mode Word (see section
10.4 ) need to handle only the invalid exception. Study of the other exception
conditions is advised, however, to provide a general understanding of their use.

Table G-l. Exception and Response Summary

Exception Masked Response Unmasked Response

Invalid If one operand is NAN, return it; Request interrupt. (8087 stack
Operation if both are NANs, return NAN with unchanged.)
larger absolute value; if neither is
NAN, return indefinite NAN.
Zerodivide Return co signed with "exclusive Request interrupt. (8087 stack
or" of operand signs. unchanged.)
Denormalized Memory operand: proceed as Request interrupt. (8087 stack
usual. unchanged.)
Register operand: convert to valid
unnormal, then reevaluate for
exceptions.
Overflow Return properly signed 00. Register desti nation: adjust
exponent, * store result, request
interrupt.
Memory destination: request
interrupt.
Underflow Denormalize result. Register destination: adjust
exponent, * store result, request
interrupt.
Memory destination:; request
interrupt.
Precision Return rounded result. Return rounded result, request
interrupt.

* On overflow, 24,576 decimal is subtracted from the true result's expone~t; this forces·the exponent
back into range and permits a user exception handler to ascertain the true result from the adjusted
result that is returned. On underflow, the same constant is addedto the true result's exponent.

G-5
Run-Time mterrupt Processing PL/M-86 User's Guide

Invalid Operation Exception

This exception generally indicates a program error. It could be caused by referencing


an un initialized REAL variable or by referencing a location that does not contain a
REAL value (as might occur with an out-of-range SUbscript for a REAL array).
Attempting to take the square root of a negative number or to store a number too
large for integer format would also generate this exception.

Another interpretation of this exception is stack error. This may be caused by failing
to restore the math unit status before returning from an interrupt routine that had
saved the status. Another cause is the generation of more than 8 intermediate results
during REAL arithmetic, which can arise if REAL procedure function calls are nested
too deeply. The compiler ensures that no single procedure does this, but cannot check
what may occur only at run time. This exception can also occur when REAL functions
(typed procedures) are used as operands within longer REAL expressions.
For example:

DELTA$1 • ALPHA • (BETA/GAMMA) + CHI (PSI, RHO, PI)


where all these names are typed REAL and CHI is some previously declared REAL
function having three parameters.

The following is less likely to cause an exception condition:

EPS • CHI (PSI, RHO, PI)


DELTA$1 • ALPHA • (BETA/GAMMA) + EPS
because all REAL arithmetic is performed using the 8087 stack, which has eight
registers. The first seven REAL parameters supplied in procedure calls are placed on
this stack. If the procedure is typed (i.e., invoked as a function), it can be imbedded
as one operand within a longer REAL expression.

Since the evaluation of such an expression also involves the use of this stack for prior
and subsequent arithmetic operations, stack overflow may occur. This overflow
amounts to unpredictable destruction of original parameters or intermediate results.
It becomes more likely as you increase the complexity of REAL expressions contain-
ing REAL functions. Thus, you are safer using an assignment statement first to store
the function's value in a real variable-and using that variable in the larger
expression.

If stack error might apply to your program, modify the code for the affected proce-
dures to call the built-in procedures SA VE$REAL$ST ATUS and
RESTORE$REAL$ STATUS as their first and last operations, respectively.

The masked (default) response is to set the result to one of the special bit patterns
called Not-A-Number (NANs), usually the indefinite value, the smallest NAN
representable in the specified precision. It also sets Bit 0 of the REAL Error Byte.

If Bit 0 of the REAL Mode Word is 0 (invalid exception unmasked), an interrupt


occurs, transferring control to the user-written interrupt handler.

Denormal Operand Exception

This condition arises when numeric operations have resulted in a number whose
exponent is literally zero and whose significand is non-zero, or a number whose sign i-
ficand does not begin with a one. Denormals usually arise in response to masked
underflow. Gradual underflow is the masked, default response to underflow. A small

G-6
PL/M-86 User's Guide Run-Time Interrupt Processing

denormal added to a large normal REAL number can give an acceptable, in-range
answer if the denormal exception is masked. In practice, denormals are very rare
since intermediate results are kept in temporary real format (I5-bit exponent).

This condition causes Bit 1 of the REAL Error Byte to be set to 1. If Bit 1 of the
REAL Mode Word is 1, the response described above occurs; if Bit I is 0, an
interrupt occurs, transferring control to the user-written interrupt handler.

Zero Divide Exception

This condition arises when in the course of some REAL computation a divisor turns
out to be zero. The masked response, when Bit 2 of the REAL Mode Word is 1, is to
return infinity appropriately signed. If Bit 1 is 0, an interrupt occurs, giving control
to the user-written interrupt handler. In either case, Bit 2 of the REAL Error Byte
is set to 1.

Overflow Exception

This error occurs when a real result is too large for the format in use. For REAL
assignments, it occurs if the result is greater than about 3.37 X 1038 ; for intermediate
REAL computations, if the result is greater than about 104932 • The overflow exception
can arise during assignment, addition, subtraction, multiplication, division, or
conversion to integer.

The masked, default response (Bit 3 of REAL Mode Word = 1) is to return infinity
(signed if Affine Mode is set) and set Bit 3 of the REAL Error Byte to 1. Unmasked
overflow must go through a user-written interrupt handler.

Underflow Exception

Underflow exception is caused by an exponent too small for the format in use. For
REAL assignments, it occurs if the exponent is less than -127, and for intermediate
results if the exponent is less than -16383. Underflow can be caused by the same
type of REAL operations as overflow.

The masked, default response (Bit 4 of REAL Mode Word = 1) is to use the denor-
mal number created by adjusting the very small result. It adjusts the significand,
moving significant digits off to the right and raising the exponent until the latter
becomes non-zero. For example, a 24-bit significand of .01 with an exponent of zero
implies the number 1 X 2- 129 because a zero exponent in this format means -127. If
the denormal exception is masked, this would be adjusted into a significand of .001
with an exponent of 1, i.e., 0.001 x 2- 126, prior to operation. This number would then
be available for use in subsequent REAL operations that might yield valid results.
Zero is returned if it is the rounded result. Bit 4 of the REAL Error Byte is set to 1.
Unmasked underflow must go through a user-written interrupt handler.

Precision Exception

This error occurs when the result of an operation is inexact (i.e., rounded) or when"
an overflow exception occurs. No special action is performed by a masked response
(Bit 5 of REAL Mode Word = 1) other than setting Bit 5 of the REAL Error Byte.
Unmasked response is as chosen by the user.

G-7
Run-Time Interrupt Processing PLfM-86 User's Guide

G.6 Writing a Procedure to Handle REAL Interrupts


This section partially summarizes the information pertaining to interrupts, floating-
point usage, and procedures. (Additional facilities for handling REAL interrupts may
be provided by your operating system.)

An interrupt-handling procedure may, for example, begin as follows:

HANDLER: PROCEDURE INTERRUPT 16;


If HANDLER will do any REAL arithmetic or assignments, its first executable
statements should be of the form:

ERR. INFO = GET.REAL$ERROR; /1 must declare ERR.INFO. BYTE


earlier 1/

or:

CALL SAVE$REAL.STATUS (eLocal_Save_Area); /1 also declare


earlier 1/

Each procedure clears the error byte. The latter procedure also clears out the REAL
stack. Thus, after either procedure is used, the REAL Error Byte no longer contains
the flagged cause of the exception condition that invoked HANDLER.

Using SA VE$REAL$STATUS is a way of avoiding possible stack errors from


cumulative usage. This· permits errors in HANDLER to be detected independently
of the originating exception condition, and allows HANDLER to restore the state of
the interrupted procedure despite HANDLER's own use of the REAL facility.
SA VE$REAL$ST ATUS also makes available all the information as to the state of
the 8087 exceptions, stack, and operations, as shown below.

Thus, the beginning of a typical routine to handle REAL exception conditions could
look like this:

HANDLER: PROCEDURE INTERRUPT 16;


DECLARE ERR.INFO BYTE;
DECLARE LOCAL_SAVE_AREA (94) BYTE;
ERRSINFO • GET.REALSERROR;

G-8
PLjM-86 User's Guide Run-Time Interrupt Processing

or, if you want to perform extensive manipulations on the save area, you could declare
a structure permitting you access to its component parts by name and/or byte, as
follows:

HANDLER: PROCEDURE INTERRUPT 16;


DECLARE ERRSINFO BYTE;
DECLARE SAVE_AREA STRUCTURE
( CONTROL(2) BYTE,
STATUS(2) BYTE,
TAG WORD,
IHSTR_OFF WORD,
IHSTR_SEL SELECTOR,
OPERAND_OFF WORD,
OPERAND_SEL SELECTOR,
STACK_TOP(S) WORD,
STACK_ONE(S) WORD,
STACK_TWO(S) WORD,
STACK_3 (5) WORD,
STACK_4 (5) WORD,
STACK_S (5) WORD,
STACK_6 (5) WORD,
STACK_7 (S) WORD);
CALL SAVESREALSSTATUS (eSAVE_AREA);
ERRSINFO = SAVE_AREA.STATUS(O);
NOTE
To make use of the words from TAG through OPERAND_SEL, you must
employ masks and shifts to access the individual fields shown in figure G-3.

You must call either the SA VE$REAL$STA TUS procedure or the


GET$REAL$ERROR function, but not both. If you do not need the extra informa-
tion gained by the SAVE (i.e., if you need only the exceptions), use the
GET$REAL$ERROR function. If you call both, the second call will produce
incorrect results.

The rest of HANDLER can perform any actions deemed appropriate. This is an
application-dependent decision. Among the possibilities:
• Incrementing an exception counter for later display
• Printing diagnostic data, e.g., the contents of SAVE-AREA
• Aborting further execution of the calculation causing exception
• Aborting all further execution

The format of the LOCAL_SAVE-AREA as it is filled by the save procedure is


shown in figure G-3.

The final action prior to returning (if desired) to the interrupted procedure is to restore
the status of the REAL math unit:

CALL RESTORESREALSSTATUS (ILOCAL_SAVE_AREA);

However, if you did not use GET$REAL$ERROR prior to the


SAVE$REAL$STATUS call, the local save area will contain the original contents
of the error byte. Under these circumstances, you must first clear the lower byte of
the saved status word before the above RESTORE so as to avoid retriggering the
save exception that invoked HANDLER in the beginning.

G-9
Run-Time Interrupt Processing PLJM-86 User's Guide

INCREASING ADDRESSES

15

CONTROL WORD ~l
;..---.t::
STATUS WORD

TAG WORD +4

INSTRUCTION
POINTER
{ IP 15-0

IP 32-16
+6

+8

OPERAND
POINTER
{ OP 15-0

OP 32-16
+10

+ 12
SIGNIFICAND 15-0 + 14
SIGNIFICAND 31-16 +16

TOP STACK
ELEMENT:ST -< SIGNIFICAND 47-32 -t 18

SIGNIFICAND 63-48 +20


-'-
sl EXPONENT 14-0 +22

SlGNIFICAND 15-0 +24

SIGNIFICAND 31-16 +26


NEXT STACK
-< SIGNIFICAND 47-32 +28
ELEMENT:ST(1)

sl•
SIGNIFICAND 63-48 +30

EXPONENT 14-0 -+-32

~~ ~ :::
SIGNIFICAND 15-0 +84

SIGNIFICAND 31-16 +86

LAST STACK
ELEMENT:ST(7) ~ SIGNIFICAND 47-32 +88

. SIGNIFICAND 63-48 +90

sl EXPONENT 14-0 +92

NOTES:
S = Sign
BIT 0 OF EACH FIELD IS RIGHTMOST, LEAST SIGNIFICANT BIT OF CORRESPONDING
REGISTER FIELD.
BIT 63 OF SIGNIFICAND IS INTEGER BIT (ASSUMED BINARY POINT IS IMMEDIATELY
TO THE RIGHT).

Figure G-3. Memory Layout of REAL SAVE AREA 121945-9

To do so, you can use a command of the form:

0; '* should precede


restore *'
or:

SAVE_AREA.STATUS (0) 0;

G-IO
APPENDIX H
COMPILER INVOCATION AND ADDITIONAL
INFORMATION FOR SERIES III USERS

This appendix contains information that is specific to the Intellec Series III Micro-
computer Development System. It covers the following areas:
• Compiler invocation and file usage
• Examples of system-dependent compiler controls
• Related publications

H.1 Compiler Invocation


The PL/M-86 compiler is a program that translates your PL/M instructions into
object code modules that can be linked with the iAPX 86 Linker and executed.

This compiler runs under ISIS V4.1 with RUN V1.2, ISIS V4.2 with RUN V1.3, or
later versions of both products.

You create a PL/M program by using the CREDIT text editor to type instructions
into a file, and then submitting the file to the PL/M-86 compiler. The file you submit
is called a source file, and the file containing the compiled program is called an object
file. (The content of the object file is also known as object code.) In
PL/M-86, you can compile parts of a program. Each separate compilation is known
as an object module.

The following discussion assumes that you have a Series III system up and running,
and that you have a suitable copy of the PL/M-86 compiler. Details on the
operating system environment are provided in the Intellec Series III Microcomputer
Development System Console Operating Instructions.

The invocation command has the general form:

R U H [: F d: 1 P L M8 6 [: F d: ] source [controls] (c r )

where
RUN is the name of the command used to execute the compiler.
:Fd: specifies on which drive, if not drive 0, the PL/M-86 compi-
ler and/or source program resides. (The source file does not
have to be on the same drive as the compiler.)
PLM86 is the name you use for the compiler PLM86.86.
source is the name of the source file containing the PL/M-86
program.
controls are optional compiler controls -described in Chapter II. You
can have many controls on the invocation line· if you use a
space between each control, and you can extend the invoca-
tion line by using the ampersand (&) as a continuation
character.
<cr) stands for use of the RETURN key on the keyboard.

Examples:

-R..,f-.! P_tr186 :~1:MY~2=3,5~: ;::~::--,-(:_;:::) -:-_:('-:5-


PR::;C,RAj"'I 4 ' ) (cr)

H-l
Compiler Invocation and Additional Information for Series III Users PL/M-86 User's Guide

In this example, the compiler is on drive 0, but MYPROG.SRC, the source program,
is on drive 1. The compiler will direct all printed output to :LP:, and place 'TEST
PROGRAM 4' in the header on each page of the listing.

In this example, both the compiler and the source program (PROG1.SRC) are on
drive 1. NOPRINT will prohibit all printed output (except error messages) usually
generated by the compiler.

H.2 File Usage

Input Files

The compiler reads the PL fM -86 source from the source file specified on the command
line (see previous section) and also from any files specified with INCLUDE controls
(as described in Chapter 11). These files must be standard ISIS-II disk files. The
source input should contain a PLfM-86 source module.

Output Files

Two output files are produced during each compilation unless specific controls are
used to suppress them. The output files are the listing and object code files. Each of
these may be explicitly directed to some standard Series II pathname (device or file)
by using the PRINT and OBJECT controls, respectively. If the user does not control
these outputs explicitly, the compiler writes them to disk files on the disk containing
the input file. These files then have the same file name as the input file but have the
extensions LST for the listing and OBJ for the object code. For example, if the
compiler is invoked by:

the listing and all other printed output is written to :Fl :MYPROG.LST and the object
code to :Fl:MYPROG.OBJ. If these files already exist, they are overwritten. If they
do not exist, the compiler creates them.

The object code file may be used as input to the ISIS-II linkage facilities. (See the
iAPX 86 Utilities User's Guide).

Compiler Work Files

The work files used by the compiler during its operation are deleted at the end of
compilation. All of these files are on the device: WORK:.

All of the work files have names with the extension TMP. Therefore, you should
avoid naming files with the extension TMP on any device used by the compiler for
work files-the operation of the compiler may destroy them.

H.3 Linking to Floating-Point Libraries with the Series III


Suppose you write a PLfM-86 program called Easy that, at first, uses no REAL
math. As modules are added, you supply a PLfM-86 REAL math routine called
ACURAT, and revise EASY to call it. At this point you would need to add an
interface library for floating-point math.

H-2
PL/M-36 User's Guide Compiler Invocation and Additional Information for Series III Users

If you do not have a 8087 chip installed in your system, the correct linking statement
is:

LIHKS6 ACURAT.DBJ, EASY.DBJ, ESOS7.LIB, PESOS7


However, if ACURAT were written in another language (e.g., FORTRAN86 or
ASM86), use instead:

LIHKS6 ACURAT.DBJ, EASY.DBJ, ESOS7.LIB, ESOS7


If your system includes a 8087 chip, use:

LIHKS6 ACURAT.OBJ, EASY.DBJ, SOS7.LIB


More detailed and advanced discussions of the features and functions of the iAPX
86 utilities appear in the iAPX 86, 88 Family Utilities User's Guide.

H.4 Series III-Specific Compiler Controls


This appendix includes a fold-out page for the system-specific examples of many of
the compiler controls. This page is designed to be opened and used in conjunction
with the corresponding text in Chapter 11.

H.S Related Publications


Below is a list of other Intel publications you might need along with this manual. The
manual order number for each publication is given immediately following the title.
The paragraph below each title describes the book.

Itellec Series III Product Overview, 121575

A summary description of the set of manuals that describe the Intellec Series III
development system and its supporting hardware and software. This short manual
includes a description of each manual related to the Series III, plus a glossary of
terms used in the manuals.

Intellec Series III Console Operating Instructions, 121609


Intellec Series III Pocket Reference, 121610

Instructions for using the console features of the Series III, including the resident
monitor. The Conssole Operating Instructions provides complete instructions, and
the Pocket Reference gives a summary of this information.

Intellec Series III Programmer Reference Manual, 121618

Instructions for calling system routines from user programs for both microprocessor
environments (8080/8085 and 8086) in the Series III.

ISIS-II CREDIT 9CRT-Based Text Editor) User's Guide, 9800902


ISIS-II CREDIT (CRT-Based Text Editor) Pocket Reference, 9800903

Instructions for using CREDIT, the CRT-based text editor supplied with the Series
III. The User's Guide provi,des complete operating instructions, and the Pocket
Reference summarizes this information for quick reference.

iAPX 86,88 Family Utilities User's Guide, 121616

H-3
Compiler Invocation and Additional Information for Series m Users PL/M-86 User's Guide

Instructions for using the utility programs LINK86, LIB86, LOC 86, CREF86, and
OH86 in iAPX 86-based environments to prepare compiled or or assembled programs
for execution.

8086/8087/8088 Macro Assembly Language Reference Manual for 8086-Based


Development Systems, 121627
8086/8087/8088 Macro Assembly Operating Instructions for 8086-Based
Development Systems, 121628
8086/8087/8088 Macro Assembly Language Pocket Reference, 121674
Instructions for using the 8086/8087 /8088 macro assembly language and its assem-
bler in iAPX 86-based environments. The Language Reference Manual gives a
complete description of the assembly language the Operating Instructions gives
complete instructions for operating the assembler and the Pocket Reference provides
summary information for quick reference. You need these publications if you are
coding some of your routines in assembly language.

ICE-86 In-Circuit Emulator Operating Instructions for ISIS-II Users, 9800714


ICE -86 Pocket Reference, 9800838
ICE-88 In-Circuit Emulator Operating Instructions for ISIS-II Users, 9800949
ICE-88 Pocket Reference, 9800950

Instructions for using the ICE-86 and ICE-88 In-Circuit Emulators for hardware and
software development. The Operating Instructions manuals give complete user
descriptions of the In-Circuit Emulators, and the Pocket Reference guides provide
summary information for quick reference. You need the corresponding publications
if you are using the ICE-86 or ICE-88 emulator.

H-4
PL/M-86 User's Guide Compiler Invocation and Additional Information for Series III Users

COMMENTS CONTROL EXAMPLES


Causes a listing of standard assembly language code CODE/NOCODE
to be placed at the end of file PROG1.LST on drive 5.

Causes file TEST6.0BJ (on drive 1) to include informa- DEBUG/NODEBUG RwN PLI'r186 :'1:iES-6,SRC DB (cr)
tion that will later be used to debug the program using
a symbolic debugger.

Causes source lines from file SYSLlB.SRC (on drive 1) INCLUDE RJN D~'18o 5'SPR=',SR~ &
to be placed in file SYSPRG.SRC (on drive 0). :N~~I"!J~(:rl :S'lSL:B,5R2) (cr)

Sends file PROG1.0BJ to the disk in drive 1 instead of OBJECT INOOBJECT RlN Cl_~85 :JR~0',SR= &
drive 0 (the default location). =B~:=-(::-':PRO:",=3J) <:r>

Directs the compiler to perform more than the default OPTIMIZE


code optimizations when generating the object code for
file SAMPLE.OBJ on drive 4.

Prints file TSTLlB.LST with a pagewidth of 70. PAGEWIDTH RUN P~1'r18o TST,-!B,SRC PIH70) (cr)

Sends printed output to the line printer. PRINT I NOPRINT

Causes the subtitle 'Module One' to appear on every SUBTITLE RLN ;::L~8o :='::N:-i,SRC &
page until another subtitle control (if any) appears in SvE-:i~~(\Y=:::J~: =!-,E') (C"J
INIT1.SRC on drive 1.

Causes a listing of all identifiers in file TSTOBJ.SRC, SYMBOLS/NOSYMBOLS


and their attributes, to appear in file TSTOBJ.LST.

Causes the title 'TEST PROGRAM 5' to appear on every TITLE R\.~ ~_~8c ::~=~~.J~= ~
page. ...:..-_~(\.,.-t:s~ ::;;:3RH Y 5') <c,..}

Prevents the type definitions of the variables output in TYPE/NOTYPE


symbols records from appearing in file MOD2.0BJ.

Produces a cross-reference listing of all identifiers in file XREF/NOXREF


MYPROG.SRC and appends the listing to default listing
file MYPROG.LST.

H-5/H-6
APPENDIX I
COMPLERINVOCATION AND ADDITIONAL
INFORMATION FOR iRMX™ 86 USERS

This appendix contains information that is specific to the iRMX 86 Operating System.
It covers the following areas:
• System requirements
• Compiler invocation and file usage
• Examples of system-dependent floating-point library linkage
• Examples of system-dependent compiler controls
• Related pUblications

I. 1 System Requirements
To run the compiler on an iRMX 86-based system, you must have the following
hardware and software:
• The iRMX 86 Human Interface (and other iRMX 86 layers necessary to support
the Human Interface).
• At least one mass storage device. The installation of the compiler always requires
a single- or double-density diskette drive, since the product is delivered in diskette
form.
• Enough memory to run the compiler (above and beyond that required for the
Operating System). This ranges from
minimum - 140K - Amount needed to run compiler assuming connection to only
six files
maximum - 512K - Largest amount the compiler can use.

1.2 Compiler Invocation


The compiler is supplied on an iRMX 86-format diskette. It may be desirable to copy
the compiler to another disk or to one of the directories that the Operating System
automatically searches when commands are entered. The compiler consists of a single
file: PLM86.

You can invoke the PL/M-86 Compiler from the system console using the standard
command format described in the iRMX 86 Human Interface Reference Manual.
You can specify continuation lines by using the ampersand (&) as a continuation
character. The ampersand can appear any place there is a space or other delimiter.

The invocation command has the general form

- [ directory] P L M8 6 sourcepath [ controls] (c r )

where
directory is the portion of the pathname that identifies the device and
directories that contain the file PLM86. If you omit the
directory portion of the pathname, the Operating Systetn
automatically searches several directories for the file PLM86.
The directories searched and the order of search are
iRMX 86 configuration parameters.

1-1
Compiler Invocation aDd Additional Information for iRMX 86 Users PLfM-86 User's Guide

sourcepath is the pathname of the file containing the PLM86 source


module. The beginning portion of this pathname can consist
of a logical name enclosed in colons (such as :Fl:). This
indicates where the Operating System starts its search for
the file. If you omit the logical name, the Operating System
assumes that the file resides in the default directory (:$:).
You can use the slashes (f) and up-arrows or circumflexes
( ) as separators between individual components of the
pathname (except immediately after the logical name). The
slash separator tells the Operating System to search down
one level in the directory tree for the next component. The
circumflex separator tells the Operating System to search up
one level in the directory tree.
controls is an optional sequ'tnce of assembler controls (see
Chapter 11).
<cr> indicates a carriage return.

In the interactive sequence shown in figure I-I, comments appearing to the right of
semicolons are for clarification, not material entered by the user. This example shows
how to compile a complete program that does not require more than 64K bytes of
storage for the code or more than 64K bytes for the data.

In the normal usage, the PLfM-86 compiler writes the compilation listing by default
to a secondary storage file on the same device as the source file. This file has the
same pathname as the source file, but the last component of the pathname has the
extension LST. Thus, in the previous example, you can find the- listing in
:PROG:MYPROG.LST. Similarly, the object code file is' on the same device and has
the same pathname, but has the extension OBJ. In the example,
:PROG:MYPROG.OBJ contains the object code produced by compiling
:PROG:MYPROG.SRC.

Examples
1.
In this example, the compiler resides in a directory that the Operating System
automatically searches; thus it does not require a device or directory name. The
compiler is directed to compile the source module on :FI:PROGl.SOURCE. This
file resides on the device with logical name : F 1: and has the name
PROG.SOURCE.
2.
In this example, the compiler resides on device :FDO:. The compiler is directed
to compile the source module on :WDO:DIRI fMYPROG.SRC, send the output
listing to :LP:, and place 'TEST PROGRAM 4' in the header on each page of
the listing.

iRMX 86 HI V2.1 : user • WORLD the system identifies itself

-PLM86 :PROG:MVPROG.SRC the compiler is invoked

iRMX 86 PL/M-86 COMPILER V2.1


PL/M-86 COMPILATION COMPLETE. o WARNINGS, o ERRORS

; the program may now be linked and relocated


Figure 1-1. iJlMX 86 Interactive Compllation Sequence

1-2
PL/M-86 User's Guide Compiler Invocation and Additional Information for iRMX 86 Users

1.3 File Usage


Input Files

The compiler reads the PL/M-86 source from the source path file specified on the
command line (see previous section) and also from any files specified with INCLUDE
controls (as described in Chapter II). These files must he standard iRMX 86 files.
The source input should contain a PL/M-86 source module.

Output Files

Two output files are produced during each compilation unless specific controls are
used to suppress them. These are the listing and object code files. Each of these may
be explicitly directed to some iRMX 86 file or device by using the PRINT and
OBJECT controls respectively. If the user does not control these outputs explicitly,
the compiler writes them to secondary storage files on the device containing the input
file. These files have the same pathname as the input file, but have the extensions
LST (for the listing) and OBJ (for the object code). For example, you invoke the
compiler with

The compiler writes the listing and all other printed output to :FI :MYPROG.LST
and the object code to :FI:MYPROG.OBJ. If these files already exist, the compiler
overwrites them.

The object code file may be used as input to the relocation and linkage facilities (see
the iAPX 86,88 Family Utilities User's GUide).

Compiler Work Files

The compiler uses work files during its operation that are deleted at the completion
of compilation. All of these files are in the directory with logical name :WORK:
unless the WORKFILES control is used to specify another directory.

All of the work files have names with the extension TMP. Therefore, if you place
those files in the work files directory, you should avoid giving your files names with
the extension TMP, because there is a possibility that the compiler will destroy them.

1.4 Linking to Floating-Point Libraries with the


iRMX 86 Operating System
Suppose you write a PL/M-86 program called EASY that, at first, uses no REAL
math at all. No interface library is needed. As modules are added during the devel-
opment process, you supply a PL/M-86 REAL math routine call ACURAT, and you
revise EASY to call it.

In order to use the REAL math facility on the iRMX 86 Operating System, you
must have an 8087 Numeric Processor Extension installed on your iRMX 86 system.
In such a case, the correct linking statement is

More detailed and advanced discussions of the features and functions of the
iAPX 86 utilities appear in the iAPX 86,88 Family Utilities User's Guide.

1-3
Compiler layocatioo aad AdditionallnformatioD for iRMX86 Users PL/M-86 User's Guide

1.5 IRMX 86 - Specific CompHer Controls


This appendix includes a fold-out page for the system-specific examples of several
compiler controls. This page is designed to be opened out and used in conjunction
with the corresponding text in Chapter 11.

1.6 Related Publications


This section lists other Intel publications you might need in addition to this one. The
manual order number for each publication immediately follow the title. The paragraph
following each title describes the manual.

Introduction to the iRMX 86 Operating System, 9803124

A general introduction to the iRMX 86 Operating System. This manual discusses the
features of the Operating System and introduces some of the terminology. It also lists
and describes each of the manuals in the iRMX 86 manual set.

iRMX 86 Human Interface Reference Manual, 9803202


iRMX 86 Disk Verification Utility Reference Manual, 144133

Instructions for entering commands at an iRMX 86 terminal. The Human Interface


manual describes file-naming conventions and provides a complete description of all
commands available with the Operating System. The Disk Verification Utility manual
describes an interactive utility that examines and restores iRMX 86 volumes.

iRMX 86 Nucleus Reference Manual, 9803122


iRMX 86 Basic I/O System Reference Manual, 9803123
iRMX 86 Extended I/O System Reference Manual, 143308
iRMX 86 Loader Reference Manual, 143318
iRMX 86 System Programmers Reference Manual,142721
Run-Time Support Manualfor iAPX 86,88 Applications, 121776

Instructions for invoking system calls from user programs.

iRMX 86 Programming Techniques, 142982


Guide to Writing Device Drivers for the iRMX 86 and iRMX 88 I/O Systems,
142926

Additional information about the Operating System that PL/M-86 users might
require.

EDIT Reference Manual, 143587

Instructions for using EDIT, the text editor available for use on the iRMX 86
Operating System.

iAPX 86,88 Family Utilities Users Guide, 121616

Instructions for using the utility programs LINK86, LIB86, LOC86, CREF86, and
OH86 in iAPX 86-based environments to prepare compiled or assembled programs
for execution.

ASM86 Assembly Language Reference Manual, 121627


ASM86 Macro Assembler Operating Instructions for 8086-Based Development
Systems, 121628

1-4
PL/M-86 User's Guide Compiler Invocation and Additional Information for iRMX 86 Users

Instructions for using the 8086/8087/8088 macro assembly language and its assem-
bler in iAPX 86-based environments. The Language Reference Manual gives a
complete description of the assembly language. The Operating Instructions Manual
gives complete instructions for operating the assembler. You need these publications
if you are coding some of your routines in assembly language.

8087 Support Library Reference Manual, 121725

Instructions for calling procedures that implement the REAL math facility of the
808 7 Numeric Processor Extension.

1-5
PL/M-86 User's Guide Compiler Invocation and Additional Information for iRMX 86 Users

COMMENTS CONTROL EXAMPLES

Causes object code to be written to file :PROG:TESTS/ OBJECT OBJECT(:PROG:TESTS/A.SDURSE)


A.SOURCE

Causes printed output to be directed to the line printer PRINT PRINTC:LP:)

Causes input of source lines from file :WDO:INCLUDE/ INCLUDE INCLUDE(:WDD: INCLUDE/SYSLIB.SRC)
SYSLlB.SRC

1-7/1-8
INDEX

8087.LIB, Appendix F block, 1-2, 1-3, 3-4


ABS, 9-4, 9-7 kinds, 1-2
actual parameters, 8-2 thru 8-5 levels, 1-4, 1-5
addition, 3-10, 4-1,4-3 names, 1-4
addresses nesting, 7-1 thru 7-5
physical,7-5 structure, 1-3, Chapter 7
relative, 11-17 BLOCKINPUT, 10-5
relocation, 1-5 BLOCKINWORD,10-5
unique, 3-2 BLOCKOUTPUT, 10-5
affine, see infinity BLOCKOUTWORD,10-5
ambiguity BNF, Appendix C
in embedded assignments, 4-14 BOOLEAN expressions
in location references, 5-5 see logical, short-circuit
of address/location, 7-4 BUILD$PTR, 9-16
AND, 4-5 thru 4-8, 6-8, 11-32 built-in
apostrophe, 2-2, 2-5 arrays, 10-5
arithmetic, 3-10 thru 3-12 functions, 9-1 thru 9-11, 9-14 thru 9-16, 10-4
floating-point, 3-11, 3-12, Chapter 10, Appendix G REAL, 10-9 thru 10-11
modulo, 4-4, 6-6 procedures, 1-4,9-9 thru 9-13, 10-5
operators, 4-3, 4-4, 4-6 REAL, 10-8 thru 10-10
signed, 3-11 variables, 1-4, 10-3, 10-4, 10-6, 10-8, 10-9
summary of rules, 4-10 thru 4-12 By, see DO, iterative
unsigned, 3-10 BYTE, 3-1, 3-10,4-1 thru 4-14
array, 3-2, 5-1 thru 5-5
contiguity, 5-1
declaration, 3-2, 5-1, 5-3
elements, 5-1,9-1, 9-2 CALL, 4-12,6-2,6-12, 8-1, 8-4 thru 8-6, 8-9
initialization, 3-4 thru 3-6 calling sequence, Appendix F
number of bytes, 9-1, 9-2 carriage return, 2-1, 2-5
number of elements, 5-1,9-1, 9-2 CARRY, 10-2, 10-3
reference, 3-13 CASE,seeDO
storage of, 5-1 CAUSE$INTERRUPT, 8-10, 10-1
structures, 5-3, 5-4, Chapter 12 character
subscripts, 5-1, 5-2 set, 2-1
ascending strings, see string
order in string moves, 9-9 thru 9-13 closed subsystems, 13-3
ASCII, 2-1, 2-5, 3-5, 4-2, 6-10, 11-24, Appendix E CMPB,9-1O
assembly language linkage, Appendix F CMPW, 9-10
assignment CODE control, 11-24, 11-25, Appendix F
embedded, 3-1,4-9,4-14,4-15 code
floating-point, 3-11, 3-12, Appendix G section, 11-6, 11-8 thru 11-22
statement, 1-4,3-4,4-12 thru 4-15, 5-2, 6-7 space efficiency, 11-9
asterisk, 2-1, 2-5, 3-6, 4-3 colon, 2-1, 2-2
@ operator, 2-1, 3-5, 3-13 thru 3-15, 8-3, 9-14 comma, 2-1, 3-3, 3-4
AT, 3-1, 3-4, 3-7,3-13,3-17 thru 3-19, 7-5 comment, 2-1,2-5
attributes, 3-1, 3-4, 5-2 communicating values, 1-5
affecting section, 11-30 see also parameters
initialization, 3-1, 3-4, 3-5 COMPACT control, 11-20, 11-21
linkage, 3-1, 3-4 thru 3-7, 8-7, 8-8 restrictions, 11-20, 11-21
location, 3-1 compilation
constant, 3-1, 3-7, 3-8
steps, 11-1
BASED, 3-15 thru 3-17, 8-2, 8-7 summary, 11-31
based, 3-4, 3-13, 3-15 thru 3-17, 5-2, 7-5,8-2,8-3,8-7,11-8 compiler controls, Chapter 11
binary compiler files, Appendix H, Appendix I
number, see constant input, Appendix H, Appendix I
point, 3-12 output, Appendix H, Appendix I
scientific notation, 3-12 work, Appendix H, Appendix I
blank, 2-1, 2-3, 6-3 compiler invocation, Appendix H, Appendix I

Index-l
Index PL/M-86 User's Guide

complement delay, 9-13


ones, 4-5 delimiters, 2-2, 2-5
twos, 3-11 denormal, Appendix G
compound descending
delimiter, 2-2 order in string moves, 9-9 thru 9-13
operands, 4-2, 4-3, 4-7 destination
COND control, 11-36, 11-37 location in string moves, 9-10 thru 9-13
conditional dimension specifier, 5-1, 8-2, 8-7
execution 6-7 thru 6-11 implicit, 3-6
compilation, 11-33 thru 11-37 DISABLE, 10-1
constant, 2-3 thru 2-5, 3-4 thru 3-8 division, 3-10, 4-1 thru 4-4
character, 2-5 DO
compilation, 3-1 as unit, 6-2, 6-4, 6-8
execution, 3-1, 3-6 block, 1-2, 1-3, 6-4, 6-8
expression, 3-4, 4-13, 4-14, 6-3 CASE, 6-1, 6-3, 6-4
list, 3-14 iterative, 6-1, 6-5 thru 6-7
numeric, 4-1 simple, 6-1 thru 6-3
binary, 2-3, 2-4 WHILE, 6-1, 6-4, 6-5
decimal, 2-3, 2-4 exit, 6-2
floating-point, 2-4 labeled, 6-3
hexadecimal, 2-3, 2-4 loop, 6-1
octal, 2-3, 2-4 nested, 6-3, 7-1 thru 7-4
real,2-4 statement, 1-3
string, 2-5 dollar sign, 2-2, 11-1
whole-number, 2-3,2-4 dot operator, 2-1, 3-5, 3-15, 3-17
type, 2-4 DOUBLE,9-4
constraints, Appendix B DS register, 11-18 thru 11-22
context, signed or unsigned, 4-1, 4-10 thru 4-14 DWORD, 3-10, 4-1,4-3,4-10 thru 4-14
contiguity, 3-2, 5-1, 8-2
of storage, 3-3, 5-1, 5-2
control line, 11-1 E8087, Appendix F
controls, Chapter 11 E8087.LIB, Appendix F
list, 11-2 EJECT control, 11-27
conversion element
explicit, 9-3 thru 9-7 in declarations, 3-1, 3-3,8-2
implicit,4-13, 8-5 in initializations, 3-4
count, 9-6 thru 9-11 in string moves, 9-9
counter, 6-1 of expression, 1-4
cross-reference listing, 11-28, 11-30 elimination of
CS register, 11-18 thru 11-22 common subexpressions, 11-5
superfluous branches, 11-5
ELSE part, 6-9
see IF statement or control
DATA, 3-1, 3-4 thru 3-7, 7-5 embedded assignment, 4-9,4-14,4-15
data section, 11-6, 11-18 thru 11-22 possible ambiguity, 4-15
DEBUG control, 11-17 ENABLE, 10-1
DEC, 10-3 END, 1-3,3-9,6-1, 8-1, 8-5
decimal adjust, 10-3 entry point, 3-13, 8-5, 8-9, Appendix F, Appendix G
decimal point, 2-1, 2-4, 4-1 equal sign, 2-1, 2-2, 11-28
DECLARE, 1-3,3-1 errors, 2-1, 3-4, 5-4, 7-5, 11-30, Chapter 14
combining, 3-3 REAL, handling, 10-9, Appendix G
elements, 3-8, 3-9 evaluation order, 4-6, 4-9
declarations, 1-3,3-1 thru 3-9 exception conditions for REALs, 10-8, 10-9, Appendix G
elements, 3-8, 3-9 exception handling procedure, Appendix G
factored, 3-2 executable statement, 1-4, 2-1, 2-8, 6-2, 8-1
local,7-3 execution
multiple, 1-3, 3-1, 7-3 constant names, 3-1
procedure, 3-9 faster, 11-9
variable, 3-1 suspending, 8-10
results, 3-3 exclusive extent, 7-1 thru 7-3
default explicit
control word setting, Appendix G label declaration, 3-8
recovery, Appendix G type conversion, 9-3 thru 9-7
defIning exponent of REAL number, 3-11, 3-12
declaration, 7-5, 8-7, 8-8 EXPORTS list, 13-4

Index-2
PL/M-86 User's Guide Index

expression, 14, 3-2, 4-1 thru 4-15, 8-4 IF statement, 4-5, 4-11, 6-3, 6-7, 6-8
analysis, 4-6 thru 4-9 enclosing DO blocks, 6-8 thru 6-10
constant, 4-10 thru 4-14 nested, 6-8 thru 6-10
evaluation order, 4-9 implicit
floating-point, 3-11, 3-12 dimension specifier, 3-6
REAL, 3-11, 3-12 label declaration, 3-8
restricted, 3-4 type conversion, 4-13, 8-5
subscript, 5-2 INCLUDE control, 11-2, 11-32, 13-6, Appendix H,
summary of rules, 4-9 thru 4-14 Appendix I
extended scope, 7-4, 7-5, 8-7, 8-8 inclusive extent, 7-1 thru 7-3
extended segmentation controls, Chapter 13 index
extent, inclusive or exclusive, 7-1 thm 7-3 in string moves, 9-9
EXTERNAL, 3-1, 3-6 thm 3-9, 6-11, 7-4 thru 7-7, 8-7, variable, 5-2, 6-6
8-8, 11-23 see also DO, iterative
infinity control, Appendix G
factored declaration, 3-3 INIT$REAL$MATH$UNIT, 10-8
false, 3-11,4-5, 4-6,6-4,6-7 INITIAL, 3-1, 3-4 thru 3-7, 3-13, 7-5, 11-23
far references to procedures, Appendix F initializations, 3-4 thru 3-7
fatal errors, 14-20 multiple, 3-4
fields of a REAL number, 3-11 of REAL math facility, 10-6
file usage, Appendix H, Appendix I string constant, 2-5
FINDB,9-11 INPUT, 1-5, 10-4, 10-5
FINDRB, 9-11 inner level, 6-11
FINDRW, 9-11 see outer
FINDW,9-11 input/output, 1-5, 10-4, 10-5
FIX, 9-3, 9-5 ports, 1-5
FLAGS, 10-3 insertion sort example, Chapter 12
FLOAT, 9-3,9-5 INT, 9-3, 9-5
floating-point linkage, Appendix F INTEGER, 3-11,4-1 thru 4-4
floating-point number, 3-11, 3-12 least significant bits, 3-11
format in memory, 3-11 interface list, 13-4
flow control statements, 6-1 thru 6-12 intermediate results, 10-6, Appendix G
folding of constant expressions, 11-5 internal REAL format, 3-11
formal parameters, 8-2 thru 8-7 INTERRUPT attribute, 8-7 thru 8-9
fraction of REAL number, 3-11 interrupt
function, 8-4 attribute, 8-7
REAL,10-15 enabled or disabled, 8-8, 8-9, Appendix G
references, 4-2,4-9,4-12, 8-1 thru 8-5 emulator usage, Appendix F
see also built-in entry point, Appendix G
epilogue, Appendix G
gates, Appendix G
genera.l controls, 11-1 masking, Appendix F, Appendix G
GET$REAL$ERROR, 10-8, 10-9, Appendix G mechanism, 8-9, Appendix G
GOTO, 3-9, 6-2,6-11, 7-6 thru 7-9, 8-5, 8-9 prologue, Appendix G
gradual underflow, Appendix G procedures, 8-8 thru 8-10, Appendix G
grammar of PL/M-86, Appendix C REAL, 10-6, Appendix G
greater than, see relational signal, 8-8, 8-9
software, 9-13
HALT,10-1 vectors, 8-8, 11-4, Appendix G
hardware interrupt request, 10-6
features, Chapter 10 INTVECTOR control, 11-4
flags, 10-1 thru 10-3 invalid operation, Appendix G
registers, 10-3, 10-4 invocation
HIGH, 4-3, 9-4 line, Appendix H, Appendix I
high-level languages, 1-1, 1-2 of procedure, 1-3
HLT,10-1 INWORD, 1-5, 10-4, 10-5
iRMX, Appendix I

lABS, 9-4, 9-7


identifier, 1-4,3-2,5-1,5-2 LABEL, 3-1, 3-8
definition, 2-3 label, 3-8, 6-2
examples, 2-3 as target of GOTO, 6-11
listing, 11-28 declaration, 3-8, 3-9, 7-1
predeclared, Appendix A results, 3-9
IF control, 11-33 definition, 3-1, 3-8, 3-9, 8-2

Index-3
Index PL/M-86 User's Guide

generated, 11-28 member


scope, 7-6 thru 7-9 reference, 5-4, 5-5, 8-2
LARGE, 11-22, 11-23 structure, 5-2 thru 5-5
restrictions, 11-23 MEMORY, 1-1,9-14
LAST, 5-5, 9-2 memory
LEFfMARGIN,II-2 concepts, 13-1
left-to-right,4-6 thru 4-9 free, 9-14
LENGTH, 5-5, 9-1 shared, 9-14
length MINUS, 10-2
in string moves, 9-9 minus sign, 4-3, 4-4, 4-6
less than, see relational MOD, operator, 1-4,4-3,4-4,4-6
letters MOD86/MODI86
upper and lower case, 2-1 control, 11-2, 11-3
level models of segmentation, 11-18 thru 11-22, Chapter 13
block, 7-1 thru 7-4 modular programming, 6-1
module, 3-7 advantages, 7-1, 8-1
outer, 1-3 use of procedures, 8-1
libraries of floating-point functions, Appendix F module, 7-1 thru 7-9
line-feed, 2-1, 2-5 as block, 1-3
LINK86, 3-10, 11-16 level,3-7
linkage, 3-1 main, 1-4
assembly language, Appendix F object, 11-16
floating-point, Appendix F modulo arithmetic in DOs, 6-6
list MOVB,9-10
as array, 3-2, 5-1 MOVE,9-13
as structure, 3-2, 5-2 thru 5-5 MOVRB, 9-10
of controls on line, 11-1 MOVRW, 9-10
of initialization values, 3-4 thru 3-7 MOVW, 9-10
restriction, 3-6, 3-7 multiple
of parameters, Chapter 8 assignment, 4-14
of scalars, 3-2, 5-1 declarations, 1-3,3-1, 7-3
LIST control, 11-24 initializations, 3-4
listing format controls, 11-26 thru 11-31 multiprocessor
listing, sample, 11-28 lock,9-14
listing selection and content controls, 11-24, 11-25 multi-tasking, Appendix G
LITERALLY, 3-1, 3-7, 3-8
loading, 3-4 name, 1-3, 3-2
LOC86, 1-1, 11-16 on a DO, 1-3
local meaning, 9-1, 11-17 of procedure, 1-3, 3-9, 8-1,8-2,8-5
locaLsave_area, Appendix G recognized in blocks, 7-1 thru 7-9
location NAN, Appendix G
address, 3-3 negative values, 3-10
attribute, 3-1 nesting
eontents, 1-3 of blocks, 1-3,6-3, 7-1 thru 7-4, 11-28
references, 2-5, 3-5, 3-13 thru 3-19, 5-5, 9-1 of procedures, 8-6, 8-10
in string moves, 9-9 NIL pointers, 9-16
lock, 9-14 NOCODE control, 11-25
LOCKSET,9-14 NOCOND control, 11-37
logical NODEBUG control, 11-17
operation, 4-1 NOINTVECTOR control, 11-4
operator, 4-1, 4-5 thru 4-9, 11-32 NOLIST control, 11-24
loop optimization, 11-7 NOOBJECT control, 11-16
LOW, 9-3, 9-4 NOOVERFLOW control, 11-4
NOPAGING control, 11-26
NOPRINT control, 11-24
NOSYMBOLS control, 11-25
machine code optimization, 11-4, 11-5 NOT,4-5, 11-32
main notation, Preface
module, 7-6, 7-9 NOTYPE control, 11-18
program, 1-4, 11-6 NOXREF control, 11-25
manual organization, Preface
masked error, 10-6, Appendix G object
matrix as structure, 5-4 code, 11-16
MEDIUM, 11-21, 11-22 file controls, Chapter -II
restrictions, 11-22 module, 11-16

Index-4
PLjM-86 User's Gaicle Index

OBJECT control, 11-16, Appendix H, Appendix I epilogue, Appendix F


object module sections, 11-16 handling REAL interrupts, Appendix G
offset invoking, 1-3, 1-6,6-12
of REAL exponent,' 3-11 in location references, 3-13, 3-14
OFFSETSOF,9-16 name, 3-9
ones complement, 4-5 parameters, 3-9, 4-2
open subsystems, 13-3 prologue, Appendix F
operand, 1-4, 4-1 thru 4-15 reentrant, 7-1, 8-10
operator, 1-4,4-1,4-6 termination, 1-3, 8-5
precedence, 4-6 typed, 4-2,8-3, Appendix F
optimization untyped, 6-12, 8-3
and hardware flags, 10-1 value, 1-3, 4-2
OPTIMIZE controls, 11-4 thru 11-15 program, 1-2, 1-3, 7-1
optimizing control, 8-1
indeterminate storage operations, 11-8 documentation, 2-5
machine code, 11-6 example, 1-6, Chapter 12
pointer comparisons, 11-9 main, 1-2
OR, 4-5, 11-32 size controls, 11-18 thru 11-22, Chapter 13
order program constraints, Appendix B
of multiple assignments, 4-14 program development process, 1-5
of operand evaluation, 4-6, 4-9, 4-14 projective, see infinity
of parameter evaluation, 8-3 prologue, 8-8, Appendix F
outer level, 1-3,3-4,3-13,6-11, 7-1 thru 7-9 PUBLIC, 3-1, 3-6 thru 3-9,6-11, 7-4 thru 7-7,8-7, 8-8
out-of-range
case number, 6-3
qualified references, 4-1, 4-2
OUTPUT, 1-5, 10-4, 10-5
quote, see apostrophe
OUTWORD, 1-5, 10-4, 10-5
OVERFLOW control, 11-4
overflow, Appendix G RAM control, 11-28
REAL,2-4, 3-11,3-12,4-1,4-3, 4-4, 4-7 thru 4-14,
PAGELENGTH control, 11-26 10-6 thru 10-10, Appendix G
PAGEWIDTH control, 11-26 REAL error
PAGING control, 11-26 byte, 10-6, 10-7
parameters, categories, Appendix G
control, 11-1 REAL exceptions, Appendix G
parentheses, 2-2, 3-2 thru 3-7, 4-2, 4-6, 4-14, 4-15, 8-2, 8-4 REAL math facility, 10-6 thru 10-10
PARITY,10-2 REAL mode word, 10-6, 10-7
pathname, 11-16, 11-26 initial value, 10-6
PE8087, Appendix F suggested value, Appendix G
PL/M-80, Appendix D REAL-parameter passing, Appendix F
PL/M-86 recursion, 8-10
compiler, Appendix H, Appendix I REENTRANT, 3-9, 8-10
PL/M-80, Appendix D reentrant procedure, 7-1, 8-1, 8-10
sample program, 1-6, Chapter 12 references
statements, 1-4 to arrays and structures, 5-4, 5-5, 8-3, 9-1, 9-2
PLM86.LIB, 4-1, Chapter 14 external, see scope
PLUS, 10-2 location, 2-5, 3-13 thru 3-15, 5-5,9-1
plus sign, 2-2, 2-5, 4-3 thru 4-6 qualified
POINTER, 3-2, 3-4, 3-13, ,4-13 fully, 4-1, 4-2, 4-12, 5-4, 9-1
pointer, 3-4, 3-13 partially, 5-4, 5-5, 9-1 thru 9-3
POINTER and SELECTOR related functions, 9-16, 9-17 unqualified, 5-4, 5-5
precedence, 4-6 thru 4-9 related publications, Preface, Appendix H
precision, 10-8, Appendix G relational
predeclared identifiers, Appendix A operation, 3-10,4-8,4-9
primary operator, 3-10, 4-4 thru 4-9, 11-32
controls, 11-1 removal of unreachable code, 11-6 thru 11-8
operands,4-3 representation of REAL values, 3-11, 3-12
PRINT control, 11-24 reserved words, 2-3, Appendix A
PROCEDURE, 3-9,8-1,8-2 RESET control, 11-35
procedure, 1-3, 1-6 RESTORE control, 11-32
activation, 1-3,6-11,6-12 RESTORESREALSSTATUS, 10-10, Appendix G
block, 7-1 thru 7-7 restoring REAL status, 10-8
body, 8-1, 8-6, 8-7 restricted expression, 3-4, 3-5
declaration, 1-3, 3-1, 3-9 RETURN, 4-12,6-12,8-5,8-6
definition block, 1-3, 3-9 return address, Appendix F

Index-5
Index PL/M-86 User's Guide

reuse of duplicate Code, 11-6, 11-7 source


restriction, 11-6 code, 1-6, Chapter 12
reversal of branch condition, 11-6 location in string moves, 9-9
ROL,9-7 source inclusion controls, 11-32
ROM control, 11.23 source PL/M-86 errors, 14-1 thru 14-19
ROR,9-7 space, see blank
rotation functions, 9-7, 9-8, 10-3 special characters, 2-1 thru 2-3
rounding, 10-8, Appendix G SS, 11-18 thru 11-22
RUN, Appendix H STACKBASE, 10-4
run-time, 4-1, 6-3, 8-3, Appendix F, Appendix H STACKPTR, 10-4
stack, Appendix F
market offset, Appendix F
maximum, 11-30
SAL, 9-8 overflow, Appendix F
sample pointer, 10-4, Appendix F
listing, 11-28 REAL, Appendix F
programs, 1-6, Chapter 12 segment
SAR,9-8 base address, 10-4, Appendix F
SAVE control, 11-32 usage, 8-10, Appendix F, Appendix G
saving REAL status, 10-9 stack section, 11-17 thru 11-22
SAVESREALSSTATUS, 10-10, Appendix G starLexpr, 6-1
scalar, 3-2 thru 3-5, 4-2, 4-12, 5-4 statement number, 11-29
SCL,10-3 step_expr, see DO, iterative
scope, 7-1 thru 7-9, 9-1 strength reduction, 11-5
extended, 7-4 thru 7-7, 8-7, 8-8 string
of labels, 3-9 in compilation constant, 3-7, 3-8
of procedure name, 8-1, 8-2 comparison, 9-9
of variables, 1-4 constant, 2-1, 2-3, 2-5, 3-1, 3-6, 3-15, 4-2
SCR,10-3 copying, 9-9
segment definition, 9-9
address, 13-1 index, 9-9
overlap, 11-8 manipulation, 9-9 thru 9-13
segmentation order of copy, 9-9
controls, 11-18 thru 11-22, Chapter 13 target, 9-11
selecLexpression, see DO CASE translation, 9-12
SELECTOR, 3-15, 4-3, 4-10, 4-13 type, 2-5
SELECTORSOF, 3-15, 9-16 value, 2-5, 3-5, 4-2
semicolon, 2-2 value assignment, 9-12
separators, 2-2, 2-3 STRUCTURE, 3-1, 3-3, 3-5, 5-2
SETB,9-12 structure, 3-2, 3-5, 3-6, 5-2 thru 5-5
SET control, 11-35 arrays, 5-2 thru 5-5
SETSINTERRUPT, 9-15 as matrix, 5-4
SETSREALSMODE, 10-8 declaration, 5-2
SETW,9-12 example, 3-3, 3-5, 3-18
shared memory, 9-14 references, 5-5
shift functions, 9-7 thru 9-9 storage of, 5-2
SHL,9-8 type, 5-2
short-circuit Boolean evaluation, 11-4 subexpression, 4-2, 4-6 thru 4-9, 11-5, 11-33
SHR,9-8 subroutine, see procedure
side effects, 4-9,8-3,8-4 subscript, 3-2, 3-3, 3-9, 3-15 thru 3-17, 4-11,
see also order 5-1 thru 5-5, 8-2
SIGN,10-2 subsystems
SIGNED,9-6 modular, Chapter 13
sign of REAL number, 3-11 unnamed, 13-3
SIZE, 5-5,9-1,9-2 SUBTITLE control, 11-27
size controls, 11-18 thru 11-22, Chapter 13 subtraction, 3-10,4-3
SKIPB,9-ll suffix, 2-4
SKIPRB, 9-11 superfluous
SKIPRW, 9-11 branches, 11-5
SKIPW, 9-11 operations, 11-5
slash, 3-1, 4-3, 4-4 support library, 3-10
SMALL, 11-18 thru 11-20 symbolic and cross-reference listing, 11-28, 11-30
restrictions, 11-19 symbolic
soft recovery f(Om REAL underflow, Appendix G debugging, 11-17
see underflow, denormal names, see variable, SYMBOLS

Index-6
PLfM-86 User's Guide Index

SYMBOLS control, 11-25, 11-28 usage


syntax declaration, 7-5, 8-7, 8-8
BNF description, Appendix C
variable, 1-4,3-1 tbru 3-3, 3-10
tab, 2-1, 2-5, 6-3 area size, 11-30
target assignment, 4-12 thru 4-15
label in GOTO, 6-11, 7-6 thru 7-9 based, 3-15 thru 3-17
in string moves, 9-11 declaration, 3-1
THEN part results, 3-3
see IF statement or control defmition, 3-1
TIME,9-13 initialization, 3-1, 3-4 thru 3-7
TITLE control, 11-27 names, 1-4, 3-1
token, 2-2 negative, 3-10
true, 4-5, 4-6, 6-4, 6-7 REAL, 3-11, 3-12
twos complement, 3-11 references, 1-4,4-2
type, 3-1 reinitialization, 3-4
of arithmetic, 1-4,3-10,4-3,4-4 subscripted, 5-1 thru 5-4
conflict, 7-5 types, 3-10 thru 3-15,4-3 thru 4-5, 4-8,4-10 thru 4-15
conversion
explicit, 9-3 thru 9-7 WAIT state, 10-10
implicit, 4-8, 4-13 warnings, 11-31, Chapter 14
of counter in iterative DO, 6-6 WHILE, see DO
data, 3-10 thru 3-15 whole-numbers,
mixing, 4-8 context, 4-1
procedure, 8-3, 8-4, 8-7, Appendix F WORD, 3-1, 3-10, 4-1 thru 4-14
TYPE control, 11-18 least significant bits, 3-10

unary operators, 4-6 XLAT,9-12


underflow, Appendix G XOR, 4-5, 11-32
underscore, 2-3 XREF control, 11-25, 11-28
unmasked error, 10-8, Appendix G
UNSIGN, 9-3,9-6 ZERO, 10-2
untyped procedure, 6-12, 8-3, 8-4, 8-7 zero divide, Appendix G

Index-7
PL/M-86 User's Guide
121636-003

REQUEST FOR READER'S COMMENTS

Intel's Technical Publications Departments attempt to provide publications that meet the needs of all Intel product
users. This form lets you participate directly in the publication process. Your comments will help us correct and
improve our publications. Please take a few minutes to respond.

Please restrict your comments to the usability, accuracy, readability, organization, and completeness of this
publication. If you have any comments on the product that this publication describes, please contact your Intel
representative. If you wish to order publications, contact the Intel Literature Department (see page ii of this
manual).

1. Please describe any errors you found in this publication (include page number).

2. Does the publication cover the information you expected or required? Please make suggestions for
improvement.

3. Is this the right type of publication for your needs? Is it at the right level? What other types of publications
are needed?

4. Did you have any difficulty understanding descriptions or wording? Where?

5. Please rate this publication on a scale of 1 to 5 (5 being the best rating). _______________

NAME ____________________________________________________ DATE ___________


TITLE _______________________________________________________________________

COMPANY NAME/DEPARTMENT _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __
ADDRESS ______________________
CITY ______________________ STATE _____________ ZIP CODe _ _ _ _ __
(COUNTRY)

Please check here if you require a written reply. 0


WE'D LIKE YOUR COMMENTS •..

This document is one of a series describing Intel products. Your comments on the back of this form will
help us produce better manuals. Each reply will be carefully reviewed by the responsible person. All
comments and suggestions become the property of Intel Corporation.

111111 NO POSTAGE
NECESSARY
IF MAilED
IN U.S.A.

BUSINESS REPLY MAIL


FIRST CLASS PERMIT NO. 1040 SANTA CLARA, CA

POSTAGE WILL BE PAID BY ADDRESSEE

Intel Corporation
Attn: Technical Publications MIS 6-2000
3065 Bowers Avenue
Santa Clara, CA 95051
INTEL CORPORATION, 3065 Bowers Avenue, Santa Clara, California 95051 (408) 987-8080
Printed in U.S.A.

You might also like