APM IMP compiler -- Version 1

Preamble

IMP Compiler for Motorola 68000 Hamish Dewar

Example commands:-
IMP MYPROG
IMP PARSER-LIST
IMP PROG2-NOCHECK-NODIAG

Unless -NOEDIT is specified, the compiler works in tandem with the editor. On detection of a fault, control is passed to the editor with the file pointer at the fault position. Corrective action may be taken, or not as wished, then %c (or keypad ',') to resume.

Calling the Compiler

The Compiler is invoked by the command IMP. There is only one obligatory parameter and that is the name of the IMP source program to be compiled. No default extension is applied to the source file-name.

Error reports are directed to the terminal (as well as the listing file). Line-numbering continues through any included files.

Unless otherwise directed, the Compiler generates an object file with the same name as the source file and extension MOB (for Motorola object). The object file is eligible for execution by citing the name as a command verb.

For example, the system command IMP MYFIRST calls for the source file "MYFIRST" (no extension) to be compiled as an IMP program, creating the file "MYFIRST.MOB". On successful completion of the compilation, the command "MYFIRST ...." becomes available as a command, and causes the object program to be loaded and entered.

Options

There are a number of options affecting the way in which the Compiler processes the source program. Modifications to the default selections may be requested by including appropriate keywords in the parameter string. These are introduced by a dash (minus).

The main options are given below. Those not yet implemented are marked with an asterisk, and those only partially implemented with a query. In the case of the yes/no options, the option is suppressed by selecting the keyword prefixed with "NO".

Source listing control:

   -LFILE=<filename>   send listing to specified file
                       (extension LIS added)
   -LFILE=LP:          send listing to network printer
   -LIST               produce source file listing
                       -- if no LFILE specified, then to
                       a file with same name as source
                       and extension LIS added
   Default: -NOLIST

   -LOG                output statistics indicating number of statements,
                       atoms per statement, identifiers per statement,
                       time taken, etc.
   Default: -NOLOG

Object program control:

   -OFILE=<filename>   produce object file with specified name
                       (extension MOB added)
   -OFILE=:N           do not produce object file

 Default: produce object file with same name as source and extension MOB

   -FORCE              produce object file even if program faulty

 Default: -NOFORCE

Run-time checks:

  ?   -ASS       include unassigned check on full integers
  ?   -STRASS    include unassigned check on strings
  ?   -SASS      include unassigned check on shorts
  ?   -BASS      include unassigned check on bytes

      -ARR       include array bound checking
  *   -LOOP      include %for loop check
  *   -OVER      include overflow check
  *   -CAP       include capacity checking

Default: -ASS-STRASS-NOSASS-NOBASS-ARR-LOOP-OVER-CAP
-NOCHECK has the effect of suppressing all checks

Run-time diagnostics:

      -DIAG         include line-number updating for diagnostics
      -TRACE        generate code which allows the program to
                    be executed one line at a time under the
                    control of the Software Front Panel
  Default: -DIAG-NOTRACE

Language facilities

The language implemented is as defined in the Departmental Report "The IMP77 Language" (3rd Edition), with the exceptions noted below. Reals are limited to 32-bits and are implemented by software.

Features of IMP77 which are not valid in IMP80 (EMAS IMP) and conversely, or which are peculiar to this implementation, are reported as 'non-standard' (warning only). However, this warning is not produced for the following widely used IMP77 facilities, even though they are not available in IMP80:

%shortintegers, %predicates, %else %if,
the operator mod-sign,
initialisation of dynamic variables to literal values
(but initialisation to non-literal values is flagged).

Not yet implemented

Omissions in current release -- to be added:

. full diagnostics and %monitor

. procedures as parameters

. NEW and DISPOSE

. %string(*)%array%name variables

Variant features

. %continue is interpreted as a return to the start of a loop so
that it by-passes any %until test on the %repeat

. %array %name parameters must have bounds specified in the declaration
in one of the following ways:

all literal bounds eg %byteintegerarrayname A(0:31)
one or more indefinite bounds eg %integerarrayname B,C(1:*)

