BLISS-11
PROGRAMMERS MANUAL


SOFTWARE SUPPORT CATEGORY

The software described in this document is not supported by Digital
Equipment Corporation. It is currently available upon request from
the Computer Science Department, Carnegie-Mellon University,
Pittsburgh, PI. 15213, subject to their own distribution and support
procedures.

First printing, December 1972
Second printing, March 1973
Third printing, April 1974 (revised)


Copyright (C) 1972, 1973, 1974 by Digital Equipment Corporation


This document is for information purposes and is subject to change
without notice.


The following are registered trademarks of Digital Equipment Corporation:

Digital (logo)	PDP-11
DEC			Comtex-11
DECtape		RSTS-11
RSX-I1		Unibus

ACKNOWLEDGEMENT
---------------


Many persons have made significant contributions to the design and
development of the BLISS-11 language and its compiler.  The
cooperation of faculty, staff, and graduate students at
Carnegie-Mellon University is possible in part because of a
Department of Computer Science orientation that pursues research
and advanced development efforts of relevance to the total
community, public and private. Digital Equipment Corporation
acknowledges the considerable work performed by the members of
the Department of Computer Science in bringing BLISS-11 into
being. Prime contributors are:

	Jerry L. Apperson
	Charles M. Geschke
	Steven O. Hobbs
	Richard K. Johnsson
	Paul J. Knueven
	Bruce W. Leverett
	Charles B. Weinstock
	David S. Wile
	William A. Wulf

Department of Computer Science
Carnegie-Mellon University
Pittsburgh, Pennsylvania

Ronald F. Brander
Mario R. Pellegrini

Digital Equipment Corporation
Maynard, Massachusetts
TABLE OF CONTENTS


          INTRODUCTION

1.0       LANGUAGE DEFINITION                                2

1.1       BLISS - An Expression Language                     2

1.2       Expressions                                        2

1.3       Simple Expressions                                 3
1.3.1       Order of Expression Evaluation

1.4       Names                                              10

1.5       The "Contents of" Operator                         10

1.6       Data Representation                                11

1.7       Comments                                           12

1.8       Modules                                            12

1.9       Blocks                                             13

1.10      Literals                                           13

1.11      Pointers to Literals                               15

1.12      Position and Size Modifier                         16

1.13      Interlude                                          23

1.14      Control Expressions                                23

1.15      Conditional Expressions                            23

1.16      Loop Expressions                                   24

1.17      Escape Expressions                                 26

1.18      Choice Expressions                                 27
1.18.1      CASE Expression
1.18.2      SELECT Expression
1.18.3      Compile-time Constant Conditional and
            Choice Expressions

1.19      Coroutine Expressions [not implemented]           30

1.20      Declarations                                      30

1.21      Storage (An Introduction)                         31

1.22      Routines                                          32
1.22.1      GLOBAL Routines
1.22.2      EXTERNAL and FORWARD Routine Declarations
1.22.3      Calling Sequence Declarations
1.22.4      Predefined Calling Sequences
1.22.5      Calling Sequences for Variable Routine Names

1.23      Data Structures (An Introduction)                 38

1.24      Data Structures (Actual Syntax)                   41
1.24.1      Structures
1.24.2      Structure Accesses for Variable Segment Names
1.24.3      Memory Allocation
1.24.4      MAP Declaration
1.24.5      BIND Declaration

1.25      LABEL Declaration                                 46

1.26      UNDECLARE Declaration                             46

1.27      ENABLE Declaration                                46

1.28      Macros                                            47
1.28.1      Syntax For Macro Declarations
1.28.2      Macro Forms and Special Functions
1.28.3      Macro Forms and Examples
1.28.4      Default Separators
1.28.5      Special Functions

1.29      CSECT and PSECT Declarations                      55

1.30      REQUIRE Declaration                               55

1.31      SWITCHES Declaration                              56


          SPECIAL LANGUAGE FEATURES                         57

          Special Routines                                  57
2.1.1       TRAP, EMT and IOT
2.1.2       HALT, RESET and WAIT
2.1.3       SWAB

2.2       INLINE - Machine Language in BLISS-11             58


3.0       SYSTEM FEATURES                                   59

3.1       Command Syntax                                    59

3.2       Compiler Options                                  59

3.3       Error Reporting                                   63


4.0       RUN TIME REPRESENTATION OF PROGRAMS               64

4.1       Introduction To Gelling Sequences                 64

4.2       BLISS-11 Internal Linkage                         64

4.3       BLISS-11 With Arguments Passed In Registers       65

4.4       FORTRAN Linkage [not implemented]                 65

4.5       INTERRUPT Linkage                                 66

4.6       EMT/TRAP Linkage                                  67

4.7       Access To Variables                               67

4.8       Coroutine Creation end Calls                      67


5.0       EXAMPLES                                          68


Appendix A - BLISS-11 Syntax                                72

Appendix B - Description of Non-Terminals of BLISS-11 BNF   76

Appendix C - Reserved Names                                 84

Appendix D - Predefined Identifiers                         85

Appendix E - RADIX 50 (RAD5O)                               86

Appendix F - Error Messages                                 87


INDEX                                                       89


Too little do we realize what a hindrance a language of
antiquated structure is. Such a language does not help, but
actually prevents correct analysis through the semantic
habits and structural implications embodied in it.

Alfred Korzybski
Science and Sanity

INTRODUCTION

BLISS-11 is a programming language for the PDP-11. It is
specifically intended to be used for implementing
"System Software". As such it differs from other languages
in several significant ways.

1   Higher level languages derive their suitability for
    a particular problem area - FORTRAN/ALGOL for mathematics,
    SNOBOL for strings, GPSS for simulations, etc., - because they
    provide to the user a vocabulary and set of conventions
    appropriate to that problem area. We view "Implementation
    Languages" in a similar way - as application languages where
    the application is a particular brand of hardware. As such,
    an implementation language must reflect the capabilities and
    architecture of its machine, and not block or frustrate the
    programmer's use of these capabilities.

2   Input/output is not a part of BLISS-11. I/O can be done
    directly in the language much as an assembly program might,
    or through subroutine calls.

3   Every attempt has been made to give the user explicit control
    over the code his program generates, while providing maximum
    convenience otherwise.

4   There are no explicit or implicit data modes other than the
    16 bit binary word. Data modes are essentially user defined
    via the STRUCTURE* mechanism which allows the user to define
    an algorithm for data access.

Clearly BLISS-11 is a close relative of BLISS-10 for the
DECsystem-10 and shares much of that language's philosophy
toward treatment of identifiers, absence of GOTO statements,
importance of structures, etc. The interested reader may find
it useful to examine the differences between the two languages
and how these are a reflection of the differences in the
machines themselves.

----------
*Words in uppercase represent reserved words in BLISS-11 (terminal
symbols in the language), but in programs the compiler treats upper
and lower case letters as equivalent and thus recognizes names
and reserved words in either case.
----------

1.0 LANGUAGE DEFINITION

1.1 BLISS - An Expression Language

The programming language BLISS enables programmers (persons who
converse in a programming language) to construct text (programs)
which evoke computations to transform input into a desired result.
Programs written in BLISS consist of declarations (which establish
structure) and expressions sequenced to compute results.
Expressions in BLISS can assume remarkably complex forms built
up from elementary forms; but regardless of their complexity every
expression computes a value. This notion, that a BLISS program
consists solely of declarations and expressions, and that these
expressions can become arbitrarily complex yet compute a single
value during the execution of the program, represents a key
concept the reader must understand to properly construct BLISS
programs and fully exploit the language's power. The concept of
a statement prevalent in many programming languages has little
meaning in BLISS. In reading this manual the reader should
strive to master the implications and meaning of the statement:

	'BLISS is an expression language'.

1.2 Expressions

Every executable form in the BLISS language (that is, every form
except the declarations) computes a value. Thus all commands are
expressions. In the syntax description E is used as an
abbreviation for expression.

	E ::= smpl-expr* / cntrl-expr

Note:
Section 1.3 lists all the simple expressions (smpl-expr) in
BLISS-11. This list appears with full knowledge that the reader
does not yet know the semantics of many of the operators. In doing
so we have presumed on the sophistication of our readers and depend
on them to fill in the gaps usually provided in documents with a
tutorial intent. The discussion of control expressions
(cntrl-expr) will appear in sections 1.14-1.19 after discussing
a sufficient number of the components making up simple
expressions (block, literal, name, etc.) to permit the
construction of some simple programs.

----------
*This manual will use a form of syntax specification similar to
BNF, differing from it by its absence of angle brackets <> to
enclose non-terminals in the language. We shall indicate
non-terminals by using lower case characters. Appendix B
contains definitions of non-terminals used throughout the manual.
-----------

1.3 Simple Expressions

The semantics of simple expressions (smpl-expr) is most easily
described in terms of the relative precedence of a set of
operators, but readers should also refer to the BNF-like
description at the end of this section. The syntax definition
implies that binding must take place in the precedence order
given below. The precedence number used should be viewed as an
ordinal, so that 1 means first and 2 second in precedence. In
the following table the letter E has been used to denote an
actual expression of the appropriate syntactic type, see
Appendix A.

The basic building block of simple expressions is the primary.
The primaries in BLISS-11 are:

	Blocks (including compound and parenthesized expressions)
	Routine Calls
	Structure Accesses
	Names
	Literals

Each primary is itself a simple expression. Blocks, routine calls
and structure accesses can be built up out of other expressions.

Other simple expressions are built up by applying operators to
primaries and to simple expressions that have already been formed.

Operators are applied in precedence order. In most cases, operators
of equal precedence are applied in left to right order. The
operators dot, unary plus, unary minus, NOT, and the store
operators (= and <--) are applied in right to left order.
(However, see discussion of side effects in Section 1.3.1)

Precedence Example(s)          Semantics

1	    (E0;E1;...En)       A block. This includes the
                               important subcases of compound
                               expression and parenthesized
                               expression. The component
                               expressions are evaluated from left
                               to right and the final value is that
                               of the last component expression.
                               Note the absence of a trailing
                               semicolon. If such a semicolon
                               appears then En is the empty
                               expression and has the value zero.

1        E0(E1,E2,£££,En)      A routine call, see 1.23.

1        name[E1,E2,...,En]    A structure access, see 1.24.

1        name                  A pointer, see 1.4.

1        13, #46, "A"          A literal. Value of the converted
                               literal, see 1.10.

Note: All precedence 1 items are primaries.

2        .E                    The "contents of" E. Value pointed
         £E<E1,E2>             at by E, possibly modified by
                               position and size E1 and E2. (E1
                               and E2 must evaluate to compile
                               time constants*.)

3        -E                    Unary minus. The negative of E.

3        +E                    Unary plus. E.

4        E1^E2**               E1 shifted arithmetically by EP
                               bits. Shift to left if Ep is positive,
                               to right if negative.

4        E1 ROT E2             Rotate E1 by E2 bits. Rotate left
                               if E2 is positive, right if negative.
                               This operator rotates 17 bits.***

5        E1*E2                 Product of E's.

5        E1/E2                 E1 divided by E2.
         E1 DIV E2

5        E1 MOD E2             E1 module E2.

6        E1+E2                 Sum of E's.

6        E1-E2                 Difference between E1 and E2.

7        E1 MAX E2             The greater of E1, E2£

7        E1 MIN E2             The lesser of E1, E2.

Note: All arithmetic is carried out module 2^16 with a residue
of -2^15 All arithmetic is integer.

Note: For all relational operators (precedence=8), the resultant
value is 1 if the relation holds and O if it does not. (See
Section 1.6)

----------
*see section 1.18.3 for a detailed discussion of compile-time
constants and their use.

**The characters up-arrow, and caret are treated identically,
as are back-arrow and underscore.

***The ROT operator is defined by the PDP-I1 ROR and ROL machine
language instructions; thus the carry bit is included in the
quantity rotated.
----------

8         E1 EQL E2            E1 "equal to" E2.

8         E1 NEQ E2            E1 "not equal to" E2.

8         E1 LSS E2            E1 "less than" E2.

8         E1 LEQ E2            E1 "less than or equal to" E2.

8         E1 GTR E2            E1 "greater than" E2.

8         E1 GEQ E2            E1 "greater than or equal to" E2.

Note: The following relational operators are unsigned versions of
the above; i.e. they treat E1 and E2 as 16 bit unsigned integers.

8         E1 EQLU E2

8         E1 NEQU E2

8         E1 LSSU E2

8         E1 LEQU E2

8         E1 GTRU E2

8         E1 GEQU E2

9         NOT E                Bitwise "complement" of E.

10        E1 AND E2            Bitwise "and" of E's.

11        E1 OR E2             Bitwise "inclusive or" of E's.

12        E1 XOR E2            Bitwise "exclusive or" of. E's.

12        E1 EQV E2            Bitwise "equivalence" of E's.

13        E1 = E2              Store E2 in E1. The value of this
          E1<E3,E4>=E2         expression is identical to that of
                               E2, but as a side effect this value
                               is stored into the partial word
                               pointed to by E1. Assignments are
                               executed from right to left: thus
                               E1 = E2 = E3 is equivalent to
                               E1 = (E2 = E3).

Note: Position and size (E3 and E4) are associated with the store
operator in this case and they modify the effect of the store (see
Section 1.12).

The reader should refer to a PDP-11 Processor Handbook for complete
definition of the arithmetic operators under various special input
value conditions.

The syntax for BLISS-11 simple expressions is as follows:

smpl-expr   ::= P12 / P12=E / pt pos-size = E

P12         ::= P11 / P12 XOR P11 / P12 EQV P11

P11         ::= P10 / P11 OR P10

P10         ::= P9 / P10 AND P9

P9          ::= P8 / NOT P9

P8          ::= P7 / P8 rel-op P7

P7          ::= P6 / P7+P6 / P7-P6

P6          ::= P5 / P6*PS / P6 DIV P5 /
               P6/P5 / P6 MOD P5

P5          ::= P4 / P5^P4 / P5 ROT P4

P4          ::= P3 / +P4 / -P4

P3          ::= P2 /.P3

P2          ::= P1 /.P2 pos-size

pi          ::= literal/ name / strc-access /
               block / routn-call

pos-site    ::= <position,size>

position    ::= compile-time-expr

size        ::= compile-time-expr

rel-op      ::= EQL / NEQ / LSS / LEQ / GTR / GEQ /
                EQLU / NEQU / LSSU / LEQU / GTRU / GEQU

strc-access ::= name[expr-lst] / name[alloc-unit expr-lst;expr-lst]

routn-call  ::= Pl(expr-lst) / P1( )

The following are legal (if somewhat unusual) BLISS-11 expressions.

	.A<0,16><0,8>=.B

	NOT NOT .A

	..(.A<0,1 6>)<0,8>

	A(.X,1,.Y)(.M,.N)

1.3.1 Order of Expression Evaluation*

BLISS-11 has two potential side-effect producing operations:

    1. The assignment operator, and
    2. Routine calls (which can produce side effects by internally
       contained assignments and routine calls.)

The order of expression evaluation is only partly specified in
BLISS-11. Whenever the order is not fully specified, the compiler
is free to complete the specification in any way it chooses.

A dangerous side-effect occurrs if the result of expression
evaluation depends upon the order in which the expression was
evaluated. This can only happen if the same variable appears
more than once in the expression (explicitly or implicitly)
and is altered at least once during expression evaluation.
For example, the expression

	(R=2; £R*(R=3))

may evaluate to 6 or 9 depending an which of the expressions .R
or (R=3) is evaluated first. Problems of this type are usually
resolved by establishing order-of-evaluation rules.

To describe these rules in BLISS-11, we must consider five
different kinds of orderings:

    Lexical order (the ordering of program text);

    Order imposed by operator precedence and parentheses;

    The order (if any) observed with respect to sub-expressions
    of commutative operators (e.g. +, *, AND, etc.);

    The 'essential' order observed with respect to expressions
    which produce 'side-effects' (specifically, assignments and
    routine calls).

    The evaluation rules for expressions whose values may be
    uniquely determined without evaluating the entire expression.

BLISS-11 applies rules to these cases as follows:

Case 1
	The lexical order is determined by the programmer.

Case 2
	The effect of operator precedence (hierarchy) and parentheses
	(grouping), subject to the definitions in Cases 3 and 4 below, will
	be observed.

----------
*This section logically belongs here, but contains examples that
presume knowledge of other sections, in particular 1.4 and 1.5;
on a first pass the reader may find it useful to read these
sections before proceeding with 1.3.1
----------

Case 3
	Mathematically commutative operators are assumed to have
	computational commutativity as well. Thus E1+E2 may compile as
	E1+E2, or E2+E1.

Case 4
	Side-effects are accounted for only at certain prescribed "mark
	points" in an expression. Thus, for example, a ";" within a
	compound expression is a "mark point", and all side-effect
	producing operations lexically to the left of the ";" within the
	enclosing compound are completed prior to evaluation of
	expressions to the right of the ";". The following "mark points"
	are currently defined in BLISS-11:
	      - ";" in a compound expression
	      - ")" in a routine call parameter list
	      - The end of each expression component in a loop
	        expression, conditional expression or choice expression
	      - ":" in an ENABLE declaration.

Case 5
	Expression evaluation occurs only to the point necessary to
	uniquely determine the expression value.

The compiler may make other re-arrangements but they are guaranteed
to observe the rules stated above.

These rules permit more code re-arrangement than typically found
in higher-level languages. There are two reasons for this:

	1. The compiler can produce considerably better code if
	   allowed more freedom, and
	2. The rules tend to eliminate the use of programming
	   techniques containing hidden side-effects since the
	   programmer himself cannot predict the outcome when
	   employing such techniques. Programs with hidden
	   side-effects are often difficult to understand and modify.

The elimination of expressions which produce unpredictable results
does require some diligence from the programmer, but the
circumstances which give rise to potentially ambiguous results
occur rarely in practice, are easily recognized, and their
elimination represents good programming practice.

Two contexts can produce unwanted side-effects, unpredictable
results, or both.

Context 1 occurs in the following situations:

	1. An assignment expression is nested in a larger expression
	   that uses the contents of the variable assigned to in the
	   inner expression.
	2. A routine is called which alters the contents of a variable
	   which is used elsewhere in the same expression as the
	   routine call. The side effects caused by routine calls can
	   arise from assignment to GLOBAL variables or indirect
	   assignments.

Examples of Context 1

