You are here: Home Projects SETL LITTLE Source code SYN: Syntax generator for the LITTLE system. By Edith Deak and David Shields.
Views
Document Actions

SYN: Syntax generator for the LITTLE system. By Edith Deak and David Shields.

by Paul McJones last modified 2021-03-17 18:38
History
Action Performed by Date and Time Comment
Publish Paul McJones 2021-03-17 18:38 No comments.

SYN: Syntax generator for the LITTLE system. By Edith Deak and David Shields.

       1 .=member intro
       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                 syntax generator for the little system
      28
      29
      30                                   by
      31
      32                               edith deak
      33                             david shields
      34
      35
      36              direct inquiries, comments and criticisms to
      37
      38                       little project coordinator
      39                      computer science department
      40               courant institute of mathematical sciences
      41                           251 mercer street
      42                       new york, new york  10012
      43                                u. s. a.
      44
      45
      46
      47 this program translates an annotated bnf-like description of a
      48 programming language grammar into tables and text fragments
      49 which form the central part of a parser for the language which
      50 consists of an interpreter for an abstract parsing machine.
      51
      52 */
       1 .=member mods
       2 $ --- all mods are to include self description after mods.2 ---
dsk    2
dsk    3 $    dsk       d. shields          15-dec-81           level 81349
dsk    4 $
dsk    5 $    1.  fix filename length for s32 and s47.
dsk    6 $    2.  make program parameter 'synbin=0/synbin' for all machines.
dsk    7 $        thus by default synbin file written only if name given. this
dsk    8 $        file not needed by any current production compiler using
dsk    9 $        syn and generally needed only during bootstrap.
dsk   10
utsa   1
utsa   2 $    utsa      d. shields          29-nov-81           level 81333
utsa   3 $
utsa   4 $    support s47: amdahl uts (universal timesharing system).
utsa   5 $    this implementation runs on s37 architecture using an operating
utsa   6 $    system very close to unix (v7), and uses the ascii character set.
utsa   7
dsj    1
dsj    2 $    dsj       d. shields          08-sep-81           level 81251
dsj    3 $
dsj    4 $    for s37, change default name for synout file to 'synout' and
dsj    5 $    change line length for synout file from 72 to 80. this is helpful
dsj    6 $    for s37 and causes no harm in other systems.
dsj    7 $    deck affected - synini
dsj    8
dsi    1
dsi    2 $    dsi       d. shields          03-sep-80           level 80247
dsi    3 $
dsi    4 $    1.  fix problem (fr153) for s37 in that some initial asm macros
dsi    5 $        had extraneous bits set.
dsi    6 $    2.  make record length of asm file 80. this needed for s37, and
dsi    7 $        causes no harm for other implementations.
dsi    8 $    3.  permit bin and asm files to be named with 'synbin=/' and
dsi    9 $        'synasm=/' respectively. this maintains compatibility with
dsi   10 $        prior practice. for s37, defaults are 'synasm=assemble/'
dsi   11 $        and 'synbin=synbin/'.
dsi   12 $    decks affected - start, synini, ptasm.
dsi   13
dsh    1
dsh    2 $    dsh       d. shields          30-jun-80           level 80182
dsh    3 $
dsh    4 $    add new feature for setl. if setl option and implicit macros
dsh    5 $    used, then report number of implicit entries. for example,
dsh    6 $    generate macro for -impmax- if im=p selected.
dsh    7 $    deck affected - ptout.
dsh    8
dsg    1
dsg    2 $    dsg       d. shields          05-may-79           level 79127
dsg    3 $    correct to generate 'search pt10' and not 'universal pt10' for
dsg    4 $    s10, and also add code for pt10 macros to s10.
dsg    5 $    decks affected - ptasm, pt10.
dsg    6
dsf    1
dsf    2 $    dsf       d. shields          13-apr-79           level 79103
dsf    3 $
dsf    4 $    a problem in using syn is that large grammars, notably setl,
dsf    5 $    require parse tables which are so large that the data
dsf    6 $    statements to initialize them cannot be compiled by the
dsf    7 $    little compiler.  prior practice has been to read in the
dsf    8 $    parse table from a file.  this correction adds option
dsf    9 $    asm= to direct syn to write assembler macro calls to unit 6
dsf   10 $    so that required data statements can be assembled by
dsf   11 $    machine assembler.  this done in new procedure ptasm.
dsf   12 $    macro definitions provided in new decks pt10, pt32, pt37 and pt66.
dsf   13 $    decks affected - start, synini, ptout; new decks ptasm, pt10
dsf   14 $        pt32, pt37 and pt66.
dsf   15
dse    1 $ dse  d. shields  26-mar-79  79085  - fix bugs in setl option.
dsd    1
dsd    2 $    dsd       d. shields          19 feb 79           level 79050
dsd    3 $
dsd    4 $    add feature if setl option enabled to write out location
dsd    5 $    of definer for  symbol.
dsd    6 $    decks affected - start, synini, gnam, ptout.
dsd    7
dsc    1
dsc    2 $    dsc       d. shields          06 feb 79           level 79037
dsc    3 $
dsc    4 $    add program option 'setl=0/1' to support setl system.
dsc    5 $    this involves generation of two additional members and
dsc    6 $    writing of parse table in binary form to unit 5.
dsc    7 $    decks affected - start, synini, res4, ptout.
dsc    8
vax    1
vax    2 $    vax       d. shields          21 nov  78          level 78325
vax    3 $              r. kenner
vax    4 $
vax    5 $    add configuration values for s32: dec vax-11/780.
vax    6 $    decks affected - macros, start, synini, nextok.
vax    7
       3
       4 $    rbkc      r. kenner           01 mar 78           level 78060
       5 $
       6 $    1.  correct miscellaneous bugs detected on porting to s37.
       7 $    2.  insert conditional code for s10.
       8 $    3.  delete unused token types and add sstok.
       9 $    decks affected - macros, start, synini, nextok, res4, putmem,
      10 $                     synexit
      11
      12
      13 $    rbkb      r. kenner           17 feb 78
      14 $
      15 $    fix error in little grammar causing miscompilations of
      16 $    certain nested assignments and extractors.  this
      17 $    update goes with mod rbkm in gen.
      18 $    deck affected - ltlgrmr
      19
      20
      21 $    dsb       d. shields          17 oct 77           level 77290.
      22 $
      23 $    add implicit macros to assist in encodings needed in grammar.
      24 $    an implicit macro is a name which begins with a letter followed
      25 $    by the break (underline) character, where the letter is
      26 $    among those selected by the -im- program parameter.
      27 $    each such group of names is assigned an integer code, starting
      28 $    from one, in the order the names occur.  the names are replaced
      29 $    by the code, so that implicit macro names can occur where syn
      30 $    accepts, or requires, an integer to appear. syn reports the
      31 $    codes assigned for implicit macro with code -l- by writing
      32 $    a member -syniml-.  there can be up to four implicit macro groups.
      33 $    implicit macros can be used to name group of constants used
      34 $    by user-defined opcode, to name error messages, etc.
      35 $    decks affected - start, nextok, ptout, listha.
      36
      37
      38 $    rbka      r. kenner           14 oct 77
      39 $
      40 $    revise little grammar according to mod rbkj in gen.
      41 $    deck affected - ltlgrmr (resequenced).
      42
      43
      44 $    dsa       d. shields          03 oct 77           level 77276.
      45 $
      46 $    fix reported bug in handling of errors in grammar.
      47 $    deck affected - parse
      48
      49
      50 $    (none)    d. shields          08 aug 77           77220.
      51 $
      52 $    release as version 1.0 of syn.  show form of mod notice.
      53
       1 .=member macros
       2
       3      +*  synlevel =  $ date of last program change.
dsk   11          'syn(81349)'  $ 15-dec-81
       5          **
       6
       7      $   q3 and macdef are used to define macros in macros. macdrop
       8      $   releases macro from macro status
       9
      10        +*  q3(a,b,c) = a b c  **
      11        +*  macdef(text) = q3(+,*text*,*)  **
      12        +*  macdrop(mname) = macdef(mname=)  **
      13
      14      +*  defc(nam) =    $ define constant identifier
      15          macdef(nam = zzyz) **
      16
      17      +*  locofer = parseerrloc **
      18      +*  pt_dim = parsearamax **
      19
      20 $ syn run on    thu  28 jul 77  11:00:00
      21      +*  parsearamax =  178 **
      22      +*  parselitaramax =  0 **
      23      +*  parselexaramax =  0 **
      24      +*  parseactmax =  23 **
      25      +*  parseerrloc =  167 **
      26      +*  parseerrmax =  24 **
      27 $ end member synmac
      28
      29      $   target machine parameters
      30      +*  ws = .ws. **  $ machine word size.
      31      +*  ps = .ps. **  $ machine pointer (address) size.
      32      +*  cs = .cs. **  $ machine character size.
      33      +*  cpw = (ws/cs) **  $ characters per machine word
      34
      35
      36      +*  wpc = $ number of words in line image
      37 .+s66    09