[Note that in the second example, all actual parameters for B,C
must have the same upper bound. Cf B(1:*),C(1:*)]

The Vax IMP form in which the keyword %array is followed by the
number of dimensions in parentheses is also accepted:

eg %integerarray(1)%name A == %integerarrayname A(*:*)
%shortarray(2)%name B == %shortarrayname B(*:*,*:*)

However, if this form is used, the number must be included even
for the one-dimensional case (cf Vax IMP which allows omission
in this case).

. the low-level pointer-relative facility (see Section 9) differs from
the version of this implemented in the current Vax compiler

Omissions and restrictions

. %name %function as variant for %map is not supported

. %on %event * as a way of trapping all events is not supported

. line-breaks following %and and %or are not ignored

. there is no built-in function TYPEOF

. untyped %name parameters are usable only to supply an address,
not type or length information; the built-in function SIZEOF
is not applicable to such parameters

. the Compiler is stricter about the ordering of statements
than the Vax IMP Compiler. The normal ordering in any block
should be declarations, then event trap if any, then instructions.
It is acceptable for static declarations, of procedures and %own
variables, to be interspersed among instructions, but the Compiler
queries any dynamic variable declarations which appear after
instructions, and hard-faults any which appear in a loop or after a
sequence change.

See also the restrictions noted in the section on externals

Obsolete features -- to be discontinued

. non-decimal constants expressed in IBM style (X'...')

. Atlas Autocode style of %for loop (without %for)

Error reports

Error reports are kept short to economise on screen space. For reports which relate to a particular component of a statement, the culprit is identified by a marker at the start of the component.

 REPORT                     MEANING

Faulty form      statement part indicated is syntactically faulty
Unknown atom     lexical atom indicated is mis-spelt or unknown
Non-starter      atom at the start of the statement is not a
                 possible statement introducer
Unknown name     identifier indicated has not been declared
Duplicate        identifier indicated has already been declared
Mismatch         parameters in body of procedure do not match spec
Not variable     operand in assignment context is not a variable
Not reference    operand in pointer context is not a reference
Wrong type       expression is of wrong type for context
Wrong class      category of identifier is wrong for context
Not literal      expression in literal context is not literal
Inside out       upper bound is less than lower
Endless loop     literal %for loop cannot terminate
Out of range     operand value is out of range
Too few args     too few arguments are given for procedure call
Too many args    too many arguments are given for procedure call
Not in loop      %exit %or %continue is not within a loop construct
Not in routine   %return is not within a routine
Not in fn/map    %result is not within a function or map
Not in pred      %true/%false is not within a predicate
%CYCLE missing   %repeat encountered with no matching %cycle
%REPEAT missing  %end reached with unmatched %cycle
%START missing   %finish or %else encountered with no matching %start
%FINISH missing  %end reached with unmatched %start
Extra %ELSE      %else encountered matching earlier unconditional %else
%BEGIN missing   %end encountered with no matching %begin or
                 procedure header
%END missing     %end %of %program or %file reached with unmatched
                 %begin or procedure header
%RESULT missing  there is apparently a path to the end of a function
                 or map which does not specify a result
Not accessible   instruction apparently cannot be executed (warning only)
Out of order     statement appears in incorrect order in block
                 (warning if benign)
Nonstandard      non-standard language feature (warning only)
<ident> void     identifier is used before a value is assigned to it
                 (warning only)
<ident> missing  forward label or specced identifier does not appear
                 in block
<ident>(?) missing  switch label to which there is an explicit jump
                 has not been specified
<n> extra values for <ident>
                 too many values for %const or %own array
Faulty operand   incorrect operand type for machine instruction
Wrong size       operand is of incorrect size for machine instruction
Too complex!     compiler limitation exceeded
Not in yet!      language feature not supported in current compiler
Out of reach!    %const or literal string, record or array is not
                 within the range of the machine addressing capability
<ident> Out of reach!
                 call to procedure specified is not within the
                 range of the machine addressing capability
