INDEX
*  PL360 TEXTBOOK
+  Preface
1  The IBM System/360 Computer
1.1  Storage
1.2  Registers
1.3  Fixed-Point Arithmetic
1.4  Instructions and Addressing
1.5  Relative Addressing
1.6  Logical Operations
1.7  Shift Operations
1.8  Floating-Point Arithmetic
1.9  Program Status Word
1.10  Summary
1.11  Exercise
2  The PL360 Language
2.1  The Program
2.2  Identifiers
2.3  Reserved and Pre-declared Identifiers
2.4  Special Symbols and Delimiters
2.5  Constants
2.5.1  Fixed-Point Constants
2.5.2  Floating-Point Constants
2.5.3  Summary of Rules for Fixed-Length Values
2.5.4  Variable-Length Strings
2.6  Comments
2.7  Exercise
3  The Main Program
3.1  Segmentation
3.2  Compiler Generated Names
3.3  Compilation and Execution
3.4  Blocks
3.4.1  Declarations
3.4.2  Statements
3.5  Main Programs
3.6  Data Segments
3.7  Program Segments
3.8  Exercise
4  Declarations
4.1  Data Segment Declarations
4.1.1  DUMMY BASE Declarations
4.1.2  CLOSE BASE Declarations
4.2  The Main Program Data Segment
4.3  Cell Declarations
4.3.1  Arrays
4.3.2  Cell Initialization
4.4  Cell References
4.5  Cell Synonyms
4.6  Register Synonyms
4.7  Integer Value Synonyms: EQUATE
4.8  Sample Declarations
4.9  Exercise
5  Assignment Statements
5.1  Register Assignment Statements
5.1.1  Integer Register Assignments
5.1.1.1  Reverse Assignment
5.1.1.2  Operator Restrictions and Precedence
5.1.1.3  Shift Operations
5.1.1.4  Logical Addition and Subtraction
5.1.1.5  Logical Operations
5.1.1.6  Multiplication and Division
5.1.1.7  Integer Register Usage
5.1.2  Floating-Point Register Assignments
5.2  Cell Assignments
5.2.1  Register-to-Storage
5.2.2  Storage-to-Storage
5.3  Exercise
6  Branching, Testing, and Loops
6.1  GOTO Statements
6.2  Conditions
6.2.1  Simple Conditions
6.2.1.1  Relational Operators
6.2.2  Compound Conditions
6.2.3  Special Conditions
6.3  IF Statements
6.4  WHILE Statements
6.5  REPEAT/UNTIL Statements
6.6  FOR Statements
6.7  CASE Statements
6.8  Exercise
7  Functions
7.1  Function Declarations
7.2  Function Statements
7.3  Pre-declared Functions
7.4  Other Functions
7.5  Exercise
8  Procedures
8.1  Local Procedures
8.2  Global Procedures
8.3  External Procedures
8.4  Pre-declared Procedures
8.5  Procedure Synonyms
8.6  Miscellaneous
8.7  Exercise
9  Sample Programs
:A  Appendix A -- Two's Complement Arithmetic
:B  Appendix B -- Floating-Point Description
:C  Appendix C -- EBCDIC Character Table
:D  Appendix D -- PL360 Constructs
:D.1  TABLE OF 2-BYTE INSTRUCTIONS
:D.2  TABLE OF 4-BYTE INSTRUCTIONS
:D.3  TABLE OF PRE-DECLARED FUNCTIONS
:D.4  TABLE OF CELLULAR INSTRUCTIONS
:D.5  Other Constructs of the Language
:E  Appendix E -- Compiler Control Facilities
:E.1  Listing Control
:E.2  Listing Options
:E.3  Operating System Control
:E.4  Program Base Register Control
:E.5  Identification
:E.6  Object Deck Control
:E.7  Copy Facility
:E.8  Conditional Compile Directives
:F  Appendix F -- Compiler Output
:F.1  Compiler Listing Output
:F.2  Compiler Object Program Output
:G  Appendix G -- Linkage Conventions
:G.1  Calling External Routines from PL360
:G.2  Requesting Supervisor Services
:G.3  Calling PL360 Procedures from External Routines
:G.4  Problems Involving Loading of Object Decks
:H  Appendix H -- Compiler Error Diagnostics
:I  Appendix I -- PL360 Syntactic Grammar
:J  Appendix J -- Format of PL360 Programs
:J.1  Indentation
:J.2  Spacing
:J.3  Choice of Identifiers
:J.4  Comments
:J.5  Miscellaneous
:K  Appendix K -- PL360 Under ORVYL
:K.1  Using the PL360 Compiler with ORVYL
:K.2  Input/Output Subroutines for Interactive PL360 Programs
:L  Appendix L -- Exercise Answers

*  PL360 TEXTBOOK

(c) 1977 by Wadsworth Publishing Company, Inc., Belmont, California 94002. All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transcribed, in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior written permission of the publisher.

Printed in the United States of America

1 2 3 4 5 6 7 8 9 10---81 80 79 78 77

Portions of this text are reprinted from "PL360 Reference Manual" with the permission of the publishers, SCIP Academic Computing Services. Copyright (c) 1975 by the Board of Trustees of The Leland Stanford Junior University.

***********************************************************
*  Library of Congress Cataloging in Publication Data     *
*                                                         *
*  Guertin, Richard L                                     *
*     Introduction to PL360 programming.                  *
*                                                         *
*     Bibliography:  p.                                   *
*     Includes index.                                     *
*     1.  PL360 (computer program language)  I.  Title.   *
*  QA76.73.P267G83          001.6'424           76-51752  *
*  ISBN 0-534-00524-1                                     *
***********************************************************

+  Preface

A few years ago, while I was teaching a short course on PL360 at Stanford University, a student asked: "Is there a textbook on PL360?" I found there wasn't, but recognized the need for one. So I set out to write this textbook with two principle goals in mind. First, describe the PL360 programming language in such a way that each section of the text builds upon material covered in earlier sections. Second, write in a style that would appeal to assembly language programmers as well as PL/1 and FORTRAN programmers.

PL360, by its very nature, is an intermediate level programming language dealing with high level language concepts such as 'block structuring', and assembly language concepts such as 'registers'. This textbook is designed to be used with an intermediate level programming course, a transitional course between higher level languages and pure assembly language programming. Of course, assembly language programmers who wish to 'move up' to a higher style of programming would also find this textbook useful, first as a learning tool, and later as a reference document. In all fairness though, I must point out that PL360 is NOT an assembly language. Most versions of the language do not have 'macro' capability, although expanded macros can be programmed directly in PL360.

The PL360 programming language was originally designed and implemented by Nicklus Wirth and Joe Wells at Stanford University for the IBM System/360 computers. However, the FUNCTION capability of PL360 makes the language extensible to IBM System/370 and Amdahl computers. In fact, PL360 can be used on any computer that supports the basic System/360 instruction set. The other instructions can be programmed through FUNCTION declarations and statements.

I would like to thank the many students and friends who helped me in preparing this textbook by reviewing the preliminary material. The final drafts were reviewed by John Lindsay at Queen's University, and by Steven M. Dreyer at City University of New York. Both of these gentlemen contributed significantly; however, any and all errors or omissions are solely my responsibility. Also, I would like to thank Mike Snell, Jenny Sill, and Anne Kelly at Wadsworth Publishing Company for all their editorial help. Finally, special thanks to Stanford University for providing me with the environment that made writing this text possible.

The PL360 compiler is a proprietary program licensed by Stanford University and is available to universities and other non-profit organizations for a small fee by writing to:

       Program Librarian
       Information Technology Systems and Services
       Polya Hall
       Stanford University
       Stanford, California  94305

Introduction to PL360 Programming

In recent years, many new languages have been introduced to aid in programming digital computers. Most of these languages have been somewhat 'transportable'; that is, the programs written in these languages could be taken from one computer to another with minor changes. They are machine independent languages. FORTRAN, ALGOL, and COBOL are just a few examples.

However, these languages, to be machine independent, are usually restrictive in nature. They seldom use the full instruction power of a computer. As a result, they are sometimes inefficient, wasteful of computer memory space, or incapable of handling some special problems. FORTRAN, for example, is not well suited to character manipulations.

These 'high level' languages are generally not suitable for 'systems programming'. Compilers, programs that translate a language such as FORTRAN into the machine dependent instructions representing the source program, are usually written in a lower level machine dependent language: an assembly language. Assembly language is much more difficult to program, but provides the programmer with access to every machine instruction available on the computer. One difficulty in assembly language programming is that each instruction must be specified on a separate source card by means of some cryptic mnemonic, and usually in varying formats depending on the mnemonic. The programmer must learn a myriad of mnemonics and formats just to get started. This clerical work is not only a burden, but also a rich source of pitfalls.

Clearly, it would be advantageous to be able to write assembly level programs in a high level language style, such as ALGOL. This is what the PL360 programming language provides for the IBM System/360 (and now 370) computers: an ALGOL style machine level language. The benefits of the ALGOL style are so overwhelming that those programmers familiar with ALGOL will hardly recognize the machine level aspects of the language. And those programmers familiar with System/360 assembly language will greatly appreciate the ease of programming in PL360. PL360, therefore, is usually a suitable language choice whenever assembly language is considered. The language contains all the facilities commonly needed to express compiler and supervisor programs; and the programmer is able to determine almost every detailed machine operation. Interestingly enough, the PL360 compiler is an efficient one pass compiler written in its own language!

We shall cover both the IBM System/360 architecture and the ALGOL style of programming in this text. The first chapter provides a basic overview of the System/360 architecture. The second chapter introduces the basic symbols used in PL360 programming and discusses how constants are specified. The remaining chapters describe PL360 programming and language structure with an aim toward defining a complete PL360 program. Some of the Exercise problems given will be complete programs, but only knowledge gained in preceding chapters will be needed to answer such problems.

1  The IBM System/360 Computer

The basic structure of a System/360 digital computer consists of a central processing unit (CPU) and a main storage or memory unit. Input/output operations are usually handled by an operating system (OS), the environment in which a PL360 program is normally run. Direct input/output operations can be performed by a PL360 program, but only indirect input/output operations will be covered in this text.

The central processing unit of a System/360 is directed by instructions stored in memory. Each instruction performs some basic action, such as ADD one operand to another. Instructions are normally taken in sequence, but branching instructions provide for alterations in the flow of control. Most instructions operate on data held either in main storage or in the CPU. The basic unit of addressable information is a byte.

A byte consists of eight bits (binary digits) and is the basic building block of all information. Bytes may be handled separately or grouped together in fields. A halfword is a group of two consecutive bytes and is the basic building block of instructions. A fullword is a group of four consecutive bytes; a double-word is a field consisting of two consecutive fullwords. The first byte of a set of consecutive bytes is sometimes referred to as the left-most, highest, or top byte. Similarly, the last byte is sometimes referred to as the right-most, lowest, or bottom byte.

1.1  Storage

The location of any field, operand, or group of bytes in main storage is specified by the address of the left-most byte of the field. Byte locations are consecutively numbered, left to right, starting with 0; each number is considered the address of the corresponding byte. Thus, a fullword specified at location 1000 consists of bytes 1000, 1001, 1002, and 1003. The addressing arrangement of most System/360 computers uses a 24-bit binary address to accommodate a maximum of 16,777,216 byte addresses. This textbook deals mainly with 24-bit addressing, but System/370 and newer models can accommodate 31-bit addresses (2GB), and PL360 can compile programs that are 31-bit clean.

The length of any field in main storage is either implied by the operation to be performed or is stated explicitly as part of the instruction. When the length is implied, the information is said to have a fixed length, which can be either one, two, four, or eight bytes. When the length of a field is not implied by the operation, but is stated explicitly, the information is said to have a variable length which can vary in 1-byte increments from a minimum of one byte to a maximum of 256 bytes (more for certain System/370 instructions).

Fixed-length fields, such as halfwords, fullwords, and double-words, must be aligned in main storage on an integral boundary commensurate with their length. For example, fullwords (four bytes) must be located in main storage so that the address of the left-most byte is a multiple of 4. A halfword must have an address that is a multiple of 2, and a double-word must have an address that is a multiple of 8. Variable-length fields are not limited to integral boundaries, and may start on any byte location. System/370 and newer models do not impose alignment restrictions, but unaligned fullwords and halfwords cause degradation in speed.

