!***********************************************************************
!*              SOAP80 - IMP80 formatter                               *
!*                                               Last altered 15/06/83 *
!*                                                                     *
!*              Created by E.N.Gregory, UKC.                           *
!*              All syntax directed sections rewritten by P.D.S., ERCC *
!*                using IMP80 syntax version 02.                       *
!*              User interface and parameters revised by J.M.M., ERCC. *
!*                                                                     *
!***********************************************************************

external  routine  spec  prompt(string  (31) s)

!***********************************************************************
!*                                                                     *
!*                           Record formats.                           *
!*                                                                     *
!***********************************************************************

record  format  fhdr(integer  dataend, datastart, filesize, filetype)
record  format  chdr(integer  conad, filetype, datastart, dataend)
constant  integer  maxopt= 16,numopt = 3
record  format  pformat(byte  integer  array  tab(0:20),
  (byte  integer  line, icontin, poscom, movecom, uckey, sepkey, expkey,
  lcasnam, spacnam, spacass, spacop, lclist, iblock, istat, seplab,
  spcomma or  byte  integer  array  optarr(1:maxopt)) or  c 
 byte  integer  array  a(1:21+maxopt))


!***********************************************************************
!*                                                                     *
!*                           System routines.                          *
!*                                                                     *
!***********************************************************************

system  string  function  spec  itos(integer  i)
system  routine  spec  connect(string  (31) name, integer  mode, hole, prot,
  record  (chdr) name  rec, integer  name  eflag)
system  routine  spec  trim(string  (31) file, integer  name  eflag)
system  routine  spec  setfname(string  (31) file)
system  string  function  spec  nexttemp
system  routine  spec  sendfile(string  (31) file, device, header,
  integer  copies, form, integer  name  eflag)
system  integer  function  spec  devcode(string  (31) name)
system  routine  spec  disconnect(string  (31) filename, integer  name  eflag)
system  string  function  spec  failuremessage(integer  type)
system  routine  spec  changefilesize(string  (31) filename,
  integer  filesize, integer  name  eflag)
system  routine  spec  newgen(string  (31) filename, newfilename,
  integer  name  eflag)
system  routine  spec  outfile(string  (31) filename, integer  size, hole,
  prot, integer  name  conad, eflag)

external  routine  soap80(string  (255) s)
   integer  ptr, dataend, inptr, z, in, obp, eflag, writeaddress, wa0,
     filesize, conad, errors, line, erptr, startline, stream, filesizeptr,
     ssalt, strdelimiter, str, semicolon, colon, maxptr, maxitem, level,
     stop, increm, inlabel, charsin, ersave, inconst, bheading, inline
   string  (255) outf
   string  (31) workfile, infile
   string  (2) percentc
   record  (pformat) p
   record  (chdr) rec, rr
   record  (fhdr) name  outrec
   constant  integer  ccsize= 16384
   half  integer  array  outbuf(0:ccsize+200)
   byte  integer  array  sc(0:ccsize)

   constant  string  (7) array  optname(1:maxopt)=   "LINE","ICONTIN","POSCOM",
    "MOVECOM","UCKEY","SEPKEY","EXPKEY","LCASNAM","SPACNAM","SPACASS","SPACOP",
    "LCLIST","IBLOCK","ISTAT","SEPLAB","SPCOMMA"
   constant  string  (39) array  optmess(0:1, 1:maxopt)= c 
    "Line length zero (!!!)","Maximum line length",
    "Continued lines not indented","Indentation of continued lines",
    "Right hand comments not positioned","Right hand comment position",
    "Whole line comments indented normally",
    "Whole line comments moved to POSCOM","Keywords output in lower case",
    "Keywords output in upper case","Keywords not split","Keywords split",
    "%FN, %CONST, %ELSE not expanded",
    "%FN, %CONST, (sometimes) %ELSE expanded",
    "Case of names controlled by UCKEY", "Case of names left alone",
    "Spaces removed from names","Spaces preserved within names",
    "No spaces round assignment operators",
    "Spaces added round assignment operators","No spaces round operators",
    "Spaces added round operators","Constant lists formatted",
    "Constant lists left alone","Block not indented w.r.t. block heading",
    "Block indented w.r.t. block heading",
    "Statements aligned with declarations",
    "Statements indented w.r.t. declarations",
    "Labels not on lines by themselves","Labels on lines by themselves",
    "No space character after commas","Space character after commas"

   constant  integer  charfile= 3; ! Code for a character file.
   constant  integer  underline= 128
   constant  integer  instring= 256,incurly = 512,bpoint = 1024,bpoint2 = 2048
   constant  integer  terminal= 1,file = 2,samefile = 3,device = 4
   constant  integer  true= 255,false = 0; ! Synthetic boolean values.
   constant  integer  nl= 10,dquotes = 34,squotes = 39
   constant  integer  rs= 30; ! RECORD SEPARATOR IS USED AS A DELETED(BY %c) NL
   constant  integer  rem= B'00000001'
   constant  integer  constart= B'00000010'
   constant  integer  quotes= B'00000100'
   constant  integer  endst= B'00001000'
   constant  integer  number= B'00010000'
   constant  integer  letter= B'00100000'
   constant  byte  integer  constfirst= B'01000000'
   constant  integer  constcont= B'10000000'
   !
   constant  byte  integer  array  onecase(0:127)=
   0,1,2,3,4,5,6,7,8,9,10,11,12,
   13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,
   35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,
   57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,
   79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68,
   69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,
   123,124,125,126,127
   constant  byte  integer  array  chartype(0:255)=     B'00000001',
 B'00000000',
          B'00000000',B'00000000',B'00000000',B'00000000',B'00000000',
          B'00000000',B'00000000',B'00000000',B'00001000',B'00000000'(22),
          B'00000001'{!},B'00000100',B'01000000',B'00000000',B'00000001'{%},
          B'00000000',B'00000100',B'00000000',B'00000000',B'00000000',
          B'00000000',B'00000000',B'00000000',B'11000000',B'00000000',
          B'11010000'(10),
          B'00000000',B'00001000',B'01000000',B'01000000',B'01000000',
          B'00000000',B'00000000',
          B'00100000',B'00100010',B'00100010',B'00100010',B'00100000',
          B'00100000',B'00100000',B'00100000',
          B'00100000',B'00100000',B'00100010',B'00100000',
          B'00100010',B'00100000',B'00100000',B'00100000',B'00100000',
          B'00100010',B'00100000',B'00100000',B'00100000',B'00100000'(2),
          B'00100010',B'00100000',B'00100000',B'00000000',B'00000000',
          B'00000000',B'00000000',B'00000000',B'00000000',
          B'00100000',B'00100010'{b},B'00100010',B'00100010',B'00100000'(6),
          B'00100010'{k},B'00100000',B'00100010'{m},B'00100000'(4),
          B'00100010'{r},B'00100000'(5),B'00100010'{x},B'00100000'(2),
          B'00000000',B'00000001'{|},B'00000000',B'00000000',B'00000000',
          B'0'(67),
          B'00000001'{%C},
          B'0'(60)
   constant  byte  integer  array  keycom(0:7)= '%','C','O','M','M','E','N','T'
   constant  integer  array  fstable(1:3)=     4096,16384,65536
   !
   ! Special delimiters noted by SOAP80.
   !
   constant  integer  offile= 133,ofprogram = 123,equals = 38,comma = 10,
 if = 12,
    unless = 15,while = 22,until = 28,else = 227,then = 222,and = 158,or = 162,
    const = 204, constant = 195, fn = 96, function = 103
   !
   constant  string  (1) snl= "
