!   IMP77 compiler  first pass

   include  "Sysinc:com.inc"

!
!            On EMAS all shorts should be changed to integers.
!            Also, the INCLUDE facility will need to be modified.
!
!
         !###################################################
         !            Copyright: 1 January 1980             #
         !     Interactive Datasystems (Edinburgh) Ltd.     #
         !              32 Upper Gilmore Place              #
         !                Edinburgh EH3 9NJ                 #
         !               All Rights Reserved                #
         !###################################################

BEGIN 
   CONSTSTRING (4) version = "8.4"

   !configuration parameters

   CONSTINTEGER  max int      = ((-1)>>1)//10
   CONSTINTEGER  max dig      = (-1)>>1-maxint*10
   CONSTINTEGER  byte size    = 8;            !bits per byte
   CONSTINTEGER  max tag      = 800;          !max no. of tags
   CONSTINTEGER  max dict     = 6000;         !max extent of dictionary
   CONSTINTEGER  name bits    = 11
   CONSTINTEGER  max names    = 1<<namebits-1
   OWNINTEGER    spare names  = max names
   CONSTINTEGER  max grammar  = 1720
   CONSTINTEGER  lit max      = 50;           !max no. of constants/stat.
   CONSTINTEGER  rec size     = 520;          !size of analysis record
   CONSTINTEGER  dim limit    = 6;            !maximum array dimension

   !symbols

   CONSTINTEGER  ff     = 12;              !form feed
   CONSTINTEGER  marker = '^';             !marker for faults
   CONSTINTEGER  squote = '"';             !string quote
   CONSTINTEGER  cquote = '''';            !character quote

   !streams

   CONSTINTEGER  report = 0,  source = 1
   CONSTINTEGER  object = 1, listing = 2


   !types

   CONSTINTEGER  integer = 1
   CONSTINTEGER  real    = 2
   CONSTINTEGER  stringv = 3
   CONSTINTEGER  record  = 4

   !forms

   CONSTINTEGER  iform = integer<<4+1

   CONSTINTEGER  var = 91
   CONSTINTEGER  const   = 93
   CONSTINTEGER  swit    = 105
   CONSTINTEGER  comment = 22
   CONSTINTEGER  termin  = 20
   CONSTINTEGER  lab     = 3
   CONSTINTEGER  jump    = 54

   CONSTINTEGER  recfm = 4
   CONSTINTEGER  proc  = 7;                     !class for proc

   !phrase entries

   CONSTINTEGER  escdec   = 252
   CONSTINTEGER  escproc  = 253
   CONSTINTEGER  escarray = 254
   CONSTINTEGER  escrec   = 255

   RECORDFORMAT  arfm(SHORTINTEGER  class,sub,link,ptype,papp,pformat,x,pos);!imp77:
!emas:%RECORDFORMAT arfm(%INTEGER class,sub,link,ptype,papp,pformat,x,pos)

   RECORDFORMAT  tagfm(INTEGER  app, format, C 
                       SHORTINTEGER  flags, index, text, link)

   !flags

!      *===.===.===.===.===.====.====.====.===.======.======*
!      ! u ! c ! c ! p ! s ! a  ! o  ! pr ! s ! type ! form !
!      ! 1 ! 1 ! 1 ! 1 ! 1 ! 1  ! 1  ! 1  ! 1 !  3   !  4   !
!      *===^===^===^===^===^====^====^====^===^======^======*
!        u   c   c   p   s   a    o    p    s    t      f
!        s   l   o   a   u   n    w    r    p    y      o
!        e   o   n   r   b   a    n    o    e    p      r
!        d   s   s   a   n   m         t    c    e      m
!            e   t   m   a   e     
!            d       s   m
!                        e
!
!                             

   CONSTINTEGER  used bit   = b'1000000000000000',
                 closed     = b'0100000000000000',
                 const bit  = b'0010000000000000',
                 parameters = b'0001000000000000',
                 subname    = b'0000100000000000',
                 aname      = b'0000010000000000',
                 own bit    = b'0000001000000000',
                 prot       = b'0000000100000000',
                 spec       = b'0000000010000000'

   CONSTINTEGER  trans bit  = x'4000'
   CONSTINTEGER  error      = x'8000'

   CONSTINTEGER  manifest = 120, figurative = 130
   CONSTINTEGER  actions  = 180, phrasal    = 200

   CONSTBYTEINTEGERARRAY  amap(0:15) = C 
 89, 91, 92, 104, 94, const, swit, 100, 101, 102, 103, 106, 107, 108, 109, 89
!?   v   n   l    fm  const  swit  rp   fp   mp   pp   a    an   na   nan  ?

   CONSTBYTEINTEGERARRAY  atoms(0:15) = 89, 1, 1, 10,  9,  1, 10,  7,
                                         7, 7, 7,  4,  1,  4,  1, 89

   RECORD (arfm)ARRAY  ar(1:rec size)

   OWNINTEGER  class        = 0;             !class of atom wanted
   OWNINTEGER  x            = 0;             !usually last tag
   OWNINTEGER  atom1        = 0;             !atom class (major)
   OWNINTEGER  atom2        = 0;             !atom class (minor)
   OWNINTEGER  subatom      = 0;             !extra info about atom
   OWNINTEGER  type         = 0,
               app          = 0,
               format       = 0;             !atom info
   INTEGER  hash value
   OWNINTEGER  faulty       = 0;             !fault indicator
   OWNINTEGER  fault rate   = 0;             !fault rate count
   OWNINTEGER  lines        = 0;             !current line number
   OWNINTEGER  text line    = 0;             !starting line for string const
   OWNINTEGER  margin       = 0;             !statement start margin
   OWNINTEGER  error margin = 0,
               error sym    = 0,
               column       = 0
   OWNINTEGER  stats        = 0;             !statements compiled
   OWNINTEGER  mon pos      = 0;             !flag for diagnose
   OWNINTEGER  sym          = nl;            !current input symbol
   OWNINTEGER  symtype      = 0;             !type of current symbol
   OWNINTEGER  quote        = 0;             !>0 strings, <0 chars
   owninteger  end mark     = 0;             !%end flag
   OWNINTEGER  cont         = ' ',
               csym         = ' ';           !listing continuation marker
   OWNINTEGER  decl         = 0;             !current declarator flags
   OWNINTEGER  dim          = 0;             !arrayname dimension
   OWNINTEGER  spec given   = 0

   OWNINTEGER  escape class = 0;             !when and where to escape
   OWNINTEGER  protection   = 0,
               atom flags   = 0
   OWNINTEGER  otype        = 0;             !current 'own' type
   OWNINTEGER  reals ln     = 1;             ! =4 for %REALSLONG
   OWNINTEGER  last1        = 0;             !previous atom class
   OWNINTEGER  gen type     = 0
   OWNINTEGER  ptype        = 0;             !current phrase type
   OWNINTEGER  papp         = 0;             !current phrase parameters
   OWNINTEGER  pformat      = 0;             !current phrase format
   OWNINTEGER  force        = 0;             !force next ptype
   OWNINTEGER  g            = 0,
               gg           = 0,
               map gg       = 0;             !grammar entries
   OWNINTEGER  fdef         = 0;             !current format definition
   OWNINTEGER  this         = -1;            !current recordformat tag
   OWNINTEGER  nmin         = 0;             !analysis record atom pointer
   OWNINTEGER  nmax         = 0;             !analysis record phrase pointer
   OWNINTEGER  rbase        = 0;             !record format definition base
   OWNINTEGER  stbase       = 0;             !constant work area base
   OWNINTEGER  gmin         = max grammar;   !upper bound on grammar
   OWNINTEGER  dmax         = 1
   OWNINTEGER  tmin         = max tag;       !upper bound on tags
   OWNINTEGER  ss           = 0;             !source statement entry
   STRING (63) include file
   OWNINTEGER  include list = 0,
               include level= 0
   OWNINTEGER  include      = 0;                 !=0 unused, #0 being used
   OWNINTEGER  perm         = 1;             !1 = compiling perm, 0 = program
   OWNINTEGER  progmode     = 0;             !-1 = file, 1 = begin/eop
   OWNINTEGER  sstype       = 0;             !-1:exec stat
                                             ! 0: declaration
                                             ! 1: block in
                                             ! 2: block out
   OWNINTEGER  spec mode    = 0;             !>=0: definition
                                             ! -1: proc spec
                                             ! -2: recordformat
   OWNINTEGER  ocount       = -1;            !own constants wanted
   OWNINTEGER  limit        = 0;             !lookup limit
   OWNINTEGER  copy         = 0;             !duplicate name flag
   OWNINTEGER  order        = 0;             !out of sequence flag
   OWNINTEGER  for warn     = 0;             !non-local flag
   OWNINTEGER  dubious      = 0;             !flag for dubious statements
   OWNINTEGER  dp           = 1
   OWNINTEGER  pos1         = 0,
               pos2         = 0;             !error position
   OWNINTEGER  pos          = 0;             !input line index
   OWNINTEGER  dimension    = 0;             !current array dimension
   OWNINTEGER  local        = 0;             !search limit for locals
   OWNINTEGER  fm base      = 0;             !entry for format decls
   OWNINTEGER  search base  = 0;             !entry for record_names
   OWNINTEGER  format list  = 0;             !size of current format list
   INTEGER  recid
   OWNBYTEINTEGERARRAY  char(0:133) = nl(134);  !input line
   INTEGERARRAY  lit pool(0:lit max)
   OWNINTEGER  lit          = 0;             !current literal (integer)
   OWNINTEGER  lp           = 0;             !literals pointer
   OWNINTEGER  block x      = 0;             !block tag
   OWNINTEGER  list         = 1;             !<= to enable
   OWNINTEGER  control      = 0
   OWNINTEGER  diag         = 0;             !diagnose flags
   SHORTINTEGERARRAY  hash(0:max names)
   RECORD (tagfm)ARRAY  tag(0:max tag)
   SHORTINTEGERARRAY  dict(1:max dict)
   BYTEINTEGERARRAY  buff(1:512)
   OWNINTEGER  bp           = 0

!*** start of generated tables ***
   include  "tables.imp"
!***  end  of generated tables ***

ROUTINE  flush buffer
   INTEGER  j
   IF  faulty = 0 START 
      select output(object)
      FOR  j = 1, 1, bp CYCLE 
         printsymbol(buff(j))
      REPEAT 
      select output(listing)
   FINISH 
   bp = 0
END 
ROUTINE  print ident(INTEGER  p, mode)
   INTEGER  j, ad
   p = tag(p)_text
   IF  p = 0 START 
      bp = bp+1 AND  buff(bp) = '?' if  Mode # 0
      RETURN 
   FINISH 
   ad = addr(dict(p+1))
   IF  mode = 0 THEN  printstring(string(ad)) ELSE  START 
      FOR  j = ad+1, 1, ad+byteinteger(ad) CYCLE 
         bp = bp+1
         buff(bp) = byteinteger(j)
      REPEAT 
   FINISH 
END 
ROUTINE  abandon(INTEGER  n)
   SWITCH  reason(0:9)
   INTEGER  stream
   stream = listing
   CYCLE 
      newline IF  sym # nl
      printsymbol('*');  write(lines,4);  space
      ->reason(n)
reason(0):printstring("compiler error!");          ->more
reason(1):printstring("switch vector too large");  ->more
reason(2):printstring("too many names");           ->more
reason(3):printstring("program too complex");      ->more
reason(4):printstring("feature not implemented");  ->more
reason(5):printstring("input ended: ")
          IF  quote # 0 START 
            IF  quote < 0 THEN  printsymbol(cquote) C 
                          ELSE  printsymbol(squote)
          ELSE 
             printstring("%endof")
             IF  progmode >= 0 THEN  printstring("program") C 
                               ELSE  printstring("file")
          FINISH 
          printstring(" missing?");                ->more
reason(6):printstring("too many faults!");         ->more
reason(7):printstring("string constant too long"); ->more
reason(8):printstring("dictionary full"); -> more
reason(9):printstring("Included file ".include file." does not exist")
more: newline
      printstring("***  compilation abandoned ***");  newline
      EXIT  IF  stream = report
      close output
      stream = report
      select output(report)
   REPEAT 
   SIGNAL  15,15 IF  diag&4096 # 0
   STOP 
END 
ROUTINE  op(INTEGER  code, param)
      buff(bp+1) <- code
      buff(bp+2) <- param>>8
      buff(bp+3) <- param
      bp = bp+3
END 
ROUTINE  set const(INTEGER  m)
      buff(bp+1) <- 'N'
      buff(bp+5) <- m;  m = m>>8
      buff(bp+4) <- m;  m = m>>8
      buff(bp+3) <- m;  m = m>>8
      buff(bp+2) <- m
      bp = bp+5
END 



ROUTINE  compile block(INTEGER  level, block tag, dmin, tmax, id)

   INTEGERFNSPEC  gapp
   ROUTINESPEC  delete names(INTEGER  quiet)
   ROUTINESPEC  analyse
   ROUTINESPEC  compile

   INTEGER  open;    open       = closed;      !zero if can return from proc
   INTEGER  dbase;   dbase      = dmax;        !dictionary base
   INTEGER  tbase;   tbase      = tmax;        !tag base
   INTEGER  tstart;  tstart     = tmax
   INTEGER  label;   label      = 4;           !first internal label
   INTEGER  access;  access     = 1;           !non-zero if accessible
   INTEGER  inhibit; inhibit    = 0;           !non-zero inhibits declaratons

   SHORTINTEGERNAME  bflags; bflags      == tag(block tag)_flags
   INTEGER  block type;      block type   = bflags>>4&7
   INTEGER  block form;      block form   = bflags&15
   INTEGER  block fm;        block fm     = tag(block tag)_format
   INTEGER  block otype;     block otype  = otype
   INTEGERNAME  block app;   block app   == tag(block tag)_app

   INTEGER  l, new app

ROUTINE  fault(INTEGER  n)

    ! -5 : -1  - warnings
    !  1 : 22  - errors

    SWITCH  fm(-5:22)
    INTEGER  st

    ROUTINE  print ss
       INTEGER  s, p
       RETURN  IF  pos = 0
       space
       p = 1
       CYCLE 
          printsymbol(marker) IF  p = pos1
          EXIT  IF  p = pos
          s = char(p);  p = p+1
          EXIT  IF  s = nl OR  (s='%' AND  p = pos)
          IF  s < ' ' START ;         !beware of tabs
             IF  s = ff THEN  s = nl ELSE  s = ' '
          FINISH 
          printsymbol(s)
       REPEAT 
       pos = 0 IF  list <= 0
    END 

    pos1 = pos2 IF  pos2 > pos1
    newline IF  sym # nl
    st = report
    st = listing IF  n = -3;              !don't report unused on the console
    cycle 
       SELECT OUTPUT(st)
       if  n < 0 then  printsymbol('?') and  pos1 = 0 else  printsymbol('*')
       if  st # report start 
          if  list <= 0 and  pos1 # 0 start 
             spaces(pos1+margin);  PRINTSTRING("      ! ")
          finish 
       finish  else  start 
          PRINTSTRING(include file) if  include # 0
          write(lines, 4);  printsymbol(csym);  space
       finish 
       ->fm(n) if  -5 <= n <= 22
       PRINTSTRING("fault");  write(n, 2);              ->ps

fm(-5):PRINTSTRING("Dubious statement");  dubious = 0;  ->psd
fm(-4):PRINTSTRING("Non-local")
       pos1 = for warn;  for warn = 0;                  ->ps
fm(-3):print ident(x, 0);  PRINTSTRING(" unused");      ->nps
fm(-2):PRINTSTRING("""}""");                            ->miss
fm(-1):PRINTSTRING("access");                           ->psd

fm(0): PRINTSTRING("form");                             ->ps
fm(1): PRINTSTRING("atom");                             ->ps
fm(2): PRINTSTRING("not declared");                     ->ps
fm(3): PRINTSTRING("too complex");                      ->ps
fm(4): PRINTSTRING("duplicate ");  Print Ident(x, 0);   ->ps
fm(5): PRINTSTRING("type");                             ->ps
fm(6): PRINTSTRING("match");                            ->psd
fm(7): PRINTSTRING("context");                          ->psd
fm(21):PRINTSTRING("context ");  print ident(this, 0);  ->ps
fm(8): PRINTSTRING("%cycle");                           ->miss
fm(9): PRINTSTRING("%start");                           ->miss
fm(10):PRINTSTRING("size");  WRITE(lit, 1) if  pos1 = 0;->ps
fm(11):PRINTSTRING("bounds")
       WRITE(ocount, 1) unless  ocount < 0;             ->ps
fm(12):PRINTSTRING("index");                            ->ps
fm(13):PRINTSTRING("order");                            ->psd
fm(14):PRINTSTRING("not a location");                   ->ps
fm(15):PRINTSTRING("%begin");                           ->miss
fm(16):PRINTSTRING("%end");                             ->miss
fm(17):PRINTSTRING("%repeat");                          ->miss
fm(18):PRINTSTRING("%finish");                          ->miss
fm(19):PRINTSTRING("result");                           ->miss
fm(22):PRINTSTRING("format");                           ->ps
fm(20):printsymbol('"');  print ident(x, 0);  printsymbol('"')
miss:  PRINTSTRING(" missing");                         ->nps
psd:   pos1 = 0
ps:    print ss
nps:   NEWLINE
       exit  if  st = listing
       st = listing
    repeat 
    if  n >= 0 start 
       signal  15,15 if  diag&4096 # 0
       if  n # 13 start ;           !order is fairly safe
          ocount = -1
          gg = 0
          copy = 0;  quote = 0
          search base = 0;  escape class = 0
          gg = 0
       finish 
       faulty = faulty+1
   
       !check that there haven't been too many faults
   
       fault rate = fault rate+3;  abandon(6) IF  fault rate > 30
       fault rate = 3 IF  fault rate <= 0
    FINISH 
    tbase = tstart
    IF  list <= 0 AND  sym # nl START 
       error margin = column
       error sym = sym;  sym = nl
    FINISH 
END 

   dmin = dmin-1;  dict(dmin) = -1;            !end marker for starts & cycles
   abandon(2) IF  dmax = dmin

   IF  list > 0 AND  level > 0 START 
      write(lines, 5);  spaces(level*3-1)
      IF  block tag = 0 START 
         printstring("Begin")
      FINISH  ELSE  START 
         printstring("Procedure ");  print ident(block tag, 0)
      FINISH 
      newline
   FINISH 

   !deal with procedure definition (parameters)

   IF  block tag # 0 START ;                   !proc
      analyse;  compile IF  ss # 0

      IF  block otype # 0 START ;              !external-ish
         IF  bflags&spec = 0 START ;           !definition
            IF  progmode <= 0 AND  level = 1 THEN  progmode = -1 C 
                                             ELSE  fault(7)
         FINISH 
      FINISH 

      new app = gapp;                          !generate app grammar
      IF  spec given # 0 START ;               !definition after spec
         fault(6) IF  new app # block app;     !different from spec
      FINISH 
      block app = new app;                     !use the latest

      IF  level < 0 START ;                    !not procedure definition
         delete names(0)
         RETURN 
      FINISH 
   FINISH  ELSE  START 
      open = 0;                                !can return from a block?
   FINISH 

   CYCLE 
      analyse
      CONTINUE  IF  ss = 0
      compile
      fault(-5) IF  dubious # 0
      flush buffer IF  bp >= 128
      IF  sstype > 0 START ;                 !block in or out
         EXIT  IF  sstype = 2;               !out
         compile block(spec mode, block x, dmin, tmax, id)
         EXIT  IF  ss < 0;                   !endofprogram
      FINISH 
   REPEAT 
   IF  list > 0 AND  level > 0 START 
      write(lines, 5);  spaces(level*3-1)
      printstring("End")
      newline
   FINISH 
   delete names(0)
   RETURN 

   INTEGERFN  gapp;                            !generate app grammar (backwards)
      CONSTINTEGER  comma = 140;               !psep
      ROUTINESPEC  set cell(INTEGER  g, tt)
      ROUTINESPEC  class(RECORD (tagfm)NAME  v)
      RECORD (tagfm)NAME  v
      INTEGER  p, link, tp, c, ap, t

      RESULT  = 0 IF  tmax = local;            !no app needed

      p = gmax1;  link = 0;  t = tmax

      CYCLE 
         v == tag(t);  t = t-1
         class(v);                             !deduce class from tag
         IF  c < 0 START ;                     !insert %PARAM
            c = -c
            set cell(196, tp)
            tp = -1
         FINISH 
         set cell(c, tp)
         EXIT  IF  t = local;                  !end of parameters
         set cell(comma, -1);                  !add the separating comma
      REPEAT 
      abandon(3) IF  gmax > gmin

      RESULT  = link

      ROUTINE  set cell(INTEGER  g, tt)

         !add the cell to the grammar, combining common tails

         WHILE  p # gmax CYCLE 
            p = p+1
            IF  glink(p) = link AND  gram(p) = g START 
               IF  tt < 0 OR  (gram(p+1) = tt AND  glink(p+1)=ap) START 
                  link = p;                    !already there
                  RETURN 
               FINISH 
            FINISH 
         REPEAT 

         !add a new cell

         gmax = gmax+1
         gram(gmax) = g
         glink(gmax) = link
         link = gmax

         IF  tt >= 0 START ;             ! set type cell
            gmax = gmax+1
            gram(gmax) = tt
            glink(gmax) = ap
         FINISH 

         p = gmax
      END 

      ROUTINE  class(RECORD (tagfm)NAME  v)
         CONSTINTEGER  err    = 89
         CONSTINTEGER  rtp    = 100
         CONSTINTEGER  fnp    = 101
         CONSTINTEGER  mapp   = 102
         CONSTINTEGER  predp  = 103
         CONSTINTEGERARRAY  class map(0:15) = C 
         err,1764, 247, err(4), -rtp, -fnp, -mapp, -predp, err, 214,
         err, 229, err
         INTEGER  tags, type, form
         ap = 0
         tags = v_flags
         type = tags>>4&7;  form = tags&15
         tp = v_format<<3!type
         c = class map(form)
         c = 208 AND  tp = 0 IF  type = 0 AND  form = 2;  !%NAME
         ap = v_app IF  tags&parameters # 0
      END 
   END 

ROUTINE  delete names(INTEGER  quiet)
   INTEGER  flags
   RECORD (tagfm)NAME  tx
   WHILE  tmax > tbase CYCLE 
      x = tmax;  tmax = tmax-1
      tx == tag(x)
      flags = tx_flags
      fault(20) IF  flags&spec # 0 and  flags&own bit = 0
               {spec with no definition & not external}
      IF  flags&used bit = 0 AND  level >= 0 AND  list <= 0 START 
         fault(-3) IF  quiet = 0;          !unused
      FINISH 
      dict(tx_text) = tx_link
   REPEAT 
END 

ROUTINE  analyse

   CONSTINTEGER  order bits = x'3000', order bit = x'1000'
   CONSTINTEGER  escape     = x'1000'
   INTEGER  strp, mark, flags, prot err, k, s, c
   OWNINTEGER  key = 0
   SHORTINTEGER  node
   SHORTINTEGERNAME  z
   RECORD (arfm)NAME  arp
!emas:   %INTEGER node
!emas:   %INTEGERNAME z
   SWITCH  act(actions:phrasal), paction(0:15)

   ROUTINE  trace analysis
      !diagnostic trace routine (diagnose&1 # 0)
      INTEGER  a
      ROUTINE  show(INTEGER  a)
         IF  0 < a < 130 START 
            space
            printstring(text(a))
         FINISH  ELSE  write(a, 3)
      END 
      OWNINTEGER  la1=0, la2=0, lsa=0, lt=0
      newline IF  mon pos # pos AND  sym # nl
      mon pos = pos
      write(g, 3)
      space
      printstring(text(class))
      printsymbol('"') IF  gg&trans bit # 0
      a = gg>>8&15
      IF  a # 0 START 
         printsymbol('{')
         write(a, 0)
         printsymbol('}')
      FINISH 
      IF  atom1 # la1 OR  atom2 # la2 OR  lsa # subatom C 
                      OR  lt # type START 
         printstring(" [")
         la1 = atom1
         show(la1)
         la2 = atom2
         show(la2)
         lsa = subatom
         write(lsa, 3)
         lt = type
         write(lt, 5)
         printsymbol(']')
      FINISH 
      newline
   END 

ROUTINE  get sym
   readsymbol(sym)
   pos = pos+1 IF  pos # 133
   char(pos) = sym
   printsymbol(sym) IF  list <= 0
   column = column+1
END 
ROUTINE  read sym
   owninteger  Last = 0
CONSTBYTEINTEGERARRAY  mapped(0:127) = C 
   0,  0,  0,  0,   0,  0,  0,  0,    0,  0, nl,  0,  3 ,  0,  0,  0,
   0,  0,  0,  0,   0,  0,  0,  0,    0,  0,  0,  0,   0,  0,  0,  0,
  0 ,'!','"','#', '$', 1 ,'&', 39,  '(',')','*','+', ',','-','.','/',
 '0','1','2','3', '4','5','6','7',  '8','9',':',';', '<','=','>','?',
 '@','A','B','C', 'D','E','F','G',  'H','I','J','K', 'L','M','N','O',
 'P','Q','R','S', 'T','U','V','W',  'X','Y','Z','[', '¬',']','^','_',
 '`','A','B','C', 'D','E','F','G',  'H','I','J','K', 'L','M','N','O',
 'P','Q','R','S', 'T','U','V','W',  'X','Y','Z', 2 , '|','}','~',  0

!!   0 = space
!!   1 = %
!!   2 = {
!!   3 = ff
!!   other values represent themselves

   IF  sym = nl START 
s1:   lines = lines+1
      printsymbol(end mark) if  end mark # 0
s11:  pos = 0;  pos1 = 0;  pos2 = 0;  margin = 0;  column = 0
      Last = 0
      end mark = 0
      IF  list <= 0 START 
         IF  include # 0 START 
            printstring(" &");  write(lines, -4)
         FINISH  ELSE   write(lines, 5)
         csym = cont;  printsymbol(csym)
         space
         IF  error margin # 0 START 
            lines = lines-1
            spaces(error margin)
            error margin = 0
            IF  error sym # 0 START 
               printsymbol(error sym)
               pos = 1;  char(1) = error sym
               sym = error sym;  error sym = 0
               ->s5
            FINISH 
         FINISH 
      FINISH 
s2:   symtype = 1
   FINISH 
s3:readsymbol(sym)
   pos = pos+1 IF  pos # 133
   char(pos) = sym
   printsymbol(sym) IF  list <= 0
   column = column+1
s5:IF  sym # nl START 
      Last = Sym
      RETURN  IF  quote # 0;                     !dont alter strings
      sym = mapped(sym&127)
      IF  sym <= 3 START ;                       !special symbol
         ->s2 IF  sym = 0;                       !space (or dubious control)
         symtype = 2 AND  ->s3 IF  sym = 1;      !%
         cont = '+' AND  ->s11 IF  sym = 3;      !ff
         !must be {
         CYCLE 
            get sym
            ->s3 IF  sym = '}'
            ->s4 IF  sym = nl
         REPEAT 
      FINISH 
      key = kdict(sym)
      IF  key&3 = 0 AND  symtype = 2 START ;            !keyword
         IF  sym = 'C' AND  nextsymbol = nl START ;     !%C...
            getsym;  cont = '+';  ->s1
         FINISH 
      ELSE 
         symtype = key&3-2
      FINISH 
      RETURN 
   FINISH 
s4:symtype = quote
   ->S1 if  last = 0 and  Quote = 0
   Cont = '+'
END 

INTEGERFN  format selected
   format list = tag(format)_app;      !number of names
   IF  format list < 0 START ;         !forward ref
      atom1 = error+22
      RESULT  = 0
   FINISH 
   IF  sym = '_' START 
      escape class = esc rec
      search base = tag(format)_format
   FINISH 
   RESULT  = 1
END 

ROUTINE  code atom(INTEGER  target)
   INTEGER  dbase, da
   INTEGER  base, n, mul, pend quote
   INTEGER  j,k,l, pt

   ROUTINE  lookup(INTEGER  d)
      CONSTINTEGER  magic = 6700421
      INTEGER  new name, vid, k1, k2, form
      RECORD (tagfm)NAME  t
!emas:      %LONGINTEGER k0
      INTEGER  new

      !first locate the text of the name

      new = addr(dict(dmax+1))

            !******** Machine code to inhibit overflow test ********

            *LI_1,magic
            * M_0,hash value
            *ST_1,K2

            {K2 = hash value*magic}

            !*******************************************************

      k2 = k2>>(32-2*name bits)!1
!emas:   k0 = magic
!emas:   k1 = (k0*hash value)&X'7FFFFFFF'
!emas:   k2 = k1>>(32-2*name bits)!1
      k1 = k2>>name bits;                      !giving name bits
      CYCLE 
         newname = hash(k1)
         EXIT  IF  newname = 0;                !not in
         ->in IF  string(addr(dict(newname+1))) = string(new)
         k1 = (k1+k2)&max names
      REPEAT 

      ! not found

      spare names = spare names-1
      abandon(2) IF  spare names <= 0
      hash(k1) = dmax;                               !put it in
      dict(dmax) = -1
      newname = dmax;  dmax = dp;  ->not in

in:   search base = rbase IF  this >= 0 AND  d # 0;  !record elem defn
      IF  search base # 0 START ;                    !record subname
         new = -1
         x = search base
         CYCLE 
            ->not in IF  x < format list
            EXIT  IF  tag(x)_text = new name
            x = x-1
         REPEAT 
      FINISH  ELSE  START ;                   !hash in for normal names
         x = dict(newname)
         ->not in IF  x <= limit;             !wrong level
      FINISH 

      subatom = x;                            !name found, extract info
      t == tag(x)
      atom flags = t_flags
      format = t_format;  app = t_app
      protection = atom flags&prot
      type = atom flags>>4&7;  atom1 = amap(atom flags&15)

      IF  diag&8 # 0 START 
         printstring("lookup:")
         write(atom1, 3)
         write(type, 1)
         write(app, 3)
         write(format, 5)
         write(atom flags, 3)
         newline
      FINISH 

      IF  d = 0 START ;                             !old name wanted
         t_flags <- t_flags!used bit
         search base = 0

         IF  atom flags&subname # 0 AND  format # 0 START ; !a record
            RETURN  IF  format selected = 0
         FINISH 

         IF  atom flags&parameters # 0 START ;      !proc or array

            IF  app = 0 START ;                     !no parameters needed
               atom2 = atom1
               atom1 = atom1-4
               IF  97 <= atom1 <= 98 START 
                  map gg = atom1;  atom1 = var
               FINISH 
            FINISH  ELSE  START 
               IF  sym = '(' START 
                  search base = 0;                  !ignore format for now
                  IF  atom1 >= 106 START ;          !arrays
                     app = phrase(app+200)
                     escape class = esc array
                     atom1 = (atom1-106)>>1+91;     !a,an->v  na,nan->n
                  FINISH  ELSE  START ;             !procedures
                     escape class = esc proc
                     atom1 = atom1-4
                  FINISH 
                  phrase(200) = app
               FINISH 
            FINISH 
            pos2 = pos;  return 
         FINISH 

         !deal with constintegers etc

         IF  atom flags&const bit # 0 AND  atom1 = var START 
               map gg = const;  atom2 = const
               subatom = -subatom IF  type = integer
         FINISH 
         RETURN 

      FINISH 
                                                 !new name wanted
      ->not in IF  tbase # tstart;               !don't fault proc parm-parm
      IF  d = lab+spec+used bit START 
         t_flags = t_flags!used bit
         RETURN 
      FINISH 
      IF  atom flags&spec # 0 START ;            !a spec has been given
         IF  d = lab START ;                     !define label
            t_flags <- t_Flags-Spec
            RETURN 
         FINISH 
         IF  7 <= decl&15 <= 10 AND  decl&spec = 0 START 

            !procedure definition after spec

            IF  (decl!!atom flags)&b'1111111' = 0 START ;  !correct type?
               t_flags = t_flags-spec
               spec given = 1
               RETURN 
            FINISH 

            !note that an external procedure must be speced as a
            !non-external procedure.

         FINISH 
         IF  decl&15 = recfm START ;              !recordformat
            t_flags = record<<4+recfm
            t_format = fdef
            RETURN 
         FINISH 
      FINISH 
      RETURN  IF  last1 = jump AND  atom1 = swit
      copy = x IF  copy = 0

notin:app = 0;  vid = 0
      atom1 = error+2

      return  if  d = 0;                         !old name wanted
      type = d>>4&7;  form = d&15;  atom1 = amap(form)

      IF  this < 0 START ;                       !normal scope
         new = newname
         tmax = tmax+1;  x = tmax
      FINISH  ELSE  START ;                      !recordformat scope
         new = -1
         recid = recid-1;  vid = recid
         tmin = tmin-1;  x = tmin
         format list = tmin
      FINISH 

      IF  11 <= form <= 14 START ;               !arrays
         dim = 1 IF  dim = 0;                    !set dim for owns
         app = dim
      FINISH 

      d = d!used bit IF  (otype > 2 AND  d&spec = 0) OR  perm # 0 OR 
                         Level = Include Level

      !external definitions need not be used in the file in which
      !they are defined, so inhibit a useless unused warning.

      t == tag(x)
      IF  form = lab START 
         id = id+1;  vid = id
      FINISH 
      t_index = vid
      t_text   = new name
      t_flags <- d
      t_app    = app
      t_format = fdef;  format = fdef
      subatom = x

      IF  new >= 0 START ;                             !insert into hash table
         t_link = dict(new);  dict(new) = x
         IF  gmin = max grammar START ;                !proc param params
            tmin = tmin-1;  subatom = tmin
            tag(tmin) = t
         FINISH 
      FINISH 
      abandon(3) IF  tmax >= tmin
   END 



top:  pos1 = pos
      subatom = 0;  pend quote = 0;  atom flags = 0

      !app and format must be left for assigning to papp & pformat

      ->name IF  symtype = -2;                   !letter
      ->number IF  symtype < 0;                  !digit
      IF  symtype = 0 START 
         atom1 = termin;  atom2 = 0
         RETURN 
      FINISH 
      IF  symtype # 2 START ;                    !catch keywords here
         ->text IF  quote # 0;                   !completion of text
         ->strings IF  sym = squote;             !start of string
         ->symbols IF  sym = cquote;             !start of symbol
         ->number IF  sym = '.' AND  '0' <= nextsymbol <= '9'
      FINISH 

                                                 !locate atom in fixed dict
      k = key>>2;  read sym
      CYCLE 
         j = kdict(k)
         EXIT  IF  j&x'4000' # 0
         IF  j&127 # sym OR  symtype < 0 START 
            ->err UNLESS  j < 0
            k = k+1
         FINISH  ELSE  START 
            l = j>>7&127;  read sym
            IF  j > 0 START 
               IF  l # 0 START 
                  ->err IF  l # sym OR  symtype < 0
                  read sym
               FINISH 
               l = 1
            FINISH 
            k = k+l
         FINISH 
      REPEAT 
      atom1 = j&127
      IF  atom1 = 0 START ;                      !comma
         atom1 = 19;  subatom = 19;  atom2 = 0
         IF  sym = nl START 
            RETURN  IF  ocount >= 0

            !special action needs to be taken with <comma nl> as
            !const array lists can be enormous

            read sym
         FINISH 
         RETURN 
      FINISH 
      atom2 = j>>7&127
      subatom = kdict(k+1)&x'3fff'
      !!!!!cont = ' '
      RETURN 

      !report an error. adjust the error marker (pos1) to point
      !to the faulty character in an atom, but care needs to be taken
      !to prevent misleading reports in cases like ...?????

err:  atom1 = error+1;  atom2 = 0
      pos1 = pos IF  pos-pos1 > 2
      RETURN 

        !take care with strings and symbol constants.
        !make sure the constant is valid here before sucking it in
        !(and potentially loosing many lines)

symbols:atom1 = var;  atom2 = const;  type = integer
        map gg = const;  protection = prot
        subatom = lp;  abandon(3) IF  lp >= lit max
        quote = ¬pend quote
        RETURN 

      !an integer constant is acceptable so get it in and
      !get the next atom

chars:n = 0;  cont = cquote
      CYCLE 
         read sym
         IF  sym = cquote START 
            EXIT  IF  nextsymbol # cquote
            read sym
         FINISH 
         IF  n&(¬((-1)>>byte size)) # 0 START ; ! overflow
            pos1 = pos;  atom1 = error+10;  RETURN 
         FINISH 
         ->err IF  quote = 0
         n = n<<byte size+sym
         quote = quote+1
      REPEAT 
      quote = 0;  cont = ' '
      readsym IF  sym # nl
      lit pool(lp) = n;  lp = lp+1
      ->top

        !sniff the grammar before getting the string

strings:atom1 = var;  atom2 = const;  type = stringv
        subatom = (strp-stbase)!x'4000'
        map gg = const;  protection = prot
        quote = subatom
        text line = lines;                         !in case of errors
        RETURN 

      !a string constant is ok here, so pull it in and get
      !the next atom

text: ->chars IF  quote < 0;                       !character consts
      l = strp; n = strp
      j = addr(glink(gmin-1));                     !absolute limit
      k = l+256;                                   !string length limit
      k = j IF  j < k;                             !choose lower

      CYCLE 
         cont = squote;  quote = 1
         CYCLE 
            read sym
            IF  sym = squote START ;               !terminator?
               EXIT  IF  nextsymbol # squote;      !yes ->
               read sym;                           ! skip quote
            FINISH 
            l = l+1;  byteinteger(l) = sym
            lines = text line AND  abandon(7) IF  l >= k; !too many chars
         REPEAT 
         byteinteger(n) = l-n;                            !plug in length
   
         strp = l+1;                                      !ready for next string
         quote = 0;  cont = ' ';  read sym
         code atom(target)
         RETURN  UNLESS  atom1 = 48 AND  sym = squote;    !fold "???"."+++"
      REPEAT 

      ROUTINE  get(INTEGER  limit)
         INTEGER  s, shift
         shift = 0
         IF  base # 10 START 
            IF  base = 16 START 
               shift = 4
            FINISH  ELSE  START 
               IF  base = 8 START 
                  shift = 3
               FINISH  ELSE  START 
                  IF  base = 2 START 
                     shift = 1
                  FINISH 
               FINISH 
            FINISH 
         FINISH 
         n = 0
         CYCLE 
            IF  symtype = -1 START ;            !digit
               s = sym-'0'
            FINISH  ELSE  START 
               IF  symtype < 0 START ;          !letter
                  s = sym-'A'+10
               FINISH  ELSE  START 
                  RETURN 
               FINISH 
            FINISH 
            RETURN  IF  s >= limit
            pt = pt+1;  byteinteger(pt) = sym
            IF  base = 10 START ;            !check overflow
               IF  n >= max int AND  (s > max dig OR  n > max int) START 

                  !too big for an integer,
                  !so call it a real

                  base = 0;  type = real;  n = 0
               FINISH 
            FINISH 
            IF  shift = 0 START 
               n = n*base+s
            FINISH  ELSE  START 
               n = n<<shift+s
            FINISH 
            read sym
         REPEAT 
      END 

number:base = 10
bxk:   atom1 = var;  atom2 = const;  type = integer;  subatom = lp
       map gg = const;  protection = prot
       abandon(3) IF  lp >= lit max
       pt = strp;  mul = 0
       CYCLE 
          get(base)
          EXIT  UNLESS  sym = '_' AND  base # 0 AND  pend quote = 0;    !change of base
          pt = pt+1;  byteinteger(pt) = '_'
          read sym
          base = n
       REPEAT 

       IF  pend quote # 0 START 
          ->err IF  sym # cquote
          readsym
       FINISH 
       IF  sym = '.' START ;                        !a real constant
          pt = pt+1;  byteinteger(pt) = '.'
          read sym
          type = real;  n = base;  base = 0;  get(n)
       FINISH 

       IF  sym = '@' START ;                        !an exponent
          pt = pt+1;  byteinteger(pt) = '@';  k = pt
          readsym
          type = integer;  base = 10
          IF  sym = '-' START 
             read sym;  get(10);  n = -n
          FINISH  ELSE  START 
             get(10)
          FINISH 
          pt = k+1;  byteinteger(pt) = lp;  litpool(lp) = n;  lp = lp+1
          atom1 = error+10 IF  base = 0
          type = real;                              !exponents force the type
       FINISH 

       IF  type = real START 
          byteinteger(strp) = pt-strp
          subatom = (strp-stbase)!x'2000';  strp = pt+1
       FINISH  ELSE  START 
          litpool(lp) = n
          lp = lp+1
       FINISH 
       RETURN 

name: atom1 = 0 AND  RETURN  IF  27 <= target <= 41
      hash value = 0

      !*****************************
      !*machine dependent for speed*
      !*****************************

      dp = dmax+1
      da = addr(dict(dp));  dbase = da
      CYCLE 
         hash value = hash value+(hash value+sym);        !is this good enough?
         da = da+1;  byteinteger(da) = sym
         read sym
         EXIT  IF  symtype >= 0
      REPEAT 
      IF  sym = cquote START 
         pend quote = 100
         ->symbols IF  hash value = 'M'
         read sym
         IF  hash value = 'X' THEN  base = 16 AND  ->bxk
         IF  hash value = 'K' C 
         OR  hash value = 'O' THEN  base = 8 AND  ->bxk
         IF  hash value = 'B' THEN  base = 2 AND  ->bxk
         ->err
      FINISH 
      n = da-dbase
      byteinteger(dbase) = n
      dp = dp+(n+2)>>1
      abandon(8) IF  dp >= dmin

      atom2 = 90;                                    !ident
      IF  last1 = 0 AND  sym = ':' START ;           !label
         limit = local;  lookup(lab);  RETURN 
      FINISH 
      IF  last1 = jump START ;                       !->label
         limit = local;  lookup(lab+spec+used bit);  RETURN 
      FINISH 
      IF  decl # 0 AND  target = 90 START ;          !identifier
         search base = fm base
         limit = local;  lookup(decl)
         search base = 0
      FINISH  ELSE  START 
         limit = 0;  lookup(0)
      FINISH 
   END 

   INTEGERFN  parsed machine code
      !   *opcode_??????????
      routine  octal(integer  n)
         integer  m
         m = n>>3
         octal(m) if  m # 0
         bp = bp+1;  buff(bp) = n&7+'0'
      end 
      atom1 = error AND  RESULT =0 UNLESS  symtype = -2;  !starts with letter
      flush buffer IF  bp >= 128
      bp=bp+1 AND  buff(bp)='w'
      CYCLE 
         bp=bp+1 AND  buff(bp)=sym
         read sym
         EXIT  IF  symtype >= 0;                !pull in letters and digits
      REPEAT 
      bp=bp+1 AND  buff(bp)='_'
      IF  symtype # 0 START ;                   !not terminator
         atom1 = error AND  result =0 UNLESS  sym = '_'
         read sym
         WHILE  symtype # 0 CYCLE 
            IF  symtype < 0 START ;             !complex
               code atom(0);  result =0 IF  atom1&error # 0
               IF  atom2 = const AND  type = integer START 
                  IF  subatom < 0 THEN  octal(tag(-subatom)_format) C 
                                  ELSE  octal(litpool(subatom))
               FINISH  ELSE  START 
                  IF  91 <= atom1 <= 109 START 
                     if  atom1 = 104 {label} and 
                         Tag(Subatom)_Flags&Closed = 0 start 
                        This = Subatom;  Atom1 = Error+21
                        result  = 0
                     finish 
                     op(' ', tag(subatom)_index)
                  FINISH  ELSE  START 
                     atom1 = error;  result =0
                  FINISH 
               FINISH 
            FINISH  ELSE  START 
               bp=bp+1 AND  buff(bp)=sym;  read sym
            FINISH 
         REPEAT 
      FINISH 
      bp=bp+1 AND  buff(bp)=';'
      RESULT =1
   END 

   cont = ' ' IF  gg = 0
   last1 = 0;  mapgg = 0
   s = 0;  ss = 0;  sstype = -1; fdef = 0
   fm base = 0
   app = 0

   !deal with alignment following an error in one statement
   !of several on a line

   margin = column;                              !start of statement

   pos = 0
   stbase = addr(glink(gmax+1));  strp = stbase;  lp = 0
   tbase = tstart;                               !??????????????
   local = tbase

   IF  gg = 0 or  ocount >= 0 START ;            !data or not continuation(z)
again:WHILE  sym type = 0 CYCLE ;                !skip redundant terminators
         c = cont
         cont = ' ';  cont = '+' IF  ocount >= 0
         read sym
         cont = c
      REPEAT 
      ->skip IF  sym = '!';                      !comment
      this = -1
      code atom(0)
      IF  atom1 = comment START 
skip:    quote = 1
         c = cont
         read sym AND  cont = c WHILE  sym # nl; !skip to end of line
         quote = 0;  symtype = 0
         ->again
      FINISH 
   FINISH 
   decl = 0;  mark = 0
   gentype = 0;  force = 0
   dim = 0;  prot err = 0
   node = 0;  nmax = 0;  nmin = rec size+1
   order = 1;  gmin = max grammar+1
   sstype = 0 AND  ->more IF  gg # 0;            !continuation
   ptype = 0;  spec given = 0

   stats = stats+1;  op('O', lines) IF  perm = 0

   ->fail1 IF  atom1&error # 0;                  !first atom faulty

   IF  escape class # 0 START ;                  !enter the hard way after
      g = imp phrase;  sstype = -1;  ->a3
   FINISH 

   g = initial(atom1);                           !pick up entry point
   IF  g = 0 START ;                             !invalid first atom
      g = initial(0);  sstype = 0;  ->a3;        !declarator?
   FINISH 
   IF  g < 0 START ;                             !phrase imp
      g = g&255
      nmax = 1
      ar(1)_class = 0;  ar(1)_link = 0;  ar(1)_sub = imp phrase
   FINISH 

   gg = gram(g);  class = gg&255;  sstype = gg>>12&3-1
   ->a1

act(194): ptype = type;  papp = app;  pformat = format;  ->more
act(196):k =g+1;  ->a610
act(188):k = ar(nmax)_sub+1
a610:     papp = glink(k)
          k = gram(k)
          ->more IF  k = 0;                        !%NAME
          ptype = k&7;  pformat = k>>3
act(183):k = type;  gentype = k IF  gentype = 0 OR  k = real
          IF  pformat < 0 START ;                  !general type
             app = papp;  format = pformat
             k = real IF  ptype = real AND  type = integer
             k = force AND  force = 0 IF  force # 0
          FINISH 
          ->fail2 UNLESS  papp = app AND  (ptype = k OR  ptype = 0)
          ->more IF  pformat=format OR  pformat = 0 OR  format = 0
          ->fail2
act(197):arp == ar(nmin)
         k = arp_sub
         ->fail3 UNLESS  block form = k&15
         arp_sub = k>>4

         type = block type
         ptype = block type;  pformat = block fm;  papp = app
         pformat = -1 IF  ptype # record
         ->more
act(195):->Fail2 if  Type # 0 and  Type # Integer and 
                                   Type # Real
         arp == ar(nmin)
         k = arp_sub
         arp_sub = k>>2
         k = k&3
                                                      !1 = check integer
                                                      !2 = check real
                                                      !3 = check real + int
          ->more IF  k = 0;                           !0 = no action
          IF  k = 1 START 
             force = integer
             ->more IF  type = integer OR  type = 0
             ->fail2
          FINISH 
          ->fail2 UNLESS  ptype = real or  ptype = 0  {or added?}
          force = integer IF  k = 3
          ->more
act(198):!%OTHER
         k = gg>>8&15
         IF  k = 0 START ;                    !restore atom
            atom1 = last1
            ->more
         FINISH 
         IF  k = 1 START ;                    !test string
            ->fail2 UNLESS  type = stringv
            ->more
         FINISH 
         if  k = 2 start                      {fault record comparisons}
            ->fail2 if  type = record
            ->more
         finish 
         if  k = 3 start ;                    !check OWN variable coming
            code atom(0)
            ->A7 if  atom flags&own bit = 0
            ->more
         finish 
         for warn = pos1 IF  x <= local;      !%FORTEST
         ->more
paction(1):IF  type = record THEN  g = phrase(242) ELSE  pformat = -1
                                               ->a3
paction(2):ptype = real;     pformat = -1;     ->a3
paction(3):ptype = stringv;  pformat = -1;     ->a3
paction(4):ptype = integer;  pformat = -1;     ->a3
paction(5):->a3 if  ptype = integer
           g = phrase(212) AND  pformat=-1 IF  ptype = real
           g = phrase(213) IF  ptype = stringv
           ->a3
paction(6):ptype = gram(ar(nmax)_sub+1)&7;  pformat = -1;  ->a3
paction(7):ptype=real IF  ptype = integer;  pformat = -1;  ->a3

a1:   last1 = class;  atom1 = 0;  s = subatom

a2:   IF  gg&trans bit = 0 START ;                !insert into analysis record
         z == node
         CYCLE ;                                  !insert cell in order
            k = z
            EXIT  IF  gg&order bits = 0 OR  k = 0
            gg = gg-order bit;  z == ar(k)_link
         REPEAT 
         gg = map gg IF  map gg # 0 AND  gg&255 = var
         nmin = nmin-1;  ->fail0 IF  nmin = nmax
         z = nmin
         arp == ar(nmin)
         arp_sub = s;  arp_class = (gg&255)!mark
         arp_link = k
      FINISH 
      mark = 0;  map gg = 0

more: g = glink(g);                               !chain down the grammar

paction(0):
a3:   gg = gram(g);  class = gg&255
      trace analysis IF  diag&1 # 0
      ->a5 IF  class = 0;                         !end of phrase

      IF  class < actions START ;                 !not a phrase or an action
         class = atomic(class) IF  class >= figurative
         ->a2 IF  class >= manifest
         code atom(class) IF  atom1 = 0
         IF  escape class # 0 START ;             !escape to new grammar
            class = escape class;  escape class = 0
            g = g+escape

            !note that following an escape the next item is
            !forced to be transparent!

esc:        gg = 0
            arp == ar(nmax+1)
            arp_papp = papp;  arp_x = x;  ->a4
         FINISH 

         ->a1 IF  class = atom1 OR  class = atom2

a7:      ->fail1 IF  gg >= 0;                     !no alternative
         g = g+1
         ->a3
      FINISH 

      IF  class >= phrasal START ;                !a phrase
a4:      nmax = nmax+1;  ->fail0 IF  nmax = nmin
         arp == ar(nmax)
         arp_ptype = ptype
         arp_pos = pos1
         arp_pformat = pformat
         arp_link = gentype
         arp_class = node
         arp_sub = g
         node = 0
         g = phrase(class)
         ptype = force AND  force = 0 IF  force # 0
         gentype = 0
         ->paction(gg>>8&15)
      FINISH 

      ->act(class);                               !only actions left

a5:   !reverse links

      s = 0
      WHILE  node # 0 CYCLE 
         z == ar(node)_link
         k = z;  z = s;  s = node;  node = k
      REPEAT 
      ss = s

a6:   IF  nmax # 0 START 
         k = gentype;                             !type of phrase
         arp == ar(nmax);  nmax = nmax-1
         node = arp_class
         gentype = arp_link
         ptype = arp_ptype
         pformat = arp_pformat
         g = arp_sub
         IF  g&escape # 0 START 
            g = g-escape
            papp = arp_papp
            mark = 255
            subatom = s
            ->a3
         FINISH 
         gentype = k IF  gentype = 0 OR  k = real
         type = gen type

         k = gg;                                  !exit-point code
         CYCLE 
            gg = gram(g)
            ->a2 IF  k = 0
            ->fail1 IF  gg >= 0;                  !no alternative phrase
            k = k-order bit
            g = g+1;                              !sideways step
         REPEAT 

      FINISH 

      Fault(4)  IF  copy # 0
      fault(13) IF  order = 0
      fault(-4) IF  for warn # 0
      pos1 = 0
      fault rate = fault rate-1
      RETURN 

act(193):gg = 0 AND  ->a5 UNLESS  sym = '=' or  sym = '<';  !cdummy
act(181):atom1 = amap(decl&15);                             !dummy
         ->more

act(182):class = escdec;  g = glink(g)!escape
         decl = 0;  otype = 0;  ->esc;                      !decl

act(199):                                                   !compile

         s = 0
         WHILE  node # 0 CYCLE 
            z == ar(node)_link
            k = z;  z = s;  s = node;  node = k
         repeat 
         ss = s

         code atom(28) IF  quote # 0;                       !expend
         compile;  ->more IF  atom1&error = 0
         ->fail1

act(184):->fail4 UNLESS  type = integer
         IF  subatom < 0 THEN  lit = tag(-subatom)_format C 
                         ELSE  lit = lit pool(subatom)
         ->fail4 IF  lit # 0
         ->more
act(185):                                                   !apply parameters
         s = 0
         WHILE  node # 0 CYCLE 
            z == ar(node)_link
            k = z;  z = s;  s = node;  node = k
         REPEAT 
         ss = s

         atom1 = ar(s)_class;  atom2 = 0
         atom1 = var IF  atom1 = 97 OR  atom1 = 98
         arp == ar(nmax)
         x = arp_x
         pos1 = arp_pos
         pos2 = 0
         app = 0
         format = tag(x)_format
         flags = tag(x)_flags
         type = flags>>4&7
         protection = flags&prot
         protection = 0 IF  flags&aname # 0

         IF  flags&subname # 0 AND  format # 0 START 
            ->fail1 if  format selected = 0
         FINISH 

         ->a6

act(187):protection = prot;  ->more;            !%SETPROT
act(186):->More if  protection&prot = 0
         prot err = nmin
         ->A7
act(191):k = protection;                        !%GUARD
         code atom(0)
         protection = k IF  atom flags&aname = 0
         ->more

act(192):->fail1 IF  parsed machine code=0
         ->more

act(189):k = gapp;                              !%GAPP
         delete names(1)
         tmax = tbase;  tbase = gram (gmin);    !restore tmax
         local= tbase
         gmin = gmin+1

         x = ar(ar(nmax)_class)_sub
         tag(x)_app = k;                        !update app
         ->more

act(190):gmin = gmin-1;                         !%LOCAL
         abandon(2) IF  gmin <= gmax
         gram (gmin) = tbase;  tbase = tmax
         local = tbase
         ->more

! errors

fail4:k = error+10;            ->failed;        !*size
fail3:k = error+7;             ->failed;        !*context
fail2:k = error+5;  pos2 = 0;  ->failed;        !*type
fail0:k = error+3;             ->failed;        !*too complex
fail1:k = atom1;    pos2 = 0

failed:
      IF  diag&32 # 0 START 
         printstring("Atom1 =");       write(atom1, 3)
         printstring("  Atom2 =");     write(atom2, 3)
         printstring("  subatom =");   write(subatom, 3);  newline
         printstring("Type =");        write(type, 1)
         printstring("   Ptype =");    write(ptype, 1);    newline
         printstring("App =");         write(app, 1)
         printstring("   Papp =");     write(papp, 1);     newline
         printstring("Format =");      write(format, 1)
         printstring("   Pformat =");  write(pformat, 1);  newline
         SIGNAL  13,15
       FINISH 

       quote = 0 AND  readsym WHILE  sym # nl AND  sym # ';'
       IF  k&error # 0 START 
          fault(k&255)
       FINISH  ELSE  START 
         IF  prot err = nmin THEN  fault(14) ELSE  fault(0)
       FINISH 
       gg = 0;  ss = 0;  symtype = 0
   END ;                                               !of analyse

   ROUTINE  compile

      CONSTINTEGER  then = 4, else = 8, loop = 16

      SWITCH  c(0:actions), litop(1:12)

      CONSTBYTEINTEGERARRAY  operator(1:14) = C 
                         '[',  ']',  'X',  '/', '&',  '!',  '%',  '+',
                         '-',  '*',  'Q',  'x', '.',  'v'

      CONSTBYTEINTEGERARRAY  cc(0 : 7) = '#','=',')','<','(','>', 'k','t'

      CONSTBYTEINTEGERARRAY  anyform(0:15) = 1,0,1,1(4),1,0,1,1,0,1,1,1,1

      CONSTSHORTINTEGERARRAY  decmap(0:15) = C 
         1,             2,
         x'100B',       x'100D',       x'140C',      x'140E',
         3,             4,
         x'1007',       x'1008',       x'1009',      x'100A',
         6,             0,             0,            0
      OWNBYTEINTEGERARRAY  cnest(0:15)
      INTEGER  lmode, clab, dupid
      INTEGER  resln
      OWNINTEGER  last def = 0
      OWNINTEGER  lb, ub
      INTEGER  cp, ord
      INTEGER  next, link, j, k, n, done
      INTEGER  class
      INTEGER  lit2, defs, decs, cident
      INTEGER  pending;  OWNINTEGERARRAY  pstack(1:40)
      OWNSTRING (8) name = ""
      OWNINTEGER  count = 0

      ROUTINE  def lab(INTEGER  l)
         op(':', l)
         access = 1
      END 

      ROUTINE  get next
         RECORD (arfm)NAME  p
gn:      IF  next = 0 START ;                        !end of phrase
            class = 0 AND  RETURN  IF  link = 0;     !end of statement
            p == ar(link)
            next = p_link
            link = p_sub
         FINISH 
         CYCLE 
            p == ar(next)
            x = p_sub
            class = p_class
            EXIT  IF  class < actions;               !an atom
            IF  x = 0 START ;                        !null phrase
               next = p_link;  ->gn
            FINISH 
            IF  p_link # 0 START ;                   !follow a phrase
               p_sub = link;  link = next
            FINISH 
            next = x
         REPEAT 
         next = p_link
         IF  diag&2 # 0 START 
            spaces(8-length(name)) UNLESS  name = ""
            name = text(class)
            write(x, 2)
            space
            printstring(name)
            space
            count = count-1
            IF  count <= 0 START 
               count = 5
               name = ""
               newline
            FINISH 
         FINISH 
      END 

      ROUTINE  set subs(INTEGER  n)

         !update the app field in n array descriptors

         INTEGER  p
         p = tmax
         WHILE  n > 0 CYCLE 
            SIGNAL  15,15 IF  p < tbase
            tag(p)_app = dimension
            p = p-1;  n = n-1
         REPEAT 
      END 

      ROUTINE  set bp

         !define a constant bound pair from the last stacked constants

         pending = pending-2
         lb = pstack(pending+1);  ub = pstack(pending+2)
         IF  ub-lb+1 < 0 START 
            pos1 = 0;  next = link;  fault(11)
            ub = lb
         FINISH 
         set const(lb);  set const(ub)
         bp=bp+1 AND  buff(bp)='b' UNLESS  class = 146
      END 

      ROUTINE  compile end(INTEGER  type)

         ! type = 0:eof, 1:eop, 2:end

         IF  access # 0 START 
            open = 0
            fault(19) IF  block form > proc;           !can reach end
         FINISH 

         WHILE  dict(dmin) >= 0 CYCLE ;                !finishes & repeats
            fault(17+dict(dmin)&1)
            dmin = dmin+1
         REPEAT 
         {delete names(0)}
         bp=bp+1 AND  buff(bp)=';'
         bp=bp+1 AND  buff(bp)=';' IF  type = 1;       !endofprogram

         bflags = bflags!open;                         !show if it returns

         def lab(0) IF  block tag # 0 AND  level # 1;  !for jump around
         IF  type # 2 START ;                          !eop, eof
            fault(16) IF  level # type;                !end missing
         FINISH  ELSE  START 
            IF  level = 0 START 
               fault(15);                              !spurious end
            FINISH 
         FINISH 

         end mark = 11;               !******Mouses specific******
      END 

      ROUTINE  def(INTEGER  p)

         !dump a descriptor

         INTEGER  t, f, type
         RECORD (tagfm)NAME  v
         flush buffer if  bp # 0
         defs = defs+1
         v == tag(p)
         t = 0
         UNLESS  v_index < 0 START ;                   !no index for subnames
            id = id+1 AND  v_index = id IF  v_index = 0
            last def = v_index
            t = last def
         FINISH 
         op('$', t)
         print ident(p, 1);                            !output the name
         t = v_flags
         type = t
         type = type&(¬(7<<4)) IF  type&(7<<4) >= 6<<4;!routine & pred
         op(',', type&b'1111111');             !type & form
         f = v_format
         f = tag(f)_index IF  t&x'70' = record<<4
         f = v_index IF  f < 0
         op(',', f);               !format
         f = otype+t>>4&b'1111000'
         f = f!8 IF  class = 125;              !add spec from %DUP
         dim = v_app;                          !dimension
         dim = 0 unless  0 < dim <= dim limit
         op(',', f+dim<<8);                    !otype & spec & prot
         defs = 0 IF  t&parameters = 0
         f = t&15
         IF  v_flags&spec # 0 START 
            v_flags = v_flags&(¬spec) UNLESS  3 <= f <= 10
            ocount = -1;                       !external specs have no constants
         FINISH 
         dimension = 0
         if  otype = 2 and  (f=2 or  f=12 or  f=14) start 
            v_flags = v_flags-1;               !convert to simple
         finish 
      END 

      ROUTINE  def s lab(INTEGER  n)

         !define a switch label, x defines the switch tag

         INTEGER  p, l, b, w, bit
         p = tag(x)_format;                               !pointer to table
         l = dict(p);                                     !lower bound
         IF  l <= n <= dict(p+1) START 
            b = n-l
            w = b>>4+p
            bit = 1<<(b&15)
            IF  dict(w+2)&bit # 0 START ;                 !already set
               fault(4) IF  pending # 0
               RETURN 
            FINISH 
            dict(w+2) <- dict(w+2)!bit IF  pending # 0
            set const(n)
            op('_', tag(x)_index)   
         FINISH  ELSE  START 
            fault(12)
         FINISH 
         access = 1
      END 

      ROUTINE  call
         RECORD (tagfm)NAME  T
         t == tag(x)
         op('@', t_index)
         access = 0 IF  t_flags&closed # 0;                !never comes back
         bp=bp+1 AND  buff(bp)='E' IF  t_app = 0;          !no parameters
      END 

      ROUTINE  pop def
         set const(pstack(pending));  pending = pending-1
      END 

      ROUTINE  pop lit
         IF  pending = 0 THEN  lit = 0 ELSE  START 
            lit = pstack(pending);  pending = pending-1
         FINISH 
      END 


      IF  sstype < 0 START ;                       !executable statement
         IF  level = 0 START ;                     !outermost level
            fault(13);                             !*order
         FINISH  ELSE  START 
            IF  access = 0 START 
               access = 1;  fault(-1);             !only a warning
            FINISH 
         FINISH 
      FINISH 

      IF  diag&2 # 0 START 
         newline IF  sym # nl
         printstring("ss =")
         write(ss, 1)
         newline
         count = 5
         name = ""
      FINISH 

      next = ss
      pending = 0;  lmode = 0
      link = 0;  decs = 0
      defs = 0;  resln = 0;  done = 0
      ord = level
      ord = 1 IF  this >= 0;                       !recordformat declarations
c(0):
top:  IF  next # link START 
         get next;  ->c(class)
      FINISH 

      !all done, tidy up declarations and jumps

      newline IF  diag&2 # 0 AND  count # 5

      IF  lmode&(loop!then!else) # 0 START ;       !pending labels and jumps
         op('B', label-1) IF  lmode&loop # 0;      !repeat
         def lab(label)   IF  lmode&then # 0;      !entry from then
         def lab(label-1) IF  lmode&else # 0;      !entry from else
      FINISH 

      RETURN  IF  decs = 0
      atom1 = error AND  RETURN  IF  atom1 # 0;    !%INTEGERROUTINE
      order = ord
      decl = decl&(¬15)+decmap(decl&15);           !construct declarator flags
      atom1 = atoms(decl&15);                      !generate class
      IF  otype # 0 START ;                        !own, const etc.
         atom1 = atom1+1 IF  atom1 # proc
         IF  otype = 2 START ;                     !const
            n = decl&15
            if  n&1 # 0 start 
               decl = decl!prot
               decl = decl!const bit IF  decl&b'1111111' = iform
            finish 
         else 
            decl = decl!own bit
         FINISH 
      FINISH 
      sstype = 1 IF  sstype = 0 AND  atom1 = proc
      atom1 = atom1+1 IF  decl&spec # 0;             !onto spec variant
      ocount = 0 AND  cont = '+' IF  atom1 = 5;      !own array
      IF  anyform(decl&15) = 0 START ;               !check meaningful
         IF  decl>>4&7 = record START 
            this = fdef IF  tag(fdef)_flags&spec # 0
            atom1 = error+21 IF  fdef = this;        !*context for format
         FINISH 
         atom1 = error+10 IF  fdef = 0;              !*size
      FINISH 
      RETURN 

atop:   access = 0;  ->top

! declarators

c(88):                                                !rtype
c(28): decl = x&(¬7);                                 !stype
       fdef = x&7;                                    !precision
       fdef = reals ln IF  x&b'1110001' = real<<4+1;  !convert to long
       decs = 1;  ->top
c(34):                                                !own
c(35): otype = x;  ord = 1;  ->top;                   !external
c(152):decl = decl+x<<1;  ->top;                      !xname
c(31):                                                !proc
c(32): spec mode = level+1;                           !fn/map
       decl = decl!prot IF  x = 9;                    !function
c(29): ord = 1;                                       !array
       dim = 0
c(30): decl = decl+x;                                 !name
       decs = 1
       ->top
c(27): lit = 0;                                       ! arrayd
       IF  pending # 0 START 
          pop lit
          UNLESS  0<lit<=dim limit START 
             atom1 = error + 11;  RETURN 
          FINISH 
       FINISH 
       dim = lit
       decl = decl + x;  decs = 1
       -> top
c(37): x = x!subname;                                 !record
c(36): lit = 0;                                       !string
       IF  pending # 0 START 
         pop lit
          UNLESS  0 < lit <= 255 START ;              !max length wrong
             atom1 = error+10;  RETURN 
          FINISH 
       FINISH 
       fdef = lit;                                    !format or length
c(33): decl = x;                                      !switch
       decs = 1
       ->top
c(39): decl = decl!spec;                              !spec
       ocount = -1;                                   !no initialisation
       spec mode = -1
       ->top
c(38): decl = 64+4;                                   !recordformat (spec)
       order = 1
       atom1 = x
       decl = decl!spec if  atom1 = 12;               !formatspec
       fdef = tmax+1;                                 !format tag
       return 
c(175):id = id+1;  tag(x)_index = id;  return ;       !FSID
c(41): decs = 1;  decl = x!spec!closed;  ->top;       !label
c(133):recid = 0;  rbase = tmin-1;                    !fname
       this = x
       fm base = fdef;  format list = tmin
       def(this);                      ->top
c(148):fdef = 0 AND  ->top IF  next = 0;              !reclb
       get next;                                      !skip name
       fdef = x
       ->top
c(127):bp=bp+1 AND  buff(bp)='}';  ->top;             !%POUT
c(126):bp=bp+1 AND  buff(bp)='{';  ->top;             !%PIN

c(174):set bp;                                        !rangerb
c(171):                                               !fmlb
c(172):                                               !fmrb
c(173):bp=bp+1 AND  buff(bp)='~';  bp=bp+1 AND  buff(bp)=class-171+'A';  ->top;         !fmor
c(168):rbase = -rbase;                                !orrb
       sstype = 0;  spec mode = 0

c(147):search base = 0;                               !recrb
       tag(this)_app = tmin
       tag(this)_format = rbase
       ->top

c(45):bp=bp+1 and  buff(bp)='U' IF  x = 36;  ->top;   !sign
c(46):bp=bp+1;  buff(bp)='¬';  ->top;                 !uop
c(47):                                                !mod
c(48):                                                !dot
c(42):                                                !op1
c(43):                                                !op2
c(44):bp=bp+1;  buff(bp)=operator(x);  ->top;         !op3

!conditions & jumps

      ROUTINE  push(INTEGER  x)
         IF  cnest(cp)&2 # x START 
            cnest(cp) = cnest(cp)!1;  x = x+4
         FINISH 
         clab = clab+1 IF  cnest(cp)&1 # 0
         cnest(cp+1) = x;  cp = cp+1
      END 

      ROUTINE  pop label(INTEGER  mode)
         lmode = dict(dmin)
         IF  lmode < 0 OR  lmode&1 # mode START 
            fault(mode+8)
         FINISH  ELSE  START 
            dmin = dmin+1;  label = label-3
         FINISH 
      END 

c(56):                                         !and
c(57):push(x);  ->top;                         !or
c(58):cnest(cp) = cnest(cp)!!2;  ->top;        !not

c(138):x = 128+32+16+4;                        !csep: treat like %WHILE
c(59):                                         !while
c(60):IF  class = 138 THEN  op('f', label-1) C 
                      ELSE  def lab(label-1);  !until
c(166):                                        !runtil
c(62):lmode = (lmode&(else!loop)) !(x>>3);     !cword
      clab = label;  cp = 1;  cnest(1) = x&7
      ->top
c(72):pop label(0);                            !repeat
      def lab(label+1) IF  lmode&32 # 0;  ->atop
c(69):pop label(1);               ->top;       !finish
c(163):                                        !xelse
c(70):pop label(1);                            !finish else ...
      fault(7) IF  lmode&3 = 3;                !dangling else
c(68):lmode = (lmode&else)!3;                  !...else...
      IF  access # 0 START 
         op('F', label-1);  lmode = else!3
      FINISH 
      def lab(label)
      ->top IF  next # 0

c(120):                                        !%MSTART
c(67):                                         !start
c(71):                                         !cycle
stcy: def lab(label-1) AND  lmode = loop IF  lmode = 0;!cycle
      dmin = dmin-1;  abandon(3) IF  dmin <= dmax
      dict(dmin) = lmode
      label = label+3
      RETURN 

c(64):fault(13) IF  dict(dmin) >= 0 OR  inhibit # 0;  !on event
      inhibit = 1
      n = 0
      n = x'FFFF' IF  pending = 0;             !* = all events
      WHILE  pending > 0 CYCLE 
         pop lit;  fault(10) IF  lit&(¬15) # 0;!too big
         j = 1<<lit
         dubious = 1 IF  n&j # 0
         n = n!j;                              !construct bit mask
      REPEAT 
      op('o', n);  op(',', label)
      lmode = then!1;  ->stcy


c(104):op('J', tag(x)_index);                   !l
       inhibit = 1;            ->atop
c(149):stats = stats-1;                         !lab
       access = 1;  inhibit = 1
       op('L', tag(x)_index);  ->top

c(63):j = dmin;  l = label-3;                   !exit, continue
      CYCLE 
         fault(7) AND  ->top IF  dict(j) < 0
         EXIT  IF  dict(j)&1 = 0
         j = j+1;  l = l-3
      REPEAT 
      l = l+1 IF  x = 32;                       !continue
      op('F', l)
      dict(j) = dict(j)!x;                      !show given
      ->atop

c(50):bp=bp+1 AND  buff(bp)='C';  ->cop;        !acomp

c(49): bp = bp+1
       IF  next # 0 START ;                     !comparator
          buff(bp)='"';  push(0);               !double sided
       FINISH  ELSE  START 
          buff(bp)='?'
       FINISH 

cop:   x = x!!1 IF  cnest(cp)&2 # 0;            !invert the condition
       j = cp;  l = clab
       WHILE  cnest(j)&4 = 0 CYCLE 
          j = j-1;  l = l-cnest(j)&1
       REPEAT 
       op(cc(x), l)
       def lab(clab+1) IF  cnest(cp)&1 # 0
       cp = cp-1
       clab = clab-cnest(cp)&1
       ->top

c(78):                                              !fresult
c(79):                                              !mresult
c(80):   open = 0;                                  !return, true, false
c(82):   access = 0;                                !stop
c(89):                                              !addop
c(81):   bp=bp+1 AND  buff(bp)=x;  ->top;           !monitor

c(65):   pop lit;  op('e', lit);  ->atop;           !signal

c(51):   bp=bp+1 AND  buff(bp)='S';  ->top;         !eq
c(53):   bp=bp+1 AND  buff(bp)='j';  ->top;         !jam transfer
c(52):   bp=bp+1 AND  buff(bp)='Z';  ->top;         !eqeq

c(74):IF  level = 0 START ;                         !begin
         IF  progmode <= 0 THEN  progmode = 1 ELSE  fault(7)
         {Permit BEGIN after external defs}
      FINISH 
      spec mode = level+1
      block x = 0
      bp=bp+1 AND  buff(bp)='H';  RETURN 
c(77):perm = 0;  lines = 0;  stats = 0;             !endofperm
      close input
      select input(source)
      list = list-1
      tbase = tmax;  tstart = tmax
      RETURN 
c(76):IF  include # 0 AND  x = 0 START ;            !end of ...
         lines = include;  sstype =  0;             !include
         close input
         list = include list
         include level = 0
         include = 0;  select input(source);  RETURN 
      FINISH 
      ss = -1;                                      !prog/file
c(75):compile end(x);  RETURN ;                     !%END

c(85):IF  x=0 THEN  control=lit ELSE  START ;       !control
         diag = lit&x'3FFF' IF  lit>>14&3 = 1
      FINISH 
      op('z'-x, lit)
      ->top
c(83):list = list+x-2;   ->top;                     !%LIST/%ENDOFLIST
c(84):reals ln = x;      ->top;                     !%REALS long/normal
c(86):IF  include # 0 START ;                       !include "file"
         fault(7);  RETURN 
      FINISH 
      get next;                                     !sconst
      include file = string(x-x'4000'+stbase)
      begin 
         on  9 start ;  Abandon(9);  finish 
         open input(3, include file)
      end 
      include = lines;  lines = 0
      include list = list;  include level = level
      select input(3)
      ->top

c(154):dimension = dimension+1;                     !dbsep
       fault(11) IF  dimension = dim limit+1
       ->top
c(145):set bp;                       ->top;         !crb
c(146):set bp;                                      !rcrb
c(142):                                             !bplrb
       dimension = 1 IF  dimension = 0
       op('d', dimension);  op(',', defs)
       IF  class # 146 START 
          set subs(defs)
          fault(13) IF  dict(dmin) >= 0 OR  inhibit # 0 OR  level=0
       FINISH 
       dimension = 0;  defs = 0
       ->top
c(128):id = dupid;  ->top;                          !EDUP
c(130):block x = x
       op('F', 0) IF  decl&spec = 0 AND  level # 0; !jump round proc
c(125):dupid = id;                                  !%DUP
       return  if  Level < 0                        {spec about}
c(90): def(x);  ->top;                              !ident
c(131):                                             !cident
       IF  tag(x)_flags&(b'1111111'+const bit) = iform+const bit START 
          tag(x)_format = lit
       FINISH  ELSE  START 
          set const(lit) IF  pending # 0
          def(x)
         op('A', 1)
       FINISH 
       cident = x
       ->top
c(124):dubious = 1 IF  tag(cident)_flags&prot # 0; !%DUBIOUS
       ->top
c(97):                                              !f
c(98):                                              !m
c(99):                                              !p
c(96): call;  ->top;                                !r

c(165):                                             !nlab
c(100):                                             !rp
c(101):                                             !fp
c(102):                                             !mp
c(103):                                             !pp
c(91):                                              !v
c(92):                                              !n
c(106):                                             !a
c(107):                                             !an
c(108):                                             !na
c(109):                                             !nan
      k = tag(x)_index
      IF  k < 0 THEN  op('n', -k) ELSE  op('@', k)
      ->top
c(121):set const(0);  ->top;                        !special for zero
c(167):bp=bp+1;  buff(bp)='G';  ->pstr;             !aconst (alias)
c(const):                                           !const
       IF  x < 0 START ;                            !constinteger
          set const(tag(-x)_format);  ->top
       FINISH 
       IF  x&x'4000' # 0 START ;                    !strings
          bp=bp+1 AND  buff(bp)=''''
