@V7 54 2 -5
@L5 HIUK1047
0
85  85  85  85  85  85  85  85
85  85  85  85  85  85  85  85
85  85  85  85  85  85  85  85
85  85  85  85  85  85  85  85
85  58  78  85  85  127 90  60
85  85  90  85  85  85  85  85
85  85  85  85  85  85  85  85
85  85  85  85  85  85  85  85
100 91  99  107 109 93  90  109
111 50  82  93  78  127 112 109
90  109 100 89  90  115 95  127
86  83  87  55  72  55  80  91
60  84  87  82  87  84  50  87
83  46  46  74  46  125 83  85
87  87  61  76  45  83  65  100
63  65  65  55  50  55  85  127
@L2 GREE1247
80
@L3 COUK1247
80
@V9 0
@YCHAPTER 9 - MUSS USER MANUAL
@G@RCHAPTER 9 - THE OVERALL ORGANISATION OF MUSL@G
@V10 1 9 137
@T% 10
@S29.1 INTRODUCTION
@T% 10
@BThe overall structure of MUSL reflects its principle function,
namely the implementation of MUSS.
In designing such a language for operating system implementation one of
two approaches can be taken. First an attempt can be made to
formally cater for the operating system requirements in the
'virtual machine' provided by the language. For example, the notion
of tasks (or processes) and multi-tasking can be included.
However, this tends to move some of the operating system
functions into the runtime package of the
language rather than providing the means for
their implementation.
The second approach, which is the one followed in MUSL,
is to allow direct access, through the language, to the actual machine.
Thus an operating system written in MUSL controls directly the
use of store, CPU and peripherals.
Many of the special features of MUSL will not be
required for writing simple user programs, and the
underlying basic language is straightforward and Pascal-like.
@BFor the purpose of describing the syntax of MUSL this manual
uses a variant of BNF. This will be mostly self evident to readers
familiar with this kind of notation. For example@
@
@M<A> ::= W!X[Y!Z]
@
means that the syntactic element A may be W, XY or XZ. Also@
@
@M<B> ::= <A>[<B>!<NIL>]
@
means that B may be@
@Q 8
@
@M   W or XY or XZ
@Nor WW or WXY or WXZ
@Nor XYXY or XYW or XYXZ
@Nor XZXZ or XZW or XZXY
@Nor WWW or WWXY or WWXZ
@N      and so on.
@
@
NIL is the only reserved name used, but some notation
is required for the symbols <,>, !, [, ] and this is <<>,<>>, <!>, <[>, <]>.
@S39.1.1 Modular Structure
@BSoftware written in MUSL is normally subdivided into modules. A
single module is all that the compiler will accept. In the simplest
case a module can be a complete program, but more commonly a program
will consist of several modules and MUSS consists of many modules.
Since the MUSL compiler only deals with single modules, it follows
that the compilation of multi-module software will involve several
calls on the MUSL compiler (one for each module), and that provision
for inter-module linking has to be made outside of the compiler. This
Chapter is mainly concerned with the rules for writing single modules
but some discussion of module linking is appropriate to set the
context.
@S39.1.2 Module Linking
@BLike all other compilers in the MUSS system the MUSL compiler
generates code indirectly through calls on the MUTL (target language)
procedures. These procedures can be instructed to generate either
relocatable or executable binary. In the former case inter-module
linking is postponed until the final link-loading pass, whereas in
the latter case it becomes the responsibility of the MUTL procedures,
and is carried out as the compilation proceeds. The MUTL procedures
and the link-loading scheme are described elsewhere but to give an
understanding of how modules of MUSL fit together some repetition is
appropriate here. It will be sufficient to consider the case where
the MUTL procedures are generating executable binary, and hence
performing the inter-module linking.
@S39.1.3 The Storage Model
@BStatements described under 9.4.1 allow a user to separate
both the code and the data, contained in a module, into @5areas@0.
This facility might be used in a module of the operating system,
for example, to separate the code that needs to be resident in
main store from that which might be paged, and similarly for the
data structures. The MUTL system provides the means for areas
to be placed at actual addresses.
@BMUTL considers the actual store to be subdivided into
@5segments@0. Each of these has a number, for identification
purposes, a size, a runtime address and a compile time address
(all in units of bytes). They are defined by calling the MUTL
procedure TL.SEG. In fact TL.SEG has one further parameter
as described in Chapter 23, but its function is not
appropriate to understanding MUSL.
Areas are related with segments
by the MUTL procedure@
@
@MTL.LOAD (MUTL segment number, MUSL area number).
@BArea 0 has a special significance of which the user
must be aware. It is the runtime procedure stack (9.2.5),
whose placement is determined by the MUTL system rather than
by the user.
@BAfter the storage requirements have been specified for
the set of modules that require to be linked, they are compiled
by a sequence of calls on the MUSL compiler
one for each module. Unless the defaults described in 9.1.6
are adequate each module should be preceded by calls on TL.LOAD
to cause proper placement of its Areas.
As the compilation
proceeds, the code and data items of the areas will accumulate
in their respective segments. If more than one area of a
module is mapped into a given segment, some interleaving may
occur, depending upon the placement of area selection directives
(9.4.1) in the source.
@S39.1.4 Initialisation
@BIt will be obvious from what has gone before that the MUTL
procedures will require data structures that carry information
across many individual MUTL procedure calls. These data structures
must be initialised, therefore at the start of a
compilation the procedure TL (MODE) should be called. Also there are
some final checks required after the last module of a compile
job and the procedure TLEND must be called.
@S39.1.5 Modes of Compilation
@BFor a 'normal' compilation of a user program the value
0 for the MODE parameter of TL
selects appropriate options. The full range of
options are described in Section 2.5.2 and in Chapter 23.
@S39.1.6 The Command Structure of a Typical Compile Job
@BIn the most general case the sequence of commands
required to control a compilation would be@
@Q 8
@T% 10
@
%a call on @GTL@G@
%one call on @GTL.SEG@G for each segment@
%one call on @GTL.LOAD@G for each area of the 1st module@
%a call on MUSL to compile the 1st module@
%a further sequence of calls on @GTL.LOAD@G followed@
%by a call on MUSL for each additional module@
%finally a call on @GTL.END@G.@
@BHowever if the MUSL compiler is called with appropriate
zeros in its MODE parameter it will call TL and TL.MODULE
at the start and TL.END.MODULE and TL.END at the end. The
least significant 8 bits of the compiler mode will be used
as the TL mode.
@BWhen TL is called with a 'normal' MODE, segment 0 is
automatically created (for code) and area 1 is automatically
mapped into it at the start of each module. As stated earlier, area 0 is the pro
cedure stack,
and its placement in store is controlled by MUTL. That is area 0 cannot
be mapped into a user created segment. Thus, for a simple program
TL.SEG and TL.LOAD calls are not necessary.
@BAlso unless directives (9.4.1) are used to control the
placement of code and variables, all code will be placed in
area 1 (segment 0) and variables will be placed in area 0
(the stack).
In more complicated situations
segments are created at the start of a compilation, and the
mapping of areas into segments is given separately for each module.
@S39.1.7 The Format of a Module
@BIn the general case a module will use procedures, and
possibly literals, data structures, types and labels declared
in other modules. Declarations for these entities, known
as the 'imports' to the module, must precede the module
heading. The module heading itself serves three functions. First
it indicates the start of the module and the entities
declared after the heading are private to the module unless
they are formally 'exported'. The second function is to allow
these exports to be specified, as a list of names enclosed
in parentheses. The third function is to provide the option of
assigning a name to the module. If this option is used then all
references to the exports from the module in other modules
must prefix the name of the exported entity by the
module name. A module is terminated by '*END' and
on encountering this the compiler will 'exit'.
@BMore formally the syntax of a module is@
@3
@U 5
@
                         <MODULE> ::= <IMPORTS>
                                      MODULE[<NAME>!<NIL>]<EXPORTS>
                                      <STATEMENTS>
                                      *END