Data fields in main storage are commonly referred to as 'cells'; whereas data fields in the CPU are kept in what are called 'registers'.

1.2  Registers

There are 16 general-purpose 32-bit registers for fixed-point operations, and four floating-point 64-bit registers for floating-point operations. Additions, subtractions, multiplications, divisions, and comparisons can be performed upon one operand in a register and another operand either in a register or in main storage. For some purposes, a pair of general-purpose registers are treated as a single register of 64 bits. In PL360, the general registers are called INTEGER registers, and the floating-point registers are called REAL or LONG REAL registers depending on how they are used.

1.3  Fixed-Point Arithmetic

The general-purpose 32-bit registers serve as accumulators in fixed-point arithmetic and logical operations. All fixed-point arithmetic is done in the general registers using signed operands. The sign bit is the high order bit of the operand, and is 0 for positive operands and 1 for negative operands. A negative operand is maintained as the two's complement of a positive operand. (See Appendix A for a full discussion of two's complement.)

Since binary (base 2) is inconvenient for expressing operands, or doing arithmetic, the hexadecimal (base 16) system is used instead. A group of four bits represents one hexadecimal digit according to the following table:

     BINARY  HEX    BINARY  HEX    BINARY  HEX    BINARY  HEX
      0000    0      0100    4      1000    8      1100    C
      0001    1      0101    5      1001    9      1101    D
      0010    2      0110    6      1010    A      1110    E
      0011    3      0111    7      1011    B      1111    F

Thus, positive 3 would be represented by 00000003 as a 32-bit hexadecimal value, and negative 3 would be represented by FFFFFFFD. Throughout this text, positive values will be shown with no leading sign, and negative values will be shown with a leading underscore character ( 3 and _3). This is done so as not to confuse the sign of a value with the operations of addition and subtraction, represented by the symbols + and -. Thus, + _3 indicates addition of a negative 3. The basic fixed-point operand is the 32-bit word. Halfword storage operands may be used for fixed-point operations of addition, subtraction, and multiplication, and for fetching and storing with general registers. Fullword multiplications and divisions require two adjacent general registers coupled together to provide a two-word capacity for products and dividends. Fixed-point operations will be covered in greater detail in section 5.1.1, Integer Register Assignments.

In PL360, the fixed-point 32-bit fullword operands are called INTEGER operands; and the 16-bit halfword storage operands are called SHORT INTEGER operands.

1.4  Instructions and Addressing

Because the 32-bit word size of the general registers readily accommodates a 24-bit storage address, the general registers are also used for address arithmetic. To fully understand the addressing usage of the general registers, we must first examine instruction formats.

The length of an instruction can be one, two, or three halfwords. All instructions must be located in storage on halfword boundaries. Figure 1 shows the four basic instruction formats.

        ________________________________________________________
       |  FIRST HALFWORD  |  SECOND HALFWORD |  THIRD HALFWORD  |

        ------------------
       | OP CODE |        |
        ------------------
                    I or RR or MR

        -------------------------------------
       | OP CODE |    | X | B |    D         |
        -------------------------------------
                    R or M

        -------------------------------------
       | OP CODE |        | B |    D         |
        -------------------------------------
                    I or RR

        --------------------------------------------------------
       | OP CODE |        | B |    D         | B |    D         |
        --------------------------------------------------------
                    L or L1L2

               FIGURE 1.   BASIC INSTRUCTION FORMATS

In each format, the first instruction halfword consists of two parts. The first byte contains the operation code (op code). The second byte is used either as a single 8-bit field designating a value (I) or length (L), or as two 4-bit fields designating two registers (RR or RX), a mask and a register (MR or MX), or two lengths (L1L2).

The second and third halfwords always have the same format: a 4-bit base register designator (B), followed by a 12-bit displacement value (D). These halfwords provide what is called 'Base+Displacement' addressing in that a storage address is computed as follows.

To the 12-bit displacement value specified by the D-field of the instruction is added the lower 24-bit value contained in the general register specified by the associated B-field of the instruction (except when B is 0). Those instructions with an X-field provide additional addressing capability, called 'indexing'. To the 'Base+Displacement' address is added the lower 24-bit value contained in the general register specified by the X-field of such instructions (except when X is 0). The final storage address is the 24-bit result of either a Base+Displacement or Index+Base+Displacement computation. This computation is done assuming all values are positive (12-bit and 24-bit), extending each value to 32 bits with leading zeros, performing 32-bit additions (ignoring overflow), and extracting the final address from the lower 24 bits of the result. If zero is specified in a B-field or X-field, then positive zero is used for that component of the address calculation rather than the contents of general register 0. Thus, general register 0 never participates in the address calculation. Figure 2 shows a sample address calculation.

        CODE      X   B    D
        ----------------------                 -----------------
       |    |   | 4 | 9 | 008 | ------------> | 0 0 0 0 0 0 0 8 |
        ----------------------                 -----------------

                     General Register 9                +
                      -----------------        -----------------
                     | 4 A 0 0 6 5 0 0 | ---> | 0 0 0 0 6 5 0 0 |
                      -----------------        -----------------

                     General Register 4                +
                      -----------------        -----------------
                     | F F F F F F F C | ---> | 0 0 F F F F F C |
                      -----------------        -----------------

     (Note: General Register 4 contains _4)
                                               -----------------
                          Final Result:       | x x 0 0 6 5 0 4 |
                                               -----------------

               FIGURE 2.   SAMPLE ADDRESS CALCULATION

1.5  Relative Addressing

The B and D fields or X, B, and D fields of an instruction constitute the addressing field of an instruction. The displacement value in an instruction address field provides a relative addressing mechanism, that is, for any given storage address contained in the associated base register, up to 4096 consecutive bytes of storage may be referenced beginning at that base address. Storage can be thought of as being segmented into sections of up to 4096 bytes. These segments may be program instruction or data areas having some specific structure, and may start anywhere in main storage providing alignment rules are not violated.

For example, consider a data area consisting of the following fixed-length fields in the order specified:

     a fullword, two halfwords, a double-word, and three fullwords.

Let's call these seven fixed-length fields XX1 to XX7, draw a diagram of the area (Figure 3), and number the bytes starting at 0.

                         -----------
        Base Address  0 |    XX1    |     fullword
                        |-----------|
                      4 | XX2 | XX3 |     two halfwords
                        |-----------|
                      8 |    XX4    |     double-word
                     12 |           |
                        |-----------|
                     16 |    XX5    |     fullword
                        |-----------|
                     20 |    XX6    |     fullword
                        |-----------|
                     24 |    XX7    |     fullword
                         -----------

                        4 bytes wide

                          FIGURE 3.

Notice that XX5 begins at relative address 16. If this data area were located in main storage beginning at location 1000, and a base register associated with the area, say general register 4, contained the address 1000, then XX5 could be referenced by the address field of an instruction which specifies register 4 in its B-field and 16 in its D-field. It is important to note that the instruction would not be changed if the area were located instead at location 2000 in main storage, and general register 4 contained that address. This makes it easy to move the data storage area without having to change every instruction that refers to it.

1.6  Logical Operations

The logical operations of AND, OR, and XOR (Exclusive-OR), and logical or un-signed addition, subtraction, and comparison can be performed upon one operand in a general register using a fullword operand either in a general register or in main storage. In such operations, all operands are considered un-signed, and all 32 bits of the operands participate in the operations. AND, OR, and XOR logic tables are given below with binary operands and results.

                             AND       OR        XOR
             Operand 1     1 1 0 0   1 1 0 0   1 1 0 0
             Operand 2     1 0 1 0   1 0 1 0   1 0 1 0

             Result:       1 0 0 0   1 1 1 0   0 1 1 0

                           LOGIC TABLES

There are also storage-to-storage operations which allow processing of variable-length data starting at any byte address and continuing left to right for up to 256 bytes. Such operations as translation, comparison, editing, and storage-to-storage copy are possible. Usually the data consists of alphabetic or numeric character codes in Extended Binary-Coded-Decimal Interchange Code (EBCDIC). These operations will be covered in more detail later. An EBCDIC table is given in Appendix C.

1.7  Shift Operations

The general registers may also participate in an operation known as shifting. The contents of a general register (or pair of adjacent general registers) may be shifted to the right or left some number of bit positions.

When shifted to the right, bits are dropped from the right end of the register and either zero bits are inserted from the left end (logical right shift), or the sign bit is propagated (arithmetic right shift).

When shifted to the left, bits are dropped from the left end, and zero bits are inserted from the right end. No error is possible in a logical left shift; but in an arithmetic left shift, an error condition is flagged if a bit differing from the original sign bit is dropped or occupies the sign bit position.

Shifting (usually arithmetic) provides a convenient means of multiplying or dividing by powers of 2. A shift of 1 to the left is equivalent to multiplication by 2; a shift of 1 to the right is equivalent to division by 2 (dropping the remainder).

1.8  Floating-Point Arithmetic

Floating-point values occur in either of two fixed-length formats: 32-bit fullwords called REAL values, and 64-bit double-words called LONG REAL values. These formats differ only in the length of the fractional portions (see Figure 4).

             REAL value  (fullword)
         --------------------------------
        |S| Exponent  |  Fraction        |
         --------------------------------
         0 1         7 8               31
             LONG REAL value  (double-word)
         --------------------------------------------------------
        |S| Exponent  |  Fraction                                |
         --------------------------------------------------------
         0 1         7 8                                      63

                           FIGURE 4.

A REAL value, equivalent to about seven decimal places of precision, permits a maximum of operands to be placed in storage and gives the shortest execution times. The LONG REAL values, used when higher precision is desired, give up to 17 decimal places of precision.

The fraction of a floating-point value is expressed as six hexadecimal digits occupying bits 8-31 for REAL values, and 14 hexadecimal digits occupying bits 8-63 for LONG REAL values.

The radix point of the fraction is assumed to be immediately to the left of the high order fraction digit (immediately before bit 8). To provide the proper magnitude for the floating-point value, the fraction is considered to be multiplied by some power of 16. The 'Exponent' portion of the floating-point value (bits 1-7) is used to indicate this power. The exponent ranges from 0 through 127 representing true (base 16) exponents from _64 through 63, and permits representations of decimal values with magnitudes ranging approximately from 10 to the _78th through 10 to the 75th.

This method of specifying exponents within the computer's representation of a value is known as 'excess 64 notation', in that 64 is added to the true exponent to arrive at the computer's exponent.

Bit position 0 in either format is the sign (S) of the fraction. The fraction (and exponent) of negative values is the same as that of positive values. Only the sign differs. Negative values are not maintained in two's complement as they are for fixed-point values.

Four 64-bit floating-point registers are provided in the hardware, and the arithmetic operations of addition, subtraction, multiplication, division, and comparison can be performed with one operand in a register and another in a register or in storage. The result, developed in a register, is generally of the same length as the operands, either 32-bit or 64-bit.

Most of the floating-point operations produce what is known as a 'normalized' result; that is, the result is adjusted so that the first hexadecimal digit of the fraction is non-zero. For example, 0.001 would become 0.1 with appropriate exponent adjustment. Normalized results retain the greatest precision possible. However, unnormalized addition and subtraction operations are provided to allow for easy transformation of floating-point values to fixed-point format or other similar purposes. (See Appendix B for further discussion of floating- point values.)

1.9  Program Status Word

A two-word quantity called the program status word (PSW), contains the information required for proper instruction execution. The PSW includes, among other things, the address of the next instruction to be executed and a 2-bit quantity called the condition code. The condition code provides decision-making capability. Most of the arithmetic and logical operations can set the code to one of four states (0, 1, 2, and 3). Conditional branch instructions can specify any selection of these four states as the criterion for branching. Specifying all four states results in an unconditional branch; specifying none of the four states results in a do-nothing operation.

The condition code reflects such conditions as: zero, negative, or positive result; overflow; and comparison is equal, low, or high. Once set, the condition code remains unchanged until modified by another instruction that reflects a different status. For example, branch instructions do not change the condition code, but additions and subtractions do change the code.

1.10  Summary