<1>	   X=.X*(X=2)
	   BLISS-11 can freely decide which of the two components in
	   the simple expression .X*(X=2) it will evaluate first since *
	   is a communtative operator. The outcome clearly depends
	   on the order of evaluation and the programmer must
	   consider it unpredictable.

<2>	   X=G(.X)+F(X)+.X
	   Here F(X), passed a pointer to X, may change X and if it
	   does the value of entire expression depends on the order
	   of evaluation. Since the + operator is commutative, this
	   construct must be viewed by the programmer as having an
	   unpredictable outcome.

The cautions are simple. Suspect any expressions which

	1. Contain store operations on variables used elsewhere in the
	   expression.
	2. Contain routine calls containing un-dotted names of variables
	   appearing elsewhere in the expression.

Context 2 occurs when a side-effect producing sub-expression may
not be needed to determine the value of the overall expression.

Examples of Context 2
<1>	   X=.A GTR .B AND (C=5) LSS F(B)
	   BLISS-11 will perform expression evaluation only to the
	   point at which it can uniquely determine a result. In the
	   above expression both the order-of-evaluation and the
	   outcome can affect the result.

	   If, for example, .A is in fact less than .B, and if the
	   compiled code evaluated this result first, then F(B), which
	   may change B, is not executed, thus eliminating a possibly
	   assumed side-effect.

	   On the other hand, if the boolean (C=5) LSS F(B) is
	   executed first, and if F(B) changes B then the outcome of
	   the test .A GTR .B is clearly affected, possibly
	   unpredictably.

<2>	   X=O*(Y=1)
	   Here X will always equal zero, but depending on order of
	   evaluation, Y may remain unchanged (since the value of X is
	   always uniquely determined here) or set equal to 1.

The caution simply exhorts the programmer to beware of expressions
whose value can be uniquely determined by the evaluation of a
sub-expression contained within it. Failure to do so may result in
an assumed side-effect not occurring.


1.4 Names

Syntactically an identifier, or name, is composed of a sequence
of letters and/or digits, the first of which must be a letter or
the character $. Identifiers may be of arbitrary length, however,
only the first ten characters are treated as significant. Since
other PDP-11 support software only recognizes six characters, care
must be taken with EXTERNAL and GLOBAL identifiers. Certain names,
such as BEGIN, EQV, etc., are reserved as delimiters (See
Appendix C). Semantically the occurrence of a name is exactly
equivalent to the occurrence of a pointer to the named item. The
term "pointer" will take on special connotation later with
respect to contiguous sub-fields within a word; however, for the
present discussion the term may be equated with "address". This
interpretation of name is uniform throughout the language and
there is no distinction between left and right hand values. Note
that a name belongs to the class of simple expressions, has a
position in the precedence hierarchy, and computes a value,
namely, the address associated with the name.

Some identifiers are initially declared in the BLISS-11 compiler.
These identifiers, given in Appendix D, may be redefined by the
programmer. They are not reserved words.


1.5 The "Contents of" Operator

Since a name always evaluates to an address, and typically a
programmer wants to manipulate the datum stored at the address,
the language must provide some notation for accessing the contents
of memory; in BLISS-11 this takes the form of the "contents of",
or "dot" operator signified by a period "." prefixing an expression.

The operator "." is a unary operator used to designate the contents
of the location named by its operand. That location may be in main
memory or one of the registers. Thus if "X" is the name of a word
of memory, then ".X" names its contents, and "..X" names the
contents of the word pointed at by the contents of location X.
Similarly, if R is a register name, then ".R" designates the
contents of that register.

To further illustrate this basic BLISS-11 concept consider the
assignment expression

	A=.B

In this expression we have two names, A and B, and two operators .
and =. To determine the value of this expression we use the
precedence rules of section 1.3. First we derive values for the
names (highest precedence). This yields the address of A and the
address of B. Then we apply the dot operator to the value of B;
thus, we derive the contents of B as the value of .B. Then we
apply the store operator, =, to the two values thus computed.
The store operator causes the value on the right hand side to be
stored into the location pointed to by the value on the left
hand side. Algorithmically, A=.B becomes

	1.  Derive value of A (a pointer)
	2.  Derive value of B (a pointer)
	3.  Apply dot to value derived in 2. (contents of B becomes
	    new value)
	4.  Apply store operator to values derived in 1 and 3. (store
	    contents of B into address specified by A)

This simple example illustrates the semantics of the operators =
and . and how simple expressions build more complex expressions.
To carry complexity a step further consider the construction

	D=(A=.B)

which represents a valid BLISS-11 construction. To determine the
semantics view it as two expressions, D and (A=.B), connected by
the store operator. The value of an expression involving the store
operator takes on the value of the right hand side, so, (A=.B) has
a value equal to the contents of B. Thus the entire expression
results in storing the contents of B into A and D. Similarly,

	A=B=C=D=O

will initialize the four variables, A, B, C, and D to O. (Store
operators are left associative).

To understand BLISS the reader must master the concept that every
BLISS expression computes a value.

Note: BLISS-11 recognizes two characters for the store operator, <--
and =, This manual, however, uses = exclusively to represent the
store operator.


1.6 Data Representation

All word values are normally treated as two's-complement signed
integers. Certain operators, e.g. dot and the unsigned relational
operators, treat the word as an unsigned integer value.

All quantities which are specified by position and size modifiers
(see Section 1.12) and which are less than a full 16-bit word are
treated as unsigned integers. In particular byte quantities are
normally treated as unsigned integers ranging between O and 255 in value.

All Boolean tests (in conditions and loop expressions) depend on
the low-order bit of the word or field being tested. The
relational operators generate a full word 0 or 1 as their
value, when required to yield a value. Zero represents falsity,
and one represents truth.

All bitwise operations (AND, OR, NOT, XOR, EQV) treat their
operands as bit strings.

1.7 Comments

	comment   ::= ! string-no-eol-sym eol-sym/
		       % string-no-pct %

Comments may be enclosed between the symbol ! and the end of the
line on which the ! appears or between paired % symbols. However,
a ! may appear in the quoted string of a literal, or between two %
symbols, without being considered the beginning of a comment.
Likewise, a % enclosed within quotes will be considered part of
a string. A % contained between an ! and the end of the line will
also be ignored. Paired - % comments may extend over several lines.

Examples:

	! Start a comment
	% Hurrah for Karamazov! %
	! the GNP declined 3%


1.8 Modules

A module is a program element which may be compiled independently
of other elements and subsequently loaded with them to form a
complete program.

	module		::= E / MODULE module-head E ELUDOM
	module-head	::= name ( mdle-parms ) = / name =
	mdle-parms	::= mdle-parm / mdle-parm , mdle-parms
	mdle-parm	::= See Section 3.2 for list of options

A module may request access to variables and routines declared in
other modules by declaring their names in EXTERNAL declarations. A
module permits general use of its variables and ROUTINES in other
modules by means of GLOBAL declarations. These lines of
communication between modules are completed by the linker prior
to execution. A complete program consists of a set of compiled
modules linked by the loader.

The mdle-parms of a module definition are used to control the
compilation. See Section 3.2 for a descriptive list of available
options and their defaults.

	Example:

		MODULE START(MAIN,NOLIST)=
		BEGIN
		...
		END
		ELUDOM

1.9 Blocks

A block consists of an arbitrary number of declarations followed
by an arbitrary number of expressions all separated by semicolons
and enclosed in a matching BEGIN-END or "(" - ")" pair.

	block		::= BEGIN blockbody END / ( blockbody )
	blockbody	::= decls ; exprs / exprs
	decls		::= decl / decl ; decls
	exprs		::= E / label : exprs / E; exprs / empty*

Compound expressions (i.e. blocks with no declarations; decls is
empty) form an important subclass of blocks.

The block indicates the lexical scope of the names declared at its
head.

The lexical scope of a name declared in a given block is that
entire block with the exception of inner blocks containing an
explicit re-declaration of the same name, or loop-expressions
(see Section 1.16) which use the name as a loop control variable.
Names of variables and ROUTINES declared as GLOBAL follow this
same rule. In addition such variables and routines may be
referenced by other modules in scopes where they are declared
EXTERNAL.

.10 Literals

The basic data element of BLISS-11 is the 16 bit word.
Literals are normally converted to a single word, but may
in fact end up being truncated to fewer bits if the use of
the literal requires less than 16 bits.

----------
*The string <empty> will mean that the construct in question has
the empty string as an alternative; i.e. a valid option is to
omit it.
----------

	literal       ::= string / number / plit
	string        ::= string-type quoted-string
	string-type   ::= ASCII / ASCIZ / RADIX50 / RAD50 / empty (=> ASCII)
	quoted-string ::= "strng" / 'strng'
	number        ::= decimal / octal
	decimal       ::= digit / digit decimal
	octal         ::= #oits
	oits          ::= oit / oit oits
	oit           ::= 0 / 1 / 2 / 3 / 4 / 5 / 6 / 7
	digit         ::= 0 / 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9
	strng         ::= A sequence of characters

Numbers (unsigned integers) are converted to binary modulo the size
of the data required in the context. This implies truncation for any
number which exceeds the precision of the data size. No warning is
given in these cases. Octal constants are indicated by a sharp
sign, #. String literals may be used to specify constants coded
in ASCII or RAD50 code.

The ASCII string-type converts the quoted-string following the
keyword ASCII into ASCII characters. ASCIZ creates an ASCII
string which has an ending byte equal to zero. BLISS-11 will
allocate one byte per character in increasing memory address order.

RADIX50 (or equivalently RAD50) packs three characters into 16
bits. The quoted-string following RADIX50 may only contain
characters from the set <A-Z>,<O-9>,<$>,<.>, and <space>. See
Appendix E for the definition of PDP-11 RADIX50 code.

