!***********************************************************************
!*              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. *
!*                                                                     *
!***********************************************************************

! We'll need to supply some lookalike routines for the various
! EMAS system library calls below.  I've converted the external specs
! into bodies, but haven't written them yet. - GT

externalstring(255)fnspec cliparam

external routine prompt(string (*) name s)
end

!***********************************************************************
!*                                                                     *
!*                           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.                          *
!*                                                                     *
!***********************************************************************

external string (255) fn spec itos(integer i)

external routine connect(string (31) name name, integer mode, hole, prot, record (chdr) name rec, integer name eflag)
end

external routine spec trim(string (31) file, integer name eflag)

external routine setfname(string (31) file)
end

external string (255) fn nexttemp
  result = ""
end

external routine sendfile(string (31) file, device, header, integer copies, form, integer name eflag)
end

external integer fn devcode(string (31) name)
  result = 0
end

external routine disconnect(string (31) name filename, integer name eflag)
end

external string (255) fn failuremessage(integer type)
  result = ""
end

external routine changefilesize(string (31) name filename, integer filesize, integer name eflag)
end

external routine newgen(string (31) name filename, string(*)name newfilename, integer name eflag)
end

external routine outfile(string (31) name filename, integer size, hole, prot, integer name conad, eflag)
end

external routine read profile(string (11) key,  record (pformat) name info, integer name version, uflag)
end

external routine write profile(string (11) name key, record (pformat) name info, integer name version, uflag)
end

begin
   string (255) s;  ! argv[1]
!%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
   short 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 (255) %array optmess(0:1, 1:maxopt)=
   constant string (255) array optmess(2:33)=
    "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 printsymbol(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 printsymbol(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 printsymbol(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
      cycle
         outbuf(obp) = chars&X'FF'
         chars = chars>>8
         obp = obp+1
      repeat until chars=0
      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  REMOVED GT
      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
            printstring(snl)
            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
         printstring(snl)
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 fn 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)
      short 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 fn 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 fn check(integer pos)
      integer defend, subdefend, subdefstart, res, item, rsptr, z,
        strdelimiter, ch, rsobj, alt, i, j
      own 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
                  cycle
                     outbuf(obp) = ch; obp = obp+1
                     ptr = ptr+1
                     ch = nextnonsp(inconst)
                  repeat until chartype(ch)&j=0
               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.                                *
!*                                                                     *
!***********************************************************************
   s = "test.imp,.out,SPCOMMA=Y,EXPKEY=Y"; ! cliparam
!printstring("preopt".snl)
   opt(s, p); ! Call option setting routine to set parameters.
!printstring("preconnect ".infile.snl)
   connect(infile, 0, 0, 0, rec, eflag); ! Open input file.
!printstring("postconnect".snl)
   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)
!printstring("outfile: ".workfile.snl)
      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 printstring(snl) else printsymbol(sc(z)&127)
            z = z+1
         repeat
         if sc(z)=';' then printsymbol(';')
         printstring(snl)
         spaces(maxptr-1); printsymbol('!'); printstring(snl)
         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 fn spec stoi(string (255) 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)

      prof vsn = 0; flag = 5;
      !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.

      ! original defaults
      !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.

      ! graham's preferred defaults
      p_a(1) = 80; ! line - lines are broken into two if length is greater than 80.
      p_a(2) = 2; ! icontin - continuation of line have an addition indentation of 3.
      p_a(3) = 41; ! poscom - position for right hand comments.
      p_a(4) = false; ! movecom - main comment are indented to POSCOM.
      p_a(5) = false; ! uckey - keywords output in upper case.
      p_a(6) = true; ! sepkey - adjacent keywords are compounded.
      p_a(7) = false; ! 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
         integer i
         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
      begin
        string(11) key
        key = "Soap80key"
        write profile(key, p, prof vsn, flag)
      end
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"
      cycle
         if parm="" then start
           begin
             string(15) s
             s = "Soap80: "
             prompt(s); ! not a real imp prompt unfortunately
           end
           readline
         finish else start
           setline
         finish
         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
            begin
              string(11) key
              key = "Soap80key"
              write profile(key, p, prof vsn, flag)
            end
            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*2).snl)
            repeat
            printstring("TAB    :{")
            for i = 1, 1, 20 cycle
               printstring(itos(p_tab(i)))
               printsymbol(':') unless i=20
            repeat
            printsymbol('}')
            printstring(snl)
            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.".snl)
         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*2).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('}')
                     printstring(snl)
                     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 fn stoi(string (255) 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 of program