Internal error <n>! compiler fault

Disastrous errors

These reports relate to compiler limits being exceeded.  They all cause
compilation to be abandoned.

Program too big             total size of the compiled code and constants
                            exceeds the maximum allowed for
Program space exhausted     size of the code for currently open blocks
                            exceeds the maximum allowed for
Identifier space exhausted  total length of all identifiers currently
                            in scope exceeds the maximum permitted
Too many identifiers        number of identifiers currently in scope
                            exceeds the maximum permitted
Too many levels             depth of textual nesting of blocks exceeds
                            the maximum permitted
Too many owns               space required for %own variable
                            initialisation exceeds the maximum permitted
Too many literals           internal storage space for literals is exhausted
Input ended                 there is no %endofprogram statement

Compiler limits

The following limits apply:

. The maximum depth of textual nesting is 7.

. The total size of the static data area (for owns/externals) is
limited to 32k bytes.

. The size of the code area (for program and constants) is limited
to 64k bytes. In addition, there is no escape from the machine
imposed reach of +-32k bytes for accesses to constants.
The compiler does attempt to cater automatically for procedure calls
which would otherwise run into this limitation, but is not
guaranteed to succeed.
The compiler report 'Out of reach!' indicates that one of these
limits has been breached. If a name is given, it is that of a
procedure; if no name is given, the problem is access to a constant.

Efficiency

. In the absence of floating-point hardware, all floating-point
operations are performed by software.

. Integer multiply and divide are also performed by software, although
multiplication by a literal power of 2 or sum of two powers of 2
is optimised. This optimisation is also performed for array
accesses where the element size meets the condition stated (with
array bound checks off).

. Accesses to arrays (including accesses via array names) are more
efficient if at least the lower bound is a literal (and for
multi-dimensional arrays if all the inner bounds are literal)

External linkage (May 83)

The external linkage mechanism provides for the use of program modules or libraries containing externally accessible procedures or variables.

A program module containing external procedures or variables, and terminated by
endoffile, is compiled in the ordinary way, eg IMP MYLIB. Before the externals
it contains can be accessed, the compiled module must be installed by the INSTALL command. The INSTALL command takes as parameter the name of a program file (extension MOB assumed) -- or list of names separated by commas. For example INSTALL MYLIB. The effect of installing a program file is to add all the external names it contains to the external symbol table; the code of the module is not loaded at this stage. Thereafter (until logoff) these names are available for external linking, which is done automatically when a program referencing any of the names is loaded. It is only necessary to re-install a program file if a change is made to the external names it contains.

An external name is the identifier declared as external (standardised to space-free lower-case form) unless this is over-ridden by an alias, in which case the alias name is used instead (exactly as presented). Note that an alias over-rides the declared identifier, rather than providing an alternative to it.

The system command HELP LIB gives information about generally available libraries.

Restrictions on externals

The following restrictions apply:-

1. Names are truncated to 11 characters for purposes of matching as externals
(temporary restriction).
2. The type checking is nominal (temporary amnesty). 3. External %name variables are not supported (temporary restriction). 4. External specs must all be at the top program level, that is, they may not
appear within procedures or inner blocks.
5. An external spec for a procedure may be satisfied by a procedure occurring
later in the same module, but the same is not true for variables.
6. Externals may not be combined with a main program (%begin ...
%endofprogram).

CAUTION: The form of external linkage in V2.0 onwards will differ from this interim form, necessitating re-compilation.

Permanent procedures

The permanent procedures listed below are available without specification. These are generally as provided on Vax, with exceptions and additions noted. Terminal output is direct, so that there is no need for any TTPUT or FLUSH OUTPUT procedures.

Standard PERM

%integermap      INTEGER(%integer a)
%realmap         REAL(%integer a)
%string(*)%map   STRING(%integer a)
%record(*)%map   RECORD(%integer a)
%bytemap         BYTEINTEGER(%integer a)
%shortmap        SHORTINTEGER(%integer a)
%bytemap         LENGTH(%string(*)%name s)
%bytemap         CHARNO(%string(*)%name s, %integer n)
%integerfn       ADDR(%name n)
%string(1)%fn    TOSTRING(%integer k)
%string(255)%fn  SUBSTRING(%string(255) s, %integer from,to)