This chapter has presented a brief overview of the System/360 architecture with an emphasis on those items of particular importance to the PL360 programming language. The reader is directed to IBM's Principles of Operation manuals for details concerning these and other System/360 computer operations, such as input/output operations. Later in this text, specific computer instructions will be covered in more detail.

1.11  Exercise

Problem 1.

What is the hexadecimal result (32-bit) of a logical right shift by 3 of the value _8 ?

Problem 2.

Compute the address in decimal by performing the Index+Base+Displacement calculations indicated below given the following general register contents:

     General Register:        0      1       2      3      4      5
     Contents (decimal):   7160    _16  510000  16000  72568   _100

          X  B   D (in decimal)
     (a)  0  2  30
     (b)  1  4   0
     (c)  3  2 200
     (d)  5  2  50
     (e)  0  0 100

Problem 3.

Determine the result in hexadecimal of logical AND, OR, and XOR operations for each value below with all values below. The values are given as 1-byte hexadecimal values.

       0F      F0      18

Problem 4.

The REAL values shown below are given in decimal notation on the left and hexadecimal (machine) notation on the right. Supply the missing decimal or hexadecimal values in the table.

    Decimal   Hexadecimal

       0.5     40800000
       8.0     41800000
       9.0     41900000
(a)    8.5     --------
(b)    ---     42180000
(c)    ---     42800000

2  The PL360 Language

PL360 programs are input to the PL360 compiler on 80-column cards or card images. The compiler processes only columns 1 through 72 of each card; columns 73 through 80 are ignored by the compiler, and are usually used for card sequencing information by the programmer.

The input consists of (one or more) PL360 programs and compiler control cards. A compiler control card is distinguished by the character $ in column 1 of the card. The PL360 program input is considered to be a stream of characters with column 1 of each non-control card immediately following column 72 of the preceding non-control card.

2.1  The Program

A program contains declarations and statements composed of identifiers, basic symbols, constants, strings, and comments. Declarations serve to identify cells of storage, registers, procedures, and other quantities which are involved in the algorithm or problem to be solved by the program. Statements specify the operations to be performed on these quantities.

The remainder of this chapter is devoted to defining identifiers, basic symbols, constants, strings, and comments. In subsequent chapters, we will proceed to construct PL360 programs with declarations and statements.

2.2  Identifiers

Identifiers are used to give a name to some quantity, such as a register or storage cell. Identifiers are composed of the mixed case alphabetic characters and decimal digits, where the first character of the identifier must be alphabetic. They may be of any length, but only the first 10 characters are retained by the PL360 compiler. The following are examples of legal identifiers, the last two of which are considered identical because the first 10 characters match:

       ABLE          HELP           SOMELIKEITCOLD
       BASE16        JackRabbit     SOMELIKEITHOT
       FLAG          K27P5
       FLAG3         X

Case doesn't matter, and identifiers are considered identical regardless of the case in which they are specified. The following are all considered identical identifiers:

       POT           POt            Pot
       pot           poT            pOT

2.3  Reserved and Pre-declared Identifiers

Some identifiers are reserved for exclusive use by the PL360 language. These identifiers have a specific meaning in the language and therefore may not be chosen as user-defined identifiers. The following is a complete list of the reserved identifiers in alphabetic order:

       AND        COMMENT    EXTERNAL   LONG       SEGMENT    THEN
       ARRAY      COMMON     FOR        NULL       SHLA       UNTIL
       BASE       DATA       FUNCTION   OF         SHLL       WHILE
       BEGIN      DO         GLOBAL     OR         SHORT      XOR
       BYTE       DUMMY      GOTO       PROCEDURE  SHRA
       CASE       ELSE       IF         REAL       SHRL
       CHARACTER  END        INTEGER    REGISTER   STEP
       CLOSE      EQUATE     LOGICAL    REPEAT     SYN

There is also a set of pre-declared identifiers that may be redefined by the programmer. However, it is recommended that these identifiers NOT be redefined. A complete list of these 'standard identifiers' follows:

       INTEGER REGISTERS

       R0   R1   R2   R3   R4   R5   R6   R7
       R8   R9   R10  R11  R12  R13  R14  R15
       FLOATING-POINT REGISTERS

       F0   F2   F4   F6    (REAL REGISTERS)
       F01  F23  F45  F67   (LONG REAL REGISTERS)
       CELL NAMES

       B1  B2 ... B15  MEM  (INTEGER CELLS)
       H1  H2 ... H15       (SHORT INTEGER CELLS)
       C1  C2 ... C15       (BYTE CELLS)
       L1  L2 ... L15       (LONG REAL CELLS)
       DSTAR, PSTAR         (DATA & PROGRAM BASE-DISP)
       MONADIC OPERATORS    (SPECIAL SYMBOLS)

       ABS        DEC       GT        LE        NEG
       EQUATE VALUES    (INTEGER VALUES)

       TRUE = _1    FALSE = 0    OVERFLOW = 1
       CARRY = 3    MIXED = 4    ON = 1   OFF = 8
       STRING = length of last string compiled
       DATAFILL = variable array size
       FUNCTIONS

       BALR       EX        MVI       RESET     STCM      TS
       CLC        IC        MVN       SET       STH       UNPK
       CLI        ICM       MVZ       SLDA      STM       XC
       CLM        LA        NC        SLDL      SVC       XI
       CVB        LH        NI        SPM       TEST
       CVD        LM        OC        SRDA      TM
       ED         LTR       OI        SRDL      TR
       EDMK       MVC       PACK      STC       TRT
       EXTERNAL PROCEDURES

       BCDTOVAL   KLOSE     PRINT     READ
       CANCEL     OPEN      PUNCH     WRITE
       GET        PAGE      PUT       VALTOBCD

2.4  Special Symbols and Delimiters

There are a number of special symbols and delimiters used in writing PL360 programs. These special symbols serve as separators between identifiers and constants, and are listed below with a brief description of their use:

       Symbol     Description

         +        plus sign, add
         -        minus sign, subtract
         ++       double plus, add logical or unnormalized
         --       double minus, subtract logical or unnormalized
         *        star, multiply
         /        slash, divide, separator
         @        address symbol
         @@       absolute address initialization
         ( )      left and right parens, subscripts, brackets
         :=       assignment operator
         =:       reverse assignment operator
         :        colon, label indicator
         _        underscore, negative value
         ,        comma, separator
         ;        semicolon, terminator
         .        period, decimal point
         #        hexadecimal number indicator
         '        apostrophe, exponent indicator
         "        quote, character string delimiters
         =        equal sign, compare equal
         <        compare less than
         >        compare greater than
         <=       compare less than or equal
         >=       compare greater than or equal
         ~=       compare not equal
         ~        not indicator
         |        comment delimiter
                  blank, space

2.5  Constants

Numbers or numerical constants written in PL360 programs are divided into three classes, namely:

(a)  fixed-point
(b)  floating-point
(c)  variable-length strings

2.5.1  Fixed-Point Constants

There are two types of fixed-point constants: (32-bit) fullword constants called INTEGER values, and (16-bit) halfword constants called SHORT INTEGER values.

A positive integer value may be written in decimal notation using the digits 0 to 9. A negative value is written as a positive value preceded by an underscore character (_). An integer value may also be written in hexadecimal notation using the character # followed by the hexadecimal digits 0 to 9 and A to F. Negative hexadecimal values must be written in computer form (see Appendix A).

A short integer value is written as an integer value followed by the letter S.

The following are examples of (32-bit) integer values starting with the largest positive value, and ending with the largest negative value that can be written in PL360 language.

         Decimal            Hexadecimal
      2147483647            #7FFFFFFF
           65536            #00010000   or   #10000
               1            #00000001   or   #1
               0            #00000000   or   #0
              _1            #FFFFFFFF
              _2            #FFFFFFFE
          _65536            #FFFF0000
     _2147483647            #80000001

The largest possible negative value is #80000000, but this value can only be written in hexadecimal notation, not decimal notation.

The following are examples of (16-bit) short integer values starting with the largest positive value, and ending with the largest negative value.

         Decimal            Hexadecimal
          32767S            #7FFFS
              1S            #0001S   or   #1S
              0S            #0000S   or   #0S
             _1S            #FFFFS
         _32768S            #8000S

2.5.2  Floating-Point Constants

There are two types of floating-point constants: (32-bit) full- word constants called REAL values, and (64-bit) double-word constants called LONG REAL values. Floating-point constants are generally used in connection with the REAL and LONG REAL floating-point registers.

     A floating-point constant is written in decimal notation as:

The portion of the number preceding the decimal point in (a) or (b), or the number preceding the exponent in (c), may not exceed 2147483647.