@0
@
@
The IMPORTS are declarations of entities exported from
other modules. Their exact form will be discussed in
9.5.11, however, it should be noted that they are of
two kinds. If the full detail of an imported entity is needed
by the compiler, in order to compile references to it inside the module,
a full duplicate declaration must be used (as in
the above example).
If there is no relevant detail a special import
declaration (9.5.11) is used that gives only the name and
kind of the entity.
@BThe EXPORTS of a module are an optional list
of names of entities declared within the module thus@
@3
@
@M  <EXPORTS> ::= (<NAME.LIST>)!<NIL>
@N<NAME.LIST> ::= <NAME>[,<NAME.LIST>!<NIL>]
@0
@BFor example, a module M2 that imports a procedure P1, which is
exported from another module M1, and exports itself two procedures
P2, P3 would have the general form@
@Q 21
@
@MPSPEC M1.P1(INTEGER)
@NMODULE M2(P2,P3)
@NPSPEC P2(INTEGER)
@NPSPEC P3(INTEGER)
@NPROC P2(I)
@N  .
@N  .
@Nstatements of P2
@N  .
@N  .
@NEND
@NPROC P3(J)
@N  .
@N  .
@Nstatements of P3
@N  .
@N  .
@NEND
@N*END
@
@
It is assumed in the example that P1, P2, P3 each have one integer
parameter. Obviously any external references to P2 and P3 must use
the names M2.P2, M2.P3.
@BSTATEMENTS are discussed more fully in subsequent Sections
but it might be helpful to give an approximate picture of how
they relate to modules and programs at this point.
They fall into two main groups, declaratives and imperatives.
The norm is for the declaratives to come first. Again the norm
will be for most of the statements in a module to be
concerned with defining
procedures. That is, they will be contained
within procedure bodies that are delimited by the procedure
headings and the matching ENDs. Thus a
module will typically take the form@
@Q 12
@
@Mimport declarations
@Nmodule heading
@Ndeclaratives
@Nimperatives
@N     procedure heading
@N     procedure body
@N     END
@N      .
@N      .
@N      .
@N*END
@S39.1.8 Kinds of Modules
@BThere are now several cases to consider
in order to convey the significance of modules.
@BIf the module is an ordinary program, a run
of the program implies executing the imperative
statements, in the main body of the module.
These may call the procedures
enclosed in the module which will cause the
imperatives that they contain to be executed.
Thus the imperatives at the outer level might be regarded as the
'main program'. A
simple variant of this case is where the module
is one of several that make up a complete
program. In this case the imperative parts
of each module will be joined together in
the order in which they are loaded.
In most of the modules the imperative statements,
in their main body, will usually be concerned with
initialising the global data structures of the module,
whilst that of one module will form the main program.
Clearly the user must be conscious of the order of
execution.
@BSometimes in a program that consists of several modules,
some of the modules may be entirely passive,
in that they contain no imperatives in their
main body. In this case
the only way that the procedures of the module
can be executed is through calls of the exported ones,
occurring in other 'active' modules.
@BModules of this kind can be treated as
libraries, which are compiled and filed, to
be repeatedly used by other programs after
being 'opened' by use of the LIB command.
The main body of a library module may in fact contain imperatives
statements, in which case they will be
executed when the library is opened. Their
function, therefore, is to initialise the data
structures of the module.
@BSome modules form part of the MUSS
system library. They are permanently 'open',
hence they cannot have initialisation statements.
If initialisation is required, as in the case
of the MUTL procedures, a procedure
(e.g. TL) must be provided that can be
explicitly called by the user.
@S29.2 KINDS OF STATEMENTS AND SCOPE RULES
@S39.2.1 Kinds of Statement
@BThere are a number of places in the language specification where
an arbitrary sequence of statements occur. Thus there is a need
for the definition@
@3
@
@M<STATEMENTS> ::= <STATEMENT>[<STATEMENTS>!<NIL>]
@0
@
This section is concerned with various kinds of STATEMENT that exist
in the language. It will be apparent that not all kinds of statement
are appropriate in every context and norms will be suggested.
However, the detailed constraints will only be given as the individual
statements are described in later chapters.
@BThere are five main kinds of STATEMENT as follows@
@3
@U 6
@
               <STATEMENT> :: = <DECLARATIVE.STATEMENT>!
                                <IMPERATIVE.STATEMENT>!
                                <DIRECTIVE.STATEMENT>!
                                <PROC.DEFN>!
                                <BLOCK>!
@0
@S39.2.2 Declaratives
@BThe declarative statements normally appear at the start of a MODULE,
PROCEDURE or BLOCK. With the single exception of LABELS (9.5) a
declaration must be given for every name introduced into a module, before any
other use of the name is permitted. The main function of declarative
statements is to create entries on the name and property lists of
the compiler. They do not, directly, result in the generation of
executable code although they may contribute to the code, executed
at procedure entry and exit time, that is concerned with dynamic
storage allocation.
@S39.2.3 Imperatives
@BThese statements are the means by which the computations are specified.
Normally each MODULE, PROCEDURE and BLOCK will have a sequence of
imperative statements following its declarative statements. They are fully discu
ssed in 9.7,
but briefly they consist of the usual forms of statement such as:@
@Q 6
@
@Mstatements that express computations
@Nprocedure calls
@NFOR/WHILE loops
@NIF/THEN/ELSE statements
@Nswitches
@S39.2.4 Directives
@BThese statements relate more directly to the compiler and the underlying MUTL
than to the
language. Their function is to select 'modes' of compilation. Some
directives merely set switches in the compiler, whilst others allow
the environment of the compilation to be manipulated by means of
direct calls on the MUTL procedures and other MUSS Library
Procedures. Obviously the positions in which they are placed must
be carefully chosen in relation to the action they have. Some
guidance on this is given along with their descriptions in
9.4.
@S39.2.5 Procedure Definitions
@BA procedure has to be both declared
and defined. Procedure declarations, which are described
in 9.5, specify the name of a procedure,
and the number and type of its parameters and result.
A procedure definition gives the code body of
the procedure that is to be executed on each call.
@BA procedure is defined by a heading followed by a sequence of
statements terminated by END.@
@3
@U 4
@
                    <PROC.DEFN> ::= <PROC.HEADING>
                                    <STATEMENTS>
                                    END
@0
@
@
Normally the STATEMENTS will consist of DECLARATIVES followed by
IMPERATIVES.
@BThe function of the PROC.HEADING is to give the name of the
procedure and the names of any parameters that it may have.@
@3
@
@M<PROC.HEADING> ::= PROC<NAME>[(<NAME.LIST)!<NIL>]
@0
@
At runtime each call of a procedure causes space to be allocated dynamically on
a
'procedure stack' containing linkage information, parameters, and the variables
declared
within the procedure. Hence procedures may be recursive.
@BAlthough every procedure must be declared before it can
be used or defined, the definition need not precede
calls on the procedure. The only restrictions on the placement
of the definition of a procedure are that it must come
after the declaration of the procedure and be at the same level
of the block structure (see 9.2.7).
@S39.2.6 Blocks
@BA BLOCK is a sequence of statements delimited by BEGIN and END.@
@3
@U 4
@
                         <BLOCK> ::= BEGIN
                                     <STATEMENTS>
                                     END
@0
@
@
Normally the statements will consist of IMPERATIVES possibly preceded
by some DECLARATIVES. The main purpose of the BLOCK construct is
to represent a group of statements as a single statement. This is
useful in some of the control constructs described in 9.7
where only a single STATEMENT is admissible. Another use of the
BLOCK construct is to localise the 'scope' of the entities declared
in the block to the statements that it contains.
@S39.2.7 Scope and Block Structure
@BThe language allows blocks and procedures to be nested inside
each other to any depth and the implications of this must be
understood. Consider the module shown schematically below@
@3
@U 22
@
          MODULE
          declaration of procedure A
          declaration of procedure B
            .
            .
               PROC A
               declaration of procedure C
                 .
                 .
                    PROC C
                      .
                      .
                    END
               END
               PROC B
                 .
                 .
               END
          *END
@0
@
@
Subject to certain restrictions the overall scope rule is that
the statements within a procedure may use entities previously declared in
the same procedure, any enclosing procedure or the enclosing module.
Thus the statements of procedures A and B may access any entity
previously declared in A or B respectively or previously declared at the
start of the module M. The statements of C may access any entity
previously declared in C, A or the module M. In particular
the statements of A may use C, A and B but the statements of B may
not use C.
@BFrom the point of view of the general scope rule blocks and
procedures need not be distinguished. Obviously since a block
has no name and is not formally declared a different example to the above is
necessary in order to illustrate the rule@
@3
@U 25
@
          MODULE M1
          declaration of procedure A
          declaration of X
               .
               .
               BEGIN
               declaration of Y
                  .
                  .
               statement S1
                  .
                  .
               END
               PROC A
               declaration of Z
                    BEGIN
                     .
                     .
                    statement S2
                     .
                     .
                    END
               END
          *END
@0
@BIn this case statement S1 may use Y, A and X but not Z.
Statement S2 may use Z, A and X but not Y.
@BThere is one important difference between the treatment of
procedures and blocks that is relevant to understanding the
exception to the general scope rule stated below. This difference is
that on entry to a procedure, a 'frame' is created on the procedure stack
that contains all the variables declared in the procedure,
together with those declared in the blocks that it contains
(and the blocks that they contain and so on), whereas it follows
that on entry to a block there is no such action. In effect
it is as if the entities declared in a block were actually
declared in the enclosing procedure (or module) head, except
that access to them is restricted to the statements of the block.
This interpretation should be assumed in understanding the restriction
stated below regarding the scope of variable.
@BWhen nested procedures occur in a module, the only variables
available to the statements of a procedure are those
previously declared in either the module heading, the outermost
procedure of the nest and the procedure in question.
@BFurther restrictions apply to labels. Normally
only the labels declared within a block or
procedure may be used in the statements of the
procedure. A special mechanism exists, as described
in 9.6, that provides an escape from this restriction.
@S39.2.8 'Statements' as the Compiler sees them
@BFrom a language definition point of view the recursive approach
followed above seems best. For example, a procedure definition
is regarded as a statement, even though it contains an arbitrary
sequence of statements some of which may be further procedure
definitions. In the current implementation of MUSL, the
compiler takes a different view of statements.
The compiler has a
main loop, which proceeds along the lines@
@3
@U 13
@
          ------>------
         |             |
         |        READ A STATEMENT
         |             |
         |             |
         |        IDENTIFY IT
         |             |
         |             |
         |        CALL THE ASSOCIATED
         |        TRANSLATION PROCEDURE
         |             |
          ------<------