%integerfn       REM(%integer a,b)

%integerfn       INTPT(%real x)
%integerfn       INT(%real x)
%realfn          FRACPT(%real x)
%realfn          SQRT(%real x)

%string(8)%fn    DATE
%string(5)%fn    TIME
%integerfn       CPUTIME  
                 !in milliseconds (actually elapsed time at present)

%record(*)       NIL
%recordformat    EVENTFM(%integer event,sub,extra,pc,
                 %string(255) message,%integerarray r(0:15))
                 !PC and R are APM-specific extensions
%record(eventfm) EVENT
%constinteger    NL
%integerfn       NEXTSYMBOL
%routine         READSYMBOL(%name n)
%routine         PRINTSYMBOL(%integer k)
%routine         SKIPSYMBOL
%routine         PRINTSTRING(%string(255) s)
%routine         READ(%name n)
%routine         WRITE(%integer m, n)
%routine         PRINT(%real x, %integer n,m)
%routine         PRINTFL(%real x, %integer n)
%routine         NEWLINE
%routine         NEWLINES(%integer i)
%routine         SPACE
%routine         SPACES(%integer i)
%routine         SELECTINPUT(%integer n)
%routine         SELECTOUTPUT(%integer n)
%routine         RESET INPUT
%routine         RESET OUTPUT
%routine         CLOSE INPUT
%routine         CLOSE OUTPUT
%integerfn       INSTREAM
%integerfn       OUTSTREAM
%routine         OPEN INPUT(%integer n, %string(31) S)
                 !*selects N at present*
%routine         OPEN OUTPUT(%integer n, %string(31) S)
                 !*selects N at present*
%routine         PROMPT(%string(31) S)
%integerfn       TESTSYMBOL
                 !*APM specific*
                 !value is -1 if no symbol available from terminal
                 !otherwise value is the symbol, which is skipped

%constinteger    NOECHO,NOTERMECHO,SINGLE,NOPAGE
%routine         SET TERMINAL MODE(%integer m)
                 !*APM specific*
                 !set terminal mode as specified by M (sum of flags)

Low-level facilities

As a system implementation language IMP provides a number of facilities which permit access to parts of the system other languages do not reach. The store-mapping functions (INTEGER, BYTEINTEGER, etc) allow for direct addressing using machine addresses; the name-relative indexing facility (as in CUR

[1] or POS[-2]) extends the capability of %name variables; the fixed-address declaration facility (as in @16_200 %integer TIMER, KBIN, KBOUT) allows efficient source-level access to specific areas of store.

The use of these facilities involves some loss of the protection normally conferred by a high-level language and a potential (particularly on a processor without hardware protection) for uncontrolled malfunction. They should, therefore, be used with restraint and care.

Assembler in IMP

Sequences of assembly language instructions may be incorporated in an IMP program at any point. At present no enabling directive is required. Apart from the usual hazards of machine level programming, there is the danger of corrupting the environment pre-supposed by the high-level facilities. For this reason, it is sensible to keep the use of these instructions to a minimum and to take particular care in programming these sections.

Assembly language instructions are distinguished from IMP statements by being prefaced by an asterisk (eg *MOVE D0,D1). They appear within IMP blocks and procedures and are executed according to the normal flow of control, subject to any control transfers invoked by the instructions themselves. IMP conventions for statement termination, labelling and commenting apply, but otherwise the form of instruction follows closely that defined under the heading of Assembler Syntax for each individual instruction in the Motorola M68000 manual. Machine-level operands are specified using the mnemonics D0-D7 and A0-A7 (or SP), and the standard syntax for <ea> modes. Immediate and Address register variants of op-codes are selected automatically. By comparison with full Assembler, most of the directives do not apply; assembly-time expression evaluation is restricted; size specification in cases where the size is implicit in the op-code is not in general allowed; the indexed PC-relative mode is not supported, nor is the 'current location counter'.