pstr:     x = x-x'4000'+stbase
          k = byteinteger(x)
          bp=bp+1 AND  buff(bp)=k
          k = k+x
          CYCLE 
             ->top IF  x = k
             x = x+1;  bp=bp+1 AND  buff(bp)=byteinteger(x)
          REPEAT 
       FINISH 
       IF  x&x'2000' # 0 START ;                    !real
          x = x-x'2000'+stbase
          k = byteinteger(x)
          op('D', k);  bp=bp+1 AND  buff(bp)=','
          k = k+x
          CYCLE 
             ->top IF  x = k
             x = x+1;  j = byteinteger(x)
             IF  j = '@' START 
                op('@', litpool(byteinteger(x+1)));  ->top
             FINISH 
             bp=bp+1 AND  buff(bp)=j
          REPEAT 
       FINISH 
       set const(lit pool(x))
       ->top

c(137):bp=bp+1 AND  buff(bp)='i';               ->top;         !asep
c(141):bp=bp+1 AND  buff(bp)='a';               ->top;         !arb

!own arrays

c(132):ocount = ub-lb+1
       def(x);                               !oident
       dimension = 1;  set subs(1)
       IF  next = 0 START ;                  !no initialisation
          op('A', ocount) IF  ocount > 0
          ocount = -1
       FINISH  ELSE  START ;                 !initialisation given
          get next
       FINISH 
       ->top