vax    9 .+s32    20  $ 80 columns
      38 .+s37    20  $ 80 columns
utsa   8 .+s47    20  $ 80 columns
mgfa   1 .+s10    20
      40          **
      41
      42      +*  blankword =  $ word of blank chars (see insnam).
vax   10 .+s32    4r
      43 .+s37    4r
utsa   9 .+s47    4r
      44 .+s66    10r
mgfa   2 .+s10    4r
      46          **
      47
      48      $   macros related to file names
      49      +*  filenamelen = 20 ** $ max. length of file name in chars.
dsk   12 .+s32 +*  filenamelen = 64 ** $ max. length of file name in chars.
dsk   13 .+s47 +*  filenamelen = 64 ** $ max. length of file name in chars.
utsa  10 .+s32  +* filenamelen = 64 **
utsa  11 .+s47  +* filenamelen = 64 **
      50      +*  lctimelen = 30  **  $ length of lctime time representation.
      51
      52      +*  tokenfile = 3 **    $ token file number.
      53
      54      +*  parsefile = 4 **      $ voa file number.
      55
      56      $   io access codes.
      57      +*  access_read    = 4 **
      58
      59
      60      $   macros for listing generation (procedures in run-time library)
      61
      62      +*  listl(n)   = call contlpr(26,n);**  $ set listing flag
      63      +*  terml(n)   = call contlpr(27,n);**  $ set terminal flag
      64      $   if less than n lines remain on current page.
      65
      66      +*  digofchar(c) =  $ value of character digit.
      67          (c-1r0)   $ use if codes for numbers in order.
      68          **
      69      +*  charofdig(c) = $ maps digit into character code
      70          (c+1r0)  $ use if codes for numbers in order.
      71          **
      72
      73
      74      +*  hexcharofdig(c) = .ch. (c)+1, '0123456789abcdef' **
      75
      76      $   countup macro for incrementing and testing variable
      77      +*  countup(var,lim,msg) =
      78          var = var+1;
      79          if (var>lim) call gtoflo(var,lim); **
      80
      81      +*  alphabet = 'abcdefghijklmnopqrstuvwxyz' **
      82
      83
      84      $   yes and no macros used for logical expressions to clarify
      85      $   logical intent.
      86      +*  yes = 1 **  +* no = 0 **
      87
      88      +*  toklenmax = 60 **  $ maximum length of token in characters
      89
      90
      91
      92      $   macros related to parser and lexical token processing
      93
      94
      95      $   (codes must agree with those assigned by lex phase.)
      96      $   the codes used in token reader procedure -nextok-
      97      $   codes for lexical types assigned in lexical scan
      98      +*  toktypes = 14 ** $ no. of token types below
      99      +*  nametok  = 1 **  $  name
     100      +*  spectok  = 2 **  $  special token, e.g. (
     101      +*  pdotok   = 3 **  $  type of period delimited operators
     102      +*  dectok   = 4 **  $  type of decimal integers, e.g. 100
     103      +*  sstok    = 5 **  $ s-type strings
     104      +*  strtok   = 6 **
     105      +*  bittok = 8 **
     106      +*  qstok    = 9 **   $ q type string constant
     107      +*  rztok    = 12 **       $ right-zero type string constant (r)
     108      +*  realtok  = 14 **    $ real token
     109      +*  listcontroltok = 27 **  $ '.=list' directive.
     110      +*  listejecttok = 28 **  $ '.=eject' list directive.
     111      +*  listtitletok = 29 **  $ '.=title' directive.
     112      +*  tokrline = 30 **  $ code for line image
     113      +*  tokreof  = 31 **  $ code for end-token-file
     114
     115 .+s66.
     116      +*  tokrtyp  = .f. 1, 5, **  $ token type (lex type or code)
     117      +*  tokrlen  = .f. 7, 7, **  $ length of token in chars
     118      +*  tokrlc   = .f. 14, 9, **  $ token literal code
     119 .-s66.
     120      +*  tokrtyp  = .f.  1, 8, **
     121      +*  tokrlen  = .f.  9, 8, **
     122      +*  tokrlc   = .f. 17, 8, **
     123 ..s66
     124
     125      +*  tokrval  =  $ first few characters of short token.
     126 .+s66    .f. 25, 36,
vax   11 .+s32    .f. 25, 8,
     127 .+s37    .f. 25, 8,
utsa  12 .+s47    .f. 25, 8,
mgfa   3 .+s10    .f. 28, 9,
     129         **
     130      +*  cpstr =  $ character per short token record
     131 .+s66    6
vax   12 .+s32    1
     132 .+s37    1
utsa  13 .+s47    1
mgfa   4 .+s10    1
     134          **
     135
     136      +*  naml(hap) =   $ print name of ha item
     137          call sdsnamr(hap);
     138          put :sdsnamstr,a;  **  $ sdsnamr puts charstring in
     139                       $ sdsnamstr
     140
     141
     142 $ p a r s e   t a b l e   o p c o d e s
     143
     144 $ the following opcodes comprise the operations of the
     145 $ parse interpreter.  these drive the interpreter in this
     146 $ program, and are also the opcodes of the parse table
     147 $ generated by this program
     148
     149      defc(op_act)  $ perform action.
     150      defc(op_bak)  $ restore parse.
     151      defc(op_err)  $ report error if failure.
     152      defc(op_jif)  $ jump if failure.
     153      defc(op_jmp)  $ jump.
     154      defc(op_lex)  $ test for token of given lexical type.
     155      defc(op_lit)  $ test for literal.
     156      defc(op_set)  $ set parse register.
     157      defc(op_sev)  $ seek zero or more instances of subpart.
     158      defc(op_sub)  $ seek subpart.
     159      defc(op_op1)  $ user operation 1.
     160      defc(op_op2)  $ user operation 2.
     161      defc(op_op3)  $ user operation 3.
     162      defc(op_op4)  $ user operation 4.
     163      defc(op_op5)  $ user operation 5.
     164
     165 .=zzyorg z     $ reset zzyz to origin
     166
     167      +*  op_max = op_op5 **  $ maximum valid operator value.
     168
     169 $ l e x i c a l   c o d e s
     170
     171 $ lexical codes for the lexical classes of the self-defining
     172 $ grammar which drives this program.
     173
     174      defc(lexc_name)
     175      defc(lexc_string)     $ quoted string
     176      defc(lexc_int)        $ integer
     177      defc(lexc_nonslash)    $ not a slash '/'
     178      defc(lexc_noneq)    $ not an arrow '='
     179      defc(lexc_brlitdir)   $ psuedo class for literal branch.
     180
     181 .=zzyorg z
     182      +*  lexc_max = lexc_brlitdir **
     183
     184
     185      $   literal codes used to parse grammar.
     186      defc(lc_ltsym)     $ '<'
     187      defc(lc_gtsym)     $ '>'
     188      defc(lc_eqsym)     $ '='
     189      defc(lc_divide)     $ '/'
     190      defc(lc_times)     $ '*'
     191      defc(lc_lparen)     $ '('
     192      defc(lc_rparen)     $ ')'
     193      defc(lc_minus)     $ '-'
     194      defc(lc_plus)     $ '+'
     195      defc(lc_set)     $ 'set'
     196      defc(lc_comma)     $ '
     197      defc(lc_ok)     $ 'ok'
     198      defc(lc_b)     $ 'b'
     199      defc(lc_option)     $ 'option'
     200      defc(lc_litmap)     $ 'litmap'
     201      defc(lc_lexmap)     $ 'lexmap'
     202      defc(lc_epc)     $ 'epc'
     203      defc(lc_mode)     $ 'mode'
     204      defc(lc_end)     $ 'end'
     205      defc(lc_op1)  $ 'op1'
     206      defc(lc_op2)  $ 'op2'
     207      defc(lc_op3)  $ 'op3'
     208      defc(lc_op4)  $ 'op4'
     209      defc(lc_op5)  $ 'op5'
     210
     211      defc(lc_error)  $ for name error, so can find 'error' index.
dse    3      defc(lc_errmp)  $ for name errmp, so can find 'errmp' index.
     212      defc(lc_synhalist)  $ .synhalist. - dump syn ha.
     213      defc(lc_synptlist)  $ .synptlist. - dump syn pt.
     214      defc(lc_synoptrace)  $ .synoptrace. - turn on syn pt trace.
     215      defc(lc_synnooptrace) $ .synnooptrace. - turn off syn pt trace.
     216      defc(lc_syntoktrace)  $ .syntoktrace. - turn on token trace.
     217      defc(lc_synnotoktrace)  $ .synnotoktrace. - turn off token trace.
     218
     219 .=zzyorg  z
     220
     221 $    p a r s e t a b   f i e l d s
     222
     223      +*  parse_op = .f. 1, 4,   **    $ parse item opcode
     224      +*  parse_parm = .f. 5, 12, **    $ parse item parameter
     225 $ parse_parm is divided into 2 subfields for the set operation
     226 $ which has 2 parameters
     227      +*  parse_parm1 = .f. 5, 3, **    $ stores register number(1-4)
     228      +*  parse_parm2 = .f. 8, 9, **   $ stores integer value
     229      +*  parsesz = 16 **    $ size of parse item
     230
     231      +*  maxint  = 511 **   $ maximum value for parse_parm2
     232
     233 $ p a r s e t a b   m a c r o s
     234
     235      +*  emitop(o, a) =  $ create a ptab entry and push in on
     236                        $ deftab
     237          parse_op parseskel = o;
     238          parse_parm parseskel = a;
     239          countup(defptr, deftabdim, 'deftab');
     240          deftab(defptr) = parseskel;
     241          **
     242
     243      $   map type codes for ha symbols.
     244 .=zzyorg z
     245      defc(mtyp_lex)  $ resolve to lexical code.
     246      defc(mtyp_lit)  $ resolve to literal code.
     247      defc(mtyp_act)  $ resolve action sequence to label index.
     248      defc(mtyp_im1)  $ implicit macro 1
     249      defc(mtyp_im2)  $ implicit macro 2
     250      defc(mtyp_im3)  $ implicit macro 3
     251      defc(mtyp_im4)  $ implicit macro 4
     252
     253
     254 $ h a   m a c r o s
     255
     256 $ ha fields
     257
     258      +*  ha_names     = .f. 01, 11, **  $ names index.
     259      +*  ha_len       = .f. 12, 06, **  $ length of name.
     260      +*  ha_islbl     = .f. 18, 01, **  $ is label in pt.
     261      +*  ha_mtyp      = .f. 19, 03, **  $ map type.
     262      +*  ha_mval      = .f. 22, 11, **  $ map value.
     263 .-s10    +*  ha_pt        = .f. 33, 11, **  $ pt index if pt symbol.
dsd   10      +*  ha_synlc     = .f. 44, 06, **  $ literal code if grammar symbo
dsd   11      +*  ha_next      = .f. 50, 11, **  $ next ha index in chain.
dsd   12 .+s10    +*  ha_pt        = .f. 61, 11, **   $ pt index if pt synbol.
     267
     268      +*  hamvalsafe = 511 **  $ maximum safe mval.
dsd   13      +*  hasynlcsafe = 63 **  $ maximum safe synlc value.
     270
     271    $ define headers for message classes
     272      +*  error_notice   = '*****error**** ' **
     273      +*  system_notice  = '*system error* ' **
     274      +*  warning_notice = '****warning*** ' **
     275
       1 .=member start
       2
       3      prog start;  $ main program.
       4
       5      $   define global variables and structures.
       6      $   it is assumed that this text compiled with 'default access'
       7      $   option so that every procedure may refer to globals defined in
       8      $   this procedure.
       9
      10
      11      size  arg(ps);    $ saves ha index of literal, lexical, name, etc
      12      size  int1(ps);   $ saves lexical integer item
      13      size  ival(ps);    $ saves lexical integer item value
      14
      15      size  errmax(ps);  $ maximum error number used in grammar.
      16      data  errmax = 0;
      17      size  ermsgarg(ps);  $ pass optional arg to ermsg.
      18
      19      size  linelisted(ps);  data linelisted = 0; $ on when line listed
      20
      21      +*  hasz =  $ size of ha in bits
      22 .+s66  60
vax   13 .+s32  64
      23 .+s37  64
utsa  14 .+s47  64
      24 .+s10    72
      25        **
      26
      27      $   the hash algorithm requires that hamax be a prime.
      28      $   possible values include 509, 599, 701, 787 and 907.
      29      +*  hamax = 907 **  $ ha dims / must be prime.
      30      +*  haxtra = 200 **  $ number of additional ha entries for
      31           $ internally generated labels
      32 .+s66  nameset blank;   $ keep in blank common on s66
      33      size  ha(hasz);  dims ha(hamax + haxtra);
      34 .+s66  end nameset;
      35      size  haused(ps);  data haused=0;  $ number of ha entries used.
      36      size  haxtrap(ps);  data haxtrap = 0;
      37
      38      size  errloc(ps); data errloc = 0;  $ location in ptab
      39               $ of error recovery
      40
dse    4      size  errmploc(ps); data errmploc = 0;  $ location in ptab
dse    5               $ of  symbol (for setl).
dsd   16
      41
      42      $   imara tracks implicit macros.  if imara(i) is nonzero, then
      43      $   the i-th letter of the alphabet is used for implicit macros,
      44      $   and imara(i) gives the mtyp code used.
      45
      46      size  imara(ps);  dims imara(26);  $ implicit macro code array.
      47      data  imara = 0(26);
      48      size  insnamstr(.sds. toklenmax);
      49      data  insnamstr = '' .pad. toklenmax;
      50
      51      $   lexlenmax is maximum length of lexical name in grammar.
      52      $   litlenmax is maximum length of literal in grammar.
      53      size  lexlenmax(ps);  data lexlenmax = 0;
      54      size  litlenmax(ps);  data litlenmax = 0;
      55
dsc   10      +*  binfile = 5 **  $ binary file for setl option.
dsf   17      +*  asmfile = 6 **  $ assembler text to unit 6 (see ptasm).
dsc   11
dsi   15      size  asmfilename(.sds. filenamelen);  $ asm file name.
dsi   16      size  binfilename(.sds. filenamelen);  $ bin file name.
      56      size  macroprefix(.sds. filenamelen);  $ macro prefix string.
      57      size  memberprefix(.sds. filenamelen);  $ start of member names.
      58      size  mtyporg(ps);  dims mtyporg(7);
      59      data  mtyporg = 0(7);
      60      size  mtyplast(ps);  dims mtyplast(7);  data mtyplast = 0(7);
      61      size  mtyptot(ps);  dims mtyptot(7);  data mtyptot = 0(7);
      62      size  mtypnum(ps);  dims mtypnum(7);  data mtypnum = 0(7);
      63
      64      $   characters in symbolic names are kept in -names- array.
      65      +*  namesmax =   $ dimension of -names- array
      66 .+s66    800
vax   14 .+s32    1600
      67 .+s37    1600
utsa  15 .+s47    1600
mgfa   5 .+s10    1600
      69          **
      70
      71      size  namesptr(ps);  data namesptr = 0; $ ptr to names array
      72 .+s66    nameset blank;  $ keep in blank common on s66.
      73      size  names(ws); dims names(namesmax);  $ names array
      74 .+s66    end nameset;
      75
      76      size  nextokha(ps);    $ ha index of last token from nextok.
      77      data  nextokha = 0;
      78
      79      size  linenumber(ps); data linenumber = 0;  $ number of lines read
      80      size  jumpnext(ps);  $ head of list of unresolved references
      81                          $ in ptab
      82      data jumpnext = 0;
      83
      84      size  nerrors(ps);  data nerrors = 0;  $ no of errors
      85      size  nwarnings(ps);  data nwarnings=0; $ num. of warnings.
      86      size  halistflag(ps);   $ flag to dump ha
      87      data  halistflag = 0;
      88      size  opnames(.sds. 3);   $ array of opcode names
      89      dims  opnames(16);
      90
      91      size  lastcol(ps);  $ last column on file 2 to use.
      92
      93      size  lcs_opt(ps);      $ list parse statistics flag
      94      size  listpt(1);      data listpt = no;  $ list pt flag
      95      size  listsw(1);      data listsw = yes;  $ list input flag
      96
      97      size  definertot(ps);  $ number of definers
      98      +*  errnummax = 256 **  $ maximum error number.
      99      size  errbit(errnummax * 2);   $ table of error numbers used
     100      data errbit = 0;
     101      +*  errbits(i) =    $ macro to access errbit
     102          .f. (i-1)*2 + 1, 2, errbit **
     103
     104
     105      size  parsetrace(ws); $ on to trace parser
     106      data  parsetrace = no;  $  trace parser action
     107
     108 $ p a r s e t a b  stores grammar produced by syn
     109
     110      +*  ptabmax = 2000 **
     111 .+s66   nameset blank;
     112      size  ptab(ws);  dims ptab(ptabmax);
     113 .+s66   end nameset;
     114      size  keeptok(ps);   $ lexical scanner keep tokenflag
     115      data keeptok = no;
     116      size  parseskel(ws);   $ ptab entry
     117      size  ptablim(ps);      $ ptab pointer
     118      data  ptablim = 0;
     119      $   ptablimout is ptablim written to member file.  ptablimout is
     120      $   ptablim rounded up to nearest multiple of epc.
     121      size  ptablimout(ps);  data ptablimout = 0;
     122
     123 $ d e f t a b  stores primary and secondary parse items
     124 $ after a definer is found, the primaries and secondaries
     125 $ are merged into ptab.
     126
     127      +*  deftabdim = 50 **
     128      size  deftab(ws);  dims deftab(deftabdim);
     129      size  defptr(ps);  data defptr = 0;
     130      size  secptr(ps);  $ beginning of secondary items in deftab
     131
     132 $ p t  stores parse table of self-defining syn grammar
     133
     134      nameset pt;
     135      size  pt(ws);    $ parse table
     136      dims  pt(pt_dim);
     137      end nameset;
     138      data  pt =
     139 $ member syntab
     140      4b'0799 0035', 4b'0137 0075', 4b'0011 0002', 4b'00aa 0013', $   1
     141      4b'0035 0017', 4b'0023 0016', 4b'0033 0027', 4b'0043 0021', $   2
     142      4b'0139 0002', 4b'0037 0002', 4b'018a 0053', 4b'0002 0031', $   3
     143      4b'0209 0047', 4b'0063 0041', 4b'0689 0051', 4b'0002 0026', $   4
     144      4b'0245 0061', 4b'0002 0066', 4b'0002 02d5', 4b'0415 0455', $   5
     145      4b'04d5 0515', 4b'05e5 0605', 4b'0057 0355', 4b'0016 0073', $   6
     146      4b'0027 0083', 4b'0071 0002', 4b'0016 0093', 4b'0057 03d5', $   7
     147      4b'0027 00a3', 4b'0081 0002', 4b'0027 00b3', 4b'0091 0002', $   8
     148      4b'00a1 0077', 4b'00c3 0002', 4b'0016 0495', 4b'00b1 0002', $   9
     149      4b'0036 0163', 4b'00c1 0002', 4b'0016 00d3', 4b'00d1 0002', $  10
     150      4b'0067 00e3', 4b'0036 00f3', 4b'00e1 00b7', 4b'0103 0036', $  11
     151      4b'0113 0077', 4b'0123 00f1', 4b'0002 0101', 4b'0002 0067', $  12
     152      4b'0133 0036', 4b'0143 0077', 4b'0153 0111', 4b'0002 0087', $  13
     153      4b'0002 00d7', 4b'06e5 0121', 4b'0002 0036', 4b'0725 00c1', $  14
     154      4b'0002 0016', 4b'0765 00d1', 4b'0002 0131', 4b'0088 0002', $  15
     155      4b'00e7 07d5', 4b'0879 0002', 4b'0107 0825', 4b'00a8 0979', $  16
     156      4b'0002 00f7', 4b'0002 00b8', 4b'09f9 0002', 4b'0127 08f5', $  17
     157      4b'0037 0173', 4b'0036 0183', 4b'0141 0002', 4b'0117 0002', $  18
     158      4b'0037 0173', 4b'0036 0183', 4b'0151 0002', 4b'0026 0002', $  19
     159      4b'0037 0173', 4b'0036 0183', 4b'0161 0002', 4b'0026 0002', $  20
     160      4b'0037 0173', 4b'0036 0183', 4b'0171 0002', 4b'0ad9 0047', $  21
     161      4b'0002 0b09', 4b'0139 0035', 4b'0046 0002', 4b'0002 0056', $  22
     162      4b'0002 0002' ;                                             $  23
     163 $ end member syntab
     164
     165 $    globals used by -parse- as parameters
     166      size  parsereg(ps);  dims parsereg(8);  $ parse registers.
     167      data  parsereg = 0(8);
     168
     169      +*  parseok = parsereg(1) **   $ the parseflab is reg1
     170      +*  ermsgno = parsereg(2) **   $ the -ermsgno- is reg2
     171      +*  litmapflag = parsereg(3) **  $ user supplies literal number ma
     172      +*  lexmapflag = parsereg(4) **  $ user supplies lexical number ma
     173
     174
     175      size  epc(ps);  $ number of parse items to pack
     176                     $ into word of ptab
     177
     178      +*  peldefault = 50 ** $ default error limit.
     179      size  pelvalue(ps);  data pelvalue = peldefault;  $ error limit
     180
     181
     182      size  sdsnamstr(.sds. toklenmax);
     183      data  sdsnamstr= '' .pad. toklenmax; $ parameter to
     184
     185
     186      $   as part of error report, syn lists the most recent
     187      $   lexlistmax tokens.  lexlistmax must be a power of two.
     188
     189      +*  lexlistmax = 16 **
     190
     191      size  lexlist(ps);  dims lexlist(lexlistmax);
     192      data lexlist = 0(lexlistmax);
     193      size  lexlistptr(ps);  data lexlistptr = 0;
     194      size  listwds(ws); dims listwds(wpc);  $ line read in
     195      size  listwdsp(ps);   $ last non-blank word
     196
dsc   12      size  res4ent(ws);        $ binary result of last res4 result.
dsc   13      size  setlopt(ps);      $ setl option.
dsc   14
dsf   18      size  asmtype(ps);  $ target machine for assembler text.
     197      size  timestr(.sds. lctimelen);   $ stores time/date string
     198
     199      +*  tokrbuflim = 256 **
     200      +*  tokarasz = ws **  $ size of tokara
     201      +*  tokaradims = ((toklenmax+cpw)/cpw) **
     202      $   review tokaradims carefully when building cross compiler
     203      $   where character sizes differ
     204      size  toklen(ps);  $ token length in characters
     205      size  toklt(ps);  $ token lexical type
     206      size  toklc(ps);   $ token hash table index
     207 .+s66    nameset blank;  $ keep in blank common on s66.
     208      size  tokrbuf(ws);  dims tokrbuf(tokrbuflim);  $ token buffer
     209 .+s66    end nameset;
     210      size  tokrbufp(ps);  data tokrbufp=0;  $ ptr to tokrbuf
     211
     212      call synini;  $ to initialize program and print title
     213      call parse;
     214      call synexit(0);
     215      end prog start;
       1 .=member synini
       2      subr synini;  $ initialization.
       3
       4      size  parm1(ws);    $ to store params for op_set
       5      size  i(ps);     $ do loop variable
       6      size  imchars(.sds. filenamelen);  $ im code chars
       7      size  mt(ps);  $ map type
       8      size  imtot(ps);    $ number of implicit macros
       9      size  s1(.sds. 1);      $ one character temporary string
      10      size  n(ps);            $ temporary
      11      size  iorc(ps);  $ io return code
      12      size  parsefilename(.sds. filenamelen);  $ name of parse file
      13      size  tokenfilename(.sds. filenamelen);  $ name of token file
      15      size  hap(ps);    $ ha index.
      16
      17      do  i = 1 to hamax;  $ clear ha
      18          ha(i) = 0;  end do;
      19
      20      $   initialize opnames, setting to '**n' if n not an op.
      21
      22      do  i = 0 to 15;
      23          opnames(i+1) = '***';
      24          .ch. 3, opnames(i+1) = hexcharofdig(i);
      25          end do;
      26      opnames(op_lit+1) = 'lit';
      27      opnames(op_lex+1) = 'lex';
      28      opnames(op_sev+1) = 'sev';
      29      opnames(op_sub+1) = 'sub';
      30      opnames(op_err+1) = 'err';
      31      opnames(op_bak+1) = 'bak';
      32      opnames(op_jif+1) = 'jif';
      33      opnames(op_jmp+1) = 'jmp';
      34      opnames(op_act+1) = 'act';
      35      opnames(op_set+1) = 'set';
      36      opnames(op_op1+1) = 'op1';
      37      opnames(op_op2+1) = 'op2';
      38      opnames(op_op3+1) = 'op3';
      39      opnames(op_op4+1) = 'op4';
      40      opnames(op_op5+1) = 'op5';
      41
      42
      43 $ hash into ha literals of syn sgrammar
      44      +*  hashin(s, lc) = call haini(s, lc); **
      45      hashin('<',   lc_ltsym)
      46      hashin('>',   lc_gtsym)
      47      hashin('=',   lc_eqsym)
      48      hashin('/',   lc_divide)
      49      hashin('*',   lc_times)
      50      hashin('(',   lc_lparen)
      51      hashin(')',   lc_rparen)
      52      hashin('-',   lc_minus)
      53      hashin('+',   lc_plus)
      54      hashin('set', lc_set)
      55      hashin(',',   lc_comma)
      56      hashin('ok',  lc_ok)
      57      hashin('b',   lc_b)
      58      hashin('option',  lc_option)
      59      hashin('litmap',  lc_litmap)
      60      hashin('lexmap',  lc_lexmap)
      61      hashin('epc',    lc_epc)
      62      hashin('mode',    lc_mode)
      63      hashin('end', lc_end)
      64
      65      hashin('op1',  lc_op1)
      66      hashin('op2',  lc_op2)
      67      hashin('op3',  lc_op3)
      68      hashin('op4',  lc_op4)
      69      hashin('op5',  lc_op5)
      70      hashin('error', lc_error)   $ ha index of symbol 'error'
      71      hashin('.synhalist.' ,lc_synhalist);
      72      hashin('.synptlist.',  lc_synptlist);
      73      hashin('.synoptrace.', lc_synoptrace);
      74      hashin('.synnooptrace.', lc_synnooptrace);
      75      hashin('.syntoktrace.', lc_syntoktrace);
      76      hashin('.synnotoktrace.', lc_synnotoktrace);
      77
      79
      80      call getspp(memberprefix, 'memp=syn/');
      81      call getspp(macroprefix, 'macp=parse/');
      82
      83      call getipp(parsetrace, 'pt=0/1');
dsc   15      call getipp(setlopt,'setl=0/1');  $ setl option.
dsc   16
dse    6      if  setlopt  then  $ in setl mode, look for name .
dse    7          hashin('errmp', lc_errmp)   $ ha index of symbol 'errmp'
dsd   19          end if;
dsd   20      macdrop(hashin)
      84      call getipp(epc, 'epc=2/3');   $ number of parseitems/word
      85      call getipp(lcs_opt, 'lcs=1/0');
      86      call getipp(halistflag, 'ha=0/1');
      87
dsf   19      $   read asm= option, default is off or machine at hand if asm
dsf   20      $   alone specified.
dsf   21 .+s10    call getipp(asmtype, 'asm=0/10');
dsf   22 .+s32    call getipp(asmtype, 'asm=0/32');
dsf   23 .+s37    call getipp(asmtype, 'asm=0/37');
utsa  16 .+s47    call getipp(asmtype, 'asm=0/47');
dsf   24 .+s66    call getipp(asmtype, 'asm=0/66');
vax   15 .+s32    call getspp(tokenfilename, 'tokens=tokens.tmp/');
      88 .+s37    call getspp(tokenfilename, 'tokens=sysut1/');
utsa  17 .+s47    call getspp(tokenfilename, 'tokens=sysut1/');
      89 .+s66    call getspp(tokenfilename, 'tokens=tokens/');
mgfa   6 .+s10    call getspp(tokenfilename, 'tokens=*.tok/');
      91      call opensio(tokenfile, iorc, access_read, tokenfilename,
      92          0, i, 0, 0);
dsia   1 .+s66  call rewisio(tokenfile, iorc, 0);
      94      call dropsio(tokenfile, iorc);  $ this is terminal use of tokenfil
      95      call rdrwsio(tokenfile, iorc, tokrbuf, 1, tokrbuflim);
vax   16 .+s32    call getspp(parsefilename, 'synout=synout.dat/');
dsj   10 .+s37    call getspp(parsefilename, 'synout=synout/');
utsa  18 .+s47    call getspp(parsefilename, 'synout=synout/');
      97 .+s66    call getspp(parsefilename, 'synout=synout/');
      98 .+s10    call getspp(parsefilename, 'synout=synout.dat/');
dsj   11      file parsefile access = put, linesize = 80, title = parsefilename;
dsj   12 .+s66 rewind parsefile;
     101
dsi   17 .+s32    call getspp(asmfilename, 'synasm=/');
dsi   18 .+s37    call getspp(asmfilename, 'synasm=assemble/');
utsa  19 .+s47    call getspp(asmfilename, 'synasm=assemble/');
dsi   19 .+s66    call getspp(asmfilename, 'synasm=/');
dsi   20 .+s10    call getspp(asmfilename, 'synasm=/');
dsi   21
dsk   14      call getspp(binfilename, 'synbin=0/synbin');
     106
     107      call getspp(imchars, 'im=/');
     108      if  (.len. imchars > 4)  .len. imchars = 4;  $ at most four.
     109      imtot = 0;
     110      do  i = 1 to .len. imchars;
     111          s1 = .s. i, 1, imchars;  $ get code character
     112          n = s1 .in. alphabet;
     113          if  (n=0)  cont do;  $ if not a letter.
     114          if  (imara(n))  cont do;  $ if already specified.
     115          imtot = imtot + 1;
     116          imara(n) = mtyp_im1 + (imtot-1);  $ set map type.
     117          end do;
     118
     119      lastcol = filestat(2,linesize)-6;
     120      call ltitlr(synlevel);
     121      call stitlr(0, 'syn - syntax generator.');
     122      call stitlr(1, 'program parameters.');
     123
     124      timestr = ' ' .pad. 30;
     125      call lstime(timestr);   $ get time/date
     126
     127      put ,'token file: tokens = ' :tokenfilename,a
     128          ,'.  output file: synout = ' :parsefilename,a ,'.' ,skip;
dsi   26      put ,'asm file: synasm = ' :asmfilename,a
dsi   27          ,'.  binary file: synbin = ' :binfilename,a ,'.' ,skip;
     129
     130      put ,'entries per constant: epc = ' :epc,i
     131          ,'.  parse trace: pt = ':parsetrace,i ,'.' ,skip;
     132      put ,'ha dump: ha = ' :halistflag,i ,'.' ,skip;
     133      put ,'macro prefix: macp = ' :macroprefix,a
     134          ,'.  member prefix: memp = ' :memberprefix,a ,'.' ,skip;
     135      put ,'implicit macros: im = ' :imchars,a ,'.' ,skip;
dsc   17      put ,'setl: setl = ' :setlopt,i ,'.' ,skip;
dsf   25      put ,'assembler text type: asm = ' :asmtype,i ,'.' ,skip;
     136      call stitlr(1, 'grammar listing.');
     137      put ,skip(2);
     138      end subr synini;
       1 .=member haini
       2      subr haini(s, lc);  $ initialize synlc for string s.
       3      size  s(.sds. 20);
       4      size  lc(ps);      $ syn literal code.
       5      size  l(ps);      $ string length.
       6      size  hap(ps);     $ ha index.
       7
       8      l = .len. s;  assert l <= toklenmax;
       9      .len. insnamstr = l;
      10      .s. 1, l, insnamstr = s;
      11      call insnam(hap);
      12      assert lc <= hasynlcsafe;  $ avoid field overflow.
      13      ha_synlc ha(hap) = lc;
      14      end subr haini;
       1 .=member parse
       2      subr parse;  $ parse grammar.
       3
       4 $ parser stack -pca- macros
       5
       6
       7      size  parsenow(ps);    $ ptable -pt- pointer
       8      size  parseop(ps);     $ current parse operation
       9      size  parseparm(ps);  $ current parse parameter
      10      size  lc(ps);   $ literal ha code
      11      size  i(ps);        $ do loop variable
      12      size  tot(ps);  $ sum of  objects found
      13      size  p1(ps);    $ parameter1
      14      size  p2(ps);    $ parameter2
      15
      16      +*  pcamax = 50 **
      17      +*  pcaret(i) = .f. 01, 11, pca(i) **   $ return address
      18      +*  pcaprm(i) = .f. 12, 11, pca(i) ** $ seek several branch target
      19      +*  pcatot(i) = .f. 23, 10, pca(i) **  $ totol no of items found
      20      size  pca(32);         $ parse stack
      21      dims  pca(pcamax);
      22      size  pcaptr(ps);      $ pointer to pca
      23      pcaptr = 0;  tot = 0;
      24
      25
      26      $   unpack parse table, two entries per constant.
      27      do  i = pt_dim/2 to 1 by -1;
      28          pt(i*2) = .f. 01, 16, pt(i);
      29          pt(i*2-1) = .f. 17, 16, pt(i);
      30          end do;
      31
      32      parsenow = 1;
      33      go to parseon;
      34
      35 /parseoncond/  $ advance parse according to parseok state.
      36      keeptok = 1 - parseok;
      37      parsenow = parsenow + 1 + parseok;
      38      go to parseon;
      39
      40 /parsenext/  $ advance to next parse op.
      41
      42      parsenow = parsenow + 1;
      43
      44 /parseon/   $ interprep next parse item
      45
      46      parseop = parse_op pt(parsenow);
      47      parseparm = parse_parm pt(parsenow);
      48
      49      if  parsetrace  then  $ if tracing parse.
      50          put ,x(4) ,'parsetrace ' :parseok :parsenow
      51              :parseop :parseparm,nil ,x :opnames(parseop+1),al ,skip;
      52          end if;
      53
      54      go to po(parseop) in 1 to op_max;
      55
      56
      57 /po(op_lit)/     $ seek literal.
      58
      59      call nextok;   $ get next token
      60      parseok = (parseparm = toklc);
      61      go to parseoncond;
      62
      63 /po(op_lex)/    $ seek lexical.
      64
      65      call nextok;   $ get next token
      66      go to lexc(parseparm) in 1 to lexc_max;
      67
      68 /lexc(lexc_name)/   $ seek <*name>.
      69
      70      parseok = (toklt = nametok);
      71      if  (parseok)  arg = nextokha;
      72      go to parseoncond;
      73
      74 /lexc(lexc_string)/   $ seek <*string>.
      75
      76      parseok = (toklt = strtok);
      77      if  (parseok)  arg = nextokha;  $ save ha index if found.
      78      go to parseoncond;
      79
      80 /lexc(lexc_int)/    $ seek <*int>.
      81
      82      parseok = (toklt = dectok);
      83      if  parseok  then $ if integer found, convert it.
      84          ival = 0;   $ result stored in -ival-
      85          do  i = 1 to (.len. insnamstr);
      86              ival = ival * 10 + digofchar((.ch. i, insnamstr));
      87              end do;
      88          end if;
      89      go to parseoncond;
      90
      91 /lexc(lexc_nonslash)/     $ seek any token but '/'.
      92
      93      parseok = (toklc ^= lc_divide);
      94      go to parseoncond;
      95
      96 /lexc(lexc_noneq)/    $ seek any token but '='.
      97
      98      parseok = (toklc ^= lc_eqsym);
      99      go to parseoncond;
     100
     101 /lexc(lexc_brlitdir)/   $ branch on literal for direct part.
     102      $   here to start direct part, check next token, and
     103      $   branch according to literal case.
     104      i = 0;
     105      if      toklc = lc_ltsym   then  i = 1;
     106      elseif  toklc = lc_lparen  then  i = 2;
     107      elseif  toklc = lc_minus   then  i = 3;
     108      elseif  toklc = lc_plus    then  i = 4;
     109      elseif  toklc = lc_set     then  i = 5;
     110      elseif  toklc = lc_ok      then  i = 6;
     111      elseif  toklc = lc_op1     then  i = 7;  int1 = 1;
     112      elseif  toklc = lc_op2     then  i = 7;  int1 = 2;
     113      elseif  toklc = lc_op3     then  i = 7;  int1 = 3;
     114      elseif  toklc = lc_op4     then  i = 7;  int1 = 4;
     115      elseif  toklc = lc_op5     then  i = 7;  int1 = 5;
     116          end if;
     117      parseok = (i > 0);
     118      keeptok = 1 - parseok;
     119      parsenow = parsenow + 1 + i;
     120      go to parseon;
     121
     122 /po(op_sev)/     $ seek several subparts.
     123
     124      countup(pcaptr, pcamax, 'ptab');
     125      pca(pcaptr) = 0;
     126      pcaret(pcaptr) = parsenow;   $ save return place
     127      pcaprm(pcaptr) = parseparm;  $ save place branching to
     128      parsenow = parseparm;
     129      go to parseon;
     130
     131 /po(op_sub)/   $ seek subpart.
     132
     133      countup(pcaptr, pcamax, 'ptab');
     134      pca(pcaptr) = 0;
     135      pcaret(pcaptr) = parsenow;
     136      parsenow = parseparm;
     137      go to parseon;
     138
     139 /po(op_err)/      $ process error
     140
     141      if  parseok  then
     142          parsenow = parsenow + 1;
     143          go to parseon;
     144          end if;
     145      ermsgno = parseparm;
     146      call ermet;
     147      pcaptr = 0;  $ clear parse stack for error recover
     148      parsenow = locofer;   $ location in pt of error processing 
     149      go to parseon;
     150
     151
     152 /po(op_bak)/   $ restore parse state
     153
     154 $ return from find subpart or find repeated instances of subpart.
     155
     156      if  pcaprm(pcaptr) = 0  then   $ seek one instance case.
     157          parsenow = pcaret(pcaptr) + parseok + 1;
     158          pcaptr = pcaptr - 1;
     159          if  (pcaptr >= 0)  go to parseon;
     160          call ermey(2);  $ fatal pca underflow.
     161
     162      else  $ seek several instances.
     163
     164          if  parseok  then     $ continue search
     165              pcatot(pcaptr) = pcatot(pcaptr) + 1;   $ increment count
     166              $ of items found
     167              parsenow = pcaprm(pcaptr);
     168              go to parseon;
     169          else    $ subpart not found.  return to point of call.
     170              parsenow = pcaret(pcaptr) + 1;
     171              parseok = yes;    $ 0 instances valid
     172              tot = pcatot(pcaptr);  $ total subparts found
     173              pcaptr = pcaptr - 1;
     174              if  (pcaptr >= 0)  go to parseon;
     175              call ermey(2);  $ fatal pca underflow.
     176              end if;
     177          end if;
     178
     179 /po(op_jif)/    $ conditional transfer    -lab
     180
     181      if  parseok  then
     182          parsenow = parsenow + 1; go to parseon;
     183          end if;
     184      parsenow = parseparm;
     185      go to parseon;
     186
     187 /po(op_jmp)/      $ transfer    +lab
     188
     189      parsenow = parseparm;
     190      go to parseon;
     191
     192 /po(op_set)/       $ set register   set(r, iv)
     193
     194      p1 = parse_parm1 pt(parsenow) + 1;
     195      p2 = parse_parm2 pt(parsenow);
     196
     197      parsereg(p1) = p2;
     198      go to parsenext;
     199
     200 /po(op_op1)/  /po(op_op2)/  /po(op_op3)/
     201 /po(op_op4)/  /po(op_op5)/
     202      put ,'error - attempt to use user op operation.' ,skip;
     203      put :parsenow,nil ,skip;
     204      call synexit(1);
     205      go to parsenext;
     206
     207 /po(op_act)/    $ execute code
     208
     209      go to pa(parseparm) in 1 to parseactmax;
     210
     211    +* pac = go to parsenext; **
     212
     213 $ member synact
     214 / pa(   1) /  call synexit ( 0 );                               pac;
     215 / pa(   2) /  call gnam;                                        pac;
     216 / pa(   3) /  call gdir;                                        pac;
     217 / pa(   4) /  go to g_alt;
     218 / pa(   5) /  call galt;                                        pac;
     219 / pa(   6) /  call glit;                                        pac;
     220 / pa(   7) /  call glex;                                        pac;
     221 / pa(   8) /  go to g_sev;
     222 / pa(   9) /  go to g_sub;
     223 / pa(  10) /  call gact;                                        pac;
     224 / pa(  11) /  go to g_jif;
     225 / pa(  12) /  go to g_err;
     226 / pa(  13) /  go to g_jmp;
     227 / pa(  14) /  go to g_saveint;
     228 / pa(  15) /  call gset;                                        pac;
     229 / pa(  16) /  go to g_ok;
     230 / pa(  17) /  go to g_opn;
     231 / pa(  18) /  go to g_bak;
     232 / pa(  19) /  go to g_next;
     233 / pa(  20) /  go to g_mode;
     234 / pa(  21) /  go to g_epc;
     235 / pa(  22) /  go to g_lexmap;
     236 / pa(  23) /  go to g_litmap;
     237 $ end member synact
     238
     239     macdrop(pac)
     240
     241 /g_epc/  $ set entries per constant.
     242      epc = ival;
     243      go to parsenext;
     244
     245 /g_lexmap/    $ assigns lexical code to name.
     246
     247      call setmtyp(arg, mtyp_lex);
     248
     249      if  ha_mtyp ha(arg) ^= mtyp_lex  then  $ if wrong type.
     250          ermsgarg = arg;  call ermsg(12);  $ name in use.
     251          ival = ha_mval ha(arg);  $ get current value.
     252      elseif  ha_mval ha(arg)  then  $ if value already set.
     253          ermsgarg = arg;  call ermsg(13);
     254          ival = ha_mval ha(arg);
     255      else  $ if first encounter, adjust lexlenmax.
     256          if  (ha_len ha(arg) > lexlenmax)  lexlenmax = ha_len ha(arg);
     257          end if;
     258
     259      ha_mval ha(arg) = ival;  assert ival <= hamvalsafe;
     260      go to parsenext;
     261
     262 /g_litmap/     $ assign literal code to literal.
     263
     264      call setmtyp(arg, mtyp_lit);
     265
     266      if  ha_mtyp ha(arg) ^= mtyp_lit  then  $ if wrong type.
     267          ermsgarg = arg;  call ermsg(12);  $ name in use.
     268          ival = ha_mval ha(arg);  $ get current value.
     269      elseif  ha_mval ha(arg)  then  $ if value already set.
     270          ermsgarg = arg;  call ermsg(13);
     271          ival = ha_mval ha(arg);
     272      else  $ if first encounter, adjust litlenmax.
     273          if  (ha_len ha(arg) > litlenmax)  litlenmax = ha_len ha(arg);
     274          end if;
     275
     276      ha_mval ha(arg) = ival;  assert ival <= hamvalsafe;
     277      go to parsenext;
     278
     279 /g_alt/   $ beginning of secondary items
     280
     281      secptr = defptr + 1;  $ mark beginning of secondary definer items
     282      go to parsenext;
     283
     284 /g_sev/     $ seek several.
     285
     286      emitop(op_sev, arg);
     287      ha_islbl ha(arg) = yes;  $ flag as name used.
     288      go to parsenext;
     289
     290 /g_sub/     $ seek syntactic subpart.
     291
     292      emitop(op_sub, arg);
     293      ha_islbl ha(arg) = yes;
     294      go to parsenext;
     295
     296
     297 /g_err/       $ error if ok = false
     298
     299      emitop(op_err, ival);    $ emit op_err item
     300      if  (errbits(ival) < 2)    $ note use if errno -ival-
     301          errbits(ival) = errbits(ival) + 1;
     302      go to parsenext;
     303
     304 /g_saveint/
     305
     306      int1 = ival;   $ save value of ival
     307      go to parsenext;
     308
     309 /g_ok/
     310
     311 $ the primitive -ok- becomes  set(1, 1)
     312      int1 = 1;  ival = 1;
     313      call gset;
     314      go to parsenext;
     315
     316
     317 /g_opn/  $ emit opn operation.
     318
     319      emitop((op_op1+int1-1), ival);
     320      go to parsenext;
     321
     322 /g_bak/
     323
     324      emitop(op_bak, 0);
     325      go to parsenext;
     326
     327 /g_jmp/     $ unconditional transfer
     328
     329      emitop(op_jmp, arg);
     330      ha_islbl ha(arg) = yes;
     331      go to parsenext;
     332
     333 /g_jif/     $ conditional transfer if ok = false
     334
     335      $   primary.
     336      emitop(op_jif, arg);
     337      ha_islbl ha(arg) = yes;
     338      go to parsenext;
     339
     340 /g_next/   $ conditional transfer to next definer
     341               $ internally generated labels
     342      if  jumpnext = 0  then  $ allocate new ha entry
     343          countup(haxtrap, haxtra, 'haxtra');
     344          jumpnext = haxtrap + hamax;
     345          end if;
     346      arg = jumpnext;
     347      emitop(op_jmp, arg);
     348      go to parsenext;
     349
     350 /g_mode/  $ process mode option.
     351      go to parsenext;
     352      end subr parse;
       1 .=member setmtyp
       2      subr setmtyp(hap, mt);  $ set mtyp of ha(hap), chain if new.
       3      size  hap(ps);   $ ha index.
       4      size  mt(ps);    $ desired mtyp value.
       5
       6      if (ha_mtyp ha(hap)) return; $ if type already set.
       7      ha_mtyp ha(hap) = mt;  $ set type.
       8      if  mtyporg(mt)=0  then  $ if first instance of type.
       9          mtyporg(mt) = hap;
      10      else
      11          ha_next ha(mtyplast(mt)) = hap;
      12          end if;
      13      mtyplast(mt) = hap;
      14      mtypnum(mt) = mtypnum(mt) + 1;
      15      end subr setmtyp;
       1 .=member gtoflo
       2      subr gtoflo(ipoin, lim);  $ increment counter
       3      $   increment -ipoin-, fatal error if -ipoin- >= -lim-.
       4      size  ipoin(ps);
       5      size  lim(ps);
       6      size  iword(ws+1);  $ name of array which overflowed
       7
       8      terml(yes);  $ write this to terminal file
       9      put ,error_notice ,' array overflow with index '
      10          :ipoin,i ,', with limit ' :lim,i ,skip;
      11      terml(no);  $ done with terminal file output
      12      call synexit(1);  $ terminate
      13      end subr gtoflo;
       1 .=member nextok
       2      subr nextok(hap);  $ get next token
       3      $   obtain next token from input stream, unless -keeptok- is on,
       4      $   in which case return prior token.
       5      $   check for 'special' period-delimited tokens,
       6      $   such as '.voadump.' which requests symbol table dump, etc.
       7      $   set -toklc- to literal code, -toklt- to lexical type,
       8      $   -toklen- to length of token in characters,
       9      $   -tokwords- to number of words in
      10      $   token, and insert token in array -tokara-.
      11      size  i(ps);            $ do loop index
      12      size  tokhdr(ws);  $ token descriptor word
      13      size  toktrace(1); data toktrace=0;  $ on to trace tokens read
      14      size  tokwords(ps);  $ no of words in token value
      15      size  toklclex(ps);  $ literal code from lex.
      16      size  fsd(ps);    $ index of first nonzero char in integer.
      17      size  nl(ps);     $ new length if eliminating leading zeros.
      18      size  v(ps);      $ value of implicit macro.
      19      size  c(ps);      $ character temporary.
      20      size  mt(ps);     $ implicit macro type.
      21      size  tokara(tokarasz); dims tokara(tokaradims); $ token array
      22
      23      +*  tokread1(wd) = $ get one word from token buffer/file
      24          if  tokrbufp >= tokrbuflim  then
      25          size  zzzv(ps);     $ io return code.
      26          call rdrwsio(tokenfile, zzzv, tokrbuf, 1, tokrbuflim);
      27              tokrbufp=0;
      28              end if;
      29          tokrbufp = tokrbufp + 1;  wd = tokrbuf(tokrbufp);
      30          **
      31
      32      +*  tokread(ara, wds) = $ read wds words into ara(1) to ara(wds).
      33          size  zzzi(ps);  $ do loop index.
      34          if  (wds+tokrbufp) >= tokrbuflim  then $ if would empty buf,
      35              do  zzzi = 1 to wds;
      36                  tokread1(ara(zzzi)); end do;
      37          else
      38              do  zzzi = 1 to wds;
      39                  ara(zzzi) = tokrbuf(tokrbufp + zzzi);  end do;
      40              tokrbufp = tokrbufp + wds;
      41              end if;
      42          **
      43      $   do  not read token till -find- clears -keeptok-
      44
      45      if  (keeptok)  return;
      46      keeptok = yes;
      47 /rdtok/
      48      tokread1(tokhdr);  $ read token descriptor
      49      toklt =tokrtyp tokhdr;  $ get lexical type/code
      50      toklclex = tokrlc tokhdr;
      51      toklen = tokrlen tokhdr;  $ no ov chars
      52      if  toktrace  then
      53          put ,'token trace ' :toklt :toklen :toklc,nil ,skip;
      54          end if;
      55      tokwords = (toklen-1)/cpw + 1;  $ no of words
      56      if  (toklen = 0)  tokwords = 0;
      57      go to t(toklt) in 1 to tokreof;
      58  /t(listcontroltok)/  $  .=list directive or change.
      59      if  toklen = 2  then  $ if list input directive change.
      60          listsw = toklclex;
      61      elseif  toklen = 1  then  $ if list code directive.
      62          listpt = toklclex;
      63          end if;
      64      go to rdtok;
      65 /t(listejecttok)/    $ .=eject
      66      put ,page;
      67      go to rdtok;
      68 /t(listtitletok)/    $ .=title
      69      go to rdtok;
      70
      71 /t(15)/  /t(16)/  /t(17)/  /t(18)/  /t(19)/ /t(20)/  /t(7)/  /t(10)/
      72 /t(21)/  /t(22)/  /t(23)/  /t(24)/  /t(25)/ /t(26)/  /t(11)/  /t(13)/
      73      call ermey(9);
      74
      75 /t(nametok)/
      76 /t(spectok)/
      77 /t(pdotok)/
      78 /t(dectok)/
      79 /t(sstok)/
      80 /t(strtok)/
      81 /t(bittok)/
      82 /t(qstok)/
      83 /t(rztok)/
      84 /t(realtok)/
      85
      86      assert toklen < (toklenmax-cpw);
      87
vax   18 .+s32    tokara(2) = blankword;
      88 .+s37    tokara(2) = blankword;
utsa  21 .+s47    tokara(2) = blankword;
      89      if  toklen <= cpstr  then
      90          tokara(1) = blankword;
      91          tokrval tokara(1) = tokrval tokhdr;
      92      else
      93          tokread(tokara, tokwords);
      94          end if;
      95      if  toktrace  then
      96          put,'token = ';
      97          do  i = 1 to tokwords;
      98               put :tokara(i),r(cpw);
      99              end do;
     100          put ,skip;
     101          end if;
     102      do  i = 1 to tokwords;  $ copy into insnamstr.
     103          .f. (1+.sds. toklenmax)-i*ws, ws, insnamstr = tokara(i);
     104          end do;
     105      .len. insnamstr = toklen;
     106      $   eliminate leading zeros if integer.
     107      if  toklt = dectok  then
     108          fsd = 1;
     109          while fsd1  then  $ if leading zeros.
     114              nl = toklen - fsd + 1;
     115                  toklen = nl;
     116              do  i = 1 to nl;
     117                  .ch. i, insnamstr = .ch. fsd+i-1, insnamstr;
     118                  end do;
     119              .len. insnamstr = nl;
     120              end if fsd;
     121          end if toklt;
     122      call insnam(nextokha);  $ hash token into ha
     123      $   check for possible implicit macro.
     124      until 1;
     125          if  (toklt^=nametok ! toklen<2)  quit until;
     126          c = .ch. 2, insnamstr;
     127          if  (c^=1r_)  quit until;
     128          i = (.s. 1, 1, insnamstr) .in. alphabet;
     129          if  (i=0)  quit until;
     130          if  (imara(i)=0)  quit until;  $ if not implicit macro code.
     131          mt = imara(i);  $ get macro type.
     132          call setmtyp(nextokha, mt);  $ see if correct type.
     133          if  (ha_mtyp ha(nextokha) ^= mt)  quit until;
     134          if  ha_mval ha(nextokha) = 0  then  $ if defining case.
     135              mtyptot(mt) = mtyptot(mt) + 1;
     136              ha_mval ha(nextokha) = mtyptot(mt);
     137              end if;
     138          v = ha_mval ha(nextokha);  $ get value.
     139          $   now hash in value as integer token, and use it.
     140          toklen = 1 + (v>9) + (v>99);
     141          .len. insnamstr = toklen;
     142          do  i = toklen to 1 by -1;
     143              .ch. i, insnamstr = charofdig(mod(v,10));
     144              v = v / 10;
     145              end do;
     146          toklt = dectok;
     147          call insnam(nextokha);
     148          end until;
     149
     150      toklc = ha_synlc ha(nextokha);
     151      lexlist(lexlistptr+1) = nextokha;  $ save token
     152      lexlistptr = (lexlistptr+1) & (lexlistmax-1);
     153 /dotok/
     154      if(toklt ^= pdotok) return;
     155      $   search for special syn directives.
     156      if  (toklc=0)  return;
     157      if  toklc = lc_synhalist  then  $ if .synhalist.
     158          call lstlin;
     159          call halist;
     160          go to rdtok;
     161      elseif  toklc = lc_synptlist  then  $ if .synptlist.
     162          call lstlin;
     163          call ptlist;
     164          go to rdtok;
     165      elseif  toklc = lc_synoptrace  then  $ if .synoptrace.
     166          parsetrace = yes;
     167          go to rdtok;
     168      elseif  toklc = lc_synnooptrace  then  $ if .synnooptrace.
     169          parsetrace = no;
     170          go to rdtok;
     171      elseif  toklc = lc_syntoktrace  then  $ if .syntoktrace.
     172          toktrace = yes;
     173          go to rdtok;
     174      elseif  toklc = lc_synnotoktrace  then  $ if .synnotoktrace.
     175          toktrace = no;
     176          go to rdtok;
     177          end if;
     178      return;
     179 /t(tokrline)/           $  line image being transmitted
     180      tokread(listwds, tokwords); $ read line image
     181      linelisted = no;  $ new line read, not yet listed
     182      linenumber = linenumber + 1;  $ updating line count
     183      listwdsp = tokwords;  $ save length
     184      if  listsw  then    $ list last line
     185          call lstlin;
     186          end if;
     187      go to rdtok;  $ get next token
     188 /t(tokreof)/  $ end-of-file token
     189      call ermsg(19);  call galt;
     190      call synexit(0);
     191      end subr nextok;
       1 .=member lstlin
       2      subr lstlin;  $ list input line.
       3      size  i(ps);    $ loop index.
       4      if  linelisted = no  then   $ must list last line
       5          put :linenumber,i(5) ,x(2);
       6          do  i = 1 to listwdsp;  $ list line image
       7              put :listwds(i),r(cpw);
       8              end do;
       9          put ,skip;
      10          linelisted = yes;  $ show line now listed
      11          end if;
      12      end subr lstlin;
       1 .=member toklist
       2      subr toklist; $ list recent tokens
       3      size  i(ps);  $ index in lexlist
       4      size  n(ps);  $ number listed
       5
       6      put ,x(15),'last few tokens: ';
       7      i = lexlistptr-1; $ set to start
       8      n = 0;
       9      while 1;
      10          i = (i+1) & (lexlistmax-1); $ bump i, modulo lexlistmax
      11          n = n+1; if (n>lexlistmax) quit while;
      12          if  (lexlist(i+1) = 0)  cont while;  $ ignore if not set
      13          call sdsnamr(lexlist(i+1));  $ get string form of token.
      14          put ,x :sdsnamstr,a;
      15          end while;
      16      put ,skip;
      17      listl(listsw=no) put ,skip; listl(yes)
      18      end subr toklist;
       1 .=member sdsnamr
       2      subr sdsnamr(hap);  $ get string form of ha entry
       3      $   convert name in names array to self defined string and
       4      $   return it in global variable sdsnamstr.
       5      size  hap(ps);    $ ha ptr
       6      size  i(ps);    $ do loop index
       7
       8      .len. sdsnamstr = 0;
       9      if  (hap<1 ! hap>hamax)  return;
      10      .len. sdsnamstr =  ha_len ha(hap);   $ set length field
      11      if  (.len. sdsnamstr = 0)  return;
      12      do  i = 1 to (ha_len ha(hap) -1) / cpw+1;
      13          .f.(1+.sds. toklenmax)-ws*i,ws,sdsnamstr
      14              = names(ha_names ha(hap)+i-1);
      15          end do;
      16
      17      end subr sdsnamr;
       1 .=member insnam
       2      subr insnam(hap);   $ insert name into ha.
       3
       4
       5      $   return the ha-index of an item, inserting it in the ha if
       6      $   necessary.
       7
       8      size  hcode(ws);  $ hash code of name
       9      size  j(ps);  $ ha-index of entry benng probed
      10      size  tokwords(ps);  $ words in token.
      11      size  hap(ps);         $ ha-index returned
      12      size  i(ps); $ do look index
      13      size  l(ps);  $ token length in characters.
      14      size  ara(ws);  dims ara((toklenmax+2*cpw)/cpw);
      15      size  probes(ps);   $ probes this search.
      16
      17      l = .len. insnamstr;
      18      tokwords = (l+(cpw-1)) / cpw;
      19      if  (l = 0)  tokwords = 0;
      20      do  i = 1 to tokwords;
      21          ara(i) = .f. (1+.sds. toklenmax)-i*ws, ws, insnamstr;
      22          end do;
      23      i = tokwords*cpw - l;  $ get number of chars to clear
      24      if  (i)  .f. 1, i*cs, ara(tokwords) = blankword;
      25      hcode = ara(1);
      26      do  i = 2 to tokwords;    $ compute hash code
      27          hcode = hcode .ex. ara(i);
      28          end do;
      29      hcode = .f. 1, ws/2, hcode .ex. .f. ws/2+1, ws/2, hcode;
      30      if  (hcode >= hamax) hcode = hcode-hamax*(hcode/hamax);
      31      if  hcode = 0  then  hcode = hamax-2;  end if; $ 0 code forbidden
      32      probes = 0;  j = 1;
      33
      34      while 1;
      35          if (probes > hamax) call ermey(3); $ ha is full-
      36          probes = probes + 1;
      37          j = j + hcode;  $ add original hashcode for next probe loc
      38          if  (j>hamax)  j = j - hamax;
      39          if  (ha_names ha(j) = 0)  quit while;  $ empty slot found
      40          if  (ha_len ha(j) ^= l)  cont while;
      41          do  i = 1 to tokwords; $ compare names
      42              if  (names(ha_names ha(j)+i-1) ^= ara(i)) cont while;
      43              end do;
      44          hap = j;
      45          return;
      46          end while;
      47
      48      $   add new name to ha.
      49      haused = haused + 1;
      50      ha_len ha(j) = l;    $ number of chars in name
      51      ha_names ha(j) = namesptr + 1;
      52      do  i = 1 to tokwords ;   $ enter name in names array
      53          countup(namesptr, namesmax, 'insert name');
      54          names(namesptr) = ara(i);
      55          end do;
      56      hap = j;
      57      end subr insnam;
       1 .=member ermet
       2      subr ermet; $  syntactic error message output procedure
       3
       4      $   report error number given by global ermsgno.  list current
       5      $   line, increment count, and terminate if error limit exceeded.
       6
       7      terml(yes);  $ give output to terminal too
       8      call lstlin;  $ list current line.
       9      nerrors = nerrors + 1;  $ update error count
      10      put ,error_notice;
      11
      12      if  ermsgno<1 ! ermsgno>parseerrmax  then
      13          go to e(0);
      14      else
      15          go to e(ermsgno) in 1 to parseerrmax;
      16          end if;
      17
      18      +*  et (erform, ertext) =
      19      call ermlst(erform, ertext); go to return; **
      20 / e( 0) /
      21      put ,'syntactic error number ' :ermsgno,i ,skip;
      22      go to return;
      23 / e( 1) /
      24      et('$definer', 'valid definer');
      25 / e( 2) /
      26      et('$<', '< before definer name');
      27 / e( 3) /
      28      et('< $name', 'definer name');
      29 / e( 4) /
      30      et('', '> after definer name');
      31 / e( 5) /
      32      et('= $definer', '');
      33 / e( 6) /
      34      et('=direct $/', '/ after direct part');
      35 / e( 7) /
      36      et('<* $name', 'name of lexical item');
      37 / e( 8) /
      38      et('<*name $>', '> after lexical name');
      39 / e( 9) /
      40      et('< $name', 'expect name after >');