If no string-type is given then BLISS-11 assumes ASCII. Within
paired double quotes, single quotes may appear freely and within
single quotes, double quotes may appear freely. The appearance of
two successive occurrences of the bracketing pair of quotes
produces a single instance of the character; hence "'A" and '''A'
both produce the word containing 'A.

All quoted-strings (when used as a literal) must fit into a
single 16 bit word. Strings of characters which exceed one word
in length may be created in plits (see Section 1.11).

In strngs ? is used as an "escape" character. The single character
immediately following a ? is interpreted as follows:

	?O             null
	?1             rubout
	??             ?
	?A         =   CONTROL-A
	...
	?Z         =   CONTROL-Z
	?SHIFT-K   =   CONTROL-SHIFT-K , etc.

Thus ?I is interpreted as a tab character and ?J is interpreted
as a line-feed character.


1.11      Painters to Literals

A "plit" is a pointer to a literal word whose contents are
specified at compile time and established at load time; e.g.,
PLIT 3 is a pointer to a word whose contents will be set to 3
at load time.

	plit           ::= PLIT plitarg / UPLIT plitarg
	plitarg        ::= load-time-expr / string / tuple
	tuple          ::= (tuple-item-lst)
	tuple-item-lst ::= tuple-item / tuple-item , tuple-item-lst
	tuple-item     ::= load-time-expr / string /
                          dup-fctr : plitarg
	dup-fctr       ::= compile-time-expr

PLIT (3)+4 has two parses:

    PLIT load-time-expr, and PLIT tuple + expr

The latter choice is used. Hence, PLIT (3)+4 is the same as
(PLIT 3)+4. Note that PLIT (3)+4 yields a value that may have
little or no meaning. PLIT (3) produces a pointer to a memory
location containing a 3. Adding 4 to this pointer may not produce
the intended value.

Load time expressions must evaluate to a constant at load time end
thus include compile time expressions and expressions which contain
only literals and addresses known at load time.

A plit may point to a contiguously stored sequence of literals
strings and nested lists of literals are also allowed. The value of

	PLIT (3,5,7,9)

is a pointer to 4 contiguous words containing 3, 5, 7 and 9
respectively. A long string (more than 2 characters) is also a
valid argument to a plit:

	PLIT "THIS ALLOCATES 12 WORDS"

allocates 12 words of ASCII characters (one character per byte).

The length (in words) of a plit is stored in the word preceding the
data. A UPLIT (i.e. uncounted plit) does not have a length word
allocated with it.

The arguments to plits need only be constant at load time. Plits are
themselves literals, so nesting of plits is allowed.

The following example uses two declarations, EXTERNAL and BIND.
EXTERNAL declares that the names following it exist in an
independently compiled module. BIND establishes an equivalence
between the variable name on the left of the equal sign, =, and
the expression on the right, such that when the variable name
appears in the program the compiler substitutes the value of
the expression for the variable name. The use of the equal sign
does not indicate a store operation in the BIND context, merely
association between the name and the expression (see
section 1.24.3 for details on EXTERNAL and 1.24.5 for details
on BIND)

Examples:

	EXTERNAL A,B,C:
	BIND Y=PLIT (A, PLIT (B,C), PLIT 3, "A LONG STRING", 5+9*3);

is such that:

	.Y[O]*      = A (i.e. the address A);
	.Y[1]       = the address of PLIT(B,C);
	..Y[1]      = B;
	.(.Y[1]+2)  = C;
	.Y[2]       = the address of PLIT 3;
	..Y[2]      = 3;
	.Y[3] = "A "; .Y[4] = "LO"; .Y[5] = "NG"; .Y[9] = "G ";
	.Y[10]      = 32;

In addition, any argument to a plit can be replicated by specifying
the number of times it is to be repeated; e.g.

	PLIT (7:3)

produces a pointer to 7 contiguous words, each of which contains the
value 3. A replication factor of zero results in no allocation.
Duplicated plits are allocated once. Identical plits are not
pooled; hence,

BIND X = PLIT (3: PLIT A, PLIT A, 2: (2,3));

is such that:

	..X[O] = ..X[1] = ..X[2] = ..X[3] = A
	.X[O] = .X[1] = .X12] <> .X[3]
	.X[4] = .X[6] = 2
	.X[5] = .X[7] = 3
	.X[-1] = 8

1.12      Position and Size Modifier

The BLISS-11 language provides the following notation as a modifier
to either the "contents of" or assignment operators:

----------
*Consider this notation as array addressing with Y[O] pointing to
the first word of the array, Y[1] pointing to the second word, etc.
----------

	pos-size   ::= <position,size>
	position   ::= compile-time-expr
	site       ::= compile-time-expr

The position and size together name a field which begins "position"
bits from the right hand side of the named byte and extending "size"
bits to the left. Thus .X<0,8> designates the contents of the byte
at location X and .X<0,16> designates the contents of the word at
location X (X must be a word address in this case). Figure 1.12a
shows these relationships.

Figure 1.12a

Note that the size may not exceed 16 bits and the field may not
cross word boundaries. Any position or size specification which
violates this rule causes a warning message to be issued. Such
erroneous position specifications are used module 16. Erroneous
site specificatons are reduced to the greatest value which does
not cause a word boundary to be crossed.

Examples: (use Figure 1.12b for memory layout)

	X=.Y<0,8>           ! Store low order byte of .Y into
	                    ! low order byte pointed to by X;
	                    ! clears high order byte of X.

	X=.Y<8,8>           ! Store high order byte of .Y into
	                    ! low order byte of X; clears
	                    ! high order byte of X.

	X=.(Y+1)<0,8>       ! Same result as previous example.
	                    ! Stare the byte at address Y+1 into the
	                    ! low order byte of X. Clear the high
	                    ! order byte of X.

	X<8,2>=1            ! Set bit 8 of X to 1 and bit 9
	                    ! to O. The low order byte of X
	                    ! unmodified and Bits 10-15 are
	                    ! also unmodified. In other words,
	                    ! bits 8 and 9 of X are set using
	                    ! the low order 2 bits of the
	                    ! literal 1.

Figure 1.12b


To understand the previous examples we need to discuss the semantics
of <position,size>, which has two valid contexts: as a modifier of
the store operator (= or <-), or as a modifier of the dot operator.

Note that X<position,size> (an undotted name) is only legal on the
left side of store in which case <position,size> is associated with
the store operator.

Every dot or store operation carries a default position-size
modifier if the programmer has not established one explicitly.
In the absence of declarations specifying otherwise* BLISS-11
uses a default of <0,16> on every store and dot operator. Thus

	X=.Y

means the same as

	X<0,16>=.Y<0,16>

where normal precedence rules hold in the evaluation of the
expression. Evaluation proceeds as follows:

	Y          Yields a pointer to Y
	.Y<0,16>   Yields full word contents of Y
	X          Yields a pointer
	<0,16>=    Stores fullword contents of Y into fullword at X

To emphasize, note that since dot has higher precedence than
store the semantics of

	.X<0,8>=.Y

is equivalent to (.X<0,8>)=.Y<0,16> and differs from (.X)<0,8>=.Y
In the first case the position-size modifier is associated with the
contents operator (".") while in the second case it is associated
with the assignment operator. The first case results in the full
word at Y being stored into the address pointed to by the contents
of the low order byte of X. The second case results in storing the
low order byte at Y into the low order byte pointed to by the
fullword contents
of X.

----------
*Section 1.24.3 discusses declarations that can alter the default
to be <0,8>.
----------

The meaning of position size modifiers (PSM) can be defined by
the following rules.

	1.  The left hand side of a store always computes the location
	    where storage is to take place. (Call this address L)

	2.  Any PSM associated with a dot an the left hand side is
	    used only for calculation of that location. i.e. it specifies
	    the field whose contents help specify L.

	3.  A PSM associated with a dot on the right-hand side is used
	    to extract the contents of a field at the location specified
	    by the right hand side. This field may be considered as
	    being stored right justified in a temporary, T, with the
	    remainder of T cleared.

	4.  The size parameter of the store operator's PSM is used to
	    extract a field from the right hand side result.  The
	    position parameter of the store's PSM determines the
	    position (in location L) where this field is to be stored.  All
	    other bits at location L are left unchanged.

Examples:

The following examples of BLISS-11 source text and the corresponding
algorithmic decomposition should help the reader extract some of the
implications of the preceding sections. The discussions will become
less prolix as the pattern becomes obvious.

	BLISS-11            Semantics
	--------            ---------

	A=B;                1.  Store address B into word A

	A=.B;               1.  Store contents of word B into word A

	A<0,8>=.B;          1.  Derive A (a pointer)
	                    2.  Derive B (a pointer)
	                    3.  Modify store operator to store a byte
	                    4.  Store low order byte of word B into
	                        the byte location pointed to by A.

	A<0,8>=.B<0,8>;     1.  Same result as previous example.

	A=.B<0,8>;          1.  Derive B (a pointer)
	                    2.  Modify dot operator to access low
	                        order byte
	                    3.  Derive .B (low order byte of the word B)
	                    4.  Derive A (a pointer)
	                    5.  Apply store (full word implied so low
	                        order contents of B stored into low
	                        order byte of A; high order byte
	                        cleared)

	(.A)<0,8>=.B<8,8>;  1.  Derive .B (contents of B)
	                    2.  Apply modifier to select high order
	                        byte of B
	                    3.  Derive .A (contents of A)
	                    4.  Apply <0,8> modifier to store operator
	                    5.  Store high order byte of B into the
	                        byte pointed to by value derived in 3
	                        (contents of A)

	                    Note:
	                        Parentheses establish precedence so
	                        that the store is modified rather than
	                        the dot.

	.A<0,8>=.B;         1.  Derive .B (contents of B)
	                    2.  Derive .A (contents of A)
	                    3.  Apply <0,8> to contents derived in 2
	                        (extract low order byte)
	                    4.  Store contents of B in location pointed
	                        to by low order byte of A.

	(.A)<0,8>=.B        1.  Derive .B (contents of B)
	                    2.  Derive .A (contents of A), an address
	                    3.  Apply <0,8> to store
	                    4.  Store low order byte of B into byte
	                        pointed to by contents of A.

	                    Note:
	                        Compare this example with the
	                        previous one.

	A=..B               1.  Derive .B (contents of B)
	                    2.  Derive contents of location pointed to
	                        by .B
	                    3.  Store result of 2 into A

	A=..B<0,8>          1.  Derive B
	                    2.  Apply <0,8> to contents of B (extract
	                        low order byte)
	                    3.  Apply dot to result derived in 2 this
	                        uses the low order byte of B as a
	                        pointer and extracts the contents at
	                        the "pointed-to" location
	                    4.  Store the contents derived in 3 into A.

	                    Note:
	                        <P,S> associates with either a dot or a
	                        store. Precedence determines order.
	                        In this example <0,8> associates with
	                        the dot nearest the B, precedence
	                        playing no role here. See the next
	                        example for contrast where
	                        parentheses do force precedence.

	A=.(.B)<0,8>        1. Derive .B
	                    2. Derive ..B (contents of location pointed
	                       to by contents of B
	                    3. Apply <0,8> to contents derived in 2
	                       thus extracting low order byte.
	                    4. Store low order byte derived in 3 into
	                       A; clear high order byte of A
	                       (remember <0,16> applies to store by
	                       default.

	A=.(B+1)<0,8>       1. Derive 8+1 (the address of the high
	                       order byte of B)
	                    2. Apply dot to B+1 (derive contents of
	                       the word which begins at B+1)
	                    3. Apply <0,8> to the two bytes
	                       beginning at B+1 extracting the low
	                       order byte of the logical word
	                       beginning at B+1. (Here logical means
	                       any two consecutive bytes in memory
	                       as apposed to hardware words which
	                       consist of two consecutive bytes
	                       beginning on word boundaries.)
	                    4. Store result of 3 into A; clear high
	                       order byte of A.

	                    Figure 1.12c should help the
	                    reader understand this example

Figure 1.12c

	A=.B<8,8>           1. This is equivalent to previous example
	                       if B is on word boundary.

	A<0,8>=.(B+1)<0,8>  1. Derive .(8+1)<0,8> (the high order byte
	                       of the word B; refer to previous
	                       example.)
	                    2. Derive A

	                    3. Apply <0,8> to store placing high order
	                       byte of contents of 8 into low order
	                       byte of A; high order byte of A
	                       remains unaltered.

	                    Note :
	                       The expression A=.(B+1) will default to
	                       a <0,16> modifier on B+1. This may
	                       violate position-size restrictions if B is
	                       on a word boundary. BLISS-11 does
	                       not make compile-time or runtime
	                       checks for valid addressing. An
	                       attempt to address a word on an odd
	                       boundary will produce a PDP-11
	                       hardware error trap.

	(A+.C)<0,8>=        1. Derive .B
	     .B<0,8>+1      2. Apply <0,8> to contents of B deriving
	                       low order byte.
	                    3. Add 1 to low order byte derived in 2
	                       creating a full word result
	                    4. Derive A (a pointer)
	                    5. Derive .C (contents of C)
	                    6. Add value derived in 4 to value
	                       derived in 5
	                    7. Apply <0,8> to store and store the low
	                       order byte of the value derived in 3
	                       into the low order byte of the
	                       location derived in 6.

	A<2,12>=.B          1. Store low order 12 bits of .B into bits
	                       2 thru 13 of A. The other bits in A
	                       are unchanged.

	A<2,12>=.B<0,14>    1. Same as previous example

	A<2,12>=.B<0,10>    1. Store low order 10 bits of .8 into bits
	                       2 thru 11 of A. Clear bits 12 and
	                       13 of A. The other bits of A are
	                       unchanged.

	A<2,12>=.B<2,12>    1. Store bits 2 thru 13 of .B into bits 2
	                       thru 13 of A

	A<2,12>=.B<2,14>    1. Same as previous example

	A<2,12>=.B<2,10>    1. Store bits 2 thru 11 of .B into bits 2
	                       thru 11 of A. Clear bits 12 and 13
	                       of A.

1.13 Interlude

In Section 1.2 we began at the basic building blocks of BLISS-11
programs namely, expressions, but interrupted it exposing the
reader to names, the dot and store operators, modules, blocks,
data representation, literals, pointers to literals (plits), and
position-size modifiers. We now return to the discussion of
expressions. It may prove useful for the reader to review
Sections 1.1 and 1.2 before proceeding.

1.14 Control Expressions

The control expressions provide the mechanism needed for
controlling the execution sequence of a program. BLISS-11 has
five forms:

	cntrl-expr ::= cndtl-expr /
	               loop-expr /
	               choice-expr /
	               escp-exprl /
	               cortn-expr

1.15 Conditional Expressions

	cndtl-expr ::= IF E1 THEN E2 ELSE E3

E1 is computed and the resulting value is tested. If it is true,
then E2 is evaluated to provide the value of the conditional
expression, otherwise E3 is evaluated.

	cndtl-expr ::= IF E1 THEN E2

This form is equivalent to the IF-THEN-ELSE form with O replacing E3.
However, it does introduce the "dangling else" ambiguity. This is
resolved by matching each ELSE to the most recent unmatched THEN
as the conditional expression is scanned from left to right. Thus
the following expressions are equivalent:

	IF E1 THEN IF E2 THEN E3 ELSE E4

	IF E1 THEN (IF E2 THEN E3 ELSE E4)

	IF E1 THEN (IF E2 THEN E3 ELSE E4) ELSE O

Examples:

<1>*	IF .X<8,1> THEN J = .K ELSE J=.L;
<2>	J = (IF .X<8,1> THEN .K ELSE .L);

	This example has the same effect as the previous one.
	However, In this one the value of the IF control expression is
	used in a store context. BLISS requires that control expressions
	be enclosed entirely in parentheses when used in contexts which
	make use of their values. Thus the expression

	X=IF E1 THEN E2 ELSE .A+.B

	will produce a syntax error since BLISS does not know which of
	the two possible meanings

	X=(IF E1 THEN E2 ELSE .A)+.B

	or X=(IF E1 THEN E2 ELSE .A+.B)
	is intended. Parenthesizing is required.

<3>	IF .L
	THEN BEGIN ... END
	ELSE BEGIN ... END

	    Notice that the use of blocks permits an arbitrarily large
	    computation to take place after a THEN or ELSE.

<4>	POS = .POS + (IF .CHAR EQL #11 %tab% THEN 8 ELSE 1);

1.16 Loop Expressions

The value of each of the six loop expressions is -1, except when an
EXlTLOOP or LEAVE is used (see Section 1.17).

    loop-expr ::= WHILE El DO E2

E1 is computed and the resulting value is tested. If it is true,
then E2 is computed and the complete loop-expr is recomputed; if
it is false, then the loop-expr evaluation is complete.

    loop-expr ::= UNTIL E3 DO E2

This form is equivalent to the WHILE-DO form except the E1 is
replaced by NOT(E3).

    loop-expr ::= DO E2 WHILE E1

The expressions E2, E1 are computed in that sequence. The value
resulting from E1 is tested: if it is true, then the complete
loop-expr is recomputed: if it is false, then the loop-expression
evaluation is complete.

----------
*The single integer values in angle brackets simply number the
examples, and do  not belong to the syntax of the language.
----------

	loop-expr ::= DO E2 UNTIL E3

This form is equivalent to the DO-WHILE form except that E1 is
replaced by NOT(E3).

    loop-expr ::= INCR name FROM E1 TO E2 BY E3 DO E4

The name is implicitly declared to be a LOCAL* variable for the
scope of the loop. This implicit declaration supersedes any
previous declaration for that name for the duration of the loop
expression. It may itself be temporarily superseded by a
declaration in an inner block of the loop or in a contained
loop-expr. The expression E1 is computed and stored in name.
The expressions E2 and E3 are computed and stored in unnamed
local memory which for explanation purposes we shall name U2
and U3. Any of the phrases FROM E1, TO E2, or BY E3 may be
omitted--in which case default values of E1=0, E2=00, E3=l are
supplied. The following loop-expr is then executed:

	BEGIN LOCAL NAME,U2,U3; NAME=E1; U2=E2; U3=E3;
	UNTIL .NAME GTR .U2 DO (E4; NAME=.NAME+.U3)
	END

The last form of a loop-expr is:

	loop-expr ::= DECR name FROM E1 TO E2 BY E3 DO E4

This is equivalent to the INCR-FROM-TO-BY-DO form except that the
loop is equivalent to

	BEGIN LOCAL NAME,U2,U3; NAME=E1; U2=E2; U3=E3;
	UNTIL .NAME LSS .U2 DO (E4; NAME=.NAME-.U3)
	END

Caution:
 BLISS-11 uses signed relationals in the loop expressions. This can
 cause unexpected results if any of the loop variables represent
 addresses rather than numerical values.

If any of the FROM, TO, or BY phrases are omitted from a DECR
expression, default values of E1=0, E2=00 and E3=1 are supplied.
Notice that in both forms the end condition is tested before the
loop, hence the loop is potentially executed zero or more times.

----------
*Section 1.24.3 discusses the LOCAL declaration.
----------

Examples:

<1>	! Following algorithm will place the address of the
	! last item of a linked list into the variable
	! LINK. Figure 1.15a shows the initial storage layout.

	LINKP.LISTHEAD;	! Link now points to first item
	WHILE ..LINK NEQ O DO
	  LINK=..LINK;	! Chain down list

Figure 1.15a

<2>	! Add up the first n integers

	SUM=O;
	INCR J FROM 1 TO .N DO SUM=.SUM+.J

1.17 Escape Expressions

The escape expressions permit control to leave its current
environment.  There are five forms:

	esc-expr	::= LEAVE label WITH E /
			    LEAVE label /
			    EXITLOOP E /
			    RETURN E /
			    SIGNAL E

Any expression may be labeled by preceding it with the label name
and a colon. Within a labeled expression, control may be caused
to leave the expression and yield the given value as the value
of the expression.

All labels must be predeclared in a label-decl (see Section 1.25).

The LEAVE expression must occur within the control scope of the
label named. The same label may be defined only once within the
lexical scope of its declaration.

If the WITH E is missing then WITH O is assumed.

EXITLOOP is a special case which exits the scope of the innermost
loop control scope which contains it. The value becomes the value
of the exited loop.

RETURN exits the routine body and passes the given value as the
value of the routine.

SIGNAL provides controlled exit within a nested environment. We
will discuss the details of SIGNAL in the context of the ENABLE
declaration.

Examples:

<1>	! Find INDEX of first space in line of 80 characters
	! INDEX is -1 if none found because the value of an
	! exhausted loop-expr equals -1

	INDEX=(INCR J FROM O TO 79 DO
	       IF .(LINE+.J)<0,8> EQL " " THEN
	           EXITLOOP .J)

<2>	! How to escape to next iteration in a loop

	INCR J FROM 1 TO 100 DO
	   L2:BEGIN
		...
		IF .condition THEN LEAVE L2;
		! The LEAVE exits the compound which
		! constitutes the loop body. This causes
		! the termination of the current iteration and
		! the beginning of the next.
		...
		END

<3>	! Find first zero element of a 2-D array

	L3: INCR I FROM 1 TO .IMAX DO
	      INCR J FROM 1 10 .JMAX DO
	        IF .ARRAY[.I,.J] EQL 0 THEN
	          (II=.I; JJ=.J; LEAVE L3);

	! This example results in complete loop termination
	! since the label, L3, labels the INCR I...
	! Contrast this with preceding example.

1.18 Choice Expressions

There are two varieties of choice expression - CASE expressions and
SELECT expressions.

1.18.1 CASE expression

	choice-expr::= CASE E1 OF SET exprs TES

Note that the syntax of exprs implies that it consists of a set
of E's and empty expressions separated by semi-colons.
"Empty expressions" are equivalent to O.

The expression E1 is evaluated and used to select the E-th
expression of the following set to execute. (The expressions are
indexed starting at zero.) The zero-th expression is executed if
E1 equals 0, the first if E1 equals 1, etc. The value of the CASE
expression is undefined if E1 is less than zero or greater then
the number of expressions. In such a case unpredictable results
will occur at runtime since no range checking is performed on E1.

The delimiters SET and TES (SET spelled backwards)* bound the
exprs within the CASE expression.

Examples:

<1>	! Collect a FORTRAN identifier
	! TYPE(C) is a routine with the value
	!     O if .C is a numeral
	!     1 if .C is a letter
	!     2 if .C is a space or tab
	!     3 otherwise
	!   NXTCHAR is a routine which returns the next input character
	!   ID is the location where the identifier is collected
	!   COUNT contains the length of the identifier

	!       The WHILE loop acts as an infinite loop since 1
	!       is always true. The computation exits this loop via the
	!       EXITLOOP in case 3.

	COUNT=0;
	WHILE 1 DO
	        CASE TYPE(CHAR=NXTCHAR()) OF
	          SET
		     !O-Numeral
		     ((ID+.COUNT)<0,8>=.CHAR; COUNT=.COUNT+1);
		     !1-Letter
		     ((ID+.COUNT)<0,8>=.CHAR; COUNT=.COUNT+1);
		     !2-ignorable
		     ;
		     ! 3 - ID is complete
		     EXITLOOP
	          TES;

----------
*BLISS-11 uses the convention of forward-reverse spelling of
keyword delimiters in every case except BEGIN-END.
----------

1.18.2 SELECT expression

	choice-expr::= SELECT E OF NSET a-expr-set TESN
	a-expr-set    a-E / a-E ; a-expr-set
	a-E           E: E / OTHERWISE : El ALWAYS : E

This form is somewhat similar to the CASE expression except that the
expressions in the a-expr-set are not thought of as being
sequentially numbered--instead each expression in the a-expr-set is
tagged with an "activation" expression. Suppose we have the
following select expression:

	SELECT E1 OF
	  NSET
	   E4: E5;
	   E6: E7;
	   E8: E9;
	   E10: E11
	   TESN

The execution proceeds as follows: El is evaluated. Then E4 is
evaluated and if it equals E1, E5 is evaluated. Then E6 is evaluated
and if it equals E1, E7 is evaluated, and so on for E8 and E10. The
value of the entire expression is that of the last one to actually
be executed. If none are executed the value is -1.

In place of one of the activation expressions, E4, E6, etc., one of
the two reserved words OTHERWISE or ALWAYS may be used, e.g.
ALWAYS: E9. The expression following an OTHERWISE will be executed
just in the case that none of the preceding selection criteria
were satisfied. The expression following an ALWAYS will always be
executed regardless of the value of E1. In the following example

	Z=(SELECT .X OF
	  NSET
	    1: E1;
	    .A+.B: E2;
	    OTHERWISE: E3;
	    36: E4;
	    ALWAYS: E5;
	    94: E6
	  TESN)

the execution of E1, E2, E4, E6 depend on .X having the value 1,
.A+.B, 36, and 94 respectively. The execution of E3 occurs if .X
did not equal 1 or .A+.8. The execution of E5 always occurs.

Note that although OTHERWISE and ALWAYS may replace any selection
expression, it makes no sense to use more than one OTHERWISE or to
use an OTHERWISE after an ALWAYS since in these cases the latter
OTHERWISEs can have no effect.

1.18.3 Compile-time Constant Conditional and Choice-Expressions

Some BLISS-11 contexts require that expressions evaluate to
constants at compile time. For example the declaration

	OWN X[E]

requires that E be completely determined at compile time. In
particular we may write without generating an error

	OWN X[IF E1 THEN E2 ELSE E3]

if we can guarantee that the conditional expression will reduce to
a compile time constant. BLISS-11 permits conditional expressions
and CASE expressions to be used in this manner, but not SELECT
expressions. Use of constant conditional and CASE expressions can
prove quite useful in effecting conditional compilations and as a
technique for the achievement of algorithm and data independence.

1.19 Coroutine Expressions

Coroutine expressions have not been implemented.

1.20 Declarations

Any number of declarations may occur at the beginning of a block.
The block defines the scope of the declarations (see Section 1.9).
Most declarations introduce names and/or provide information about
names. Other declarations are used for such things as listing
control, inclusion of text from other source files and control
over certain code optimizations. The declarations are the following:

decl ::=   routn-decl /
           ext-fwd-decl /
           link-decl /
           strc-decl /
           alloc-decl /
           bind-decl /
           map-decl /
           label-decl /
           un-decl /
           enable-decl /
           macro-decl /
           csect-decl /
           requ-decl /
           swtch-decl

The remainder of Chapter 1 will describe these declarations in detail.


1.21 Storage (An Introduction)

Before proceeding with a detailed discussion of the name-introducing
declarations we shall give an intuitive overview of their effect.

A BLISS-11 program operates with and on a number of storage
"segments". A storage segment consists of a fixed and finite number
of words or bytes, each of which is composed of a fixed and finite
number of bits (16 and 8 for the PDP-11).

In practice a segment generally contains either program or data,
and if the latter, it is generally integer numbers, characters,
or pointers to other data. To a BLISS-11 program, however, a
segment merely contains a pattern of bits.

Segments are introduced into a BLISS-11 program by declarations,
called allocation declarations (alloc-decl) or routine
declarations (routn-decl); for example:

	GLOBAL G
	OWN X,Y[5],Z
	LOCAL P[100]
	REGISTER R1,R2
	ROUTINE F(A,B) -- .A^.B
	GLOBAL ROUTINE INC(X) = .X+1
	STACKLOCAL S1,S2

Each of these declarations introduces one or more segments and binds
the identifiers mentioned (e.g. G, X, V, etc.) to the address of the
associated segment. (The ROUTINE declarations also initialize the
segments named "F" and "INC" to the appropriate machine code.)

The data segments introduced by these declarations contain one or
more words, where the number of words may be specified (as in LOCAL
P[100]), or defaulted to one (as in GLOBAL G). The identifiers
introduced by a declaration are defined only within the scope of
the block in which the declaration is made, with one
exception - namely, GLOBAL identifiers are made available to
other, separately compiled modules.

Segments created by OWN, GLOBAL, and ROUTINE declarations are
created only once and are preserved for the duration of the
execution of a program. Segments created by LOCAL and REGISTER
declarations are created at the time of block entry and are
preserved only for the duration of the execution of that block.
REGISTER segments differ from LOCAL segments in that they must
be allocated from the machine's general purpose (fast) registers.
Re-entry of a block before it is exited (by recursive routine
calls, for example) results in the dynamic allocation of LOCAL
and REGISTER segments on each incarnation of the block. The
compiler may choose to allocate LOCAL variables in registers.
The STACKLOCAL declaration is identical to LOCAL with the
exception that STACKLOCAL's are explicitly prohibited from being
allocated in registers. They are always allocated on the runtime
stack.

There are three additional declarations whose effect is to
associate identifiers with segments, but which do not actually
create segments; examples are:

	EXTERNAL S
	FORWARD RTN
	BIND Y2=Y+2, PA=P+.A

An EXTERNAL declaration specifies that an identifier represents a
segment named by the same identifier and declared GLOBAL in another,
separately compiled module. A FORWARD declaration indicates that an
identifier is associated with a routine which will be declared
lexically later in the module. The BIND declaration associates an
identifier with the segment whose address is given by the value of
an expression at the time the block is entered. At least potentially
the value of this expression may not be calculable until run
time - as in 'PA = P+.A' above.

1.22 Routines

	routn-decl  ::= glbl-decl ROUTINE routn-specs
	glbl-decl   ::= GLOBAL / empty
	routn-specs ::= routn-spec / routn-spec , routn-specs
	routn-spec  ::= link-id name(name-lst)=E / link-id name=E
	link-id     ::= link-name / empty (=> BLISS)
	link-name   ::= name

The ROUTINE declaration (routn-decl) defines the name to be that
of a potentially recursive and re-entrant routine whose value is
the expression E and which is called using the linkage mechanism
(calling sequence) specified by link-id. If link-id is empty then
the default link-name BLISS is used. The name-ist defines the
names of the routine's formal parameters. The scope of these
names is the body of the routine, the expression E. However,
the scope does not include the bodies of any routines defined
within E (i.e. up-level addressing is not permitted). The syntax
of a routine call is

	routn-call ::= Pl(expr-lst) / P1()
	P1         ::= literal / name / strc-access /
	               block / routn-call

P1 is a primary expression, and should evaluate, either at compile
time or runtime, to a name which has been declared as a ROUTINE.
The expr-lst at the call site (routn-call) is used to supply actual
values of the parameters for the invocation. All parameters are
call-by-value; but notice that call-by-reference is achieved by
simply presenting addresses at the call site. Parentheses are
required at the call site even for a routine with no formal
parameters since the name by itself is a pointer to the routine,
not a request for a call.

To eliminate possible misunderstanding on the BLISS-11 parameter
passing mechanism for those readers familiar with other higher
level languages, and to make the process explicit for others,
we shall examine it in more detail.

BLISS routines have one local variable set aside for each formal
parameter declared. These local variables may be on the stack or
in registers depending on the link-name associated with the routine
(see Section 1.22.3). When a call on the routine occurs, an
evaluation of the actual parameters takes place, and the values
are stored in the corresponding local variables. Because every
expression in BLISS-11 computes a value, and because the value
thus computed in a routine call establishes the contents of the
formal parameter, we say that all BLISS-11 calls occur as
calls-by-value.

Examples:

<1>	! Calculate the sum of O, 1,..., .N

	ROUTINE ARITHSUM(N)=(.N*(.N+1 ))/2

	Call:
	    Y=ARITHSUM(10)

	The call mechanism evaluates the actual parameter and deposits
	it in the local variable, N, in the called routine, then invokes the
	routine. The routine operates on the passed value; note the
	formal, N, has the dot operator applied.

	Y=ARITHSUM(A)

	In the above call A, as a value, is the address A and the call
	mechanism deposits this value into the local variable reserved
	for the formal N. The value returned equals the arithmetic sum
	of the address treated as an integer--hardly the outcome
	intended. To achieve the desired result requires the call:

	Y=ARITHSUM(.A)

	This places the contents of A into the location of the formal N.

	This example amplifies the strict call-by-value parameter passing
	in BLISS-11. Specifically, we have a routine with a list of
	formal names and for each formal name a location. At the call
	site each actual parameter is evaluated and the contents of the
	corresponding formal receives the value; the caller, using the
	requirements of the routines, sets up the call to effect the
	proper initialization of the formals. Figure 1.22a shows storage
	locations for the above two calls

Figure 1.22a

<2>	The occurrence of a primary expression followed by a parameter
	list enclosed in parentheses triggers a function call; an identifier
	by itself, even one declared as the name of a routine, merely
	denotes an address.

	The value of a routine call results from the execution of the
	body of the routine. Consider:

	BEGIN
	GLOBAL X,Y,Z;
	ROUTINE F(A,B)=(.A=.B);
	Y=5;
	Z=F;
	(.Z)(X,.Y);
	.X
	END

	This block has 5 as its value. Z=F stores the address of F into
	Z but does not trigger a call. The expression (.Z)(X,.Y) is
	actually a routine call which results in storing the contents of Y
	into X. A routine call need not explicitly name a routine by its
	associated identifier, only that the primary expression evaluate to
	a routine segment which can properly accept the arguments.

1.22.1 GLOBAL Routines

A routine name is like an OWN name in that its scope is limited to
the block in which it is declared and its associated storage segment
is already created before block entry. The prefix GLOBAL makes the
routine name available for reference by modules which are loaded
with the module containing the routine declaration. The other
modules gain access to the name by means of an EXTERNAL declaration.

A GLOBAL routine is prohibited from accessing register variables
declared outside of the routine itself unless the register is
mentioned in a RESERVE module parameter (see Section 3.4).

1.22.2 EXTERNAL and FORWARD routine declarations

	ext-fwd-decl ::= EXTERNAL mlid-lst /
	                 FORWARD mlid-lst
	mlid-lst     ::= mlid-elmt / mlid-elmt , mlid-lst
	mlid-elmt    ::= link-id id-part
	id-part      ::= name / name : id-part

Normally a routine must be declared lexically before any reference
to the routine name. The EXTERNAL and FORWARD declarations are used
to make exceptions to this rule.

The EXTERNAL declaration allows the name of a routine declared in
an other module to be made available for reference within the scope
of the declaration. A routine with the same name must be declared
GLOBAL in some module which is loaded with the module containing
the EXTERNAL declaration. Note that the EXTERNAL declaration may
also take the form of an alloc-decl (see Section 1.24.3).

The FORWARD declaration permits the name of a routine declared
later in the current lexical scope to be made available for
reference prior to its actual declaration. This allieviates the
necessity of arranging routine definitions in any particular
order. It also makes it possible for two routines to call
each other.

Both of these declarations allow a linkage specification to be
associated with the routine names. All names in the id-part of
a mlid-elmt use the link-id appearing in the mlid-elmt. As in
routine declarations an empty link-id causes the default
link-name, BLISS, to be used.

1.22.3 Calling Sequence Declarations

There are two motivations for allowing some degree of programmer
control over routine calling sequences. First, it is desirable that
it be relatively simple to interface BLISS-11 routines with the
PDP-11 hardware calling sequences (e.g. for interrupts, EMT's, etc.)
and with programs written in programming languages using calling
sequences other than the standard BLISS sequence. Second, since a
generalized calling sequence cannot be the most efficient in all
cases, user-defined calling sequences provide an opportunity for
the programmer to gain additional efficiency if it is necessary.

A calling, sequence consists of the following five components:

1) the call instruction(s)
2) parameter location
3) state saving and restoring (e.g. register contents)
4) routine value conventions
5) the return instruction(s).

BLISS-11 recognizes several calling sequence types. Each specifies
a particular set of conventions for the areas listed above.

The programmer may create calling sequences of his own by using the
LINKAGE declaration. The only calling sequence component which may
be changed is the location of parameters. It is hoped that this
together with the variety of predefined linkage types will meet
the interfacing and efficiency requirements mentioned previously.

LINKAGE declarations have the following syntax:

	link-decl     ::= LINKAGE link-specs
	link-specs    ::= link-spec /link-spec , link-specs
	link-spec     ::= name - link-typ / name = link-typ ( link-call-ist )
	link-typ      ::= BLISS / INTERRUPT / EMT / TRAP / IOT /
			    FORTRAN / link-name
	link-call-ist ::= link-arg /link-arg , link-call-lst
	link-arg      ::= STACK / REGISTER=num
	num           ::= 0 / 1 / 2 / 3 / 4 / 5

A LINKAGE declaration defines the name to specify a calling sequence
which has the basic characteristics of the link-typ appearing in the
declaration. The link-call-lst, if specified, describes the locations
to be used to hold the positionally corresponding actual parameters
in a call on a routine which is invoked using the newly defined
linkage name. STACK means the parameter is placed on the runtime
stack in memory. REGISTER=num means it is loaded into the general
register specified by num.

Once a linkage name has been defined it may be used as the link-typ
in subsequent LINKAGE declarations. In this case it specifies that
the basic link-typ to be used is the link-typ associated with the
link-name in its own declaration.

A link-name is associated with a routine by specifying it in the
declaration of the routine name (see Section 1.22).

1.22.4 Predefined Calling Sequences

There are six predefined calling sequence types, BLISS, INTERRUPT,
EMT, TRAP, IOT and FORTRAN. Of these only BLISS and INTERRUPT are
currently implemented. The details of the run-time representation
and characteristics of these calling sequences may be found in
Sections 4.1 to 4.6.

The BLISS calling sequence is the standard calling sequence used
in BLISS-11. The link-name BLISS is the default link-name in all
routine declarations so normally it need not be explicitly
specified. This default can be changed merely by using a LINKAGE
declaration to define a new calling sequence with the name BLISS.

The predefined BLISS linkage specifies that a routine returns a
value and that all actual arguments are to be placed on the stack.
New calling sequences with link-typ of BLISS may specify that
certain arguments are to be put into registers. For example, the
declarations

	LINKAGE NONSTD=BLISS(REGISTER=1,REGISTER=2,STACK)
	ROUTINE NONSTD LINKUP(FOREWARD,BACKWARD,HOME)=E1

will result in a calling sequence that will place the actual
argument for FOREWARD in R1, the actual for BACKWARD in R2, and
the actual for HOME on the stack, then transfer to LINKUP using
the characteristics of the BLISS calling sequence. If a ROUTINE
declaration contains more formals than its corresponding LINKAGE
declaration, then the actuals corresponding to these formals are
placed on the stack.

The INTERRUPT linkage declares that a routine will be entered as
a result of a hardware interrupt or trap. Explicit calls are not
allowed to invoke a routine which is declared to use the INTERRUPT
linkage. Thus INTERRUPT routines do not return a value. Note that
using this linkage name only declares a routine for servicing
interrupts. The user must separately arrange to establish the
routine name and desired status word in the appropriate interrupt
vector.

An INTERRUPT routine may not have any explicitly declared formal
parameters. However it has two implicitly declared formal
parameters. OLDPC and OLDPS, which may be used to access the
Program Counter and Processor Status saved on the stack by the
interrupt hardware.

1.22.5 Calling Sequences for Variable Routine Names

When a linkage name is itself used syntactically as a routine name
in a routine call expression, the first argument is evaluated at
run-time and interpreted to designate the routine entry point to
be called. The remaining arguments are passed to the named routine
in the manner required by the linkage definition.

Example:

	FORTRAN(.(TRANSFERVECTOR+.I),PAR1 ,PAR2)
	! this call generates a FORTRAN linkage to a routine
	! located at .(TRANSFERVECTOR+.I) and passes
	! two parameters.

1.23 Data Structures (An Introduction)

Two principles were followed in the design of the data structure
facility of BLISS:

	1.  The user must be able to specify the accessing algorithm
	    for elements of a structure.
	2.  The representational specification and the specification of
	    algorithms which operate on the information represented
	    must be separated in such a way that either can be be
	    modified without affecting the other.

The definition of a class of structures, that is, of an accessing
algorithm to be associated with certain specific data structures,
may be made by a declaration of somewhat the following form:

	STRUCTURE name[strc-frml-lst]=E

Particular storage segments may then be associated with a structure,
that is with an accessing algorithm, by specifying the structure
name in the declaration of the storage.

Consider the following example:

<1>	BEGIN
	STRUCTURE ARY2[1,J]=(.ARY2+(.I-1)*2*10+(.J-1)*2)<0, 16>;
	OWN ARY2 X[100];
	OWN ARY2 Y[100];
	OWN ARY2 2[100];
	...
	X[.A,.B] = .Y[.B,.A];
	...
	END;

In this example we introduce a very simple structure, ARY2, for
two-dimensional (10x10) word arrays*, declare three segments of 100
words each with names X, Y, and Z bound to them, and associate the
structure ARY2 with these names. The syntactic forms X[E1,EZ] and
Y[E3,E4] are valid within this block and denote evaluation of the
accessing algorithm defined by the ARY2-structure declaration (with
an appropriate substitution of actual for formal parameters).

----------
*Remember that on the PDP-11 memory is byte-addressable, Words are
addressed by the even addresses; hence the multiplications by 2 in
the definition of ARY2.
----------

Although they are not implemented in this way, for purposes of
exposition one may think of the STRUCTURE declaration as defining
a routine with one more formal parameter than is explicitly
mentioned. The value of this hypothetical routine is the address
of the data structure element which is accessed by the call to
the routine. For example, the STRUCTURE declaration in the
previous example

	STRUCTURE ARY2[I,J] = (.ARY2+(.1-I)*2*10+(.J-l)*2);

conceptually is identical to a ROUTINE declaration

	ROUTINE ARY2(FO,F1,F2) = ( .FO+(.F1-1)*2* 10+(.F2-l)*2);

The expressions X[.A,.B] and Y[.B,.A] correspond to calls on this
routine; i.e. to ARY2(X,.A,.B) and ARY2(Y,.B,.A).

In a STRUCTURE declaration there is an implicit, un-named formal
parameter, the name (address) of the storage segment to be
accessed. The name of the structure itself is used to denote
this zero-th parameter. This convention maintains the positional
correspondence of actuals and formals. Thus, in the example above,
.ARY2 denotes the value of the name of the particular segment
being referenced, and X[.A,.B] is equivalent to:

	(X+(.A-1)*2*10+(.B-1)*2)

The value of this expression is a pointer to the designated element
of the segment named by X. Remember, routines have locations assigned
to each of its formals. To continue the analogy three locations ARY2,
I, J, would exist, and on call invocation, ARY2 would contain the
value of X, I the value of .A, and J the value of .B as shown in
figure 1.23a.

Figure 1.23a

In the following example the STRUCTURE facility and BIND
declaration have been used in the computation of a matrix product.
Each element of the product Z is the vector product of a row of X
and a column of Y. In the inner block the names XR and YC are bound
to pointers to the base of a row of X and column of Y respectively.
These identifiers are then associated with structures which allow
one-dimensional access.

	BEGIN
	STRUCTURE ARY2[1,J] - (.ARY2+(.1-1 )*2*10+(.J-1)*2),
	        ROW[I] = (.ROW+(.I-1)*2),
	        COL[J] = (.COL+(.J-l)*2*10);
	OWN ARY2 X[100]:Y[100]:Z[100];
	...
	INCR I FROM 1 TO 10 DO ! Loop over rows
	 BEGIN BIND ROW XR=X[.I,1]:ZR=Z[.I,1];
	   INCR J FROM 1 TO 10 DO ! Loop over columns
	   BEGIN
	     LOCAL T; BIND COL YC=Y[I,.J];
	     T = 0;
	     INCR K FROM 1 TO 10 DO T = .T+.XR[.K]*.YC[.K];
	     ZR[.J] - .T;
	   END;
	 END;
	...
	END

	! The XR BIND establishes a row pointer in X
	! The YR BIND establishes a column pointer in Y
	! The ZR BIND establishes a row pointer in Z
	! T accumulates the vector multiply for a given row and column
	! ZR[.J] establishes a unique element in Z; ZR via the BIND selects
	! the row and .J the element within the row. Figure 1.23b
	! shows memory at the beginning of the calculation for Z(2,3)

Figure 1.23b

1.24 Data Structures (Actual Syntax)

The example declarations in the preceding section are valid BLISS
syntax; however, they do not reflect the complete power of the
declarative facilities. The following sections are definitive
presentations of the actual syntax and semantics of these declarations 

1.24.1 Structures

	strc-decl    ::= STRUCTURE name strc-fml-lst = strc-size E
	strc-fml-lst ::= [name-lst] / empty
	strc-size    ::= [E] / empty
	strc-access  ::= name[expr-lst] / name[alloc-unit expr-lst;expr-lst]
	expr-lst     ::= E / E,expr-lst / empty

Structure declarations serve to define a class of data structures
by defining an explicit access algorithm, E, to be used in accessing
instances of that structure. The access algorithm introduced by such
a declaration is given a name which may be used as the structure
name (strc-id) in an allocation declaration, BIND declaration or
MAP declaration. In this way the access algorithm is associated
with a storage segment.

The strc-size specifies an allocation algorithm. It is an
expression which calculates the number of bytes of storage which
are allocated to the segment referenced by a name associated
with the structure in an allocation declaration. The expression
must evaluate, after substitution for formal arguments, to a
compile-time constant when the allocation declaration is made.

The names in the structure formal list (strc-fml-lst) are formal
parameter identifiers which are used in two distinct ways:

	1.  Dotted occurences of the formal names in E positionally
	    correlate with the values of expr-lst elements at the site of
	    a structure access. These are referred to as access
	    formals and access actuals respectively.

	2.  Undotted occurrences of the formal names positionally
	    correlate with the values of the expr-lst elements in a
	    size-part at the site of the declaration which associated the
	    variable name with the structure class (see Section 1.24.3).
	    These are referred to as incarnation formals and incarnation
	    actuals respectively. They may occur in both strc-size and
	    in E.

In addition to the explicit formal names, the structure name in
dotted form is used as an access formal to denote the'name of the
specific segment being accessed (that is, to denote the pointer to
the base of the segment).

The access algorithm, E, on the right of the equal sign in a
STRUCTURE declaration is just another BLISS-11 expression once
it is invoked as a structure access. On the PDP-11 both bytes and
words can be addressed. Proper access to byte and word data
structure elements depends on the computation in the access
algorithm. The keyword BYTES provides a means of specifying data
structures whose basic units may be either bytes or words
depending on the allocation declaration of the storage. In the
strc-size or E of a STRUCTURE declaration the name BYTES has a
value of 1 or 2 depending on the size indicated in the alloc-unit
portion of a declaration referencing the structure (see
Section 1.24.3). An alloc-unit of BYTE gives it a value 1, WORD
makes it 2. Thus BYTES is the number of bytes in the basic
allocation unit of the storage segment.

Whether the user cares to use the BYTES keyword depends on the
exact specification of a structure and the amount of allocation
unit independence desired, but he must always be aware of the
fact that a structure access usually produces an address which
selects a data item and he is responsible for generating the
correct address.

Consider the following declarations:

	STRUCTURE VECTOR[I] = [I*BYTES] (.VECTOR+.I*BYTES)<O,8*BYTES>;
	WORD OWN VECTOR X[100];

The incarnation actual 100 replaces the undotted occurrences of I
in the STRUCTURE declaration. Since the allocation unit is WORD the
special keyword BYTES is replaced by 2. After making these
substitutions the strc-size expression gives the value 200, so
200 bytes (100 words) are allocated as an OWN storage segment with
the name X.

A structure access such as .X[10] supplies an access actual, 10,
which replaces occurrences of .I and a segment name, X, which
replaces .VECTOR. The access expands to

	.(X+10*2)<0,8*2>

which specifies the contents of the 10-th element (where the
first word is the zero-th element) of the word vector X.

This example shows the interaction of a simple allocation
declaration with a syntactically complete structure declaration;
it remains now to discuss the complete syntax of allocation
declarations.

The VECTOR structure defined in the last example is the default
structure used in any structure access in which no other
structure name has been indicated. The default may be altered
by using a STRUCTURE declaration to redefine the algorithm
identified by VECTOR.

1.24.2 Structure Accesses for Variable Segment Names

A structure access of the following form

	strc-name[alloc-unit E, expr-lst ; expr-lst)

may be used to treat the expression E as the name of a storage
segment and to perform an access as specified by the access
algorithm associated with the strc-name. The first and second
expr-lst's are used as the incarnation actuals and access
actuals respectively. The alloc-unit is used to give a value to BYTES.

1.24.3 Memory Allocation

Informally, an allocation declaration looks like the following:

	        OWN
	empty   LOCAL
	BYTE    GLOBAL         alloc-decl-arg-list
	WORD    EXTERNAL
	        REGISTER
	        STACKLOCAL

where alloc-decl-arg-list is essentially a list of names to be declared.

The BNF description is the following:

	alloc-decl ::= alloc-unit init-type msid-lst1 /
	               alloc-unit REGISTER msid-lst2 /
	               alloc-unit other-type msid-lst3
	alloc-unit ::= WORD / BYTE / empty (=> WORD)
	init-type  ::= OWN / GLOBAL
	other-type ::= LOCAL / EXTERNAL / STACKLOCAL

	msid-lstn  ::= msid-elmt, / msid-elmtn, msid-lst,
	msid-elmtn ::= link-id strc-id id-groups, / link-id strc-id id-part /
	               link-id strc-id id-groupsn : id-part
	id-groupsn ::= id-group, / id-groupn : id-groups,

	id-groupl  ::= id-part size-part init-part /
	               id-part size-part / id-part init-part
	id-groupn  ::= id-part size-part reg-part /
	               id-part size-part / id-part reg-part
	id-groupa  ::= id-part size-part

	id-part    ::= name / name : id-part
	size-part  ::= [ expr-lst ]
	init-part  ::= = plitarg
	reg-part   ::= = oit
	strc-id    ::= strc-name / empty (=> VECTOR)
	strc-name  ::= name
	link-id    ::= link-name / empty  (=> BLISS)
	link-name  ::= name

An allocation declaration introduces names, each of which has a
scope consisting of the block in which the declaration occurs minus
any inner blocks containing an explicit redeclaration of the sam
 name. however, no up-level addressing is permitted for names
declared as LOCAL, REGISTER or STACKLOCAL. By this it is meant
that the scope of such names does not include the bodies of any
routines declared within the block where the name is declared.
Certain problems may arise with valid redeclarations of OWN names.
For a discussion of and solution for the problem see the
explanation of the UNAMES switch in Section 3.2.

REGISTER, LOCAL, and STACKLOCAL declarations cause allocation of
storage at each block entry (including recursive ones), and
corresponding de-allocation on block exit. Storage for OWN and
GLOBAL declarations is allocated once (before execution begins)
and remains allocated during the entire execution of the program.
EXTERNAL declarations do not allocate storage, but cause a
reference to be made to storage declared with the same name in a
GLOBAL declaration of another module. Space for allocation is
taken from main memory for OWN and GLOBAL declarations, and from
the machine's high speed registers for REGISTER declarations.
Space for allocation of LOCAL declarations will be taken from
either the registers or main memory depending upon the availability
of registers and the use of the LOCAL. STACKLOCALS are always
allocated in main memory.

If present, alloc-unit specifies what unit memory size is to be
allocated. If this is not present then WORD is assumed.

An msid-lstn specifies one or more identifiers which are to be
declared as the type of storage indicated. Each msid-elmt,
contains a linkage name, a structure name, a list of identifiers
and possibly some other information. If the linkage name is
omitted then the name BLISS is used by default. Similarly the name
VECTOR is used if the structure name is omitted. All of the
identifiers appearing in the msid-elmt, have the given or
defaulted linkage and structure names associated with them. Within
an msid-elmt, the identifiers may be divided into id-groupn's.
Each id-group, is followed by some additional information which
is applied to all names in the id-part of the id-groupn. Three
kinds of additional information may occur. These are the syntactic
units size-part, init-part and reg-part. Each will be discussed
in detail.

A size-part specifies a list of incarnation actuals to be used
in the structure definitions associated with the identifiers.
This may be specified in any alloc-decl. However, in REGISTER
declarations the allocation size which is computed by the
strc-size expression in the structure definition and which
typically is a function of the incarnation actuals must be one
word. If no size-part is indicated for an identifier its
incarnation actuals default to 1.

An init-part may be included in a GLOBAL or OWN declaration.
It supplies a series of data words which are used as initial
values of the associated storage segment. Note that in the
plitarg specifies words (never bytes) of data regardless of
the allocation unit appearing in the declaration. This
initialization is performed only once.

A reg-part can be used in a REGISTER declaration to force a name to
be allocated to a specific register. The oit following the equal
sign is the number of the general register which is to be assigned
to the identifiers in the id-part of the id-groupn containing the
reg-part.

The first example in section 1.23 of a two-dimensional array might
now be written:

	BEGIN
	STRUCTURE ARY2[1,J]=
	  [I*J*BYTES] (.ARY2+.(1-1 )*BYTES*J)+(.J-1)*BYTES)<0,8*BYTES>;
	OWN ARY2 X:Y:Z[10,10];
	...
	X[.A,.B] = .Y[.B,.A];
	...
	END;

Notice that the declaration

	OWN A,X[100]

allocates a single-ward OWN variable A and a 100-word OWN vector X
because the defaults make it equivalent to

	WORD OWN VECTOR A[1], VECTOR X[100]

where VECTOR is as defined in Section 1.24.1 (unless it has been
redefined by a STRUCTURE declaration).


1.24.4 MAP Declaration

	map-decl ::= MAP msid-lst3

The MAP declaration is syntactically and semantically similar to an
allocation declaration except that no new storage or identifiers are
introduced. The purpose of the MAP declaration is to permit
redefinition of the structure and incarnation actuals associated
with an identifier (or set of identifiers) for the scope of the
block in which the MAP declaration occurs. This is the only way to
associate a structure (other than VECTOR) with a formal parameter
or a control variable of an INCR or DECR loop.

1.24.5 BIND Declaration

	bind-decl   ::= BIND msid-lst4
	msid-elmt4  ::= link-id strc-id id-groups4
	id-groups4  ::= id-group4 / id-group4 : id-groups4
	id-group4   ::= id-part size-part bind-part / id-part bind-part
	bind-part   ::= = E

A BIND declaration introduces a new set of names whose scope is the
block in which the BIND declaration occurs, and binds the value of
these names to the value of the associated expressions at the time
that the block is entered. Note that these expressions need not be
constant at compile time.


1.25 LABEL Declaration

	label-decl ::= LABEL name-lst

Labels are used solely in conjunction with the LEAVE expression.
Each name to be used as a label must be so declared in some block
containing that usage. See the description of the UNAMES switch for
a discussion of a potential problem with label names.


1.26 UNDECLARE Declaration

	un-decl ::= UNDECLARE name-ist

The identifiers in the name-lst become undefined within the scope
of the declaration. This can be used to prevent accidental access
to variable names defined in outer blocks.


1.27 ENABLE Declaration

	enable-decl ::= ENABLE a-expr-set ELBANE

The syntax of a-expr-set is identical to that of the body of a
SELECT expression including OTHERWISE and ALWAYS.

ENABLE serves to dynamically declare an interest in handling a set
of conditions that may occur in the dynamic scope of the declaration,
where the occurrence of one of the conditions is signalled by the
subsequent execution of a SIGNAL expression.

In particular, when a SIGNAL expression, say 'SIGNAL e', is executed
the context of the most recently executed ENABLE declaration is
immediately entered and the value of e is compared to each of the
selection expressions (preceding the colons). If none of the
selection criteria is satisfied, the next embracing ENABLE context
is entered, etc., until some selection criterion is satisfied.
When a selection criterion is satisfied the associated expression
(following the colon) is executed - unless explicit subsequent
control sequencing is specified in this expression (e.g. another
'escape' expression) control will pass out of the block in which
the ENABLE declaration occurs. The value of the block is the value
of the expression in the ENABLE which was executed.

The value of the global variable SIGVAL contains the value of the
argument of the most recently executed SIGNAL. This may be of use
inside the body of an ENABLE.

ENABLE declarations can have adverse effect on variables contained
in registers. The source code within the ENABLE declaration and
following the block containing the ENABLE must not rely on the
contents of REGISTER or LOCAL variables or register parameters
whose scope contains an ENABLE. If a LOCAL variable is required
it should be declared using the STACKLOCAL declaration. These
problems are a deficiency in the implementation of ENABLE and
should not be considered a permanent feature of the language.


1.28 Macros

In order to facilitate program readability and modifiability, a
macro system is embedded in BLISS. The system allows nested macro
definition as well as iterative and recursive forms of evaluation.


1.28.1 Syntax for Macro Declarations

	macro-decl ::= MACRO dfn-lst
	dfn-lst    ::= dfn / dfn ,dfn-lst
	dfn        ::= name fxd-parms itrd-parms = body $
	fxd-parms  ::= (name-lst)/ empty
	itrd-parms ::= [] / [name-lst] / empty

The essential function of the macro system is to replace the macro
name and its actual parameter list (wherever the name occurs within
the scope of the macro definintion in the program) by its body, with
actual parameters substituted for formals. The body is considered
to be a string of "atoms"--names, literals and delimiters--and is
therefore independent of editing symbols--blanks, CR, LF, and BLISS
comments. Atoms are the smallest recognizable syntactic elements
in the BLISS-11 language.

The format of the macro call is simply the macro. name possibly
followed by the bracketed actual parameter list. The brackets must
be one of the pairs: (), [], <>, and the actual parameters must
be separated by commas. The actual parameters may be arbitrary
strings of atoms; however, occurrences of the brackets: (), [], <>,
and components of a parameter must be properly balanced and nested.
All macros in actual parameter lists are expanded before
formal/actual binding; i.e. BLISS-11 expands macros from the
inside out. It is possible to trace the expansion of macros through
the use of the EXPAND switch. See Section 3.2 for a discussion of
this facility.

Macros effect a text substitution process. The actual parameters
in the call serve as the "text values" for formal parameters in the
definition and, on call, the definition serves as a template for a
text substitution process resulting in a macro expansion. The
result of the macro expansion depends on the form of the macro,
the context of the call, and any "special functions" used within
the macro definition.


1.28.2 Macro Forms and Special Functions

BLISS has six macro forms and seven special functions:

          Macro Forms        Special Functions
               Substitute            SREMAINING*
               Simple                $LENGTH
               Pass                  $COUNT
               Recursive             $OUOTE
               Iterated              $UNQUOTE
               Fixed Iterated        $STRING*
                                     $NAME*


1.28.3 Macro Forms and Examples

<1> Substitute

Syntax: MACRO name=body$

Call Format: name

Replacement Algorithm: The body replaces the macro name.

Example:
 Definitions:

	MACRO HBYTE=8,8$,       ! position-size of high-order byte
	      LBYTE=0,8$,       ! position-size of low-order byte
	      LINK=2,0,16$,     ! specify a data field
	      TAB=OUTPUT(#11)$; ! call to output routine

----------
*These special functions have not yet been implemented.
----------

Calls:

	A<LBYTE>=.B<HBYTE>;    ! move a byte
	PTR=.PTR[LINK];        ! follow a linked list
	TAB;                   ! output a tab character

In expanding the above calls a one-for-one substitution occurs
between the name and the body, so A<LBYTE>=.B<HBYTE> expands to
A<0,8>=.B<8,8>


<2> Simple

Syntax: MACRO name(frml1,...,frmln)=body$

Call Format: name(actul1,...,actuln)*

Replacement Algorithm: Occurrences of the formals (frml1...) in body
    are replaced by the actuals (actul1...) at the call site. After the
    replacement the expanded body replaces the call. Unspecified
    actuals default to empty. The algorithm ignores extra actuals,
    but issues a warning message.

Example:
 Definition:

	! Use this macro to call an output routine
	! to print an error message
	MACRO OUTERR(NUM,MSG)=
	    OUTSTRING(PLIT($STRING('ERR',NUM,':',MSG))$

This macro uses the special function $STRING. The string values of
the $STRINC argument list are concatenated to form a string (a
single atom).

Call:

	OUTERR(4,' Invalid Date')
	 expands to:
	OUTSTRING(PLIT('ERR4: Invalid Data'))

<3> Pass

Syntax: MACRO name[]=body$

----------
*Macro calls may use any of the bracketing pairs (), <>, or [];
all the examples will use ().
----------

Call Format: name(actul1,...,actuln)

Replacement Algorithm: The body replaces the call only if a non-empty
    actual-parameter list is specified; otherwise, the macro is
    replaced by the empty atom. If an actual-parameter list is
    specified, the special function $REMAINING may be used in the
    body to stand for the actual-parameter list with outer brackets
    removed and the "default separator" replacing the commas.
    $REMAINING and default separators are discussed in more detail
    in later sections.

Example: The example in the discussion of the recursive macro form
    will cover the pass form as well as recursive.


<4> Recursive

Declaration Syntax: MACRO name(frml1,...,frmln)[]=body$

Call Syntax: name(actul1,...,actuln,actuln+1,...,actulm)

Replacement Algorithm: If the call has not specified at least n actuals
    then the empty atom replaces the call; otherwise the macro is
    expanded with actul1,...,actuln replacing frml1,...,frmln in the body.
    The special function SREMAINING may be used in the body to
    denote the remaining actuals actuln+1,...,actulm.

    Note: The body may have a recursive call within it, but this is
    not necessary.

Example:
 Definition:

	MACRO COND(BOOL,EXP)[] =
	     IF BOOL THEN EXP EL($REMAINING) COND($REMAINING)$;
	MACRO EL[]=ELSE$;

	The macro, COND, has the recursive form, and the macro, EL, the
	pass form. Note that a call on COND appears in the body of
	COND.

Call:

The COND macro requires two actuals to replace the formals BOOL and
EXP, but can accept any number of pairs of actuals. A call such as

	COND(E1,E2,...,E2n-1,E2n)

results in BLISS code which evaluates E1, E3, ... , E2n-l until one
of them, Ei , is true; then Ei+1 is evaluated. Consider the call

	COND(.B,A=.X,.X OR .Y,FCT(.M))

This will expand to

	IF .B THEN A=.X EL(.X OR .Y,FCT(.M))
	    COND(.X OR .Y,FCT(.M))

Since the argument list passed to EL is not empty it is replaced by
its body. Next the recursive call to COND is made. At this point the
expanded text looks like the following:

	IF .B THEN A=.X ELSE
	    IF .X OR .Y THEN FCT(.M) EL() COND()

The argument list in the call to EL is empty so the call just
disappears. Similarly the next recursive call to COND has an
empty argument list and yields no text. The expansion is finished
and the result is

	IF .B THEN A=.X ELSE
	    IF .X OR .Y THEN FCT(.M)

<5> Iterated

Declaration Syntax: MACRO name[frml1,...,frmln]=body$

Call Syntax: name(actul1 1,...,actul I,actul21,-..,actul2,...,acfu),l,...,acf

Replacement Algorithm: The macro is treated as if it were a simple
    macro and called m times. The first time the formals are bound
    to actul11,...,actul1n, the second time to actul21,...,actul2n, etc.
    Default separators are placed between the text produced by the
    iterations of the macro expansion. Note that expansion stops
    when less than n actual parameters remain to be bound to the
    formals. (Thus the expansion is not exactly like a simple macro
    since unspecified actuals do not default to empty.)

Inside the body the special function $COUNT denotes the integer
which gives the number of iterations completed up to the point
where it appears. $REMAINING may be used to denote the actuals
which have not been bound to formals so far in the expansion process.

<6> Fixed Iterated

Declaration Syntax: MACRO name(fixdl,...,fixd,)[frml1,...,frmln]=body$

Call Syntax: name(actul1,...,actulm,actulm+1,...actulm+k)

Replacement Algorithm: The fixed formals, fixd1,...,fixdm, are bound to
    the first m actual parameters, then the macro behaves exactly as
    if it were an iterated macro with formals frml1,...,frmln, and
    actuals actulm+1,...,actulm+k.

Example:
 Definition:

	MACRO INITLOCLVEC (ARYNAME)[]=
	     LOCAL ARYNAME[$LENGTH-1];
	     LOAD (ARYNAME, $REMAINING)$;
	MACRO LOAD(BASE)[VALUE]=BASE[$COUNT]IVALUE$;

The special function $LENGTH has a value equal to the number of
actuals passed in the current macro call.

Call:

	INITLOCLVEC(CAT,4,3,7,0,1 )
	 expands to
	LOCAL CAT[5];
	CAT[O]=4;
	CAT[I]-3;
	CAT[2]=7;
	CAT[3]=0;
	CAT[4]=1

The initial expansion results in

	LOCAL CAT[6-1];
	LOAD(CAT,4,3,7,0,1)

The expansion of LOAD iterates as follows

	- $COUNT=O BASE=CAT VALUE=4 produces CAT[0]=4
	- The default separator is emitted
	- $COUNT=1 BASE=CAT VALUE=3 produces CAT[0]=3
	- The default separator is emitted
	- etc.

1.28.4     Default Separators

Because punctuation plays a critical role in BLISS syntax, the
iterated macro forms could produce incorrect BLISS source text if
the proper punctuation atoms did not occur between the text produced
by the various iterations. To establish proper punctuation BLISS-11
outputs punctuation atoms, called default separators, based on the
context of the macro call. The following list describes possible
BLISS contexts and the default separators associated with them; in
addition certain contexts also generate brackets, and these are
described where they apply.

1. Preceding Context:

    a.  The separator ","
    b.  The declarators EXTERNAL, BIND, MACRO, ROUTINE, etc.
    c.  The bracket "<"
    d.  The bracket "(" used as parameter list bracket for
        routine or macro call
    a.  PLIT (
    f.  PLIT
    g.  An expression or name

    Separator Generated: ","

    Brackets Generated: For cases f and g generate "(" and ")"

2.  Preceding Context:

    a.  The separator ";
    b.  BEGIN
    c.  "(" used as open bracket of a block
    d.  SET or NSET
    e.  An OF following a CASE or SELECT

    Separator Generated: ";"

    Brackets Generated: After OF following CASE generate a
        SET, TES pair. After OF following SELECT generate a
        NSET, TESN pair.

3.  Preceding Context:
    a. Structure or linkage name in a declaration

    Separator Generated: ":"

1.28.5 Special Functions

$REMAINING

Within the body of a pass, recursive, iterated or fixed iterated
macro this special function denotes the string consisting of all
those actual parameters not yet bound to a formal parameter. The
commas in the actual parameter list are replaced by the default
separator implied by the context of the use of $REMAINING.

$LENGTH

This special function may appear in the body of any form of macro.
It denotes the integer which is the number of actual parameters
passed to the current iteration or invocation of a macro.

$COUNT

Inside the body of a recursive, iterated or fixed iterated macro
the value of $COUNT is the integer which specifies the recursion
depth or iteration count for an expansion of the body. The
recursion depth is the number of partially complete expansions
of the macro which cannot be completed until the current call
to the macro is complete. The iteration count for an iterated
or fixed iterated macro is the number of iterations of the macro
completed so far.

$QUOTE

The single atom following this special function is its argument.
It causes this argument to be used as it appears rather than
attaching any special meaning to it. For example, if the argument
is a name it is not associated with any meaning it may have as the
result of a previous declaration. A $QUOTEd "," in a macro argument
list will act as just another atom in the current argument rather
than indicating the end of the argument. A $QUOTEd "$" may appear
within a MACRO declaration without terminating the declaration. Note
that this allows nested macro definition. Similarly special functions
may be $QUOTEd to allow their use in nested macro definitions.

$UNQUOTE

The single atom following $UNQUOTE is its argument. It forces the
argument to take on the current meaning that is associated with it.
This is useful only in the case of names appearing within macro
declarations. Normally a name inside a macro declaration is
automatically $QUOTEd, i.e. it is not associated with the meaning
given the name in some other declaration. When macro expansion
occurs a name atom is associated with any declaration of the name
which is in effect at the site of the macro call. Using $UNQUOTE
within a macro declaration forces a name to be associated with
any declaration of the name which is in effect at the site of
the macro definition.

$STRING( ... )

The string values of the items in the argument list are concatenated
to form a single atom which is a string.

$NAME( ... )

As in $STRING the string values of the arguments are concatenated
to form a single atom. However, this atom is a name rather than a
string. Some typical uses of this special function might be to
create new names from macro parameters or to construct names
acceptable to the loader but not to BLISS (e.g. the name S.FDB).

1.29 CSECT and PSECT Declarations

	csect-decl ::= CSECT name / PSECT name /
	               CSECT keys / PSECT keys
	keys       ::= key / key , keys
	key        ::= keyword = quoted-string
	keyword    ::= CODE / DEBUG / GLOBAL / OWN / PLIT

A csect-decl may occur only in the outermost block of a module.
When CSECT is used, the assembler directive .CSECT is generated for
the control section. When PSECT is used, .PSECT is generated. The
quoted string may contain both a control section name and
attributes acceptable to the loader.

Examples:

	PSECT ABCD;
	  generates
	.PSECT        ABCD.C    ;code
	.PSECT        ABCD.D    ;debug
	.PSECT        ABCD.G    ;globals
	.PSECT        ABCD.O    ;owns
	.PSECT        ABCD.P    ;plits

	MODULE AP ...
	PSECT CODE=' ',OWN='$OWN',GLOBAL='GLOBLS,GBL';
	  generates
	.PSECT                  ;code
	.PSECT        A.D       ;debug
	.PSECT        $OWN      ;owns
	.PSECT        GLOBLS,GBL ;globals
	.PSECT        A.P       ;plits


1.30 REQUIRE Declaration

It is often convenient to maintain files of declarations or code
which may be used in more than one module. The REQUIRE declaration
implements a way to specify this in a BLISS-11 program.

	requ-decl     ::= REQUIRE filespec
	filespec      ::= device filenamespec
	device        ::= name: / empty (=> DSK:)
	filenamespec  ::= filename / filename[ppnspec]
	filename      ::= name / name.name
	ppnspec       ::= octal,octal / CMU-ppn* / empty (=> ppn of job)

The REQUIRE declaration instructs the compiler to read the text of
the file named by the filespec as if that text had been copied into
the source file immediately following the semicolon which follows
the declaration. A REQUIRE file may in turn REQUIRE another file to
a total depth of eleven REOUIREd files.

----------
*This is a special form of ppn acceptable on the PDP-10 systems at
Carnegie-Mellon University.
----------

The defaults for omitted parts of a filespec are as follows: device
is defaulted to DSK, ppnspec is defaulted to the project-programmer
number of the job which is running the compiler.

The following points should be noted:
1) Ppn's such as [27,15] must be entered as octal constants,
   i.e. [#27,#15].
2) Everything between the semicolon which follows a REQUIRE
   declaration and the next carriage return will be ignored.
3) Only the first six (six, three) characters of the name given for a
   device (file, extension) will be used. These names should refer to
   existing devices and files.
4) The ppnspec should refer to a valid account number on the system
   being used.
5) The result of a REQUIRE inside a macro is unpredictable.


1.31 SWITCHES Declaration

	swtch-decl ::= SWITCHES swtch-lst
	swtch-lst  ::= swtch / swtch , swtch-lst

The SWITCHES declaration allows the user to set various switches
which control the compiler options. The effect of a SWITCHES
declaration is limited to the scope of the block in which the
declaration is made. The allowed forms of swtch are given in
tabular form in section 3.2.


2.0 SPECIAL LANGUAGE FEATURES

The previous chapter described the basic features of the BLISS
language. In this chapter we describe additional features which
are highly machine and implementation dependent. The reader should
consult a PDP-11 Processor Handbook for full descriptions of
specific PDP-11 machine instructions mentioned in the following
sections.

2.1 Special Routines

A number of features have been added to the basic BLISS-11
language which allow greater access to the PDP-11 hardware
features. These features have the syntactic form of routine
calls and are thus referred to as "special routine calls".
Code for special routines is always generated in line.

2.1.1 TRAP, EMT and IOT

	spcl-rout   ::= emt-call / trap-call / lot-call
	emt-call    ::= EMT(compile-time-expr ,expr-lst)
	trap-call   ::= TRAP(compile-time-expr , expr-lst)
	lot-call    ::= I0T(expr-lst)

An EMT or TRAP special routine call is syntactically a routine
call with at least one parameter. The first (and possibly only)
parameter must evaluate at compile-time to a value in the range
O to 255 inclusive. This value is incorporated into the low byte
of the EMT/TRAP instruction itself. The remaining arguments,
(if any) are evaluated and pushed onto the stack prior to the
EMT/TRAP instruction. The arguments are removed from the stack
following return from the EMT/TRAP. An IOT special routine call
is similar to an EMT/TRAP special routine call except that the
integer parameter is not used and the instruction generated is IOT.

2.1.2 HALT, RESET and WAIT

	spcl-rout ::= HALT() / RESET() / WAIT()

Each of these parameterless special routine calls causes the
corresponding PDP-11 machine instruction of the same name to be
emitted. Care should be taken to ensure that the instruction
occurs in the desired place.

2.1.3 SWAB

	spcl-rout ::= SWAB(E)

Not implemented yet.


2.2 INLINE - Machine Language in BLISS-11

	inline ::= INLINE(string)

INLINE is a simple escape mechanism to allow the programmer to
embed machine language code in his BLISS-11 program. Its use is
both machine and context dependent and extreme caution is
recommended. It is intended primarily as a means to continue
program development while a compiler bug or language deficiency
is being handled.

The text string is saved intact for inclusion in the compiled
assembly source. When the assembly source is generated, a
carriage-return/line-feed is appended to the string.

A warning message is given for each use of INLINE.

3.0 SYSTEM FEATURES

3.1 Command Syntax

The general format of the initial command to BLISS-11 is:

	LSTDEV:FILE.EXT=SORCDEV:FILE.EXT,...,SORCDEV:FILE.EXT

The LSTDEV:FILE.EXT may be omitted with the implication that the
file is not to be generated. The .EXT may be omitted on any of the
file specifications and following defaults will be assumed:

Listing File:   P11
Source File:    Bll

As with other DEC system programs, switches of the form /X,
X=A,B,...,Z may be placed anywhere in a command string,
and *XY..Z)=/X/Y.../Z.

The listing file is properly formatted for immediate assembly.

3.2 Compiler Options

The actions of the compiler with respect to a program may be
controlled by specifications located in:

	1) the initial command string typed by the user,
	2) the module head, or
	3) a SWITCHES declaration.

The remainder of this section gives a list of compiler options
and the associated command switch and/or source language
constructs which specify these options.

Many of the options are two-valued switches; that is, they may be
either activated or deactivated. These cases are described by
showing both settings of the option. The affirmative or activated
setting is given first. Normally the function described will be
that of the affirmative setting. An asterisk (') indicates the
initial setting of such options.

Not all options may be specified in all places. If a particular
option cannot be manipulated in one of the three possible
locations a "--" will appear as the entry corresponding to the location.

Keep in mind that a SWITCHES declaration is in effect only for
the block in which it appears. Upon leaving a block options
revert to their previous settings.

Command Switch: /D, /-D*
Module Head:    --
SWITCHES:       --
Function: Produce symbol table and linkages for SIX12 debugging
 package.


Command Switch: /E, /-E*
Module Head:    EXPAND, NOEXPAND
SWITCHES:       EXPAND, NOEXPAND
Function: Activate tracing of macro expansions.


Command Switch: /F*, /-F
Module Head:    FINAL, NOFINAL
SWITCHES:       FINAL, NOFINAL
Function: Activate final peephole optimization. On the PDP-11 external
 devices are made available by including their control registers in the
 address space. These addresses appear to be ordinary memory
 locations. However, accessing such locations may cause unexpected
 events to occur. For example, setting a bit (in an I/O device
 register) may cause the contents of another location (the device
 buffer) to change; or, changing a single location (a segment register)
 may have drastic effects on the values at many other locations.
 The peephole optimization phase of the compiler cannot detect these
 "volatile" locations and performs optimizations assuming no such
 unusual events occur. This may result in the generation of
 incorrect object code. Peephole optimization may be suppressed by
 using this switch. The SWITCHES specification may occur only in
 the outermost block of a routine or module.


Command Switch: /H, /-H*
Module Head:    --
SWITCHES:       --
Function: Do special things for CMUs HYDRA operating system.


Command Switch: /L*, /-L
Module Head:    LIST, NOLIST
SWITCHES:       LIST, NOLIST
Function: Activate listing of source code.


Command Switch: /N, /-N*
Module Head:    NOERRS, ERRS
SWITCHES:       NOERRS, ERRS
Function: Suppress printing of warning and error messages on user's
 input terminal.


Command Switch: /O*, /-O
Module Head:    OPTIMIZE, NOOPTIMIZE
SWITCHES:       OPTIMIZE, NOOPTIMIZE
Function: NOOPTIMIZE may be used to disable all code motion
 optimizations and common sub-expression elimination across mark
 points (see Section 1.3.1), except that expressions common to all
 branches of a condtl-expr or case-expr may be computed before
 the branch point when possible. The compiler assumes
 (approximately) that at each mark point a null expression is
 executed which modifies every variable.


Command Switch: /P, /-P*
Module Head:    PIC, NOPIC
SWITCHES:       PIC, NOPIC
Function: Generate position independent code. The SWITCHES
 specification may occur only in the outermost block of a routine or
 module.


Command Switch: /Q*, /-Q
Module Head:    SAFE, UNSAFE
SWITCHES:       SAFE, UNSAFE
Function: Because of the possibility of computed addresses in a BLISS
 program, it is not always possible for the compiler to determine
 whether certain optimizations are "safe" across mark points (see
 Section 1.3.1). For example, in the expression

	BEGIN
	EXTERNAL A,B,C,D,E,F;
	A=.E+.F;
	.C=.D;
	B=.E+.F;
	END

 the assignment .C=.D may or may not affect the variables E and F,
 and the expression .E+.F may or may not have to computed twice.
 When the Q switch is on the compiler assumes that such
 optimizations are safe, i.e. in the above example .E+.F is computed
 only once. Note that variables declared as REGISTER cannot be
 affected by such assignments since the PDP-11 registers are not in
 the address space. Hence, if E and F are declared registers the
 optimization is automatically safe.


Command Switch: /S, /-S*
Module Head:    --
SWITCHES:       --
Function: Print each routine name and its size on the user's input
 terminal when the routine is finished compiling.

Command Switch: /U, /-U*
Module Head:    UNAMES, NOUNAMES
SWITCHES:       UNAMES, NOUNAMES
Function: Generate unique names for OWN variables, routine names and
 labels. The object file output by the compiler is a source file for
 a PDP-11 assembler. OWN variables, routines and labels are
 referred to in this file by their original source names. However,
 the BLISS language allows, through the use of block structure, the
 declaration of many such variables or names which have the same
 name but which indicate different items. Since the assembler does
 not provide any block structure the only way to prevent such
 names from referring to the same location is to generate unique
 names for each separate item. These names are of the form U$n
 where n is an integer.


Command Switch: /X
Module Head:    SYNTAX
SWITCHES:       SYNTAX
Function: Only perform a syntax check of the input. Do not generate
 code. This may be useful during the early stage of program
 development since a syntax check can be done considerably faster
 than a full compilation.


Command Switch: /Z, /-Z*
Module Head:    ZIP, UNZIP
SWITCHES:       ZIP, UNZIP
Function: Make some space-time tradeoffs in favor of time. The only
 decision currently affected by this switch is register saving and
 restoring. /Z forces this to be done inline rather than by the
 normal way of calling a routine. The SWITCHES form of
 specification may occur only in the outermost block of a routine or
 module.


Command Switch: --
Module Head:    IDENT = quoted-string
SWITCHES:       --
Function: Cause the assembler directive ".IDENT" to be generated with
 /quoted-string/ as its argument.


Command Switch: --
Module Head:    MAIN(E) or MAIN
SWITCHES:       --
Function: Declares that the module contains the starting point to be
 used by the loader as the loaded program's starting address. If E
 is specified it causes a stack of E words to be allocated from
 address #400 to #400+E and intializes the SP register to point to
 it.


Command Switch: --
Module Head:    RESERVE(expr-lst)
SWITCHES:       --
Function: Reserves the registers specified by the values in expr-lst.
 This prevents the compiler from generating code which uses these
 registers unless the program explicitly references them; i.e. by
 declaring a specific register such as REGISTER A=2.


Command Switch: --
Module Head:    STACK
SWITCHES:       --
Function: Equivalent to MAIN(#400).


3.3 Error Reporting

Compiler error messages are of the form:

	;TYPE#NNN ........2......3.......1 L1:NNN1 L2:NNN2 L3:NNN3
	;MESSAGE

where

	TYPE is either WARN for an informational or warning message
	    not fatal to the compilation, or ERR for a fatal error.
	    Syntax-only processing continues after a fatal error
	    message.
	NNN is the error number.
	MESSAGE is the error or warning message text.

The integers 1, 2, 3 and line indexes L1, L2, L3 and line numbers
following the line indexes provide three items of information about
the location of the error:

	1 and L1:NNN1 give the point in the text where the error was
	    detected.
	2 and L2:NNN2 give the beginning of the opening of the current
	    control scope in which the error is detected.
	3 and L3:NNN3 give the end of the last control scope
	    successfully completed prior to the error.

If any of the integers occur at the same position, then priority
is given as they are listed above.

Example:

	;      0003  X=(B=.C; .Y .Z);
	; ERR #006   .......3.2...1 L1:0003 L2:0003 L3:0003
	; IMPROPERLY FORMED ARITHMETIC EXPRESSION

4.0 RUN TIME REPRESENTATION OF PROGRAMS

4.1 Introduction To Calling Sequences

In order to make fullest possible use of BLISS-11 it is important
to understand the run-time environment in which BLISS-11 programs
execute.  The address space is occupied by various types of
information:

	1. Programs
	2. Constants
	3. Static variable areas (GLOBALS and OWNS)
	4. Run-time Stack

Programs are 'pure' - they do not modify themselves. Programs
and constant areas can be placed in contiguous read only memory.
Static variable storage and stack areas must be placed in read/write
memory.

BLISS-11 provides a number of linkage mechanisms for passing control
to or from programs written using other language processors and to
interface with the PDP-11 interrupt structure. The cases include:

	1. BLISS - standard internal calling sequence

	2. FORTRAN - FORTRAN compatible, out-of-line calling sequence
	   convention.

	3. INTERRUPT - hardware initiated routine calls via hardware
	   traps

	4. EMT, TRAP or IOT - software initiated call to interrupt
	   routine

These are discussed in turn.

4.2 BLISS-11 Internal Linkage

The first type of routine linkage discussed is used by BLISS-11
itself. The basic mechanism is simply to push the arguments onto
the stack, call the routine via register 7 (the PC), and on
return the calling program deletes the arguments from the stack.
The prototype call is thus:

	PUSH	ARG1
	PUSH	ARG2
	...
	PUSH	ARGn
	JSR	PC,SUB
	ADD	#2*N,SP

Note the following about this linkage:

    1. The called routine must access both formals and locals via
       offsets from the stack pointer (SP, Register 6).

    2. The calling sequence itself does not provide a reasonable
       means to determine the number of arguments passed. Thus
       if a variable number of arguments. are to be used, the last
       argument must be the number of arguments to enable the
       called routine to do the appropriate address arithmetic.

    3. The call is pure and reentrant.
    4. Return is via "RTS PC".
    5. The value of the called routine is returned in register zero,
       the previous contents of this register are last.

Further, the called routine is responsible for saving and restoring
any registers that are used during the execution.

4.3 BLISS-11 With Arguments Passed In Registers

The calling sequence for placing an argument in a register consists
simply of moving the value to that register instead of onto the
stack. Manipulating register contents for code efficiency is the
responsibility of the compiler.

A routine which is called with an argument in a register generates
code substantially as if the formal parameter had actually been
declared as a register.

4.4 FORTRAN Linkage [Not implemented]

The FORTRAN linkage is a mechanism compatible with the PDP-11
FORTRAN Linkage mechanism as set forth in DEC PDP-11 FORTRAN
manual, DEC-11-OXFMA-A-D. In particular, the out-of-line convention
is used. This call consists of:

		...
		JSR	PC,OUTLIN
		...

	OUTLIN:JSR	R1,$SAV5	;SAVE R1 - R5 WHICH MAY BE
					;CHANCED BY FORTRAN ROUTINE
		MOV	#ARGLIST,R5	;SET PARAMETER LIST POINTER
		JSR	PC,SUB
		RTS	PC
	ARGLIST:.BYTE	N,0
		.WORD	ARG1
		...
		.WORD	ARGN

At the call site, the appropriate values are stored into the impure
area beginning at ARGLIST. Arguments which are constant at compile
time may be set up at compile time rather than at run time.

Note that, as with FORTRAN compiled routines:

	1.  Formals are accessed relative to the argument pointer (R5,
	    register 5).

	2.  The number of arguments is available as the value of the
	    expression ".(.R5)<0,8>"

	3.  Return is via "RTS PC".

The FORTRAN standard call sequence makes available at run-time the
number of arguments actually presented to a routine. This number may
be obtained as the value of the expression.

	.(.R5)<0,8>

Note that only the low order byte is accessed.

4.5 INTERRUPT Linkage

The INTERRUPT designation is applicable only to a routine (callee)
and never to a call - that is, interrupt routines are intended to
respond directly to hardware interrupts. The requirements for the
called routine are as follows:

	1.  All register preservation and restoration is the responsibility
	    of the called routine.

	2.  Termination of the routine is via an RTI instruction.

	3.  Every INTERRUPT routine has two implicit arguments:
	    OLDPC and OLDPS which may be used to access the
	    program counter and processor status pushed onto the
	    stack by the interrupt hardware. No explicit arguments
	    (formal parameters) are permitted.

4.6 EMT/TRAP Linkage

(No Specification yet.)

4.7 Access to Variables

This section briefly indicates the mechanisms by which generated
code accesses various types of variables (formals, OWNS, and GLOBALS,
LOCALS; etc.). The exact addressing scheme used by the compiler in
any particuiar case is highly dependent upon the context; however,
the following material should aid in understanding the overall
strategy.

    1. OWN and GLOBAL variables are accessed directly. They are
       accessed by absolute addressing or by PC-relative
       addressing unless the PIC switch is on. In this case
       PC-relative addressing is used.

    2. The compiler will attempt to allocate 'simple' LOCAL variables
       to registers whenever possible and more efficient to do so.
       Several LOCAL variables, REGISTER variables, and temporary
       results may be allocated to ocupy the same physical
       location if their "lifetimes" do not overlap.

    3. Local variables and Formal parameters of the current routine
       are accessed with respect to the SP-register. Access to
       these locations depends on the action of the stack pointer
       and is not the same at every point in a routine.

4.8 Coroutine Creation and Calls

(No specification yet.)

5.0 EXAMPLES

MODULE LISTPKG=
BEGIN

MACRO NOVALUE=.VREG$;

! ITEM DEFINITION

STRUCTURE ITEM[I,J]=
   CASE .I OF
     SET
     (.ITEM);
     (..ITEM+2*.J);
     (...ITEM+2*.J);
     (.(..ITEM+2)+2*.J);
     TES;

MACRO
   BASE=O,O$,
   RLINK=1,0$,
   LLINK=1,1$,
   SIZE=1,2$,
   DATA(I)=1,(I)+3$,
   NXTRLINK=2,0$,
   NXTLLINK=2,1$,
   NXTSIZE=2,2$,
   NXTDATA(I)=2,(I)+3$,
   PRVRLINK=3,0$,
   PRVLLINK=3,1$,
   PRVSIZE=3,2$,
   PAVDATA(I)=3,(I)+3$;

FORWARD GET;

MACRO INITITEM(ITM,SZ)=
   BEGIN
   BIND ITEM I=ITM;
   I[RLINK]=I[LLINK]=.I[BASE];
   I[SIZE]=SZ
   END$;

GLOBAL ROUTINE COPYITEM(FRM,T00)=
   BEGIN
   MAP ITEM FRM:TOO;
   DECR I FROM (.FRM[SIZE] MIN .TOOCSIZE])-3 TO 0 DO
       TOO[DATA(.I)]=.FRM[DATA(.I)];
   .TOO[BASE]
   END;

GLOBAL ROUTINE NEWCOPY(ITM)=
   BEGIN
   MAP ITEM ITM;
   COPYITEM(.ITM[BASE],GET(.ITM[SIZE]))
   END;


! LIST MANIPULATION

GLOBAL ROUTINE LINK(ITM,AFTER)=
   BEGIN
   MAP ITEM ITM:AFTER;
   ITM[LLINK]=.AFTER[BASE]; ITM[RLINK]=.AFTER[RLINK];
   AFTER[NXTLLINK]=AFTER[RLINK]= .ITM[BASE]
   END;

GLOBAL ROUTINE DELINK(ITM)=
   BEGIN
   MAP ITEM ITM;
   ITM[PRVRLINK]=.ITM[RLINK]; ITM[NXTLLINK]=.lTM[LLINK];
   TM[RLINK]=ITM[LLINK]=.lTM[BASE]
   END;

GLOBAL ROUTINE EMPTY(ITM)=
   BEGIN
   MAP ITEM ITM;
   .ITM[BASE] EQL .ITM[RLINK]
   END;

MACRO FORALL(L,I,BODY)=
   BEGIN
   LOCAL ITEM I;
   BIND ITEM Z=(L);
   I[BASE]=.Z[BASE];
   WHILE (I[BASE]=.I[RLINK]) NEQ .Z[BASE] DO (BODY)
   END$;


! STORAGE ALLOCATION

BIND K=13;

STRUCTURE VECTOR2[l]=(.VECTOR2+4*.I);

OWN VECTOR2 FREE[K],
   ITEM MEM[ITK],
   VECTOR TTN[K+1]=
      ( 1 ,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192),
   VECTOR MASK[K+1]=
       (0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191);


MACRO
   BUDDIES(A,B,N)= (((A) XOR (8)) EQL .TTN[N])$,
   BASEOF(A,N)= ((A) AND NOT(.TTN[N]))$,
   INCLUDES(A,B,N)= (((A) XOR (B)) LSS .TTN[N])$;

MACRO TESTFREE(INDX,FRM,TOO,ID,CONDITION)=
   BEGIN
   INCR INDX FROM (FRM) TO (TOO) DO
      FORALL(FREE[.INDX],ID,(IF (CONDITION) THEN RETURN -1));
   END$;

ROUTINE COLLAPSE(A,N)=
   BEGIN
   MAP ITEM A;
   FORALL(FREE[.N],TN,
     (IF BUDDIES(( .TN[BASE]),( .A[BASE]),.N) THEN
       BEGIN
       DELINK( .TN[BASE]);
       COLLAPSE(BASEOF((.TN[BASE]),.N), .N+1);
       RETURN NOVALUE
       END));
   LINK(.A[BASE], FREE[.N]);
   NOVALUE
   END;

ROUTINE LOG2(N)=
   BEGIN
   LOCAL I,T;
   I=0;
   IF (T=.N) NEQ O THEN
       UNTIL (I=.l+l) GTR K DO
          IF (T=.T/2) EQL O THEN EXITLOOP .I
   END;

GLOBAL ROUTINE GET(N)=
   BEGIN
   LOCAL T;
   IF .N LSS O THEN RETURN -1;
   IF (N=LOG2(.N)) LSS O THEN RETURN -1;
   IF NOT EMPTY(FREE[.N])
      THEN DELINK(.FREE[.N])
      ELSE IF (T=GET(.N+1)) GEQ O THEN
        (LINK(INITITEM( .T+.TTN[.N],.N),FREE[.N]); INITITEM(.T,.N))
   END;

GLOBAL ROUTINE RELEASE(A)=
   BEGIN
   MAP ITEM A;
   LOCAL N;
   N=.A[SIZE];
   IF .N LSS O THEN RETURN -1;
   IF (N=LOG2(.N)) LSS O THEN RETURN -1;
   TESTFREE(I,O,.N-1 ,T,(INCLUDES( .T,.A,.I)));
   TESTFREE(I,.N,.N,T,.T EQL .A);
   TESTFREE(I,.N+1 ,K,T,(INCLUDES(.A,.T,.I)));
   COLLAPSE(.A,.N);
   O
   END;

END
ELUDOM

Appendix A - BLISS-11 Syntax

module           ::= E / MODULE module-head E ELUDOM
module-head      ::= name ( mdle-parms ) = / name =
mdle-parms       ::= mdle-parm / mdle-parm mdle-parms
mdle-parm        ::= LIST / NOLIST /ERRS / NOERRS /
                     OPTIMIZE / NOOPTIMIZE / SYNTAX /
                     PIC / NOPIC / EXPAND / NOEXPAND /
                     FINAL / NOFINAL / UNAMES / NOUNAMES /
                     SAFE / UNSAFE / ZIP / UNZIP /
                     MAIN(E) / MAIN / RESERVE(expr-lst) /
                     STACK / IDENT=quoted-string

block            ::= BEGIN blockbody END / ( blockbody )
blockbody        ::= decls ; exprs / exprs
decls            ::= decl / decl ; decls
exprs            ::= E / label : exprs / E; exprs / empty
expr-lst         ::= E / E, expr-lst / empty

comment          ::= ! string-no-eel-sym eel-sym /
                     % string-no-pet %

E                ::= smpl-expr / cntrl-expr
smpl-expr        ::= P12 / P12=E / P1 pos-size = E
P12              ::= P11 / P12 XOR P11 / P12 EQV P11
P11              ::= PIO / P11 OR P10
P10              ::= P9 / P10 AND P9
P9               ::= P8 / NOT P9
P8               ::= P7 / P8 rel-op P7
P7               ::= P6 / P7+P6 / P7-P6
P6               ::= P5 / P6*P5 / P6/P5 / P6 DIV P5 / P6 MOD P5
P5               ::= P4 / P5^P4 / P5 ROT P4
P4               ::= P3 / +P4 / -P4
P3               ::= P2 / .P3
P2               ::= P1 / .P2 pos-size
P1               ::= literal/ name / strc-access / block / routn-call
pos-size         ::= <position,size>
position         ::= compile-time-expr
size             ::= compile-time-expr
strc-access      ::= name[expr-lst] / name[alloc-unit expr-lst;expr-lst]
routn-call       ::= Pl(expr-lst)/ P1( )
rel-op           ::= EQL / NEQ / LSS / LEQ / GTR / GEQ /
                     EQLU / NEQU / LSSU / LEQU / GTRU / GEQU
literal          ::= string / number / plit
string           ::= string-type quoted-string
string-type      ::= ASCII / ASCIZ / RADIX50 / RAD50 / empty (=> ASCII)
quoted-string    ::= "strng" / 'strng'
number           ::= decimal / octal
decimal          ::= digit / digit decimal
octal            ::= #oits
oits             ::= oit / oit oits
oit              ::= 0 / 1 / 2 / 3 / 4 / 5 / 6 / 7
digit            ::= 0 / 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9
plit             ::= PLIT plitarg / UPLIT plitarg
plitarg          ::= load-time-expr / string / tuple
tuple            ::= (tuple-item-lst)
tuple-item-lst   ::= tuple-item / tuple-item , tuple-item-lst
tuple-item       ::= load-time-expr / string / dup-fctr : plitarg
dup-fctr         ::= compile-time-expr

name             ::= $ namer / letter namer
namer            ::= letter / digit / namer letter / namer digit
letter           ::= A/B/C/.../Z/a/b/c/.../z

cntrl-expr       ::= cndtl-erpr / loop-expr / choice-expr /
                     escp-expr / cortn-eupr

cndtl-expr       ::= IF E1 THEN E2 ELSE E3 /
                     IF E1 THEN E2

loop-expr        ::= WHILE E1 DO E2 /
                     UNTIL E1 DO E2 /
                     DO E1 WHILE Ep /
                     DO E1 UNTIL E2 /
                     INCR name FROM E1 TO E2 BY E3 DO E4 /
                     DECR name FROM E1 TO E2 BY E3 DO E4

esc-expr         ::= LEAVE label WITH E /
                     LEAVE label /
                     EXITLOOP E /
                     RETURN E /
                     SIGNAL E
label            ::= name

choice-expr      ::= CASE E OF SET exprs TES /
                     SELECT E OF NSET a-expr-set TESN
a-expr-set       ::= a-E / a-E ; a-expr-set
a-E              ::= E : E / OTHERWISE : E / ALWAYS : E

decl             ::= routn-decl /
                     ext-fwd-decl /
                     link-decl /
                     strc-decl /
                     alloc-decl /
                     bind-decl /
                     map-decl /
                     label-decl /
                     un-decl /
                     enable-decl /
                     macro-decl /
                     csect-decl /
                     requ-decl /
                     swtch-decl

routn-decl       ::= glbl-decl ROUTINE routn-specs
glbl-decl        ::= GLOBAL / empty
routn-specs      ::= routn-spec / routn-spec , routn-specs
routn-spec       ::= link-id name(name-lst)=E / link-id name=E

ext-fwd-decl     ::= EXTERNAL mlid-lst / FORWARD mlid-lst
mlid-lst         ::= mlid-elmt / mlid-elmt , mlid-lst
mlid-elmt        ::= link-name id-part

link-decl        ::= LINKAGE link-specs
link-specs       ::= link-spec / link-spec , link-specs
link-spec        ::= name = link-typ / name = link-typ (link-call-lst)
link-typ         ::= BLISS / INTERRUPT / EMT / TRAP / IOT / FORTRAN /
		       link-name
link-call-lst    ::= link-arg / link-arg , link-call-lst
link-arg         ::= STACK / REGISTER=num
num              ::= 0 / 1 / 2 / 3 / 4 / 5

strc-decl        ::= STRUCTURE name strc-fml-lst = strc-size E
strc-fml-lst     ::= [name-lst] / empty
strc-size        ::= [E] / empty

alloc-decl       ::= alloc-unit init-type msid-lst1 /
                     alloc-unit REGISTER msid-lst2 /
                     alloc-unit other-type msid-lst3
alloc-unit       ::= WORD / BYTE / empty (=> WORD)
init-type        ::= OWN / GLOBAL
other-type       ::= LOCAL / EXTERNAL / STACKLOCAL

msid-lstn        ::= msid-elmtn / msid-elmtn, msid-lstn
msid-elmtn       ::= link-id strc-id id-groupsn / link-id strc-id id-part /
                     link-id strc-id id-groupsn: id-part
id-groupsn       ::= id-groupn / id-groupn: id-groupsn

id-group1        ::= id-part size-part init-part /
                     id-part size-part / id-part init-part
id-group2        ::= id-part size-part reg-part /
                     id-part size-part / id-part reg-part
id-group3        ::= id-part size-part

id-part          ::= name / name : id-part
size-part        ::= [ expr-lst ]
init-part        ::= = plitarg
reg-part         ::= = oit
strc-id          ::= strc-name / empty (=> VECTOR)
strc-name        ::= name
link-id          ::= link-name / empty (=> BLISS)
link-name        ::= name

map-decl         ::= MAP msid-lst3
bind-decl        ::= BIND msid-lst4
id-group4        ::= id-part size-part bind-part / id-part bind-part
bind-part        ::= = E

label-decl       ::= LABEL name-ist
un-decl          ::= UNDECLARE name-ist
enable-decl      ::= ENABLE a-expr-set ELBANE

macro-decl       ::= MACRO dfn-lst
dfn-lst          ::= dfn / dfn , dfn-lst
dfn              ::= name fxd-parms itrd-parms = body $
fxd-parms        ::= (name-lst) / empty
itrd-parms       ::= [] / [name-lst] / empty

name-ist         ::= name / name , name-ist

csect-decl       ::= CSECT name / PSECT name /
                     CSECT keys / PSECT keys
keys             ::= key / key , keys
key              ::= keyword = quoted-string
keyword          ::= CODE / DEBUG / GLOBAL / OWN / PLIT

requ-decl        ::= REQUIRE filespec
filespec         ::= device filenamespec
device           ::= name: / empty (=> DSK:)
filenamespec     ::= filename / filename[ppnspec]
filename         ::= name / name.name
ppnspec          ::= octal , octal / CMU-ppn / empty (=> ppn of job)

swtch-decl       ::= SWITCHES swtch-lst
swtch-lst        ::= swtch / swtch swtch-lst
swtch            ::= LIST / NOLIST ERRS / NOERRS /
                     OPTIMIZE / NOOPTIMIZE / EXPAND / NOEXPAND /
                     SAFE / UNSAFE / ZIP / UNZIP /
                     FINAL / NOFINAL /PIC / NOPIC /
                     UNAMES / NOUNAMES

spcl-rout        ::= emt-call / trap-call / iot-call / HALT() /
                     RESET() / WAIT() / SWAB(E)
emt-call         ::= EMT(compile-time-expr , expr-lst)
trap-call        ::= TRAP(compile-time-expr , expr-lst)
lot-call         ::= IOT(expr-lst)

inline           ::= INLINE(quoted-string)

empty            ::= The empty string
strng            ::= A sequence of characters
compile-time-expr::= Expression with constant value at compile time
load-time-expr   ::= Expression with constant value at load time
eel-sym          ::= Character which indicates the end of a source line
string-no-eol-sym::= A strng which does not contain an eel-sym
string-no-pet    ::= A strng which does not contain a per-cent sign


Appendix B - Description of Non-Terminals of BLISS-11 BNF

The non-terminal mnemonics appear in the same order as they are
defined in Appendix A.

module
    An independently compilable and linkable entity.

module-head
    The beginning of a module consisting of a module name and
    parameters which affect the type of module produced.

mdle-parms
    A list of module parameters separated by commas.

mdle-parm
    A single module parameter. Module parameters specify various
    compilation options.

block
    An explicit grouping of declarations and/or expressions. A block
    defines the lexical scope of declarations.

blockbody
    A series of declarations and/or expressions separated by
    semi-colons.

decls
    A series of declarations separated by semi-colons.

exprs
    A series of optionally labeled expressions separated by
    semicolons.

expr-lst
    A list of expressions separated by commas.

comment
    Source text ignored by the compiler.

E
    An expression.

smpl-expr
    A simple expression; i.e. an expression containing no unbracketed
    control expressions.

Pn
    n has some integer value between 1 and 12. Language
    elements which compute a single value. These consist of
    literals, names, structure names, routine calls, and blocks or
    larger expressions built up from these. Pi with larger i are
    built up from Pj's with j<i. This corresponds to precedence
    order.

pos-siz
    A position-size specification. This is used to select a subfield
    of a word.

position
    The bit position (bit O is the least significant bit of a word) of
    the least significant bit of a subfield of a word.

size
    The number of bits in a subfield of a word.

strc-access
    A structure access.

routn-call
    A routine call.

relop
    The relational operators. Those ending in "U" are unsigned
    relationals, i.e. they treat their operands as 16-bit unsigned
    integers. The others consider their operands to be signed
    integers.

literal
    An atom which represents itself at compile time.

string
    A string of characters in the format specified by the string-type
    component.

string-type
    A symbol used to indicate the internal storage representation of
    string. This can be ASCII, ASCIZ, RADIX50, or RAD50. The
    default is ASCII.

quoted-string
    A string of characters enclosed in quotes.

number
    An unsigned integer specified in either decimal or octal format.
    The permitted range is from -2^15 to 2^15-1.

decimal
    A decimal integer, i.e. a sequence of decimal digits.

octal
    An octal integer, i.e. a sequence of octal digits preceded by "#".
    The "#" is used to indicate that it is in octal format.

oits
    A sequence of octal digits.

oit
    An octal digit.

digit
    A decimal digit.

plit
    A pointer to a literal.

plitarg
    The argument of a plit.

tuple
    A parenthesized list of tuple items.

tuple-item-lst
    A list of tuple items separated by commas.

tuple-item
    A tuple item is the basic element used to specify data values in
    a plit argument.

dup-fctr
    Duplication factor for a data element in a plit.

name
    A letter or dollar-sign followed by letters and/or digits. A
    name is used to identify variables, structures, macros, routines,
    etc.

letter
    An upper or lower case letter. Note that a lower case letter is
    considered equivalent to its upper case counterpart.

cntrl-expr
    A control expression; i.e. an expression which may alter the
    standard sequential execution sequence within BLISS-11 programs.

cndtl-expr
    A conditional expression.

loop-expr
    A loop expression; i.e. the specification of an expression which
    is to be repeatedly executed until some halting criterion is
    satisfied.
esc-expr
    An escape expression; i.e. an expression whichenables the
    termination of a control context.

label
    A name currently defined by a LABEL declaration.

choice-expr
    A choice expression.

a-expr-set
    An associative expression set. The argument list for a SELECT
    expression.

a-E
    An associative expression.

decl
    A declaration.

routn-decl
    Routine declaration. Used to introduce the definition of routines.

glbl-decl
    Possible specification that a routine name is to be declared
    GLOBAL.

routn-specs
    A list of routine definitions separated by commas.

routn-spec
    A single routine definition.

ext-fwd-decl
    An external or forward routine declaration.

mlid-lst
    A list of mlid-elmt's separated by commas.

mlid-elmt
    A group of routine names in an EXTERNAL or FORWARD
    declaration which all have the specified linkage name associated
    with them.

link-decl
    A linkage declaration defines a set of calling sequences.

link-specs
    A list of link-spec's separated by commas.

link-spec
    A single specification of a user-defined calling sequence.

link-typ
    The linkage type component of a linkage declaration which
    specifies the basic characteristics of the calling sequence.

link-call-lst
    A list of arguments in a linkage declaration which specify the
    locations of passed parameters as either on the STACK or in a
    REGISTER.

link-arg
    A specification of parameter location.

num
    A number used to identify a specific register.

strc-decl
    A structure declaration.

strc-frml-lst
    A list of the formal parameters used in the definition of a
    structure.

strc-size
    An algorithm used to compute the number of bytes of storage
    to allocate to a name declared to associated with the structure.

alloc-decl
    A declaration used to establish names for storage segments,
    specify their size, and optionally associate them with a structure.

alloc-unit
    A specification of the basic storage unit of a storage segment.

init-type
    Types of declarations which may include a specification of data
    to be used as initial values of the declared variables.

other-type
    Other types of allocation declarations.

msid-lst,
    A list of msid-elmt,'s separated by commas.

msid-elmt,
    A main structure identifier element. Optional linkage and
    structure specifications followed by names which are to be
    associated with the linkage and structure.

id-groups,
    A list of id-group,'s separated by commas.

id-group,
    A series of names separated by colons and followed by a
    specification of some information to be associated with all of the
    names.

id-part
    A list of names separated by colons.

size-part
    A specification of incarnation actuals used by a structure.

init-part
    A specification of data to be used as initial values in a storage
    segment.

reg-part
    A specification of a particular register.

strc-id
    A specification of a structure name. The default is VECTOR.

strc-name
    A name currently defined by a STRUCTURE declaration.

link-id
    A specification of a linkage name. The default is BLISS.

link-name
    A name currently defined by a LINKAGE declaration.

map-decl
    A map delclaration. Used to (re)define, the access algorithm
    associated with a name.

bind-decl
    A bind declaration.

bind-part
    A specification of a value to be used as a pointer.

label-decl
    A label declaration.

un-decl
    An undeclare declaration.

enable-decl
    An enable declaration.

macro-decl
    A macro declaration. Used to define a set of macros.

dfn-lst
    A list of macro definitions separated by commas.

dfn
    A macro definition.

fxd-parms
    The fixed parameters of a macro definition.

itrd-parms
    The iterated parameters of a macro definition.

name-lst
    A list of names separated by commas.

csect-decl
    A csect or psect name definition.

keys
    A list of key's separated by commas.

key
    A specification of the parameters to be used with a particular
    PSECT or CSECT.

keyword
    A name used to identify a particular CSECT or PSECT.

requ-decl
    A require declaration.

filespec
    The specification of a file.

device
    The specification of an I/O device name. The default is DSK.

filenamespec
    A specification of a file name and project-programmer code.

filename
    A specification of a file name with or without a file extension.

ppnspec
    The specification of a project-programmer code.

swtch-decl
    A declaration of compiler options to be used for a block.

swtch-lst
    A list of swtch's separated by commas.

swtch
    A switch which declares a compiler option.

spcl-rout
    A special routine call used to implement a machine-dependent
    operation.

emt-call
    A special routine call to issue an EMT.

trap-call
    A special routine call to issue a TRAP.

lot-call
    A special routine call to issue an IOT.

inline
    A specification of a line of machine code to be include in the
    object file.

Appendix C - Reserved Names

The following list contains all the names reserved in the language:

ALWAYS             GTRU               REGISTER
AND                IF                 REQUIRE
ASCII              INCR               RETURN
ASCIZ              INLINE             ROT
BEGIN              LABEL              ROUTINE
BIND               LINKAGE            SELECT
BY                 LEAVE              SET
BYTE               LEQ                SIGNAL
BYTES              LEQU               STACKLOCAL
CASE               LOCAL              STRUCTURE
CSECT              LSS                SWITCHES
DECR               LSSU               TES
DIV                MACRO              TESN
D0                 MAP                THEN
ELBANE             MAX                TO
ELSE               MIN                UNDECLARE
ELUDOM             MOD                UNTIL
ENABLE             MODULE             UPLIT
END                NEQ                WHILE
EQL                NEQU               WITH
EQLU               NOT                WORD
EQV                NSET               XOR
EXITLOOP           OF                 SCOUNT
EXTERNAL           OR                 $LENGTH
FORWARD            OTHERWISE          $NAME
FROM               OWN                $QUOTE
GEQ                PLIT               $REMAINING
GEQU               PSECT              $STRING
GLOBAL             RAD5O              $UNQUOTE
GTR                RADIX50


Appendix D - Predefined Identifiers

STRUCTURE VECTOR[I] I [I*BYTES] (.VECTOR+BYTES*.I)<0,BYTES*8>;

LINKAGE BLISS    = % PREDEFINED %,
    EMT          = % PREDEFINED %,
    FORTRAN      = % PREDEFINED %,
    HYDRA        = % PREDEFINED %,
    IHYDRA       = % PREDEFINED %,
    INTERRUPT    = % PREDEFINED %,
    IOT          = % PREDEFINED %,
    TRAP         = % PREDEFINED %,
    BLISSREG1    = BLISS(REGISTER=1),
    BLISSREG2    = BLISS(REGISTER=1 ,REGISTER=2),
	...
    BLISSREGS    = BLISS(REGISTER=1,.. .,REGISTER=5);

REGISTER RO:VREG=0, R1=1, R2=2, R3=3, R4=4, RS=5, SP=6, PC=7;

! Out-of-line routines for various operators

EXTERNAL BLISS MUL:DIVR:MODR:ROTATE:SHIFT:EXCHJ;

! Out-of-line routines to save and restore registers

EXTERNAL %SPECIAL LINKAGE% $SAV2:$SAV3:$SAV4:$SAV5;

! Entry points in the SIX12 debugging package

EXTERNAL BLISS INIT612:SIX12:ESIX12;
EXTERNAL % SPECIAL LINKAGE % XSIX12

! Out-of-line routines to handle SIGNAL and ENABLE

EXTERNAL % SPECIAL LINKAGE % $SIGNL:$SIGN1 :$ENABL;

! Global data used by SIGNAL and ENABLE

EXTERNAL SIGVAL,SIGREG;

Appendix E - RADIX50(RAD50)

The following codes show the internal storage conventions for
RADIX50. All numeric values in the table are octal.


FIRST CHAR            SECOND CHAR       THIRD CHAR

A  003100             000050            000001
B  006200             000120            000002
C  011300             000170            000003
D  014400             000240            000004
E  017500             000310            000005
F  022600             000360            000006
G  025700             000430            000007
H  031000             000500            000010
I  034100             000550            000011
J  037200             000620            000012
K  042300             000670            000013
L  045400             000740            000014
M  050500             001010            000015
N  053600             001060            000016
O  056700             001130            000017
P  062000             001200            000020
Q  065100             001250            000021
R  070200             001320            000022
S  073300             001370            000023
T  076400             001440            000024
U  101500             001510            000025
V  104600             001560            000026
W  107700             001630            000027
X  113000             001700            000030
Y  116100             001750            000031
Z  121200             002020            000032
$  124300             002070            000033
.  127400             002140            000034
   132500             002210            000035 (UNUSED)
O  135600             002260            000036
1  140700             002330            000037
2  144000             002400            000040
3  147100             002450            000041
4  152200             002520            000042
5  155300             002570            000043
6  160400             002640            000044
7  163500             002710            000045
8  166600             002760            000046
9  171700             003030            000047


Appendix F - Error Messages

ID   Message
O    UNDECLARED IDENTIFIER
1    MISPLACED DECLARATION
2    EXPRESSION IN WRONG CONTEXT
3    BEGIN...) AND (...END ARE ILLEGAL
4    OPERATOR IN ILLEGAL CONTEXT
5    CONTROL EXPRESSION MUST BE PARENTHESIZED
6    IMPROPERLY FORMED ARITHMETIC EXPRESSION
7    IMPROPERLY FORMED ARITHMETIC EXPRESSION
8    MISSING THEN IN IF EXPRESSION
9    MISSING DO AFTER WHILE OR UNTIL
10   MISSING WHILE OR UNTIL AFTER DO
11   IMPROPERLY DEFINED CONTROL VARIABLE
12   MISSING DO AFTER INCR OR DECR
13   PARAMETER LIST NOT CLOSED PROPERLY
14   IMPROPER SELECTION LIST 1N CASE
15   MISSING SET AFTER CASE
16   MISSING TES AFTER SET
17   IMPROPER SELECTION LIST IN SELECT
18   MISSING NSET AFTER SELECT
19   COLON MISSING IN SELECT EXPRESSION
20   MISSING TESN AFTER NSET
21   ADDRESS ARITHMETIC INVOLVING LOCAL
22   ILLEGAL OCCURRENCE OF POINTER EXPRESSION
23   INVALID POSITION EXPRESSION IN POINTER
24   INVALID SIZE EXPRESSION 1N POINTER
25   POINTER EXPRESSION CROSSES WORD BOUNDARY
26   POSITION SPECIFIED IS GREATER THAN 16
27   BAD SYNTAX IN INLINE
28   INLINE ARGUMENT MUST BE STRING
29   CAVEAT EMPTOR! (USE OF INLINE)
30   MISSING COLON IN ENABLE
31   MISSING ELBANE AFTER ENABLE
32   MORE THAN ONE ENABLE IN BLOCK
33   MISSING OPEN PARENTHESIS IN EXCHJ
34   MISSING COMMA IN EXCHJ
35   MISSING CLOSE PARENTHESIS IN EXCKI
39   NON-ADDRESSABLE SYMBOL USED AS EXPRESSION
40   LABEL NOT USED ON THIS EXPRESSION
41   LABEL NOT YET ENCOUNTERED
42   MUST LEAVE TO LABEL
46   REGISTER NOT AVAILABLE FOR RESERVATION
47   TOO MANY CLOSE BRACKETS OR MISSING OPEN BRACKET
48   ERROR IN MODULE HEAD; SCAN RESTARTED AT FIRST BEGIN
49   INVALID SWITCH SPECIFIED
50   SYMBOL ALREADY DECLARED IN THIS BLOCK
51   SYNTAX ERROR IN SWITCH SPECIFICATION
52   EXPRESSION MUST BE LITERAL
53   UNDECLARED STRUCTURE
54   INVALID STRUCTURE NAME
55   MISSING EQUAL SIGN
56   DELIMITER MUST BE COMMA OR SEMICOLON
57   MORE THAN 1 EXPRESSION IN PARENTHESIS
58   ILLEGAL SYMBOL BEFORE DECLARATOR NAME
59   REGISTER NOT AVAILABLE
60   MISSING BRACKET AFTER SIZE FIELD
61   MISSING SEMICOLON AFTER DECLARATION
62   MODULE DECLARATION INSIDE MODULE BODY
63   SIZE FIELD ILLEGAL IN LABEL DECLARATION
64   REGISTER TO BE ALLOCATED ALREADY IN USE
65   MISSING EQUAL 1N ROUTINE DECLARATION
66   MISSING OPERATOR
67   NO DECLARATION FOLLOWING BYTE
68   INVALID USE OF POINTER
69   STRUCTURE NAME MUST BE DOTTED IN ITS BODY
70   MUST NOT DOT A FORMAL IN SIZE EXPRESSION
71   MISSING CLOSING BRACKET IN PARAMETER LIST
72   SYMBOL OR LITERAL AFTER CLOSE BRACKET
73   EQUAL SIGN MISSING IN STRUCTURE OR MACRO
74   MISSING ACTUAL PARAMETER LIST
75   MISSING ACTUAL PARAMETER
76   EXTRA ACTUAL PARAMETERS IN STRUCTURE ACCESS
77   MISSING CLOSING BRACKET IN STRUCTURE ACCESS
78   MISSING SEMICOLON IN STRUCTURE ACCESS
79   MISSING ACTUAL PARAMETER LIST DELIMITER
80   INVALID ESCAPE CHARACTER
81   MISSING RIGHT QUOTE
82   MISSING CLOSE PARENTHESIS IN PLIT
83   PLIT DUPLICATION FACTOR NOT LITERAL
84   PLIT ARGUMENT NOT LITERAL AT LOAD TIME
85   ILLEGAL USE OF LONG STRING
86   ROUTINE DECLARED FORWARD IS NOT DEFINED
87   SIZE OF INITIAL VALUE SPECIFICATION EXCEEDS DECLARED SIZE
88   STRING FUNCTION REQUIRES STRING ARGUMENT
89   CSECT DECLARATION ERROR - IGNORED
90   MISSING EQUAL IN LINKAGE DECLARATION
91   NO LINKAGE TYPE SPECIFIED
92   TOO MANY PARAMETERS IN LINKAGE DECLARATION
93   MISSING COMMA IN LINKAGE DECLARATION
94   PARAMETER TYPE NOT STACK OR REGISTER
95   INVALID REGISTER NUMBER
96   CANNOT MAP TRAP LINKAGE TYPE
97   ILLEGAL CHARACTER IN RADIX 50 STRING
100  ATTEMPT TO DIVIDE BY ZERO
101  MISSING SYMBOL IN DECLARATION
103  ILLEGAL UP-LEVEL ADDRESSING
502  REQUIRE FILE NOT FOUND
503  INVALID PPN FORMAT IN REQUIRE
504  REQUIRE DEVICE ERROR
505  REQUIRE DECLARATIONS NESTED MORE THAN 11 LEVELS
511  NOT IMPLEMENTED YET