c(162):lit = ocount;  ->ins;                 !indef
c(143):pop lit;                              !orb
ins:   fault(10) AND  lit = 0 IF  lit < 0
       get next
       ->inst
c(139):                                      !osep (x=19)
c(153):lit = 1
inst:  pop def IF  pending # 0;              !ownt (x=0)
       op('A', lit)
       ocount = ocount-lit
       IF  ocount >= 0 START 
          ->top IF  x # 0;                          !more coming
          ocount = -1 AND  RETURN  IF  ocount = 0;  !all done
       FINISH 
       fault(11);  RETURN 

c(swit):op('W', tag(x)_index);  inhibit = 1;  ->atop
c(134):def(x);                               !swid
       n = ub-lb+1
       n = (n+15)>>4;                        !slots needed (includes zero)
       j = dmax;  dmax = dmax+n+2
       abandon(1) IF  dmax >= dmin
       tag(x)_format = j
       dict(j) = lb;  dict(j+1) = ub
       CYCLE 
          n = n-1
          ->top IF  n < 0
          j = j+1;  dict(j+1) = 0
       REPEAT 
c(151):stats = stats-1;                      !slab
       fault(7) AND  RETURN  IF  x < tbase
       IF  pending # 0 START ;               !explicit label
          def s lab(pstack(1))
       FINISH  ELSE  START 
          fault(4) AND  RETURN  IF  tag(x)_app # 0
          tag(x)_app = 1
          n = tag(x)_format
          FOR  j = dict(n), 1, dict(n+1) CYCLE 
             def s lab(j)
             flush buffer IF  bp >= 128
          REPEAT 
       FINISH 
       inhibit = 1
       RETURN 