The error report 'Faulty operand' indicates use of an invalid operand for the context, but the compiler does not fully check the validity of <ea> modes for the particular instruction.

NB the default 'size' applied is Long (32-bits) rather than Word (16-bits) which is the manufacturer's default. It is sensible to make a practice of including the size suffix explicitly for all relevant instructions.

The special mnemonics USP (User Stack Pointer), SR (Status Register) and CCR (Condition Code Register) are NOT supported but the relevant effects can be achieved by use of the additional op-codes:

  MTCCR <ea>          for      MOVE <ea>,CCR
  MTSR <ea>           for      MOVE <ea>,SR
  MFSR <ea>           for      MOVE SR,<ea>
  MTUSP An            for      MOVE An,USP
  MFUSP An            for      MOVE USP,An
  ATCCR #<data>       for      AND #<data>,CCR
  ATSR #<data>        for      AND #<data>,SR
  ETCCR #<data>       for      EOR #<data>,CCR
  ETSR #<data>        for      EOR #<data>,SR
  OTCCR #<data>       for      OR #<data>,CCR
  OTSR #<data>        for      OR #<data>,SR

IMP identifiers may also be used as operands for assembly language instructions. The detailed implications of this over the whole range of data types are fairly complex and subject to change. The following cases are reasonably straightforward and stable. Scalar variables may be used as <ea> operands provided that they are:

declared as own or
declared at the outermost level or
declared at the current level or
declared by means of a fixed-address declaration

Variables declared at intermediate levels should not be accessed. In the case of a name variable the reference is to the pointer value (32-bit address) rather than the referenced object. At present it is not possible to access record fields in assembly language instructions.

Labels and procedure names may be referenced in the Branch group of instructions, including BSR. The only alternative form of operand for these instructions is immediate (eg *BLT #-4), the value specified being the machine-level displacement. Short and long branches are handled automatically (though the Compiler's CODE listing does not show this). To access a forward label in an assembly language instruction, it is neccesary for the label to have been declared by means of the IMP declaration %LABEL <lab>.

The registers D0-D3 and A0-A3 may be freely used within assembly sections, but no assumptions can be made about their contents after execution of most IMP statements. Other registers may be used only on the basis that their values are restored before reverting to IMP. In particular this applies to SP. In addition, NOTE WELL that the accessing of local variables depends on SP; if SP is changed, access to such variables in machine instructions becomes a nonsense (though no error report can be made). Similarly, any modification of A4-A6 rules out access to non-local variables.

Note that any declaration of IMP identifiers which co-incide with the register mnemonics takes precedence.

Events

Events may be signalled by the system or by the user (using %SIGNAL) and trapped using the %ON %EVENT.. construction.

%on %event <eventno>, <eventno>, ..... %start
...
finish

"%event" is optional in the statement above. Once the event has been trapped, further information may be obtained by interrogating the built-in record EVENT..

%recordformat eventfm(%byte event,sub,%short line,%integer extra,
%string(255)message,%integerarray r(0:15))

IMP and PASCAL share a common set of Event numbers. HELP EVENTS gives a table of these.

Known Defects

 . Statements like "%if COND %then %result = EXP1 %else %result = EXP2"
                   "%if COND %then %return %else ...
                   "%if COND %then %true/%false %else ...
                   "%if COND %then ->LAB %else ...
   are liable to be mis-compiled. Fix: change "%else" to ";".

 . run-time checks are not imposed on capacity, overflow for addition
   and subtraction, invalid %for loops or stack over-run

 . The %include construction cannot currently be nested i.e. %included files
   should not contain %includes.  This restriction has been lifted in versions
   of IMP for the new operating system.

This software is frozen. It may be possible to fix bugs in the run-time libraries but any faults found in the compiler will have to be programmed around.

view:impv1 printed on 01/03/89 at 16.15

Hamish Dewar