An exponent is written as the apostrophe character ('), which signifies 'times 10 to the power of', followed by a positive or negative decimal integer value indicating the power of 10 desired. The final magnitude of the number must range from 10'_75 through 10'75.

When written as specified above, the values are REAL values. A LONG REAL value is written as a REAL value followed by the letter L. A negative value is written as a positive value preceded by an underscore character (_).

A floating-point constant may also be written as a positive or negative decimal integer value followed by the letter R for REAL values, or the letter L for LONG REAL values.

All the above decimal forms of writing floating-point constants yield normalized values. Normalized (or unnormalized) values are a characteristic of how the System/360 computer represents the value internally. Floating-point constants may be written in this internal form, either normalized or unnormalized, in hexadecimal notation. Hexadecimal floating-point constants are written as: the character # followed by (up to) eight hexadecimal digits and the letter R, for REAL values, or (up to) 16 hexadecimal digits and the letter L for LONG REAL values.

The following are examples of REAL (normalized) values, the first column showing a variety of ways of writing 'pi', and the last two values showing the largest and smallest positive non-zero decimal values.

             3.14159          1.75             _15.0
             314159'_5        1R               175.'_2
             0.314159'1       0.  (zero)       7.237'75
             314.159'_2       _7.6             1'_75

The following are samples of real values in hexadecimal notation, starting with the largest and smallest possible positive non-zero normalized values, and ending with an unnormalized long real value which will be discussed later in section 5.1.2.

             Value            Hexadecimal
             7.237'75         #7FFFFFFFR
             5.4 x 10-79      #00100000R
             1.56256'_2       #3F400000R
             0.5              #40800000R
             1.0              #41100000R
             0.0 (zero)       #00000000R   or   #0R
             (special)        #4E00000000000000L

Note: the first three values are only approximately equal to the hexadecimal values given, and the second value is too small to be written in decimal notation. The reason for approximations is that exact values in one base system may not convert to exact values in another base system, in this case, decimal to hexadecimal. For example, decimal 0.5 (5/10) is hexadecimal 0.8 (8/16), but decimal 0.3 (3/10) is a repeating hexadecimal value: 0.4CCCCCCC.... Therefore, floating-point values are only accurate to six or seven decimal digits for real values, and 16 or 17 decimal digits for long real values.

2.5.3  Summary of Rules for Fixed-Length Values

(a)  There are four types of fixed-length values:  INTEGER,
     SHORT INTEGER,  REAL,  and LONG REAL.
(b)  REAL and LONG REAL values may be  written  in  decimal
     digits  with  decimal  point,  exponent, or both;  and
     LONG REAL values must end in the letter L.
(c)  Any value may be written in hexadecimal  (leading  #),
     or   in  decimal  digits  (without  decimal  point  or
     exponent).  SHORT INTEGER values end in S, REAL values
     end in R, and LONG REAL values end in L.
(d)  The length of a hexadecimal value is usually twice the
     byte   length   of   the   fixed-length   value  being
     represented (two hexadecimal digits per byte).
(e)  Negative decimal values are  indicated  by  a  leading
     underscore character (_).

2.5.4  Variable-Length Strings

A string is a sequence of characters, each character taking one byte (two hexadecimal digits). The set of all possible characters is given in Appendix C. The set includes the English alphabet in both upper and lower case, decimal digits, a selection of special symbols, blank (or space), and other characters (non-graphic).

A string is normally written as a sequence of characters enclosed in quotation marks, called a quote string, and may contain a sequence of from one through 255 characters. If a quote mark (") is to be a character of the sequence, it is represented by a pair of consecutive quotes. All characters are significant within quote strings, including blank characters. An "accent" character (`) followed by a normal character is used to represent certain special (non-graphic) characters. If a true accent character is to be entered in the string, it must be doubled (similar to what happens for quote).

Examples:  "A""z"    denotes the sequence  A"z
           """X"""   denotes the sequence  "X"
           """"      denotes the single character  "
           "This is an example of a quoted string"
           "This string has an accent (``) character"

If a quote string cannot be contained on a single input card because of its length, then note that column 72 of one card is followed by column 1 of the next card (excluding control cards). The character $ cannot occur in column 1 of a card (since that signifies a compiler control card).

There are instances where a quote string is not a convenient means of specifying a variable-length string, such as when non-graphic characters are to be used for some special purpose. In such instances, another form of variable-length string may be used, namely a hexadecimal string. A hexadecimal string is written as the character # followed by from one to 16 hexadecimal digits followed by the character X. Each pair of hexadecimal digits represent one character. If the number of hexadecimal digits specified is odd, then a hexadecimal zero is prefixed to the first specified hexadecimal digit to make the total even. A hexadecimal string then may be used to specify from one to eight characters (bytes).

Examples:  #2X       denotes the single character  02
           #C3C1C2X  denotes a 3-byte string equivalent to "CAB"
           #4096FX   denotes a 3-byte packed-decimal value of +4096
           #20202021204B2020X  denotes an 8-byte special editing value

Certain non-graphic characters may be included in a quote string using the accent escape character followed by a graphic character. Here is a table showing the character which follows the accent to obtain the non-graphic character, shown in hexadecimal below the character.

    Table of Accent (`) Characters.
    .
    .   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
    . #01 #02 #03 #37 #2D #2E #2F #16 #05 #25 #0B #0C #0D #0E #0F
    .
    .   P   Q   R   S   T   U   V   W   X   Y   Z   %   [   >   ?
    . #10 #11 #12 #13 #3C #3D #32 #26 #18 #19 #3F #17 #27 #28 #09
    .
    .   !   $   *   )   ;   ~   0   1   \   /   `   :   #   @   ]
    . #04 #14 #15 #2B #55 #FA #20 #21 #22 #07 #79 #08 #09 #00 #1D
    .
    .   =   ^   .   <   (   +   &   "
    . #2C #35 #1E #1F #1B #1C #0A #7F

#20202021204B2020X could be given as: "`0`0`0`1`0.`0`0".

2.6  Comments

Comments may appear freely throughout a PL360 program. A comment is written as the reserved identifier COMMENT followed by a delimiter character and any number of characters except a semicolon, and is terminated by a semicolon (;). A comment may also be written as any number of characters excluding the vertical bar (|) between vertical bars. As with quote strings, the character $ may not appear in column 1 of a card; otherwise a non-quoted $ signifies end-of-card.

       |This is a comment|   $ rest of card is comment
       COMMENT  This is the end of Chapter 2.;

2.7  Exercise

Problem 1.

Which of the following are not valid identifiers, and why?

(a)  IDENTIFIER
(b)  2X
(c)  A.B
(d)  Samson
(e)  EASY2READ
(f)  ICU2
(g)  #F

Problem 2.

Which of the following are not valid constants, and why?

(a)  #AX
(b)  2,124,587
(c)  "This must be right!"
(d)  .2L
(e)  _5'_6L
(f)  #8A S
(g)  PI
(h)  #FACES

Problem 3.

What is the 'type' of the valid constants in Problem 2 above? Specify INTEGER, SHORT INTEGER, LONG REAL, STRING, etc.

3  The Main Program

3.1  Segmentation

The addressing mechanism of the System/360 computers is such that instructions can indicate the absolute address of stored information only relative to a base address contained in a register. The difference D between the desired absolute address and the available base address must satisfy: 0 <= D < 4096. To accomplish this, a PL360 program may be subdivided into individually identified parts, called segments. Every quantity requiring storage space and defined within a program is known by the segment in which it occurs and by its displacement relative to the origin of that segment. The problem then consists of subdividing the program and choosing base registers so that proper instructions can be generated. Of course, the number of times base addresses must be reloaded into base registers should be kept reasonably small; and therefore, the programmer is encouraged to organize the program in such a way as to minimize the number of cross-references between segments by explicitly stating which parts of the program constitute segments.

One natural division is between the instructions of a program and the data operated upon by the instructions. Therefore, in PL360, the program is divided into program segments (instructions) and data segments (data areas). There are two benefits in doing this. First, there are many instances where it is desirable that program and data areas be kept apart as separate entities, such as in reentrant programs. Second, the programmer's knowledge about segment sizes and occurrences of cross-references differs for program and data areas. In the program area case, his knowledge about the eventual size of the compiled program segment is only vague; whereas in the data area case, he knows exactly the amount of storage space needed for declared quantities, and he knows precisely in which places in the program these quantities are referenced.

For the purposes of illustration, we shall assume a main program consists of only one program segment and one data segment. We shall assign the program segment base register R15, and the data segment base register R13. These are the base register assignments assumed by the PL360 compiler unless the compiler is explicitly directed to assign other base registers.

3.2  Compiler Generated Names

Every segment generated by the PL360 compiler must be given a name. This name either is explicitly specified by the programmer, or is generated by the compiler. All generated names are seven characters long, the first three of which are usually SEG and the last four are always the letter N and three decimal digits. Generally the programmer is not concerned about what names are generated, as long as the result is valid and acceptable. But it is important to note that every segment is named.

In our forthcoming examples, neither the program segment nor the data segment will be explicitly named; and therefore, compiler generated names will be used to name each segment. Thus, SEGN001 and SEGN000 will be assigned to the program and data segments respectively.

3.3  Compilation and Execution

The PL360 compiler is a program which, like most computer programs, performs essentially three functions: input, processing, and output.

The input consists of an ordered set of card images upon which is inscribed, in PL360 language, the declarations and statements of a problem program.

The processing is that of compiling or translating the input PL360 program into System/360 machine language or computer instructions.

The output consists of a set of card images, called object decks, each deck describing one segment of the compiled program. The name of the segment, the amount of space the segment would occupy in main storage, and the System/360 machine instructions or other data which compose the segment are all part of this description. Also, information relating to cross-references between segments is included.

The compiler also outputs a listing or printout of the original program along with other information relating to the compilation, such as any error diagnostics which may have occurred.

The object decks are later processed by another program, called a loader. It is the loader's task to load or place into main storage all the segments of the compiled program, resolving cross-references between segments. The loader then transfers control to the starting address of the main program segment, initializing the base register (R15) to that starting address. The program then proceeds to execute.

3.4  Blocks

A block begins with the reserved identifier BEGIN and ends with the reserved identifier END. A block contains declarations, statements, and labels, composed of identifiers, basic symbols, constants, and strings. All declarations must come first in a block, each declaration being terminated by a semicolon (;). Then, statements and labels may occur, each statement terminated by a semicolon (;), and each label terminated by a colon (:). The general form of a block is:

       BEGIN  D;  D;  D;  ...  S;  S;  S;  END

where the D's represent declarations and the S's represent statements. A label (L:) may occur anywhere a statement (S;) may occur. Labels serve to designate branch points within a block, and GOTO statements refer to such points. The two main purposes of a block are:

3.4.1  Declarations

     The following list includes all possible PL360 declarations:

                   -------------------------------
                  | 1.  data segment declarations |
                  | 2.  cell declarations         |
                  | 3.  cell synonyms             |
                  | 4.  register synonyms         |
                  | 5.  integer value synonyms    |
                  | 6.  function declarations     |
                  | 7.  procedure declarations    |
                   -------------------------------

Declarations serve to define data segments and identify storage cells and other quantities. The following is a sample cell declaration which defines alpha, beta, and gamma as integer cells.

       INTEGER  ALPHA, BETA, GAMMA;

Note: although the compiler allows identifiers in mixed case, reserved and pre-declared identifiers will be shown in upper case, and some user-defined identifiers will be shown in lower case to indicate that no specific identifier is intended.

3.4.2  Statements

The following list includes all possible PL360 statements:

                ------------------------------------
               |  1.  block                         |
               |  2.  register assignment statement |
               |  3.  cell assignment statement     |
               |  4.  GOTO statement                |
               |  5.  IF statement                  |
               |  6.  WHILE statement               |
               |  7.  REPEAT/UNTIL statement        |
               |  8.  FOR statement                 |
               |  9.  CASE statement                |
               | 10.  function statement            |
               | 11.  procedure statement           |
               | 12.  NULL statement                |
                ------------------------------------

Notice that a block is an allowed statement; that is, blocks may be nested one inside another. The following two lines serve to illustrate the concept:

     BEGIN  D;  D;  D;  ...  S;  S;  block;  S;  S;  END  (outer block)
        BEGIN  D;  D;  ...  S;  S;  END                   (inner block)

The second line is called the 'inner block' in relation to the first line, and it replaces the word 'block' of the first line. The first line is called the 'outer block' in relation to the second line. Therefore, the inner block is contained within the outer block.

Since other declarations may occur within inner blocks, the question of the 'scope' of a declaration presents itself. (The scope of a declaration is that portion of the program where the declared quantities of a block may legitimately be referenced.)

The restriction is that the scope of any declared quantity is limited to the block in which the declaration occurs and any inner blocks, unless re-declared within an inner block. The declared quantity is known from the point where the declaration occurs within a block through to the END of that block. It is not known outside that block.

Every declared quantity must also be unique to a block. That is, the same identifier may not be declared more than once within a block. However, an inner block may re-declare an identifier, in which case the new meaning for that identifier holds from the point of re-declaration through to the END of that inner block, and then the old or original meaning resumes within the outer block.

The following 5-block example should clarify most of the points covered thus far. The BEGIN's and END's of each block are joined together by a numbered line solely for the purposes of illustration, and only cell declarations are included in the example. Other declarations and statements are left out to keep the example simple, but '....;' shows where they might occur.

         | BEGIN  INTEGER ALPHA, SAVE;
         |    ....;
         |    | BEGIN  REAL BETA, SAVE;
         |    |    ....;
         |    |    | BEGIN  INTEGER GAMMA;
       1 |  2 |  3 |    ....;
         |    |    | END;
         |    |    ....;
         |    |    | BEGIN  INTEGER SAVE;
         |    |  4 |    ....;
         |    |    | END;
         |    |    ....;
         |    | END;
         |    ....;
         |    | BEGIN  REAL DELTA;
         |  5 |    ....;
         |    | END;
         |    ....;
         | END.

ALPHA (declared in block 1) is known throughout all blocks.
BETA  (declared in block 2) is known only in blocks 2, 3, and 4.
GAMMA (declared in block 3) is known only in block 3.
DELTA (declared in block 5) is known only in block 5.
SAVE is declared 3 times;  once in block 1, and again (re-declared) in
block 2, and again (re-declared) in block 4.  The scope of each is:

       SAVE of block 1 is known in blocks 1 and 5 only.
       SAVE of block 2 is known in blocks 2 and 3 only.
       SAVE of block 4 is known in block 4 only.

Note that although SAVE is declared INTEGER in both blocks 1  and  4,
they  are NOT the same SAVE.  A reference to SAVE in any block is a
reference to the only SAVE known to that block and no other.

3.5  Main Programs

A main program is defined as a block followed by a period (.). The preceding 5-block example represents a main program since it terminates with a period. Comments may occur anywhere before the terminating period.

3.6  Data Segments

Assuming no other declarations in the 5-block example just given, all the cell declarations would be collected together by the compiler to form a single data segment which could be diagrammed as:

                        -------------------
                       | ALPHA             |
                       |-------------------|
                       | SAVE (of block 1) |
                       |-------------------|
                       | BETA              |
                       |-------------------|
                       | SAVE (of block 2) |
                       |-------------------|
                       | GAMMA             |
                       |-------------------|
                       | SAVE (of block 4) |
                       |-------------------|
                       | DELTA             |
                        -------------------

This sample data segment would be assigned some base register which, as stated earlier, we shall assume is register R13. Each cell declared within this data segment then would have some relative address depending upon the number of bytes of storage space required by all cells which precede it. (Reread section 1.5, Relative Addressing, if necessary.)

3.7  Program Segments

All of the statements in our 5-block example generate System/360 computer instructions that compose our main program segment. This segment also requires a base register which, as stated earlier, we shall assume is register R15.

Constants and strings referenced by PL360 statements, and which cannot be contained within generated instructions, are placed at the end of the program segment following all generated instructions. These constants and strings are called 'literals', and the collection of all literals at the end of a program segment is called the 'literal pool'. The base register associated with these literals is the program segment's base register, not a data segment's base register as might be assumed.

Under certain circumstances, which will be covered more completely in Chapter 8, a block may define a program segment separate from the main program segment. Usually this further subdividing of the program into more than one program segment is done when the amount of code generated by the problem program would exceed 4096 bytes. Every such program segment is a logically self-contained entity having its own literal pool. Only those literals referenced by the statements of a particular program segment are contained in that segment's literal pool.

3.8  Exercise

The following is a complete main program. Although a majority of this program involves material not yet covered, it is being presented at this point to give you some idea of what PL360 programs look like. The problems in this exercise use this program, but only material covered thus far is used in these problems.

|01|  BEGIN  COMMENT -- THIS IS A SAMPLE PROGRAM WHICH
|02|  * READS IN THE DIMENSIONS OF A BOX, COMPUTES THE
|03|  * VOLUME, AND WRITES THE RESULT.  --;
|04|
|05|  COMMENT -- DECLARE FUNCTIONS AND VARIABLES --;
|06|     FUNCTION REDUCE(6,#0600);  |-- SUBTRACT 1 FROM REGISTER --|
|07|
|08|     ARRAY 133 BYTE INPUT = (" INPUT DIMENSIONS ARE:",111(" "));
|09|        BYTE CARD SYN INPUT(23);  |-- CARD PART OF INPUT --|
|10|     ARRAY 133 BYTE OUTPUT = (" VOLUME =",124(" "));
|11|        BYTE ANSWER SYN OUTPUT(10);  |-- ANSWER PART OF OUTPUT --|
|12|
|13|  COMMENT -- MAIN PROGRAM CODE --;
|14|     WHILE  R0 := @CARD;  READ;  = DO  |-- PROCESS CARD --|
|15|     BEGIN  R0 := @INPUT;  WRITE;  |-- SHOW INPUT DATA --|
|16|        R1 := @CARD;  R2 := 1 =: R5;  R3 := 3;
|17|        WHILE R3 > 0 DO  |-- COMPUTE VOLUME --|
|18|        BEGIN  BCDTOVAL;  R5 := R5 * R0;  REDUCE(R3);
|19|        END;  COMMENT -- NOW GENERATE ANSWER --;
|20|        R1 := @ANSWER;  R3 := 7;  R0 := R5;  VALTOBCD;
|21|        R0 := @OUTPUT;  WRITE;  |-- OUTPUT THE ANSWER --|
|22|     END;
|23|  END.

Problem 1.

Specify the line numbers of the BEGIN and END of all blocks. Line numbers are shown on the left side of the program as |nn| comments.

Problem 2.

Integer and string constants are used in this program. Which lines contain string constants? (See section 2.5.4.)

Problem 3.

Using section 2.3,

4  Declarations

This chapter covers all PL360 declarations except function and procedure declarations which will be covered later in separate chapters. As for the others, data segment declarations define data segments, and cell declarations define the structure and content of data segments. Cell synonyms provide an additional cell naming capability, such as declaring that X and Y are the same cell. Register synonyms allow alternate names for the standard registers, such as stating that ZERO and R0 refer to the same register. And integer value synonyms provide the programmer with the capability of giving a name to an integer value, an integer constant expression.

4.1  Data Segment Declarations

As program segments are composed of computer instructions generated by statements, so also data segments are composed of cells defined by cell declarations. And as statements are bound into program segments by blocks (BEGIN through END), so also cell declarations are bound into data segments by data segment declarations.

Let us first examine data segment declarations. There are six declarations that may begin or initiate a data segment, and one declaration that may end or terminate any data segment. Of the six declarations that begin data segments, five will be discussed here, and the last, called a DUMMY segment, will be discussed separately in the section on DUMMY BASE declarations.

Each of the first five data segment declarations is given below in general syntactic form, where 'name' is an identifier naming the segment, and Rn indicates the selected base register, R0 through R15. (Note: only the first eight characters of a 'name' longer than eight characters are significant in naming a segment.) Remember that each of these declarations is terminated by a semicolon.

              ---------------------------------
             | 1.  COMMON DATA name BASE Rn;   |
             | 2.  COMMON BASE Rn;             |
             | 3.  SEGMENT BASE Rn;            |
             | 4.  GLOBAL DATA name BASE Rn;   |
             | 5.  EXTERNAL DATA name BASE Rn; |
              ---------------------------------

Each of the above declarations specifies three things:

  (a) the type of data segment
  (b) the name of the data segment (possibly compiler defined)
  (c) the base register to be assigned to the data segment

Every data segment is assigned a base register, and that register must be an integer register, R0 through R15, other than the current program segment's base register. At the point in the block where these data segment declarations occur, an instruction is generated in the corresponding program segment to load the specified base register with the base address of the declared data segment. In assembly language, the instruction generated would correspond very closely to:

      L   Rn,=V(name)

Of course, R0 is not allowed to be a base register by the hardware, so no instruction is generated when R0 is specified. We shall cover such usage at the end of DUMMY BASE declarations.

It is the programmer's responsibility to insure the integrity of this data segment base register; that is, the register must contain the base address of the data segment whenever cells declared within that segment are referenced by subsequent statements. Of course, the contents of the register could be saved, the register used for some other purpose, and then the contents restored. But if cells are referenced that depend on a base address and the base register does not contain that address, then either the program will not execute properly or it will abnormally terminate.

The COMMON declarations define what is called a 'common area'. This type of area is normally used in conjunction with FORTRAN programs. The first declaration specifies labeled or named common; and the second declaration specifies unlabeled or blank common (so called because the data segment name is all blank). The same (named) common area may be declared more than once, usually by separately compiled programs, such as a PL360 program and a FORTRAN program. All would refer to the same storage area identified by their common name.

The SEGMENT BASE and GLOBAL DATA declarations both create data segments that must be unique. The only difference between these two declarations is that for the SEGMENT BASE declaration, the compiler generates the data segment name; whereas for the GLOBAL DATA declaration, the programmer explicitly specifies the data segment name.

The EXTERNAL DATA declaration allows reference to GLOBAL DATA segments either created in separately compiled programs to be run with this program, or created elsewhere in this same program. EXTERNAL DATA declarations do not create an actual data segment, but only refer to a data segment created by a GLOBAL DATA declaration somewhere else. As such, the cell declarations that compose an EXTERNAL DATA segment serve only to define the structure of the segment and not the content.

Normally, data segments are declared early in the program so that the cells which compose them may be referenced over the widest range of statements. Thus, for example, if a GLOBAL DATA segment were declared early in a program (in the outermost block), then the need to refer to that same data segment by an EXTERNAL DATA declaration is greatly reduced. However, an EXTERNAL DATA declaration could serve to re-establish the base address of a previously defined GLOBAL DATA segment by writing a statement of the form:

       BEGIN  EXTERNAL DATA name BASE Rn;  END

All of the above data segment declarations either create or refer to data segments that occupy specific areas of main storage. The instructions generated in the program segments load the absolute address of the start or base of these data segments into their associated base registers. The cross-references from program segments to these data segments are resolved by a loader program as described in section 3.3, Compilation and Execution.

4.1.1  DUMMY BASE Declarations

One other declaration may be used to define a data segment. It is the DUMMY BASE declaration, and has the general syntactic form:

DUMMY BASE Rn;

This declaration is discussed separately because it differs substantially from the preceding declarations. For example, dummy segments do not have a name, not even a compiler generated name. Also, no instruction is generated in the program segment to load the base register (Rn) specified. In fact, dummy segments neither create nor refer to any specific area of main storage!

A dummy segment acts as a template or overlay for any desired section of main storage. The cell declarations composing such a segment define only the structure of the template, never the contents of storage.

To use a dummy segment, the program computes, or is given as a parameter during execution, the address of some section of main storage which is assumed to have the same structure as that defined by the dummy segment. Statements of the program then place this address into the base register (Rn) of the dummy segment before other statements reference the cells of that segment.

If the address is changed or replaced by a new address, then the dummy segment or template is moved to overlay a different section of storage beginning at the new address.

For example, let us assume that some section of storage contains telephone book entries, each composed of a 32-character name, a 32-character address, and an 8-character telephone number, in that order. Then the following dummy segment could be used to reference the component parts of any individual entry once the dummy segment's base register (in this case, R7) has been set to the origin address of an entry.

       DUMMY BASE R7;
          ARRAY 32 CHARACTER NAME, ADDRESS;
          ARRAY  8 CHARACTER TELEPHONE;
       CLOSE BASE;

  (We shall cover CLOSE BASE and cell declarations shortly.)

There is one special case of base register specification for any data segment, which is especially useful in DUMMY BASE declarations. That is when R0 is specified as the base register, which really implies no base register at all, since R0 can never be used as a base or index register (see section 1.4, Instructions and Addressing). The cell declarations of such a segment supply only relative displacement values. The base registers for these cells are supplied explicitly by the programmer when these cells are referenced. Therefore, the programmer may choose one or more base registers (R1 through R15) with which to make references to these cells. For instance, if the dummy segment in our preceding telephone book example was declared DUMMY BASE R0 instead of DUMMY BASE R7, then an 8-character telephone number (or other component of the segment) could be referenced using any base register containing the address of an entry. In fact, two entirely separate entries could be referenced simultaneously (such as when comparing two telephone numbers) using two registers, each containing the address of one entry.

4.1.2  CLOSE BASE Declarations

All cell declarations are associated with data segments; that is, once a data segment has been initiated by one of the preceding declarations, the data segment is open to accepting cell declarations. The first cell declared in a data segment is assigned a displacement value of 0. Succeeding cells are assigned higher displacement values.

While a data segment is open, a new data segment may be initiated; that is, data segments may be nested one inside another. Cell declarations would then be associated with the newly opened data segment.

A data segment is closed to accepting further cell declarations upon encountering the END of the block in which the data segment was initiated; but the CLOSE BASE declaration may be used to close a data segment before the END. The CLOSE BASE declaration serves only to prevent subsequent cell declarations (if any) from being associated with the closed data segment. The scope of the cell declarations (composing the data segment) is not affected. The CLOSE BASE declaration is simply the reserved identifiers:

CLOSE BASE;

4.2  The Main Program Data Segment

When the main program is defined as a block terminated by a period (BEGIN ... END.), the compiler initiates a data segment which could be described:

       SEGMENT BASE R13;
          ARRAY 18 INTEGER B13;

The cell declaration (for B13) beginning the data segment provides a save area for linkage to other programs and subroutines. Other types of main programs will be discussed in Chapter 8, Procedures.

4.3  Cell Declarations

The structure of a data segment is defined by the cell declarations that compose it. There are five basic types of cell declarations, each type defining the number of bytes of storage to be reserved for the declared cell as specified in the table below.

                       TYPE          BYTES RESERVED
                       ----          --------------

               BYTE (or CHARACTER)         1
               SHORT INTEGER               2
               INTEGER (or LOGICAL)        4
               REAL                        4
               LONG REAL                   8

The general form of a cell declaration is:

Type id1, id2, ... , idn;

Type id;

where 'Type' is one of the basic types specified in the table above, and the id's are cell identifiers. For example, the following data segment and cell declarations would define the structure of some storage area as diagrammed below. (We saw this diagram in Figure 3 in Chapter 1.)

                  SEGMENT BASE R7;
                     INTEGER  XX1;
                     SHORT INTEGER  XX2, XX3;
                     LONG REAL  XX4;
                     INTEGER  XX5, XX6, XX7;
                  CLOSE BASE;
                         -----------
          R7 ------>  0 |    XX1    |
                        |-----------|
                      4 | XX2 | XX3 |
                        |-----------|
                      8 |    XX4    |
                     12 |           |
                        |-----------|
                     16 |    XX5    |
                        |-----------|
                     20 |    XX6    |
                        |-----------|
                     24 |    XX7    |
                         -----------

                        4 bytes wide

                    FIGURE 5.

The data segment declaration specifies register R7 as the base address register of this area. That is, it defines the value of the B-field of any instructions that refer to the declared cells. The cell declarations in turn specify the D-field of such instructions. (See Instructions and Addressing in Chapter 1, if necessary.)

The displacement value associated with any declared cell is determined by the total number of bytes of storage space reserved by preceding cell declarations of the data segment, and by the alignment rule associated with the type of the cell being defined.

The alignment rule simply states that the displacement value assigned for a cell must be an integral multiple of the basic cell length: 1, 2, 4, or 8 bytes depending on the type. The alignment rule is always applied before the compiler reserves the space associated with the basic cell type. The following example should demonstrate the concept.

                  DUMMY BASE R2;
                     SHORT INTEGER  S;
                     INTEGER  X;
                     BYTE  B;
                     INTEGER  Y;
                  CLOSE BASE;
                          -------
          R2 ------>   0 | S |///|
                         |-------|
                       4 |   X   |
                         |-------|
                       8 |B|/////|
                         |-------|
                      12 |   Y   |
                          -------

                         FIGURE 6.

The slashed areas (/) of the diagram are not exactly waste space, because they can be referenced as we shall see later. However, a tighter packing of the area would result by ordering the declarations as follows:

                  DUMMY BASE R2;
                     INTEGER  X, Y;
                     SHORT INTEGER  S;
                     BYTE  B;
                  CLOSE BASE;

The area would then appear as:

                          -------
          R2 ------>   0 |   X   |
                         |-------|
                       4 |   Y   |
                         |-------|
                       8 | S |B|/|
                          -------

                         FIGURE 7.

The various types not only define the number of bytes of storage to be reserved, but also the manner in which the cells are likely to be used. We shall cover this concept in detail in the next chapter.

4.3.1  Arrays

Each basic cell declaration may be preceded by the reserved word ARRAY followed by a non-negative integer value. An array declaration applies to every cell identifier of the declaration, and it causes the amount of space reserved for each cell to be n-times the basic cell length, where 'n' is the non-negative integer value. For example:

       ARRAY 4 BYTE NAME, ADDRESS;

indicates that four bytes of space must be reserved for both NAME and ADDRESS. The compiler does not 'remember' array declarations, but simply reserves the requested space. Of course, alignment is always done before space is reserved. An ARRAY 0 type of declaration reserves no space of its own; it only aligns the declared cell to the appropriate boundary. Thus:

       ARRAY 0 LONG REAL Y;
       ARRAY 2 INTEGER X;

causes X and Y both to begin at the same double-word boundary. The declaration of Y causes the alignment, and the declaration of X reserves the actual space.

Changing the cell declarations given with Figure 6 by including arrays, we can create exactly the same area as shown below.

                  DUMMY BASE R2;
                     ARRAY 2 SHORT INTEGER  S;
                     INTEGER  X;
                     ARRAY 4 BYTE  B;
                     INTEGER  Y;
                  CLOSE BASE;

                          -------
          R2 ------>   0 | S |   |
                          -------
                       4 |   X   |
                          -------
                       8 |B| | | |
                          -------
                      12 |   Y   |
                          -------

                         FIGURE 8.

Cells of an array are normally referenced by displacements which are a multiple of the basic cell length, starting with 0. Thus, the four bytes of B would be referenced as B(0), B(1), B(2), and B(3). The two short integers of S would be referenced as S(0) and S(2). Note that a reference to S alone is NOT a reference to the entire array! It is only a reference to S(0). Also, S(4) would be a reference to the first halfword of integer X, and S(6) would be a reference to the second halfword of X. Similarly, X(_4) is a reference to all of the declared S array (two short integers = one integer). We shall cover cell references in more detail in section 4.4.

4.3.2  Cell Initialization

Cell declarations of SEGMENT BASE and GLOBAL DATA areas may be initialized at compile time to specific values. Then, when these data segments are loaded into core, the initialized cells will contain the specified values. Non-initialized cells could contain unpredictable values unless the operating system initializes core.

Cell initialization is specified by following a cell identifier with an equal sign (=) and a predefined value or list of values. For example:

       INTEGER  X = 27,  SIX = 6;

Cell identifiers declared to be an array of 'n' cells may be initialized with a list of up to 'n' values. The values must be separated by commas and the entire list must be enclosed in parentheses. For example:

       ARRAY 12 INTEGER TERMS = 10,
                        TABLE = (1,4,4,4,5,6,1,4,4,4,5,6);

In the above example, only the first reserved integer of TERMS is initialized and the remaining 11 reserved integers of TERMS are undefined. All of TABLE is initialized by a parenthesized list of values (12 integers). Any parenthesized initialization list may be preceded by a positive (non-zero) integer replication factor, and any individual value of a list may be replaced by a parenthesized list of values optionally preceded by such a replication factor. Therefore, the preceding example could be rewritten as follows:

       ARRAY 12 INTEGER TERMS = 10,
                        TABLE = 2(1,3(4),5,6);

In all the examples given thus far, the type of the declared cell has been the same as the type of the initializing values. If the initializing values are fixed-length values, then the cell type determines the amount of space initialized by each value. This is made possible by the fact that all fixed-length values are maintained within the PL360 compiler as fullword (fixed-point) or double-word (floating-point) values regardless of their specific type. Therefore, an array of byte cells may be initialized by a list of integer values, and only the lower byte of each value is used in doing the initialization. Similarly, an array of integer cells may be initialized by a list of short integer values with each short integer value sign-extended to fill the integer cell. For example:

       ARRAY 4 BYTE MARKS = (1,5,0,7);
       INTEGER RATION = 9S;

                -----------
       MARKS   |01|05|00|07|
               |-----------|
       RATION  |00 00 00 09|
                -----------

Since the PL360 compiler does not check the type of an initializing fixed-length value against the type of the cell being initialized, it is possible to initialize INTEGER cells with floating-point values or REAL cells with fixed-point values. In general however, cells should be initialized with values of compatible type.

If the initializing value is a variable-length string, then the string determines the amount of space initialized regardless of cell type. Strings are never truncated or expanded. Each character occupies one byte starting with the left-most byte. For example, an 8-byte string would completely initialize any LONG REAL, ARRAY 2 INTEGER, ARRAY 4 SHORT INTEGER, or ARRAY 8 BYTE cell declaration.

SHORT INTEGER and INTEGER cells may be initialized to the Base-Displacement field of a previously declared cell as follows:

       SEGMENT BASE R3;
          INTEGER SOMECELL;
          SHORT INTEGER POINT = @SOMECELL;
       CLOSE BASE;

The value initializing POINT would be equivalent to #3000S since 3 is the Base field value and 000 is the Displacement field value for SOMECELL.

INTEGER cells may also be initialized to the absolute address of a previously declared cell. The initialization is done by the Loader. Absolute address initialization is indicated by using the @@-symbol. The general form of absolute address initialization is:

       INTEGER cellname = @@prevcell(disp/flags)

where "disp" is an additional displacement added to the absolute address of prevcell, and "flags" are a byte-sized value that will be placed in the upper byte of the integer along with the 3-byte absolute address. Such usage is restricted to 24-bit addressing. For example:

       SEGMENT BASE R4;
          INTEGER SOMECELL;
          INTEGER PARMPTR = @@SOMECELL(0/#80);
       CLOSE BASE;

PARMPTR will contain the absolute address of SOMECELL when loading is completed, with hex-80 in the upper byte.

The @@-symbol may also be used to initialize INTEGER cells to the absolute entry point address of previously declared procedures. Also, the @-symbol may be used to initialize SHORT INTEGER and INTEGER cells to the program segment Base and relative Displacement of previously declared procedures. We shall cover procedures in depth in Chapter 8.

DUMMY BASE and EXTERNAL DATA areas may also show cell initialization, but such areas are not actually initialized. Any initialization shown for cells of such areas only serves as documentation of what is expected, not of what may actually exist.

Arrays may also be declared such that the amount of space they take is determined by the amount of initialization given.

       ARRAY DATAFILL celltype cellname = (fill);
 or    ARRAY DATAFILL celltype = (fill);  |-- No cellname --|

The amount of "fill" determines the amount of space. For example:

       ARRAY DATAFILL INTEGER MARKERS = (1,3,5,9);
 and   ARRAY 4 INTEGER MARKERS = (1,3,5,9);

would produce the same storage results. If there is no fill, then ARRAY DATAFILL acts like ARRAY 0. DATAFILL is a compiler pre-declared EQUATE whose value is not likely to be given as an ARRAY size.

DSTAR is a pre-declared data cell address definition of base-displacement form corresponding to the current Bddd location in the data segement. DSTAR can be used to compute the length of data regions. For example:

       ARRAY DATAFILL INTEGER MARKERS = (1,3,5,9);
       EQUATE MARKLEN SYN DSTAR - MARKERS;  |-- length in bytes --|

Since both DATAFILL and DSTAR are pre-declared, you may redeclare them, but then you would lose the fill-defined array capability or relative data location capability. The compiler is not checking the names, just the special values associated with them.

DATAFILL is very handy when defining string arrays:

       ARRAY DATAFILL BYTE MESSAGE = ("This is a message");
       EQUATE MSGSIZE SYN STRING;  |-- Length of array --|

The following examples demonstrate the points covered by this section on cell initialization.

       ARRAY 120 BYTE ITEMS = ( 5, "Items", 8, "Examples", 4, "Help");
       ARRAY 132 BYTE BLANKS = 132(" "),
                      BUFF = 33(" ",2("*")," ");
       INTEGER WORD = "word";
       INTEGER WORDLOC = @@WORD;
       ARRAY 3 SHORT INTEGER INSTRUCTION = (#D200,@BUFF,@BLANKS);

4.4  Cell References

Once cells have been declared, they may be referenced in subsequent declarations and statements. For each cell identifier, the compiler remembers the cell's Index-Base-Displacement, i.e., its X-B-D fields. Normally, the X-field is 0, the B-field is Rn of the Data Segment Declaration containing the declared cell, and the D-field is the relative displacement of the start of the declared cell within the data segment.

A cell reference allows the programmer to modify the X-B-D field and directs the PL360 compiler to use the resultant X-B-D field in satisfying the declaration or statement containing the reference.

Several forms of cell reference are shown below, the last of which indicates a non-subscripted (unmodified) cell reference.

       identifier(Rb+Rx+k)  or  identifier(Rb+Rx-k)
       identifier(Rb+k)     or  identifier(Rb-k)
       identifier(Rb)       or  identifier(Rx)
       identifier(Rx+k)     or  identifier(Rx-k)
       identifier(k)
       identifier

Rb is allowed if the referenced cell has 0 for its B-field. In such a case, Rb replaces the B-field. DUMMY BASE R0 cells are examples of such cases. Rb defines the BASE register and should not be R0.

Rx is allowed if the referenced cell has 0 for its X-field. In such a case, Rx replaces the X-field. Rx defines the INDEX register and should not be R0.

'k' is either a single integer value or an expression of added and/or subtracted integer values. Each integer value is either added to or subtracted from the D-field to create a new D-field which must satisfy 0 <= D < 4096.

It is important to note that the D-field is always a byte displacement and that 'k' is an adjustment in byte amounts. Therefore, given the following integer array:

       ARRAY 5 INTEGER SPACE;

each element of the array takes four bytes and would be referenced as follows:

       SPACE(0)     or   SPACE
       SPACE(4)
       SPACE(8)
       SPACE(12)
       SPACE(16)

Throughout the remainder of this text we shall use the term 'cell' to indicate a cell reference regardless of cell type. Also, whenever the X-field of a cell is non-zero, the cell is 'indexed'.

4.5  Cell Synonyms

Cell synonym declarations provide the programmer with the ability to associate another identifier with a previously declared cell. The general form of a cell synonym declaration is:

Type id1 SYN cell1, id2 SYN cell2, ... , idn SYN celln;

Type id SYN cell;

where 'Type' is one of the basic cell types as given in section 4.3, i.e., BYTE, SHORT INTEGER, INTEGER, REAL, and LONG REAL.

The 'Type' of the newly declared identifier need not match the type associated with the referenced cell. In fact, the PL360 compiler does not check either type or alignment. Therefore, the programmer may define different types of cells having the same address. For example:

       DUMMY BASE R5;
          ARRAY 3 INTEGER Y;
       CLOSE BASE;

       INTEGER YINDEX SYN Y(R3);
       SHORT INTEGER YHI SYN Y,
                     YLO SYN Y(2);

The Index-Base-Displacement fields for the above are:

       Y        05000
       YINDEX   35000
       YHI      05000
       YLO      05002

'Type' may be preceded by 'ARRAY n', but the compiler will ignore the array portion of the declaration because cell synonym declarations never reserve any actual space. Using ARRAY in such a case is more for documentation purposes than anything else. However, if the SYN portion of the declaration were removed, the declaration would become a standard cell declaration which does reserve space. For example:

       ARRAY 132 BYTE OUTPUT;
       ARRAY 80 BYTE CARD SYN OUTPUT(1);
          |-- CARD is 80 bytes of OUTPUT beginning at 2nd byte --|

Cell synonym declarations also allow direct definition of the X-B-D field of a cell identifier by using an integer value in place of a cell reference. For example, the definition of Y above could have been done as follows:

       INTEGER Y SYN #5000;

There is a set of pre-declared cell identifiers that may be used in defining other identifiers. They are:

       MEM, B1, B2, B3, B4, B5, B6, B7, B8, B9,
       B10, B11, B12, B13, B14, B15

These identifiers are given below using declarations that would yield equivalent definitions to those pre-declared by the PL360 compiler.

       DUMMY BASE R0;   INTEGER MEM;   CLOSE BASE;
       DUMMY BASE R1;   INTEGER B1;    CLOSE BASE;
       DUMMY BASE R2;   INTEGER B2;    CLOSE BASE;
       DUMMY BASE R3;   INTEGER B3;    CLOSE BASE;
       DUMMY BASE R4;   INTEGER B4;    CLOSE BASE;
       DUMMY BASE R5;   INTEGER B5;    CLOSE BASE;
       DUMMY BASE R6;   INTEGER B6;    CLOSE BASE;
       DUMMY BASE R7;   INTEGER B7;    CLOSE BASE;
       DUMMY BASE R8;   INTEGER B8;    CLOSE BASE;
       DUMMY BASE R9;   INTEGER B9;    CLOSE BASE;
       DUMMY BASE R10;  INTEGER B10;   CLOSE BASE;
       DUMMY BASE R11;  INTEGER B11;   CLOSE BASE;
       DUMMY BASE R12;  INTEGER B12;   CLOSE BASE;
       DUMMY BASE R13;  INTEGER B13;   CLOSE BASE;
       DUMMY BASE R14;  INTEGER B14;   CLOSE BASE;
       DUMMY BASE R15;  INTEGER B15;   CLOSE BASE;
or     INTEGER MEM SYN 0,  |-- cell defined by integer value --|
               B1 SYN MEM(R1), B2 SYN MEM(R2), B3 SYN MEM(R3),
               B4 SYN MEM(R4), B5 SYN MEM(R5), B6 SYN MEM(R6),
               B7 SYN MEM(R7), B8 SYN MEM(R8), B9 SYN MEM(R9),
               B10 SYN MEM(R10), B11 SYN MEM(R11), B12 SYN MEM(R12),
               B13 SYN MEM(R13), B14 SYN MEM(R14), B15 SYN MEM(R15);

All of these pre-declared cell identifiers may be re-declared to be anything desired by the programmer; however, this is not recommended. The ARRAY 18 INTEGER B13; declaration shown in section 4.2 actually re-declares B13 to be the same as its pre-declared definition. If the declaration had been ARRAY 9 LONG REAL B13; then B13 would have been redefined.

4.6  Register Synonyms

Register synonyms serve to associate identifiers with registers, i.e., to define other identifiers for registers besides the standard register identifiers listed in section 2.3.

There are three types of registers: INTEGER, REAL, and LONG REAL. The general form of a register synonym declaration is:

Type REGISTER id1 SYN reg1, id2 SYN reg2, ... , idn SYN regn;

Type REGISTER id SYN reg;

where 'Type' is either INTEGER, REAL, or LONG REAL and 'reg' is a pre-declared or previously declared register identifier of matching type. For example:

       INTEGER REGISTER ZERO SYN R0,  Z0 SYN ZERO;
       REAL REGISTER FLOAT SYN F2;

A register synonym identifier may be used anywhere a standard register identifier may be used, throughout the scope of the register synonym declaration. For example:

       INTEGER REGISTER RECORD SYN R1;
       DUMMY BASE RECORD;

The DUMMY BASE declaration is equivalent to:

       DUMMY BASE R1;

Frequently, registers are used in place of storage cells, and therefore register synonym identifiers serve better to define the nature of these 'pseudo cells' than do the standard register identifiers. Also, registers that serve a specific purpose in the program, such as the base address register of some data, are often given register synonym identifiers. But regardless of what the intended purpose may be, the programmer should not be led to believe that a different name implies a different physical entity; IT DOES NOT. One of the most common programming errors is the failure to recognize that fact.

Although the pre-declared register identifiers may be re-declared as anything desired by the programmer, imagine the confusion that could cause! It is therefore strongly recommended that the standard register identifiers be treated as though they were basic symbols.

Throughout this text, any references to the pre-declared register identifiers apply to register synonyms as well.

4.7  Integer Value Synonyms: EQUATE

Integer value synonyms are commonly referred to as 'equates' or 'equate declarations'. These declarations serve to associate identifiers with integer values or integer value expressions which are computed by the PL360 compiler at the time the declaration is processed. These integer value identifiers may be used anywhere integer values are used, and their definition remains in effect throughout the scope of the declaration. (See section 2.5.1 for the definition of integer values.)

The general form of an integer value synonym declaration is:

EQUATE id1 SYN exp1, id2 SYN exp2, ... , idn SYN expn;

EQUATE id SYN exp;

where each 'exp' may be of the form

       start operator iv operator iv ... operator iv
or     start

where 'iv' represents any pre-declared, previously declared, or self-defining integer value; and 'start' represents one of the following eight ways to start an equate's expression:

       iv
       ABS iv
       DEC iv
       NEG iv
       NEG ABS iv
       cella - cellb
       "string"
       regname

The pre-declared words ABS, DEC, NEG and NEG ABS are called monadic operators. They indicate taking the absolute value, decrement by 1, sign inversion, or sign inversion of the absolute value of the integer value which follows.

The cella-cellb form represents a value which is the difference between the D-fields of two pre-declared or previously declared cells. The only restriction is that the X and B-fields must be identical for the two referenced cells.

The "string" form is limited to a character string of from one through four characters. The value defined by the "string" is the EBCDIC representation of the characters right-justified and zero-filled to the left if less than four characters. Thus,

       EQUATE ACTSTR SYN "A123",  SEPCHAR SYN ".";

is equivalent to defining the following:

       EQUATE ACTSTR SYN #C1F1F2F3,  SEPCHAR SYN #0000004B;

The regname form specifies a register identifier and the value is taken to be the number of the specified register. Thus,

       EQUATE X SYN R1,  Y SYN R5;

is equivalent to defining the following:

       EQUATE X SYN 1,   Y SYN 5;

Register synonyms are typically used in the regname form since the actual register number may vary depending on the synonym.

Once the expression has been started, it may be continued by as many occurrences of 'operator iv' as desired. The allowed operators are:

     (a)  Arithmetic (see section 1.3)
          +      addition
          -      subtraction
          *      multiplication
          /      division
          ++     logical addition (unsigned)
          --     logical subtraction (unsigned)
     (b)  Logical (see section 1.6)
          AND    conjunction
          OR     inclusive injunction
          XOR    exclusive injunction
     (c)  Shifting (see section 1.7)
          SHLL   shift left (multiply by 2 raised to iv power)
          SHLA   (same as SHLL)
          SHRL   shift right (divide by 2 raised to iv power)
          SHRA   (same as SHRL)

There is no operator precedence! The expression is evaluated in a strictly left-to-right sequence.

There are a number of pre-declared equates which we shall find useful in the next few chapters. They are shown below using declarations equivalent to the compiler's default declarations.

       EQUATE OVERFLOW SYN 1,  ON SYN 1,  MIXED SYN 4,  OFF SYN 8,
              CARRY SYN 3,  FALSE SYN 0,  TRUE SYN _1;
       EQUATE DATAFILL SYN #87654321;
       EQUATE STRING SYN 0;  |-- varies during compilation --|

The last definition, for STRING, cannot be truly duplicated because the value of STRING varies during compilation. Its initial value is 0, but every time the compiler processes a "string" the value of STRING becomes the length (in bytes) of that "string". DATAFILL is a special value used to assign array size by content.

There is also a SHORT EQUATE declaration that provides SHORT INTEGER equivalents. The values defined will be treated like integers ending in S, such as: #40S, _3S, etc.

       SHORT EQUATE LOMASK SYN #FFF8;
Examples:

       EQUATE A SYN 200,  B SYN A+8,  C SYN 4,
              D SYN A/C AND _4;
       INTEGER S = A;
       ARRAY B BYTE X, Y;
       EQUATE E SYN Y(B)-S,  F SYN E-C SHLL 2;
       INTEGER REGISTER XR SYN R1,  YR SYN R5;
       EQUATE G SYN XR, H SYN YR - G + 1;
       ARRAY H INTEGER SPACE;
       EQUATE I SYN "AB", J SYN STRING;

 A=200         B=208         C=4           D=48          E=420
 F=1664        G=1           H=5           I=#C1C2       J=2

4.8  Sample Declarations

The sample declarations given in this section will be used throughout the remainder of this text, particularly in Chapters 5 and 6.

       BEGIN  INTEGER REGISTER ZERO SYN R0,  TEMP SYN R1,
                               I SYN R7,  J SYN R8,  K SYN R9;
          BYTE C1 SYN B1,  C2 SYN B2,  C3 SYN B3;
          SHORT INTEGER H1 SYN B1,  H2 SYN B2,  H3 SYN B3;

          LONG REAL LRA,  LRB = #4E00000000000000L;
          INTEGER IA SYN LRA(4),  IB SYN LRB(4);
          REAL RA SYN LRA,  RB SYN RA(4);

          INTEGER X, Y, Z;
          SHORT INTEGER S1, S2;
          INTEGER BLANKS = "    ";
          ARRAY 132 BYTE LINE = 132(" ");
          ARRAY 16 BYTE TAB = "0123456789ABCDEF";
          ARRAY 256 BYTE TRTAB SYN TAB(_240);

          EQUATE SQUARES SYN 64,
                 STAKL SYN SQUARES * 3,
                 SPACE SYN SQUARES * 5;
          ARRAY STAKL INTEGER STACK;
          ARRAY SPACE BYTE TABLES;
          BYTE FLAGS SYN TABLES(_1),
               TABLE1 SYN FLAGS(SQUARES),
               TABLE2 SYN TABLE1(SQUARES),
               TABLE3 SYN TABLE2(SQUARES),
               TABLE4 SYN TABLE3(SQUARES);

The tables below list the identifiers given in the declarations on the preceding page into two groups. The first group is arranged by the sort order of the identifiers. The second group is arranged by the order in which the identifiers were declared. For each group, the value the compiler associates with the identifier is also given.

         Sorted order                           Declared order
         ------ -----                           -------- -----

       Identifier  Value                      Identifier  Value

       BLANKS       D068                      ZERO         0000
       C1           1000                      TEMP         0001
       C2           2000                      I            0007
       C3           3000                      J            0008
       FLAGS        D3FF                      K            0009
       H1           1000                      C1           1000
       H2           2000                      C2           2000
       H3           3000                      C3           3000
       I            0007                      H1           1000
       IA           D04C                      H2           2000
       IB           D054                      H3           3000
       J            0008                      LRA          D048
       K            0009                      LRB          D050
       LINE         D06C                      IA           D04C
       LRA          D048                      IB           D054
       LRB          D050                      RA           D048
       RA           D048                      RB           D04C
       RB           D04C                      X            D058
       SPACE    00000140                      Y            D05C
       SQUARES  00000040                      Z            D060
       STACK        D100                      S1           D064
       STAKL    000000C0                      S2           D066
       S1           D064                      BLANKS       D068
       S2           D066                      LINE         D06C
       TAB          D0F0                      TAB          D0F0
       TABLES       D400                      TRTAB        D000
       TABLE1       D43F                      SQUARES  00000040
       TABLE2       D47F                      STAKL    000000C0
       TABLE3       D4BF                      SPACE    00000140
       TABLE4       D4FF                      STACK        D100
       TEMP         0001                      TABLES       D400
       TRTAB        D000                      FLAGS        D3FF
       X            D058                      TABLE1       D43F
       Y            D05C                      TABLE2       D47F
       Z            D060                      TABLE3       D4BF
       ZERO         0000                      TABLE4       D4FF

4.9  Exercise

Problem 1.

The following block contains: two other blocks, three data segments (ALPHA, BETA, DELTA), and six cells (TEST, EXAM, FLAGS, TOPS, EXTRA, LAST).

     |01|    BEGIN  GLOBAL DATA ALPHA BASE R6;
     |02|              INTEGER TEST;
     |03|           GLOBAL DATA BETA BASE R7;
     |04|              INTEGER EXAM;
     |05|       |.... (statement group 1) ....|
     |06|           BEGIN  INTEGER FLAGS;
     |07|               CLOSE BASE;
     |08|                  INTEGER TOPS;
     |09|               |.... (statement group 2) ....|
     |10|           END;
     |11|       |.... (statement group 3) ....|
     |12|           BEGIN  INTEGER EXTRA;
     |13|               GLOBAL DATA DELTA BASE R8;
     |14|                  INTEGER LAST;
     |15|               |.... (statement group 4) ....|
     |16|           END;
     |17|       |.... (statement group 5) ....|
     |18|    END

Problem 2.

On the following page is a complete main program which computes and prints odd-sized magic squares from a 15 by 15 down to a 3 by 3.

|01|  BEGIN  ARRAY 133 BYTE LINE = 133(" ");  |-- OUTPUT LINE AREA --|
|02|     ARRAY 256 INTEGER XX;  |-- SPACE FOR UP TO 16 BY 16 SQUARE --|
|03|     INTEGER SIZE, LIMIT;  |-- SQUARE SIZE AND SUB-SQUARE LIMIT --|
|04|     PROCEDURE MAGIC (R6);   |-- MAGIC SQUARE GENERATOR --|
|05|     BEGIN SHORT INTEGER NSQR;  |-- CURRENT SQUARE SIZE --|
|06|        INTEGER REGISTER N SYN R0, I SYN R1, J SYN R2,
|07|                         X SYN R3, IJ SYN R4, K SYN R5;
|08|        NSQR := N;  I := N * NSQR;  NSQR := I;
|09|        I := 1 + N SHRL 1;  J := N;
|10|        FOR K := 1 STEP 1 UNTIL NSQR DO
|11|        BEGIN  IJ := I SHLL 4 + J SHLL 2;
|12|           X := XX(IJ-68);  IF X ~= 0 THEN
|13|           BEGIN I := I - 1;  J := J - 2;
|14|              IF I <= 0 THEN I := I + N;
|15|              IF J <= 0 THEN J := J + N;
|16|              IJ := I SHLL 4 + J SHLL 2;
|17|           END;  XX(IJ-68) := K;  I := I + 1;
|18|           IF I > N THEN I := I - N;
|19|           J := J + 1;  IF J > N THEN J := J - N;
|20|        END;
|21|     END;
|22|
|23|  |-- MAIN PROGRAM CODE STARTS HERE --|
|24|     R0 := 15 =: SIZE;   |-- ESTABLISH INITIAL 15 BY 15 --|
|25|     WHILE R0 > 1 DO  |-- MAIN LOOP FOR SQUARE GENERATION --|
|26|     BEGIN  R1 := 16 - SIZE SHLA 2 =: LIMIT;
|27|        XX := 0;  XX(4/256) := XX;     |-- ZERO OUT --|
|28|        XX(260/256) := XX;             |-- THE WORK --|
|29|        XX(516/256) := XX;             |--  SPACE.  --|
|30|        XX(772/252) := XX;
|31|        R0 := SIZE;  MAGIC;   |-- FORM MAGIC SQUARE --|
|32|        R2 := 1;  R4 := R4-R4;  R7 := R4;  R3 := 5;
|33|        R6 := SIZE;  WHILE R4 < R6 DO  |-- OUTPUT LINES --|
|34|        BEGIN  R1 := @LINE;  R5 := R5-R5;  WHILE R5 < R6 DO
|35|           BEGIN R0 := XX(R7);  VALTOBCD;  R5 := @B5(1);
|36|              R7 := @B7(4);  R1 := @B1(R3);
|37|           END;  R0 := @LINE;  WRITE;  R7 := R7 + LIMIT;
|38|           R4 := @B4(1);  |-- BUMP LINE COUNTER --|
|39|        END;  LINE := " ";  LINE(1/132) := LINE;
|40|        R0 := @LINE;  WRITE;  |-- WRITE BLANK LINE --|
|41|        R0 := SIZE - 2 =: SIZE;  |-- REDUCE SIZE BY 2 --|
|42|     END;  |-- OF MAIN WHILE LOOP --|
|43|  END.

5  Assignment Statements

This chapter and the next cover the majority of all statements used in a PL360 program. Each statement is normally terminated by a semicolon; however, a semicolon is not part of the formal definition of a statement, and therefore many examples of statements will not include the terminating semicolon. The reason for this will become clear when we examine the IF statement in the next chapter.

This chapter covers all PL360 assignment statements. An assignment statement is recognizable by its characteristic form:

item := expression

where 'item' is either a register identifier or a cell reference, and ':=' is the assignment operator that may occur only once in any assignment statement.

An assignment statement is read as follows: 'item' is assigned the value of the 'expression'; that is, the contents of 'item' becomes the value of the 'expression'. The permissible forms of 'expression' depend on the type of 'item'; but it is important to note that every 'expression' is evaluated in a strictly left-to-right sequence and that the contents of 'item' changes at each step in the evaluation. This is quite different from languages such as FORTRAN where the 'expression' is completely evaluated before its value is assigned to the 'item'.

For example, the FORTRAN statement I = J + I is done as follows:

"Take the current value of J and add to it the current value of I; now place the result of the computation into I."

The PL360 statement I := J + I is done as follows:

"Take the value of J and place it into I; now take the value in I and add it to the value in I, i.e., double the value in I."

As you can see the two methods may lead to entirely different results for the final value left in I. The correct PL360 statement that accomplishes the same result as the FORTRAN statement would be:

       I := I + J

In section 4.8, I and J were declared as integer register synonyms for R7 and R8 respectively; therefore, the above statement is equivalent to:

       R7 := R7 + R8

The PL360 statement R7 := R8 + R7 is equivalent to the two statements

       R7 := R8;  R7 := R7 + R7;

5.1  Register Assignment Statements

There are three types of register assignment statements corresponding to the three types of registers: INTEGER, REAL, and LONG REAL. In general, the 'expression' following the assignment operator (:=) consists of one or more terms separated from each other by operators other than the assignment operator; that is,

register := term1 op term2 ... op termn

register := term

Each term may either be a constant value or specify the contents of a designated register or cell. Terms must be of compatible type to the assigned register; that is, INTEGER registers with INTEGER and SHORT INTEGER terms, REAL registers with REAL terms, and LONG REAL registers with REAL and LONG REAL terms.

The first term immediately following the assignment operator may be preceded by one of the monadic operators ABS, NEG, and NEG ABS which indicate taking the absolute value, sign inversion, or sign inversion of the absolute value of the first term, then placing the resulting value into the assigned register. If the first term is not preceded by a monadic operator and is not the same as the assigned register, then the value or contents of the designated register or cell is placed into the assigned register. Thus,

     R1  := R2       place contents of register R2 into register R1
     J   := X        place contents of cell X into register J
     R3  := 50       place the value 50 into register R3
     F0  := 1R       place the value 1.0 into register F0
     F23 := NEG LRB  place the complement of the contents of cell LRB
                     into register F23

The assignment operator causes the generation of zero, one, or two instructions depending on the term which follows the assignment operator and the use or non-use of monadic operators. The following examples illustrate the cases:

     R1 := R1        no instruction because same register on both sides
     R1 := R2        one instruction, load R1 from R2
     R1 := X         one instruction, load R1 from cell X
     R1 := NEG R1    one instruction, complement contents of R1
     R1 := NEG R2    one instruction, load R1 with complement from R2
     R1 := 5000      one instruction, load R1 from a cell containing
                         the integer constant 5000
     R1 := NEG X     two instructions; first instruction corresponding
                         to  R1 := X;  second instruction corresponding
                         to  R1 := NEG R1

As a shorthand for 'register := register op term2 ...' where register is the same on both sides of the assignment operator, PL360 allows 'register op term2 ...' as the definition of a register assignment statement; that is, R1 := R1 can be shortened to R1 only. However, this shorthand form is not recommended since it lacks the clarity of the long form.

5.1.1  Integer Register Assignments

When the assigned register is an integer register, then all terms must be integer or short integer values or cells, or integer registers. The first term immediately following the assignment operator may be preceded by a monadic operator, ABS, DEC, NEG, or NEG ABS. ABS results in the absolute value of the term (zero or positive). DEC results in the value of the term reduced by 1. NEG results in the negation of the term, with positives becoming negative, negatives becoming positive (except for the largest negative), and zero remaining zero. NEG ABS results in the negation of the absolute value of the term (zero or negative).

The first term immediately following the assignment operator may also be one of the following, but they may not be preceded by the monadic operators:

     (a)  "string"       (string of 4 or fewer characters)
     (b)  @ Procname     (Procname is a known PROCEDURE name)
     (c)  @ cell         (cell may be of any type: BYTE, REAL, etc.)
       R1 := "WORD"  is equivalent to  R1 := #E6D6D9C4
     and
       R1 := "2"     is equivalent to  R1 := #000000F2  or  R1 := #F2
       R4 := NEG 4;  |--  R4 = _4 --|
       R9 := #6500;  |--  R9 = some address --|
     then
       R1 := @B9(R4+8);   |--  R1 = #6504 --|

The result in R1 is the same as the address calculation given in section 1.4. If the statement had been R1 := B9(R4+8) then R1 would be assigned the 4-byte contents of the cell whose address was #6504.

Since B1, B2, etc. are cell names corresponding to a D-field of 0, an X-field of 0, and a B-field specifying R1, R2, etc., then the use of the address operator (@) before these cell names simply implies doing address arithmetic with the B-field integer register. Modification of such cell names by a displacement or index register results in nothing more than additive arithmetic. Generally, it is more economical to increment integer register contents by using address arithmetic rather than by using straight addition. For example:

       R1 := @B1(4)     adds 4 to the contents of R1
       R2 := @B2(R1+8)  adds R1+8 to the contents of R2
       R3 := @B2(R1+8)  adds R1+8 to R2 and places result in R3

The examples above could just as well have been done as follows:

       R1 := R1 + 4
       R2 := R2 + R1 + 8
       R3 := R2 + R1 + 8

The major difference between the two methods is that the address arithmetic involves only a single 'load address' instruction and no memory references for constants in the literal pool. The other method takes a constant in the literal pool, and therefore a memory reference, and in the last two cases it takes more instructions. So @-operator arithmetic is more economical providing the following conditions are accepted:

   (1)  The result of the address computation is always greater than or
        equal to 0 and less than 2'24.  This means that the top byte of
        the result will always be 00 hexadecimal.  If a negative result
        is possible, @-operator arithmetic is not appropriate.

   (2)  Addition or subtraction of integer constants must not  violate:
        0 <= ddd < 4096.   Addition or subtraction of constants outside
        that range is not allowed by @-operator arithmetic.

   (3)  Not  more  than  two  integer  registers  may  participate   in
        @-operator  arithmetic, and only integer registers are allowed.
        Addition is the only allowed operation.  Subtraction cannot  be
        done using @-operator arithmetic.

   (4)  Address arithmetic never affects the machine 'condition code'.

Now at first glance, these restrictions seem to eliminate a lot of cases; but in actual fact, much of the arithmetic involving integer registers can be done with @-operator arithmetic. Consider a simple loop through an array of integer cells where an index register is incremented by 4 each time in the loop; such as, R1 := @B1(4). This is just one of many pos