c(140):bp=bp+1 AND  buff(bp)='p';                  ->top;          !psep
c(144):buff(bp+1)='p';  buff(bp+2)='E';  bp=bp+2;  ->top;          !prb

!constant expressions

c(155):                                      !pconst
       IF  x < 0 THEN  lit = tag(-x)_format c 
                 ELSE  lit = lit pool(x)
       pending = pending+1;     pstack(pending) = lit;  ->top
c(156):lit = pstack(pending);  lit = -lit IF  lit < 0
                                pstack(pending) = lit;  ->top;  !cmod
c(157):lit = -pstack(pending);  pstack(pending) = lit;  ->top;  !csign
c(158):lit = ¬pstack(pending);  pstack(pending) = lit;  ->top;  !cuop
c(159):                                      !cop1
c(160):                                      !cop2
c(161):pending = pending-1;                  !cop3
       lit2 = pstack(pending+1);  lit = pstack(pending)
       ->litop(x>>2)
litop(10):lit = lit*lit2;   ->setl
litop(12):
litop(3):n = 1;                              !lit = lit¬¬lit2
         fault(10) IF  lit2 < 0
         WHILE  lit2 > 0 CYCLE 
            lit2 = lit2-1
            n = n*lit
         REPEAT 
         lit = n;           ->setl
