externalstring(255)fnspec date
externalstring(255)fnspec time
systemroutinespec exit alias "exit" (integer rc)

externalintegerfnspec cputime
externalroutinespec getblock alias "GETBLOCK_JSB" (integer len, bytename base)
externalintegerfunctionspec getlong alias "GETLONG_JSB"
externalintegerfunctionspec getword alias "GETWORD_JSB"
   externalroutinespec get(integername n)
   externalroutinespec put(integer n)
   externalroutinespec putword(integer n)
   externalroutinespec putlong(integer n)
   externalroutinespec putblock(integer len, bytename b)
!   Computer Science IMP77 Compiler   -   Version 8  Third pass
!      23rd March 1981
!      Mods by MT October/November 1981
!
! Uses common include file defining constants,
! spec'ing common externals etc.
!
!!%include "control.imp"

{%systemroutinespec exit %alias "exit" (%integer s)
!%external %routine %spec  PUT (%integer n)
!%external %routine %spec  PUT WORD (%integer n)
!%external %routine %spec  PUT LONG (%integer n)
!%external %routine %spec  PUT BLOCK (%integer n, %bytename b)
external routine spec  SELECT INPUT TANK (integer n)
external routine spec  SELECT OUTPUT TANK (integer n)
!%external %routine %spec  GET (%integer %name ch)
!%external %routine %spec  GET BLOCK (%integer len, %byte %name b)
external routine spec  PRINT RECORD (integer len, byte name buff)
external integer function spec  LOOK
!%external %integer %function %spec  GETWORD
!%external %integer %function %spec  GETLONG
external integer function spec  TAG alias "GETLONG";       ! For pass 2
external string(63) function spec  ITOS (integer n, p)

! streams
const integer  report      = 0
const integer  object file = 1
const integer  listing     = 2
const integer  diag stream = listing

! miscellaneous
const integer  max ident = 31;          ! Length for external linkage
const integer  fatal = 16_1000002C;     ! Error exit code to VMS


! external data (defined in driver)
external string(6) spec  version;       ! Compiler version string
external integer spec  command
external integer spec  control

! command bit meanings (set by command line)
const integer  diag bit  = 8_00004
const integer  line bit  = 8_00010
const integer  log bit   = 8_00020
const integer  time bit  = 8_01000
const integer  entry bit = 8_02000
const integer  init bit  = 8_04000
const integer  pic bit   = 8_10000

! control bit meanings  (%control n, or set by driver (/check= etc))
! bit set => check on

const integer  ass check  =   1;        ! unassigned checking
const integer  str check  =   2;        ! string capacity checking
const integer  for check  =   4;        ! %for checking
const integer  arr check  =   8;        ! array bound checking
const integer  ovf check  =  16;        ! integer overflow checking
const integer  rec round  = 128;        ! rounding in records (turns it on)
const integer  profiling  = 256;        ! call TRACE (line no) at bounds

! object file commands  Pass2 => Pass3

const integer  obj extern    = 1;       ! insert external entry
const integer  obj code      = 2;       ! code block
const integer  obj gla       = 3;       ! gla  block
const integer  obj pdef      = 4;       ! external proc definition
const integer  obj pspec     = 5;       ! external proc specification
const integer  obj ddef      = 6;       ! external data definition
const integer  obj dspec     = 7;       ! external data specification
const integer  obj reloc     = 8;       ! relocate gla
const integer  obj set       = 9;       ! set gla to tag address
const integer  obj header    = 10;      ! start of procedure
const integer  obj call      = 11;      ! procedure call
const integer  obj jump      = 12;      ! jump
const integer  obj prim spec = 13;      ! prim definition
const integer  obj end       = 14;      ! end of object file
const integer  obj line      = 15;      ! line number
const integer  obj term      = 16;      ! end of block
const integer  obj diag p    = 17;      ! diags for proc header
const integer  obj diag v    = 18;      ! diags for variable
const integer  obj weak      = 19
const integer  obj b lab     = 20;      ! bxxb in m/code
const integer  obj w lab     = 21;      ! bxxw in m/code
const integer  obj glam      = 22;      ! initialise n items in GLA
const integer  obj modd      = 23;      ! modify displacement
const integer  obj prim ref  = 24;      ! call to prim
const integer  obj ext ref   = 25;      ! call to external procedure
const integer  last obj code = 25

! directive file commands  Pass2 => Pass3

const integer  dir used      = 1;       ! external used
const integer  dir ldef      = 2;       ! label definition
const integer  dir pref      = 3;       ! procedure reference
const integer  dir cref      = 4;       ! conditional label reference
const integer  dir uref      = 5;       ! unconditional label reference
const integer  dir end       = 6;       ! end of procedure
const integer  dir sizes     = 7;       ! end of directives+sizes
const integer  dir x end     = 8;       ! end of external entry
const integer  dir header    = 9;       ! start of procedure
const integer  dir entry     = 10;      ! define entry label
const integer  last dir code = 10

!!%end %of %file

! Size constants
const integer  max tag       = 4000;          ! total tags in use
const integer  max ref       = 6000;          ! references to tags
const integer  max procs     =  600;          ! procedures in module
const integer  max externals =  400;          ! external defs/refs
const integer  max rec       =  512;          ! object record size

external routine  PASS3 (string(63) module, integer object, directives)
   integer  check ass = control&ass check;       ! unassigned checking on
   integer  diags     = command&diag bit;        ! dump diag psect
   integer  ldump     = command&line bit;        ! dump lines (trace) psect
   integer  pic       = command&pic bit;         ! PIC for gla
   integer  init      = command&init bit;        ! initialisation needed
   integer  timing    = command&time bit;        ! full timing report
   integer  clog      = command&log bit;         ! summary to console

   const integer  proc enter prim = 13;          ! = "$_M"

   const integer  non zero = 1;                  ! boolean

   ! Op-codes
   const integer  brb    = 16_11;                ! +127/-128
   const integer  brw    = 16_31;                ! +32767/-32768
   const integer  jmp    = 16_17;                ! anywhere...
   const integer  bneq   = 16_12, bnequ = 16_12
   const integer  beql   = 16_13, beqlu = 16_13
   const integer  bgtr   = 16_14
   const integer  bleq   = 16_15
   const integer  bgeq   = 16_18
   const integer  blss   = 16_19
   const integer  bgtru  = 16_1A
   const integer  blequ  = 16_1B
   const integer  bgequ  = 16_1E
   const integer  blssu  = 16_1F
   const integer  jsb    = 16_16
   const integer  calls  = 16_FB
   const integer  movl   = 16_D0
   const integer  moval  = 16_DE
   const integer  movab  = 16_9E
   const integer  subl2  = 16_C2
   const integer  movc5  = 16_2C

   ! Branch table - invert (branch (b)) = branch(b!!7)
   const byte array  branch (0 : 15) =
      brb,   beql,  blss,  bleq,  bgtr,  bgeq,  bneq,   0,      {signed}
    { u/c     =      <      <=     >      >=      #   never }
      brb,   beqlu, blssu, blequ, bgtru, bgequ, bnequ,  0       {unsigned}


   const integer  margin   = 800;                ! stretch margin for jumps
   const integer  safe low = 16_ffff8001+margin
   const integer  safe high= 16_00008000-margin

   const integer  middling = 16_1000;            ! word disp ref

   ! Object record constants

   const integer  obj hdr = 0
   const integer      hdr mhd = 0;               ! module header
   const integer      hdr lng = 1;               ! language sub-header

   const integer  obj gsd = 1
   const integer      gsd psc = 0;               ! P-sect def
   const integer      gsd sym = 1;               ! Symbol (def/ref)
   const integer      gsd epm = 2;               ! Ext def + mask

   const integer  obj tir = 2
   const integer      tir stag    = 0;           ! Stack global symbol
   const integer      tir stasb   = 1;           ! Stack signed byte
   const integer      tir stasw   = 2
   const integer      tir stal    = 3
   const integer      tir stpbb   = 4
   const integer      tir stpbw   = 5
   const integer      tir stpbl   = 6
   const integer      tir staub   = 7;           ! Stack unsigned byte
   const integer      tir stob    = 20;          ! Store signed byte
   const integer      tir stow    = 21;          ! Store signed word
   const integer      tir stol    = 22;          ! Store longword
   const integer      tir stold   = 25;          ! Store longword
   const integer      tir stopidr = 27;          ! Store PIC data reference
   const integer      tir stopicr = 28;          ! Store PIC reference
   const integer      tir sto rl  = 31;          ! Store repeated long
   const integer      tir stoub   = 33;          ! Store unsigned byte
   const integer      tir stogb   = 37;          ! Store general byte
   const integer      tir sto rb  = 39;          ! Store repeated byte
   const integer      tir sto rw  = 40;          ! Store repeated word
   const integer      tir add     = 51
   const integer      tir setrb   = 80
   const integer      tir augrb   = 81

   const integer  obj eom = 3
   const integer  obj dbg = 4

   !P-sect info

   const integer  quad = 3;                      ! 8(=2**3)-byte alignment

   const integer  ps pic = 1<<0
   const integer  ps rel = 1<<3
   const integer  ps shr = 1<<5
   const integer  ps exe = 1<<6
   const integer  ps rd  = 1<<7
   const integer  ps wrt = 1<<8

   own integer name  ca
   own integer name  ga
   own integer  base        =  0
   own short    ref head    =  0
   own short name  ref chain;   ref chain == ref head
   own short    def list    =  0;        !ordered list of labels
   own integer  this line   =  0
   own integer  entry tag   = -1

   const integer  code flags = ps pic ! ps rel ! ps rd  ! ps exe ! ps shr
   own   integer  glap flags = ps rd  ! ps wrt ! ps rel ! ps pic
!                    glap flags = glap flags ! ps pic %if pic # 0
   const integer  diag flags = ps pic ! ps rel ! ps rd  ! ps shr
   const integer  line flags = ps pic ! ps rel ! ps rd  ! ps shr

   const string(10)  code name = "$_CODEAREA"
   own   string(10)  glap name = "$_GLAPAREA"
!                       glap name = "$_GLAPPIC"
   const string(10)  diag name = "$_DIAGAREA"
   const string(10)  line name = "$_CODELINE"
   const string(10)  init proc = "IMP$_INIT"

   integer  refs, last tag
   integer  code size, glap size, diag size, line size
   integer  procs, events, event base, evp, specs
   own string(max ident)  text

   record format  psect fm (integer bp, pa, dump, bs, lr, lrp,
                              integer index, lbs, bb, be, max,
                              (byte type or
                               byte array b (1 : maxrec)))
   own record(psect fm)  codep, glapp, workp, diagp, linep
   own record(psect fm) name  buff;        ! Points at one of above

   record format  ref fm (integer ca, tag, short flag, link)
   record format  def fm (integer ca, short uses, link)
   record(def fm) array  def (0 : max tag)
   record(ref fm) array  ref (1 : max ref)

   record format  proc fm (integer frame,
                             short type, mask, diag, diag ep, line ep)
   record(proc fm) array  proc tab (1 : max procs)

   byte              array  ext used (1 : max externals)
   string(max ident) array  ext text (1 : max externals)


   routine  ERROR (string(31) text, integer extra)
      select output (report)
      newline
      print string ("***Pass3 fails """);  print string (text)
      print string (""" (");  write (extra, 0);  print symbol (')')
      newline
      monitor
      exit (16_1000002c)     {1000002c is SS$_ABORT with the inhibit message bit set - could just use EXIT_FAILURE}
   end

   routine  GET STRING (string(*) name  t)
      integer  len, file len
      get (len)
      file len = len
      error ("external size?", len) unless 0 < len <= max ident
      len = len - 1 if len = max ident {make room for '_' in Gla name}
      length(t) = len
      getblock (file len, charno(t,1))
   end

   routine spec  STPB (record(psect fm) name p, integer d)
   routine spec  ADD (integer b)
   routine  FLUSH BUFF
      integer name  bp
      bp == buff_bp
      if bp > max rec start
         ! over the limits!
         error ("buffer error - seek help!!", bp-maxrec)
      finish
      if buff_dump # 0 start
         error ("buffer error", 1) if buff_bs > 0;   ! Still in IMMED mode
         if bp > 1 start
            print record (bp, buff_b(1))
         finish
      finish
      buff_bs = 0;  buff_be = 0;  buff_lbs = 0;  buff_lr = 0
      bp = 1;                   ! leave type field
      if buff_type = obj tir and buff_dump # 0 start
         ! fill in reloc command
         stpb (buff, buff_pa);  add (tir setrb)
         buff_lr = buff_bp;  buff_lrp = 1
      finish
   end

   routine  NEED (integer  b)
      ! ensure there are at least b bytes free in current buffer
      flush buff if buff_bp + b > max rec
   end

   routine  SET WORK (integer type)
      buff == workp;  flush buff
      workp = 0;  workp_dump = 1
      workp_type = type;  workp_bp = 1
   end

   routine  ADD (integer b)
      return if buff_dump = 0
      buff_bp = buff_bp + 1;  buff_b(buff_bp) = b&255
   end

   routine  ADDW (integer n)
      return if buff_dump = 0
      shortinteger(addr(buff_b(buff_bp+1))) = n
      buff_bp = buff_bp + 2
   end

   routine  ADDL (integer n)
      return if buff_dump = 0
      integer(addr(buff_b(buff_bp+1))) = n
      buff_bp = buff_bp + 4
   end

   routine  ADD STRING (integer from, string(63) s)
      integer b, l
      return if buff_dump = 0
      l = length(s)
      if from = 0 start
         string(addr(buff_b(buff_bp+1))) = s
         buff_bp = buff_bp + 1
      else
         b = buff_b(buff_bp)
         string(addr(buff_b(buff_bp))) = s
         buff_b(buff_bp) = b
      finish
      buff_bp = buff_bp + l
   end

   routine  ADD TEXT (integer data)
      string(max ident) t = text
      return if buff_dump = 0
      t = t . "_" if data # 0
      add string (0, t)
   end

   integer function  RANGE (integer disp, extra)
      result = 1 if -128 <= disp <= 127
      result = 2 if 16_FFFF8000 <= disp-extra <= 16_7FFF
      result = 4
   end

   routine  STAG (string(max ident+3) S)
      need (1+1+length(S))
      add (tir stag);   add string (0, S)
   end

   routine  TIR COMMAND (integername value, integer param,
                          byte array name  clist)
      integer  size
      size = range (value, 0)
      need (2+size)
      add (clist(size))
      add (param) if param >= 0
      if size = 1 start
         add (value)
      else if size = 2
         addw (value)
      else
         addl (value)
      finish
      value = size
   end

   routine  STPB (record(psect fm) name p, integer offset)
      own byte array  stpbc (1 : 4) =
         tir stpbb, tir stpbw, 0, tir stpbl
      tir command (offset, p_index, stpbc)
   end

   routine  STAK (integer  value)
      own byte array  stac (1 : 4) =
         tir stasb,  tir stasw, 0, tir stal
      tir command (value, -1, stac)
   end

   routine  SELECT (integer disp)
      return if buff_dump = 0
      need (7);                 ! Sequence must be in one record!
      error ("psect overflow", disp) if disp > buff_max
      if buff_lr = buff_bp start
         ! Have not planted anything since last 'select'
         buff_bp = buff_lrp;    ! Forget last select
         buff_pa = -20;         ! Ensure this one planted!
      finish
      if buff_pa # disp start
         buff_lrp = buff_bp
         stpb (buff, disp)
         add (tir setrb)
         buff_lr = buff_bp
         buff_pa = disp
      finish
   end

   routine  START IMMED (integer max)
      return if buff_dump = 0
      error ("buffer in use", 0) if buff_bs # 0
      error ("immediate size error", max) if max > 128
      need (max+1)
      if buff_be = buff_bp and
          max + (buff_bp - buff_lbs) <= 128 start
         ! Can concatenate buffers
         buff_bs = buff_lbs
      else
         add (0);                            ! Length byte
         buff_bs = buff_bp
      finish
      buff_bb = buff_bp;                     ! Where this block started
   end

   routine  END IMMED
      integer  size
      return if buff_dump = 0
      error ("buffer not in use", 0) if buff_bs = 0
      size = buff_bp - buff_bs
      if size # 0 start
         error ("buffer overflow", size) if size > 128
         buff_b(buff_bs) = -size
         buff_lbs = buff_bs
         buff_be = buff_bp
      else
         buff_bp = buff_bp - 1
      finish
      buff_pa = buff_pa + buff_bp - buff_bb; ! Update psect disp.
      error ("Psect immediate overflow", 0) if buff_pa > buff_max
      buff_bs = 0;                           ! Not buffering now
   end

   routine  SPEC (integer flags, data, value, mask)
      integer  def, len, psect
      psect = |data|
      data = 0 if data < 0;                   ! no '_' for ext data def
      def = flags&2
      len = (1+1)+(data+length(text))
      len = len + 7 if def # 0
      set work (obj gsd)
      if def = 0 start
         add (gsd sym)
      else
         add (gsd epm)
      finish
      add (0);                               ! data type - unknown
      addw (flags);                          ! symbol flags
      if def # 0 start;                      ! definition
         add (psect)
         addl (value)
         addw (mask)
      finish
      add text (data)
   end

   routine  INPUT DIRECTIVES
      switch  d (1 : last dir code)
      short  first = 0, list = 0
      short name  ref list == first, end
      record(proc fm) name  proc
      record(ref fm)  name  r
      record(def fm)  name  t
      integer name  q
      integer  proc head, n, frame, ldiag
      integer  ecode, unass code, size
      integer  rp, tag, block tag, dcode
      own integer  dap = 0, lap = 2

      procs = procs + 1
      proc == proc tab(procs)
      proc_diag ep = 0
      proc_line ep = 0

      cycle
         get (dcode)
         -> d(dcode) if 1 <= dcode <= last dir code
         error ("spurious directive", dcode)

   d(dir used):
         ext used(getword) = non zero
         continue

   d(dir ldef):
         tag = getword
         error ("too many labels", tag) unless 0 < tag <= max tag
         t == def(tag)
         t_ca = getlong;    ! ca
         end == t_link if list = 0
         t_link = list;  list = tag
         continue

   d(dir pref):
   d(dir cref):
   d(dir uref):
         tag = getword
         error ("too many labels", n) unless 0 < tag <= max tag
         error ("too many references", refs) if refs = max ref
         refs = refs + 1;  r == ref(refs)
         r_tag = tag
         r_ca = getlong;                     ! ca
         r_flag = dcode - 3
         ref list = refs
         ref list == r_link
         continue

   d(dir entry): ! define ep
         entry tag = getword
         continue

   d(dir header):
         input directives
      repeat

   d(dir end):
      proc_type = getlong
      proc_mask = getword&16_CFFC
      frame = -getlong
      proc_frame = frame;               ! frame size
      ldiag = getword
      proc_diag = ldiag
      error ("corrupt diags", diags) if ldiag = 0 and diags # 0
      proc_diag ep = dap;  dap = dap + ldiag
      proc_line ep = lap;  lap = lap + getword
      block tag = getword
      ! compute length of entry code sequence
      ecode = 2;                             ! for entry mask
      if block tag = entry tag and init # 0 start
         ecode = ecode + 7;                  ! calls #0,l^init proc
      finish
      if proc_type # 0 start
         ecode = ecode + 7;                  ! moval l^ep_,gla
      finish
      ecode = ecode + 3;                     ! movl fp, base
      if frame # 0 start
         ! locals - needs frame + unass code
         unass code = 8;                     ! movc5 #0,(fp),(gla),s^#f,(sp)
         if frame <= 63 start
            !short lit - byte's worth
            ecode = ecode + 3;               ! subl2 i^#f, sp
            unass code = 6;                  ! movc5 #0,(fp),(gla),i^#f,(sp)
         else if frame <= 16_7fff
            !word's worth (sheer poetry)
            ecode = ecode + 5;               ! moval w^-f(sp), sp
         else
            ecode = ecode + 7;               ! subl2 s^#f, sp
         finish
         if check ass # 0 start
            ecode = ecode + unass code
            proc_mask = proc_mask ! 16_003C; ! r0-r5 corrupted by MOVC5!!!
         finish
      finish
      t == def(block tag)
      t_ca = t_ca - ecode
      base = base + ecode

   d(dir xend):  ! end of external proc

      tag = list
      while tag # 0 cycle
         t == def(tag)
         t_ca = t_ca + base
         tag = t_link
      repeat
      if list # 0 start;                     ! add labels to def list
         end = def list
         def list = list
      finish
      ref list = 0;                          ! mark the end
      rp = first
      while rp # 0 cycle
         r == ref(rp)
         r_ca = r_ca + base
         rp = r_link
      repeat
      size = getlong;                        ! total size
      base = base + size
      if first # 0 start
         ref chain = first
         ref chain == ref list
         ref chain = 0
      finish
      return

   d(dir sizes):   ! end of directives, totals follow
      glap size  = getlong
      last tag   = getword
      specs      = getword
      diag size  = getword
      events     = getword
      proc tab(1)_diag ep = dap
      line size  = lap
   end

   routine  STRETCH JUMPS
      integer  extra, here, there, disp, mod, tag
      integer name  pt
      short name  last, next
      record(ref fm) name  r
      record(def fm) name  t
      cycle
         extra = 0
         last == ref head
         while last # 0 cycle
            r == ref(last)
            next == r_link
            r_ca = r_ca + extra
            here = r_ca + 2
            there = def(r_tag)_ca
            disp = there - here
            mod = 0
            if r_flag&middling = 0 and
                not -128 <= disp <= 127 start
               r_flag = r_flag!middling
!********               %if safelow <= disp <= safe high %start
!********                  ! will not stretch again
!********                  last = next
!********                  next == last
!********               %finish
               mod = 1;                      ! 1-byte -> 2-byte disp
               mod = 3 if r_flag&1 # 0;      ! conditional -> skip+brw
            else unless 16_FFFF8001 <= disp <= 16_8000
               ! cannot get bigger
               last = next
               next == last
               mod = 2;                      ! word disp -> longword disp
               mod = 3 if r_flag&3 # 0;      ! brw -> jmp
            finish
            if mod # 0 start
               tag = def list
               while tag # 0 cycle
                  t == def(tag)
                  pt == t_ca
                  exit if pt < here
                  pt = pt + mod
                  tag = t_link
               repeat
               extra = extra + mod
            finish
            last == next
         repeat
         base = base + extra
      repeat until extra = 0
      event base = (base+7)&(¬7)
      evp = event base
      code size = event base + events*16 + 4
   end

   routine  DUMP CODE (integer base, btag, limit)
      switch  c (1 : last obj code)
      own byte array  base mod (5 : 15)
      ! Code type enables pre-selection of the appropriate
      ! output buffer for each command code byte from Pass 2.
      const byte array  code type (1 : last obj code) =
         0, 0, 1, 0, 0,
         1, 1, 1, 1, 0,
         0, 0, 0, 0, 3,
         0, 2, 2, 0, 0,
         0, 1, 0, 0, 0
      own record(psect fm) name array  buff for (0 : 3)
      own integer  called = 0

      integer  disp, cond
      integer  ldiag, value
      integer  ocode, type
      integer  gb, gx, cx, xno, pno
      integer  old ca, old la, old da
      integer  count, size, n, save
      integer  reg, specifier, mode
      integer  evlow, evep, evword
      integer  tag, lim, nbase
      record(proc fm) name  proc

      routine  DUMP LINE
         buff == linep
         start immed (6)
         addl (ca);  addw (this line)
         end immed
      end

      routine  LOAD BLOCK
         integer  n
         get (n);  start immed (n)
         get block (n, buff_b(buff_bp+1))
         buff_bp = buff_bp + n
         end immed
      end

      routine  SET PRIM TEXT (integer  pno)
         text = "$_"
         text = text . "_" and pno = pno - 26 while pno > 26
         text = text . tostring ('A'-1+pno)
      end

      routine  PLUG GLAP (record(psect fm) name with,
                           integer with disp, where, inst)
         integer  old ga = ga
         unless 0 < where < glap size start
            error ("faulty glap relocation", where)
         finish
         buff == glapp;  select (where)
         need (7);                   ! Must have following in one record..
         stpb (with, with disp)
         add (inst)
         select (old ga)
      end

      routine  BSEL (integername old, record(psect fm) name p,
                      integer  new)
         buff == p
         old = p_pa
         select (new)
      end

      routine  INITIALISE BUFFERS
         buff for(0) == codep
         buff for(1) == glapp
         buff for(2) == diagp
         buff for(3) == linep
         called = non zero
      end

      routine  HANDLE BLOCK ENTRY
         integer  mask, unsaved, reg
         integer  frame
         base = 13 if base = 12;             ! bottom 2 levels
         dump line if ldump # 0
         buff == codep
         ! Calculate true offset from FP of args to this proc
         ! for benefit of inner procs referencing them.  This
         ! is affected by the number of regs saved on the stack
         ! on proc call.  Pass 2 assumes all regs saved, we now
         ! calculate how many aren't, and subtract this*4 from
         ! displacement used by pass 2.
         mask = proc_mask;  unsaved = 0
         for reg = 2, 1, 11 cycle
            unsaved = unsaved + 1 if mask & (1<<reg) = 0
         repeat
         base mod(base) = unsaved*4;         ! to subtract off
         frame = proc_frame;                 ! frame size
         start immed (50);                   ! For entry sequence
         addw (mask);                        ! entry mask
         if proc_type # 0 start
            ! %external entry
            get string (text);               ! name
            if entry tag = btag and init # 0   start
               add (calls);  add (0);        ! calls  #0,init proc
               end immed
               stag (init proc);             ! spec reference
               add (tir stopicr);            ! store it
               ca = ca + 5
               start immed (1)
            finish
            add (moval);   end immed;        ! moval
            need (1+1+length(text)+1+1);
            stag (text."_");
            add (tir stopicr);               !        ep_,
            ca = ca + 5
            start immed (50);  add (16_5B);  !            gla
         finish
         add (movl);                         ! movl
         add (16_5D);  add (16_50+base);     !        fp, base
         if frame # 0 start
            if frame <= 63 start
               add (subl2);                  ! subl2
               add (frame);                  !        S^#frame
            else if frame <= 16_7fff
               add (movab);                  ! movab
               add (16_CE);  addw (-frame);  !        W^-frame(sp)
            else
               add (subl2);                  ! subl2
               add (16_8F);  addl (frame);   !        I^#frame
            finish
            add (16_5E);                     !                    , SP
            if check ass # 0 start
               add (movc5);  add (0);  add (16_6D);  add (16_6B)
               if frame <= 63 start
                  add (frame)
               else
                  add (16_8F);  addw (frame&16_7FFF)
               finish
               add (16_6E)
               !movc5_#0,(fp),(gla), #N, (sp)
            finish
         finish
         end immed
      end

      initialise buffers if called = 0
      procs = procs + 1
      proc == proc tab(procs)
      bsel (old da, diagp, proc_diag ep)
      bsel (old la, linep, proc_line ep)
      bsel (old ca, codep, def(btag)_ca)
      handle block entry if base # 0

      cycle
         get (ocode)
         buff == buff for(code type(ocode))
         -> c(ocode) if 0 < ocode <= 25
   c(*): error ("spurious object", ocode)

   c(obj diag p):
         n = getword
         get string (text)
         ldiag = proc_diag
         error ("corrupt diags", 0) if ldiag = 0
         start immed (50)
         addw (ldiag);  addw (n);  addl (limit);  add text (0)
         end immed
         continue
   c(obj diag v):
         start immed (50)
         addw (getword);  addl (getlong)
         get string (text);  add text (0)
         end immed
         continue
   c(obj code):
         load block
         continue
   c(obj modd):
         get (ocode);  error ("faulty mod", ocode) if ocode # 2
         get (n);                            ! # bytes following
         start immed (n)
         get (specifier);   n = n - 1
         reg = specifier & 15
         add (specifier)
         if n = 1 start
            get (disp)
         else if n = 2
            disp = getword
         else if n = 4
            disp = getlong
         else
            error ("faulty disp in mod", n)
         finish
         disp = disp - base mod(reg)
         add (disp)
         add (disp>>8) if n > 1
         addw (disp>>16) if n = 4
         end immed
         continue
   c(obj gla):
         gb = getlong
         error ("gla pos error", gb-ga) if gb # ga
         load block
         continue
   c(obj glam):
         gb = getlong
         error ("glam pos error", gb-ga) if gb # ga
         value = getlong;                    ! value
         count = getlong;                    ! repeat count
         size  = getlong;                    ! bytes in object
         if count*size > 15 start
            ! Worth doing as 'store repeated' type
            stak (value)
            stak (count)
            need (1)
            if size = 1 start
               add (tir sto rb)
            else if size = 2
               add (tir sto rw)
            else if size = 4
               add (tir sto rl)
            else
               error ("Faulty glam size", size)
            finish
            ga = ga + count*size
         else
            start immed (count*size)
            for n = 1, 1, count cycle
               if size = 1 start
                  add (value)
               else if size = 2
                  addw (value)
               else if size = 4
                  addl (value)
               else
                  error ("Faulty glam size", size)
               finish
            repeat
            end immed
         finish
         continue
   c(obj pdef): ! proc def
         tag = getlong
         get string (text)
         spec (2_1010, 0,
               def(tag)_ca, proc_mask);      ! ep
         spec (2_1010, 1, 0, 0);             ! gla (ep_)
         continue
   c(obj pspec): ! proc spec
         xno = getword
         get string (text)
         if ext used(xno) # 0 start;           ! strong code
            spec (2_1000, 0, 0, 0)
            ext text(xno) = text
         finish
         continue
   c(obj ddef): ! data def
         gx = getlong
         get string (text)
         spec (2_1010, -1, gx, 0);           ! Note -1 => special
         continue
   c(obj weak):  ! weak ref
   c(obj dspec): ! data ref
         xno = getword
         get string (text)
         ext text(xno) = text
         mode = 2_1000;  mode = 2_1001 if ocode = obj weak
         spec (mode, 0, 0, 0)
         continue
   c(obj ext ref):
         xno = getword;                      ! External number
         disp = getlong;                     ! Offset
         get (reg);                          ! Base reg (+ indirect bit)?
         stag (ext text(xno));               ! External address
         if disp # 0 start
            stak (disp);   need (1);  add (tir add)
         finish
         need (1);   add (tir stopicr);   ca = ca + 5
         if reg&16 # 0 start
            !indirect ref - won't work if absolute!!
            need (16)
            add (tir augrb);   addl (-5);    ! Go back to specifier byte
            add (tir staub);   add (16_FF);  ! stack byte 16_FF = @L^X(PC)
            add (tir stoub);                 ! store byte
            add (tir augrb);   addl (4);     ! return to correct ca
         finish
         continue
   c(obj reloc): ! relocate gla
!         error ("Not PIC", 0) %if pic # 0
         gb = getlong;   gx = getlong
         plug glap (glapp, gx, gb, tir stopidr)
         continue
   c(obj set): !set gla
         cx = def(getlong)_ca;           ! Switch label address
         gb = getlong;                       ! Gla address to plug
         plug glap (codep, cx+4, gb, tir stold)
         continue
   c(obj header):
         get (nbase);                        ! base
         tag = getword;                      ! tag
         lim = getword
         this line = getword
         dump code (nbase, tag, def(lim)_ca)
         continue
   c(obj call):
         tag = getlong
         disp = def(tag)_ca-ca-2
         start immed (5)
         n = range (disp, 1)
         if n = 1 start;
            add (16_AF);  add (disp)
         else if n = 2
            add (16_CF);  addw (disp-1)
         else
            add (16_EF);  addl (disp-3)
         finish
         end immed
         continue
   c(obj jump): ! jump <cond> <tag>
         get (cond);  tag = getword
         cond = cond&15
         disp = def(tag)_ca-ca-2
         size = range (disp, 1)
         start immed (8)
         if cond = 0 start;            !unconditional
            if size = 1 start
               add (brb);  add (disp)
            else if size = 2
               add (brw);  addw (disp-1)
            else
               add (jmp);  add (16_EF);  addl (disp-4)
            finish
         else;                         !conditional
            if size = 1 start
               add (branch(cond));   add (disp)
            else if size = 2
               add (branch(cond!!7));  add (3)
               add (brw);  addw (disp-3)
            else
               add (branch(cond!!7));  add (6)
               add (jmp);  add (16_EF);  addl (disp-6)
            finish
         finish
         end immed
         continue
   c(obj b lab):  ! m/code byte label reference
   c(obj w lab):  !  " " " word  " "  " " " "
         disp = def(getword)_ca-ca-1
         start immed (2)
         if ocode = obj w lab start;            !word
            addw (disp-1)
         else;                                  !byte
            error ("branch overflow", disp) unless -128 <= disp <= 127
            add (disp)
         finish
         end immed
         continue
   c(obj prim spec):
         get (pno);  set prim text (pno)
         spec (2_1000, 0, 0, 0)
         continue
   c(obj prim ref):
         get (pno);  set prim text (pno)
         if pno # proc enter prim start
            start immed (1);  add (jsb);   end immed
         finish
         stag (text)
         need (1);  add (tir stopicr);  ca = ca + 5
         continue
   c(obj line): ! line number
         this line = getword
         dump line if ldump # 0
      repeat

   c(obj term):!block end
      if diagp_pa # 0 start
         buff == diagp
         start immed (1);  add (0);  end immed
      finish
      evword = getword;                        !events
      if evword # 0 start;                     !events trapped
         evlow = getword;                      !evlow
         evep  = getword;                      !evep
         buff == codep;  save = ca
         select (evp)
         start immed (16)
         addl (evword);                        !ev list
         addl (def(evlow)_ca);                 !from
         addl (save);                          !to (ca)
         addl (def(evep)_ca);                  !entry point
         end immed
         evp = evp + 16
      finish

   c(obj end):
      bsel (n, diagp, old da)
      bsel (n, linep, old la)
      bsel (n, codep, old ca)
   end

   routine  DUMP ALL CODE
      select input tank (object)
      procs = 0
      dump code (0, 0, 0)
   end

   routine  DEFINE PSECT (record(psect fm) name ps,
                           integer  align, flags, size,
                           string(31) name)
      own integer  psect no = 0
      set work (obj gsd)
      add (gsd psc);            ! P-sect def field
      add (align);              ! Align (as power of 2)
      addw (flags);             ! P-sect flags (rd,wrt,exe etc)
      addl (size);              ! Allocation in bytes
      add string (0, name);     ! Ident
      ps = 0
      ps_dump = 1;  ps_type = obj tir;  ps_bp = 1
      ps_max = size
      ps_index = psect no
      psect no = psect no + 1
      flush buff
      buff == ps;  ps_pa = -999;  ! ensure SELECT happens...
      select (0)
   end

   routine  DUMP MODULE HEADER
      string(31) temp
      select output (object file)
      set work (obj hdr);                   !header
      add (hdr mhd);                        !module header record
      add (0);                              !structure level
      addw (max rec);                       !max record length
      add string (0, module);               !module name
      add string (0, "V01.00");             !module version
      temp = date . " " . time
      length(temp) = length(temp) - 3;      !remove milliseconds
      add string (1, temp);                 !creation date
      add string (1, "IMP is wonderful!");  !last patch!!
      set work (obj hdr)
      add (hdr lng);                        !language sub-header
      add string (1, "VAX-11 Imp77 ".version)
   end

   routine  DEFINE PSECTS
      define psect (codep, quad, code flags, code size, code name)
      define psect (glapp, quad, glap flags, glap size, glap name)
      if diags # 0 start
         define psect (diagp, quad, diag flags, diag size+2, diag name)
         ! add 2 to ensure 0 word at end...
      else
         diagp_dump = 0
      finish
      if ldump # 0 start
         define psect (linep, quad, line flags, line size, line name)
         !fill in length word
         buff == linep;  select (0)
         start immed (2);  addw (line size);  end immed
      else
         linep_dump = 0
      finish
   end

   routine  INITIALISE
      integer  j
      ext used(j) = 0 for j = 1, 1, max externals
      select input tank (directives)
      refs = 0;  procs = 0;  def(0) = 0
      ca == codep_pa;  ga == glapp_pa
   end

   routine  SPEC INIT PROC
      return if entry tag < 0 or init = 0
      set work (obj gsd)
      add (gsd sym);             ! symbol entry
      add (0);                   ! unknown data type
      addw (2_1000);             ! flags
      add string (0, init proc); ! name
      flush buff
   end

   routine  PLUG PSECTS
      buff == glapp;  select (12);       ! plug things into gla
      ! code psect base
      need (50)
      stpb (codep, 4);     add (tir stold)
      ga = ga + 4
      ! diags psect base
      if diags # 0 start
         stpb (diagp, 4)
      else
         stak (4)
      finish
      add (tir stold)
      ga = ga + 4
      ! lines psect base
      if ldump # 0 start
         stpb (linep, 4)
      else
         stak (4)
      finish
      add (tir stold)
      ga = ga + 4
      start immed (10)
      addw (0);                         ! null string
      addl (proc tab(1)_diag ep)
      addl (event base)
      end immed
      buff == codep;  select (evp)
      stak (0);  add (tir stol)
      if diags # 0 start
         buff == diagp;  select (diag size)
         start immed (2);  addw (0);  end immed
      finish
   end

   routine  DUMP EOM
      set work (obj eom)
      add (0);                            ! Successful compilation
      if entry tag >= 0 start
         add (0)
         addl (def(entry tag)_ca)
      finish
      flush buff
   end

   routine  FLUSH BUFFERS
      buff == codep;  flush buff
      buff == glapp;  flush buff
      buff == diagp;  flush buff
      buff == linep;  flush buff
      buff == workp;  flush buff
   end

   routine  REPORT INFO
      integer  stream
      for stream = report, listing-report, listing cycle
         continue if clog = 0 and stream = report
         select output (stream)
         print string ("Code");            write (codep_max-4, 1)
         print string (" bytes  Glap");    write (glapp_max, 1)
         print string (" bytes  Diags");   write (diagp_max+linep_max, 1)
         print string (" bytes   Total size")
         write (codep_max-4+glapp_max+diagp_max+linep_max, 1)
         print string (" bytes");  newline
      repeat
   end

   routine  TIME (routine  R, string(15) name)
      external integer function spec  PAGEFAULTS
      integer  t, p
      own integer  called = 0
      p = page faults;   t = cputime
      R
      t = cputime - t;   p = pagefaults - p
      return if timing = 0
      select output (report)
      print string ("Pass 3 breakdown:") and newline if called = 0
      called = 1
      spaces (3)
      print string (name);  print symbol (':')
      spaces (15-length(name));  space
      if t >= 20 start
         write (t, -5);  print string ("ms,    ")
      else
         print string ("negligible, ")
      finish
      write (p, -3);  print string (" page fault")
      print symbol ('s') if p # 1
      newline
      select output (object file)
   end

   ! MAIN CODE

   initialise
   time (input directives, "Directive input")
   time (stretch jumps, "Jump stretching")
   dump module header
   define psects
   spec init proc
   time (dump all code, "Code dumping")
   plug psects
   flush buffers
   dump eom
   report info

end

BEGIN
END

end of file