@0
@BObvious problems arise, on small computers such as the PDP11, if STATEMENTs ar
e very large.
Thus the compiler is organised to break certain potentially
long statements into a sequence of statements. For example, a procedure
statement is treated by the compiler as the group of statements@
@Q 4
@
@Mprocedure heading statement
@Nthe statements of the procedure
@Nan END statement.
@BClearly context information must be remembered across such a group
of statements, so that when, for example, the END statement
occurs the compiler knows of what it is the end.
Even so this feature of the compiler influences the
style of fault monitoring, described in Chapter 7, and it is
responsible for some of the restrictions mentioned,
in subsequent Sections, in connection
with specific statement descriptions concerning the used of
statement separators and newlines.
@S29.3. BASIC ELEMENTS OF THE LANGUAGE
@S39.3.1. Symbols
@BEach statement in MUSL is a sequence of symbols. These
symbols may be names, numbers or delimiters. To compensate for
the shortage of suitable characters some delimiters are represented
by reserved words. Alternatively an abbreviated form of each reserved
word may be used comprising the first two characters of the full name
preceded by the $ sign. The space character has no meaning at the
statement level, but it terminates a symbol therefore it should be
used to separate symbols where ambiguity would otherwise arise.
Newline and tab are equivalent to spaces, except where specific
restrictions are placed on the use of newlines in certain 'long
statements'. The list below gives the full form of each reserved
word delimiter.@
@U 7
@
          IF, FI, THEN, ELSE, DO, OD, WHILE, WITHIN,
          FOR, EXIT, SWITCH, ALTERNATIVE, FROM,
          INTEGER, LOGICAL, REAL, SELECT, PROC,
          PSPEC, LSPEC, LITERAL, DATAVEC, END,
          BEGIN, MODULE, ADDR, SPACE, VSTORE,
          LABEL, AND, OR, OF, IS, TYPE, IMPORT.
@BThe delimiters INTEGER, LOGICAL, REAL are special in that they
can be followed by an integer, giving their size in bits. Thus in effect INTEGER
16($IN16)
LOGICAL8($L08) and REAL64($RE64), for example, are also delimiters.
@S39.3.2. Statement Separators
@BA ';' is normally used to separate statements, it may be omitted
if the statement ends with a reserved word or the following statement
begins with a reserved word which cannot occur within a statement.
The delimiters that start statements and can also be used within
statements are@
@
@MINTEGER  REAL  LOGICAL  ADDR
@
@
Redundant ';'s between
statements will be ignored, therefore if in doubt, use ; consistently
as a terminator.
@S39.3.3. Comments
@BThe comment symbol is '::'. All following characters will be
ignored up to the next newline symbol. A comment is an alternative
way of terminating a statement and is equivalent to ';'.
@S39.3.4. Names
@BNames (henceforth referred to as <NAME>) are used to represent
variables, types, literals, procedures etc. They must begin with
a letter which is then followed by an arbitrary sequence of
letters and digits possibly connected by fullstops (period).
The latter are allowed as a readability aid and are ignored when
names are matched.
For example, A X X1 NAME IN.NAME1 and INNAME1 are
all examples of valid names, the last two referring to the
same item.
@S39.3.5. Integer Constants
@BThese (henceforth referred to as <CONST>) can be written in various
styles.  They are all taken to be of TYPE INTEGER (9.7.2).
@
@3
@U 6
@
                    <CONST> ::= <DEC.INTEGER>!
                                <HEX.CONST>!
                                <CHAR.CONST>!
                                <MULTI.CHAR.CONST>!
                                <NAME>
@0
@S39.3.5.1 Decimal Integer Constants
@BA decimal integer constant may be optionally preceded
by a sign.@
@3
@
@M<DEC.INTEGER> ::= [+!-!<NIL>]<DECIMALS>
@N<DECIMALS>    ::= <DECIMAL.DIGIT>[<DECIMALS>!<NIL>]
@0
@
@
For example, all the following are allowed@
@
@M34, -90, +34, 65535
@BAll the above constants would be appropriate in an INTEGER16
context.  They could also be used in an INTEGER32 context, in which
case they would be sign extended to 32 bits.
@S39.3.5.2 Hexadecimal Constants
@BHexadecimal constants are used when the
bit pattern representing a constant is more significant
than the value it represents when interpreted as a number.
@X%~
@BThey are represented by the '%' symbol followed by
@X%%
sequence of hexadecimal digits, and the notation allows
multiple occurrences of the same digit to be specified
by a repetition factor expressed as an unsigned decimal
integer enclosed in brackets.@
@3
@U 5
@
@X%~
     <HEX.CONST> ::= %<HEX.SEQUENCE>
@X%%
     <HEX.SEQUENCE> ::= <HEX.DIGITS>[<HEX.SEQUENCE>!<NIL>]
     <HEX.DIGITS> ::= <HEXDIGIT>[(DECIMALS)!<NIL>]
     <HEX.DIGIT> ::= <DECIMAL.DIGIT>!A!B!C!D!E!F