litop(1):lit = lit<<lit2;   ->setl
litop(2):lit = lit>>lit2;   ->setl
litop(5):lit = lit&lit2;    ->setl
litop(11):
litop(4):IF  lit2 = 0 THEN  fault(10) ELSE  lit = lit//lit2
                            ->setl
litop(8):lit = lit+lit2;    ->setl
litop(9):lit = lit-lit2;    ->setl
litop(6):lit = lit!lit2;    ->setl
litop(7):lit = lit!!lit2

setl: pstack(pending) = lit;  ->top

c(170):Fault(4) if  IMPCOM_Option # ""
       IMPCOM_Option = String(x-x'4000'+Stbase);      !Option string
       ->Top

!string resolution

c(135):resln = 2;                    ->top;           !dotl
c(136):resln = resln+1;              ->top;           !dotr
c(55): op('r', resln);    resln = 0; ->top;           !resop
c(164):op('r', resln+4);  resln = 0;                  !cresop
c(122):x = 6;                        ->cop;           !%PRED
c(87): set const(pstack(1));                          !mass
       bp=bp+1 AND  buff(bp)='P';    ->top
   END 

END ;                                                 !of compile block

   ON  9 START 
      abandon(5)
   FINISH 

   list = 15 IF  Impcom_Flags&x'1000' # 0

   selectinput(2);  selectoutput(listing)
   tag(max tag) = 0;                       !%BEGIN defn
   tag(0) = 0;  tag(0)_flags = 7;          !%BEGIN tag!
   Hash(x) = 0 FOR  x = 0, 1, max names
   printstring("         Edinburgh IMP77 Compiler - Version ")
   printstring(version);  newlines(2)
   op('l', 0)
   compile block(0, 0, max dict, 0, 0)
   bp=bp+1 AND  buff(bp)=nl                {for bouncing off}
   flush buffer
   Impcom_Statements = stats
   Impcom_Statements = -faulty IF  faulty # 0
ENDOFPROGRAM