"
   !
   constant  string  (60) array  fault(1:4)=
              "Statement is too long and could not be compiled.",
              "End of file reached before end of program terminator found.",
              "%END found, but could not match it to a start of routine.",
              "Disaster *** Indentation too near line length limit."
   !
   !
   !
   routine  spec  fail(integer  type, action)
   routine  spec  opt(string  (255) parm, record  (pformat) name  p)
   !
   ! Produced by oldps from impalgs_imp80ps04 on 19/01/83
   constant  byte  integer  array  clett(0:434)=   1,
{1}  43,   1,  45,   1,  40,   1,  41,   1,  42,   1,  44,   2, 201, 198,
{15}   6, 213, 206, 204, 197, 211, 211,   5, 215, 200, 201, 204, 197,   5,
{29} 213, 206, 212, 201, 204,   3, 198, 207, 210,   1,  61,   5, 193, 204,
{43} 201, 193, 211,   7, 201, 206, 212, 197, 199, 197, 210,   4, 210, 197,
{57} 193, 204,   4, 204, 207, 206, 199,   4, 194, 217, 212, 197,   6, 211,
{71} 212, 210, 201, 206, 199,   4, 200, 193, 204, 198,   6, 210, 197, 195,
{85} 207, 210, 196,   7, 210, 207, 213, 212, 201, 206, 197,   2, 198, 206,
{99}   3, 205, 193, 208,   8, 198, 213, 206, 195, 212, 201, 207, 206,   4,
{113} 206, 193, 205, 197,   5, 193, 210, 210, 193, 217,   9, 207, 198, 208,
{127} 210, 207, 199, 210, 193, 205,   6, 207, 198, 198, 201, 204, 197,   6,
{141} 207, 198, 204, 201, 211, 212,   6, 198, 207, 210, 205, 193, 212,   3,
{155} 206, 207, 212,   3, 193, 206, 196,   2, 207, 210,   1,  58,   4, 211,
{169} 208, 197, 195,   3, 207, 215, 206,   8, 197, 216, 212, 197, 210, 206,
{183} 193, 204,   9, 197, 216, 212, 210, 201, 206, 211, 201, 195,   8, 195,
{197} 207, 206, 211, 212, 193, 206, 212,   5, 195, 207, 206, 211, 212,   5,
{211} 197, 214, 197, 206, 212,   5, 211, 212, 193, 210, 212,   4, 212, 200,
{225} 197, 206,   4, 197, 204, 211, 197,   1,  95,   6, 211, 217, 211, 212,
{239} 197, 205,   7, 196, 217, 206, 193, 205, 201, 195,   4,  80,  85,  84,
{253}  95,   5,  67,  78,  79,  80,  95,   2, 204,  61,   1,  60,   1,  62,
{267}   4,  40, 196, 210,  43,   2, 196, 210,   1, 194,   3, 212, 207, 211,
{281}   3, 204, 206, 194,   3, 216, 206, 194,   2, 208, 195,   3, 195, 212,
{295} 194,   2,  45,  62,   6, 210, 197, 212, 213, 210, 206,   6, 210, 197,
{309} 211, 213, 204, 212,   7, 205, 207, 206, 201, 212, 207, 210,   4, 211,
{323} 212, 207, 208,   6, 211, 201, 199, 206, 193, 204,   4, 197, 216, 201,
{337} 212,   8, 195, 207, 206, 212, 201, 206, 213, 197,   6, 198, 201, 206,
{351} 201, 211, 200,   5, 195, 217, 195, 204, 197,   6, 210, 197, 208, 197,
{365} 193, 212,   3, 197, 206, 196,   7, 201, 206, 195, 204, 213, 196, 197,
{379}   5, 194, 197, 199, 201, 206,   2, 207, 206,   6, 211, 215, 201, 212,
{393} 195, 200,   4, 204, 201, 211, 212,  14, 212, 210, 213, 211, 212, 197,
{407} 196, 208, 210, 207, 199, 210, 193, 205,   6, 205, 193, 201, 206, 197,
{421} 208,   7, 195, 207, 206, 212, 210, 207, 204,   4,  40,  42,  41,  58


   constant  integer  array  symbol(1300:2167)=  1307,
  1303,     0,  1305,     2,  1307,  1000,  1319,  1312,  1001,  1366,
  1786,  1315,  1003,  1020,  1319,     4,  1345,     6,  1329,  1323,
  1001,  1014,  1325,  1003,  1329,     4,  1329,     6,  1336,  1336,
  1010,  1028,  1319,  1011,  1359,  1345,  1343,  1010,  1028,  1319,
  1011,  1359,  1345,     8,  1352,  1352,  1010,  1028,  1307,  1011,
  1352,  1359,  1357,  1026,  1307,   999,  1359,  1000,  1366,  1364,
  1026,  1319,   999,  1366,  1000,  1374,  1372,     4,  1345,  1374,
     6,  1374,  1000,  1381,  1379,    10,  1345,   999,  1381,  1000,
  1386,  1384,    12,  1386,    15,  1410,  1393,    22,  1010,  1536,
  1556,  1011,  1399,    28,  1010,  1536,  1556,  1011,  1410,    34,
  1010,  1001,    38,  1345,    10,  1345,    10,  1345,  1011,  1416,
  1414,    40,  1013,  1416,  1000,  1423,  1421,    10,  1001,   999,
  1423,  1000,  1428,  1426,    46,  1428,  1000,  1436,  1431,    54,
  1433,    46,  1436,    59,    54,  1458,  1439,    46,  1441,    54,
  1444,    59,  1428,  1447,    64,  1423,  1450,    69,  1689,  1453,
    76,  1423,  1458,    81,     4,  1848,     6,  1465,  1461,    88,
  1465,  1004,  1436,  1465,  1472,  1468,    96,  1470,    99,  1472,
   103,  1488,  1478,  1436,  1493,  1001,  1416,  1484,  1458,  1488,
  1001,  1416,  1501,  1488,   112,  1001,  1416,  1493,  1491,   112,
  1493,  1000,  1501,  1497,   117,   112,  1499,   112,  1501,  1000,
  1511,  1509,     4,  1010,  1472,  1011,  1511,     6,  1511,  1000,
  1520,  1518,  1030,  1010,  1472,  1011,   999,  1520,  1000,  1531,
  1524,   123,  1016,  1526,   133,  1529,   140,  1018,  1531,  1016,
  1536,  1534,   147,  1536,  1000,  1550,  1542,  1345,  1032,  1345,
  1550,  1547,     4,  1536,  1556,     6,  1550,   154,  1536,  1556,
  1554,  1037,  1345,  1556,  1000,  1567,  1561,   158,  1536,  1567,
  1565,   162,  1536,  1574,  1567,  1000,  1574,  1572,   158,  1536,
   999,  1574,  1000,  1581,  1579,   162,  1536,   999,  1581,  1000,
  1589,  1585,  1033,  1345,  1587,   165,  1589,  1000,  1595,  1593,
   167,  1008,  1595,  1015,  1599,  1598,   167,  1599,  1608,  1606,
    10,  1345,   165,  1345,  1599,  1608,  1000,  1617,  1613,  1493,
  1001,  1416,  1617,   117,  1531,  1617,  1623,  1623,  1001,  1416,
  1794,  1623,  1629,  1627,    10,  1617,  1629,  1000,  1646,  1639,
  1493,  1595,  1010,  1001,  1410,  1802,  1011,  1646,  1646,   117,
  1531,  1595,  1001,  1794,  1668,  1657,  1655,    10,  1010,  1001,
  1410,  1802,  1011,  1646,  1657,  1000,  1668,  1660,   172,  1662,
   176,  1664,   185,  1666,   195,  1668,   204,  1679,  1677,    38,
  1012,  1028,  1319,  1359,  1689,  1679,  1679,  1000,  1689,  1687,
    10,  1028,  1319,  1359,  1689,   999,  1689,  1000,  1696,  1694,
     4,  1336,     6,  1696,  1000,  1703,  1701,    10,  1329,   999,
  1703,  1000,  1708,  1706,   210,  1708,  1000,  1714,  1712,    10,
  1345,  1714,  1000,  1727,  1725,    10,  1001,  1416,     4,  1345,
   165,  1345,     6,   999,  1727,  1000,  1734,  1732,    28,  1536,
  1556,  1734,  1000,  1747,  1737,  1019,  1739,  1006,  1744,  1381,
  1536,  1556,  1006,  1747,  1386,  1006,  1761,  1751,   216,  1034,
  1755,   222,   216,  1034,  1761,   222,  1010,  2008,  1011,  1767,
  1767,  1765,   158,  2008,  1767,  1000,  1773,  1771,   227,  1773,
  1773,  1000,  1786,  1777,   216,  1034,  1784,  1381,  1010,  1536,
  1556,  1011,  1747,  1786,  2008,  1794,  1792,   232,  1001,  1366,
  1786,  1794,  1000,  1802,  1802,     4,  1345,   165,  1345,  1599,
     6,  1810,  1808,    38,  1028,  1319,  1359,  1810,  1000,  1819,
  1813,   234,  1815,   176,  1817,   241,  1819,  1000,  1830,  1828,
  1001,    38,  1345,    10,  1345,    10,  1345,  1830,  1000,  1837,
  1835,    10,  1855,   999,  1837,  1000,  1848,  1841,   167,  1001,
  1848,  1001,     4,  1855,  1830,  1873,     6,  1855,  1851,  1001,
  1855,  1855,  1830,  1873,  1865,  1859,  1436,  1865,  1865,     4,
  1855,  1830,  1873,     6,  1873,  1870,  1493,  1001,  1416,  1873,
   117,  1617,  1881,  1879,   162,  1855,  1830,   999,  1881,  1000,
  1898,  1886,   249,  1002,  1006,  1890,  1022,  1898,  1006,  1896,
   254,  1009,    10,  1009,  1006,  1898,  1031,  1912,  1902,  1023,
  1912,  1907,  1024,   260,  1951,  1956,  1912,  1025,  1005,    10,
  1935,  1935,  1917,   263,  1001,   265,  1919,  1984,  1924,     4,
  1984,  1973,     6,  1928,   267,  1984,     6,  1933,     4,   272,
  1973,     6,  1935,   275,  1951,  1940,   263,  1001,   265,  1942,
  1984,  1947,     4,   272,  1973,     6,  1951,   267,  1005,     6,
  1956,  1954,   272,  1956,  1005,  1964,  1962,    10,  1005,    10,
  1005,  1964,  1000,  1973,  1968,     0,  1005,  1971,     2,  1005,
  1973,  1000,  1979,  1977,     0,   275,  1979,  1000,  1984,  1982,
    38,  1984,  1000,  1999,  1989,  1979,  1300,  1003,  1992,  1001,
  1964,  1997,     4,  1999,  1964,     6,  1999,   277,  2008,  2002,
   281,  2004,   285,  2006,   289,  2008,   292,  2041,  2017,  1010,
  1001,  1366,  1786,  1011,  1581,  1761,  2021,   296,  1001,  1366,
  2023,   299,  2027,   306,  1033,  1345,  2030,   313,  1761,  2032,
   321,  2037,   326,  1703,  1329,  1708,  2039,   333,  2041,   338,
  2168,  2048,  1027,  1010,  2008,  1011,  1734,  2050,  1007,  2058,
  1381,  1010,  1536,  1556,  1011,  1747,  1006,  2063,   347,  1035,
  1767,  1006,  2068,   354,  1029,  1819,  1006,  2073,   360,  1036,
  1727,  1006,  2078,  1386,   354,  1029,  1006,  2086,  1004,  1008,
  1010,  1436,  1011,  1608,  1006,  2090,   367,  1520,  1006,  2095,
    81,   147,  1837,  1006,  2105,  1010,  1810,  1458,  1011,  1589,
  1001,  1410,  1501,  1006,  2110,  1657,  1436,  1629,  1006,  2114,
   371,  1003,  1038,  2118,   379,  1015,  1006,  2127,   385,  1021,
  1703,  1329,  1696,   216,  1034,  1006,  2138,   388,  1001,  1416,
     4,  1345,   165,  1345,     6,  1714,  1006,  2142,   395,  1006,
  1017,  2148,   227,  1035,  1039,  1034,  1006,  2151,     8,  1881,
  2154,   400,  1006,  2158,   415,  1001,  1006,  2162,   422,  1003,
  1006,  2166,  1001,   430,  1019,  2168,  1006


   constant  integer  ss= 2041
   constant  integer  comment= 2; ! alt of p<SS> of %comment
   constant  integer  ownalt= 12; ! alt of p<SS> for owns
   constant  integer  eisss= X'00017F00'; ! Flag declarative ss alts
   ! MAY CHANGE WITH NEW SYNTAX
   constant  integer  array  opc(0:127)=
    0, M' JCC', M' JAT', M' JAF', 0(4),
    M' VAL', M' CYD', M'INCA', M'MODD', M'PRCL', M'   J', M' JLK', M'CALL',
    M' ADB', M' SBB', M'DEBJ', M' CPB', M' SIG', M' MYB', M' VMY', M'CPIB',
    M' LCT', M'MPSR', M'CPSR', M'STCT', M'EXIT', M'ESEX', M' OUT', M' ACT',
    M'  SL', M'SLSS', M'SLSD', M'SLSQ', M'  ST', M'STUH', M'STXN', M'IDLE',
    M' SLD', M' SLB', M'TDEC', M'INCT', M' STD', M' STB', M'STLN', M'STSF',
    M'   L', M' LSS', M' LSD', M' LSQ', M'RRTC', M' LUH', M'RALN', M' ASF',
    M'LDRL', M' LDA', M'LDTB', M' LDB', M'  LD', M'  LB', M' LLN', M' LXN',
    M' TCH', M'ANDS', M' ORS', M'NEQS', M'EXPA', M' AND', M'  OR', M' NEQ',
    M'  PK', M' INS', M'SUPK', M' EXP', M'COMA', M' DDV', M'DRDV', M'DMDV',
    M'SWEQ', M'SWNE', M' CPS', M' TTR', M' FLT', M' IDV', M'IRDV', M'IMDV',
    M' MVL', M'  MV', M'CHOV', M' COM', M' FIX', M' RDV', M'RRDV', M'RDVD',
    M' UAD', M' USB', M'URSB', M' UCP', M' USH', M' ROT', M' SHS', M' SHZ',
    M' DAD', M' DSB', M'DRSB', M' DCP', M' DSH', M' DMY', M'DMYD', M'CBIN',
    M' IAD', M' ISB', M'IRSB', M' ICP', M' ISH', M' IMY', M'IMYD', M'CDEC',
    M' RAD', M' RSB', M'RRSB', M' RCP', M' RSC', M' RMY', M'RMYD', M' PUT'

   routine  cnptf