@0
@BHexadecimal constants are right-justified, for example, the
binary patterns@
@
@M1001100110010000 and 11111110
@
@
@X%~
might be expressed as %9(3)0 and %FE respectively.
@X%%
If a hexadecimal constant occurs in context
requiring more than the specified number of bits,
it is automatically extended by zeros at the 'left hand end'.
@S39.3.5.3 Character Constants
@BThese are used to represent the ISO-code of the
visible characters. The notation is@
@3
@
@M<CHAR.CONST> ::= '<CHARACTER>
@0
@
@
where CHARACTER represents, any printing character except $,
a space character, or the character pairs@
@Q 7
@
@M$L
@N$P
@N$N
@N$"
@N$$
@
@
representing newline, newpage, null, quotes(") or dollar ($).
@X%~
For example 'A, '1, '$$ are equivalent to %41, %31, %24.
@X%%
@S39.3.5.4 Multi-character Constants
@BThese are used when it is required to have
the ISO-codes for several characters concatenated
into one constant. The notation is@
@3
@U 3
@
     <MULTI.CHAR.CONST> ::= "<CHARACTERS>"
     <CHARACTERS> ::= <CHARACTER>[<CHARACTERS>!<NIL>]
@0
@BExamples are "NAME1", "$$RE" which are equivalent to the
@X%~
hexadecimal constants %4E414D4531 and %245245.
@X%%
Like hexadecimal constants they are right-justified
and zero extended on the left when used in a
context bigger than themselves.
@S39.3.5.5 Name Constant
@BAny name can be defined as a literal and given a
constant value (9.5.4). Its use elsewhere is equivalent
to using the value explicitly.
In fact names can also be assigned to the Character Strings and
Real Constants described below.
@S39.3.6 Character Strings
@BWhen general character strings are to be
passed as parameters, they should be stored in
a vector of bytes and a 'reference' or pointer to
the vector should be used as the parameter. Procedures
that have parameters of this kind will have them
declared as ADDR[LOGICAL8] (see Section 9.5.2).
Since this situation occurs frequently in
programs that require to print messages, a
special notation is provided that allows the
actual character string to be written at the
point where a reference to it is required. This
notation is@
@3
@
@X%~
@M<CHAR.STRING> ::= %"<CHARACTERS>"
@X%%
@0
@
@
An example of its use would be@
@
@X%~
@MCAPTION (%"THIS IS AN ERROR MESSAGE");
@X%%
@S39.3.7 Real Constant
@BReal constants are used to represent floating point
numbers. The number of bytes occupied by the floating point
number is determined by its TYPE. Floating point numbers are
internally represented as a 32 or 64 bit entities.
@BWhen real constants are input, the digits up to the
decimal point are evaluated as an integer constant and then
converted to real. The precision of the conversion is the
precision allowed for the (default) integer constant (32 bit
integer). The remainder of the constant is evaluated as
real. If greater precision is required, the exponent form
(+1.23456789@@8) must be used.@
@3
@
@M<REAL.CONST> ::= [<NIL>!+!-][<DECIMALS>!<NIL>].
@N          [<DECIMALS>!<NIL>][@@<DEC.INTEGER>!<NIL>]
@0
@
@
For example@
@
@M+23, 17.3 -90.23 -3.@@9 4.3@@-4 -.6666 +.5@@+3
@S29.4. DIRECTIVE STATEMENTS
@BAll DIRECTIVEs start with "*" which is usually followed by the name of the
directive, some parameters if appropriate, and they are
terminated by ;.
They are used mainly to control the mapping of a module
or program and its variables into areas, to control the form of
compile time output and to manipulate the environment of the compilation
by making calls on MUTL procedures or other library procedures.@
@3
@U 12
@
               <DIRECTIVE.STATEMENT> ::= *CODE<CONST>!
                                         *GLOBAL<CONST>!
                                         *CMAP<CONST>!
                                         *STOPC!
                                         *INFORM<CONST>!
                                         *INIT<CONST>
                                         *TLSEG<CONST><CONST><CONST>!
                                         *TLLOAD<CONST><CONST>!
                                         *TLMODE<CONST><CONST>!
                                         *VTYPE<TYPE>!
                                         **<ANY MUSS COMMAND>
@0
@S39.4.1. Areas
@BAreas are the major
logical subdivisions of the store in which a module is to be placed. A
module can reference up to 32 areas, which at compile time are known
only by number (0-31). They are assigned to actual store
locations by use of the MUTL procedures TL.SEG and TL.LOAD.
Area 0 is special in that it is the procedure stack,
whose placement in store is directly under the control
of MUTL.
Code is always compiled into the area
last specified in the directive@
@
@M*CODE <CONST>
@
@
If the same area is specified more than once, the successive
sequences of code will occur consecutively in the given area.@
@BA precisely similar effect can be achieved with the mapping of
global variables (i.e. those declared at the outer
level of a module)
into segments by use of the directive@
@
@N*GLOBAL <CONST>
@
@
Area 0 may be specified, in which case, global variables
subsequently declared will be on the stack immediately before
the first stack frame.
Variables declared inside procedures are dynamically allocated on the
stack.
@S39.4.2. Compiler Output
@BAnother pair of directives are concerned with the output
that is produced during compilation, are@
@
@M*CMAP <CONST>
@N*STOPC
@
@
The first of the pair causes compile time output to appear on the stream
specified by the given constant, and the last stops this output.
The CMAP is a compile map giving line
numbers and positions in store as various landmarks are passed.
It is described more fully in 9.8.
@BTo assist with understanding the action of the compiler,
for example, if modifications are required,
there is a further directive@
@
@N*INFORM <CONST>
@
@
This will cause printing of various compiler
lists and information depending on the value of the bit significant
parameter (CONST) as follows.@
@Q 12
@T% 10 17
@
%@OBit@O%@OFunction@O@
@
%0%Print the encoded itemised statement in hexadecimal,@
%%every statement read@
%1%Print the text character by character@
%%as they are read@
%4%Print the analysis record of <COMPUTATIONS>.@
%5%Inhibit compile map@
%Bits 8 - 15 control MUTL output@
%(i.e. they are passed as bits 0 - 7 of the parameter@
%to TL.PRINT)@
@S39.4.3 Initialisation
@BIf the MUSL compiler is not running in a full MUSS
environment, in which the MUTL system can
be initialised and stored by direct calls on MUTL
procedures from the command stream of a compile
run, facilities for this purpose are necessary in the
compiler. In particular it is necessary
to call TL and TL.END at the
start and finish of the compile run, possibly
make several calls on TL.SEG to establish
the segments for the compilation in which
case it will also be necessary to make calls on
TL.LOAD and possibly to call TL.MODE
for the compilation of individual modules.
Thus the following directives are provided@
@Q 5
@
@M*INIT<CONST>
@N*TLSEG<CONST><CONST><CONST>
@N*TLLOAD<CONST><CONST>
@N*TLMODE<CONST><CONST>
@BThe parameter of *INIT is a bit significant CONST
whose bits have the following meaning.@
@Q 7
@T% 10 22
@
%bit 0 = 0%the compilation is for a 32-bit machine@
%bit 0 = 1%the compilation is for a 16-bit machine@
%bit 1 = 1%the module following it the first of a@
%%compile run@
%bit 2 = 1%the module following is the last of a@
%%compile run.@
@
@
If bit 1 = 1 a call will be made on TL and bits
8-15 of CONST will be used as the parameter of TL.
If bit 2 = 1 there is no immediate action but the next
*END encountered will finally result in a call on
TL.END.
@B*TLSEG *TLLOAD and *TLMODE should be followed by
the appropriate parameters separated by spaces.
@S39.4.4. Binary Patching
@BThere is also a *@2#@0<CONST> directive which allows
binary machine instructions to be introduced into critical
machine dependent sequences.
This is used in MUSS, for example, to implement
register dumping and reloading when a process
change takes place.
@S39.4.5. MUSS Library Calls
@BIf the MUSL compiler is running in a MUSS
environment, a call of any MUSS library procedure
can be forced from the compiler by using in the
MUSL source a MUSS command preceded by **.
This facility is most often used to manipulate the
input/output streams. For example, two separate files
can be made to appear as one, to the compiler by
using the 'IN' command in one file (i.e. '**IN name of file')
at the point where the other file is to be included.
@BAnother use of the facility is to make
direct calls on the MUTL procedures that control
the environment of the compilation.
@BThe command following the ** up to the next newline
is processed by MUSS not by the compiler and it should
not therefore be terminated by ';' or a comment.
@S39.4.6 Vstore Type
@BThe VSTORE declarations of Section 9.5.10 introduce
the idea of a default VSTORE type. This is normally the
same as the default integer type but it may be reset by the
directive@
@
@M*VTYPE INTEGER32;
@
@
for example.
@S29.5 DECLARATIVE STATEMENTS
@BEvery name used in a MUSL statement must be declared
before it is used except for the reserved names of the
language and label names. The declarations of the
language are@
@3
@U 12
@
@
     <DECLARATIVE.STATEMENT> ::= <LABEL.DEC>!
                                 <VAR.DEC>!
                                 <PROC.DEC>!
                                 <LIT.DEC>!
                                 <DATA.VEC>!
                                 <TYPE.DEC>!
                                 <FIELD.DEC>!
                                 <SPACE.DEC>!
                                 <V.STORE.DEC>!
                                 <IMPORT.DEC>
@0
@BIn effect a declaration specifies one or more names, defines
the kind of entities to which they relate, and where relevant
gives their properties. Thus a name declared in a LABEL.DEC
is regarded as a label name and a name declared
in a PROC.DEC is regarded as a procedure name. The
former will have no additional properties but the latter might
have properties concerned with the kind and type of its
parameters and result.
@S39.5.1 Label Declarations
@
@3
@
@M<LABEL.DEC> ::= <NAME>:
@0
@
@
A label declaration provides a way of referencing the statement
which follows it in a '->'(goto) statement.
Normally labels are automatically generated by Flocoder and
the user will not be directly concerned with them.
In effect the label name is a
literal whose value is the address of the statement that follows it.
Unlike all other declarations the scope of the name declared is the
@5whole@0 of the procedure or block in which it is declared.
That is, forward references within a procedure or block are permitted, whereas i
n all other
declarations, they are
only effective forwards from the place where they appear.
Labels may not be referenced in a '->' statement of an enclosed
procedure, since a goto of this kind implies unwinding the procedure
stack. However this restriction does not apply to label variables and
parameters of type LABEL.
@S39.5.2 Variable Declarations
@
@3
@
@M<VAR.DEC> ::= <TYPE><NAME.LIST>
@0
@BA variable declaration specifies an arbitrary list of names of
variables of a given type. They may be scalar or vector variables
depending on whether or not the dimension is given in@
@3
@
@M<TYPE> ::= <SCALARTYPE>[<[><CONST><]>!<NIL>]
@0
@
@
Scalar types may be numeric types, type LABEL, the names of user defined types (
see later),
pointers to scalar or vector instances of either of these, or
pointers to procedures. In this latter case the name must be
one for which at least a PSPEC and possibly a procedure
definition has been previously given.@
@3
@U 7
@
          <SCALARTYPE> ::= <NUMERICTYPE>/LABEL!<NAME>!
                           ADDR[<NUMERICTYPE>!<NAME>]!
                           ADDR<[>[<NUMERICTYPE>!<NAME>]<]>
                           ADDR<[>ADDR<]>!ADDR ADDR!ADDR
          <NUMERICTYPE>::= [INTEGER!REAL!LOGICAL]<SIZE>
          <SIZE>       ::= 1!8!16!24!32!64!128!<NIL>
@0
@
@Q 13
@
For example@
@T% 30
@
INTEGER32@Idenotes a 32-bit signed integer@
LOGICAL8@Idenotes an 8-bit unsigned integer@
INTEGER32[10]@Idenotes a vector of 10 32-bit integers@
ADDR INTEGER32[10]@Idenotes a vector of 10 addresses of 32-bit
integers@
ADDR [INTEGER32]@Idenotes the address of any vector of
32-bit integers@
ADDR P1@Ican be used to indicate the address
of a particular type of procedure where
P1 is a name defined in a PSPEC
@BThe main numeric types are integer and real, but each may exist
in a range of sizes. For type INTEGER the size may be 8, 16, 24 or 32,
short operands will be sign extended up to the size of the COMPUTATION
in which they appear.
If the size indication is omitted the natural size
(16/32 bits) of the target machine will be chosen.
Type REAL may only be 32, 64 or 128.
@BThe third numeric type (LOGICAL) is similar to
INTEGER, but the sign propagation of short operands
is suppressed and sizes 1 and 64 are also permitted.
It should be noted that LOGICAL is merely a name for unsigned
integers. Entities of this type can be used in any INTEGER context.
There is no separate LOGICAL mode of arithmetic
but the logical operators representing 'and', 'or' and
'non-equivalence' can be used in INTEGER computations.
@BVariables of type LABEL may have labels (or other label
variables) assigned to them. They may then be used as the
operand of a 'goto' statement.
@BIn the declaration of vectors the CONST should have
an integer value >0. It specifies the number of elements in the
vector and subsequent accesses should regard them as being
numbered 0 to CONST-1.
@BWhen a type is preceded by ADDR, it denotes a pointer to an
object of that type. ADDR may also be used as a numeric
type to indicate an integer whose size is the address length
of the target machine. Similarly a pointer to such an integer or vector
of integer is denoted by ADDR ADDR, ADDR[ADDR].
This size may be specified in the mode parameter
when the compiler is called (see 2.5.2).
@BVariables which are declared inside a procedure are local to that
procedure and are allocated space on its run time stack frame.
The variables of a procedure declared at the outer level of a
module can be accessed non-locally from any nested procedure.
Variables declared at the outer level of a module are @5global@0 to all the
procedures of the module.
More general non-local access is not permitted.
The positions occupied by global variables depend upon the
use of the *GLOBAL directive (9.4).
@S39.5.3 Procedure Declarations
@
@3
@
@M<PROC.DEC> ::= [PSPEC!LSPEC]<NAME>[<PSPEC>!=<NAME>]
@N<PSPEC> ::= ([<T.LIST>!<NIL>])[/<SCALARTYPE>!<NIL>]
@0
@BA declaration should normally be given for every procedure, before it is
used or defined. This declaration defines the NAME to be a procedure name
indicates whether the procedure is to be given (PSPEC) or found in a library (LS
PEC), gives
the type of each parameter, and the type of the result (after the /), if it is a
function procedure.
Only scalar types are permitted
as parameters, and results are further
restricted to non user defined types and addresses of user defined types.@
@3
@
@N<T.LIST>  ::= <SCALARTYPE>[,<T.LIST>!<NIL>]
@0
@
@
Thus vectors cannot be passed as parameters
but their addresses can. Also addresses of user
defined types can be passed thereby enabling procedures
to place results in the associated variables.
@BIf a group of procedures have identical specifications
a full specification must be given for the first
then the '='s option can be used in all further PSPECs.
@BSometimes it might be appropriate to give a specification
for a name of a class of procedures (e.g. TRIGFN) which
is not itself a procedure,
and to use it to declare the procedures of that
class, for example@
@
@MPSPEC SIN = TRIGFN
@
@
It may also be used to declare pointers to procedures of that particular
class, for example@
@
@MADDR TRIGFN
@BIf a user prefers to forfeit some degree of checking,
the LSPECs may be omitted and the compiler will automatically
generate LSPECs for any undefined procedure name which corresponds
to a library procedure name in a currently open library. This
option is controlled by a mode bit (section 2.5.2).
@S39.5.4 Literal Declarations
@BThese declarations allow names to be assigned to various kinds of
constant, e.g. INTEGER constants, REAL constants, AGGREGATE constants
and POINTER constants.  The syntax for each kind of constant is
different, thus@
@3
@U 6
@
@
          <LIT.DEC> ::= LITERAL[<INTEGER.LITS>!
                                <REAL.LITS>!
                                <AGGREGATE.LITS>!
                                <POINTER.LIT>]
@0
@BAn INTEGER literal may be of any INTEGER type and several may be
defined in the same statement.  It is the only kind of literal where
compile time evaluation of an expression is allowed@
@3
@U 7
@
@
     <INTEGER.LITS> ::= [/<INTEGER.TYPE>!<NIL>]<INTEGER.LIST>
     <INTEGER.TYPE> ::= INTEGER, INTEGER8, INTEGER16, INTEGER32
     <INTEGER.LIST> ::= <NAME> = <VALUE>[,<INTEGER.LIST>!<NIL>]
     <VALUE>        ::= <CONST>[<CONST.OP><VALUE>!<NIL>]
     <CONST.OP>     ::= +, -, &, !, *, /
@0
@
@
Some examples of the declaration of INTEGER literals are@
@3
@U 4
@
@
     LITERAL          L1=10, L2=20, L3=L1-1;
     LITERAL/INTEGER8 A="A", Z="Z", ONE="1";
@0
@
@
When the TYPE is not explicitly given the default integer type
will be assumed.
@BIn practice INTEGER LITERAL declarations are sometimes very long with
many names declared in the same statement.  Thus the compiler has
been organised to take them a line at a time.  As a consequence of this
each intermediate line must end with ','.  For example@
@3
@U 4
@
@
                    LITERAL   A = 1,
                    B = 2;
@0
@
@
is acceptable but@
@3
@U 4
@
@
                    LITERAL   A = 1, B
                      = 2;
@0
@
@
is not acceptable.
@BREAL literals are names assigned to floating point values.  Thus@
@3
@U 5
@
@
     <REAL.LITS> ::= /<REAL.TYPE><REAL.LIST>
     <REAL.TYPE> ::= REAL, REAL32, REAL64
     <REAL.LIST> ::= <NAME>=<REAL.CONST>[,<REAL.LIST>!<NIL>]
@0
@
@
For example@
@3
@U 3
@
@
     LITERAL/REAL      TEN = 10., ONE.TENTH = 0.1;
@0
@BAGGREGATE literals are names assigned to particular instances
of user defined types which are composed of a sequence of basic
types.  The notation for expressing such a value is to give
each of the individual basic components separated by '\'.  Thus@
@3
@U 5
@
@
     <AGGREGATE.LITS> ::= /<TYPE.NAME><AGG.LIST>
     <AGG.LIST>       ::= <NAME>=<AGG.VALUE>[,<AGG.LIST>!<NIL>]
     <AGG.VALUE>      ::= <CONST>!<REAL.CONST>[\<AGG.VALUE>!<NIL>]
@0
@
@
For example, if UT1 is a user defined type comprising two integers and a
real, then a name 'X' might be assigned to a particular instance of UT1 thus@
@3
@U 3
@
@
     LITERAL/UT1      X = 1\ 2\ .135;
@0
@BThe final kind of literal definition allows 'nil' pointers to be
created for any pointer type.  The syntax is@
@3
@U 3
@
@
     <POINTER.LIT> ::= /ADDR[<ANYTYPE>]<NAME>=;
@0
@
@
For example@
@3
@U 3
@
@
     LITERAL/ADDR[LOGICAL8]  NIL.STR=;
@0
@
@
defines NIL.STR to have the value of a pointer to an empty vector of
bytes.
@0@S39.5.5 Data Vectors
@BA Data Vector is a one dimensional array of literals having
a name which can be used like any other vector name in order to
access the elements of the vector as operands. However, if
the data vector is stored
in a read only
segment it cannot be altered
by the program.
If it appears at the outer level of a MODULE
it will be placed with the global variables of the
module and if it is contained within a procedure
it will be stored with the code. Thus the placement
of data vectors can be determined by the programmer by
preceding them with *GLOBAL directives in the first
case and *CODE directives in the second case.@
@3
@U 4
@
               <DATAVEC>  ::=  DATAVEC<NAME>(<SCALARTYPE>)
                               <LITERALS>
                               END
@0
@BAny number of LITERALs are allowed but they must all
be of the same given TYPE.
The only permitted pointer type of data vector
element is the address of a procedure or data vector (ADDR<NAME>).@
@3
@U 3
@
     <LITERALS>  ::= <LITERAL>[<[><CONST><]>!<NIL>]
                      [<LITERALS>!<NIL>]
@0
@BObviously the individual literals must be separated and it is
usual to use space or newline for this purpose.
If a LITERAL is followed by a bracketed <CONST> it will
be repeated the CONST number of times.
Only CONSTs with integer values >0 should be
used in this context.
For example:@
@Q 5
@
@MDATAVEC NAME($LO8)
@N'J 'A 'C 'K
@NEND;@
@
is a VEC called NAME of 4 bytes, and@
@Q 9
@
%LITERAL COUNT = 4@
%DATAVEC CONSTS($IN)@
%1  2  3@
%10[5]@
%20[COUNT]@
%6@
%END;@
@
@
is a VEC of 13 integers.
@BBecause of the high incidence of character
data vectors in some parts of MUSS, for example,
as error messages, a special construct is provided
to abbreviate lists of character literals. It
is "<CHSTRING>". Thus the first example above
could be written@
@Q 4
@
%DATAVEC NAME($LO8)@
%"JACK"@
%END;@
@S39.5.6 Type Declarations
@3
@U 6
@
     <TYPE.DEC>  ::= TYPE<NAME> [IS <STRUCTURE>!<NIL>]!
                     TYPE<NAME> = <CONST>!
                     WITHIN<NAME> IS <STRUCTURE>
     <STRUCTURE> ::= <FIELDS>[OR<STRUCTURE>!<NIL>]
     <FIELDS>    ::= <TYPE><N.LIST>[<FIELDS>!<NIL>]
@0
@BType declarations allow the user to declare a NAME as a type name
and to associate it with
a STRUCTURE comprising several fields of simpler types.
The fields are
given names so that they may be subsequently accessed as operands.
Consecutive fields of the same type are
declared by giving a list of names after the TYPE. If fields are of different ty
pes
a TYPE word should appear before each field name.
A TYPE.DEC which has an alternative is called a UNION.
In all declared instances of a UNION,
the compiler will allow space for the largest alternative form, but the onus
is on the user to know which alternative is present at
any point in time.
@BIt is sometimes necessary to use a TYPE name before giving
its declaration. This may occur, for example, in importing
procedures which use exported types. Thus the NIL alternative
of a type declaration allows a name to be introduced as a type name.
Its full definition must be given later in the usual way.
@BThe last two alternatives of a type definition allow a type
to be defined incrementally with several modules adding some fields.
First of all a type name, and size in bytes, must be given
using the construct@
@
@MTYPE PRB.TYPE = 1000;
@
@
which states that the type PRB.TYPE will have a size not greater
than 1000 bytes.  The WITHIN statement which has the same
syntax as a normal type definition, may then be used in any
module into which the type is imported to add some fields.  Only
those fields declared in a module will be accessible in that module.
@S39.5.7 Examples of Variable/Type Declarations
@BThe simplest example of a declaration is
where no dimension is given, e.g.@
@
@MINTEGER I,J;
@
@
In this case I and J will be local variables of type
INTEGER. If a vector of elements
of type INTEGER is required a dimension must be given
thus:@
@
@NINTEGER[25]VECI;
@
@
In this case the 25 INTEGER elements of VECI will be numbered
0,1,...24.
@BNew types are created by use of the TYPE declaration, e.g:@
@U 3
@
          TYPE IPAIR IS $IN PROP1, PROP2;
          TYPE CONDITIONS IS REAL TEMP, PRESS, VOL;
@BThese TYPE names can be used to declare scalar or vector instances
of the TYPEs in question, e.g:@
@U 6
@
          IPAIR I1,I2,I3;
@
declares three integer pairs and
@
          CONDITIONS [20]U,V;
@
declares two vectors each having 20 elements containing a
TEMP PRESS and VOL component.
@BA TYPE may have several different fields, e.g:@
@U 2
@
          TYPE IOAREA IS $IN SPN, PID $LO8[100]MBUFF
@
@
declares a TYPE IOAREA with three fields which are the two integers SPN, PID and
a vector (MBUFF) of 100 bytes. This might be used to declare an IOCONT vector
containing 16 IOAREA's thus:-@
@U 2
@
          IOAREA[16] IOCONT;
@BIt should be noted that every field has a name
which must be unique within the type
the purpose of which
is to provide a means of accessing it as described in 9.5.
@S39.5.8 Field Declarations
@BThese are duplicate declarations for the fields
of structures which allow them to be 'selected' and subsequently accessed by the
ir
field name only. The syntax of the statement is given
below, but its meaning and use is discussed in 9.6.
@3
@U 3
@
@
          <FIELD.DEC>  ::=  SELECT<CONTEXT>
@0
@
@
where CONTEXT is defined in 9.6.
@S39.5.9 Space Declaration
@BIt is convenient to be able to reserve some unmapped store to be
dynamically mapped by means of the MAKE function. The SPACE.DEC provides
for this.@
@3
@
@
@M<SPACE.DEC> ::= SPACE<NAME>[<[><CONST><]>!<NIL>]
@0
@BIf these declarations appear inside a procedure the space will be
reserved on the run time stack otherwise it will be reserved in the
current global area (i.e. that last
selected by a *GLOBAL directive).
@BThe NAME may subsequently be used as the parameter of a call for the
built-in function MAKE.
The CONST specifies the required amount of
space in bytes and must be an integer >0.
Thus a space of 1 Kbytes called HEAP1 would be declared@
@
@
@MSPACE HEAP1[1024]
@BThe use of the MAKE function and the provision made for
'garbage collection' in such spaces is discussed
in 9.6.5
@BIn some situations in MUSS areas of store arise dynamically.
For example, when a file is opened, or a message is received. These
can be treated as 'SPACE's if a space name declared without
parameters is subsequently associated with an area by means of the
built in function POSN also described in 9.6.5.
@S39.5.10 V-store Declarations
@BThe MUSS 'ideal machine' is defined
as a set of 'ideal V-lines' concerned with the
control of peripherals, store management hardware
and CPU status. V.STORE.DEC is concerned with their
mapping into an actual machine. There are
two forms of V.STORE.DEC as follows@
@X%#
@3
@U 8
@
@
               <V.STORE.DEC> ::= VSTORE <VDEFS>
                     <VDEFS> ::= <VDEF>[,<VDEFS>!<NIL>]
                     <VDEF>  ::= <NAME>[<[><CONST><]>!<NIL>]
                                 [%<HEXCONST>!<NAME>]
                                 [<<><NAME>!<NIL>]
                                 [<>><NAME>!<NIL>]
@0
@X%%
@BOne option in V.STORE.DEC provides a means
for associating an absolute address with an ideal V-line.
It uses the CONST option where the CONST must
have an integer value giving the address of the
V-line in bytes and its type will be taken to be
the default VTYPE (Section 9.4.7).
For example@
@
@X%~
@MVSTORE LPTSTATUS %3FF4C;
@X%%
@
@
associates LPTSTATUS with the byte address
@X%~
%3FF4C. In cases where the machine VSTORE does not
@X%%
correspond to the ideal machine VSTORE, it is necessary
to map the ideal VSTORE onto a variable and to emulate
the special actions of the ideal VSTORE by using
PREPROCs and POSTPROCs. Thus another form of VDEC is@
@
@MVSTORE V1 PSEUDOV1 <PROC1 >PROC2
@
@
Here the VSTORE variable V1 is mapped onto the variable PSEUDOV1 (and takes its
type), and
the names which (optionally) follow
are the names of procedures. If the first procedure name is present (e.g. PROC1
above) it will
be called before a read access on V1 and the second (PROC2) will be
called after a write access to V1.
The TYPE of VSTORE variables may be machine dependent
but it will usually be type INTEGER, although if a
VSTORE variable is mapped into another variable it takes
the TYPE of that variable.
@BSome VSTORE entities, for example, page address
registers occur naturally as vectors. In these
cases a dimension should be given as for
vectors of ordinary variables.
@BA procedure used as a PREPROC or POSTPROC
is a restricted form of procedure.
It may not have local
variables, parameters or a result. However, the code it contains may use the
automatically declared name VSUB, providing it has not been redeclared, to obtai
n the subscript in the
case where it relates to a vector of V-lines.
In effect the VSTORE declaration serves as the 'PSPEC' of the
'PROC's hence it should precede the PROCs and be at the
same block level.
In particular MUTL implementations, the restrictions
may be more severe (e.g. language constructs that
cause the compiler to generate local variables must
be avoided).
@S39.5.11 Import Declarations
@3
@U 4
@
@
          <IMPORTS> ::= <IMPORT><IMPORTS>!<NIL>
           <IMPORT> ::= <PROC.DEC>!<VAR.DEC>!<IMPORT.DEC>!<TYPE.DEC>
@0
@BIn general a module may import any entity which is
exported from another module. When the imported entity is a
procedure or variable a full duplicate specification must be given before
the module heading.
@BA module sometimes uses imported entities without
requiring a full specification to precede the module
heading. This applies to TYPEs, VSTORE, LABELS and LITERALs.
Thus the following special IMPORT statement is
provided@
@3
@U 5
@
          <IMPORT.DEC> ::= IMPORT<KIND><IMP.LIST>
          <KIND>       ::= [LITERAL!VSTORE][<NUMERICTYPE>!<NIL>]!
                           TYPE!LABEL
          <IMP.LIST>   ::= <NAME>[<[><]>!<NIL>][,<IMP.LIST>!<NIL>]
@0
@BA type may be specified for an imported LITERAL or VSTORE and
the NAME[] construct is used to indicate when a vector
instance of VSTORE is to be imported.
@BIf a type name is imported in the above manner only the type
name and not its fields are accessible in the module into which it
is imported. A full duplicate type definition must be given before
the module heading if use is to be made of the field
names of the type. Similarly if procedures or variables are
imported, full duplicate definitions are necessary. Clearly any
entity that is imported into a module must be exported from another
module, and modules related in this way must be
loaded in the same load run, or compiled in the same compile
run if a generate executable binary option is used.
@S29.6 OPERAND FORMS
@T% 10
@3
@U 15
@
     <OPERAND> ::= [^!<NIL>]<VARIABLE>[OF<CONTEXT>!<NIL>]!
                   <CONST>!
                   <NAME>[^!<NIL>]([<P.LIST>!<NIL>])!
                   (<COMPUTATION>)!
                   (<COND.COMP>)!
                   <BUILT.IN.FUNCTION>
    <VARIABLE> ::= <NAME><SUBSCRIPT>[^<SUBSCRIPT>!<NIL>]
     <CONTEXT> ::= <VARIABLE>[OF<CONTEXT>!<NIL>]
   <SUBSCRIPT> ::= <[><COMPUTATION><]>!<NIL>
      <P.LIST> ::= <COMPUTATION>[,<P.LIST>!<NIL>]
   <COND.COMP> ::= IF<CONDITION>THEN<COMPUTATION>
                   ELSE<COMPUTATION>
@0
@
<COMPUTATION> and <CONDITION> are defined in 9.6.
@BThe operand capability of MUSL is moderately complicated
and warrants some discussion. Inevitably the examples given
reflect the structure of the COMPUTATIONs described in the next
Section but their meaning should be self evident.
@S39.6.1 Variables
@BConsidering first the case where no CONTEXT is given,
VARIABLES which are scalars are represented by
names, which are declared as
described in 9.4. They may be
Local, Non-local or Global.
Those which are vector elements are represented
by the vector name followed by a subscript.
The subscript (or index) is
the result of a computation which gives the required element number. For example
,
A[0] denotes the first element of a vector A and A[9] denotes its
10th element. It follows that A[I-1] denotes the Ith element.
If a variable contains the address of the required variable it must
be followed by "^" to explicitly dereference it.
Any variable so dereferenced might have been a pointer
to a vector in which case a further subscript
is required.
For example if the NAME in the
definition of VARIABLE refers to the address of a vector,
for example, it has been declared@
@
@MADDR[INTEGER] name1;
@
@
and the address of a suitable vector has been
assigned to name1,
then an element in the vector is accessed thus:@
@
@Nname1^ [subscript]
@
@
Whereas if it were the NAME of a vector of addresses
of integers, declared as@
@
@NADDR INTEGER[10] name2;
@
@
any one of the integers addressed could be accessed thus:@
@
@Nname2 [subscript]^
@BIf a reference to a variable is to be created then its name is preceded
by an "^". Thus@
@
@N^name1^[4] => name2[3]
@
@
computes the address of the 4th element
of the vector of integers whose address is given by
name1 and assigns it to the 3rd element of the
vector of addresses name2.
@BWhen a variable is a field of an aggregate type
its CONTEXT must also be given. E.g.@
@
@NSPN OF IOCONT[I]
@BIf it is required to access an element of a vector which is
itself a field in an element of a vector,
for example an element of the MBUFF defined in
9.5, the notation is:-@
@
@NMBUFF[J] OF IOCONT[I]
@
@
meaning the Jth element of the MBUFF in the Ith (aggregate)
element of IOCONT.
@BIn general aggregate types can be nested to an arbitrary depth,
hence, CONTEXT is defined recursively. It should be noted that
the last name given in the specification of a variable refers
to an instance of a
declared object, whereas the preceding names are field names.
Any of these names might be subscripted
and/or dereferenced.
@BThe repetition of the full specification,
when a series of operations are performed on a variable
embedded in a STRUCTURE, is tedious.
The FIELD.DEC described in 9.6.3 allows them to be accessed through
their field names only.
@S39.6.2 Constants
@BThese were described in 9.3. Any of the usual forms are
permitted but they must be type compatible with the context in which
they appear (see 9.7.2).
@S39.6.3 Field Declarations
@BThe syntax was given in 9.4. Its use is illustrated in
the example below.@
@
@NSELECT IOCONT[I]
@
@
serves two functions. It causes the address of the
element of IOCONT specified by I to be noted
and it implicitly declares all the fields of
IOCONT to be accessible by their field name only.
@BGiven this, and assuming SPN, PID
and MBUFF are fields of IOCONT, a statement such as@
@U 5
@
          IF SPN OF IOCONT[I] = 0 THEN
          FOR J<100 DO 0 => MBUFF[J] OF IOCONT[I]OD
          FI
@
@
could be rewritten@
@Q 2
@
@MIF SPN = 0 THEN FOR J<100 DO 0 => MBUFF [J]OD
@0
@BThe addresses of the selected fields are computed at the time the
declaration is processed. Hence, subsequent changes in the values
of variables which appear as subscripts of the selected fields will
be ineffective.
@S39.6.4 Procedure Calls
@BProcedures are called by giving their
name (or a dereferenced pointer to a procedure) followed by a P.LIST
enclosed in brackets.
The parameters must be COMPUTATIONs which yield values of the correct type, alth
ough the
usual automatic type conversions that apply in
COMPUTATIONs may be assumed. For example, an INTEGER can be
substituted for a REAL.
Type and type conversions are discussed in 9.7.2.
@BProcedures which return
results do so by assigning them to the name of the PROC
as described earlier.
@S39.6.5 Built-In Functions
@BSeveral built-in functions have already been mentioned but the
significance of "built-in" has not been explained. Their textual
representation is that of a procedure. They are built into the
compiler because their implementation uses facilities not available
at the user level. These fall into three main groups.@
@Q 5
@
@Mdirect manipulation of addresses
@Nvariable TYPE parameters
@Ninterpretive entry to libraries.
@
@
A complete list of the built-in functions is@
@U 10
@
     MAKE(ANY TYPE,$IN,[ANY SPACE!A BYTE ADDRESS!<NIL>]
                                      )ADDR OF GIVEN TYPE
     PART(ADDR OF A VEC,$IN,$IN)ADDR(OF A VEC OF LIKE TYPE)
     SIZE(ADDR OF A VEC)$IN
     POSN(ANY SPACE,A BYTE ADDRESS)
     BYTE(<COMPUTATION>)$IN(A BYTE ADDRESS)
     LLST()
     LPST(ANY BASIC TYPE, COMPUTATION)
     LENT(INTEGER COMPUTATION,ANY BASIC TYPE)GIVEN BASIC TYPE
@S39.6.5.1 Dynamic Allocation of Store
@BThe built-in function MAKE exists to allocate space at runtime for
an object in a space previously created by a SPACE declaration.
The function has three
parameters. The first is a type name, and the second is a number.
Space for the specified number of objects of the given type is reserved.
The third parameter of MAKE specifies the name of the SPACE that is to be used.
@BThe function yields a value of type ADDR of type of object created.
If the number of objects required is the constant 0
a pointer to a scalar is yielded, otherwise a pointer
to a vector instance of the objects is yielded.
@BThus:-@
@
@MMAKE(REAL,0,HEAP1)
@
@
generates space for a REAL value in the space specified as HEAP1 and yields
its address.
@BThis implies that associated with
HEAP1 is an index
that keeps track of the amount of space actually in use.
Obviously the need might arise to note and reset this index and this
is achieved by using the name of the space as an integer variable.
@BIn fact the third parameter of MAKE can be omitted
and in this case the run-time stack frame of the
procedure will be used, or it can be an explicit byte address.
@S39.6.5.2 Address Manipulation
@BClearly operands have addresses but normally the
programmer is only concerned with their names or with the names of ADDRESS
type variables. Addresses may be generated or dereferenced
by means of the "^" operator described earlier.
However, certain exceptional requirements arise in
system programming which make it necessary to manipulate addresses more directly
.
A simple example occurs when a character string has
to be read, stored and returned as a result. In this
case a global or parametric byte vector of adequate length could be used to
store the characters and the built-in-function:@
@
@MPART(<COMPUTATION>,<COMPUTATION>,<COMPUTATION>)
@
@
is available to generate the appropriate result
to return. The
first COMPUTATION should yield the address of a
vector and
the next two COMPUTATIONs give the first and last subscripts of
the partition whose address is required.
As the parameters may be evaluated in an implementation
dependent order they should have no side effects which
would affect the values of the other parameters.
@BAgain in the context of parametric vectors it might
be necessary to discover
the number of elements that it contains.
The function@
@
@MSIZE(<COMPUTATION>)
@
@
yields the size of the vector whose address is
yielded by the COMPUTATION.
@BAnother requirement arises as a result of the Operating System
allowing segments to pass from one virtual machine to another, either
as files or messages. This means that a program can acquire
information at a particular address unknown to the compiler.
In this case usable addresses for the objects can be obtained from
the built-in function
MAKE providing the area of store can be treated
as a SPACE. The built-in function@
@
@MPOSN(<SPACENAME>,<ADDRESS>)
@
@
associates the given SPACE name with the area
of store whose byte address is given as the second parameter.
The first parameter is the name of the SPACE and the second is its
address in byte units.
Alternatively, for similar reasons a byte address can be
used directly in MAKE. Byte address of variables can be
obtained by using the function@
@
@MBYTE(<COMPUTATION>)
@
@
The COMPUTATION must yield a result of pointer type.
@S39.6.5.3 Interpretive Library Calls
@BThese facilities are required by, for example,
a command language interpreter. A normal (compiled)
procedure call is broken down by a compiler into
several steps. These are notionally@
@U 11
@
               prepare to call a procedure
               stack the first parameter
               stack the second parameter
                       .
                       .
               stack the last parameter
               enter the procedure
               assign result
@
@
Further code might be interleaved with these
to compute the parameters. In order to facilitate
interpretive procedure calls these same steps
are made available individually as built-in functions.
They are@
@U 6
@
               LLST()
               LPST(TYPE,COMPUTATION)
               LENT(procedure index, TYPE)
@
@
The procedure index is the integer result
returned by the library procedure FINDN. The LENT procedure is
used to enter the procedure indicated by the FINDN index given
to it. The TYPE (or 0) is the type of the result of the given
procedure and if given then this call on LENT may be followed by
an assignment to a variable of that type. Two
other related library procedures are usually required
in order to make an interpretive procedure call. They
are PARAMS and PARAMTYPE.
@S29.7 IMPERATIVE STATEMENTS
@BThe Imperative Statements include both:@
@Q 3
@
@MComputational Statements
@Nand Control Statements
@BComputational Statements may be conditional, unconditional,
repeated WHILE some
CONDITION holds or FOR a given number of times (any of which may be zero times),
 thus:@
@Q 17
@T% 5 28
@
%<IMPERATIVE.STATEMENT>%::= <COMP.ST>!<CONTROL.ST>@
%<COMP.ST>%::= <COMPUTATION>!@
%%    <IF.ST>!@
%%    <WHILE.ST>!@
%%    <FOR.ST>@
%<CONTROL.ST>%::= <GO.ST>!@
%%    <SWITCH.ST>!@
%%    <ALT.ST>!@
%%    EXIT@
%<IF.ST>%::= IF<CONDITION><ACTION>@
%<WHILE.ST>%::= WHILE<CONDITION>@
%%    DO<STATEMENTS>OD@
%<FOR.ST>%::= FOR[<NAME><<>!<NIL>]<COMPUTATION>DO@
%%    <STATEMENTS>OD@
%<ACTION>%::= ,<GOST>!THEN<STATEMENTS><ELSECL>FI@
%<ELSECL>%::= ELSE<STATEMENTS>!<NIL>@
@
@
CONDITIONS also appear in conditional control statements and are
described in 9.7.3. In the WHILE
statements the CONDITION is repeatedly evaluated. Each
time it yields a true result, the
imperative statements between the following DO and OD
are obeyed. On the first occasion that the condition yields
false, control passes to the next statement after the OD.
The FOR statement provides for a similar set of imperative statements
to be executed a given number of times as specified
by the control COMPUTATION which is evaluated once at the start. As the repetiti
on proceeds a
counter is maintained which starts from zero. When it
reaches the specified value the repetition stops.
If this "control variable" is to be used during or after
the loop an INTEGER variable name must be given in the NAME.
On completion of a FOR loop the value of the
'control variable' will be the value of the control COMPUTATION.
@S39.7.1 Computations
@BA computation is expressed as a sequence
of operators and operands thus:@
@3
@U 3
@
     <COMPUTATION> ::= <OPR.OPD.SEQ>
     <OPR.OPD.SEQ> ::= <OPERAND>[<OPERATOR><OPR.OPD.SEQ>!<NIL>]
@0
@BEvery COMPUTATION is an expression and
the final result which occurs after complete evaluation
of the OPERATOR OPERAND sequence (from left to right)
is the VALUE of the expression.
This value is discarded if the
computation is a statement in its own right.
@BThe OPERATORs are the following@
@U 22
@T% 5 9 18
@
%+%meaning%add@
%-%meaning%subtract@
%*%meaning%multiply@
%/%meaning%divide (rounding towards 0 for integer result)@
%&%meaning%logical "AND"@
%!%meaning%logical "OR"@
%-=%meaning%logical "NON-EQUIVALENCE" (or exclusive OR)@
%-:%meaning%reverse subtract@
%/:%meaning%reverse divide@
%+>%meaning%ADD into store@
%->%meaning%SUBTRACT from store@
%*>%meaning%MULTIPLY into store@
%/>%meaning%DIVIDE into store@
%&>%meaning%AND into store@
%!>%meaning%OR into store@
%-=>%meaning%NONEQUIVALENCE into store@
%=>%meaning%assign to@
%-:>%meaning%reverse subtract from store@
%/:>%meaning%reverse divide into store@
%<<-%meaning%left logical shift@
%->>%meaning%right logical shift@
@
@
When an OPERATOR is
followed by ">" (excepting of course ->>,<<- and =>), first the OPERATOR is appl
ied (reversed if not
commutative) to the current result and the following OPERAND,
then this new result is assigned to the following OPERAND
and finally the new result is carried forward to the next stage
of the COMPUTATION. For example, 1->X will decrement X and
generate a result "X-1".
Note that some operators namely &, !, -=, &>, !>,
-=>, <<-, ->> are not available in floating point mode.
@BGeneral computations are not permitted on variables
of aggregate or pointer types. They may, however, be
moved and compared,
but in the case of aggregates not both in the same
statement. For example:@
@
@MAGG1 => AGG2 => AGG3
@N$IF AGG1 /= AGG2 /= AGG3 $TH
@
@
are acceptable.@
@
@N$IF AGG1 /= AGG2 => AGG3 $TH
@
@
is not acceptable.
@S39.7.2 Type
@BThe TYPE of arithmetic used in evaluating a
computation is determined by its operands.
In any COMPUTATION (or COMPARISON) the TYPE and size of
the operands must be compatible. Obviously if they
are all the same, they are compatible, but there
will be automatic type and size conversion in some other cases.
@BFor any computation the compiler determines a computation
type by looking ahead
up to and including the first
'assigned to' operand,
or the end of the computation if this occurs first.
The operand of the largest type determines the
computation type. The possible computation types are
INTEGER (size 16/32/64), REAL (size 32/64/128), user defined
types and the permissible address types
(any REAL type is considered larger than any
INTEGER type). However,
the operations available are in some case restricted
as shown in the table below (/ indicates allowed x indicates not allowed).@
@3
@U 23
@
     REAL(32/64/128) INTEGER(16/32) INTEGER(64) USER/ADDR TYPES
+           /              /              x             x
-           /              /              x             x
*           /              /              x             x
/           /              /              x             x
&           x              /              /             x
!           x              /              /             x
-=          x              /              /             x
-:          /              /              x             x
/:          /              /              x             x
+>          /              /              x             x
->          /              /              x             x
*>          /              /              x             x
/>          /              /              x             x
&>          x              /              /             x
!>          x              /              /             x
-=>         x              /              /             x
=>          /              /              /             /
-:>         /              /              x             x
/:>         /              /              x             x
<<-         x              /              /             x
->>         x              /              /             x
@0
@
@
Type conversions are permitted only as follows@
@3
@U 16
@
      OPERAND                 COMPUTATION TYPE
      TYPE         INTEGER  16  32  64    REAL  32  64  128
      LOGICAL1               /   /   /           /   /   /
      LOGICAL8               /   /   /           /   /   /
      LOGICAL16              /   /   /           /   /   /
      LOGICAL24              /   /   /           x   x   x
      LOGICAL32              /   /   /           /   /   /
      LOGICAL64              /   /   /           /   /   /
      INTEGER8               /   /   /           /   /   /
      INTEGER16              /   /   /           /   /   /
      INTEGER24              /*  /   /           /   /   /
      INTEGER32              /*  /   /           /   /   /
      REAL32                 /*  /*  /*          /   /   /
      REAL64                 /*  /*  /*          /   /   /
@0
@
@
The conversions marked '/*' are permitted but they may
generate arithmetic overflow.
@BIf an 'assigned to' operand is less than
the type of the computation, a type conversion
will be applied, after the computation
has been evaluated. This type converted result
is the value carried forward as the first operand when further operators and
operands follow.
If the expression contains further assignment this
process is repeated for each. For example, given@
@Q 12
@T% 10 26
@
@
%INTEGER32%I,J@
%LOGICAL64%LL@
%REAL32%R1@
%REAL64%RR2@
@
%I+J-1=>R1%will be evaluated in 32-bit real mode@
%I+J+R1=>RR2%will be evaluated in 64-bit real mode@
%R1*RR2=>J%will be evaluated in 64-bit real mode@
%%but converted to 32-bit integer mode@
%I<<-8!J<<-8=>LL%will be evaluated in 64-bit integer mode@
@BParenthesised computations
yield an operand of the 'final'
type used inside the parentheses. The result
is then converted, if necessary to the type of the
expression that contains it. Thus in@
@
@M(I+J-1) => R1
@
@
the arithmetic would occur in INTEGER32 mode
and the result would be converted to REAL32 before
being assigned to R1.
@BIn a TEST involving COMPARISONs each computation
is evaluated in a type not less than that of the 'largest' computation.
For example@
@
@MCH()<<-8!CH()<<-8!CH()<<-8!CH()<<-8!CH()<<-8 = NAME
@
@
will be evaluated in INTEGER64 mode even if CH
delivers a LOGICAL8 result providing NAME is
LOGICAL64.
For the above purpose the type of each computation is taken
to be its final type.
@BHowever, in those computations which begin in a type larger
than the comparison type, the evaluation will begin in this larger
type.  For example,
@
@
@MLL ->> 32 => I = J
@
@
is a comparison of type INTEGER32, but LL will be
loaded and shifted in 64-bit integer mode before being converted
to INTEGER32 type.
@BParameter expressions are evaluated in a type of arithmetic
consistent with the expression being followed by an assignment
to a variable of the type of the formal parameter.
@S39.7.3 Conditions
@3
@U 4
@
     <CONDITION> ::= <TEST>[<LOGOP><CONDITION>!<NIL>]
          <TEST> ::= <[><CONDITION><]>!<COMPARISON>
         <LOGOP> ::= OR!AND
@0
@BThe simplest form of CONDITION is a TEST in the form of a COMPARISON applied
to the results of two or more COMPUTATIONs.
The syntax for COMPARISON is:@
@3
@U 5
@
     <COMPARISON>   ::= <COMPUTATION><COMPARE.LIST>
     <COMPARE.LIST> ::= <COMPARATOR><COMPUTATION>
                        [<COMPARE.LIST>!<NIL>]
     <COMPARATOR>   ::= =!/=!<<>!<>>!=<<>!<>>=
@0
@
@
This allows several COMPARISONS to be made against
the same RESULT. They must all be satisfied for the
CONDITION to be satisfied.
@BExamples of simple conditions are:@
@U 6
@
          X = Y
          X-1 /= Y/Z
          INSYM() =<'Z >='A(meaning the same as below)
@
@
More complicated conditions would use AND and OR, e.g.@
@U 5
@
          INSYM() => SYM =< 'Z AND SYM >= 'A
          X=Y AND Z=10 OR P /= 4
@
@
The AND symbol has greater binding power than OR hence
the following parenthesis is implied:@
@
@M[X=Y AND Z=10] OR P /= 4
@BConditions are evaluated left to right and the
evaluation ceases when the status of the condition is known.
This is when a test that succeeds is followed by "OR" or one that
fails is followed by "AND".
@S39.7.4 Control Statements
@3
@
@M<GO.ST>       ::= -><NAME>
@0
@BAny basic statement in a program can be labelled
thus defining a label name.
A GOTO statement may reference these label names or
OPERANDS which are of type LABEL.
Usually, however, the labels and '->'s are generated by
Flocoder not the programmer.
Non-local '->'s are permitted only where the
name is a label variable or parameter of type LABEL
normally concerned with
error recovery.
@BThe switch statement also uses labels. Its syntax is@
@3
@
@X{{
@M<SWITCH.ST> ::= SWITCH <COMPUTATION>\<NLIST>;
@X{\
@0
@
@
Here the value of the computation decides which NAME is
selected in the N.LIST (value 0 selecting the first), and a GOTO that NAME is ob
eyed.
The NAMEs must be locally defined LABELs.
@BAn alternative statement specifies a COMPUTATION and a
list of STATEMENTS thus:@
@3
@U 4
@
     <ALT.ST> ::= ALTERNATIVE <COMPUTATION>FROM
                  <STATEMENTS>
                  END
@0
@S39.7.5 Implicit Blocks
@BBlocks were introduced in 9.2.6 and the scope
restrictions they impose in 9.2.7. Some groups
of STATEMENTS are treated as if they constitute
a block even though explicit BEGINs and ENDs
are not given. They are the STATEMENTS used in@
@Q 7
@T% 30
@
%    IF.ST@
%    WHILE.ST@
%    FOR.ST@
%and ALT.ST@
@
@
One important effect of this is that GOTOs
entering or leaving such statement groups are
not permitted.
@S39.7.6 Examples of a Procedure Definition
@BAs an illustration of a complete sequence of MUSL
statements, consider the following procedure for
reading as decimal integer.
@
@
Its specification is@
@3
@U 39
@
     PSPEC IN.I()/INTEGER;
     PROC IN.I;
     INTEGER SIGN, CH, ANS;
@
@
     WHILE IN.CH() => CH =< " " DO OD	::IGNORE SPACES
@
@
     IF CH = "-" THEN	::DEAL WITH OPTIONAL SIGN
        1 => SIGN;
        IN.CH() => CH;
     ELSE
        0 => SIGN;
        IF CH = "+" THEN
           IN.CH() => CH;
        FI
     FI
@
     IF CH - "0" => ANS >= 0 =< 9 THEN
        WHILE IN.CH() - "0" => CH >= 0 =< 9 DO
           ANS * 10 + CH => ANS;
        OD
@
@
        IN.BACKSPACE (1);
        IF SIGN = 0 THEN
           ANS => IN.I;
        ELSE
           0 - ANS => IN.I;
        FI
@
@
     ELSE
        ENTER.TRAP (6,8);
     FI
@
@
     END
@0
@S29.8 OPERATIONAL CHARACTERISTICS OF THE COMPILER
@F
