home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sa104os2.zip / SATHR104.ZIP / SATHER / COMPILER / PARSE.SA < prev    next >
Text File  |  1995-02-13  |  82KB  |  2,322 lines

  1. -- Copyright (C) International Computer Science Institute, 1994.  COPYRIGHT  --
  2. -- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
  3. -- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in    --
  4. -- the file "Doc/License" of the Sather distribution.  The license is also   --
  5. -- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA.  --
  6. --------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
  7.  
  8. -- parse.sa: 1.0 version of parser for 1.0 Sather compiler.
  9. -------------------------------------------------------------------
  10. class PARSE is
  11.    -- Test the parser out.
  12.  
  13.    main(arg: ARRAY{STR}) is
  14.       if arg.size < 2 then #OUT + "Usage: " + arg[0] + " [-pSather] <files>\n" end;
  15.       #OUT + "Sather/pSather 1.0 parser - 9 Aug 94\n";
  16.       pSather: BOOL; i: INT;
  17.       if (arg.size > 1) and (arg[1] = "-pSather") then pSather := true; i := 2
  18.       else pSather := false; i := 1
  19.       end;
  20.       p ::= PROG::create;
  21.       loop while!(i < arg.size);
  22.          parser ::= PARSER::create(p, arg[i], pSather);
  23.          if ~void(parser) then
  24.             #OUT + "In file " + arg[i] + ":\n";
  25.             tcd: TR_CLASS_DEF := parser.source_file;
  26.             #OUT + "\n";
  27.             loop until!(void(tcd));
  28.                #OUT + ' ' + tcd.name.str + '\n';
  29.                tcd := tcd.next
  30.             end
  31.          end;
  32.          #OUT + "\n\n";
  33.          i := i+1
  34.       end
  35.    end
  36.  
  37. end; -- PARSE
  38.    
  39. -------------------------------------------------------------------   
  40. class LEX_CONST is
  41.    const
  42.    -- Sather tokens
  43.       eof_tok, null_tok, ident_tok, type_name_tok, and_tok, assert_tok,
  44.       attr_tok, break_tok, case_tok, class_tok, const_tok, else_tok,
  45.       elsif_tok, end_tok, exception_tok, external_tok, false_tok, if_tok,
  46.       include_tok, initial_tok, is_tok, ITER_tok, loop_tok, new_tok, or_tok,
  47.       post_tok, pre_tok, private_tok, protect_tok, quit_tok, raise_tok,
  48.       readonly_tok, result_tok, return_tok, ROUT_tok, SAME_tok, self_tok,
  49.       shared_tok, then_tok, true_tok, type_tok, typecase_tok, until_tok,
  50.       value_tok, void_tok, when_tok, while_tok, yield_tok, lint_tok, lflt_tok,
  51.       lstr_tok, lchar_tok, lparen_tok, rparen_tok, lbracket_tok, rbracket_tok,
  52.       lbrace_tok, rbrace_tok, comma_tok, dot_tok, semi_tok, colon_tok, under_tok,
  53.       plus_tok, minus_tok, times_tok, quotient_tok, is_lt_tok, is_gt_tok, sharp_tok,
  54.       bang_tok, iter_bang_tok, pow_tok, mod_tok, vbar_tok, is_neq_tok, is_leq_tok,
  55.       is_geq_tok, assign_tok, dcolon_tok, transform_tok, is_eq_tok, not_tok,
  56.       
  57.    -- pSather tokens
  58.       fork_tok, lock_tok, unlock_tok, try_tok, cobegin_tok, with_tok, at_tok,
  59.       here_tok, where_tok, near_tok, far_tok, spread_tok, dist_tok,
  60.       do_tok, as_tok
  61. end; -- LEX_CONST
  62.    
  63. -------------------------------------------------------------------   
  64. value class TOKEN is
  65.    include LEX_CONST;
  66.    
  67.    attr val: INT;
  68.  
  69.    create (val: INT): TOKEN is
  70.       t: TOKEN; t := t.val(val); return t
  71.    end;
  72.  
  73.    is_eq (y: INT): BOOL is return val = y end;
  74.    is_eq (y: TOKEN): BOOL is return val = y.val end;
  75.    is_neq (y: INT): BOOL is return val /= y end;
  76.    is_neq (y: TOKEN): BOOL is return val /= y.val end;
  77.  
  78.    str: STR is
  79.    -- A string version of the token.
  80.       res: STR;
  81.       case val
  82.    -- Sather tokens
  83.       when eof_tok then res := "end of file"
  84.       when null_tok then res := "null character"
  85.       when ident_tok then res := "an identifier"
  86.       when type_name_tok then res := "an abstract type name"
  87.       when and_tok then res := "'and'"
  88.       when assert_tok then res := "'assert'"
  89.       when attr_tok then res := "'attr'"
  90.       when break_tok then res := "'break'"
  91.       when case_tok then res := "'case'"
  92.       when class_tok then res := "'class'"
  93.       when const_tok then res := "'const'"
  94.       when else_tok then res := "'else'"
  95.       when elsif_tok then res := "'elsif'"
  96.       when end_tok then res := "'end'"
  97.       when exception_tok then res := "'exception'"
  98.       when external_tok then res := "'external'"
  99.       when false_tok then res := "'false'"
  100.       when if_tok then res := "'if'"
  101.       when include_tok then res := "'include'"
  102.       when initial_tok then res := "'initial'"
  103.       when is_tok then res := "'is'"
  104.       when ITER_tok then res := "'ITER'"
  105.       when loop_tok then res := "'loop'"
  106.       when new_tok then res := "'new'"
  107.       when or_tok then res := "'or'"
  108.       when post_tok then res := "'post'"
  109.       when pre_tok then res := "'pre'"
  110.       when private_tok then res := "'private'"
  111.       when protect_tok then res := "'protect'"
  112.       when quit_tok then res := "'quit'"
  113.       when raise_tok then res := "'raise'"
  114.       when readonly_tok then res := "'readonly'"
  115.       when return_tok then res := "'return'"
  116.       when ROUT_tok then res := "'ROUT'"
  117.       when SAME_tok then res := "'SAME'"
  118.       when self_tok then res := "'self'"
  119.       when shared_tok then res := "'shared'"
  120.       when then_tok then res := "'then'"
  121.       when true_tok then res := "true"
  122.       when type_tok then res := "type"
  123.       when typecase_tok then res := "'typecase'"
  124.       when value_tok then res := "'value'"
  125.       when void_tok then res := "'void'"
  126.       when when_tok then res := "'when'"
  127.       when while_tok then res := "'while!'"
  128.       when yield_tok then res := "'yield'"
  129.       when lint_tok then res := "an integer literal"
  130.       when lflt_tok then res := "a floating point literal"
  131.       when lstr_tok then res := "a string literal"
  132.       when lchar_tok then res := "a character literal"
  133.       when lparen_tok then res := "a left parenthesis '('"
  134.       when rparen_tok then res := "a right parenthesis ')'"
  135.       when lbracket_tok then res := "a left bracket '['"
  136.       when rbracket_tok then res := "a right bracket ']'"
  137.       when lbrace_tok then res := "a left brace '{'"
  138.       when rbrace_tok then res := "a right brace '}'"
  139.       when comma_tok then res := "a comma ','"
  140.       when dot_tok then res := "a dot '.'"
  141.       when semi_tok then res := "a semicolon ';'"
  142.       when colon_tok then res := "a colon ':'"
  143.       when under_tok then res := "an underscore '_'"
  144.       when plus_tok then res := "a plus '+'"
  145.       when minus_tok then res := "a minus '-'"
  146.       when times_tok then res := "an asterisk '*'"
  147.       when quotient_tok then res := "a slash '/'"
  148.       when is_lt_tok then res := "a less than '<'"
  149.       when is_gt_tok then res := "a greater than '>'"
  150.       when sharp_tok then res := "a sharp '#'"
  151.       when bang_tok, iter_bang_tok then res := "an exclamation mark '!'"
  152.       when pow_tok then res := "a carat '^'"
  153.       when mod_tok then res := "a percent '%'"
  154.       when vbar_tok then res := "a vertical bar '|'"
  155.       when is_neq_tok then res := "a not equals '/='"
  156.       when is_leq_tok then res := "a less than or equals '<='"
  157.       when is_geq_tok then res := "a greater than or equals '>='"
  158.       when assign_tok then res := "an assign operator ' := '"
  159.       when transform_tok then res := "a transform '->'"
  160.       when is_eq_tok then res := "a equals '='"
  161.       when not_tok then res := "a not '~'"
  162.       
  163.    -- pSather tokens
  164.       when fork_tok then res := "a fork ':-'"
  165.       when lock_tok then res := "'lock'"
  166.       when unlock_tok then res := "'unlock'"
  167.       when try_tok then res := "'try'"
  168.       when cobegin_tok then res := "'cobegin'"
  169.       when with_tok then res := "'with'"
  170.       when at_tok then res := "a at '@'"
  171.       when here_tok then res := "'here'"
  172.       when where_tok then res := "'where'"
  173.       when near_tok then res := "'near'"
  174.       when far_tok then res := "'far'"
  175.       when spread_tok then res := "'spread'"
  176.       when dist_tok then res := "'dist'"
  177.       when do_tok then res := "'do'"
  178.       when as_tok then res := "'as'"
  179.       
  180.       else res := "unknown token"
  181.       end;
  182.       return res
  183.    end;
  184.          
  185. end; -- TOKEN
  186.  
  187. ----------------------------------------------------------------------
  188.  
  189. value class SFILE_ID is
  190. -- A character position in a Sather source file. Used for generating error messages.
  191. -- Maintains a shared list of already processed files, and provides the routines for
  192. -- reading a file. Non-reentrant.
  193.  
  194.    const eof_char: CHAR := '\0'; -- returned at end of file
  195.  
  196.    private attr loc: INT;
  197.    private const B: INT := 1024; -- maximal line length
  198.    private const sentinel: INT := 2147483647;
  199.    private shared files: FLIST{STR}; -- list of registered file names
  200.    private shared lines: FLIST{INT}; -- list of accumulated lines (0 for first file)
  201.  
  202.    private shared source: FSTR; -- the current source file as a FSTR
  203.    private shared pos: INT; -- the current position in source line
  204.    private shared column: INT; -- the current column
  205.    private shared line_pos: INT; -- the position of the first character in the line
  206.    private shared newline: BOOL; -- next character starts a new line
  207.    private shared line: INT := 0; -- current accumulated line number
  208.  
  209.  
  210.    create (loc: INT): SFILE_ID is
  211.       r: SFILE_ID; r := r.loc(loc); return r
  212.    end;
  213.  
  214.    is_eq (y: SFILE_ID): BOOL is return loc = y.loc end;
  215.    is_neq (y: SFILE_ID): BOOL is return loc /= y.loc end;
  216.  
  217.    no_location: SFILE_ID is return #SFILE_ID(-1) end;
  218.  
  219.    open_file (p: PROG, name: STR): BOOL is
  220.       file: FILE := file.open_for_read(name);
  221.       if ~file.error then source := file.fstr; file.close
  222.       else source := void
  223.       end;
  224.       if ~void(source) then
  225.          if void(files) then
  226.             files := FLIST{STR}::create(64);
  227.             lines := FLIST{INT}::create(64);
  228.          end;
  229.          files := files.push(name);
  230.          lines := lines.push(sentinel);
  231.          pos := 0; column:=1; newline := true;
  232.          return true
  233. --    else                                                                      -- NLP
  234.       end;                                                                      -- NLP
  235.          p.set_eloc(no_location);
  236.          p.err("couldn't read file: " + name);
  237.          return false
  238. --    end                                                                       -- NLP
  239.    end;
  240.  
  241.    close_file is
  242.       if ~void(source) then lines[lines.size-1] := line; source := void end
  243.    end;
  244.  
  245.    next: CHAR is
  246.       if pos < source.size then
  247.          if newline then
  248.          line := line+1;
  249.          line_pos := pos;
  250.          newline := false;
  251.          column := 1;
  252.      end;
  253.          ch: CHAR := source[pos];
  254.      pos := pos+1;
  255.      case ch
  256.      when '\t' then column:=column+8-(column-1).mod(8);
  257.          when eof_char then ch := ' ' -- eof_char only at the end of the file
  258.          when '\n' then newline := true;
  259.      else newline:=false; column:=column+1;
  260.          end;
  261.          return ch
  262. --    else return eof_char                                                      -- NLP
  263.       end; return eof_char;                                                     -- NLP
  264. --    end                                                                       -- NLP
  265.    end;
  266.  
  267.    source_loc: SFILE_ID is
  268.       if ~void(source) then
  269.          c: INT := (column-2).min(SFILE_ID::B-1).max(1);
  270.          return #SFILE_ID(line*SFILE_ID::B + c)
  271. --    else return no_location                                                   -- NLP
  272.       end; return no_location;                                                  -- NLP
  273. --    end                                                                       -- NLP
  274.    end;
  275.  
  276.    ---------------------------------
  277.    -- The following routines operate on self
  278.    ---------------------------------
  279.  
  280.    private index: INT is
  281.    -- List index referred to encoded in loc
  282.       if ~void(lines) then
  283.          i: INT := 0;
  284.          l: INT := loc/SFILE_ID::B;
  285.          p: INT := -1;
  286.          loop while!(i < lines.size);
  287.             if (p < l) and (l <= lines[i]) then break! end;
  288.             p := lines[i]; i := i+1
  289.          end;
  290.          return i
  291.       else #OUT + "compiler error in SFILE_ID::index: no files\n";
  292. --       return 0                                                               -- NLP
  293.       end; return 0;                                                            -- NLP
  294. --    end                                                                       -- NLP
  295.    end;
  296.  
  297.    file_in: STR is
  298.    -- File name encoded in loc
  299.       return files[index]
  300.    end;
  301.  
  302.    line_num_in: INT is
  303.    -- Line number encoded in loc
  304.       i: INT := index;
  305.       if i > 0 then return loc/SFILE_ID::B - lines[i-1]
  306. --    else return loc/SFILE_ID::B                                               -- NLP
  307.       end; return loc/SFILE_ID::B;                                              -- NLP
  308. --    end                                                                       -- NLP
  309.    end;
  310.  
  311.    col_num_in: INT is
  312.    -- Column position encoded in loc
  313.       return loc.mod(SFILE_ID::B)
  314.    end;
  315.  
  316.    str: STR is
  317.    -- Name of the file into which loc is pointing
  318.       if loc = -1 then return "at unknown location"
  319. --    else return file_in + ':' + line_num_in + ':' + col_num_in                -- NLP
  320.       end; return file_in + ':' + line_num_in + ':' + col_num_in;               -- NLP
  321. --    end                                                                       -- NLP
  322.    end;
  323.  
  324. end; -- SFILE_ID
  325.  
  326. -------------------------------------------------------------------
  327.  
  328. class SCANNER is
  329.    -- Scanner for Sather 1.0.  Strategy: a big case statement.
  330.    -- Whitespace and comments are passed in tight loops.  Keywords
  331.    -- are distinguished from identifiers by switching on the first
  332.    -- character, followed by verification on the following characters
  333.    -- ordered by expected keyword frequency.
  334.  
  335.    include LEX_CONST; -- consts for tokens
  336.  
  337. -- Scan a string for Sather 1.0 tokens
  338.  
  339.    attr lex_value:IDENT; -- ident token value
  340.    attr char_value:CHAR; -- character token value
  341.    attr num_value:RAT; -- numerical value
  342.    attr value_type: INT; -- one of the five floating_point types (see TR_FLT_LIT_EXPR)
  343.                                      -- TR_FLT_LIT_EXPR::flt and TR_FLT_LIT_EXPR::flti also used for
  344.                                      -- integers
  345.  
  346.    attr prog: PROG;
  347.    attr next: CHAR;
  348.    attr buf: FSTR;
  349.    attr backed_up: BOOL;
  350.    attr last_char: CHAR;
  351.    attr pSather: BOOL;
  352.  
  353.    create (p: PROG, file: STR, pSather: BOOL): SCANNER is
  354.    -- initialize scanner, read f
  355.       res: SCANNER;
  356.       if SFILE_ID::open_file(p, file) then
  357.          res := new;
  358.          res.prog := p;
  359.          res.next := SFILE_ID::next;
  360.          res.buf := #FSTR(256);
  361.          res.backed_up := false;
  362.          res.pSather := pSather
  363.       else res := void
  364.       end;
  365.       return res
  366.    end;
  367.  
  368.    close_file is
  369.       SFILE_ID::close_file                
  370.    end;
  371.  
  372.    fetch is
  373.       if backed_up then
  374.          c: CHAR := next;
  375.          next := last_char;
  376.          last_char := c;
  377.          backed_up := false
  378.       else
  379.          last_char := next;
  380.          next := SFILE_ID::next
  381.       end 
  382.    end;
  383.  
  384.    backup is
  385.    -- Backup one character at most.
  386.    --
  387.       c: CHAR := next;
  388.       next := last_char;
  389.       last_char := c;
  390.       backed_up := true end;
  391.  
  392.    error (msg:STR) is
  393.    -- where errors during scanning go
  394.    --
  395.       prog.set_eloc(SFILE_ID::source_loc);
  396.       prog.err(msg) end;
  397.    
  398.    character: CHAR is
  399.    -- value of something preceeded by a backslash
  400.    --
  401.       res: CHAR;
  402.       fetch;
  403.       case next
  404.       when '0','1','2','3','4','5','6','7' then -- octal character
  405.          v: INT := 0; d: INT;
  406.          loop d := next.hex_digit_value;
  407.             while!((0 <= d) and (d < 8));
  408.             v := v*8 + d;
  409.             fetch
  410.          end;
  411.          res := v.char
  412.       when 'a' then res := '\a'; fetch
  413.       when 'b' then res := '\b'; fetch
  414.       when 'f' then res := '\f'; fetch
  415.       when 'n' then res := '\n'; fetch
  416.       when 'r' then res := '\r'; fetch
  417.       when 't' then res := '\t'; fetch
  418.       when 'v' then res := '\v'; fetch
  419.       when '\\' then res := '\\'; fetch
  420.       when '\'' then res := '\''; fetch
  421.       when '"' then res := '\"'; fetch
  422.       else res := next; fetch
  423.       end;
  424.       return res
  425.    end;
  426.  
  427.    identifier: TOKEN is
  428.    -- Find out if ident or keyword.
  429.    --
  430.       buf.clear;
  431.       loop c::=next;
  432.       while!(c.is_alphanum or (c = '_'));
  433.           buf := buf + c;
  434.       fetch;
  435.       end;
  436.       res ::= ident_tok;
  437.       case buf[0]
  438.       when 'a' then
  439.          case buf
  440.          when "attr" then res := attr_tok
  441.          when "and" then res := and_tok
  442.          when "assert" then res := assert_tok
  443.      when "as" then if pSather then res := as_tok end
  444.          else end
  445.       when 'b' then
  446.          if (buf = "break") and (next = '!') then fetch; res := break_tok end
  447.       when 'c' then
  448.          case buf
  449.          when "case" then res := case_tok
  450.          when "class" then res := class_tok
  451.          when "const" then res := const_tok
  452.          when "cobegin" then
  453.             if pSather then res := cobegin_tok end
  454.          else end
  455.       when 'd' then
  456.      if pSather then
  457.          case buf
  458.          when "dist" then res := dist_tok
  459.          when "do" then res := do_tok
  460.          else end
  461.      end
  462.       when 'e' then
  463.          case buf
  464.          when "end" then res := end_tok
  465.          when "elsif" then res := elsif_tok
  466.          when "else" then res := else_tok
  467.          when "exception" then res := exception_tok
  468.          when "external" then res := external_tok
  469.         else end
  470.       when 'f' then
  471.          case buf
  472.          when "false" then res := false_tok
  473.          when "far" then
  474.             if pSather then res := far_tok end
  475.          else end
  476.       when 'h' then
  477.          if (buf = "here") and pSather then res := here_tok end
  478.       when 'i' then
  479.          case buf
  480.          when "is" then res := is_tok
  481.          when "if" then res := if_tok
  482.          when "initial" then res := initial_tok
  483.          when "include" then res := include_tok
  484.         else end
  485.       when 'I' then
  486.          if buf = "ITER" then res := ITER_tok end
  487.       when 'l' then
  488.          case buf
  489.          when "loop" then res := loop_tok
  490.          when "lock" then
  491.             if pSather then res := lock_tok end
  492.          else end
  493.       when 'n' then
  494.          case buf
  495.          when "new" then res := new_tok
  496.          when "near" then
  497.             if pSather then res := near_tok end
  498.          else end
  499.       when 'o' then
  500.          if buf = "or" then res := or_tok end
  501.       when 'p' then
  502.          case buf
  503.          when "pre" then res := pre_tok
  504.          when "post" then res := post_tok
  505.          when "private" then res := private_tok
  506.          when "protect" then res := protect_tok
  507.         else end
  508.       when 'q' then
  509.          if buf = "quit" then res := quit_tok end
  510.       when 'r' then
  511.          case buf
  512.          when "return" then res := return_tok
  513.          when "result" then res := result_tok
  514.          when "readonly" then res := readonly_tok
  515.          when "raise" then res := raise_tok
  516.         else end
  517.       when 'R' then
  518.          if buf = "ROUT" then res := ROUT_tok end
  519.       when 's' then
  520.          case buf
  521.          when "self" then res := self_tok
  522.          when "shared" then res := shared_tok
  523.      when "spread" then if pSather then res := spread_tok end
  524.          else end
  525.       when 'S' then
  526.          if buf = "SAME" then res := SAME_tok end
  527.       when 't' then
  528.          case buf
  529.          when "then" then res := then_tok
  530.          when "true" then res := true_tok
  531.          when "type" then res := type_tok
  532.          when "typecase" then res := typecase_tok
  533.          when "try" then
  534.             if pSather then res := try_tok end
  535.          else end
  536.       when 'u' then
  537.          case buf
  538.          when "until" then
  539.             if next = '!' then fetch; res := until_tok end
  540.          when "unlock" then
  541.             if pSather then res := unlock_tok end
  542.          else end
  543.       when 'v' then
  544.          case buf
  545.          when "void" then res := void_tok
  546.          when "value" then res := value_tok
  547.          else end
  548.       when 'w' then
  549.          case buf
  550.          when "when" then res := when_tok
  551.          when "while" then
  552.             if next = '!' then fetch; res := while_tok end
  553.          when "where" then
  554.             if pSather then res := where_tok end
  555.          when "with" then
  556.             if pSather then res := with_tok end
  557.          else end
  558.       when 'y' then
  559.          if buf = "yield" then res := yield_tok end
  560.       else end;
  561.       if res = ident_tok then add_buf_to_sym_table end;
  562.       return #TOKEN(res)
  563.    end;
  564.  
  565.    add_buf_to_sym_table is
  566.    -- make sure in sym table, and set lex_value to id.
  567.    --
  568.       lex_value := prog.ident_for(buf.str)
  569.    end;
  570.  
  571.    int_literal (base: INT): INTI is
  572.       b ::= #INTI(base); x ::= #INTI(0);
  573.       loop d ::= next.hex_digit_value;
  574.          if next = '_' then fetch
  575.          elsif (0 <= d) and (d < base) then fetch; x := x*b + #INTI(d)
  576.          else break!
  577.          end
  578.       end;
  579.       return x
  580.    end;
  581.  
  582.    number: TOKEN is
  583.       res: INT := lint_tok; d ::= 10;
  584.       if next = '0' then fetch; -- check for special base
  585.          if next = 'b' then fetch; d := 2
  586.          elsif next = 'o' then fetch; d := 8
  587.          elsif next = 'x' then fetch; d := 16 end
  588.       end;
  589.       m ::= int_literal(d); e ::= #INTI(0);
  590.       if (next = '.') and (d = 10) then fetch;
  591.          d := next.digit_value;
  592.          if d >= 0 then -- floating point number
  593.             ec ::= 0; ten ::= #INTI(10);
  594.             loop
  595.                if next = '_' then fetch
  596.                elsif d >= 0 then fetch; m := m*ten + #INTI(d); ec := ec-1
  597.                else break!
  598.                end;
  599.                d := next.digit_value
  600.             end;
  601.             e := #INTI(ec);
  602.             if next = 'e' then fetch;
  603.                neg ::= false;
  604.                if next = '-' then fetch; neg := true end;
  605.                d := next.digit_value;
  606.                if d >= 0 then
  607.                   if neg then e := e - int_literal(10)
  608.                   else e := e + int_literal(10)
  609.                   end
  610.                else error("malformed floating point literal: e must be followed by - or a decimal digit")
  611.                end
  612.             end;
  613.             res := lflt_tok
  614.          else backup -- integer with a dot call
  615.          end
  616.       end;
  617.       if e.is_neg then num_value := #RAT(m, #INTI(10) ^ (-e.int))
  618.       else num_value := #RAT(m * #INTI(10) ^ e.int)
  619.       end;
  620.       value_type := TR_FLT_LIT_EXPR::flt; -- ordinary case
  621.       if next = 'i' then fetch; value_type := TR_FLT_LIT_EXPR::flti
  622.       elsif res = lflt_tok then
  623.          if next = 'd' then fetch;
  624.             if next = 'x' then fetch; value_type := TR_FLT_LIT_EXPR::fltdx
  625.             else value_type := TR_FLT_LIT_EXPR::fltd
  626.             end
  627.          elsif next = 'x' then fetch; value_type := TR_FLT_LIT_EXPR::fltx
  628.          end
  629.       end;
  630.       return #TOKEN(res)
  631.    end;
  632.    
  633.    skip_whitespace is
  634.       loop while!(next.is_space); fetch end
  635.    end;
  636.  
  637.    comment is
  638.       n ::= 1;
  639.       loop
  640.          while!((next /= SFILE_ID::eof_char) and (n > 0));
  641.          if next = '(' then fetch;
  642.             if next = '*' then fetch; n := n+1 end
  643.          elsif next = '*' then fetch;
  644.             if next = ')' then fetch; n := n-1 end
  645.          else fetch
  646.          end
  647.       end
  648.    end;
  649.    
  650.    is_class_name (s: STR): BOOL is
  651.    -- s is a legal identifier
  652.    --
  653.       loop if s.elt!.is_lower then return false end end;
  654.       return true 
  655.    end;
  656.  
  657.    token: TOKEN is
  658.    -- next Sather token; eof_tok if at end.
  659.    --
  660.       whitespace ::= false;
  661.       res: INT := null_tok;
  662.       loop
  663.          case next
  664.          when SFILE_ID::eof_char then res := eof_tok
  665.          when '\n', ' ', '\t', '\b', '\r', '\v' then
  666.             whitespace := true; skip_whitespace
  667.          when 'a','b','c','d','e','f','g','h','i','j','k','l','m',
  668.             'n','o','p','q','r','s','t','u','v','w','x','y','z',
  669.             'A','B','C','D','E','F','G','H','I','J','K','L','M',
  670.             'N','O','P','Q','R','S','T','U','V','W','X','Y','Z' then
  671.             res := identifier.val
  672.          when '(' then fetch;
  673.             if next = '*' then fetch; comment
  674.             else res := lparen_tok end
  675.          when ')' then fetch; res := rparen_tok
  676.          when '[' then fetch; res := lbracket_tok
  677.          when ']' then fetch; res := rbracket_tok
  678.          when '{' then fetch; res := lbrace_tok
  679.          when '}' then fetch; res := rbrace_tok
  680.          when ',' then fetch; res := comma_tok
  681.          when '.' then fetch; res := dot_tok
  682.          when ';' then fetch; res := semi_tok
  683.          when '$' then fetch;
  684.             if next.is_upper then
  685.                res := identifier.val;
  686.                if (res = ident_tok) and is_class_name(lex_value.str) then
  687.                   lex_value := prog.ident_for("$" + lex_value.str);
  688.                   res := type_name_tok
  689.                end
  690.             end;
  691.             if res /= type_name_tok then 
  692.                error("'$' without type name")
  693.             end
  694.          when '+' then fetch; res := plus_tok
  695.          when '-' then fetch;
  696.             if next = '-' then -- skip comment
  697.                loop fetch;
  698.                   until!((next = '\n') or (next = SFILE_ID::eof_char)) end;
  699.                if next = '\n' then fetch
  700.                else res := eof_tok end
  701.             elsif next = '>' then fetch; res := transform_tok
  702.             else res := minus_tok
  703.             end
  704.          when '*' then fetch; res := times_tok
  705.          when '#' then fetch; res := sharp_tok
  706.          when '^' then fetch; res := pow_tok
  707.          when '%' then fetch; res := mod_tok
  708.          when '|' then fetch; res := vbar_tok
  709.          when '!' then fetch;
  710.             if whitespace then res := bang_tok
  711.             else res := iter_bang_tok end
  712.          when '_' then fetch; res := under_tok
  713.          when '=' then fetch; res := is_eq_tok
  714.          when ':' then -- one of :,  := , ::, :  :=, :- 
  715.             fetch;
  716.             if next = ':' then fetch;
  717.                if next = '=' then        -- special case for " ::= "
  718.                   res := colon_tok;
  719.                   backup
  720.                else res := dcolon_tok end;
  721.             elsif next = '=' then fetch; res := assign_tok
  722.             elsif (next = '-') and pSather then res := fork_tok
  723.             else res := colon_tok end
  724.          when '/' then -- one of /, /=
  725.             fetch;
  726.             if next = '=' then fetch; res := is_neq_tok
  727.             else res := quotient_tok end
  728.          when '<' then -- one of <, <=
  729.             fetch;
  730.             if next = '=' then fetch; res := is_leq_tok
  731.             else res := is_lt_tok end
  732.          when '>' then -- one of >, >=
  733.             fetch;
  734.             if next = '=' then fetch; res := is_geq_tok
  735.             else res := is_gt_tok end
  736.          when '~' then fetch; res := not_tok
  737.          -- everything left is some kind of literal
  738.          when '\'' then -- a CHAR literal
  739.             fetch;
  740.             if next = '\\' then -- something funny, have to decode
  741.                char_value := character
  742.             else char_value := next; fetch
  743.             end;
  744.             if next /= '\'' then error("malformed character literal") end;
  745.             fetch; res := lchar_tok
  746.          when '"' then -- a STR literal
  747.             fetch;
  748.             buf.clear;
  749.             loop -- collect adjacent strings
  750.                loop until!(next = '"' or next = '\n');
  751.                   if next = '\\' then buf := buf + character;
  752.                   else buf := buf + next; fetch
  753.                   end
  754.                end;
  755.                if next = '\n' then
  756.                   error("unterminated STR literal");
  757.                   break! end;
  758.                fetch; skip_whitespace;
  759.                if next /= '"' then break! end;
  760.                fetch -- go past next " mark
  761.             end; -- outer loop
  762.             add_buf_to_sym_table;
  763.             res := lstr_tok
  764.          when '0','1','2','3','4','5','6','7','8','9' then res := number.val
  765.          when '@' then
  766.             if pSather then fetch; res := at_tok
  767.             else error("unknown character: '" + next + '\''); fetch
  768.             end;
  769.          else error("unknown character: '" + next + '\''); fetch
  770.          end;
  771.          while!(res = null_tok)
  772.       end;
  773.       return #TOKEN(res)
  774.    end
  775.    
  776. end; -- SCAN
  777.    
  778. ----------------------------------------------------------------------
  779. class PARSER is
  780.    include LEX_CONST;
  781.    
  782.    attr prog: PROG;
  783.    attr scanner: SCANNER;
  784.    attr next: TOKEN;
  785.    attr entered: FLIST{STR}; -- stack of grammatical procedure calls
  786.  
  787.    create (p: PROG, file: STR, pSather: BOOL): PARSER is
  788.       res: PARSER;
  789.       s ::= SCANNER::create(p, file, pSather); 
  790.       if ~void(s) then
  791.          res := new;
  792.          res.prog := p;
  793.          res.scanner := s;
  794.          res.next := res.scanner.token;
  795.          res.entered := FLIST{STR}::create(64)
  796.       else res := void
  797.       end;
  798.       return res
  799.    end;
  800.  
  801.    close_file is
  802.       scanner.close_file
  803.    end;
  804.    
  805.    source_loc: SFILE_ID is
  806.       return SFILE_ID::source_loc
  807.    end;
  808.  
  809.    error (msg: STR) is
  810.       -- where errors during parsing go
  811.       prog.set_eloc(source_loc);
  812.       prog.err(msg + " (in " + entered.top + ')')
  813.    end;
  814.  
  815.    exp_error (msg: STR) is
  816.       error(msg + " expected, but found " + next.str)
  817.    end;
  818.  
  819.    fetch is
  820.       next := scanner.token
  821.    end;
  822.  
  823.    match (t: INT) is
  824.       if next /= t then exp_error(#TOKEN(t).str) end;
  825.       fetch
  826.    end;
  827.  
  828.    check (t: INT): BOOL is
  829.       if next = t then fetch; return true
  830. --    else return false                                                         -- NLP
  831.       end; return false;                                                        -- NLP
  832. --    end                                                                       -- NLP
  833.    end;
  834.  
  835.    enter (s: STR) is
  836.    -- announce beginning of syntactic structure (for nice errors)
  837.    --
  838.       entered := entered.push(s)
  839.    end;
  840.  
  841.    exit is
  842.    -- exit from syntactic structure
  843.    --
  844.       s ::= entered.pop
  845.    end;
  846.  
  847.    ident: IDENT is
  848.       return scanner.lex_value
  849.    end;
  850.  
  851.    append_bang (arg: IDENT): IDENT is
  852.       -- make new version with trailing bang
  853.       return prog.ident_for(arg.str + "!")
  854.    end;    
  855.  
  856.    is_type_or_class_start (t: TOKEN): BOOL is
  857.       case t.val
  858.       when type_tok, spread_tok, value_tok, external_tok, class_tok then
  859.       return true
  860. --    else return false                                                         -- NLP
  861.       else; end; return false;                                                  -- NLP
  862. --    end                                                                       -- NLP
  863.    end;
  864.       
  865.    source_file: TR_CLASS_DEF is
  866.    -- source_file =>
  867.    -- [abstract_type_def | class] {';' [abstract_type_def | class]}
  868.    --
  869.       res: TR_CLASS_DEF;
  870.       enter("source file");
  871.       loop
  872.          if is_type_or_class_start(next) then
  873.             if next = type_tok then 
  874.            if void(res) then res:=abstract_type_def
  875.            else res.append(abstract_type_def) end;
  876.         else 
  877.            if void(res) then res:=class_def
  878.            else res.append(class_def) end end end;
  879.      if check(semi_tok) then -- ok
  880.      elsif is_type_or_class_start(next) then exp_error("semicolon")
  881.          else
  882.             if next /= eof_tok then exp_error("end of file") end;
  883.             break! end end;
  884.       close_file;
  885.       exit; return res
  886.    end;
  887.  
  888.    abstract_type_def: TR_CLASS_DEF is
  889.    -- abstract_type_def =>
  890.    -- 'type' abstract_type_name
  891.    -- ['{' param_dec {',' param_dec}'}']
  892.    -- ['<' type_spec_list] ['>' type_spec_list]
  893.    -- 'is' [abstract_signature] {';' [abstract_signature]} 'end'
  894.    --
  895.       enter("abstract type definition");
  896.       res ::= #TR_CLASS_DEF; res.source := source_loc; res.kind := res.abs;
  897.       match(type_tok);
  898.       if check(type_name_tok) then --ok
  899.       else exp_error("abstract type name");
  900.          if next = ident_tok then fetch end
  901.       end;
  902.       res.name := ident;
  903.       if check(lbrace_tok) then
  904.          loop until!(next /= ident_tok);
  905.         if void(res.params) then res.params:=param_dec
  906.         else res.params.append(param_dec) end;
  907.             if ~check(comma_tok) then break! end end;
  908.          match(rbrace_tok) end;
  909.       if check(is_lt_tok) then res.under := type_spec_list end;
  910.       if check(is_gt_tok) then res.over := type_spec_list end;
  911.       match(is_tok);
  912.       res.body := abstract_signature_list;
  913.       match(end_tok);
  914.       exit;
  915.       return res
  916.    end;
  917.  
  918.    abstract_signature_list: $TR_CLASS_ELT is
  919.    -- abstract_signature_list => 
  920.    -- [abstract_signature] {';' [abstract_signature]}
  921.    --
  922.       res: $TR_CLASS_ELT;
  923.       enter("list of abstract signatures");
  924.       loop
  925.          if (next = ident_tok) or (next = bang_tok) or
  926.             (next = iter_bang_tok) then
  927.             if void(res) then res := abstract_signature
  928.             else res.append(abstract_signature) end
  929.          end;
  930.          if check(semi_tok) then -- ok
  931.          elsif next = ident_tok then exp_error("semicolon")
  932.          else break!
  933.          end
  934.       end;
  935.       if next /= end_tok then
  936.          exp_error("semicolon");
  937.          loop while!((next /= end_tok) and (next /= eof_tok)); fetch end
  938.       end;
  939.       exit;
  940.       return res
  941.    end;
  942.  
  943.    abstract_signature: TR_ROUT_DEF is
  944.    -- abstract_signature =>
  945.    -- (ident | iter_name)
  946.    -- ['(' abstract_argument {',' abstract_argument} ')']
  947.    -- [':' type_spec]
  948.    --
  949.       enter("abstract signature");
  950.       res ::= #TR_ROUT_DEF; res.source := source_loc; res.is_abstract := true;
  951.       res.name := rout_or_iter_name;
  952.       if check(lparen_tok) then
  953.          enter("abstract arguments");
  954.          loop
  955.         if void(res.args_dec) then 
  956.            res.args_dec:=abstract_argument(res.name.is_iter);
  957.         else res.args_dec.append(
  958.            abstract_argument(res.name.is_iter)) end;
  959.             while!(check(comma_tok)) end;
  960.          match(rparen_tok);
  961.          exit end;
  962.       if check(colon_tok) then 
  963.          enter("return type specification");
  964.          res.ret_dec := type_spec; 
  965.          exit end;
  966.       exit;
  967.       return res
  968.    end;
  969.  
  970.    abstract_argument (is_iter: BOOL): TR_ARG_DEC is
  971.    -- arg_dec => [ident {',' ident} ':'] type_spec ['!']
  972.    --
  973.       res: TR_ARG_DEC;
  974.       enter("abstract argument");
  975.       loop
  976.          newa ::= #TR_ARG_DEC; newa.source := source_loc;
  977.          match(ident_tok);
  978.          newa.name := ident;
  979.          if void(res) then res := newa 
  980.          else res.append(newa)
  981.          end;
  982.          while!(check(comma_tok))
  983.       end;
  984.       match(colon_tok);
  985.       tp:TR_TYPE_SPEC := type_spec;
  986.       hot:BOOL := check(bang_tok) or check(iter_bang_tok);
  987.       if hot and ~is_iter then
  988.          error("hot arguments not allowed in routine declarations")
  989.       end;
  990.       p: TR_ARG_DEC := res;
  991.       loop until!(void(p)); p.tp := tp; p.is_hot := hot; p := p.next end;
  992.       exit;
  993.       return res
  994.    end;
  995.  
  996.    class_def: TR_CLASS_DEF is
  997.    -- class =>
  998.    --        ['spread' | 'value' | 'external'] 'class' uppercase_ident
  999.    --        ['{' param_dec {',' param_dec}'}']
  1000.    --        ['<' type_spec_list]
  1001.    --        'is' class_elt_list 'end'
  1002.    --
  1003.       enter("class");
  1004.       res ::= #TR_CLASS_DEF; res.source := source_loc;
  1005.       case next.val
  1006.       when spread_tok then fetch; res.kind := res.spr
  1007.       when value_tok then fetch; res.kind := res.val
  1008.       when external_tok then fetch; res.kind := res.ext
  1009.       else res.kind := res.ref end;
  1010.       match(class_tok);
  1011.       if check(ident_tok) then
  1012.          if ~is_class_name(ident) then
  1013.             exp_error("class name")
  1014.          end
  1015.       else exp_error("concrete class name");
  1016.          if next = type_name_tok then fetch end
  1017.       end;
  1018.       res.name := ident;
  1019.       if check(lbrace_tok) then
  1020.          loop until!(next /= ident_tok);
  1021.         if void(res.params) then res.params:=param_dec
  1022.         else res.params.append(param_dec) end;
  1023.             if ~check(comma_tok) then break! end end;
  1024.          match(rbrace_tok) end;
  1025.       if check(is_lt_tok) then res.under := type_spec_list end;
  1026.       match(is_tok);
  1027.       res.body := class_elt_list;
  1028.       match(end_tok);
  1029.       exit;
  1030.       return res
  1031.    end;
  1032.  
  1033.    is_class_name (x: IDENT): BOOL is
  1034.       return SCANNER::is_class_name(x.str)
  1035.    end;
  1036.  
  1037.    param_dec: TR_PARAM_DEC is
  1038.    -- param_dec => uppercase_ident ['<' type_spec]
  1039.    --
  1040.       enter("parameter declaration");
  1041.       res ::= #TR_PARAM_DEC; res.source := source_loc;
  1042.       match(ident_tok); res.name := ident;
  1043.       if ~is_class_name(res.name) then 
  1044.          exp_error("class name") end;
  1045.       if check(is_lt_tok) then res.type_constraint := type_spec end;
  1046.       exit;
  1047.       return res
  1048.    end;
  1049.  
  1050.    is_class_elt_start (t: TOKEN): BOOL is
  1051.       case t.val
  1052.       when private_tok, readonly_tok, const_tok, shared_tok,
  1053.          attr_tok, include_tok, ident_tok, bang_tok, iter_bang_tok
  1054.       then return true
  1055. --    else return false                                                         -- NLP
  1056.       else; end; return false;                                                  -- NLP
  1057. --    end                                                                       -- NLP
  1058.    end;
  1059.  
  1060.    class_elt_list: $TR_CLASS_ELT is
  1061.    -- class_elt_list => [class_elt] {';' [class_elt]}
  1062.    --
  1063.       res: $TR_CLASS_ELT;
  1064.       enter("list of class elements");
  1065.       loop
  1066.          if is_class_elt_start(next) then
  1067.             if void(res) then res := class_elt
  1068.             else res.append(class_elt) end end;
  1069.          if check(semi_tok) then -- ok
  1070.          elsif is_class_elt_start(next) then exp_error("semicolon")
  1071.          else break! end end;
  1072.       if next /= end_tok then
  1073.       exp_error("semicolon");
  1074.       loop while!((next /= end_tok) and (next /= eof_tok)); fetch end end;
  1075.       exit;
  1076.       return res
  1077.    end;
  1078.  
  1079.    class_elt: $TR_CLASS_ELT is
  1080.    -- class_elt => include_clause | const_def | shared_def | attr_def | 
  1081.    --    rout_def | iter_def
  1082.    --
  1083.       res: $TR_CLASS_ELT;
  1084.       enter("class element");
  1085.       mode ::= #TOKEN(null_tok);
  1086.       if (next = private_tok) or (next = readonly_tok) then mode := next; fetch end;
  1087.       case next.val
  1088.       when include_tok then res := include_clause(mode)
  1089.       when const_tok then res := const_def(mode)
  1090.       when shared_tok then res := shared_def(mode)
  1091.       when attr_tok then res := attr_def(mode)
  1092.       else res := rout_def(mode)
  1093.       end;
  1094.       exit;
  1095.       return res
  1096.    end;
  1097.  
  1098.    include_clause (mode: TOKEN): $TR_CLASS_ELT is
  1099.    -- include_clause => 'include' type_spec [feat_mod {',' feat_mod}]
  1100.    -- feat_mod => ident '->' [['private' | 'readonly'] ident]
  1101.    --
  1102.    -- 'private' already seen and stripped if present.
  1103.    --
  1104.       res: $TR_CLASS_ELT;
  1105.       enter("include clause");
  1106.       if mode = readonly_tok then 
  1107.          error("readonly not allowed for includes") end;
  1108.       match(include_tok);
  1109.       incl ::= #TR_INCLUDE_CLAUSE; incl.source := source_loc;
  1110.       incl.is_private := mode = private_tok;
  1111.       incl.tp := type_spec;
  1112.       res := incl;
  1113.       if (next = ident_tok) or (next = bang_tok) or (next = iter_bang_tok) then
  1114.          loop
  1115.             newm ::= #TR_FEAT_MOD; newm.source := source_loc;
  1116.             newm.name := rout_or_iter_name;
  1117.             match(transform_tok);
  1118.             case next.val
  1119.             when private_tok then fetch;
  1120.                newm.is_private := true;
  1121.                newm.new_name := rout_or_iter_name
  1122.             when readonly_tok then fetch;
  1123.                newm.is_readonly := true;
  1124.                newm.new_name := rout_or_iter_name
  1125.             when ident_tok, bang_tok, iter_bang_tok then 
  1126.                newm.new_name := rout_or_iter_name
  1127.             else end;
  1128.             if ~void(newm.new_name) then
  1129.                if newm.name.is_iter /= newm.new_name.is_iter then
  1130.                   error("routine can't become an iter or vice versa")
  1131.                end
  1132.             end;
  1133.         if void(incl.mods) then incl.mods:=newm
  1134.         else incl.mods.append(newm) end;
  1135.             while!(check(comma_tok))
  1136.          end
  1137.       end;
  1138.       exit;
  1139.       return res
  1140.    end;
  1141.  
  1142.    const_def (mode: TOKEN): $TR_CLASS_ELT is
  1143.    -- const_def =>
  1144.    --        ['private'] 'const' ident
  1145.    --        (':' type_spec ' := ' expr | [' := ' expr][',' ident_list])
  1146.    --
  1147.    -- private_tok already seen and stripped if present.
  1148.    --
  1149.       res: $TR_CLASS_ELT;
  1150.       enter("const definition");
  1151.       if mode = readonly_tok then 
  1152.          error("readonly not allowed for constants") end;
  1153.       match(const_tok);
  1154.       con ::= #TR_CONST_DEF; con.source := source_loc;
  1155.       con.is_private := mode = private_tok;
  1156.       res := con;
  1157.       match(ident_tok);
  1158.       con.name := ident;
  1159.       if check(colon_tok) then
  1160.          con.tp := type_spec; match(assign_tok); con.init := expr
  1161.       else
  1162.          if check(assign_tok) then con.init := expr
  1163.          else zero ::= #TR_INT_LIT_EXPR; zero.source := source_loc; zero.val := #INTI(0); 
  1164.             con.init := zero
  1165.          end;
  1166.          counter: INT := 1;
  1167.          loop while!(check(comma_tok));
  1168.             -- new constant
  1169.             newc ::= #TR_CONST_DEF; newc.source := source_loc;
  1170.             newc.is_private := mode = private_tok;
  1171.             match(ident_tok);
  1172.             newc.name := ident;
  1173.                -- new value
  1174.             arg ::= #TR_INT_LIT_EXPR; arg.source := source_loc; arg.val := #INTI(counter);
  1175.             ex ::= #TR_CALL_EXPR; ex.source := source_loc;
  1176.             ex.ob := con.init;
  1177.             ex.name := prog.ident_builtin.plus_ident;
  1178.             ex.args := arg;
  1179.             newc.init := ex;
  1180.         if void(res) then res:=newc
  1181.         else res.append(newc) end;
  1182.             counter := counter+1
  1183.          end
  1184.       end;
  1185.       exit;
  1186.       return res
  1187.    end;
  1188.  
  1189.    shared_def (mode: TOKEN): $TR_CLASS_ELT is
  1190.    -- shared_def =>
  1191.    --        'shared' (ident ':' type_spec ':=' expr | 
  1192.    --        ident_list ':' type_spec)
  1193.    --
  1194.    -- private or readonly already stripped if present.
  1195.    --
  1196.       res: $TR_CLASS_ELT;
  1197.       enter("shared definition");
  1198.       match(shared_tok);
  1199.       loop
  1200.          newid ::= #TR_SHARED_DEF; newid.source := source_loc;
  1201.          newid.is_private := mode = private_tok;
  1202.          newid.is_readonly := mode = readonly_tok;
  1203.          match(ident_tok);
  1204.          newid.name := ident;
  1205.          if void(res) then res := newid
  1206.          else res.append(newid)
  1207.          end;
  1208.          while!(check(comma_tok)) end;
  1209.       match(colon_tok);
  1210.       tp: TR_TYPE_SPEC := type_spec;
  1211.       p: $TR_CLASS_ELT := res;
  1212.       loop until!(void(p));
  1213.          typecase p when TR_SHARED_DEF then p.tp := tp end;
  1214.          p := p.next
  1215.       end;
  1216.       if check(assign_tok) then
  1217.          typecase res when TR_SHARED_DEF then res.init := expr end;
  1218.          if ~void(res.next) then
  1219.             error("only single shareds may be initialized") end end;
  1220.       exit;
  1221.       return res
  1222.    end;
  1223.    
  1224.    attr_def (mode: TOKEN): $TR_CLASS_ELT is
  1225.    -- attr_def =>  'attr' ident_list ':' type_spec
  1226.    --
  1227.    -- private or readonly already stripped if present.
  1228.    --
  1229.       res: $TR_CLASS_ELT;
  1230.       enter("attribute definition");
  1231.       match(attr_tok);
  1232.       loop
  1233.          newid ::= #TR_ATTR_DEF; newid.source := source_loc;
  1234.          newid.is_private := mode = private_tok;
  1235.          newid.is_readonly := mode = readonly_tok;
  1236.          match(ident_tok);
  1237.          newid.name := ident;
  1238.          if void(res) then res := newid
  1239.          else res.append(newid)
  1240.          end;
  1241.          while!(check(comma_tok)) end;
  1242.       match(colon_tok);
  1243.       tp:TR_TYPE_SPEC := type_spec;
  1244.       p: $TR_CLASS_ELT := res;
  1245.       loop until!(void(p));
  1246.          typecase p when TR_ATTR_DEF then p.tp := tp end;
  1247.          p := p.next
  1248.       end;
  1249.       exit;
  1250.       return res
  1251.    end;
  1252.  
  1253.    type_spec: TR_TYPE_SPEC is
  1254.    -- type_spec =>
  1255.    --        class_name ['{' type_spec_list '}'] |
  1256.    --        ('ROUT' | 'ITER') ['{' type_spec ['!'] 
  1257.    --                {',' type_spec ['!']} '}'] [':' type_spec] |
  1258.    --        'SAME'
  1259.    --
  1260.       enter("type specification");
  1261.       res ::= #TR_TYPE_SPEC; res.source := source_loc;
  1262.       if check(SAME_tok) then res.kind := TR_TYPE_SPEC::same
  1263.       elsif (next = type_name_tok) or (next = ident_tok) then
  1264.          if (next = ident_tok) and ~is_class_name(ident) then
  1265.             error("class name must be all upper_case") end;
  1266.          res.kind := TR_TYPE_SPEC::ord;
  1267.          res.name := ident; fetch;
  1268.          if check(lbrace_tok) then
  1269.             res.params := type_spec_list;
  1270.             match(rbrace_tok) end
  1271.       else
  1272.          if check(ROUT_tok) then res.kind := TR_TYPE_SPEC::rt
  1273.          elsif check(ITER_tok) then res.kind := TR_TYPE_SPEC::it
  1274.          else exp_error("type specifier") end;
  1275.          if check(lbrace_tok) then
  1276.             loop
  1277.                tp:TR_TYPE_SPEC := type_spec;
  1278.                if check(bang_tok) or check(iter_bang_tok) then
  1279.                   if res.kind = TR_TYPE_SPEC::it then tp.is_hot := true
  1280.                   else error("no hot arguments in bound routine") end end;
  1281.            if void(res.params) then res.params:=tp
  1282.            else res.params.append(tp) end;
  1283.                while!(check(comma_tok)) end;
  1284.             match(rbrace_tok) end;
  1285.          if check(colon_tok) then res.ret := type_spec end end;
  1286.       exit;
  1287.       return res
  1288.    end;
  1289.  
  1290.    type_spec_list: TR_TYPE_SPEC is
  1291.    -- type_spec_list => type_spec {',' type_spec}
  1292.    --
  1293.       enter("list of type specifications");
  1294.       res ::= type_spec;
  1295.       loop while!(next = comma_tok);
  1296.          fetch; res.append(type_spec)
  1297.       end;
  1298.       exit;
  1299.       return res
  1300.    end;
  1301.  
  1302.    rout_or_iter_name: IDENT is
  1303.    -- rout_or_iter_name => ident | [ident] '!'
  1304.    --
  1305.       res: IDENT;
  1306.       if next = ident_tok then res := ident; fetch;
  1307.          if next = iter_bang_tok then fetch;
  1308.             res := append_bang(res)
  1309.          elsif next = bang_tok then fetch;
  1310.             res := append_bang(res); error("not a correct iter_name")
  1311.          end
  1312.       elsif (next = bang_tok) or (next = iter_bang_tok) then fetch;
  1313.          res := prog.ident_for("!")
  1314.       else exp_error("routine or iter name"); res := prog.ident_for("a")
  1315.       end;
  1316.       return res
  1317.    end;
  1318.  
  1319.    rout_def (mode: TOKEN): TR_ROUT_DEF is
  1320.    -- rout_def =>
  1321.    --        (ident | iter_name) ['(' arg_dec {',' arg_dec} ')'] 
  1322.    --        [':' type_spec]
  1323.    --        ['pre' expr] ['post' expr]
  1324.    --        ['is' stmt_list 'end']
  1325.    --
  1326.    -- private already stripped if present.
  1327.    --
  1328.       res: TR_ROUT_DEF;
  1329.       enter("routine or iter definition");
  1330.       if mode = readonly_tok then 
  1331.          error("readonly not allowed for routines or iters") end;
  1332.       res := #TR_ROUT_DEF; res.source := source_loc;
  1333.       res.name := rout_or_iter_name;
  1334.       res.is_private := mode = private_tok;
  1335.       if check(lparen_tok) then
  1336.          enter("arguments");
  1337.          loop
  1338.         if void(res.args_dec) then 
  1339.            res.args_dec:=arg_dec(res.name.is_iter)
  1340.         else res.args_dec.append(arg_dec(res.name.is_iter)) end;
  1341.             while!(check(comma_tok)) end;
  1342.          match(rparen_tok);
  1343.          exit end;
  1344.       if check(colon_tok) then 
  1345.          enter("return type specification");
  1346.          res.ret_dec := type_spec; 
  1347.          exit end;
  1348.       if check(pre_tok) then 
  1349.          enter("precondition declaration");
  1350.          res.pre_e := expr; 
  1351.          exit end;
  1352.       if check(post_tok) then 
  1353.          enter("postcondition declaration");
  1354.          res.post_e := expr; 
  1355.          exit end;
  1356.       if check(is_tok) then
  1357.          enter("routine/iter body");
  1358.          res.stmts := stmt_list; res.is_abstract := false;
  1359.          match(end_tok);
  1360.          exit
  1361.       else res.is_abstract:=true end;
  1362.       exit;
  1363.       return res
  1364.    end;
  1365.  
  1366.    arg_dec (is_iter: BOOL): TR_ARG_DEC is
  1367.    -- arg_dec => ident {',' ident} ':' type_spec ['!']
  1368.    --
  1369.       res: TR_ARG_DEC;
  1370.       enter("routine/iter argument declaration");
  1371.       loop
  1372.          newa ::= #TR_ARG_DEC; newa.source := source_loc;
  1373.          match(ident_tok);
  1374.          newa.name := ident;
  1375.      if void(res) then res:=newa
  1376.      else res.append(newa) end;
  1377.          while!(check(comma_tok)) end;
  1378.       match(colon_tok);
  1379.       tp:TR_TYPE_SPEC := type_spec;
  1380.       hot:BOOL := check(bang_tok) or check(iter_bang_tok);
  1381.       if hot and ~is_iter then
  1382.          error("hot arguments not allowed in routine declarations") end;
  1383.       p:TR_ARG_DEC := res;
  1384.       loop until!(void(p)); p.tp := tp; p.is_hot := hot; p := p.next end;
  1385.       exit;
  1386.       return res
  1387.    end;
  1388.  
  1389.    ident_of (x: $TR_EXPR): IDENT is
  1390.    -- make sure x consists of an ident only
  1391.    --
  1392.       typecase x when TR_CALL_EXPR then
  1393.           if void(x.ob) and ~void(x.name) and void(x.args) then return x.name end
  1394.       else end;
  1395.       error("identifier only expected");
  1396.       return void
  1397.    end;
  1398.       
  1399.    break_stmt:TR_EXPR_STMT is
  1400.       res ::= #TR_EXPR_STMT; res.source := source_loc; res.e := #TR_BREAK_EXPR;
  1401.       return res
  1402.    end;
  1403.  
  1404.    make_if_stmt (test: $TR_EXPR, then_part, else_part: $TR_STMT): TR_IF_STMT is
  1405.       res ::= #TR_IF_STMT; res.source := source_loc; res.test := test; 
  1406.       res.then_part := then_part; 
  1407.       res.else_part := else_part;
  1408.       return res
  1409.    end;
  1410.  
  1411.    stmt: $TR_STMT is
  1412.    -- stmt =>
  1413.    -- dec_stmt | assign_stmt | expr_stmt |
  1414.    -- if_stmt | loop_stmt | return_stmt | yield_stmt | quit_stmt |
  1415.    -- case_stmt | typecase_stmt | assert_stmt | protect_stmt | raise_stmt
  1416.    -- while!_expr | until!_expr | break!_expr |
  1417.    -- cobegin_stmt | lock_stmt | unlock_stmt | try_stmt | with_near_stmt |
  1418.    -- fork_stmt | dist_stmt
  1419.    --
  1420.    -- (while!_expr's and until!_expr's are transformed into aquivalent
  1421.    -- if statements and break!'s)
  1422.    --
  1423.       res: $TR_STMT;
  1424.       enter("statement");
  1425.       was_at: SFILE_ID := source_loc;
  1426.       case next.val
  1427.       when if_tok then fetch; res := if_stmt
  1428.       when loop_tok then res := loop_stmt
  1429.       when return_tok then res := return_stmt
  1430.       when yield_tok then res := yield_stmt
  1431.       when quit_tok then fetch; res := #TR_QUIT_STMT; res.source := source_loc;
  1432.       when case_tok then res := case_stmt
  1433.       when typecase_tok then res := typecase_stmt
  1434.       when assert_tok then res := assert_stmt
  1435.       when protect_tok then res := protect_stmt
  1436.       when raise_tok then res := raise_stmt
  1437.       when cobegin_tok then res := cobegin_stmt
  1438.       when lock_tok then res := lock_stmt
  1439.       when unlock_tok then res := unlock_stmt
  1440.       when try_tok then res := try_stmt
  1441.       when with_tok then res := with_near_stmt
  1442.       when dist_tok then res := dist_stmt
  1443.       when fork_tok then
  1444.          enter("fork statement (without LHS)");
  1445.          fetch;
  1446.          r ::= #TR_FORK_STMT; r.source := source_loc;
  1447.          r.lhs := void; r.rhs := expr; res := r;
  1448.          exit
  1449.       when while_tok then
  1450.          enter("while! expression");
  1451.          fetch; match(lparen_tok);
  1452.          res := make_if_stmt(expr, void, break_stmt);
  1453.          match(rparen_tok);
  1454.          exit
  1455.       when until_tok then
  1456.          enter("until! expression");
  1457.          fetch; match(lparen_tok);
  1458.          res := make_if_stmt(expr, break_stmt, void);
  1459.          match(rparen_tok);
  1460.          exit
  1461.       when break_tok then
  1462.          fetch; res := break_stmt
  1463.       else
  1464.          -- must be one of:dec_stmt, assign_stmt, fork_stmt (with lhs) or expr_stmt:
  1465.          --                
  1466.          -- dec_stmt => ident_list ':' type_spec
  1467.          -- assign_stmt => (expr | ident ':' [type_spec]) ' := ' expr
  1468.          -- expr_stmt => expr
  1469.          --
  1470.          -- none of these can be easily distinguished; all may start
  1471.          -- with identifiers.  However, all look like they start
  1472.          -- with expr's, so do that and then patch up.
  1473.          x: $TR_EXPR := expr;
  1474.          if check(colon_tok) then -- ident ':'
  1475.             tp: TR_TYPE_SPEC;
  1476.             if next /= assign_tok then tp := type_spec end;
  1477.             if check(assign_tok) then -- ident ':' [type_spec] ' := '
  1478.                enter("assignment with declaration");
  1479.                r ::= #TR_ASSIGN_STMT; r.source := source_loc;
  1480.                r.name := ident_of(x); r.tp := tp; r.rhs := expr; res := r;
  1481.                exit
  1482.             else -- ident ':' type_spec
  1483.                enter("single variable declaration");
  1484.                sdecl_res ::= #TR_DEC_STMT; sdecl_res.source := source_loc;
  1485.                sdecl_res.name := ident_of(x);
  1486.                sdecl_res.tp := tp;
  1487.                res := sdecl_res;
  1488.                exit
  1489.             end
  1490.          elsif check(assign_tok) then -- expr ':='
  1491.             enter("assignment");
  1492.             r ::= #TR_ASSIGN_STMT; r.source := source_loc;
  1493.             r.lhs_expr := x; r.rhs := expr; res := r;
  1494.             exit
  1495.          elsif check(fork_tok) then -- expr ':-'
  1496.             enter("fork statement (with LHS)");
  1497.             r ::= #TR_FORK_STMT; r.source := source_loc;
  1498.             r.lhs := x; r.rhs := expr; res := r;
  1499.             exit
  1500.          elsif next = comma_tok then -- ident ','
  1501.             enter("declaration");
  1502.             decl_res ::= #TR_DEC_STMT; decl_res.source := source_loc;
  1503.             decl_res.name := ident_of(x);
  1504.             res := decl_res;
  1505.             loop while!(check(comma_tok));
  1506.                newdec ::= #TR_DEC_STMT;
  1507.                newdec.source := source_loc;
  1508.                match(ident_tok);
  1509.                newdec.name := ident;
  1510.                if void(res) then res := newdec
  1511.                else res.append(newdec) end
  1512.             end;
  1513.             match(colon_tok);
  1514.             tp2: TR_TYPE_SPEC := type_spec;
  1515.             p: $TR_STMT := decl_res;
  1516.             loop until!(void(p));
  1517.                typecase p when TR_DEC_STMT then p.tp := tp2 end;
  1518.                p := p.next
  1519.             end;
  1520.             exit
  1521.          else -- expr
  1522.             r ::= #TR_EXPR_STMT; r.source := source_loc;
  1523.             r.e := x; res := r
  1524.          end
  1525.       end;
  1526.       res.source := was_at;
  1527.       exit;
  1528.       return res
  1529.    end;
  1530.  
  1531.    is_expr_start (t:TOKEN):BOOL is
  1532.       case t.val
  1533.       when self_tok, ident_tok, bang_tok, iter_bang_tok, SAME_tok, void_tok,
  1534.          minus_tok, not_tok, new_tok, sharp_tok, vbar_tok, exception_tok, 
  1535.          initial_tok, result_tok, while_tok, until_tok, break_tok, 
  1536.          true_tok, false_tok, lchar_tok, lstr_tok, lint_tok, lflt_tok, 
  1537.          lparen_tok, lbracket_tok,
  1538.       -- pSather tokens
  1539.          here_tok, where_tok, near_tok, far_tok
  1540.       then return true
  1541. --    else return false                                                         -- NLP
  1542.       else; end; return false;                                                  -- NLP
  1543. --    end                                                                       -- NLP
  1544.    end;
  1545.  
  1546.    is_stmt_start (t:TOKEN):BOOL is
  1547.       case t.val
  1548.       when ident_tok, if_tok, loop_tok, yield_tok, quit_tok, return_tok,
  1549.          case_tok, typecase_tok, assert_tok, protect_tok, raise_tok,
  1550.          while_tok, until_tok, break_tok,
  1551.       -- pSather tokens
  1552.          fork_tok, lock_tok, unlock_tok, try_tok, cobegin_tok, with_tok,
  1553.      dist_tok
  1554.       then return true
  1555. --    else return is_expr_start(t)                                              -- NLP
  1556.       else; end; return is_expr_start(t);                                       -- NLP
  1557. --    end                                                                       -- NLP
  1558.    end;
  1559.  
  1560.    stmt_list: $TR_STMT is
  1561.    -- stmt_list => [stmt] {';' [stmt]}
  1562.    --
  1563.       res: $TR_STMT;
  1564.       enter("list of statements");
  1565.       loop
  1566.          if is_stmt_start(next) then
  1567.             if void(res) then res := stmt
  1568.             else res.append(stmt) end end;
  1569.          if check(semi_tok) then -- ok
  1570.          elsif is_stmt_start(next) then exp_error("semicolon")
  1571.          else break! end end;
  1572.       exit;
  1573.       return res
  1574.    end;
  1575.  
  1576.    if_stmt: TR_IF_STMT is
  1577.    -- if_stmt =>
  1578.    --        'if' expr 'then' stmt_list {'elsif' expr 'then' stmt_list}
  1579.    --        ['else' stmt_list] 'end'
  1580.    --
  1581.    -- if_tok already fetched
  1582.    --
  1583.       enter("if statement");
  1584.       res ::= #TR_IF_STMT; res.source := source_loc;
  1585.       res.test := expr; match(then_tok); res.then_part := stmt_list;
  1586.       if check(elsif_tok) then res.else_part := if_stmt
  1587.       else
  1588.          if check(else_tok) then res.else_part := stmt_list end;
  1589.          match(end_tok) end;
  1590.       exit;
  1591.       return res
  1592.    end;
  1593.  
  1594.    loop_stmt: TR_LOOP_STMT is
  1595.    -- loop_stmt => 'loop' stmt_list 'end'
  1596.    --
  1597.       enter("loop statement");
  1598.       match(loop_tok);
  1599.       res ::= #TR_LOOP_STMT; res.source := source_loc;
  1600.       res.body := stmt_list;
  1601.       match(end_tok);
  1602.       exit;
  1603.       return res
  1604.    end;
  1605.  
  1606.    case_stmt: TR_CASE_STMT is
  1607.    -- case_stmt =>
  1608.    --        'case' expr
  1609.    --        {'when' expr {',' expr} ' then' stmt_list}
  1610.    --        ['else' stmt_list] 'end'
  1611.    --
  1612.       enter("case statement");
  1613.       match(case_tok);
  1614.       res ::= #TR_CASE_STMT; res.source := source_loc;
  1615.       res.test := expr;
  1616.       loop while!(check(when_tok));
  1617.          first, this:TR_CASE_WHEN;
  1618.          first := void;
  1619.          loop
  1620.             this := #TR_CASE_WHEN; this.source := source_loc;
  1621.             if void(first) then first := this end;
  1622.             this.val := expr;
  1623.         if void(res.when_part) then res.when_part:=this
  1624.         else res.when_part.append(this) end;
  1625.             while!(check(comma_tok)) end;
  1626.          match(then_tok);
  1627.          st: $TR_STMT := stmt_list; this := first;
  1628.          loop until!(void(this)); this.then_part := st; 
  1629.             this := this.next end end;
  1630.       if check(else_tok) then 
  1631.          res.else_part := stmt_list; res.no_else := false
  1632.       else res.no_else := true end;
  1633.       match(end_tok);
  1634.       exit;
  1635.       return res
  1636.    end;
  1637.  
  1638.    typecase_stmt: TR_TYPECASE_STMT is
  1639.    -- typecase_stmt =>
  1640.    --        'typecase' ident
  1641.    --        {'when' type_spec 'then' stmt_list}
  1642.    --        ['else' stmt_list] 'end'
  1643.    --
  1644.       enter("typecase statement");
  1645.       match(typecase_tok);
  1646.       res ::= #TR_TYPECASE_STMT; res.source := source_loc;
  1647.       match(ident_tok);
  1648.       res.name := ident;
  1649.       loop while!(check(when_tok));
  1650.          this ::= #TR_TYPECASE_WHEN; this.source := source_loc;
  1651.          this.tp := type_spec;
  1652.          match(then_tok);
  1653.          this.then_part := stmt_list;
  1654.      if void(res.when_part) then res.when_part:=this
  1655.      else res.when_part.append(this) end end;
  1656.       if check(else_tok) then 
  1657.          res.else_part := stmt_list; res.no_else := false
  1658.       else res.no_else := true end;
  1659.       match(end_tok);
  1660.       exit;
  1661.       return res
  1662.    end;
  1663.  
  1664.    return_stmt: TR_RETURN_STMT is
  1665.    -- return_stmt => 'return' [expr]
  1666.    --
  1667.       enter("return statement");
  1668.       res ::= #TR_RETURN_STMT; res.source := source_loc;
  1669.       match(return_tok);
  1670.       if is_expr_start(next) then res.val := expr end;
  1671.       exit;
  1672.       return res
  1673.    end;
  1674.    
  1675.    yield_stmt: TR_YIELD_STMT is
  1676.    -- return_stmt => 'yield' [expr]
  1677.    --
  1678.       enter("yield statement");
  1679.       res ::= #TR_YIELD_STMT; res.source := source_loc;
  1680.       match(yield_tok);
  1681.       if is_expr_start(next) then res.val := expr end;
  1682.       exit;
  1683.       return res
  1684.    end;
  1685.  
  1686.    assert_stmt: TR_ASSERT_STMT is
  1687.    -- assert_stmt => 'assert' expr 'end'
  1688.    --
  1689.       enter("assert statement");
  1690.       res ::= #TR_ASSERT_STMT; res.source := source_loc;
  1691.       match(assert_tok);
  1692.       res.test := expr;
  1693.       exit;
  1694.       return res
  1695.    end;
  1696.  
  1697.    raise_stmt: TR_RAISE_STMT is
  1698.    -- raise_stmr => 'raise' expr
  1699.    --
  1700.       enter("raise statement");
  1701.       res ::= #TR_RAISE_STMT; res.source := source_loc;
  1702.       match(raise_tok);
  1703.       res.val := expr;
  1704.       exit;
  1705.       return res
  1706.    end;
  1707.  
  1708.    protect_stmt: TR_PROTECT_STMT is
  1709.    -- protect_stmt =>
  1710.    --        'protect' stmt_list
  1711.    --        {'when' type_spec_list 'then' stmt_list}
  1712.    --        ['else' stmt_list] 'end'
  1713.    --
  1714.       enter("protect statement");
  1715.       match(protect_tok);
  1716.       res ::= #TR_PROTECT_STMT; res.source := source_loc;
  1717.       res.stmts := stmt_list;
  1718.       loop while!(check(when_tok));
  1719.          first, this:TR_PROTECT_WHEN;
  1720.          first := void;
  1721.          loop
  1722.             this := #TR_PROTECT_WHEN; this.source := source_loc;
  1723.             if void(first) then first := this end;
  1724.             this.tp := type_spec;
  1725.         if void(res.when_part) then res.when_part:=this
  1726.         else res.when_part.append(this) end;
  1727.             while!(check(comma_tok)) end;
  1728.          match(then_tok);
  1729.          st: $TR_STMT := stmt_list; this := first;
  1730.          loop until!(void(this)); this.then_part := st; 
  1731.             this := this.next end end;
  1732.       if check(else_tok) then 
  1733.          res.else_part := stmt_list; res.no_else := false
  1734.       else res.no_else := true end;
  1735.       match(end_tok);
  1736.       exit;
  1737.       return res
  1738.    end;
  1739.  
  1740.    cobegin_stmt: TR_COBEGIN_STMT is
  1741.    -- cobegin_stmt => 'cobegin' stmt_list 'end'
  1742.    -- (pSather construct)
  1743.    --
  1744.       enter("cobegin statement");
  1745.       match(cobegin_tok);
  1746.       res ::= #TR_COBEGIN_STMT; res.source := source_loc;
  1747.       res.stmts := stmt_list;
  1748.       match(end_tok);
  1749.       exit;
  1750.       return res
  1751.    end;
  1752.  
  1753.    lock_stmt: TR_LOCK_STMT is
  1754.    -- lock_stmt => 'lock' expr {',' expr} 'then' stmt_list 'end'
  1755.    -- (pSather construct)
  1756.    --
  1757.       enter("lock statement");
  1758.       res ::= #TR_LOCK_STMT; res.source := source_loc;
  1759.       match(lock_tok); res.e_list := expr_list(false);
  1760.       match(then_tok); res.then_part := stmt_list;
  1761.       match(end_tok);
  1762.       exit;
  1763.       return res
  1764.    end;
  1765.  
  1766.    unlock_stmt: TR_UNLOCK_STMT is
  1767.    -- unlock_stmt => 'unlock' expr
  1768.    -- (pSather construct)
  1769.    --
  1770.       enter("unlock statement");
  1771.       res ::= #TR_UNLOCK_STMT; res.source := source_loc;
  1772.       match(unlock_tok); res.e := expr;
  1773.       exit;
  1774.       return res
  1775.    end;
  1776.  
  1777.    try_stmt: TR_TRY_STMT is
  1778.    -- try_stmt =>
  1779.    --   'try'  expr {',' expr} 'then' stmt_list
  1780.    --   ['else' stmt_list] 'end'
  1781.    -- (pSather construct)
  1782.    --
  1783.       enter("try statement");
  1784.       res ::= #TR_TRY_STMT; res.source := source_loc;
  1785.       match(try_tok); res.e_list := expr_list(false);
  1786.       match(then_tok); res.then_part := stmt_list;
  1787.       if check(else_tok) then res.else_part := stmt_list end;
  1788.       match(end_tok);
  1789.       exit;
  1790.       return res
  1791.    end;
  1792.  
  1793.    ident_list: TR_IDENT_LIST is
  1794.    -- ident_list => ident {',' ident}
  1795.    --
  1796.       enter("identifier list");
  1797.       res, id: TR_IDENT_LIST;
  1798.       loop
  1799.          if next = ident_tok then
  1800.             id := #TR_IDENT_LIST; id.name := ident;
  1801.          else exp_error("identifier")
  1802.          end;
  1803.          fetch;
  1804.          if void(res) then res := id
  1805.          else res.append(id)
  1806.          end;
  1807.          while!(check(comma_tok))
  1808.       end;
  1809.       exit;
  1810.       return res
  1811.    end;
  1812.  
  1813.    with_near_stmt: TR_WITH_NEAR_STMT is
  1814.    -- with_near_stmt =>
  1815.    --   'with'  ident_list 'near' stmt_list
  1816.    --   ['else' stmt_list] 'end'
  1817.    -- (pSather construct)
  1818.    --
  1819.       enter("with_near statement");
  1820.       res ::= #TR_WITH_NEAR_STMT; res.source := source_loc;
  1821.       match(with_tok); res.idents := ident_list;
  1822.       match(near_tok); res.near_part := stmt_list;
  1823.       if check(else_tok) then res.else_part := stmt_list end;
  1824.       match(end_tok);
  1825.       exit;
  1826.       return res
  1827.    end;
  1828.  
  1829.    dist_stmt: TR_DIST_STMT is
  1830.    -- dist_stmt =>
  1831.    --    'dist' [expr 'as' ident] {',' expr 'as' ident} 'do' stmt_list 'end'
  1832.        enter("dist statement");
  1833.        res ::= #TR_DIST_STMT; res.source := source_loc;
  1834.        match(dist_tok);
  1835.        if ~check(do_tok) then
  1836.        res.exprs:=res.exprs.push(expr);
  1837.        match(as_tok);
  1838.        match(ident_tok);
  1839.        res.ids:=res.ids.push(ident);
  1840.        loop until!(check(do_tok));
  1841.            match(comma_tok);
  1842.            res.exprs:=res.exprs.push(expr);
  1843.            match(as_tok);
  1844.            match(ident_tok);
  1845.            res.ids:=res.ids.push(ident);
  1846.        end;
  1847.        end;
  1848.        res.stmts:=stmt_list;
  1849.        match(end_tok);
  1850.        return res;
  1851.    end;
  1852.  
  1853.    expr: $TR_EXPR is
  1854.    -- expr => expr7 {'@' expr 7}
  1855.    --
  1856.       enter("expression (prec = 8)");
  1857.       res ::= expr7;
  1858.       loop while!(next = at_tok);
  1859.          fetch;
  1860.          h ::= #TR_AT_EXPR; h.source := source_loc;
  1861.          h.e := res; h.at := expr7; res := h
  1862.       end;
  1863.       exit;
  1864.       return res 
  1865.    end;
  1866.  
  1867.    expr7: $TR_EXPR is
  1868.    -- expr7 => expr6 {('and' | 'or') expr6}
  1869.    --
  1870.       enter("expression (prec = 7)");
  1871.       res ::= expr6;
  1872.       loop
  1873.          if check(and_tok) then
  1874.             a ::= #TR_AND_EXPR; a.source := source_loc;
  1875.             a.e1 := res; a.e2 := expr6; res := a
  1876.          elsif check(or_tok) then
  1877.             o ::= #TR_OR_EXPR; o.source := source_loc;
  1878.             o.e1 := res; o.e2 := expr6; res := o
  1879.          else break! end end;
  1880.       exit;
  1881.       return res
  1882.    end;
  1883.  
  1884.    expr6: $TR_EXPR is
  1885.    -- expr6 => expr5 {('=' | '/=' | '<' | '<=' | '>=' | '>') expr5}
  1886.    --
  1887.       enter("expression (prec = 6)");
  1888.       res ::= expr5;
  1889.       loop
  1890.          name: IDENT;
  1891.          if check(is_eq_tok) then name := prog.ident_builtin.is_eq_ident
  1892.          elsif check(is_neq_tok) then name := prog.ident_builtin.is_neq_ident
  1893.          elsif check(is_lt_tok) then name := prog.ident_builtin.is_lt_ident
  1894.          elsif check(is_leq_tok) then name := prog.ident_builtin.is_leq_ident
  1895.          elsif check(is_geq_tok) then name := prog.ident_builtin.is_geq_ident
  1896.          elsif check(is_gt_tok) then name := prog.ident_builtin.is_gt_ident
  1897.          else break!
  1898.          end;
  1899.          c ::= #TR_CALL_EXPR; c.source := source_loc; c.name := name;
  1900.          c.ob := res; c.args := expr5; res := c
  1901.       end;
  1902.       exit;
  1903.       return res
  1904.    end;
  1905.  
  1906.    expr5: $TR_EXPR is
  1907.    -- expr5 => expr4 {('+' | '-') expr4}
  1908.    --
  1909.       enter("expression (prec = 5)");
  1910.       res ::= expr4;
  1911.       loop
  1912.          name:IDENT;
  1913.          if check(plus_tok) then name := prog.ident_builtin.plus_ident
  1914.          elsif check(minus_tok) then name := prog.ident_builtin.minus_ident
  1915.          else break! end;
  1916.          c ::= #TR_CALL_EXPR; c.source := source_loc; c.name := name;
  1917.          c.ob := res; c.args := expr4; res := c end;
  1918.       exit;
  1919.       return res
  1920.    end;
  1921.    
  1922.    expr4: $TR_EXPR is
  1923.    -- expr4 => expr3 {('*' | '/' | '%') expr3}
  1924.    --
  1925.       enter("expression (prec = 4)");
  1926.       res ::= expr3;
  1927.       loop
  1928.          name:IDENT;
  1929.          if check(times_tok) then name := prog.ident_builtin.times_ident
  1930.          elsif check(quotient_tok) then name := prog.ident_builtin.div_ident
  1931.          elsif check(mod_tok) then name := prog.ident_builtin.mod_ident
  1932.          else break! end;
  1933.          c ::= #TR_CALL_EXPR; c.source := source_loc; c.name := name;
  1934.          c.ob := res; c.args := expr3; res := c end;
  1935.       exit;
  1936.       return res
  1937.    end;
  1938.  
  1939.    expr3: $TR_EXPR is
  1940.    -- expr3 => '-' expr3 | '~' expr3 | exp2.
  1941.    --
  1942.    -- in case of literals and '-' do the negation directly to prevent
  1943.    -- overflow in case of minint (e.g. -5 gets translated into 5.negate)
  1944.    --
  1945.       x: $TR_EXPR; c: TR_CALL_EXPR;
  1946.       res: $TR_EXPR;
  1947.       enter("expression (prec = 3)");
  1948.       if next = minus_tok then fetch; x := expr3;
  1949.          typecase x
  1950.          when TR_INT_LIT_EXPR then
  1951.             i ::= #TR_INT_LIT_EXPR; i.source := source_loc;
  1952.             i.val := -x.val; res := i
  1953.          when TR_FLT_LIT_EXPR then
  1954.             f ::= #TR_FLT_LIT_EXPR; f.source := source_loc;
  1955.             f.val := -x.val; f.tp := x.tp; res := f
  1956.          else
  1957.             c := #TR_CALL_EXPR; c.source := source_loc;
  1958.             c.name := prog.ident_builtin.negate_ident;
  1959.             c.ob := x; res := c
  1960.          end
  1961.       elsif next = not_tok then fetch; x := expr3;
  1962.          c := #TR_CALL_EXPR; c.source := source_loc;
  1963.          c.name := prog.ident_builtin.not_ident;
  1964.          c.ob := x; res := c
  1965.       else res := expr2
  1966.       end;
  1967.       exit;
  1968.       return res
  1969.    end;
  1970.  
  1971.    expr2: $TR_EXPR is
  1972.    -- expr2 => exp1 ['^' exp2]
  1973.    --
  1974.       enter("expression (prec = 2)");
  1975.       res ::= expr1(false);
  1976.       if check(pow_tok) then
  1977.          c ::= #TR_CALL_EXPR; c.source := source_loc;
  1978.          c.name := prog.ident_builtin.pow_ident;
  1979.          c.ob := res; c.args := expr2; res := c end;
  1980.       exit;
  1981.       return res
  1982.    end;
  1983.  
  1984.    expr_list (underscore_args:BOOL): $TR_EXPR is
  1985.    -- expr_list => bound_arg {',' bound_arg}
  1986.    -- bound_arg => expr | '_' [':' type_spec]
  1987.    --
  1988.       res: $TR_EXPR;
  1989.       if underscore_args then enter("list of bound arguments")
  1990.       else enter("list of expressions")        end;
  1991.       loop x: $TR_EXPR;
  1992.          if check(under_tok) then
  1993.             u ::= #TR_UNDERSCORE_ARG; u.source := source_loc;
  1994.             u.source := source_loc; x := u;
  1995.             if check(colon_tok) then u.tp := type_spec end;
  1996.             if ~underscore_args then
  1997.                error("no underscore arguments allowed") end
  1998.          else x := expr end;
  1999.          if void(res) then res := x
  2000.          else res.append(x) end;
  2001.          while!(check(comma_tok)) end;
  2002.       exit;
  2003.       return res
  2004.    end;
  2005.  
  2006.    call_expr (ob: $TR_EXPR, tp: TR_TYPE_SPEC, underscore_args: BOOL): TR_CALL_EXPR is
  2007.    -- call_expr => (ident | [ident] '!') ['(' expr_list ')']
  2008.    --
  2009.       res: TR_CALL_EXPR;
  2010.       enter("call expressions");
  2011.       res := #TR_CALL_EXPR; res.source := source_loc; res.ob := ob; res.tp := tp;
  2012.       res.name := rout_or_iter_name;
  2013.       if check(lparen_tok) then res.args := expr_list(underscore_args); match(rparen_tok) end;
  2014.       exit;
  2015.       return res
  2016.    end;
  2017.  
  2018.    type_of (x: $TR_EXPR): TR_TYPE_SPEC is
  2019.    -- make sure x could be a type_spec
  2020.    --
  2021.       typecase x when TR_CALL_EXPR then
  2022.          if void(x.ob) then
  2023.             if void(x.tp) then
  2024.                if is_class_name(x.name) then
  2025.                   tp ::= #TR_TYPE_SPEC; tp.source := x.source;
  2026.                   tp.kind := TR_TYPE_SPEC::ord;
  2027.                   tp.is_hot := false;
  2028.                   tp.name := x.name;
  2029.                   tp.params := void;
  2030.                   tp.ret := void;
  2031.                   return tp
  2032.                end
  2033.             else return x.tp
  2034.             end
  2035.          end
  2036.       else end;
  2037.       error("type specifier expected");
  2038.       return void
  2039.    end;
  2040.  
  2041.    expr1 (underscore_args:BOOL): $TR_EXPR is
  2042.    -- expr1 =>
  2043.    --        (expr0 '.' call_expr | type_spec '::' call_expr | 
  2044.    --               call_expr | expr0 '[' expr_list ']')
  2045.    --        {"." call_expr | '[' expr_list ']'}
  2046.    --
  2047.    -- (expr0 accepts type_specs for local_exprs)
  2048.    --
  2049.       enter("expression (prec = 1)");
  2050.       res ::= expr0;
  2051.       c:TR_CALL_EXPR;
  2052.       if check(dot_tok) then -- expr0 '.'
  2053.          res := call_expr(res, void, underscore_args)
  2054.       elsif check(dcolon_tok) then -- type_spec '::'
  2055.          res := call_expr(void, type_of(res), underscore_args)
  2056.       elsif check(iter_bang_tok) then -- part of call_expr: ident '!'
  2057.          c := #TR_CALL_EXPR; c.source := source_loc;
  2058.          c.name := append_bang(ident_of(res));
  2059.          if check(lparen_tok) then c.args := expr_list(underscore_args); 
  2060.             match(rparen_tok) end;
  2061.          res := c
  2062.       elsif check(lparen_tok) then -- part of call_expr: ident '('
  2063.          c := #TR_CALL_EXPR; c.source := source_loc;
  2064.          c.name := ident_of(res);
  2065.          c.args := expr_list(underscore_args); match(rparen_tok);
  2066.          res := c
  2067.       elsif check(lbracket_tok) then -- part of call_expr: expr0 '['
  2068.          c := #TR_CALL_EXPR; c.source := source_loc;
  2069.          c.ob := res; c.args := expr_list(false); c.is_array := true;
  2070.          match(rbracket_tok);
  2071.          res := c
  2072.       end;
  2073.       loop
  2074.          if check(dot_tok) then
  2075.             res := call_expr(res, void, underscore_args)
  2076.          elsif check(lbracket_tok) then
  2077.             c := #TR_CALL_EXPR; c.source := source_loc;
  2078.             c.ob := res; c.args := expr_list(false); c.is_array := true;
  2079.             match(rbracket_tok);
  2080.             res := c
  2081.          else break! end end;
  2082.       exit;
  2083.       return res
  2084.    end;
  2085.  
  2086.    expr0: $TR_EXPR is
  2087.    -- expr0 =>
  2088.    --      self_expr | local_expr | void_expr | new_expr |
  2089.    --      create_expr | array_expr | bound_create_expr |
  2090.    --      except_expr | initial_expr | result_expr | while!_expr |
  2091.    --      until!_expr | break!_expr | bool_lit_expr | char_lit_expr |
  2092.    --      str_lit_expr | int_lit_expr | flt_lit_expr | '(' expr ')' |
  2093.    --      '[' expr_list ']' |
  2094.    --      here_expr | where_expr | near_expr | far_expr
  2095.    --
  2096.    -- local_expr accepts also type_spec, filtered out here or in expr1
  2097.    --
  2098.       enter("expression (prec = 0)");
  2099.       res: $TR_EXPR;
  2100.       case next.val
  2101.       when self_tok then
  2102.          fetch; res := #TR_SELF_EXPR; res.source := source_loc
  2103.       when ident_tok then
  2104.          call_exp ::= #TR_CALL_EXPR; call_exp.source := source_loc;
  2105.          if is_class_name(ident) then call_exp.tp := type_spec;
  2106.         -- DPS changed from this
  2107.             --if (call_exp.tp.kind = TR_TYPE_SPEC::ord) and void(call_exp.tp.params) then -- maybe ordinary call
  2108.             --   call_exp.name := call_exp.tp.name;
  2109.             --   call_exp.tp := void
  2110.             --end
  2111.             if (call_exp.tp.kind = TR_TYPE_SPEC::ord) then
  2112.         if void(call_exp.tp.params) then -- ordinary call
  2113.             call_exp.name := call_exp.tp.name;
  2114.             call_exp.tp := void;
  2115.         elsif next/=dcolon_tok then
  2116.               error("This typespec neither preceeds '::' nor follows '#'");
  2117.         end
  2118.             end
  2119.          else call_exp.name := ident; fetch end;
  2120.          res := call_exp
  2121.       when bang_tok then
  2122.          r ::= #TR_CALL_EXPR; r.source := source_loc;
  2123.          r.name := prog.ident_for("!"); fetch;
  2124.          res := r
  2125.       when iter_bang_tok then
  2126.          r ::= #TR_CALL_EXPR; r.source := source_loc;
  2127.          r.name := prog.ident_for("!"); fetch;
  2128.          res := r
  2129.       when SAME_tok then
  2130.          r ::= #TR_CALL_EXPR; r.source := source_loc;
  2131.          r.tp := type_spec;
  2132.          res := r
  2133.       when void_tok then
  2134.          enter("void expressions");
  2135.          fetch;
  2136.          if next = lparen_tok then fetch;
  2137.             vtest ::= #TR_IS_VOID_EXPR; vtest.source := source_loc;
  2138.             vtest.arg := expr; res := vtest;
  2139.             match(rparen_tok)
  2140.          else res := #TR_VOID_EXPR; res.source := source_loc
  2141.          end;
  2142.          exit
  2143.       when new_tok then
  2144.          enter("new expression");
  2145.          fetch;
  2146.          new_ex ::= #TR_NEW_EXPR; new_ex.source := source_loc;
  2147.          res := new_ex;
  2148.          if check(lparen_tok) then
  2149.             new_ex.arg := expr;
  2150.             match(rparen_tok) end;
  2151.          exit
  2152.       when sharp_tok then fetch;
  2153.          if (next = ROUT_tok) or (next = ITER_tok) then
  2154.             res := bound_create_expr
  2155.          else res := create_expr end
  2156.       when vbar_tok then
  2157.          enter("array expression");
  2158.          fetch;
  2159.          arr_ex ::= #TR_ARRAY_EXPR; arr_ex.source := source_loc;
  2160.          res := arr_ex;
  2161.          arr_ex.elts := expr_list(false);
  2162.          match(vbar_tok);
  2163.          exit
  2164.       when exception_tok then
  2165.          fetch; res := #TR_EXCEPT_EXPR; res.source := source_loc;
  2166.       when initial_tok then
  2167.          enter("initial expression");
  2168.          fetch; match(lparen_tok);
  2169.          init_ex ::= #TR_INITIAL_EXPR; init_ex.source := source_loc;
  2170.          res := init_ex;
  2171.          init_ex.e := expr;
  2172.          match(rparen_tok);
  2173.          exit
  2174.       when result_tok then
  2175.          fetch; res := #TR_RESULT_EXPR; res.source := source_loc;
  2176.       when while_tok then
  2177.          enter("while! expression");
  2178.          fetch; match(lparen_tok); res := expr; match(rparen_tok);
  2179.          error("while! expression must stand alone");
  2180.          exit
  2181.       when until_tok then
  2182.          enter("until! expression");
  2183.          fetch; match(lparen_tok); res := expr; match(rparen_tok);
  2184.          error("until! expression must stand alone");
  2185.          exit
  2186.       when break_tok then
  2187.          fetch; res := #TR_BOOL_LIT_EXPR; res.source := source_loc;
  2188.          error("break! expression must stand alone")
  2189.       when true_tok then
  2190.          r ::= #TR_BOOL_LIT_EXPR; r.source := source_loc;
  2191.          r.val := next = true_tok; res := r; fetch
  2192.       when false_tok then
  2193.          r ::= #TR_BOOL_LIT_EXPR; r.source := source_loc;
  2194.          r.val := next = true_tok; res := r; fetch
  2195.       when lchar_tok then
  2196.          c ::= #TR_CHAR_LIT_EXPR; c.source := source_loc;
  2197.          c.val := scanner.char_value.int; 
  2198.          res := c; fetch
  2199.       when lstr_tok then
  2200.          s ::= #TR_STR_LIT_EXPR; s.source := source_loc;
  2201.          s.s := ident.str; res := s; fetch
  2202.       when lint_tok then
  2203.          assert scanner.num_value.is_int;
  2204.          i ::=  #TR_INT_LIT_EXPR; i.source := source_loc;
  2205.          i.val := scanner.num_value.floor;
  2206.          i.is_inti := (scanner.value_type = TR_FLT_LIT_EXPR::flti);
  2207.          res := i; 
  2208.          fetch
  2209.       when lflt_tok then
  2210.          f ::= #TR_FLT_LIT_EXPR; f.source := source_loc;
  2211.          f.val := scanner.num_value;
  2212.          f.tp := scanner.value_type;
  2213.          res := f; fetch
  2214.       when lparen_tok then
  2215.          fetch; res := expr; match(rparen_tok)
  2216.       when lbracket_tok then
  2217.          fetch; a ::= #TR_CALL_EXPR; a.source := source_loc;
  2218.          a.args := expr_list(false); a.is_array := true; res := a;
  2219.          match(rbracket_tok)
  2220.       when here_tok then
  2221.          fetch; res := #TR_HERE_EXPR; res.source := source_loc
  2222.       when where_tok then
  2223.          enter("where expression");
  2224.          r ::= #TR_WHERE_EXPR; r.source := source_loc; res := r;
  2225.          fetch; match(lparen_tok); r.e := expr; match(rparen_tok);
  2226.          exit
  2227.       when near_tok then
  2228.          enter("near expression");
  2229.          r ::= #TR_NEAR_EXPR; r.source := source_loc; res := r;
  2230.          fetch; match(lparen_tok); r.e := expr; match(rparen_tok);
  2231.          exit
  2232.       when far_tok then
  2233.          enter("far expression");
  2234.          r ::= #TR_FAR_EXPR; r.source := source_loc; res := r;
  2235.          fetch; match(lparen_tok); r.e := expr; match(rparen_tok);
  2236.          exit
  2237.       else exp_error("expression"); res := #TR_VOID_EXPR; res.source := source_loc end;
  2238.       exit;
  2239.       return res
  2240.    end;
  2241.  
  2242.    check_underscores (call:TR_CALL_EXPR, is_iter:BOOL) is
  2243.       if call.name.is_iter /= is_iter then
  2244.          if is_iter then error("bound routine must be an iter")
  2245.          else error("bound routine must not be an iter") end end;
  2246.       if call.is_array then
  2247.          error("only call expressions allowed") end;
  2248.       ob: $TR_EXPR := call.ob;
  2249.       loop until!(void(ob));
  2250.          this: $TR_EXPR := ob;
  2251.          typecase this when TR_CALL_EXPR then
  2252.             ob := this.ob;
  2253.             arg: $TR_EXPR := this.args;
  2254.             loop until!(void(arg));
  2255.                typecase arg when TR_UNDERSCORE_ARG then
  2256.                   error("illegal underscore arguments");
  2257.                   return
  2258.                else end;
  2259.                arg := arg.next
  2260.             end
  2261.          else
  2262.             typecase ob when TR_UNDERSCORE_ARG then
  2263.                if ~SYS::ob_eq(ob, call.ob) then
  2264.                   error("illegal underscore arguments")
  2265.                end
  2266.             else end;
  2267.             return
  2268.          end
  2269.       end
  2270.    end;
  2271.  
  2272.    bound_create_expr: TR_BOUND_CREATE_EXPR is
  2273.    -- bound_create_expr =>
  2274.    --        '#' ('ROUT' | 'ITER') '('
  2275.    --        ('_' [':' type_spec] '.' call_expr | expr1)
  2276.    --        [':' type_spec] ')'
  2277.    --
  2278.    -- '#' already seen and stripped away
  2279.    -- next is one of ROUT_tok,  ITER_tok (guaranteed)
  2280.    --
  2281.       enter("bound create expression");
  2282.       res ::= #TR_BOUND_CREATE_EXPR; res.source := source_loc;
  2283.       res.is_iter := next = ITER_tok; fetch;
  2284.       match(lparen_tok);
  2285.       if check(under_tok) then
  2286.          u ::= #TR_UNDERSCORE_ARG; u.source := source_loc;
  2287.          if check(colon_tok) then u.tp := type_spec end;
  2288.          match(dot_tok);
  2289.          res.call := call_expr(u, void, true)
  2290.       else -- hack: should be improved
  2291.          x ::= expr1(true);
  2292.          typecase x when TR_CALL_EXPR then res.call := x end
  2293.       end;
  2294.       check_underscores(res.call, res.is_iter);
  2295.       if check(colon_tok) then res.ret := type_spec end;
  2296.       match(rparen_tok);
  2297.       exit;
  2298.       return res
  2299.    end;
  2300.  
  2301.    create_expr: TR_CREATE_EXPR is
  2302.    -- create_expr => '#' [type_spec] ['(' expr_list ')']
  2303.    --
  2304.    -- '#' already seen and stripped away
  2305.    --
  2306.       enter("create expression");
  2307.       res ::= #TR_CREATE_EXPR; res.source := source_loc;
  2308.       if (next = ident_tok) or (next = SAME_tok) then res.tp := type_spec
  2309.       elsif next = type_name_tok then res.tp := type_spec;
  2310.          error("no abstract types allowed")
  2311.       end;
  2312.       if check(lparen_tok) then
  2313.          res.elts := expr_list(false); match(rparen_tok) end;
  2314.       exit;
  2315.       return res
  2316.    end
  2317.  
  2318. end -- PARSER
  2319.    
  2320. -------------------------------------------------------------------
  2321.  
  2322.