!***********************************************************************
!*    Create New Page To File :- This is called when the output file   *
!*    is full and must be extended to a new page.                      *
!***********************************************************************
      if  filesizeptr<3 then  c 
       filesizeptr = filesizeptr+1 and  filesize = fstable(filesizeptr) else  c 
       filesize = filesize+fstable(3)
      changefilesize(workfile, filesize, eflag)
      if  eflag=261 start 
         ! V.M. hole is too small for the new file size.
         disconnect(workfile, eflag); if  eflag#0 then  fail(eflag, 5)
         changefilesize(workfile, filesize, eflag)
         if  eflag=0 start 
            writeaddress = writeaddress-conad
            connect(workfile, 3, 0, 0, rr, eflag)
            if  eflag#0 then  fail(eflag, 5)
            conad = rr_conad
            writeaddress = writeaddress+conad
            outrec == record(conad)
         finish 
      finish 
      if  eflag#0 then  fail(eflag, 5)
      outrec_filesize = filesize; ! Update file size in header.
   end 

   routine  transfer(integer  from, to)
!***********************************************************************
!*    Transfer copies the contents of OUTBUF from FROM to TO into the  *
!*    output file or channel.                                          *
!***********************************************************************
      integer  i, ch, last
      if  stream#terminal start 
         last = to-from+1+writeaddress-conad
         if  last>filesize then  cnptf
         outrec_dataend = last
      finish 
      for  i = from, 1, to cycle 
         ch = outbuf(i)&X'7F'
         if  ch&127=rs then  continue 
         if  ch=nl start 
            charsin = 0; line = line+1
            unless  stream=terminal start 
               write address = write address-1 while  c 
                write address>wa0 and  byteinteger(write address-1)=' '
            finish 
         finish  else  charsin = charsin+1
         if  stream=terminal then  printch(ch) else  c 
          byteinteger(writeaddress) = ch and  writeaddress = writeaddress+1
      repeat 
   end 

   routine  outstring(string  (40) text)
!***********************************************************************
!*    Outstring copies TEXT to the output file or channel.             *
!***********************************************************************
      integer  i, ch, last
      if  stream#terminal start 
         last = length(text)+writeaddress-conad
         if  last>filesize then  cnptf
         outrec_dataend = last
      finish 
      for  i = 1, 1, length(text) cycle 
         ch = charno(text, i)
         if  ch=nl then  charsin = 0 and  line = line+1 else  c 
          charsin = charsin+1
         if  stream=terminal then  printch(ch) else  c 
          byteinteger(writeaddress) = ch and  writeaddress = writeaddress+1
      repeat 
   end 

   routine  dupl(integer  char, integer  times)
!***********************************************************************
!*    Dupl copies CHAR, TIMES times to the output file or channel.     *
!***********************************************************************
      integer  i, last
      if  times<=0 then  return 
      charsin = charsin+times
      if  stream#terminal start 
         last = times+writeaddress-conad
         if  last>filesize then  cnptf
         outrec_dataend = last
      finish 
      for  i = 1, 1, times cycle 
         if  stream=terminal then  printch(char) else  c 
          byteinteger(writeaddress) = char and  writeaddress = writeaddress+1
      repeat 
   end 

   routine  insert(integer  chars, lsflag, rsflag)
!***********************************************************************
!*   This will place upto four characters into the OUTBUF buffer this  *
!*   includes the option of have spaces around the characters.         *
!***********************************************************************
      if  lsflag=true#inconst then  outbuf(obp) = ' ' and  obp = obp+1
      until  chars=0 cycle 
         outbuf(obp) = chars&X'FF'
         chars = chars>>8
         obp = obp+1
      repeat 
      if  rsflag=true#inconst then  outbuf(obp) = ' ' and  obp = obp+1
   end 




   routine  closedown(integer  success)
!***********************************************************************
!*     Closedown is called when the program is to terminate execution  *
!*     and is to print a suitable message and to close the output file *
!*     if any.                                                         *
!***********************************************************************
      if  success=true start 
         printstring(itos(line)." lines have been processed".snl)
      finish  else  start 
         printstring("Soap80 fails :- ".itos(errors))
         if  errors=1 then  printstring(" error.".snl) else  c 
          printstring(" errors.".snl)
      finish 
      ! Is there a file to close?
      if  stream#terminal start 
         outrec_dataend = writeaddress-conad
         trim(workfile, eflag)
         disconnect(workfile, eflag)
         if  stream=samefile start 
            if  errors>0 then  c 
             printstring("Output stored in ".workfile.", since ".infile. c 
             " contains errors.".snl) else  start 
               newgen(workfile, outf, eflag)
               if  eflag#0 start 
                  printstring("Attempt to create ".outf." failed because ". c 
                   failuremessage(eflag).snl)
                  printstring("Output stored in ".workfile.".".snl)
               finish 
            finish 
         finish  else  start 
            if  stream=device start 
               if  length(infile)>8 then  length(infile) = 8
               sendfile(workfile, outf, "Soap80: ".infile, 1, 0, eflag)
               if  eflag#0 then  fail(eflag, 5)
            finish 
         finish 
      finish 
      pprofile
      stop ; ! Exit from SOAP80.
   end 

   routine  punch
!***********************************************************************
!*     PUNCH is  for tranferring the contents of the OUTBUF array      *
!*   to the output file or channel, using TRANSFER, OUTSTRING and DUPL.*
!*                                                                     *
!*    PUNCH decides where to break a line if it is too long.           *
!***********************************************************************
      integer  lst, bk, i, ubp, lbp, bbp, tp, inn, ch, curlend
      inn = in
      inn = inn+1 if  1<<ssalt&eisss=0 and  p_istat=true
      if  ssalt#comment and  semicolon=false then  dupl(' ', p_tab(inn)-charsin)
      if  outbuf(obp-1)=';' then  semicolon = true else  semicolon = false
      if  semicolon=true and  p_line-20<charsin+obp then  c 
       semicolon = false and  outbuf(obp-1) = nl
      if  semicolon=true then  outbuf(obp) = ' ' and  obp = obp+1

      if  increm=true start 
         increm = false
         ! Is indenting value too near the line length limit?
         if  p_tab(in+1)+20>p_line then  fail(4, 2) else  in = in+1
      finish 

      lst = 1

      if  ssalt=comment start 
         ! Look for RS in comment.  If found, output as more than one line.
         cycle 
            if  chartype(sc(1))&rem=0 or  semicolon=true start 
               ! Comment does not start in column 1.
               if  semicolon!colon=false and  p_movecom=false then  c 
                dupl(' ', p_tab(inn)-charsin) else  dupl(' ', p_poscom-charsin)
            finish 
            i = lst
            i = i+1 while  i<obp and  outbuf(i)&127#rs
            ->final part if  i=obp
            transfer(lst, i-1)
            if  outbuf(i-1)&127=',' then  outstring(snl) else  c 
             outstring(percentc.snl)
            i = i+1 until  i=obp or  outbuf(i)#' '
            lst = i
         repeat 
      finish 

      cycle 
         ubp = p_line+lst-charsin-4; ! RHMOST BREAK POINT
         lbp = (ubp+lst)//2
         bbp = (ubp+3*lst)//4
         curlend = 0

         ! First check for nl in string const or list
         for  bk = lst, 1, ubp+3 cycle 
            exit  if  bk>=obp
            ch = outbuf(bk)
            if  ch&127=nl or  (ch&127=rs and  ssalt=ownalt and  c 
             p_lclist=true) then  ->printpart
         repeat 
         if  obp<ubp+3 then  exit ; ! 3 FOR " %C"
         for  bk = ubp, -1, bbp cycle ; ! CHECK FOR PRIMARY BREAK POINTS
            if  outbuf(bk)&bpoint#0 start 
               bk = bk+1 while  outbuf(bk+1)=' '
               ->printpart
            finish 
         repeat 
         for  bk = ubp, -1, bbp cycle ; ! CHECK FOR SECONDARY BREAK POINT
            if  outbuf(bk)&bpoint2#0 start 
               bk = bk+1 while  outbuf(bk+1)=' '
               ->printpart
            finish 
         repeat 
         for  bk = ubp, -1, bbp cycle 
            if  outbuf(bk)=',' then  ->printpart
         repeat 
         if  outbuf(ubp)&incurly#0 start ; ! IN A CURLY COMMENT
            curlend = 1
            for  bk = ubp, 1, obp-2 cycle 
               curlend = 0 and  exit  if  outbuf(bk)&incurly=0
            repeat 
            ! curlend indicates whether the curly comment goes to the end of the line.
            for  bk = ubp, -1, bbp cycle 
               if  outbuf(bk)&incurly=0 then  bk = bk-1 and  ->printpart
            repeat 
            ->final part if  curlend=1; ! Overlong curly comment.
            for  bk = ubp, 1, obp-2 cycle 
               if  outbuf(bk)&incurly=0 then  ->printpart
            repeat 
         finish 
         for  bk = ubp+1, -1, lbp cycle 
            if  outbuf(bk)=' ' and  outbuf(bk-1)&underline#0 then  ->printpart
         repeat 
         if  p_spacnam=false start ; ! MUST OMIT IF NAMES ARE SPACED
            for  bk = ubp+1, -1, lbp cycle 
               if  outbuf(bk)=' ' then  ->printpart
            repeat 
         finish 
         for  bk = ubp, -1, lbp cycle 
            if  outbuf(bk)='%' then  bk = bk-1 and  ->printpart
         repeat 
         for  bk = ubp, -1, lbp cycle 
            if  outbuf(bk)='.' or  outbuf(bk)=')' then  ->printpart
            if  outbuf(bk)='(' then  bk = bk-1 and  ->printpart
         repeat 
         if  outbuf(ubp)&instring#0 start 
            ! Break point is inside a string.
            for  bk = ubp, -1, bbp cycle 
               if  outbuf(bk)=',' or  outbuf(bk)='.' or  outbuf(bk)='=' then  c 
                ->printpart
            repeat 
            for  i = ubp, -1, lst+3 cycle 
               if  outbuf(i)=dquotes then  bk = i-1 and  ->printpart
            repeat 
            for  i = bk, -1, lst cycle 
               if  outbuf(i)=squotes start 
                  if  chartype(outbuf(i-1))&constart=0 then  bk = i-1 else  c 
                   bk = i-2
                  ->printpart
               finish 
            repeat 
            ! Break string.
            printstring("Line:".itos(line)." problem:")
            printsymbol(outbuf(i)) for  i = lst, 1, ubp
            newline
            tp = ubp-1
            transfer(lst, tp)
            outstring(""".".percentc.snl)
            dupl(' ', p_tab(inn)+p_icontin)
            outstring("""")
            lst = tp+1
            continue 
         finish  else  bk = ubp
         printstring("Line:".itos(line)." problem:")
         printsymbol(outbuf(i)) for  i = lst, 1, ubp
         newline
printpart:
         i = bk
         i = i-1 while  outbuf(i)=' ' or  outbuf(i)&127=rs
         transfer(lst, i)
         if  i<lst or  outbuf(i)&127#nl start ; ! NOT NATURAL BREAK
            if  outbuf(i)&127#',' and  outbuf(bk)#rs!128 and  curlend=0 then  c 
             outstring(" ".percentc)
            outstring(snl)
            dupl(' ', p_tab(inn)+p_icontin) if  inconst=false
            outstring("%") if  c 
             outbuf(bk+1)&underline#0 and  outbuf(bk+1)#rs!128
         finish 
         lst = bk+1
      repeat 
finalpart:
      transfer(lst, obp-1)
      obp = 1
   end 

   integer  function  nextnonsp(integer  print)
      ! If PRINT is True then ' ' or '%' or RS are transferred to the output
      ! buffer when encountered.
      integer  ch
      cycle 
         ch = sc(ptr)
         if  ch='{' start 
            outbuf(obp) = ' ' and  obp = obp+1 if  obp>1 and  print=false
            outbuf(obp) = '{'
            obp = obp+1; ptr = ptr+1
            cycle 
               ch = sc(ptr)
               outbuf(obp) = ch!incurly
               obp = obp+1
               ptr = ptr+1
            repeat  until  ch='}'
            continue 
         finish 
         exit  unless  ch=' ' or  ch='%' or  ch&127=rs
         if  print=true then  outbuf(obp) = ch and  obp = obp+1
         ptr = ptr+1
      repeat 
      result  = ch
   end 

   routine  getline(integer  initptr)
!***********************************************************************
!*    GETLINE :- take from the input file and processes the data and   *
!*               it into the array SC.                                 *
!*                                                                     *
!*    The following processing is done:                                *
!*       1) All delimiters have 128 added to each character in the word*
!*       2) Lines are joined togther if there is a %c or ',' at the end*
!*          of the first line. The newline position is marked by RS.   *
!***********************************************************************
      constant  byte  integer  array  itoi(0:255)= c 
                  32(10),10,32(14),25,26,32(5),
                  32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
                  48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
                  64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
                  80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
                  96,97,98,99,100,101,102,103,104,105,106,107,108,109,
                  110,111,112,113,114,115,116,117,118,119,
                  120,121,122,123,124,125,126,32,
                  26(5),10,26(10),
                  26(16),
                  26(14),92,38,
                  26(11),35,26(4),
                  26(16),
                  26(9),35,26(5),94,
                  26(32)
      half  integer  array  scurl, ecurl(1:20)
      integer  in keyword, char, p, ncurl
      own  integer  strdelimiter

      if  initptr=1 then  startline = inptr
      ptr = initptr

      cycle 
         in keyword = false
         ncurl = 0
         cycle 
            if  ptr>ccsize then  fail(1, 1) and  exit 
            if  inptr>dataend then  fail(2, 1)
            char = itoi(byteinteger(inptr))
            inptr = inptr+1

            if  char=nl start 
               inline = inline+1
               sc(ptr) = nl
               ptr = ptr+1
               exit 
            finish 

            if  str=true start 
               sc(ptr) = char; ptr = ptr+1
               if  char=strdelimiter then  str = false
               continue 
            finish 

            if  chartype(char)&endst#0 then  c 
             sc(ptr) = char and  ptr = ptr+1 and  exit 

            ! Deal with curly bracket comments noting start so as to permit
            ! continuations of the form ...,{...}.
            ! Note that any missing closing brace is replaced.
            if  char='{' start 
               ncurl = ncurl+1; scurl(ncurl) = ptr
               sc(ptr) = char; ptr = ptr+1
               cycle 
                  char = itoi(byteinteger(inptr))
                  if  char=nl then  char = '}' else  inptr = inptr+1
                  if  char='}' then  exit 
                  sc(ptr) = char
                  ptr = ptr+1
               repeat 
               ecurl(ncurl) = ptr
            finish 

            if  in keyword=true start 
               if  chartype(char)&letter=0 then  in keyword = false else  c 
                sc(ptr) = onecase(char)!underline and  ptr = ptr+1 and  c 
                continue 
            finish 

            if  char='%' then  in keyword = true

            if  char=squotes or  char=dquotes start 
               str = true; strdelimiter = char
            finish 

            sc(ptr) = char
            ptr = ptr+1
         repeat 

         if  char=nl start ; ! TRAILING SPACES CHECK
            ptr = ptr-1 while  ptr>2 and  sc(ptr-2)=' '
            sc(ptr-1) = nl
            if  str=false start 
               p = ptr-2
               while  ncurl>0 and  ecurl(ncurl)=p cycle 
                  ! Step past curly bracket.
                  p = scurl(ncurl)-1; ncurl = ncurl-1
                  p = p-1 while  p>0 and  sc(p)=' '
               repeat 
               ! Now p points at character determining continuation.
               if  p>0 start 
                  char = sc(p)
                  if  char=',' start 
                     sc(ptr-1) = rs!128
                     continue 
                  finish 
                  if  char='C'+underline start 
                     if  p>1 and  sc(p-1)='%' then  sc(p-1) = ' '
                     sc(p) = ' '
                     sc(ptr-1) = rs
                     continue 
                  finish 
                  if  char&127=rs then  sc(ptr-1) = rs!128 and  continue 
               finish 
            finish 
         finish 
         exit 
      repeat 
      ptr = initptr

   end 

   integer  function  compare(integer  test)
      integer  i, ch, key, j

      for  i = 1, 1, clett(test) cycle 
         ch = nextnonsp(inconst)
         if  ch#clett(i+test) then  result  = false
         ptr = ptr+1
      repeat 

      if  test=offile or  test=ofprogram then  stop = true

      if  test=comma then  insert(',', false, p_spcomma) and  result  = true
      if  test=equals start 
         if  ssalt=ownalt then  inconst = p_lclist
         ! If in own or const declaration and p_lclist is set, then set
         ! inconst to true.  The effect of this is leave the declaration
         ! unformatted.  Inconst is not set earlier as we do not wish the
         ! leading spaces in the statement to be preserved - i.e. the first
         ! line of the statement is indented with the rest of the program.
         insert('=', p_spacass, p_spacass)
         result  = true
      finish 
      if  p_expkey=true start 
         test = function if  test=fn
         test = constant if  test=const
      finish 
      if  obp=1 or  (outbuf(obp-1)&underline=0 and  c 
       outbuf(obp-1)&127#'%') then  key = false else  key = true
      ! Current state of outbuf.
      for  i = 1, 1, clett(test) cycle 
         ch = clett(test+i)
         if  ch<underline and  key=true start 
            outbuf(obp) = ' '
            obp = obp+1
            key = false
         finish  else  if  ch>underline start 
            if  key=false start 
               if  obp>1 and  '('#outbuf(obp-1)#' ' then  c 
                outbuf(obp) = ' ' and  obp = obp+1
               outbuf(obp) = '%'
               obp = obp+1
               key = true
            finish  else  if  i=1 and  p_sepkey=true then  c 
             outbuf(obp) = ' ' and  outbuf(obp+1) = '%' and  obp = obp+2
         finish 

         if  ch&underline#0 and  p_uckey=false and  ch#rs!128 then  ch = ch!32
         outbuf(obp) = ch
         obp = obp+1
      repeat 

      if  (test=offile or  test=ofprogram) and  p_sepkey=true start 
         if  test=offile then  j = 4 else  j = 7
         obp = obp+2
         outbuf(obp-i) = outbuf(obp-i-2) for  i = 1, 1, j
         outbuf(obp-j-2) = ' '
         outbuf(obp-j-1) = '%'
      finish 
      if  test=if or  test=unless or  test=while or  test=until or  c 
       test=else or  test=then then  outbuf(obp-1) = ch!bpoint
      if  test=and or  test=or then  outbuf(obp-1) = ch!bpoint2
      result  = true
   end 

   integer  function  check(integer  pos)
      integer  defend, subdefend, subdefstart, res, item, rsptr, z,
        strdelimiter, ch, rsobj, alt, i, j
      constant  string  (19) fes="FINISH %ELSE %START"
      own  integer  uci
      own  integer  depth=0
      switch  bip(999:1039); ! Built-in phrases.

      alt = 0
      depth = depth+1; ! Depth of recursion in check.
      ssalt = 0 if  depth=1; ! Initialise ssalt if in top-level call.

      rsptr = ptr; rsobj = obp
      defend = symbol(pos)
      pos = pos+1
      while  pos<defend cycle 
         alt = alt+1
         if  depth=1 start ; ! Outer level - i.e. trying ss alternatives.
            ssalt = ssalt+1
            inconst = false
         finish 
         subdefend = symbol(pos)
         pos = pos+1
         res = true
         subdefstart = pos
         while  pos<subdefend cycle 
            item = symbol(pos)
            if  999<=item<1300 then  ->bip(item)
            if  item<999 then  res = compare(item)
            if  item>=1300 then  res = check(item)
            pos = pos+1
            ->bypass

bip(999):
            pos = subdefstart; ! Star function.
            rsptr = ptr; rsobj = obp
            ->bypass

bip(1000):
            depth = depth-1; result  = true; ! Zero function.

bip(1001):
            ! Name
            ch = nextnonsp(inconst)
            j = ptr; ptr = ptr+1; i = obp
            if  chartype(ch)&letter=0 then  res = false and  ->inc
            if  chartype(ch)&constart#0 and  c 
             nextnonsp(inconst!p_spacnam)=squotes then  res = false and  ->inc
            ptr = j; obp = i; ! AVOID FUNNY SPACING ON 1 LETTER NAMES
            j = outbuf(obp-1); ! LAST CHAR OUT
            if  j>128 or  chartype(j)&letter#0 or  j=')' then  c 
             outbuf(obp) = ' ' and  obp = obp+1
            while  chartype(ch)&(letter!number)#0 cycle 
               if  chartype(ch)&letter#0 and  p_lcasnam=false start 
                  ! Letter case in names to be controlled by P_UCKEY.
                  if  p_uckey=true then  ch = ch&(¬32) else  ch = ch!32
               finish 
               outbuf(obp) = ch; obp = obp+1
               j = obp; ! Position after latest character of name.
               ptr = ptr+1
               ch = nextnonsp(inconst!p_spacnam)
            repeat 
            ! Now j gives posn in outbuf after last character of name, and obp
            ! gives next free posn in outbuf.
            if  p_spacnam=true and  inconst=false and  j<obp start 
               ! Throw away bytes after name, apart from curly comments.
               i = j
               cycle 
                  i = i+1 while  i<obp and  outbuf(i)&127#'{'
                  exit  if  i=obp
                  if  j<i start 
                     outbuf(j) = ' '
                     cycle 
                        j = j+1
                        outbuf(j) = outbuf(i)
                        i = i+1
                     repeat  until  outbuf(j)&127='}'
                  finish  else  start 
                     j = j+1 until  outbuf(j)&127='}'
                     i = j+1
                  finish 
                  j = j+1
               repeat 
               obp = j
            finish 
            ->inc
bip(1005):
            ! N - Number.
            ch = nextnonsp(inconst)
            if  chartype(ch)&number=0 then  res = false and  ->inc
bip(1002):
            ! Iconst.
bip(1003):
            ! Const.
            ch = nextnonsp(inconst)
            ptr = ptr+1
            res = false and  ->inc unless  c 
             chartype(ch)&(quotes!constfirst)#0 or  c 
             (chartype(ch)&constart#0 and  nextnonsp(inconst)=squotes)
            if  outbuf(obp-1)>128 or  chartype(outbuf(obp-1))&letter#0 then  c 
             outbuf(obp) = ' ' and  obp = obp+1
            if  chartype(ch)&constfirst=0 start 
               if  chartype(ch)&constart#0 start 
                  outbuf(obp) = ch; obp = obp+1
                  strdelimiter = nextnonsp(inconst)
                  ptr = ptr+1
               finish  else  strdelimiter = ch
               outbuf(obp) = strdelimiter; obp = obp+1
               cycle 
                  if  sc(ptr)=strdelimiter start 
                     outbuf(obp) = strdelimiter!instring
                     if  sc(ptr+1)#strdelimiter then  exit 
                     outbuf(obp+1) = strdelimiter!instring
                     obp = obp+2; ptr = ptr+2
                  finish  else  start 
                     ch = sc(ptr)
                     outbuf(obp) = ch!instring
                     obp = obp+1; ptr = ptr+1
                     if  ch=nl start 
                        getline(ptr)
                     finish 
                  finish 
               repeat 
               ptr = ptr+1; obp = obp+1
            finish  else  start 
               ptr = ptr-1
               cycle 
                  cycle 
                     exit  if  chartype(ch)&constcont=0
                     outbuf(obp) = ch; obp = obp+1
                     ptr = ptr+1
                     ch = nextnonsp(inconst)
                  repeat 
                  if  '_'#ch#'@' then  exit 
                  if  ch='@' then  j = number else  j = number!letter
                  ! Second part of @ and radix consts
                  until  chartype(ch)&j=0 cycle 
                     outbuf(obp) = ch; obp = obp+1
                     ptr = ptr+1
                     ch = nextnonsp(inconst)
                  repeat 
               repeat 
            finish 
            ->inc
bip(1004):! Phrase check extended type
            ch = nextnonsp(inconst)
            res = false unless  c 
             ch>underline and  X'80000000'>>(ch&31)&X'20C83000'#0
            ->inc
bip(1038):! Include
bip(1006):! S - End statement.
            ch = nextnonsp(inconst)
            if  chartype(ch)&endst=0 then  res = false and  ->inc
            obp = obp-1 while  obp>1 and  outbuf(obp-1)=' '
            outbuf(obp) = ch; obp = obp+1
            ->inc
bip(1007):! Text - comment string.
            ch = nextnonsp(inconst)
            if  chartype(ch)&rem=0 then  res = false and  ->inc
            if  ch&underline#0 and  (outbuf(obp-1)&underline=0) then  c 
             outbuf(obp) = '%' and  obp = obp+1
            outbuf(obp) = ch; obp = obp+1
            ptr = ptr+1
            if  ch='C'+underline start 
               outbuf(obp-1) = ch!32 if  p_uckey=false
               for  i = 2, 1, 7 cycle 
                  ch = nextnonsp(inconst)
                  if  ch#keycom(i)+underline then  res = false and  ->inc
                  if  p_uckey=false then  ch = ch!32
                  outbuf(obp) = ch
                  obp = obp+1
                  ptr = ptr+1
               repeat 
            finish 
            str = false
            cycle 
               while  sc(ptr)#nl and  (str=true or  sc(ptr)#';') cycle 
                  ch = sc(ptr)
                  if  ch=squotes or  ch=dquotes start 
                     if  str=false then  c 
                      strdelimiter = ch and  str = true else  if  c 
                      ch=strdelimiter then  str = false
                  finish 
                  if  ch&underline#0 and  p_uckey=false and  ch#rs!128 then  c 
                   ch = ch!32
                  outbuf(obp) = ch; obp = obp+1
                  ptr = ptr+1
               repeat 
               outbuf(obp) = sc(ptr); obp = obp+1
               ptr = ptr+1
               exit  if  outbuf(obp-1)=nl
               ! Semi-colon terminated input - carry on reading.
               getline(1)
            repeat 
            str = false
            ->inc
bip(1009):! N255 - Test string declaration length.
            ch = nextnonsp(inconst)
            unless  '0'<=ch<='9' then  res = false and  ->inc
            z = 0
            while  '0'<=ch<='9' cycle 
               z = z*10+ch-'0'
               outbuf(obp) = ch; obp = obp+1
               ptr = ptr+1
               ch = nextnonsp(inconst)
            repeat 
            if  z>255 then  res = false
            ->inc
bip(1012):! Readline?
            ch = nextnonsp(inconst)
            ! Deal with "FRED(1:10) = <nl> .. init vals .." constructions.
            if  ch=nl start 
               outbuf(obp) = nl; obp = obp+1
               sc(ptr) = rs!128
               getline(ptr+1)
            finish 
            ->inc
bip(1015):! Down.
            level = level+1
            bheading = true
            if  p_iblock=true then  increm = true
            ->inc
bip(1016):! Up.
            level = level-1
            bheading = true
            if  p_iblock=true and  in>0 then  in = in-1
            ->inc
bip(1019):! Colon - Is previous character a colon ':'?
            if  sc(ptr-1)#':' then  res = false and  ->inc
            if  charsin>0 then  outstring(snl)
            ch = nextnonsp(inconst)
            transfer(1, obp-1)
            obp = 1
            if  p_seplab=true and  ch#nl then  outstring(snl)
            inlabel = true
            ->inc
bip(1022):! Setnem.
            ch = nextnonsp(inconst)
            z = M'    '
            while  chartype(ch)&letter#0 cycle 
               z = z<<8!onecase(ch)
               outbuf(obp) = ch; obp = obp+1
               ptr = ptr+1
               ch = nextnonsp(inconst)
            repeat 

            unless  ch='_' and  z#M'    ' then  res = false and  ->inc
            outbuf(obp) = '_'; obp = obp+1
            uci = z
            ptr = ptr+1
            ->inc
bip(1023):! Primform
            for  i = 7, 1, 127 cycle 
               ->pfnd if  opc(i)=uci
            repeat 
            res = false
            ->inc
pfnd:! Mnemonic found
            res = false if  8<=i>>3<=11 and  i&7<=3
            ->inc
bip(1024):! Sectform.
            for  i = 64, 8, 88 cycle 
               for  j = 0, 1, 3 cycle 
                  if  opc(i+j)=uci then  ->inc
               repeat 
            repeat 
            res = false
            ->inc
bip(1025):! Tertform.
            for  i = 3, -1, 1 cycle 
               if  opc(i)=uci then  ->inc
            repeat 
            res = false
            ->inc
bip(1026):! Op.
            ch = nextnonsp(inconst)
            ptr = ptr+1
            unless  32<ch<127 and  X'80000000'>>(ch&31)&X'4237000A'#0 then  c 
             res = false and  ->inc

            if  ch='&' or  ch='+' or  ch='-' then  c 
             insert(ch, p_spacop, p_spacop) and  ->inc

            if  ch='*' start 
               if  ch#nextnonsp(inconst) then  c 
                insert('*', p_spacop, p_spacop) and  ->inc
               ptr = ptr+1; j = ptr
               ch = nextnonsp(inconst)
               ptr = ptr+1
               if  M'*'=ch=nextnonsp(inconst) then  c 
                insert(M'****', p_spacop, p_spacop) and  ptr = ptr+1 and  ->inc
               insert(M'**', p_spacop, p_spacop)
               ptr = j; ->inc
            finish 

            if  ch='/' start 
               if  ch#nextnonsp(inconst) then  c 
                insert('/', p_spacop, p_spacop) and  ->inc
               insert(M'//', p_spacop, p_spacop)
               ptr = ptr+1; ->inc
            finish 

            if  ch='!' start 
               if  ch#nextnonsp(inconst) then  c 
                insert('!', p_spacop, p_spacop) and  ->inc
               insert(M'!!', p_spacop, p_spacop)
               ptr = ptr+1; ->inc
            finish 

            if  ch='.' then  outbuf(obp) = '.' and  obp = obp+1 and  ->inc
            if  ch=nextnonsp(inconst)='>' start 
               insert(M'>>', p_spacop, p_spacop)
               ptr = ptr+1
               ->inc
            finish 

            if  ch=nextnonsp(inconst)='<' start 
               insert(M'<<', p_spacop, p_spacop)
               ptr = ptr+1
               ->inc
            finish 

            if  ch='¬' start 
               if  ch#nextnonsp(inconst) then  c 
                insert('¬', p_spacop, p_spacop) and  ->inc
               insert(M'¬¬', p_spacop, p_spacop)
               ptr = ptr+1; ->inc
            finish 

            res = false; ->inc

bip(1027):! Chui.
            ch = nextnonsp(inconst)
            if  chartype(ch)&letter=0 and  ch#'-' and  c 
             X'80000000'>>(ch&31)&X'14043000'=0 then  res = false
            ->inc
bip(1028):! +'.
            ch = nextnonsp(inconst)
            if  ch='+' or  ch='-' or  ch='¬' or  ch=X'7E' then  c 
             insert(ch, p_spacop, p_spacop) and  ptr = ptr+1
            ->inc
bip(1031):! Ucwrong (unknown user code format - allow it through).
            cycle 
               ch = nextnonsp(inconst)
               outbuf(obp) = ch; obp = obp+1
               ->inc if  chartype(ch)&endst#0
               ptr = ptr+1
            repeat 
bip(1030):! ,'.
            ch = nextnonsp(inconst)
            res = false if  ch=')'
            if  res=true then  insert(',', false, p_spcomma)
            if  ch=',' then  ptr = ptr+1
            ->inc
bip(1032):! Chcomp.
bip(1037):! Comp2
            ch = nextnonsp(inconst)
            ptr = ptr+1
            unless  32<ch<=92 and  X'80000000'>>(ch&31)&X'1004000E'#0 then  c 
             res = false and  ->inc
            if  ch='=' start 
               if  nextnonsp(inconst)=ch then  c 
                ptr = ptr+1 and  insert(M'==', p_spacop, p_spacop) and  ->inc
               insert('=', p_spacop, p_spacop)
               ->inc
            finish 
            if  ch='#' start 
               if  nextnonsp(inconst)=ch then  c 
                ptr = ptr+1 and  insert(M'##', p_spacop, p_spacop) and  ->inc
               insert('#', p_spacop, p_spacop)
               ->inc
            finish 
            if  ch='¬' and  nextnonsp(inconst)='=' start 
               ptr = ptr+1
               if  nextnonsp(inconst)='=' then  c 
                ptr = ptr+1 and  insert(M'==¬', p_spacop, p_spacop) and  ->inc
               insert(M'=¬', p_spacop, p_spacop)
               ->inc
            finish 
            if  ch='>' start 
               if  nextnonsp(inconst)='=' then  c 
                ptr = ptr+1 and  insert(M'=>', p_spacop, p_spacop) and  ->inc
               insert('>', p_spacop, p_spacop)
               ->inc
            finish 
            if  ch='<' start 
               if  nextnonsp(inconst)='=' then  c 
                ptr = ptr+1 and  insert(M'=<', p_spacop, p_spacop) and  ->inc
               if  nextnonsp(inconst)='>' then  c 
                ptr = ptr+1 and  insert(M'><', p_spacop, p_spacop) and  ->inc
               insert('<', p_spacop, p_spacop)
               ->inc
            finish 
            if  ch='-' and  nextnonsp(inconst)='>' then  c 
             ptr = ptr+1 and  insert(M'>-', p_spacop, p_spacop) and  ->inc
            res = false
            ->inc
bip(1033):! Assop.
            ch = nextnonsp(inconst)
            ptr = ptr+1
            if  ch='=' start 
               if  nextnonsp(inconst)='=' then  c 
                ptr = ptr+1 and  insert(M'==', p_spacass, p_spacass) and  ->inc
               insert('=', p_spacass, p_spacass)
               ->inc
            finish 
            if  ch='<' and  nextnonsp(inconst)='-' then  c 
             ptr = ptr+1 and  insert(M'-<', p_spacass, p_spacass) and  ->inc
            if  ch='-' and  nextnonsp(inconst)='>' then  c 
             ptr = ptr+1 and  insert(M'>-', p_spacass, p_spacass) and  ->inc
            res = false
bip(1008):! Bighole.
            ->inc
bip(1010):! Hole.
bip(1011):! Mark.
            ->inc
bip(1013):! Alias.
            ch = nextnonsp(inconst)
            ptr = ptr+1
            if  ch#'"' then  res = false and  ->inc
            outbuf(obp) = ' '; obp = obp+1
            outbuf(obp) = '"'; obp = obp+1
            cycle 
               if  sc(ptr)='"' start 
                  outbuf(obp) = '"'!instring
                  if  sc(ptr+1)#'"' then  exit 
                  outbuf(obp+1) = '"'!instring
                  obp = obp+2; ptr = ptr+2
               finish  else  start 
                  ch = sc(ptr)
                  outbuf(obp) = ch!instring
                  obp = obp+1; ptr = ptr+1
                  getline(ptr) if  ch=nl
               finish 
            repeat 
            ptr = ptr+1; obp = obp+1
            ->inc
bip(1014):! Dummyapp.
bip(1017):! Liston.
bip(1018):! List off.
bip(1020):! Note const.
bip(1021):! Trace.
            ->inc
bip(1039):! Dummy start
            if  p_expkey=true start ; ! Expand %else to %finish %else %start
               obp = obp-4
               for  i = 1, 1, 19 cycle 
                  j = charno(fes, i)
                  continue  if  p_sepkey=false and  (j=' ' or  j='%')
                  j = j!32 if  p_uckey=false and  'A'<=j<='Z'
                  outbuf(obp) = j; obp = obp+1
               repeat 
            finish 
bip(1029):! Note cycle
bip(1034):! Note start
            increm = true; ->inc
bip(1035):! Note finish
bip(1036):! Note repeat
            if  in>0 then  in = in-1; ->inc
inc:
            pos = pos+1
bypass:
            if  res=false start 
               pos = subdefend
               obp = rsobj
               if  ptr>maxptr then  maxptr = ptr and  maxitem = item
               ptr = rsptr
            finish 
         repeat 
         if  res=true then  depth = depth-1 and  result  = true
      repeat 
      ptr = rsptr; obp = rsobj
      depth = depth-1
      result  = false
   end 


!***********************************************************************
!*                                                                     *
!*                Main calling routine.                                *
!*                                                                     *
!***********************************************************************
   opt(s, p); ! Call option setting routine to set parameters.
   connect(infile, 0, 0, 0, rec, eflag); ! Open input file.
   if  eflag#0 then  fail(eflag, 5)
   if  rec_filetype#charfile then  setfname(infile) and  fail(267, 5)
   inptr = rec_conad+rec_datastart; ! Start of data.
   dataend = rec_conad+rec_dataend; ! End of data.

   ! Set output stream, possibilities are:
   ! Terminal, file, same file or output device.
   if  outf=".OUT" then  stream = terminal else  start 
      if  infile=outf then  stream = samefile else  start 
         if  charno(outf, 1)='.' start 
            if  devcode(outf)<=0 start 
               ! Invalid output device.
               setfname(outf)
               fail(264, 5)
            finish  else  stream = device
         finish  else  stream = file
      finish 
   finish 

   ! Create tempory output file?
   if  stream=samefile or  stream=device then  workfile = "T#".nexttemp else  c 
    workfile = outf
   if  stream#terminal start 
      filesizeptr = 1
      filesize = fstable(filesizeptr)
      outfile(workfile, filesize, 0, 0, conad, eflag)
      if  eflag#0 then  fail(eflag, 5)
      outrec == record(conad)
      writeaddress = conad+outrec_datastart; wa0 = write address
      outrec_filetype = charfile
      ! Rest of record elements to be fill in at end of indentation.
   finish 

   outbuf(0) = 0; sc(0) = 0
   level = 0; obp = 1; in = 0
   inline = 1; line = 0 {output line}
   errors = 0; erptr = 0; charsin = 0
   str = false
   stop = false; semicolon = false; increm = false; inlabel = false
   ersave = false
   if  p_uckey=true then  percentc = "%C" else  percentc = "%c"
   cycle 
      bheading = false
      maxptr = 0
      ! Is there more to analyse in this statement.
      colon = inlabel
      if  inlabel=false then  getline(1) else  inlabel = false
      if  check(ss)=false start 
         printstring(snl."Syntax analysis fails on input line ".itos(inline-1))
         printstring(" (output line ".itos(line+1).")".snl)
         z = 1
         while  chartype(sc(z))&endst=0 cycle 
            if  sc(z)&127=rs then  newline else  printch(sc(z)&127)
            z = z+1
         repeat 
         if  sc(z)=';' then  printch(';')
         newline
         spaces(maxptr-1); printch('!'); newline
         startline = startline+1 while  byteinteger(startline)=' '
         if  stream#terminal start 
            obp = 1
            ! Line failed - Input line to output routine.
            z = byteinteger(startline)
            while  chartype(z)&endst=0 cycle 
               if  chartype(z)&quotes#0 start 
                  strdelimiter = z
                  outbuf(obp) = strdelimiter; obp = obp+1
                  startline = startline+1
                  z = byteinteger(startline)
                  while  z#strdelimiter cycle 
                     outbuf(obp) = z
                     obp = obp+1; startline = startline+1
                     z = byteinteger(startline)
                  repeat 
               finish 
               outbuf(obp) = z
               obp = obp+1; startline = startline+1
               z = byteinteger(startline)
            repeat 
            outbuf(obp) = z; obp = obp+1
            punch
         finish 
         str = false
         errors = errors+1
      finish  else  start 
         if  inlabel=false then  punch
      finish 

      if  stop=true start 
         if  errors=0 then  closedown(true) else  closedown(false)
      finish 
   repeat 
   ! DOES NOT  COME THROUGH HERE

   routine  fail(integer  type, action)
      if  action#5 start 
         if  action&2=0 then  c 
          printstring(snl."*** Error: ") and  errors = errors+1 else  c 
          printstring(snl."*** Warning: ")
      finish 

      if  action&4=0 start 
         printstring(fault(type).snl)
         printstring("*** In input line ".itos(inline)." (output line ".itos c 
          (line).")".snl)
      finish  else  printstring("*** Soap80 fails -".failuremessage(type)) c 
       and  stop 

      if  action&1=1 then  closedown(false)
   end 

   routine  opt(string  (255) parm, record  (pformat) name  p)
!***********************************************************************
!*    THIS ROUTINE PROCESSES THE USER OPTION LIST                      *
!***********************************************************************
      routine  spec  readline
      routine  spec  setline
      integer  function  spec  stoi(string  name  snum)
      routine  spec  ask(integer  optno)
      integer  i, j, temp, flag, prof vsn
      string  (80) line, option, value, filename
      constant  integer  prog vsn= 3
      switch  prof(0:prog vsn)
      external  routine  spec  read profile(string  (11) key, name  info,
        integer  name  version, uflag)
      external  routine  spec  write profile(string  (11) key, name  info,
        integer  name  version, uflag)

      read profile("Soap80key", p, prof vsn, flag)
      if  flag>4 start 
         printstring( c 
          "Failed to read file SS#PROFILE.  Defaults options assumed.".snl)
      finish 

      ->prof(prof vsn)

      ! In the following profile-handling code, we work with array p_a
      ! (alternative format) rather than the actual option names (p_sepkey
      ! etc.).  This is because the p_a operations remain valid even if the
      ! record format is subsequently changed.

prof(0):
      ! Code to set up profile vsn 1 data:
      ! This consists of 14 options followed by 21 tab values.

      p_a(1) = 80; ! line - lines are broken into two if length is greater than 80.
      p_a(2) = 3; ! icontin - continuation of line have an addition indentation of 3.
      p_a(3) = 41; ! poscom - position for right hand comments.
      p_a(4) = true; ! movecom - main comment are indented to POSCOM.
      p_a(5) = true; ! uckey - keywords output in upper case.
      p_a(6) = false; ! sepkey - adjacent keywords are compounded.
      p_a(7) = true; ! lcasnam - case of names left alone.
      p_a(8) = true; ! spacnam - spaces are left within names.
      p_a(9) = true; ! spacass - spaces are added round assignment operators.
      p_a(10) = false; ! spacop - spaces are not added round other operators.
      p_a(11) = true; ! lclist - const lists to be left alone.
      p_a(12) = true; ! iblock - block contents are indented w.r.t. block heading.
      p_a(13) = false; ! istat - statements are aligned with declarations.
      p_a(14) = false; ! seplab -  Labels and statements may occupy the same line.
      ! Set default indentation values.
      p_a(i+15) = 3*i for  i = 0, 1, 10
      p_a(i+15) = 5*i-20 for  i = 11, 1, 20

prof(1):
      ! Code to set up profile vsn 2 data:
      ! This consists of 15 options followed by 21 tab values.
      p_a(i) = p_a(i-1) for  i = 36, -1, 16; ! Move tab values down to make room.
      printstring("**New parameter available: SPCOMMA".snl)
      printstring("      Y : One space character inserted after commas.".snl)
      printstring( c 
       "      N : No space character inserted after commas (default).".snl.snl)
      p_a(15) = false; ! spcomma - default false.
prof(2):
      ! Code to set up profile vsn 3 data:
      ! This consists of 21 tab values followed by 16 options.
      begin 
         byte  integer  array  tab(0:20)
         tab(i) = p_a(i+16) for  i = 0, 1, 20; ! Copy tab values out.
         p_a(i+21) = p_a(i) for  i = 1, 1, 6; ! Move options down.
         ! Item _a(28) will be the new parameter (expkey).
         p_a(i+22) = p_a(i) for  i = 7, 1, 15; ! Move options down.
         p_a(i+1) = tab(i) for  i = 0, 1, 20; ! Copy tab values back.
      end 
      printstring("**New parameter available: EXPKEY".snl)
      printstring( c 
       "      Y : Keywords %FN, %CONST and (sometimes) %ELSE expanded.".snl)
      printstring("      N : %FN, %CONST and %ELSE left alone (default).". c 
       snl.snl)
      p_a(28) = false; ! expkey default - false.

      ! The following two lines should always be just before the final 'prof'
      ! switch label.
      prof vsn = prog vsn
      write profile("Soap80key", p, prof vsn, flag)
prof(3):

      ! Split up parameters and change default values.
      if  parm->filename.(",").outf start 
         unless  outf->outf.(",").parm then  parm = ""
      finish  else  filename = parm and  outf = parm and  parm = ""
      infile = filename
      if  outf="" then  outf = filename
      if  parm="" then  return 


      temp = charno(parm, length(parm))
      if  temp#'*' and  temp#'?' then  parm = parm.",END"
      prompt("Soap80: ")
      cycle 
         if  parm="" then  readline else  setline
         if  line="END" or  line=".END" then  return 
         ! End of parameter settings.
         if  line="GO" or  line=".GO" then  return 
         ! End of parameter settings.
         if  line="STOP" or  line=".STOP" then  stop ; ! Abandon Soap80.

         if  line="SAVE" or  line=".SAVE" start 
            write profile("Soap80key", p, prof vsn, flag)
            printstring("Profile file SS#PROFILE created and cherished.".snl) c 
              if  flag=1
         finish  else  if  line="?" start 
            ! Print options so far.
            printstring( c 
             "Option name:{current setting}Meaning of current setting".snl)
            for  i = 1, 1, maxopt cycle 
               printstring(optname(i))
               spaces(7-length(optname(i)))
               printstring(":{")
               j = p_optarr(i)
               if  j=false then  printsymbol('N') else  if  j=true then  c 
                printsymbol('Y') else  printstring(itos(j))
               j = 1 if  j>0
               printstring("}".optmess(j, i).snl)
            repeat 
            printstring("TAB    :{")
            for  i = 1, 1, 20 cycle 
               printstring(itos(p_tab(i)))
               printsymbol(':') unless  i=20
            repeat 
            printsymbol('}')
            newline
            printstring("        Indenting values".snl)
            printstring( c 
             "SAVE     : Save current option settings, for defaults henceforth.
GO or END: Cause SOAP80 to start processing the input.
STOP     : Cause SOAP80 to stop immediately.")
            newline
         finish  else  start 
            if  line->option.("=").value and  value#"" start 
               flag = 0
               for  i = 1, 1, maxopt cycle 
                  continue  unless  option=optname(i)
                  flag = 1; ! Option identified.
                  if  value="?" start 
                     printstring(optname(i)); spaces(7-length(optname(i)))
                     printstring(":{")
                     j = p_optarr(i)
                     if  j=false then  printsymbol('N') else  if  c 
                      j=true then  printsymbol('Y') else  printstring(itos(j))
                     j = 1 if  j>0
                     printstring("}".optmess(j, i).snl)
                  finish  else  start 
                     if  i<=numopt start ; ! Numerical value.
                        temp = stoi(value)
                        if  option="LINE" and  (temp<30 or  temp>160) start 
                           printstring( c 
                            "Bad line length - Only from 30 to 160".snl)
                           exit 
                        finish 
                        temp = -1 if  temp>255
                        if  temp=-1 then  c 
                         printstring(value." - ".failure message(320)) else  c 
                         p_optarr(i) = temp
                     finish  else  ask(i)
                  finish 
                  exit 
               repeat 
               continue  if  flag=1; ! Cycle found option name.
               if  option="TAB" start 
                  ! Set indenting value.
                  if  value="?" start 
                     printstring("TAB    :{")
                     for  i = 1, 1, 20 cycle 
                        printstring(itos(p_tab(i)))
                        printsymbol(':') unless  i=20
                     repeat 
                     printsymbol('}')
                     newline
                     printstring("        Indenting values".snl)
                  finish  else  start 
                     i = 1
                     while  i<=20 and  value#"" cycle 
                        temp = stoi(value)
                        if  temp=-1 then  c 
                         printstring(value." - ".failuremessage(320)) and  c 
                         exit 
                        p_tab(i) = temp
                        if  length(value)=0 then  i = i+1 and  exit 
                        if  charno(value, 1)#':' start 
                           printstring(value." - ".failuremessage(320))
                           i = 21
                        finish  else  value = substring(value, 2,
                          length(value))
                        i = i+1
                     repeat 
                     ! End of indenting value, make up the rest
                     for  j = i, 1, 20 cycle 
                        p_tab(j) = 2*p_tab(j-1)-p_tab(j-2)
                        if  p_tab(j)>p_line then  p_tab(j) = p_line
                     repeat 
                  finish 
                  continue 
               finish 
               printstring(option." - ".failuremessage(322))
               ! Keyword not recognised.
            finish  else  start 
               printstring(line." -  invalid: format should be
      'keyword = value'      or     'keyword = ?'     or    '?'    or
      'SAVE'    or    'END'     or    'GO'     or     'STOP'".snl)
            finish 
         finish 
      repeat 
      return 

      routine  readline
!***********************************************************************
!*    READLINE creates a line from the input device, converting all    *
!*    lower case characters to upper case.                             *
!***********************************************************************
         integer  ch
         cycle 
            line = ""
            cycle 
               readsymbol(ch); if  ch=nl then  exit 
               if  ch=' ' then  continue 
               ! Convert lower to upper.
               line = line.tostring(onecase(ch))
            repeat 
            ! Return only if the line has some thing on it.
            if  length(line)>0 then  return 
         repeat 
      end 

      routine  setline
!***********************************************************************
!*    SETLINE breaks the parameter list into single commands.          *
!************************************************************************
         unless  parm->line.(",").parm start 
            ! Last command in parameter.
            if  charno(parm, length(parm))='*' then  readline else  line = parm
            parm = ""
         finish 
      end 

      routine  ask(integer  i)
!***********************************************************************
!*    ASK checks that value starts with Y or N and                     *
!*    assigns True or False accordingly to P_OPTARR(I).                *
!***********************************************************************
         integer  s
         s = charno(value, 1)
         if  s='Y' then  p_optarr(i) = true else  if  s='N' then  c 
          p_optarr(i) = false else  printstring("Answer Yes or No or ?".snl)
      end 

      integer  function  stoi(string  name  snum)
!***********************************************************************
!*    STOI builts up an integer in INUM from the string SNUM, in       *
!*    doing so characters are deleted from this string.                *
!*    It is an error if the first character of the string is not a     *
!*    number.  This is signalled by returning -1.                      *
!***********************************************************************
         integer  i, inum
         unless  '0'<=charno(snum, 1)<='9' then  result  = -1
         i = 1; inum = 0
         while  '0'<=charno(snum, i)<='9' cycle 
            inum = inum*10+charno(snum, i)-'0'
            i = i+1
            if  i>length(snum) then  exit 
         repeat 
         if  i>=length(snum) then  snum = "" else  c 
          snum = substring(snum, i, length(snum))
         result  = inum
      end 
   end 
end 
end  of  file