home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #4 / amigaacscoverdisc1998-041998.iso / utilities / shareware / dev / ppcsmalleiffel / lib_se / eiffel_parser.e < prev    next >
Encoding:
Text File  |  1998-01-16  |  108.8 KB  |  4,637 lines

  1. --          This file is part of SmallEiffel The GNU Eiffel Compiler.
  2. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  3. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr 
  4. --                       http://www.loria.fr/SmallEiffel
  5. -- SmallEiffel is  free  software;  you can  redistribute it and/or modify it 
  6. -- under the terms of the GNU General Public License as published by the Free
  7. -- Software  Foundation;  either  version  2, or (at your option)  any  later 
  8. -- version. SmallEiffel is distributed in the hope that it will be useful,but
  9. -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. -- or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU General Public License 
  11. -- for  more  details.  You  should  have  received a copy of the GNU General 
  12. -- Public  License  along  with  SmallEiffel;  see the file COPYING.  If not,
  13. -- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  14. -- Boston, MA 02111-1307, USA.
  15. --
  16. class EIFFEL_PARSER
  17.  
  18. inherit GLOBALS;
  19.    
  20. creation make
  21.    
  22. feature {NONE}
  23.    
  24.    make is do end;
  25.    
  26. feature 
  27.    
  28.    case_insensitive: BOOLEAN;
  29.  
  30.    drop_comments: BOOLEAN;
  31.      -- When objects COMMENT are not necessary.
  32.  
  33.    is_running: BOOLEAN;
  34.      -- True when the parser is running.
  35.  
  36. feature {SMALL_EIFFEL} 
  37.       
  38.    analyse_class(class_name: CLASS_NAME): BASE_CLASS is
  39.       require
  40.      parser_buffer.is_ready;
  41.      not is_running
  42.       local
  43.      old_nbe, old_nbw: INTEGER;
  44.      path: STRING; 
  45.       do
  46.      path := parser_buffer.path;
  47.      if nb_errors > 0 then
  48.         eh.append("Correct previous error(s) first.");
  49.         eh.print_as_fatal_error;
  50.      end;
  51.      debug
  52.         if small_eiffel.is_ready then
  53.            eh.append("Try to load class ");
  54.            eh.append(path);
  55.            eh.append(" while small_eiffel `is_ready'.");
  56.            eh.print_as_warning;
  57.         end;
  58.      end;
  59.      echo.put_integer(small_eiffel.base_class_count + 1);
  60.      echo.put_character('%T');
  61.      echo.put_string(path);
  62.      echo.put_character('%N');
  63.      old_nbe := nb_errors;
  64.      old_nbw := nb_warnings;
  65.      is_running := true;
  66.      function_type := Void; 
  67.      in_ensure := false;
  68.      last_comments := Void;
  69.      ms_numbering := 0;
  70.      line := 1;
  71.      column := 1;
  72.      current_line := parser_buffer.item(line);
  73.      if current_line.count = 0 then
  74.         cc := '%N';
  75.         else
  76.         cc := current_line.first;
  77.      end;
  78.      !!last_base_class.make;
  79.      skip_comments;
  80.      a_class_declaration; 
  81.      is_running := false;
  82.      parser_buffer.unset_is_ready;
  83.      Result := last_base_class;
  84.      if nb_errors - old_nbe > 0 then
  85.         show_nb_errors;
  86.         echo.w_put_string("Load class %"");
  87.         echo.w_put_string(path);
  88.         echo.w_put_string("%" aborted.%N");
  89.         Result := Void;
  90.      elseif nb_warnings - old_nbw > 0 then
  91.         show_nb_warnings;
  92.         check
  93.            Result /= Void
  94.         end;
  95.      end;
  96.      if Result /= Void then
  97.         small_eiffel.add_class(Result);
  98.         if class_name /= Void and then 
  99.            class_name.to_string /= Result.base_class_name.to_string 
  100.          then
  101.            eh.add_position(class_name.start_position);
  102.            eh.append(fz_01);
  103.            eh.append(path);
  104.            eh.append("%" does not contains class %"");
  105.            eh.append(class_name.to_string);
  106.            fatal_error(fz_03);
  107.         end;
  108.         Result.get_started;
  109.      end;
  110.       ensure
  111.      not parser_buffer.is_ready
  112.       end;
  113.  
  114. feature
  115.    
  116.    set_case_insensitive is
  117.       do
  118.      case_insensitive := true;
  119.       end;
  120.  
  121.    current_class_name: CLASS_NAME is
  122.      -- The name of the class the parser is parsing.
  123.       require
  124.      is_running
  125.       do
  126.      Result := last_base_class.base_class_name;
  127.       ensure
  128.      Result /= Void
  129.       end;
  130.  
  131.    current_class: BASE_CLASS is
  132.      -- The class the parser is parsing.
  133.       require
  134.      is_running
  135.       do
  136.      Result := last_base_class;
  137.       ensure
  138.      Result /= Void
  139.       end;
  140.  
  141. feature {CECIL_POOL}
  142.  
  143.    connect_to_cecil: STRING is
  144.       -- Return the cecil file path (first line).
  145.       require
  146.      not is_running;
  147.      nb_errors = 0;
  148.      run_control.cecil_path /= Void
  149.       local
  150.      path: STRING;
  151.       do
  152.      path := run_control.cecil_path;
  153.      echo.put_string("Parsing Cecil File : ");
  154.      echo.put_string(path);
  155.      echo.put_character('%N');
  156.      parser_buffer.load_file(path);
  157.      if not parser_buffer.is_ready then
  158.         fatal_error(
  159.             "Cannot open Cecil file (use -verbose flag for details).");
  160.      end;
  161.      is_running := true;
  162.      formal_generic_list := Void;
  163.      function_type := Void; 
  164.      in_ensure := false;
  165.      last_comments := Void;
  166.      line := 1;
  167.      column := 1;
  168.      current_line := parser_buffer.item(line);
  169.      if current_line.count = 0 then
  170.         cc := '%N';
  171.         else
  172.         cc := current_line.first;
  173.      end;
  174.      skip_comments;
  175.      from
  176.         !!Result.make(32);
  177.      until
  178.         cc = '%N'
  179.      loop
  180.         Result.extend(cc);
  181.         next_char;
  182.      end;
  183.      skip_comments;
  184.       end;
  185.  
  186.    end_of_input: BOOLEAN is
  187.       do
  188.      Result := cc = end_of_text;
  189.       end;
  190.  
  191.    parse_c_name: STRING is
  192.       do
  193.      from
  194.         !!Result.make(32);
  195.      until
  196.         cc.is_separator
  197.      loop
  198.         Result.extend(cc);
  199.         next_char;
  200.      end;
  201.      skip_comments;
  202.       end;
  203.  
  204.    parse_run_type: TYPE is
  205.       do
  206.      if a_class_type then
  207.         Result := last_class_type;
  208.      else
  209.         fcp(em18);
  210.      end;
  211.       ensure
  212.      nb_errors = 0
  213.       end;
  214.       
  215.    parse_feature_name: FEATURE_NAME is
  216.       do
  217.      if a_feature_name then
  218.         Result := last_feature_name;
  219.      else
  220.         fcp(em2);
  221.      end;
  222.       ensure
  223.      nb_errors = 0
  224.       end;
  225.  
  226.    disconnect is
  227.       do
  228.      is_running := false;
  229.      parser_buffer.unset_is_ready;
  230.       end;
  231.       
  232. feature 
  233.    
  234.    line, column: INTEGER; 
  235.      -- Current `line' number and current `column' number.
  236.    
  237.    current_line: STRING; 
  238.      -- Current line string of `text'.
  239.    
  240.    cc: CHARACTER; 
  241.      -- Current character in the `current_line'.
  242.    
  243.    current_position: POSITION is
  244.       do
  245.      !!Result.make(line,column);
  246.       end;
  247.    
  248.    tmp_feature: TMP_FEATURE is
  249.       once
  250.      !!Result;
  251.       end;
  252.  
  253. feature {C_PRETTY_PRINTER}
  254.  
  255.    show_nb_warnings is
  256.       do
  257.      show_nb(nb_warnings," warning(s).%N");
  258.       end;
  259.  
  260.    show_nb_errors is
  261.       do
  262.      show_nb(nb_errors," error(s).%N");
  263.       end;
  264.  
  265. feature {NONE}
  266.    
  267.    show_nb(nb: INTEGER; tail: STRING) is
  268.       do
  269.      if nb > 0 then
  270.         echo.w_put_string(fz_error_stars);
  271.         echo.w_put_integer(nb);
  272.         echo.w_put_string(tail);
  273.      end;
  274.       end;
  275.  
  276. feature {NONE}
  277.    
  278.    fcp(msg: STRING) is
  279.       do
  280.      eh.add_position(current_position);
  281.      fatal_error(msg);
  282.       end;
  283.    
  284.    ecp(msg: STRING) is
  285.       do
  286.      error(current_position,msg);
  287.       end;
  288.    
  289.    wcp(msg: STRING) is
  290.       do
  291.      warning(current_position,msg);
  292.       end;
  293.    
  294.    err_exp(sp: POSITION; operator: STRING) is
  295.      -- When an error occurs in the right hand side of `operator'.
  296.       local
  297.      msg: STRING;
  298.       do
  299.      !!msg.make(0);
  300.      msg.append("Right hand side expression of %"");
  301.      msg.append(operator);
  302.      msg.append("%" expected.");
  303.      eh.add_position(sp);
  304.      fatal_error(msg);
  305.       end;
  306.    
  307.    end_of_text: CHARACTER is '%/0/'; -- Flag of the end of the `text'. 
  308.    
  309.    last_comments: COMMENT; 
  310.      -- Void or waiting comment.
  311.    
  312.    function_type: TYPE; 
  313.      -- Never Void during parsing of a function body.
  314.  
  315. feature {NONE}
  316.    
  317.    formal_generic_list: FORMAL_GENERIC_LIST;
  318.      -- Void or not empty list of formal generic arguments.
  319.    
  320.    in_ensure: BOOLEAN; 
  321.      -- True during the parsing of a ensure clause.
  322.    
  323.    in_rescue: BOOLEAN; 
  324.      -- True during the parsing of a rescue clause.
  325.    
  326.    arguments: FORMAL_ARG_LIST; 
  327.      -- Void or actual formal arguments list.
  328.  
  329.    local_vars: LOCAL_VAR_LIST; 
  330.      -- Void or actual local variables list. 
  331.            
  332.    ok: BOOLEAN; 
  333.      -- Dummy variable to call functions.
  334.    
  335. feature {NONE} -----------------------------------------------------------------
  336.    -- List of once tmp_* objects. 
  337.    
  338.    tmp_name: TMP_NAME is
  339.       once
  340.      !!Result.make;
  341.       end;
  342.    
  343.    ms_numbering: INTEGER;
  344.  
  345. feature {NONE} -----------------------------------------------------------------
  346.    -- This list of variables is used to store the last encountered element
  347.    -- during syntax analysis.
  348.    
  349.    last_ascii_code: INTEGER;
  350.    last_base_class: BASE_CLASS;
  351.    last_base_type: TYPE;
  352.    last_binary: INFIX_NAME;
  353.    last_bit_constant: BIT_CONSTANT;
  354.    last_boolean_constant: BOOLEAN_CONSTANT;
  355.    last_character_or_integer: BASE_TYPE_CONSTANT;
  356.    last_character_constant: CHARACTER_CONSTANT;
  357.    last_class_name: CLASS_NAME;
  358.    last_class_type: TYPE;
  359.    last_expression: EXPRESSION;
  360.    last_feature_declaration: E_FEATURE;
  361.    last_feature_list: ARRAY[FEATURE_NAME];
  362.    last_feature_name: FEATURE_NAME;
  363.    last_keyword: STRING;
  364.    last_type_formal_generic: TYPE_FORMAL_GENERIC;
  365.    last_infix: INFIX_NAME; 
  366.    last_prefix: PREFIX_NAME;
  367.    last_integer_constant: INTEGER_CONSTANT;
  368.    last_instruction: INSTRUCTION;
  369.    last_index_value: EXPRESSION;
  370.    last_manifest_constant: EXPRESSION;
  371.    last_manifest_string: MANIFEST_STRING;
  372.    last_parent: PARENT;
  373.    last_real_constant: REAL_CONSTANT;
  374.    last_type: TYPE;
  375.    last_tag_mark: TAG_NAME;
  376.    
  377. feature {NONE} ----------------------------------------------------------------
  378.    -- Following functions never move cc.
  379.    
  380.    a_argument: BOOLEAN is
  381.       local
  382.      rank: INTEGER;
  383.       do        
  384.      if arguments /= Void then
  385.         rank := arguments.rank_of(tmp_name.to_string);
  386.         if rank > 0 then
  387.            last_expression := tmp_name.to_argument_name2(arguments,rank);
  388.            Result := true;
  389.         end;
  390.      end;
  391.       end;
  392.    
  393.    a_current: BOOLEAN is
  394.       do
  395.      if tmp_name.is_current then
  396.         last_expression := tmp_name.to_e_current;
  397.         Result := true;
  398.      end;
  399.       end;
  400.    
  401.    a_formal_arg_list is
  402.      -- formal_arg_list -> ["(" {declaration_group ";" ...} ")"]
  403.      --++ declaration_group -> {identifier "," ...}+ ":" type
  404.       local
  405.      sp: POSITION;
  406.      name: ARGUMENT_NAME1;
  407.      name_list: ARRAY[ARGUMENT_NAME1];
  408.      declaration: DECLARATION;
  409.      list: ARRAY[DECLARATION];
  410.      state: INTEGER;
  411.      -- state 0 : waiting for "(".
  412.      -- state 1 : waiting for the first name of a group.
  413.      -- state 2 : waiting "," or ":".
  414.      -- state 3 : waiting for a name (not the first).
  415.      -- state 4 : waiting for type mark.
  416.      -- state 5 : waiting ";" or ")".
  417.      -- state 6 : end. 
  418.      -- state 7 : error.
  419.       do
  420.      from  
  421.         arguments := Void;
  422.      until
  423.         state > 5
  424.      loop
  425.         inspect 
  426.            state
  427.         when 0 then
  428.            if skip1('(') then
  429.           !!sp.make(start_line,start_column);
  430.           state := 1;
  431.            else
  432.           state := 6;
  433.            end;
  434.         when 1 then
  435.            if a_identifier then
  436.           name := tmp_name.to_argument_name1;
  437.           state := 2;
  438.            elseif skip1(')') then
  439.           state := 6;
  440.            else
  441.           state := 7;
  442.            end;
  443.         when 2 then
  444.            if skip1(':') then
  445.           if name_list /= Void then
  446.              name_list.add_last(name);
  447.              name := Void;
  448.           end;
  449.           state := 4;
  450.            else
  451.           ok := skip1(',');
  452.           if name_list = Void then
  453.              name_list := <<name>>;
  454.           else
  455.              name_list.add_last(name);
  456.           end;
  457.           name := Void;
  458.           state := 3;
  459.            end;
  460.         when 3 then
  461.            if a_identifier then
  462.           name := tmp_name.to_argument_name1;
  463.           state := 2;
  464.            elseif cc = ',' or else cc = ';' then
  465.           wcp(em13);
  466.           ok := skip1(',') or else skip1(';');
  467.            else
  468.           state := 7;
  469.            end;
  470.         when 4 then
  471.            if a_type then
  472.           if name_list /= Void then
  473.              !DECLARATION_GROUP!declaration.make(name_list,last_type);
  474.              name_list := Void;
  475.           else
  476.              !DECLARATION_1!declaration.make(name,last_type);
  477.              name := Void;
  478.           end;
  479.           if list = Void then
  480.              list := <<declaration>>;
  481.           else
  482.              list.add_last(declaration)
  483.           end;
  484.           declaration := Void;
  485.           state := 5;
  486.            else
  487.           state := 7;
  488.            end;
  489.         else -- state = 5
  490.            if skip1(')') then
  491.           state := 6;
  492.            elseif cc = ',' then
  493.           wcp("Substitute with %";%".");
  494.           ok := skip1(',');
  495.           state := 1;
  496.            else
  497.           ok := skip1(';'); 
  498.           state := 1;
  499.            end;
  500.         end;
  501.      end;
  502.      if state = 7 then
  503.         fcp("Bad formal aguments list.");
  504.      elseif sp /= Void and then list = Void then
  505.         warning(sp,"Empty formal argument list (deleted).");
  506.      elseif sp /= Void then
  507.         !!arguments.make(sp,list);
  508.         tmp_feature.set_arguments(arguments);
  509.      end;
  510.       end;
  511.    
  512.    a_local_var_list(sp: POSITION) is
  513.      -- local_var_list -> [{declaration_group ";" ...}]
  514.      --++ declaration_group -> {identifier "," ...}+ ":" type
  515.       local
  516.      name: LOCAL_NAME1;
  517.      name_list: ARRAY[LOCAL_NAME1];
  518.      declaration: DECLARATION;
  519.      list: ARRAY[DECLARATION];
  520.      rank, state: INTEGER;
  521.      -- state 0 : waiting for the first name of a group.
  522.      -- state 1 : waiting "," or ":".
  523.      -- state 2 : waiting for a name (not the first).
  524.      -- state 3 : waiting for type mark.
  525.      -- state 4 : waiting ";".
  526.      -- state 5 : end. 
  527.      -- state 6 : error.
  528.       do
  529.      from  
  530.      until
  531.         state > 4
  532.      loop
  533.         inspect 
  534.            state
  535.         when 0 then
  536.            if a_identifier then
  537.           name := tmp_name.to_local_name1;
  538.           state := 1;
  539.           if arguments /= Void then
  540.              rank := arguments.rank_of(name.to_string); 
  541.              if rank > 0 then
  542.             eh.add_position(name.start_position);
  543.             eh.add_position(arguments.name(rank).start_position);
  544.             eh.error("Same identifier appears twice (local/formal).");
  545.              end;
  546.           end;
  547.            elseif cc = ',' or else cc = ';' then
  548.           wcp(em13);
  549.           ok := skip1(',') or else skip1(';');
  550.            else
  551.           state := 5;
  552.            end;
  553.         when 1 then
  554.            if skip1(':') then
  555.           if name_list /= Void then
  556.              name_list.add_last(name);
  557.              name := Void;
  558.           end;
  559.           state := 3;
  560.            else
  561.           if cc = ';' then
  562.              wcp("Substitute with %",%".");
  563.              ok := skip1(';');
  564.           else
  565.              ok := skip1(',');
  566.           end;
  567.           if name_list = Void then
  568.              name_list := <<name>>;
  569.           else
  570.              name_list.add_last(name);
  571.           end;
  572.           name := Void;
  573.           state := 2;
  574.            end;
  575.         when 2 then
  576.            if a_identifier then
  577.           name := tmp_name.to_local_name1;
  578.           state := 1;
  579.           if arguments /= Void then
  580.              rank := arguments.rank_of(name.to_string); 
  581.              if rank > 0 then
  582.             eh.add_position(name.start_position);
  583.             eh.add_position(arguments.name(rank).start_position);
  584.             eh.error("Same identifier appears twice (local/formal).");
  585.              end;
  586.           end;
  587.            elseif cc = ',' or else cc = ';' then
  588.           wcp(em13);
  589.           ok := skip1(',') or else skip1(';');
  590.            else
  591.           state := 6;
  592.            end;
  593.         when 3 then
  594.            if a_type then
  595.           if name_list /= Void then
  596.              !DECLARATION_GROUP!declaration.make(name_list,last_type);
  597.              name_list := Void;
  598.           else
  599.              !DECLARATION_1!declaration.make(name,last_type);
  600.              name := Void;
  601.           end;
  602.           if list = Void then
  603.              list := <<declaration>>;
  604.           else
  605.              list.add_last(declaration);
  606.           end;
  607.           state := 4;
  608.            else
  609.           state := 6;
  610.            end;
  611.         else -- state = 4
  612.            if cc = ',' then
  613.           wcp("Substitute with %";%".");
  614.           ok := skip1(',');
  615.           state := 0;
  616.            else
  617.           ok := skip1(';');
  618.           state := 0;
  619.            end;
  620.         end;
  621.      end;
  622.      if state = 6 then
  623.         fcp("Bad local variable list.");
  624.      elseif list /= Void then
  625.         !!local_vars.make(sp,list);
  626.         tmp_feature.set_local_vars(local_vars);
  627.      end;
  628.       end;
  629.    
  630.    a_local_variable: BOOLEAN is
  631.       local
  632.      rank: INTEGER;
  633.       do
  634.      if local_vars /= Void then
  635.         rank := local_vars.rank_of(tmp_name.to_string);
  636.         if rank > 0 then
  637.            last_expression := tmp_name.to_local_name2(local_vars,rank);
  638.            Result := true;
  639.         end;
  640.      end;
  641.       end;
  642.    
  643.    a_result: BOOLEAN is
  644.       do
  645.      if tmp_name.is_result then
  646.         if function_type = Void then
  647.            error(tmp_name.start_position,em14);
  648.         end;
  649.         last_expression := tmp_name.to_e_result;
  650.         Result := true;
  651.      end;
  652.       end;
  653.    
  654.    a_void: BOOLEAN is
  655.       do
  656.      if tmp_name.is_void then
  657.         last_expression := tmp_name.to_e_void;
  658.         Result := true;
  659.      end;
  660.       end;
  661.    
  662.    get_comments: COMMENT is
  663.       do
  664.      Result := last_comments;
  665.      last_comments := Void;
  666.       end;
  667.    
  668. feature {NONE} ----------------------------------------------------------------
  669.    -- Very low level character and text manipulation.
  670.    
  671.    start_line, start_column: INTEGER;
  672.      -- To store beginning position of : `a_keyword', `a_integer', 
  673.      -- `a_real', `skip1', `skip2' and `skip1unless2'.
  674.    
  675.    a_keyword(keyword: STRING): BOOLEAN is
  676.      -- Look for `keyword' beginning strictly at current position.
  677.      -- A keyword is never followed by a character of
  678.      -- this set : 'A'..'Z','a'..'z','0'..'9','_'.
  679.      -- When Result is true, `last_keyword' is updated. 
  680.       require
  681.      not keyword.empty
  682.       local
  683.      i, keyword_count: INTEGER;
  684.       do
  685.      keyword_count := keyword.count;
  686.      from
  687.         start_line := line;
  688.         start_column := column;
  689.      until
  690.         i = keyword_count or else not cc.same_as(keyword.item(i+1))
  691.      loop
  692.         i := i + 1;
  693.         next_char;
  694.      end;
  695.      if i = keyword_count then
  696.         inspect 
  697.            cc
  698.         when ' ','%N','%T','-' then
  699.            Result := true;
  700.            last_keyword := keyword;
  701.            skip_comments;
  702.         when 'a'..'z','A'..'Z','0'..'9','_' then
  703.            from  
  704.            until
  705.           i = 0
  706.            loop
  707.           prev_char;
  708.           i := i - 1;
  709.            end;
  710.         else
  711.            Result := true;
  712.            last_keyword := keyword;
  713.         end;
  714.      else
  715.         from  
  716.         until
  717.            i = 0
  718.         loop
  719.            prev_char;
  720.            i := i - 1;
  721.         end;
  722.      end;
  723.       end;
  724.    
  725.    a_ascii_code is
  726.      -- To read a character given as an ascii code in a manifest 
  727.      -- constant CHARACTER or STRING;
  728.      -- Require/Ensure : cc = '/'.
  729.       local
  730.      counter: INTEGER;
  731.       do
  732.      from  
  733.         check
  734.            cc = '/'
  735.         end;
  736.         next_char;
  737.         counter := 0;
  738.         last_ascii_code := 0;
  739.      until
  740.         counter > 3 or else cc = '/'
  741.      loop
  742.         inspect 
  743.            cc
  744.         when '0' .. '9' then
  745.            last_ascii_code := last_ascii_code * 10 + cc.value;
  746.         else
  747.            fcp("Unexpected character in ascii code.");
  748.         end;
  749.         counter := counter + 1;
  750.         next_char;
  751.      end;
  752.      if counter = 0 then
  753.         fcp("Bad (empty ?) ascii code.");
  754.      elseif counter > 3 then
  755.         fcp("Three digit is enought for an ascii code.");
  756.      else
  757.         check
  758.            cc = '/'
  759.         end;
  760.      end;
  761.       end;
  762.    
  763. feature {NONE} ----------------------------------------------------------------
  764.    -- Very VERY low level character and text manipulation.
  765.    
  766.    go_back(p: POSITION) is
  767.      -- Go back to `p'.
  768.       do
  769.      go_back_at(p.line,p.column);
  770.       end; 
  771.    
  772.    go_back_at(l, c: INTEGER) is
  773.      -- Go back to `l',`c'.
  774.       do
  775.      line := l;
  776.      column := c;
  777.      current_line := parser_buffer.item(line);
  778.      if column = current_line.count + 1 then
  779.         cc := '%N';
  780.      elseif column = 0 then
  781.         cc := '%U';
  782.      else
  783.         cc := current_line.item(column);
  784.      end;
  785.       end; 
  786.    
  787.    next_char is
  788.       do
  789.      if column < current_line.count then
  790.         column := column + 1;
  791.         cc := current_line.item(column);
  792.      elseif column = current_line.count then
  793.         column := column + 1;
  794.         cc := '%N';
  795.      elseif line = parser_buffer.count then
  796.         cc := end_of_text;
  797.      else
  798.         column := 1;
  799.         line := line + 1;
  800.         current_line := parser_buffer.item(line);
  801.         if current_line.count = 0 then
  802.            cc := '%N';
  803.         else
  804.            cc := current_line.first;
  805.         end;
  806.      end;
  807.       end; 
  808.    
  809.    prev_char is
  810.       do
  811.      if column > 1 then
  812.         column := column - 1;
  813.         cc := current_line.item(column);
  814.      else -- column = 1
  815.         if line > 1 then
  816.            line := line -1;
  817.            current_line := parser_buffer.item(line);
  818.            column := current_line.count + 1;
  819.            cc := '%N';
  820.         else
  821.            column := 0;
  822.            cc := '%U';
  823.         end;
  824.      end;
  825.       end;
  826.    
  827.    skip1(char: CHARACTER): BOOLEAN is
  828.       do
  829.      if char = cc then
  830.         start_line := line;
  831.         start_column := column;
  832.         Result := true;
  833.         next_char;
  834.         skip_comments;
  835.      end;
  836.       end;
  837.       
  838.    skip2(c1, c2: CHARACTER): BOOLEAN is
  839.       do
  840.      if c1 = cc then
  841.         start_line := line;
  842.         start_column := column;
  843.         next_char;
  844.         if c2 = cc then
  845.            Result := true;
  846.            next_char;
  847.            skip_comments;
  848.         else
  849.            prev_char;
  850.         end;
  851.      end;
  852.       end;
  853.    
  854.    skip1unless2(c1, c2: CHARACTER): BOOLEAN is
  855.       do
  856.      start_line := line;
  857.      start_column := column;
  858.      if cc = c1 then
  859.         next_char;
  860.         if cc = c2 then
  861.            prev_char;
  862.         else
  863.            Result := true;
  864.            skip_comments;
  865.         end;
  866.      end;
  867.       end;
  868.    
  869.    skip_comments is
  870.      -- Skip separators and store comments in `last_comments'.
  871.       local
  872.      sp: POSITION;
  873.      state: INTEGER;
  874.      -- state 0 : nothing read.
  875.      -- state 1 : first '-' read.
  876.      -- state 2 : end.
  877.       do
  878.      from  
  879.      until
  880.         state = 2
  881.      loop
  882.         inspect         
  883.            state
  884.         when 0 then
  885.            inspect 
  886.           cc
  887.            when ' ','%T','%N' then
  888.           next_char;
  889.            when '-' then
  890.           next_char;
  891.           state := 1;
  892.            else 
  893.           state := 2;
  894.            end;
  895.         when 1 then
  896.            inspect 
  897.           cc
  898.            when '-' then
  899.           from  
  900.              if drop_comments then
  901.              else 
  902.             if last_comments = Void then
  903.                !!sp.make(line,column - 1);
  904.             end;
  905.              end;
  906.              next_char;
  907.              lcs.clear;
  908.           until
  909.              cc = '%N'
  910.           loop
  911.              lcs.extend(cc);
  912.              next_char;
  913.           end;
  914.           if drop_comments then
  915.           else
  916.              if last_comments = Void then
  917.             !!last_comments.make(sp,<<(lcs.twin)>>);
  918.              else
  919.             last_comments.add_last(lcs.twin);
  920.              end;
  921.           end;
  922.           state := 0;
  923.            else
  924.           prev_char;
  925.           state := 2;
  926.            end;
  927.         end;
  928.      end;
  929.       end;
  930.    
  931. feature {NONE} ----------------------------------------------------------------
  932.    -- Lexicographic level.
  933.    
  934.    a_bit_constant: BOOLEAN is
  935.       local
  936.      l, c, state: INTEGER;
  937.      -- state 0 : first bit read.
  938.      -- state 1 : happy end.
  939.      -- state 2 : error end.
  940.       do
  941.      if cc = '0' or else cc = '1' then
  942.         from
  943.            l := line;
  944.            c := column;
  945.            tmp_string.clear;
  946.            tmp_string.extend(cc);
  947.         until
  948.            state > 0
  949.         loop
  950.            next_char;
  951.            inspect 
  952.           cc
  953.            when '0','1' then
  954.           tmp_string.extend(cc);
  955.            when 'b','B' then
  956.           !!last_bit_constant.make(pos(l,c),tmp_string.twin);
  957.           next_char;
  958.           skip_comments;
  959.           state := 1;
  960.           Result := true;
  961.            else
  962.           go_back_at(l,c);
  963.           state := 2;
  964.            end;
  965.         end;
  966.      end;   
  967.       end;
  968.       
  969.    a_character_constant: BOOLEAN is
  970.       local
  971.      sp: POSITION;
  972.      state, printing_mode: INTEGER;
  973.      value: CHARACTER;
  974.      -- state 0 : first '%'' read.
  975.      -- state 1 : first '%%' read.
  976.      -- state 2 : wait for second '%''.
  977.      -- state 3 : happy end.
  978.       do
  979.      if cc = '%'' then
  980.         from  
  981.            !!sp.make(line,column);
  982.            Result := true;
  983.         until
  984.            state > 2
  985.         loop
  986.            next_char;
  987.            inspect 
  988.           state
  989.            when 0 then
  990.           inspect 
  991.              cc
  992.           when '%%' then
  993.              state := 1;
  994.           when '%'' then
  995.              fcp(em10);
  996.              state := 2;
  997.           else
  998.              value := cc;
  999.              printing_mode := 0;
  1000.              state := 2;
  1001.           end;
  1002.            when 1 then
  1003.           printing_mode := 1;
  1004.           state := 2;
  1005.           inspect
  1006.              cc
  1007.           when 'A' then
  1008.              value := '%A';
  1009.           when 'B' then
  1010.              value := '%B';
  1011.           when 'C' then
  1012.              value := '%C';
  1013.           when 'D' then
  1014.              value := '%D';
  1015.           when 'F' then
  1016.              value := '%F';
  1017.           when 'H' then
  1018.              value := '%H';
  1019.           when 'L' then
  1020.              value := '%L';
  1021.           when 'N' then
  1022.              value := '%N';
  1023.           when 'Q' then
  1024.              value := '%Q';
  1025.           when 'R' then
  1026.              value := '%R';
  1027.           when 'S' then
  1028.              value := '%S';
  1029.           when 'T' then
  1030.              value := '%T';
  1031.           when 'U' then
  1032.              value := '%U';
  1033.           when 'V' then
  1034.              value := '%V';
  1035.           when '%%' then
  1036.              value := '%%';
  1037.           when '%'' then
  1038.              value := '%'';
  1039.           when '%"' then
  1040.              value := '%"';
  1041.           when '(' then
  1042.              value := '%(';
  1043.           when ')' then
  1044.              value := '%)';
  1045.           when '<' then
  1046.              value := '%<';
  1047.           when '>' then
  1048.              value := '%>';
  1049.           when '/' then
  1050.              a_ascii_code;
  1051.              value := last_ascii_code.to_character;
  1052.              printing_mode := 2;
  1053.           else
  1054.              fcp("Unknown special character.");
  1055.           end;
  1056.            else -- state = 2
  1057.           state := 3;
  1058.           inspect 
  1059.              cc
  1060.           when '%'' then
  1061.           else
  1062.              fcp(em10);
  1063.           end;
  1064.           next_char;
  1065.           skip_comments;
  1066.            end;
  1067.         end;
  1068.         !!last_character_constant.make(sp,value,printing_mode);
  1069.      end;
  1070.       end;
  1071.    
  1072.    a_constant: BOOLEAN is
  1073.       -- Only true for constant allowed in "when of inspect".
  1074.       local
  1075.      e_current: E_CURRENT;
  1076.      sfn: SIMPLE_FEATURE_NAME;
  1077.       do
  1078.      if a_identifier then
  1079.         Result := true;
  1080.         sfn := tmp_name.to_simple_feature_name;
  1081.         !!e_current.make(sfn.start_position,false);
  1082.         !CALL_0_C!last_expression.make(e_current,sfn);
  1083.      elseif a_character_constant then
  1084.         Result := true;
  1085.         last_expression := last_character_constant;
  1086.      elseif a_integer_constant then
  1087.         Result := true;
  1088.         last_expression := last_integer_constant;
  1089.      end;
  1090.       end;
  1091.    
  1092.    a_base_class_name: BOOLEAN is
  1093.       local
  1094.      state: INTEGER;
  1095.      do_warning: BOOLEAN;
  1096.      -- state 0 : first letter read.
  1097.      -- state 1 : end.
  1098.       do
  1099.      if cc.is_letter then
  1100.         from
  1101.            if cc >= 'a' then
  1102.           do_warning := true;
  1103.           cc := cc.to_upper;
  1104.            end;
  1105.            tmp_name.initialize(line,column);
  1106.            tmp_name.extend(cc);
  1107.         until
  1108.            state > 0
  1109.         loop
  1110.            next_char;
  1111.            inspect
  1112.           cc
  1113.            when 'A'..'Z','0'..'9','_' then
  1114.           tmp_name.extend(cc);
  1115.            when 'a'..'z' then
  1116.           do_warning := true;
  1117.           tmp_name.extend(cc.to_upper);
  1118.            else
  1119.           state := 1;
  1120.            end;
  1121.         end;
  1122.         if tmp_name.isa_keyword then
  1123.            from  
  1124.           state := tmp_name.count;
  1125.            until
  1126.           state = 0
  1127.            loop
  1128.           state := state - 1;
  1129.           prev_char;
  1130.            end;
  1131.         else
  1132.            Result := true;
  1133.            skip_comments;
  1134.            if do_warning then
  1135.           warning(tmp_name.start_position,em15);
  1136.            end;
  1137.            last_class_name := tmp_name.to_class_name;
  1138.         end;
  1139.      end;
  1140.       end;
  1141.    
  1142.    a_base_class_name1 is
  1143.       -- Read the current base class name.
  1144.       local
  1145.      state: INTEGER;
  1146.      do_warning: BOOLEAN;
  1147.      ccn: CLASS_NAME;
  1148.      -- state 0 : first letter read.
  1149.      -- state 1 : end.
  1150.       do
  1151.      ccn := last_base_class.base_class_name;
  1152.      if cc.is_letter then
  1153.         from
  1154.            ccn.start_position.set_line_column(line,column);
  1155.            tmp_name.initialize(line,column);
  1156.            if cc >= 'a' then
  1157.           do_warning := true;
  1158.           cc := cc.to_upper;
  1159.            end;
  1160.            tmp_name.extend(cc);
  1161.         until
  1162.            state > 0
  1163.         loop
  1164.            next_char;
  1165.            inspect
  1166.           cc
  1167.            when 'A'..'Z','0'..'9','_' then
  1168.           tmp_name.extend(cc);
  1169.            when 'a'..'z' then
  1170.           do_warning := true;
  1171.           tmp_name.extend(cc.to_upper);
  1172.            else
  1173.           state := 1;
  1174.            end;
  1175.         end;
  1176.         skip_comments;
  1177.         if tmp_name.isa_keyword then
  1178.            eh.add_position(ccn.start_position);
  1179.            fatal_error(em16);
  1180.         end;
  1181.         if do_warning then
  1182.            warning(ccn.start_position,em15);
  1183.         end;
  1184.         ccn.identify(tmp_name.to_string);
  1185.      else
  1186.         fcp(em16);
  1187.      end;
  1188.      if forbidden_class.fast_has(ccn.to_string) then
  1189.         eh.add_position(ccn.start_position);
  1190.         fatal_error("Cannot write such a class.");
  1191.      end;
  1192.       end;
  1193.  
  1194.    a_type_formal_generic: BOOLEAN is
  1195.       local
  1196.      fga: FORMAL_GENERIC_ARG;
  1197.      cn: CLASS_NAME;
  1198.      rank: INTEGER;
  1199.       do
  1200.      if formal_generic_list /= Void then
  1201.         from  
  1202.            rank := 1;
  1203.         until
  1204.            Result or else rank > formal_generic_list.count
  1205.         loop
  1206.            fga := formal_generic_list.item(rank);
  1207.            if a_keyword(fga.name.to_string) then
  1208.           !!cn.make(fga.name.to_string,pos(start_line,start_column));
  1209.           !!last_type_formal_generic.make(cn,rank);
  1210.           Result := true;
  1211.            end;
  1212.            rank := rank + 1;
  1213.         end;        
  1214.      end;
  1215.       end;
  1216.    
  1217.    a_free_operator: BOOLEAN is
  1218.      --++ free_operator -> "@..." |
  1219.      --++                  "#..." |
  1220.      --++                  "|..." |
  1221.      --++                  "&..."
  1222.      --++                
  1223.       do
  1224.      if (cc = '@') or else 
  1225.         (cc = '#') or else
  1226.         (cc = '|') or else
  1227.         (cc = '&') then
  1228.         Result := true;
  1229.         from  
  1230.            tmp_name.initialize(line,column);
  1231.            tmp_name.extend(cc);
  1232.            next_char;
  1233.         until
  1234.            (cc = '%N') or else
  1235.            (cc = ' ') or else
  1236.            (cc = '%T') or else
  1237.            (cc = '%"')
  1238.         loop
  1239.            tmp_name.extend(cc);
  1240.            next_char;
  1241.         end;
  1242.         skip_comments;
  1243.      end;
  1244.       end;
  1245.    
  1246.    a_identifier: BOOLEAN is
  1247.       do
  1248.      if case_insensitive then
  1249.         Result := a_identifier1;
  1250.      else
  1251.         Result := a_identifier2;
  1252.      end;
  1253.       end;
  1254.  
  1255.    a_integer: BOOLEAN is
  1256.       local
  1257.      state, value: INTEGER;
  1258.      -- state 0 : 1st digit read (no '_' encountered).
  1259.      -- state 1 : 2nd digit read (no '_' encountered).
  1260.      -- state 2 : 3rd digit read (no '_' encountered).
  1261.      -- state 3 : more than 3 digit read (no '_' encountered).
  1262.      -- state 4 : after '_'.
  1263.      -- state 5 : after '_' and 1 digit read.
  1264.      -- state 6 : after '_' and 2 digit read.
  1265.      -- state 7 : after '_' and 3 digit read.
  1266.      -- state 8 : satisfaction state.
  1267.       do
  1268.      if cc.is_digit then
  1269.         from  
  1270.            Result := true;
  1271.            start_line := line;
  1272.            start_column := column;
  1273.            value := cc.value;
  1274.         until
  1275.            state > 7
  1276.         loop
  1277.            next_char;
  1278.            inspect 
  1279.           state
  1280.            when 0 then
  1281.           inspect 
  1282.              cc
  1283.           when '0'..'9' then
  1284.              value := value * 10 + cc.value;
  1285.              state := 1;
  1286.           when '_' then
  1287.              state := 4;
  1288.           else
  1289.              state := 8;
  1290.           end;
  1291.            when 1 then
  1292.           inspect 
  1293.              cc
  1294.           when '0'..'9' then
  1295.              value := value * 10 + cc.value;
  1296.              state := 2;
  1297.           when '_' then
  1298.              state := 4;
  1299.           else
  1300.              state := 8;
  1301.           end;
  1302.            when 2 then
  1303.           inspect 
  1304.              cc
  1305.           when '0'..'9' then
  1306.              value := value * 10 + cc.value;
  1307.              state := 3;
  1308.           when '_' then
  1309.              state := 4;
  1310.           else
  1311.              state := 8;
  1312.           end;
  1313.            when 3 then
  1314.           inspect 
  1315.              cc
  1316.           when '0'..'9' then
  1317.              value := value * 10 + cc.value;
  1318.           when '_' then
  1319.              fcp(em9);
  1320.           else
  1321.              state := 8;
  1322.           end;
  1323.            when 4 then
  1324.           inspect 
  1325.              cc
  1326.           when '0'..'9' then
  1327.              value := value * 10 + cc.value;
  1328.              state := 5;
  1329.           else
  1330.              fcp(em9);
  1331.           end;
  1332.            when 5 then
  1333.           inspect 
  1334.              cc
  1335.           when '0'..'9' then
  1336.              value := value * 10 + cc.value;
  1337.              state := 6;
  1338.           else
  1339.              fcp(em9);
  1340.           end;
  1341.            when 6 then
  1342.           inspect 
  1343.              cc
  1344.           when '0'..'9' then
  1345.              value := value * 10 + cc.value;
  1346.              state := 7;
  1347.           else
  1348.              fcp(em9);
  1349.           end;
  1350.            when 7 then
  1351.           inspect 
  1352.              cc
  1353.           when '0'..'9' then
  1354.              fcp(em9);
  1355.           when '_' then
  1356.              state := 4;
  1357.           else
  1358.              state := 8;
  1359.           end;
  1360.            end;
  1361.         end;
  1362.         if cc.is_letter then
  1363.            fcp(em20);
  1364.         end;
  1365.         skip_comments;
  1366.         !!last_integer_constant.make(value,pos(start_line,start_column));
  1367.      end;
  1368.       end;
  1369.    
  1370.    a_manifest_string: BOOLEAN is
  1371.       local
  1372.      state: INTEGER;
  1373.      -- state 0 : inside string.
  1374.      -- state 1 : just read a '%%'.
  1375.      -- state 2 : extended form starting (waiting for '%N').
  1376.      -- state 3 : extended form ending (waiting for '%%').
  1377.      -- state 4 : happy end.
  1378.       do
  1379.      if cc = '%"' then
  1380.         from  
  1381.            Result := true;
  1382.            ms_numbering := ms_numbering + 1;
  1383.            !!last_manifest_string.make(pos(line,column),ms_numbering);
  1384.         until
  1385.            state > 3
  1386.         loop
  1387.            next_char;
  1388.            inspect 
  1389.           state
  1390.            when 0 then
  1391.           inspect 
  1392.              cc
  1393.           when '%N' then
  1394.              fcp(em8);
  1395.           when '%"' then
  1396.              state := 4;
  1397.           when '%%' then
  1398.              state := 1;
  1399.           else
  1400.              last_manifest_string.add(cc);
  1401.           end;
  1402.            when 1 then
  1403.           state := 0;
  1404.           inspect 
  1405.              cc
  1406.           when '%N' then
  1407.              state := 3;
  1408.           when 'A' then
  1409.              last_manifest_string.add_percent('%A');
  1410.           when 'B' then
  1411.              last_manifest_string.add_percent('%B');
  1412.           when 'C' then
  1413.              last_manifest_string.add_percent('%C');
  1414.           when 'D' then
  1415.              last_manifest_string.add_percent('%D');
  1416.           when 'F' then
  1417.              last_manifest_string.add_percent('%F');
  1418.           when 'H' then
  1419.              last_manifest_string.add_percent('%H');
  1420.           when 'L' then
  1421.              last_manifest_string.add_percent('%L');
  1422.           when 'N' then
  1423.              last_manifest_string.add_percent('%N');
  1424.           when 'Q' then
  1425.              last_manifest_string.add_percent('%Q');
  1426.           when 'R' then
  1427.              last_manifest_string.add_percent('%R');
  1428.           when 'S' then
  1429.              last_manifest_string.add_percent('%S');
  1430.           when 'T' then
  1431.              last_manifest_string.add_percent('%T');
  1432.           when 'U' then
  1433.              last_manifest_string.add_percent('%U');
  1434.           when 'V' then
  1435.              last_manifest_string.add_percent('%V');
  1436.           when '%%' then
  1437.              last_manifest_string.add_percent('%%');
  1438.           when '%'' then
  1439.              last_manifest_string.add_percent('%'');
  1440.           when '%"' then
  1441.              last_manifest_string.add_percent('%"');
  1442.           when '(' then
  1443.              last_manifest_string.add_percent('%(');
  1444.           when ')' then
  1445.              last_manifest_string.add_percent('%)');
  1446.           when '<' then
  1447.              last_manifest_string.add_percent('%<');
  1448.           when '>' then
  1449.              last_manifest_string.add_percent('%>');
  1450.           when '/' then
  1451.              a_ascii_code;
  1452.              last_manifest_string.add_ascii(last_ascii_code.to_character);
  1453.           when ' ','%T' then
  1454.              state := 2;
  1455.           else
  1456.              fcp("Unknown special character.");
  1457.              state := 0;
  1458.           end;
  1459.            when 2 then
  1460.           inspect 
  1461.              cc
  1462.           when '%N' then
  1463.              state := 3;
  1464.           when ' ','%T' then
  1465.           else
  1466.              fcp("In extended form of manifest string.%
  1467.              %Bad character after '%%'.");
  1468.           end;
  1469.            else -- state = 3
  1470.           inspect 
  1471.              cc
  1472.           when ' ','%T' then
  1473.           when '%%' then
  1474.              last_manifest_string.break_line;
  1475.              state := 0;
  1476.           when '%N' then
  1477.              fcp(em8);
  1478.              state := 0;
  1479.           else 
  1480.              fcp("In extended form of manifest string.%
  1481.              % Bad character before '%%'.");
  1482.              state := 0;
  1483.           end;
  1484.            end;
  1485.         end;        
  1486.         next_char;
  1487.         skip_comments;
  1488.      end;
  1489.       end;
  1490.    
  1491.    a_real: BOOLEAN is
  1492.       local
  1493.      state, l, c: INTEGER;
  1494.      -- state 0  : reading integral part.
  1495.      -- state 1  : reading integral part after '_'.
  1496.      -- state 2  : reading integral part after '_' and 1 digit.
  1497.      -- state 3  : reading integral part after '_' and 2 digits.
  1498.      -- state 4  : '.' read and not empty integral_part.
  1499.      -- state 5  : '.' read and empty integral_part.
  1500.      -- state 6  : reading frac_part.
  1501.      -- state 7  : reading frac_part after '_'.
  1502.      -- state 8  : reading frac_part after '_' and 1 digit.
  1503.      -- state 9  : reading frac_part after '_' and 2 digits.
  1504.      -- state 10 : 'E' or 'e' read.
  1505.      -- state 11 : reading exponent.
  1506.      -- state 12 : happy end.
  1507.      -- state 13 : error end.
  1508.       do
  1509.      if cc.is_digit or else cc = '.' then
  1510.         from
  1511.            l := line;
  1512.            c := column;
  1513.            tmp_string.clear;
  1514.            if cc = '.' then
  1515.           tmp_string.append(fz_59);
  1516.           state := 5;
  1517.            else
  1518.           tmp_string.extend(cc);
  1519.            end;
  1520.         until
  1521.            state > 11
  1522.         loop
  1523.            next_char;
  1524.            inspect 
  1525.           state
  1526.            when 0 then
  1527.           inspect 
  1528.              cc
  1529.           when '0' .. '9' then
  1530.              tmp_string.extend(cc);
  1531.           when '.' then
  1532.              tmp_string.extend('.');
  1533.              state := 4;
  1534.           else
  1535.              state := 13;
  1536.           end;
  1537.            when 1 then
  1538.           inspect 
  1539.              cc
  1540.           when '0'..'9' then
  1541.              tmp_string.extend(cc);
  1542.              state := 2;
  1543.           else
  1544.              fcp(em9);
  1545.           end;
  1546.            when 2 then
  1547.           inspect 
  1548.              cc
  1549.           when '0'..'9' then
  1550.              tmp_string.extend(cc);
  1551.              state := 3;
  1552.           else
  1553.              fcp(em9);
  1554.           end;
  1555.            when 3 then
  1556.           inspect 
  1557.              cc
  1558.           when '0'..'9' then
  1559.              tmp_string.extend(cc);
  1560.              state := 0;
  1561.           else
  1562.              fcp(em9);
  1563.           end;
  1564.            when 4 then
  1565.           inspect 
  1566.              cc
  1567.           when '0'..'9' then
  1568.              tmp_string.extend(cc);
  1569.              state := 6;
  1570.           when 'E','e' then
  1571.              tmp_string.extend('E');
  1572.              state := 10;
  1573.           else
  1574.              state := 12;
  1575.           end;
  1576.            when 5 then
  1577.           inspect 
  1578.              cc
  1579.           when '0'..'9' then
  1580.              tmp_string.extend(cc);
  1581.              state := 6;
  1582.           else
  1583.              state := 13;
  1584.           end;
  1585.            when 6 then
  1586.           inspect 
  1587.              cc
  1588.           when '0'..'9' then
  1589.              tmp_string.extend(cc);
  1590.           when 'E','e' then
  1591.              tmp_string.extend('E');
  1592.              state := 10;
  1593.           when '_' then
  1594.              state := 7;
  1595.           else
  1596.              state := 12;
  1597.           end;
  1598.            when 7 then
  1599.           inspect 
  1600.              cc
  1601.           when '0'..'9' then
  1602.              tmp_string.extend(cc);
  1603.              state := 8;
  1604.           else
  1605.              fcp(em1);
  1606.           end;
  1607.            when 8 then
  1608.           inspect 
  1609.              cc
  1610.           when '0'..'9' then
  1611.              tmp_string.extend(cc);
  1612.              state := 9;
  1613.           else
  1614.              fcp(em1);
  1615.           end;
  1616.            when 9 then
  1617.           inspect 
  1618.              cc
  1619.           when '0'..'9' then
  1620.              tmp_string.extend(cc);
  1621.              state := 6;
  1622.           else
  1623.              fcp(em1);
  1624.           end;
  1625.            when 10 then
  1626.           inspect 
  1627.              cc
  1628.           when '+' then
  1629.              state := 11;
  1630.           when '-' then
  1631.              tmp_string.extend('-');
  1632.              state := 11;
  1633.           when '0'..'9' then
  1634.              tmp_string.extend(cc);
  1635.              state := 11
  1636.           else
  1637.              fcp("Exponent of a real value expected.");
  1638.              state := 13;
  1639.           end;
  1640.            else -- state = 11
  1641.           inspect 
  1642.              cc
  1643.           when '0'..'9' then
  1644.              tmp_string.extend(cc);
  1645.           else
  1646.              state := 12;
  1647.           end;
  1648.            end;
  1649.         end;        
  1650.         if state = 12 then
  1651.            !!last_real_constant.make(pos(l,c),tmp_string.twin);
  1652.            Result := true;
  1653.            skip_comments;
  1654.         else
  1655.            go_back_at(l,c);
  1656.         end;
  1657.      end;
  1658.       end;
  1659.    
  1660.    a_retry: BOOLEAN is
  1661.       do
  1662.      if a_keyword(fz_retry) then
  1663.         if not in_rescue then
  1664.            error(pos(start_line,start_column),
  1665.               "%"retry%" cannot be outside of a rescue clause."); 
  1666.         end;
  1667.         !E_RETRY!last_instruction.make(pos(start_line,start_column));
  1668.         Result := true;
  1669.      end;
  1670.       end;
  1671.    
  1672. feature {NONE} ----------------------------------------------------------------- 
  1673.    -- Syntax analysis (recursive descent).
  1674.    -- Rules are in alphabetic order.
  1675.    -- 
  1676.    
  1677.    a_actual: BOOLEAN is
  1678.      --++ actual -> expression |
  1679.      --++           "$" identifier
  1680.      --++
  1681.       do
  1682.      if skip1('%D') then
  1683.         if a_identifier then
  1684.            if a_result or else a_void or else a_current then
  1685.           eh.add_position(last_expression.start_position);
  1686.           fatal_error(em17);
  1687.            else
  1688.           !ADDRESS_OF!last_expression.make(tmp_name.to_simple_feature_name);
  1689.           Result:= true;
  1690.            end;
  1691.         else
  1692.            fcp(em17);
  1693.         end;
  1694.      elseif a_expression then
  1695.         Result := true;
  1696.      end;
  1697.       end;
  1698.    
  1699.    a_actuals: EFFECTIVE_ARG_LIST is
  1700.      --++ actuals -> "(" {actual "," ...} ")"
  1701.      --++
  1702.       local     
  1703.      args: ARRAY[EXPRESSION];
  1704.       do
  1705.      if skip1('(') then
  1706.         from        
  1707.         until
  1708.            not a_actual
  1709.         loop
  1710.            if args = Void then
  1711.           args := <<last_expression>>;
  1712.            else
  1713.           args.add_last(last_expression);
  1714.            end;
  1715.            if not skip1(',') and then cc /= ')' then
  1716.           wcp(em5);
  1717.            end;
  1718.         end;
  1719.         if args = Void then
  1720.            wcp("Empty argument list (deleted).");
  1721.         else
  1722.            !!Result.make(args);
  1723.         end;
  1724.         if not skip1(')') then
  1725.            fcp("')' expected to end arguments list.");
  1726.         end;
  1727.      end;
  1728.       end;
  1729.    
  1730.    a_after_a_dot(do_instruction: BOOLEAN; target: EXPRESSION) is
  1731.      --++ after_a_dot -> identifier [actuals] ["." after_a_dot]
  1732.      --++
  1733.       require      
  1734.      target /= Void
  1735.       local
  1736.      sfn: SIMPLE_FEATURE_NAME;
  1737.      eal: EFFECTIVE_ARG_LIST;
  1738.       do
  1739.      if a_identifier then
  1740.         if a_result or else a_void or else a_current 
  1741.          then
  1742.            eh.add_position(last_expression.start_position);
  1743.            eh.error("This name must not appear after a dot.");
  1744.         end;
  1745.         sfn := tmp_name.to_simple_feature_name;
  1746.         eal := a_actuals;
  1747.         a_r10(do_instruction,target,sfn,eal);
  1748.      else
  1749.         fcp("Identifier expected after a dot.");
  1750.      end;
  1751.       end;
  1752.    
  1753.    a_assignment_or_call: BOOLEAN is
  1754.      --++ assignment_or_call -> "(" expression ")" r10 |
  1755.      --++                       "Current" r10 |
  1756.      --++                       "Result" r10 |
  1757.      --++                       local_variable r10 |
  1758.      --++                       formal_argument r10 |
  1759.      --++                       writable ":=" expression | 
  1760.      --++                       writable "?=" expression |
  1761.      --++                       identifier procedure_call
  1762.      --++
  1763.       do
  1764.      if skip1('(') and then a_expression then
  1765.         Result := true;
  1766.         if skip1(')') then
  1767.            a_r10(true,last_expression,Void,Void);
  1768.         else
  1769.            fcp("')' expected.");
  1770.         end;
  1771.      elseif a_identifier then
  1772.         Result := true;
  1773.         if skip2(':','=') then
  1774.            a_assignment_aux(true);
  1775.         elseif skip2('?','=') then
  1776.            a_assignment_aux(false);
  1777.         elseif a_current or else a_result or else a_local_variable 
  1778.            or else a_argument then
  1779.            a_r10(true,last_expression,Void,Void);
  1780.         else   
  1781.            a_procedure_call;
  1782.         end;
  1783.      end;
  1784.       end;
  1785.    
  1786.    a_assignment_aux(regular: BOOLEAN) is
  1787.       local
  1788.      writable, rhs: EXPRESSION;
  1789.       do
  1790.      if a_current then
  1791.         eh.add_position(last_expression.start_position);
  1792.         fatal_error("Must not affect `Current'.");
  1793.      elseif a_void then
  1794.         eh.add_position(tmp_name.start_position);
  1795.         fatal_error("Must not affect `Void'.");
  1796.      elseif a_argument then
  1797.         eh.add_position(last_expression.start_position);
  1798.         fatal_error("Must not affect a formal argument.");
  1799.      else
  1800.         if tmp_name.is_result then
  1801.            if function_type = Void then
  1802.           error(tmp_name.start_position,em14);
  1803.            end;
  1804.            writable := tmp_name.to_e_result;
  1805.         elseif a_local_variable then
  1806.            writable := last_expression;
  1807.         else
  1808.            writable := tmp_name.to_simple_feature_name;
  1809.         end;
  1810.         if a_expression then
  1811.            rhs := last_expression;
  1812.            if regular then
  1813.           !ASSIGNMENT!last_instruction.make(writable,rhs);
  1814.            else
  1815.           !REVERSE_ASSIGNMENT!last_instruction.make(writable,rhs);
  1816.            end;
  1817.         else
  1818.            fcp("Right hand side expression expected for assignment.");
  1819.         end;
  1820.      end;
  1821.       end;
  1822.    
  1823.    a_assertion: ARRAY[ASSERTION] is
  1824.      --++ assertion -> {assertion_clause ";" ...}
  1825.      --++ assertion_clause -> [identifier ":"] [expression] [comment]
  1826.      --++
  1827.       local
  1828.      tag: like last_tag_mark;
  1829.      expression: like last_expression;
  1830.      assertion: ASSERTION;
  1831.      state: INTEGER;
  1832.      -- state 0 : nothing read.
  1833.      -- state 1 : read a `tag'.
  1834.      -- state 2 : read an `expression'.
  1835.      -- state 3 : read a `tag' and an `expression'.
  1836.      -- state 4 : end;
  1837.       do
  1838.      from
  1839.      until
  1840.         state > 3
  1841.      loop
  1842.         inspect 
  1843.            state
  1844.         when 0 then
  1845.            if cc = ';' then
  1846.           wcp(fz_desc);
  1847.           ok := skip1(';');
  1848.           if last_comments /= Void then
  1849.              !!assertion.make(Void,Void,get_comments);
  1850.              if Result = Void then
  1851.             Result := <<assertion>>;
  1852.              else
  1853.             Result.add_last(assertion);
  1854.              end;
  1855.           end;
  1856.            elseif a_tag_mark then
  1857.           tag := last_tag_mark;
  1858.           state := 1;
  1859.            elseif a_expression then          
  1860.           expression := last_expression;
  1861.           state := 2;
  1862.            else
  1863.           state := 4;
  1864.            end;
  1865.         when 1 then
  1866.            if skip1(';') then
  1867.           !!assertion.make(tag,Void,get_comments);
  1868.           if Result = Void then
  1869.              Result := <<assertion>>;
  1870.           else
  1871.              Result.add_last(assertion);
  1872.           end;
  1873.           state := 0;
  1874.            elseif a_tag_mark then
  1875.           !!assertion.make(tag,Void,get_comments);
  1876.           if Result = Void then
  1877.              Result := <<assertion>>;
  1878.           else
  1879.              Result.add_last(assertion);
  1880.           end;
  1881.           tag := last_tag_mark;
  1882.            elseif a_expression then
  1883.           expression := last_expression;
  1884.           state := 3;
  1885.            else
  1886.           !!assertion.make(tag,Void,get_comments);
  1887.           if Result = Void then
  1888.              Result := <<assertion>>;
  1889.           else
  1890.              Result.add_last(assertion);
  1891.           end;
  1892.           state := 4;
  1893.            end;
  1894.         when 2 then
  1895.            if skip1(';') then
  1896.           !!assertion.make(Void,expression,get_comments);
  1897.           if Result = Void then
  1898.              Result := <<assertion>>;
  1899.           else
  1900.              Result.add_last(assertion);
  1901.           end;
  1902.           state := 0;
  1903.            elseif a_tag_mark then
  1904.           !!assertion.make(Void,expression,get_comments);
  1905.           if Result = Void then
  1906.              Result := <<assertion>>;
  1907.           else
  1908.              Result.add_last(assertion);
  1909.           end;
  1910.           tag := last_tag_mark;
  1911.           state := 1;
  1912.            elseif a_expression then
  1913.           !!assertion.make(Void,expression,get_comments);
  1914.           if Result = Void then
  1915.              Result := <<assertion>>;
  1916.           else
  1917.              Result.add_last(assertion);
  1918.           end;
  1919.           expression := last_expression;
  1920.           state := 2;
  1921.            else
  1922.           !!assertion.make(Void,expression,get_comments);
  1923.           if Result = Void then
  1924.              Result := <<assertion>>;
  1925.           else
  1926.              Result.add_last(assertion);
  1927.           end;
  1928.           state := 4;
  1929.            end;
  1930.         else -- state = 3
  1931.            if skip1(';') then
  1932.           !!assertion.make(tag,expression,get_comments);
  1933.           if Result = Void then
  1934.              Result := <<assertion>>;
  1935.           else
  1936.              Result.add_last(assertion);
  1937.           end;
  1938.           state := 0;
  1939.            elseif a_tag_mark then
  1940.           !!assertion.make(tag,expression,get_comments);
  1941.           if Result = Void then
  1942.              Result := <<assertion>>;
  1943.           else
  1944.              Result.add_last(assertion);
  1945.           end;
  1946.           tag := last_tag_mark;
  1947.           state := 1;
  1948.            elseif a_expression then
  1949.           !!assertion.make(tag,expression,get_comments);
  1950.           if Result = Void then
  1951.              Result := <<assertion>>;
  1952.           else
  1953.              Result.add_last(assertion);
  1954.           end;
  1955.           expression := last_expression;
  1956.           state := 2;
  1957.            else
  1958.           !!assertion.make(tag,expression,get_comments);
  1959.           if Result = Void then
  1960.              Result := <<assertion>>;
  1961.           else
  1962.              Result.add_last(assertion);
  1963.           end;
  1964.           state := 4;
  1965.            end;
  1966.         end;
  1967.      end;
  1968.       end;
  1969.    
  1970.    a_base_type: BOOLEAN is
  1971.      --++ base_type -> "ANY" | ARRAY "[" type "]" | "BOOLEAN" | 
  1972.      --++         "CHARACTER" | "DOUBLE" | "INTEGER" | "NONE" | 
  1973.      --++         "POINTER" | "REAL" | "STRING"      
  1974.      --++
  1975.       local 
  1976.      sp: POSITION;
  1977.       do
  1978.      Result := true;
  1979.      if a_keyword(us_any) then
  1980.         !TYPE_ANY!last_base_type.make(pos(start_line,start_column));
  1981.      elseif a_keyword(us_array) then
  1982.         !!sp.make(start_line,start_column);
  1983.         if skip1('[') and then a_type and then skip1(']') then
  1984.            check
  1985.           last_type /= Void
  1986.            end;
  1987.            !TYPE_ARRAY!last_base_type.make(sp,last_type);
  1988.         else
  1989.            fcp("Bad use of predefined type ARRAY.");
  1990.         end;
  1991.      elseif a_keyword(us_native_array) then
  1992.         !!sp.make(start_line,start_column);
  1993.         if skip1('[') and then a_type and then skip1(']') then
  1994.            check
  1995.           last_type /= Void
  1996.            end;
  1997.            !TYPE_NATIVE_ARRAY!last_base_type.make(sp,last_type);
  1998.         else
  1999.            fcp("Bad use of predefined type NATIVE_ARRAY.");
  2000.         end;
  2001.      elseif a_keyword("C_ARRAY") then
  2002.         !!sp.make(start_line,start_column);
  2003.         if skip1('[') and then a_type and then skip1(']') then
  2004.            check
  2005.           last_type /= Void
  2006.            end;
  2007.            !TYPE_NATIVE_ARRAY!last_base_type.make(sp,last_type);
  2008.         else
  2009.            fcp("Bad use of predefined type C_ARRAY.");
  2010.         end;
  2011.         warning(sp,"For Java compatibility, the new name is NATIVE_ARRAY.");
  2012.      elseif a_keyword(us_boolean) then
  2013.         !TYPE_BOOLEAN!last_base_type.make(pos(start_line,start_column));
  2014.      elseif a_keyword(us_character) then
  2015.         !TYPE_CHARACTER!last_base_type.make(pos(start_line,start_column));
  2016.      elseif a_keyword(us_double) then
  2017.         !TYPE_DOUBLE!last_base_type.make(pos(start_line,start_column));
  2018.      elseif a_keyword(us_integer) then
  2019.         !TYPE_INTEGER!last_base_type.make(pos(start_line,start_column));
  2020.      elseif a_keyword(us_none) then
  2021.         !TYPE_NONE!last_base_type.make(pos(start_line,start_column));
  2022.      elseif a_keyword(us_pointer) then
  2023.         !TYPE_POINTER!last_base_type.make(pos(start_line,start_column));
  2024.      elseif a_keyword(us_real) then
  2025.         !TYPE_REAL!last_base_type.make(pos(start_line,start_column));
  2026.      elseif a_keyword(us_string) then
  2027.         !TYPE_STRING!last_base_type.make(pos(start_line,start_column));
  2028.      else
  2029.         Result := false;
  2030.      end;
  2031.       end;
  2032.    
  2033.    a_binary(sp: POSITION): BOOLEAN is
  2034.      --++ binary -> "<=" | ">=" | "//" | "\\" |
  2035.      --++           "+" | "-" | "*" | "/" | "<" | ">" | "^" | 
  2036.      --++           xor" | "implies" | "and then" | "and" | "or else" | "or" 
  2037.      --++
  2038.       do
  2039.      Result := true;
  2040.      if skip2('<','=') then
  2041.         !!last_binary.make(us_le,sp);
  2042.      elseif skip2('>','=') then
  2043.         !!last_binary.make(us_ge,sp);
  2044.      elseif skip2('/','/') then
  2045.         !!last_binary.make("//",sp);
  2046.      elseif skip2('\','\') then
  2047.         !!last_binary.make("\\",sp);
  2048.      elseif skip1('+') then
  2049.         !!last_binary.make(us_plus,sp);
  2050.      elseif skip1('-') then
  2051.         !!last_binary.make(us_minus,sp);
  2052.      elseif skip1('*') then
  2053.         !!last_binary.make(us_muls,sp);
  2054.      elseif skip1('/') then
  2055.         !!last_binary.make(us_slash,sp);
  2056.      elseif skip1('>') then
  2057.         !!last_binary.make(us_gt,sp);
  2058.      elseif skip1('<') then
  2059.         !!last_binary.make(us_lt,sp);
  2060.      elseif skip1('^') then
  2061.         !!last_binary.make("^",sp);
  2062.      elseif a_keyword(us_xor) then
  2063.         !!last_binary.make(us_xor,sp);
  2064.      elseif a_keyword(us_implies) then
  2065.         !!last_binary.make(us_implies,sp)
  2066.      elseif a_keyword(us_and) then
  2067.         if a_keyword(fz_then) then
  2068.            !!last_binary.make(us_and_then,sp);
  2069.         else
  2070.            !!last_binary.make(us_and,sp);
  2071.         end;
  2072.      elseif a_keyword(us_or) then
  2073.         if a_keyword(fz_else) then
  2074.            !!last_binary.make(us_or_else,sp);
  2075.         else
  2076.            !!last_binary.make(us_or,sp);
  2077.         end;
  2078.      else
  2079.         last_binary := Void;
  2080.         Result := false;
  2081.      end;
  2082.       end;
  2083.    
  2084.    a_boolean_constant: BOOLEAN is
  2085.      --++ boolean_constant -> "true" | "false"
  2086.      --++
  2087.       do
  2088.      if a_keyword(fz_true) then
  2089.         !E_TRUE!last_boolean_constant.make(pos(start_line,start_column));
  2090.         Result := true;
  2091.      elseif a_keyword(fz_false) then
  2092.         !E_FALSE!last_boolean_constant.make(pos(start_line,start_column));
  2093.         Result := true;
  2094.      end;
  2095.       end; 
  2096.    
  2097.    a_character_or_integer: BOOLEAN is
  2098.      --++ character_or_integer -> character_constant |
  2099.      --++                         integer_constant
  2100.      --++
  2101.       do
  2102.      if a_character_constant then
  2103.         last_character_or_integer := last_character_constant;
  2104.         Result := true;
  2105.      elseif a_integer_constant then
  2106.         last_character_or_integer := last_integer_constant;
  2107.         Result := true;
  2108.      end;
  2109.       end;
  2110.    
  2111.    a_check: BOOLEAN is
  2112.      --++ check -> "check" assertion "end"
  2113.      --++
  2114.       local
  2115.      sp: POSITION;
  2116.      hc: COMMENT;
  2117.      al: ARRAY[ASSERTION];
  2118.       do
  2119.      if a_keyword(fz_check) then
  2120.         Result := true;
  2121.         !!sp.make(start_line,start_column);
  2122.         hc := get_comments;
  2123.         al := a_assertion;
  2124.         if hc /= Void or else al /= Void then
  2125.            !E_CHECK!last_instruction.make(sp,hc,al);
  2126.         else
  2127.            wcp("Empty check instruction removed.");
  2128.         end;
  2129.         if not a_keyword(fz_end) then
  2130.            fcp("Keyword %"end%" expected at the end of check clause.");
  2131.         end;
  2132.      end;
  2133.       end;
  2134.    
  2135.    a_class_declaration is
  2136.      --++ class_declaration -> [indexing]
  2137.      --++                      ["expanded" | "deferred"]
  2138.      --++                      "class" base_class_name
  2139.      --++                      ["[" formal_generic_list "]"]
  2140.      --++                      [comment]
  2141.      --++                      ["obsolete" manifest_string]
  2142.      --++                      ["inherit" parent_list]
  2143.      --++                      {"creation" creation_clause ...} 
  2144.      --++                      {"feature" feature_clause ...} 
  2145.      --++                      ["invariant" assertion]
  2146.      --++                      "end"
  2147.      --++
  2148.       local
  2149.      sp: POSITION;
  2150.      hc: COMMENT;
  2151.      al: ARRAY[ASSERTION];
  2152.       do
  2153.      a_indexing; 
  2154.      if a_keyword(fz_deferred) then
  2155.         last_base_class.set_is_deferred;
  2156.      end;
  2157.      if a_keyword(fz_expanded) then      
  2158.         last_base_class.set_is_expanded;
  2159.         if a_keyword(fz_deferred) then
  2160.            last_base_class.set_is_deferred;
  2161.         end;
  2162.      end;
  2163.      last_base_class.set_heading_comment1(get_comments);
  2164.      if not a_keyword(fz_class) then
  2165.         fcp("Keyword %"class%" expected.");
  2166.      end;
  2167.      a_base_class_name1;
  2168.      a_formal_generic_list; 
  2169.      if a_keyword(fz_obsolete) then
  2170.         if a_manifest_string then
  2171.            last_base_class.set_obsolete_type_string(last_manifest_string);
  2172.         else
  2173.            fcp("Manifest string expected for %"obsolete%" clause.");
  2174.         end;
  2175.      end;
  2176.      last_base_class.set_heading_comment2(get_comments);
  2177.      if a_keyword(fz_inherit) then
  2178.         a_parent_list(pos(start_line,start_column),get_comments);
  2179.      end;
  2180.      from
  2181.      until
  2182.         not a_keyword(fz_creation)
  2183.      loop
  2184.         a_creation_clause(pos(start_line,start_column));
  2185.      end;
  2186.      from
  2187.      until
  2188.         not a_keyword(fz_feature)
  2189.      loop
  2190.         a_feature_clause; 
  2191.      end;
  2192.      if a_keyword(fz_invariant) then
  2193.         !!sp.make(start_line,start_column);
  2194.         hc := get_comments;
  2195.         al := a_assertion;
  2196.         last_base_class.set_invariant(sp,hc,al);
  2197.      end;
  2198.      if a_keyword(fz_end) or else last_keyword = fz_end then
  2199.         if cc = ';' then
  2200.            wcp(fz_desc);
  2201.            ok := skip1(';');
  2202.         end;
  2203.         last_base_class.set_end_comment(get_comments);
  2204.         if cc /= end_of_text then
  2205.            fcp("End of text expected.");
  2206.         end;
  2207.      else
  2208.         fcp("Keyword %"end%" expected at the end of a class.");
  2209.      end;
  2210.       end;
  2211.    
  2212.    a_class_type: BOOLEAN is
  2213.      --++ class_type -> base_type |
  2214.      --++               base_class_name ["[" {type "," ...} "]"]
  2215.      --++
  2216.       local
  2217.      state: INTEGER;
  2218.      base_class_name: CLASS_NAME;
  2219.      generic_list: ARRAY[TYPE];
  2220.      -- state 0 : `base_class_name' read.
  2221.      -- state 1 : waiting next generic argument.
  2222.      -- state 2 : waiting ',' or ']'.
  2223.      -- state 3 : end.
  2224.       do 
  2225.      if a_base_type then
  2226.         last_class_type := last_base_type;
  2227.         Result := true;
  2228.      elseif a_base_class_name then
  2229.         from  
  2230.            Result := true;
  2231.            base_class_name := last_class_name;
  2232.         until
  2233.            state > 2
  2234.         loop
  2235.            inspect 
  2236.           state
  2237.            when 0 then
  2238.           if skip1('[') then
  2239.              state := 1;
  2240.           else
  2241.              !TYPE_CLASS!last_class_type.make(base_class_name);
  2242.              state := 3;
  2243.           end;
  2244.            when 1 then
  2245.           if a_type then
  2246.              if generic_list = Void then
  2247.             generic_list := <<last_type>>;
  2248.              else
  2249.             generic_list.add_last(last_type);
  2250.              end;
  2251.              state := 2;
  2252.           elseif cc = ',' then
  2253.              wcp(em12);
  2254.              ok := skip1(',');
  2255.           elseif cc = ']' then
  2256.              state := 2;
  2257.           else
  2258.              fcp(em18);
  2259.              state := 2;
  2260.           end;
  2261.            else -- state = 2
  2262.           if skip1(',') then
  2263.              state := 1;
  2264.           elseif cc = ']' then
  2265.              if generic_list = Void then
  2266.             wcp("Empty generic list (deleted).");
  2267.             !TYPE_CLASS!last_class_type.make(base_class_name);
  2268.              else
  2269.             !TYPE_GENERIC!last_class_type.make(base_class_name,generic_list);
  2270.              end;
  2271.              ok := skip1(']');
  2272.              state := 3;
  2273.           elseif a_type then
  2274.              if generic_list = Void then
  2275.             generic_list := <<last_type>>;
  2276.              else
  2277.             generic_list.add_last(last_type);
  2278.              end;
  2279.              warning(last_type.start_position,em5);
  2280.           else
  2281.              fcp("Bad generic list.");
  2282.              state := 3;
  2283.           end;
  2284.            end;
  2285.         end;
  2286.      end; 
  2287.       end;
  2288.    
  2289.    a_clients: CLIENT_LIST is
  2290.      --++ clients -> "{" { base_class_name "," ... } "}"
  2291.      --++
  2292.       local
  2293.      sp: POSITION;
  2294.      list: ARRAY[CLASS_NAME];
  2295.      state: INTEGER;
  2296.      -- state 0 : waiting a base_class_name or "}" if empty list.
  2297.      -- state 1 : waiting a base_class_name after a ",".
  2298.      -- state 2 : waiting "," or "}" to end list.
  2299.      -- state 3 : error.
  2300.      -- state 4 : end.
  2301.       do
  2302.      if skip1('{') then
  2303.         from
  2304.            !!sp.make(start_line,start_column);
  2305.         until
  2306.            state > 3
  2307.         loop
  2308.            inspect 
  2309.           state
  2310.            when 0 then
  2311.           if a_base_class_name then
  2312.              list := <<last_class_name>>;
  2313.              state := 2;
  2314.           elseif skip1('}') then
  2315.              state := 4;
  2316.           elseif cc = ',' then
  2317.              wcp(em7);
  2318.              ok := skip1(',');
  2319.           else
  2320.              state := 3;
  2321.           end;
  2322.            when 1 then
  2323.           if a_base_class_name then 
  2324.              list.add_last(last_class_name);
  2325.              state := 2;
  2326.           elseif cc = ',' then
  2327.              wcp(em7);
  2328.              ok := skip1(',');
  2329.           elseif cc = '}' then
  2330.              wcp("Unexpected bracket.");
  2331.              ok := skip1('}');
  2332.              state := 4;
  2333.           else
  2334.              state := 3;
  2335.           end;
  2336.            when 2 then
  2337.           if skip1(',') then
  2338.              state := 1;
  2339.           elseif skip1('}') then
  2340.              state := 4;
  2341.           elseif a_base_class_name then
  2342.              warning(last_class_name.start_position,em5);
  2343.              list.add_last(last_class_name);
  2344.           else
  2345.              state := 3;
  2346.           end;          
  2347.            else -- state = 3
  2348.           fcp(em11);
  2349.           state := 4;
  2350.            end;
  2351.         end;
  2352.         !!Result.make(sp,list);
  2353.      else
  2354.         !!Result.omitted;
  2355.      end;
  2356.       ensure
  2357.      Result /= Void
  2358.       end;
  2359.    
  2360.    a_compound1(compound_of: STRING): COMPOUND is
  2361.      --++ compound -> {instruction ";" ...}
  2362.      --++
  2363.       local
  2364.      hc: COMMENT;
  2365.      list: ARRAY[INSTRUCTION];
  2366.      instruction: like last_instruction;
  2367.       do 
  2368.      from        
  2369.         hc := get_comments;
  2370.         from  
  2371.         until
  2372.            cc /= ';'
  2373.         loop
  2374.            wcp(fz_desc);
  2375.            ok := skip1(';');
  2376.         end;
  2377.      until
  2378.         not a_instruction or else nb_errors > 0
  2379.      loop
  2380.         instruction := last_instruction;
  2381.         check
  2382.            instruction /= Void;
  2383.         end;
  2384.         if cc = '(' then
  2385.            wcp(em6);
  2386.         end;
  2387.         from  
  2388.            ok := skip1(';');
  2389.         until
  2390.            cc /= ';'
  2391.         loop
  2392.            wcp(fz_desc);
  2393.            ok := skip1(';');
  2394.         end;
  2395.         if nb_errors = 0 then
  2396.            if list = Void then
  2397.           list := <<instruction.add_comment(get_comments)>>;
  2398.            else           
  2399.           list.add_last(instruction.add_comment(get_comments));
  2400.            end;
  2401.         end;
  2402.      end;
  2403.      if hc /= Void or else list /= Void then
  2404.         !!Result.make(hc,list);
  2405.      end;
  2406.       end;
  2407.    
  2408.    a_compound2(compound_of, terminator: STRING): COMPOUND is
  2409.      -- Like a_compound1 but stop when `terminator' is encountered. 
  2410.       local
  2411.      hc: COMMENT;
  2412.      list: ARRAY[INSTRUCTION];
  2413.      instruction: like last_instruction;
  2414.       do 
  2415.      from        
  2416.         hc := get_comments;
  2417.         from  
  2418.         until
  2419.            cc /= ';'
  2420.         loop
  2421.            wcp(fz_desc);
  2422.            ok := skip1(';');
  2423.         end;
  2424.      until
  2425.         not a_instruction or else nb_errors > 0
  2426.      loop
  2427.         instruction := last_instruction;
  2428.         check
  2429.            instruction /= Void;
  2430.         end;
  2431.         if cc = '(' then
  2432.            wcp(em6);
  2433.         end;
  2434.         from  
  2435.            ok := skip1(';');
  2436.         until
  2437.            cc /= ';'
  2438.         loop
  2439.            wcp(fz_desc);
  2440.            ok := skip1(';');
  2441.         end;
  2442.         if nb_errors = 0 then
  2443.            if list = Void then
  2444.           list := <<instruction.add_comment(get_comments)>>;
  2445.            else
  2446.           list.add_last(instruction.add_comment(get_comments));
  2447.            end;
  2448.         end;
  2449.      end;
  2450.      if not a_keyword(terminator) then
  2451.         eh.append("In compound (");
  2452.         eh.append(compound_of);
  2453.         eh.append("). Instruction or keyword %"");
  2454.         eh.append(terminator);
  2455.         fcp("%" expected.");
  2456.      end;
  2457.      if hc /= Void or else list /= Void then
  2458.         !!Result.make(hc,list);
  2459.      end;
  2460.       end;
  2461.    
  2462.    a_conditional: BOOLEAN is
  2463.      --++ conditional -> "if" then_part_list ["else" compound] "end"
  2464.      --++
  2465.       local
  2466.      ifthenelse: IFTHENELSE;
  2467.       do
  2468.      if a_keyword(fz_if) then
  2469.         Result := true;
  2470.         !!ifthenelse.make(pos(start_line,start_column)); 
  2471.         a_then_part_list(ifthenelse);
  2472.         if a_keyword(fz_else) then
  2473.            ifthenelse.set_else_compound(a_compound2("else part",fz_end));
  2474.         else
  2475.            if not a_keyword(fz_end) then
  2476.           wcp("Keyword %"end%" added.");
  2477.            end;
  2478.         end;
  2479.         last_instruction := ifthenelse;
  2480.      end;
  2481.       end;
  2482.    
  2483.    a_creation: BOOLEAN is
  2484.      --++ creation -> "!"[type]"!" writable ["." proc_name [actuals]]
  2485.      --++
  2486.       local
  2487.      sp: POSITION;
  2488.      type: TYPE;
  2489.      writable: EXPRESSION;
  2490.      proc_name: FEATURE_NAME;
  2491.      call: PROC_CALL;
  2492.      state: INTEGER;
  2493.      -- state 0 : waiting first '!'.
  2494.      -- state 1 : waiting `type' or second '!'.
  2495.      -- state 2 : waiting second '!'.
  2496.      -- state 3 : waiting `writable'.
  2497.      -- state 4 : waiting `.'.
  2498.      -- state 5 : waiting `proc_name'.
  2499.      -- state 6 : waiting `actuals'.
  2500.      -- state 7 : end.
  2501.      -- state 8 : error.
  2502.  
  2503.       do
  2504.      from  
  2505.      until
  2506.         state > 6
  2507.      loop
  2508.         inspect 
  2509.            state
  2510.         when 0 then
  2511.            if skip1('!') then
  2512.           !!sp.make(start_line,start_column);
  2513.           state := 1;
  2514.            else
  2515.           state := 7;
  2516.            end;
  2517.         when 1 then
  2518.            if a_type then
  2519.           type := last_type;
  2520.           if type.is_anchored then
  2521.              warning(type.start_position,
  2522.              "Explicit creation type mark must not be anchored.");
  2523.           end;
  2524.           state := 2;
  2525.            elseif skip1('!') then
  2526.           state := 3;
  2527.            else
  2528.           fcp("Bad creation (type or '!' expected).");
  2529.           state := 8
  2530.            end;
  2531.         when 2 then
  2532.            if skip1('!') then
  2533.           state := 3;
  2534.            else
  2535.           state := 8
  2536.           fcp("Bad creation ('!' expected).");
  2537.            end;
  2538.         when 3 then
  2539.            if a_identifier then
  2540.           if a_current then
  2541.              state := 8;
  2542.              error(last_expression.start_position,
  2543.              "Current is not a writable variable.");
  2544.           elseif a_argument then
  2545.              state := 8;
  2546.              error(last_expression.start_position,
  2547.              "A formal argument is not a writable variable.");
  2548.           elseif a_result or else a_local_variable then
  2549.              writable := last_expression;
  2550.              state := 4;
  2551.           else
  2552.              writable := tmp_name.to_simple_feature_name;
  2553.              state := 4;
  2554.           end;
  2555.            else
  2556.           state := 8;
  2557.           fcp("Bad creation (writable expected).");
  2558.            end;
  2559.         when 4 then
  2560.            if skip1unless2('.','.') then
  2561.           state := 5;
  2562.            else
  2563.           state := 7
  2564.            end;
  2565.         when 5 then
  2566.            if a_identifier then
  2567.           proc_name := tmp_name.to_simple_feature_name;
  2568.           state := 6;
  2569.            else
  2570.           state := 8;
  2571.           fcp("Bad creation (procedure name expected).");
  2572.            end;
  2573.         else -- state = 6
  2574.            if cc = '(' then
  2575.           call := to_proc_call(writable,proc_name,a_actuals);
  2576.            else
  2577.           !PROC_CALL_0!call.make(writable,proc_name);
  2578.            end;
  2579.            state := 7;
  2580.         end;
  2581.      end;
  2582.      if state = 7 and then sp /= Void then
  2583.         Result := true;
  2584.         if type = Void and then call = Void then
  2585.            !CREATION_CALL_1!last_instruction.make(sp,writable);
  2586.         elseif type /= Void and then call = Void then
  2587.            !CREATION_CALL_2!last_instruction.make(sp,type,writable);
  2588.         elseif type = Void and then call /= Void then
  2589.            !CREATION_CALL_3!last_instruction.make(sp,writable,call);
  2590.         else
  2591.            !CREATION_CALL_4!last_instruction.make(sp,type,writable,call);
  2592.         end;
  2593.      end;
  2594.       end;
  2595.    
  2596.    a_creation_clause(sp: POSITION) is
  2597.      --++ creation_clause -> [clients] [comment] feature_list
  2598.      --++
  2599.       local
  2600.      clients: CLIENT_LIST;
  2601.      comments: COMMENT;
  2602.      list: ARRAY[FEATURE_NAME];
  2603.      creation_clause: CREATION_CLAUSE;
  2604.       do
  2605.      clients := a_clients;
  2606.      comments := get_comments;
  2607.      if a_feature_list then
  2608.         list := last_feature_list;
  2609.      end;
  2610.      !!creation_clause.make(sp,clients,comments,list);
  2611.      last_base_class.add_creation_clause(creation_clause);
  2612.       end;
  2613.    
  2614.    a_debug: BOOLEAN is
  2615.      --++ debug -> "debug" "(" {manifest_string "," ...} ")"
  2616.      --++                  compound "end"
  2617.      --++
  2618.       local
  2619.      sp: POSITION;
  2620.      list: ARRAY[MANIFEST_STRING];
  2621.      e_debug: E_DEBUG;
  2622.       do
  2623.      if a_keyword(fz_debug) then
  2624.         !!sp.make(start_line,start_column);
  2625.         if skip1('(') then
  2626.            from        
  2627.            until
  2628.           not a_manifest_string
  2629.            loop
  2630.           if list = Void then
  2631.              list := <<last_manifest_string>>;
  2632.           else
  2633.              list.add_last(last_manifest_string);
  2634.           end;
  2635.           ok := skip1(',');
  2636.            end;
  2637.            if list = Void then
  2638.           wcp("Empty debug key list (deleted).");
  2639.            end;
  2640.            if not skip1(')') then
  2641.           fcp("%")%" expected to end debug string list.");
  2642.            end;
  2643.         end;
  2644.         Result := true;
  2645.         !!e_debug.make(sp,list,a_compound2("debug",fz_end));
  2646.         last_instruction := e_debug;
  2647.      end;
  2648.       end;
  2649.    
  2650.    a_expression: BOOLEAN is
  2651.      --++ expression -> "<<" {Expression "," ...} ">>" |
  2652.      --++               e0
  2653.      --++
  2654.       local
  2655.      sp: POSITION;
  2656.      list: ARRAY[EXPRESSION];
  2657.       do
  2658.      if skip2('<','<') then
  2659.         from    
  2660.            Result := true;
  2661.            !!sp.make(start_line,start_column);
  2662.         until
  2663.            not a_expression
  2664.         loop
  2665.            if list = Void then
  2666.           list := <<last_expression>>;
  2667.            else
  2668.           list.add_last(last_expression);
  2669.            end;
  2670.            ok := skip1(',');
  2671.         end;
  2672.         if not skip2('>','>') then
  2673.            fcp("End of manifest array expected.");
  2674.         end;
  2675.         !MANIFEST_ARRAY!last_expression.make(sp,list);
  2676.      else
  2677.         Result := a_e0;
  2678.      end;
  2679.       end;
  2680.    
  2681.    a_e0: BOOLEAN is
  2682.      --++ e0 -> e1 r1
  2683.      --++
  2684.       do
  2685.      Result := a_e1; 
  2686.      a_r1(last_expression);
  2687.       end;
  2688.    
  2689.    a_e1: BOOLEAN is
  2690.      --++ e1 -> e2 r2
  2691.      --++
  2692.       do
  2693.      Result := a_e2;
  2694.      a_r2(last_expression);
  2695.       end;
  2696.    
  2697.    a_e2: BOOLEAN is
  2698.      --++ e2 -> e3 r3
  2699.      --++
  2700.       do
  2701.      Result := a_e3; 
  2702.      a_r3(last_expression);
  2703.       end;
  2704.    
  2705.    a_e3: BOOLEAN is
  2706.      --++ e3 -> e4 r4
  2707.      --++
  2708.       do
  2709.      Result := a_e4; 
  2710.      a_r4(last_expression);
  2711.       end;
  2712.    
  2713.    a_e4: BOOLEAN is
  2714.      --++ e4 -> e5 r5
  2715.      --++
  2716.       do
  2717.      Result := a_e5; 
  2718.      a_r5(last_expression);
  2719.       end;
  2720.    
  2721.    a_e5: BOOLEAN is
  2722.      --++ e5 -> e6 r6
  2723.      --++
  2724.       do
  2725.      Result := a_e6; 
  2726.      a_r6(last_expression);
  2727.       end;
  2728.    
  2729.    a_e6: BOOLEAN is
  2730.      --++ e6 -> e7 r7
  2731.      --++
  2732.       do
  2733.      Result := a_e7; 
  2734.      a_r7(last_expression);
  2735.       end;
  2736.    
  2737.    a_e7: BOOLEAN is
  2738.      --++ e7 -> e8 r8
  2739.      --++
  2740.       do
  2741.      Result := a_e8; 
  2742.      a_r8(last_expression);
  2743.       end;
  2744.    
  2745.    a_e8: BOOLEAN is
  2746.      --++ e8 -> "not" e8 |
  2747.      --++       "+" e8 |
  2748.      --++       "-" e8 |
  2749.      --++       free_operator e8 !
  2750.      --++       e9
  2751.      --++
  2752.       local
  2753.      prefix_not: CALL_PREFIX_NOT;
  2754.      prefix_plus: CALL_PREFIX_PLUS;
  2755.      prefix_moins: CALL_PREFIX_MINUS;
  2756.      op: PREFIX_NAME;
  2757.      prefix_freeop: CALL_PREFIX_FREEOP;
  2758.      sp: POSITION;
  2759.       do
  2760.      if a_keyword(us_not) then
  2761.         !!sp.make(start_line,start_column);
  2762.         if a_e8 then
  2763.            !!prefix_not.make(sp,last_expression);
  2764.            last_expression := prefix_not;
  2765.            Result := true;
  2766.         else
  2767.            err_exp(sp,us_not);
  2768.         end;
  2769.      elseif skip1('+') then
  2770.         !!sp.make(start_line,start_column);
  2771.         if a_e8 then
  2772.            !!prefix_plus.make(sp,last_expression);
  2773.            last_expression := prefix_plus;
  2774.            Result := true;
  2775.         else
  2776.            err_exp(sp,"+ (prefix)");
  2777.         end;
  2778.      elseif skip1('-') then
  2779.         !!sp.make(start_line,start_column);
  2780.         if a_e8 then
  2781.            !!prefix_moins.make(sp,last_expression);
  2782.            last_expression := prefix_moins;
  2783.            Result := true;
  2784.         else
  2785.            err_exp(sp,"- (prefix)");
  2786.         end;
  2787.      elseif a_free_operator then
  2788.         op := tmp_name.to_prefix_name;
  2789.         if a_e8 then
  2790.            !!prefix_freeop.make(last_expression,op);
  2791.            last_expression := prefix_freeop;
  2792.            Result := true;
  2793.         else
  2794.            eh.append("Bad use of prefix operator. ");
  2795.            err_exp(op.start_position,op.to_string);
  2796.         end;
  2797.      else
  2798.         Result := a_e9;
  2799.      end;
  2800.       end;
  2801.    
  2802.    a_e9: BOOLEAN is
  2803.      --++ e9 -> e10 |
  2804.      --++       "old" e10 
  2805.      --++
  2806.       local
  2807.      e_old: E_OLD;
  2808.       do
  2809.      if a_keyword(fz_old) then
  2810.         if not in_ensure then
  2811.            error(pos(start_line,start_column),
  2812.            "Expression %"old%" can be used in ensure clause only.");
  2813.         end;
  2814.         if a_e10 then
  2815.            !!e_old.make(last_expression);
  2816.            last_expression := e_old;
  2817.            Result := true;
  2818.         else
  2819.            fcp("Expression expected after %"old%".");
  2820.         end;
  2821.      else
  2822.         Result := a_e10;
  2823.      end;
  2824.       end;
  2825.    
  2826.    a_e10: BOOLEAN is
  2827.      --++ e10 -> strip |
  2828.      --++       "(" expression ")" r10 |
  2829.      --++       manifest_constant |
  2830.      --++       "Result" r10 |
  2831.      --++       "Current" r10 |
  2832.      --++       "Void" r10 |
  2833.      --++       local_variable r10 |
  2834.      --++       argument r10 |
  2835.      --++       function_call r10 |
  2836.      --++
  2837.       do
  2838.      if a_strip then
  2839.         Result := true;
  2840.      elseif skip1('(') then
  2841.         Result := true;
  2842.         if a_expression then
  2843.            if skip1(')') then
  2844.           a_r10(false,last_expression,Void,Void);
  2845.            else
  2846.           fcp("')' expected in expression.")
  2847.            end;
  2848.         else
  2849.            fcp("Expression expected.")
  2850.         end;
  2851.      elseif a_manifest_constant then
  2852.         last_expression := last_manifest_constant;
  2853.         Result := true;
  2854.         if skip1unless2('.','.') then
  2855.            wcp("Added brackets for manifest constant before dot.");
  2856.            a_after_a_dot(false,last_expression);
  2857.         end;
  2858.      elseif a_identifier then
  2859.         Result := true;
  2860.         if a_result or else a_current or else a_void or else
  2861.            a_local_variable or else a_argument then
  2862.            a_r10(false,last_expression,Void,Void);
  2863.         else
  2864.            a_function_call;
  2865.         end; 
  2866.      end;
  2867.       end;
  2868.          
  2869.    a_external: ROUTINE is
  2870.      --++ external -> "XXX" external_name |
  2871.      --++             "YYY" external_name |
  2872.      --++             "..." external_name
  2873.      --++
  2874.       local
  2875.      l: NATIVE;
  2876.       do
  2877.      if cc /= '%"' then
  2878.         wcp(em19);
  2879.      else
  2880.         ok := skip1('%"');
  2881.      end;
  2882.      if a_keyword(fz_se) then
  2883.         !NATIVE_SMALL_EIFFEL!l;
  2884.      elseif a_keyword(fz_c_withcurrent) then
  2885.         !NATIVE_WITH_CURRENT!l;
  2886.      elseif a_keyword(fz_c_inlinewithcurrent) then
  2887.         !NATIVE_INLINE_WITH_CURRENT!l;
  2888.      elseif a_keyword(fz_c_withoutcurrent) then
  2889.         !NATIVE_WITHOUT_CURRENT!l;
  2890.      elseif a_keyword(fz_c_inlinewithoutcurrent) then
  2891.         !NATIVE_INLINE_WITHOUT_CURRENT!l;
  2892.      elseif a_keyword("CSE") then
  2893.         !NATIVE_SMALL_EIFFEL!l;
  2894.         wcpefnc("CSE",fz_se);
  2895.      elseif a_keyword("CWC") then
  2896.         !NATIVE_WITH_CURRENT!l;
  2897.         wcpefnc("CWC",fz_c_withcurrent);
  2898.      elseif a_keyword("ICWC") then
  2899.         !NATIVE_INLINE_WITH_CURRENT!l;
  2900.         wcpefnc("ICWC",fz_c_inlinewithcurrent);
  2901.      elseif a_keyword("C") then
  2902.         !NATIVE_WITHOUT_CURRENT!l;
  2903.      elseif a_keyword("IC") then
  2904.         !NATIVE_INLINE_WITHOUT_CURRENT!l;
  2905.         wcpefnc("IC",fz_c_inlinewithoutcurrent);
  2906.      elseif a_keyword(fz_jvm_invokestatic) then
  2907.         !NATIVE_JVM_INVOKESTATIC!l;
  2908.      elseif a_keyword(fz_jvm_invokevirtual) then
  2909.         !NATIVE_JVM_INVOKEVIRTUAL!l;
  2910.      else
  2911.         fcp("Unkown external specification. Currently supported %
  2912.             % keywords are : %"C_WithCurrent%", %"C_InlineWithCurrent%", %
  2913.         %%"C_WithoutCurrent%", %"C_InlineWithoutCurrent%" and %
  2914.             %%"SmallEiffel%".");
  2915.      end;
  2916.      if cc /= '%"' then
  2917.         wcp(em19);
  2918.      else
  2919.         ok := skip1('%"');
  2920.      end;
  2921.      Result := tmp_feature.to_external_routine(l,a_alias);
  2922.       end;
  2923.          
  2924.    a_alias: STRING is
  2925.      --++ external_name -> ["alias" manifest_string]
  2926.      --++
  2927.       do
  2928.      if a_keyword(fz_alias) then
  2929.         if a_manifest_string then
  2930.            Result := last_manifest_string.to_string;
  2931.         else
  2932.            fcp("Alias name of external expected.");
  2933.         end;
  2934.      end;
  2935.       end;
  2936.    
  2937.    a_feature_list: BOOLEAN is
  2938.      --++ feature_list -> {feature_name "," ...}
  2939.      --++
  2940.      --
  2941.      -- Gives true when list is not empty.
  2942.       local
  2943.      state: INTEGER;
  2944.      -- state 0 : nothing read.
  2945.      -- state 1 : feature name read.
  2946.      -- state 2 : separator read.
  2947.      -- state 3 : end.
  2948.       do
  2949.      from        
  2950.         last_feature_list := Void;
  2951.      until
  2952.         state >= 3
  2953.      loop
  2954.         inspect
  2955.            state
  2956.         when 0 then
  2957.            if a_feature_name then
  2958.           last_feature_list := <<last_feature_name>>;
  2959.           Result := true;
  2960.           state := 1;
  2961.            elseif cc = ',' then
  2962.           wcp(em7);
  2963.           ok := skip1(',');
  2964.            else
  2965.           state := 3
  2966.            end;
  2967.         when 1 then
  2968.            if cc = ',' then
  2969.           ok := skip1(',');
  2970.           state := 2;
  2971.            elseif a_feature_name then
  2972.           warning(last_feature_name.start_position,em5);
  2973.           last_feature_list.add_last(last_feature_name);
  2974.            else
  2975.           state := 3;
  2976.            end;
  2977.         when 2 then
  2978.            if a_feature_name then
  2979.           last_feature_list.add_last(last_feature_name);
  2980.           state := 1;
  2981.            elseif cc = ',' then
  2982.           wcp(em12);
  2983.           ok := skip1(',');
  2984.            else
  2985.           ecp(em2);
  2986.           state := 3;
  2987.            end;
  2988.         end;
  2989.      end;
  2990.       end;
  2991.    
  2992.    a_feature_name: BOOLEAN is
  2993.      --++ feature_name -> prefix |
  2994.      --++                 infix |
  2995.      --++                 simple_feature_name
  2996.      --++
  2997.       do
  2998.      if a_prefix then
  2999.         last_feature_name := last_prefix;
  3000.         Result := true;
  3001.      elseif a_infix then
  3002.         last_feature_name := last_infix;
  3003.         Result := true;
  3004.      elseif a_identifier then
  3005.         last_feature_name := tmp_name.to_simple_feature_name;
  3006.         Result := true;
  3007.      end;
  3008.       end;
  3009.  
  3010.    a_feature_clause is
  3011.      --++ feature_clause -> [clients] [comment] feature_declaration_list
  3012.      --++
  3013.       local
  3014.      feature_clause: FEATURE_CLAUSE;
  3015.      clients: CLIENT_LIST;
  3016.      comment: COMMENT;
  3017.       do   
  3018.      from
  3019.         clients := a_clients;
  3020.         comment := get_comments;
  3021.         faof.clear;
  3022.      until
  3023.         not a_feature_declaration
  3024.      loop
  3025.         ok := skip1(';');
  3026.         if last_feature_declaration /= Void then
  3027.            faof.add_last(last_feature_declaration);
  3028.            last_feature_declaration.set_header_comment(get_comments);
  3029.         end;
  3030.      end;
  3031.      if faof.upper >= 0 then
  3032.         !!feature_clause.make(clients,comment,faof.twin);
  3033.         last_base_class.add_feature_clause(feature_clause);
  3034.      elseif comment /= Void then
  3035.         !!feature_clause.make(clients,comment,Void);
  3036.         last_base_class.add_feature_clause(feature_clause);
  3037.      end;
  3038.      last_keyword := Void;
  3039.       end;
  3040.    
  3041.    a_feature_declaration: BOOLEAN is
  3042.      --++ feature_declaration -> {["frozen"] feature_name "," ...}+
  3043.      --++                        formal_arg_list
  3044.      --++                        [":" type] 
  3045.      --++                        ["is" "unique" | 
  3046.      --++                         "is" manifest_constant | 
  3047.      --++                         "is" routine]
  3048.      --++
  3049.       do   
  3050.      from
  3051.         tmp_feature.initialize;
  3052.         if a_keyword(fz_frozen) then
  3053.            if a_feature_name then
  3054.           Result := true;
  3055.           last_feature_name.set_is_frozen(true);
  3056.           tmp_feature.add_synonym(last_feature_name);
  3057.            else
  3058.           fcp(em2);
  3059.            end;
  3060.         elseif a_feature_name then
  3061.            Result := true;
  3062.            tmp_feature.add_synonym(last_feature_name);
  3063.         end;
  3064.      until
  3065.         not skip1(',')
  3066.      loop
  3067.         if a_keyword(fz_frozen) then
  3068.            if a_feature_name then
  3069.           last_feature_name.set_is_frozen(true);
  3070.           tmp_feature.add_synonym(last_feature_name);
  3071.            else
  3072.           fcp("Frozen feature name synonym expected.");
  3073.            end;
  3074.         elseif a_feature_name then
  3075.            tmp_feature.add_synonym(last_feature_name);
  3076.         else
  3077.            ecp("Synonym feature name expected.");
  3078.         end;
  3079.      end;
  3080.      if Result then
  3081.         a_formal_arg_list;
  3082.         function_type := Void;
  3083.         if skip1(':') then
  3084.            if a_type then
  3085.           function_type := last_type;
  3086.           tmp_feature.set_type(last_type);
  3087.            else
  3088.           fcp(em18);
  3089.            end;
  3090.         end;
  3091.         if a_keyword(fz_is) then
  3092.            if a_keyword(fz_unique) then
  3093.           last_feature_declaration := tmp_feature.to_cst_att_unique;
  3094.            elseif a_boolean_constant then
  3095.           last_feature_declaration := 
  3096.              tmp_feature.to_cst_att_boolean(last_boolean_constant);
  3097.            elseif a_character_constant then
  3098.           last_feature_declaration := 
  3099.              tmp_feature.to_cst_att_character(last_character_constant);
  3100.            elseif a_manifest_string then
  3101.           last_feature_declaration := 
  3102.              tmp_feature.to_cst_att_string(last_manifest_string);
  3103.            elseif a_bit_constant then
  3104.           last_feature_declaration := 
  3105.              tmp_feature.to_cst_att_bit(last_bit_constant);
  3106.            elseif a_real_constant then
  3107.           last_feature_declaration := 
  3108.              tmp_feature.to_cst_att_real(last_real_constant);
  3109.            elseif a_integer_constant then
  3110.           last_feature_declaration := 
  3111.              tmp_feature.to_cst_att_integer(last_integer_constant);
  3112.            else 
  3113.           last_feature_declaration := a_routine;
  3114.            end;
  3115.         else
  3116.            last_feature_declaration := tmp_feature.to_writable_attribute;
  3117.         end;
  3118.         function_type := Void;
  3119.         arguments := Void;
  3120.      end;
  3121.       end;
  3122.    
  3123.    a_formal_generic_list is
  3124.      --++ formal_generic_list -> ["[" {formal_generic "," ...} "]"]
  3125.      --++ formal_generic -> base_class_name ["->" class_type]
  3126.      --++
  3127.       local
  3128.      sp: POSITION;
  3129.      name: CLASS_NAME;
  3130.      constraint: TYPE;
  3131.      fga: FORMAL_GENERIC_ARG;
  3132.      list: ARRAY[FORMAL_GENERIC_ARG];
  3133.      state: INTEGER;
  3134.      -- state 0 : waiting for "[".
  3135.      -- state 1 : waiting for a base class `name'.
  3136.      -- state 2 : waiting for "->" or "," or "]".
  3137.      -- state 3 : waiting for "," or "]".
  3138.      -- state 4 : waiting for a `constraint' type.
  3139.      -- state 5 : end. 
  3140.      -- state 6 : error.
  3141.       do   
  3142.      from  
  3143.         formal_generic_list := Void;
  3144.      until
  3145.         state > 4 
  3146.      loop
  3147.         inspect 
  3148.            state
  3149.         when 0 then
  3150.            if skip1('%(') then
  3151.           !!sp.make(start_line,start_column);
  3152.           state := 1;
  3153.            else
  3154.           state := 5;
  3155.            end;
  3156.         when 1 then
  3157.            if a_base_class_name then
  3158.           name := last_class_name;
  3159.           state := 2;
  3160.            else
  3161.           state := 6;
  3162.            end;
  3163.         when 2 then
  3164.            if skip2('-','>') then
  3165.           state := 4;
  3166.            elseif cc = ',' or else cc = ']' then
  3167.           !!fga.make(name,constraint);
  3168.           name := Void;
  3169.           constraint := Void;
  3170.           if list = Void then
  3171.              list := <<fga>>;
  3172.           else
  3173.              list.add_last(fga);
  3174.           end;
  3175.           fga := Void;
  3176.           if skip1(',') then
  3177.              state := 1;
  3178.           else
  3179.              ok := skip1('%)');
  3180.              state := 5;
  3181.           end;
  3182.            else
  3183.           state := 6;
  3184.            end;
  3185.         when 3 then
  3186.            if cc = ',' or else cc = ']' then
  3187.           !!fga.make(name,constraint);
  3188.           name := Void;
  3189.           constraint := Void;
  3190.           if list = Void then
  3191.              list := <<fga>>;
  3192.           else
  3193.              list.add_last(fga);
  3194.           end;
  3195.           fga := Void;
  3196.           if skip1(',') then
  3197.              state := 1;
  3198.           else
  3199.              ok := skip1('%)');
  3200.              state := 5;
  3201.           end;
  3202.            else
  3203.           state := 6;
  3204.            end;
  3205.         else -- state = 4
  3206.            if a_class_type then
  3207.           constraint := last_class_type;
  3208.           state := 3;
  3209.            else
  3210.           fcp("Constraint Class name expected.");
  3211.           state := 6;
  3212.            end;
  3213.         end;
  3214.      end;
  3215.      if state = 6 then
  3216.         check
  3217.            nb_errors > 0;
  3218.         end;
  3219.      elseif sp /= Void and then list = Void then
  3220.         warning(sp,"Empty formal generic list (deleted).");
  3221.      elseif sp /= Void then
  3222.         check 
  3223.            not list.empty;
  3224.         end;
  3225.         !!formal_generic_list.make(sp,list);
  3226.         last_base_class.set_formal_generic_list(formal_generic_list);
  3227.      end;
  3228.       end;
  3229.    
  3230.    a_function_call is
  3231.      --++ function_call -> [actuals] r10 |
  3232.      --++                   ^
  3233.      --++
  3234.       local
  3235.         sfn: SIMPLE_FEATURE_NAME;
  3236.      e_current: E_CURRENT;
  3237.       do        
  3238.      sfn := tmp_name.to_simple_feature_name;
  3239.      !!e_current.make(sfn.start_position,false);
  3240.      a_r10(false,e_current,sfn,a_actuals);
  3241.       end;
  3242.    
  3243.    a_index_clause: BOOLEAN is
  3244.      --++ index_clause -> [identifier ":"] {index_value "," ...}+
  3245.      --++
  3246.       local
  3247.      index_clause: INDEX_CLAUSE;
  3248.       do
  3249.      if a_identifier then
  3250.         Result := true;
  3251.         if skip1(':') then
  3252.            !!index_clause.make(tmp_name.to_string);
  3253.            if a_index_value then
  3254.           index_clause.add_index_value(last_index_value);
  3255.            else
  3256.           fcp(em3);
  3257.            end;
  3258.         else
  3259.            !!index_clause.make(Void);
  3260.            index_clause.add_index_value(tmp_name.to_simple_feature_name);
  3261.         end;
  3262.      elseif a_manifest_constant then
  3263.         Result := true;
  3264.         !!index_clause.make(Void);
  3265.         index_clause.add_index_value(last_manifest_constant);
  3266.      end;
  3267.      if Result then
  3268.         from  
  3269.         until
  3270.            not skip1(',')
  3271.         loop
  3272.            if a_index_value then
  3273.           index_clause.add_index_value(last_index_value);
  3274.            else
  3275.           fcp(em3);
  3276.            end;
  3277.         end;
  3278.         last_base_class.add_index_clause(index_clause);
  3279.      end;
  3280.       end;
  3281.       
  3282.    a_index_list is
  3283.      --++ index_list -> {index_clause ";" ...}
  3284.      --++
  3285.       do
  3286.      from        
  3287.      until
  3288.         not a_index_clause
  3289.      loop
  3290.         ok := skip1(';');
  3291.      end;
  3292.       end;
  3293.    
  3294.    a_index_value: BOOLEAN is
  3295.      --++ index_value -> identifier | manifest_constant
  3296.      --++
  3297.       do
  3298.      if a_identifier then
  3299.         last_index_value := tmp_name.to_simple_feature_name;
  3300.         Result := true;
  3301.      elseif a_manifest_constant then
  3302.         last_index_value := last_manifest_constant;
  3303.         Result := true;
  3304.      end;
  3305.       end;
  3306.    
  3307.    a_indexing is
  3308.      --++ indexing -> "indexing" index_list
  3309.      --++
  3310.       do
  3311.      if a_keyword(fz_indexing) then
  3312.         a_index_list;
  3313.      end;
  3314.       end;
  3315.    
  3316.    a_infix: BOOLEAN is
  3317.      --++ infix -> "infix" "%"" binary "%""
  3318.      --++          "infix" "%"" free_operator "%""
  3319.      --++
  3320.       local
  3321.      sp: POSITION;
  3322.       do
  3323.      if a_keyword(fz_infix) then
  3324.         Result := true;
  3325.         !!sp.make(start_line,start_column);
  3326.         if cc = '%"' then
  3327.            next_char;
  3328.         else
  3329.            wcp("Character '%%%"' inserted after %"infix%".");
  3330.         end;
  3331.         if a_binary(sp) then 
  3332.            last_infix := last_binary;
  3333.         elseif a_free_operator then
  3334.            last_infix := tmp_name.to_infix_name(sp);
  3335.         else
  3336.            fcp("Infix operator name expected.");
  3337.         end;
  3338.         if not skip1('%"') then
  3339.            wcp("Character '%%%"' inserted.");
  3340.         end;
  3341.      end;
  3342.       end;
  3343.       
  3344.    a_inspect: BOOLEAN is
  3345.      --++ inspect -> "inspect" expression 
  3346.      --++            {when_part ...}
  3347.      --++            ["else" compound]
  3348.      --++            "end"
  3349.      --++
  3350.       local
  3351.      sp, spec: POSITION;
  3352.      i: E_INSPECT;
  3353.      ec: COMPOUND;
  3354.       do
  3355.      if a_keyword(fz_inspect) then
  3356.         Result := true;
  3357.         !!sp.make(start_line,start_column);
  3358.         if a_expression then
  3359.            last_expression := last_expression.add_comment(get_comments);
  3360.         else
  3361.            fcp("Expression expected (%"inspect ... %").");
  3362.         end;
  3363.         from  
  3364.            !!i.make(sp,last_expression);
  3365.         until
  3366.            not a_when_part(i)
  3367.         loop
  3368.         end;
  3369.         if a_keyword(fz_else) then
  3370.            !!spec.make(start_line,start_column);
  3371.            ec := a_compound2("else of inspect",fz_end);
  3372.            i.set_else_compound(spec,ec);
  3373.         elseif not a_keyword(fz_end) then
  3374.            wcp("Added %"end%" for inspect instruction.");
  3375.         end;     
  3376.         last_instruction := i;
  3377.      end;
  3378.       end;
  3379.    
  3380.    a_instruction: BOOLEAN is
  3381.      --++ instruction -> check | debug | conditionnal | retry |
  3382.      --++                inspect | loop | creation | assignment_or_call   
  3383.      --++ 
  3384.       do   
  3385.      Result := a_check or else a_debug or else a_conditional or else
  3386.                    a_retry or else a_inspect or else a_loop or else 
  3387.            a_creation or else a_assignment_or_call;
  3388.       end;
  3389.    
  3390.    a_integer_constant: BOOLEAN is
  3391.      --++ integer_constant -> ["+" | "-"] integer
  3392.      --++
  3393.       local
  3394.      l, c: INTEGER;
  3395.       do
  3396.      if skip1('+') then
  3397.         l := start_line;
  3398.         c := start_column;
  3399.         if a_integer then
  3400.            last_integer_constant.start_position.set_line_column(l,c);
  3401.            Result := true;
  3402.         else
  3403.            fcp(fz_iinaiv);
  3404.         end;
  3405.      elseif skip1('-') then
  3406.         l := start_line;
  3407.         c := start_column;
  3408.         if a_integer then
  3409.            last_integer_constant.start_position.set_line_column(l,c);
  3410.            last_integer_constant.unary_minus;
  3411.            Result := true;
  3412.         else
  3413.            fcp(fz_iinaiv);
  3414.         end;
  3415.      else
  3416.         Result := a_integer;
  3417.      end;
  3418.       end; 
  3419.    
  3420.    a_loop: BOOLEAN is
  3421.      --++ loop -> "from" compound 
  3422.      --++         ["invariant"] assertion
  3423.      --++         ["variant" [identifier ":"] expression]
  3424.      --++         "until" expression
  3425.      --++         "loop" compound 
  3426.      --++         "end"
  3427.      --++
  3428.       local
  3429.      l1, c1, l2, c2: INTEGER;
  3430.      e_loop: E_LOOP;
  3431.      i: COMPOUND;
  3432.      ic: LOOP_INVARIANT; 
  3433.      vc: LOOP_VARIANT;
  3434.      ue: EXPRESSION;
  3435.      lb: COMPOUND;
  3436.      hc: COMMENT;
  3437.      al: ARRAY[ASSERTION];
  3438.       do
  3439.      if a_keyword(fz_from) then
  3440.         Result := true;
  3441.         l1 := start_line;
  3442.         c1 := start_column;
  3443.         i := a_compound1("from part of a loop");
  3444.         if a_keyword(fz_invariant) then
  3445.            l2 := start_line;
  3446.            c2 := start_column;
  3447.            hc := get_comments;
  3448.            al := a_assertion;
  3449.            if hc /= Void or else al /= Void then
  3450.           !!ic.make(pos(l2,c2),hc,al);
  3451.            end;
  3452.         end;
  3453.         if a_keyword(fz_variant) then
  3454.            if a_tag_mark and then a_expression then
  3455.           !LOOP_VARIANT_2!vc.make(last_tag_mark,last_expression,
  3456.                                   get_comments);
  3457.            elseif a_expression then 
  3458.           !LOOP_VARIANT_1!vc.make(last_expression,get_comments);
  3459.            else
  3460.           wcp("Variant (INTEGER) Expression Expected.");
  3461.            end;
  3462.         end;
  3463.         if a_keyword(fz_until) then
  3464.            if a_expression then
  3465.           ue := last_expression.add_comment(get_comments);
  3466.            else
  3467.           fcp("Boolean expression expected (until).");
  3468.           ue := last_expression;
  3469.            end;
  3470.         else
  3471.            fcp("Keyword %"until%" expected (in a loop).");
  3472.            ue := last_expression;
  3473.         end;
  3474.         if cc = ';' then
  3475.            wcp(fz_desc);
  3476.            ok := skip1(';');
  3477.         end;
  3478.         if not a_keyword(fz_loop) then
  3479.            wcp("Keyword %"loop%" expected (in a loop).");
  3480.         end;
  3481.         lb := a_compound2("loop body",fz_end);
  3482.         !!e_loop.make(pos(l1,c1),i,ic,vc,ue,lb);
  3483.         last_instruction := e_loop;
  3484.      end;
  3485.       end; 
  3486.    
  3487.    a_manifest_constant: BOOLEAN is
  3488.      --++ manifest_constant -> boolean_constant | character_constant |
  3489.      --++                      real_constant | integer_constant |
  3490.      --++                      manifest_string | bit_constant
  3491.      --++
  3492.       do
  3493.      if a_boolean_constant then
  3494.         last_manifest_constant := last_boolean_constant;
  3495.         Result := true;
  3496.      elseif a_character_constant then
  3497.         last_manifest_constant := last_character_constant;
  3498.         Result := true;
  3499.      elseif a_manifest_string then
  3500.         last_manifest_constant := last_manifest_string;
  3501.         Result := true;
  3502.      elseif a_bit_constant then
  3503.         last_manifest_constant := last_bit_constant;
  3504.         Result := true;
  3505.      elseif a_real_constant then
  3506.         last_manifest_constant := last_real_constant;
  3507.         Result := true;
  3508.      elseif a_integer_constant then
  3509.         last_manifest_constant := last_integer_constant;
  3510.         Result := true;
  3511.      end;
  3512.       end;
  3513.    
  3514.    a_new_export_list is
  3515.      --++ new_export_list -> ["export" {new_export_item ";" ...}]
  3516.      --++ new_export_item -> clients "all" |
  3517.      --++                    clients feature_list
  3518.      --++
  3519.       local
  3520.      export_list: EXPORT_LIST;
  3521.      sp: POSITION;
  3522.      clients: CLIENT_LIST;
  3523.      items: ARRAY[EXPORT_ITEM];
  3524.      new_export_item: EXPORT_ITEM;
  3525.      state: INTEGER;
  3526.      -- state 0 : waiting for a `clients'.
  3527.      -- state 1 : `clients' read.
  3528.      -- state 2 : waiting ";" before next one.
  3529.      -- state 3 : error.
  3530.      -- state 4 : end.
  3531.      -- 
  3532.       do
  3533.      if a_keyword(fz_export) then
  3534.         from
  3535.            !!sp.make(start_line,start_column);
  3536.         until
  3537.            state > 3
  3538.         loop
  3539.            inspect 
  3540.           state
  3541.            when 0 then
  3542.           if cc = '{' then
  3543.              clients := a_clients;
  3544.              state := 1;
  3545.           elseif cc = ';' then
  3546.              wcp(fz_desc);
  3547.              ok := skip1(';');
  3548.           else
  3549.              if items /= Void then
  3550.             !!export_list.make(sp,items);
  3551.             last_parent.set_export(export_list);
  3552.              end;
  3553.              state := 4;
  3554.           end;
  3555.            when 1 then
  3556.           if a_keyword(fz_all) then
  3557.              !!new_export_item.make_all(clients);
  3558.              if items = Void then
  3559.             items := <<new_export_item>>;
  3560.              else
  3561.             items.add_last(new_export_item);
  3562.              end;
  3563.              state := 2;
  3564.           else
  3565.              if a_feature_list then
  3566.             !!new_export_item.make(clients,last_feature_list);
  3567.             if items = Void then
  3568.                items := <<new_export_item>>;
  3569.             else
  3570.                items.add_last(new_export_item);
  3571.             end;
  3572.             state := 2;
  3573.              else
  3574.             state := 3;
  3575.              end;
  3576.           end;
  3577.            when 2 then
  3578.           if skip1(';') then
  3579.              state := 0;
  3580.           elseif cc = '{' then
  3581.              wcp(em6);
  3582.              state := 0;
  3583.           else
  3584.              if items /= Void then
  3585.             !!export_list.make(sp,items);
  3586.             last_parent.set_export(export_list);
  3587.              end;
  3588.              state := 4;
  3589.           end;
  3590.            else -- state = 3
  3591.           fcp(em11);
  3592.           state := 4;
  3593.            end;
  3594.         end;
  3595.      end;
  3596.       end;
  3597.    
  3598.    a_parent_list(sp: POSITION; hc: COMMENT) is
  3599.      --++ parent_list -> {parent ";" ...}
  3600.      --++
  3601.       local
  3602.      list: ARRAY[PARENT];
  3603.       do 
  3604.      from        
  3605.      until
  3606.         not a_parent
  3607.      loop
  3608.         if list = Void then
  3609.            list := <<last_parent>>;
  3610.         else
  3611.            list.add_last(last_parent);
  3612.         end;
  3613.         ok := skip1(';');
  3614.         last_parent.set_comment(get_comments);
  3615.      end;
  3616.      if hc /= Void or else list /= Void then
  3617.         if list = Void then
  3618.            if last_base_class.heading_comment2 = Void then
  3619.           last_base_class.set_heading_comment2(hc);
  3620.            else
  3621.           last_base_class.heading_comment2.append(hc);
  3622.            end;
  3623.         else
  3624.            last_base_class.set_parent_list(sp,hc,list);
  3625.         end;
  3626.      end;
  3627.       end;
  3628.    
  3629.    a_parent: BOOLEAN is
  3630.      --++ parent -> class_type
  3631.      --++           ["rename" rename_list]
  3632.      --++           new_export_list
  3633.      --++           ["undefine" undefine_list]
  3634.      --++           ["redefine" redefine_list]
  3635.      --++           ["select" select_list]
  3636.      --++           ["end"]
  3637.      --++
  3638.       do
  3639.      if a_class_type then
  3640.         Result := true;
  3641.         !!last_parent.make(last_class_type);
  3642.         if a_keyword(fz_rename) then
  3643.            a_rename_list;
  3644.            if cc = ';' then
  3645.           wcp("Unexpected %";%" to end rename list.");
  3646.           ok := skip1(';');
  3647.            end;
  3648.         end;
  3649.         a_new_export_list;
  3650.         if a_keyword(fz_undefine) then
  3651.            a_undefine_list;
  3652.         end;
  3653.         if a_keyword(fz_redefine) then
  3654.            a_redefine_list;
  3655.         end;
  3656.         if a_keyword(fz_select) then
  3657.            a_select_list;
  3658.         end;
  3659.         if a_keyword(fz_rename) or else 
  3660.            a_keyword(fz_export) or else 
  3661.            a_keyword(fz_undefine) or else 
  3662.            a_keyword(fz_redefine) or else  
  3663.            a_keyword(fz_select) then
  3664.            eh.add_position(pos(start_line,start_column));
  3665.            fatal_error("Inheritance option not at a good place. %
  3666.                        %The good order is: %"rename... export... %
  3667.                %undefine... redefine... select...%".",);
  3668.         end;
  3669.         ok := a_keyword(fz_end);
  3670.      end;
  3671.       end;
  3672.    
  3673.    a_prefix: BOOLEAN is
  3674.      --++ prefix -> "prefix" "%"" unary "%""
  3675.      --++           "prefix" "%"" free_operator "%""
  3676.      --++
  3677.       do
  3678.      if a_keyword(fz_prefix) then
  3679.         Result := true;
  3680.         if cc = '%"' then
  3681.            next_char;
  3682.         else
  3683.            wcp("Character '%%%"' inserted after %"prefix%".");
  3684.         end;
  3685.         if a_unary then
  3686.         elseif a_free_operator then
  3687.            last_prefix := tmp_name.to_prefix_name;
  3688.         else
  3689.            fcp("Prefix operator name expected.");
  3690.         end;
  3691.         if not skip1('%"') then
  3692.            wcp("Character '%%%"' inserted.");
  3693.         end;
  3694.      end;
  3695.       end;
  3696.       
  3697.    a_procedure_call is
  3698.      --++ procedure_call -> [actuals] r10 |
  3699.      --++                   ^
  3700.      --++
  3701.       local
  3702.         sfn: SIMPLE_FEATURE_NAME;
  3703.      e_current: E_CURRENT;
  3704.       do        
  3705.      sfn := tmp_name.to_simple_feature_name;
  3706.      !!e_current.make(sfn.start_position,false);
  3707.      a_r10(true,e_current,sfn,a_actuals);
  3708.       end;
  3709.    
  3710.    a_real_constant: BOOLEAN is
  3711.      --++ real_constant -> ["+" | "-"] real
  3712.      --++
  3713.       local
  3714.      l, c: INTEGER;
  3715.       do
  3716.      l := line;
  3717.      c := column;
  3718.      if skip1('+') then
  3719.         if a_real then
  3720.            last_real_constant.start_position.set_line_column(l,c);
  3721.            Result := true;
  3722.         else
  3723.            go_back_at(l,c);
  3724.         end;
  3725.      elseif skip1('-') then
  3726.         if a_real then
  3727.            last_real_constant.start_position.set_line_column(l,c);
  3728.            last_real_constant.unary_minus;
  3729.            Result := true;
  3730.         else
  3731.            go_back_at(l,c);
  3732.         end;
  3733.      elseif a_real then
  3734.         Result := true;
  3735.      end;
  3736.       end;
  3737.    
  3738.    a_redefine_list is
  3739.      --++ redefine_list -> feature_list
  3740.       do
  3741.      if a_feature_list then
  3742.         last_parent.set_redefine(last_feature_list)
  3743.      end;
  3744.       end;
  3745.    
  3746.    a_rename_list is
  3747.      --++ rename_list -> {rename_pair "," ...}
  3748.      --++
  3749.       do
  3750.      from
  3751.      until
  3752.         not a_rename_pair
  3753.      loop
  3754.         ok := skip1(',');
  3755.      end;
  3756.       end;
  3757.    
  3758.    a_rename_pair: BOOLEAN is
  3759.      --++ rename_pair -> identifier "as" identifier
  3760.      --++
  3761.       local
  3762.      name1: FEATURE_NAME;
  3763.      rename_pair: RENAME_PAIR;
  3764.       do
  3765.      if a_feature_name then
  3766.         name1 := last_feature_name;
  3767.         if a_keyword(fz_as) then
  3768.            if a_feature_name then
  3769.           Result := true;
  3770.           !!rename_pair.make(name1,last_feature_name);
  3771.           last_parent.add_rename(rename_pair);
  3772.            else
  3773.           fcp("Second identifier of a %"rename%" pair expected.");
  3774.            end;
  3775.         else
  3776.            go_back(name1.start_position);
  3777.         end;           
  3778.      end;
  3779.       end;
  3780.    
  3781.    a_routine: ROUTINE is
  3782.      --++ routine -> ["obsolete" manifest_string]
  3783.      --++            ["require" ["else"] assertion]
  3784.      --++            ["local" entity_declaration_list]
  3785.      --++            routine_body
  3786.      --++            ["ensure" ["then"] assertion]
  3787.      --++            ["rescue" compound]
  3788.      --++            "end"
  3789.      --++
  3790.       local
  3791.      sp: POSITION;
  3792.      hc: COMMENT;
  3793.      al: ARRAY[ASSERTION];
  3794.      ea: E_ENSURE;
  3795.      
  3796.       do
  3797.      if a_keyword(fz_obsolete) then
  3798.         if a_manifest_string then
  3799.            tmp_feature.set_obsolete_mark(last_manifest_string);
  3800.         else
  3801.            fcp("Obsolete manifest string expected.");
  3802.         end;
  3803.      end;
  3804.      tmp_feature.set_header_comment(get_comments);
  3805.      if a_keyword(fz_require) then
  3806.         !!sp.make(start_line,start_column);
  3807.         if a_keyword(fz_else) then
  3808.            hc := get_comments;
  3809.            tmp_feature.set_require_else(sp,hc,a_assertion);
  3810.         else
  3811.            hc := get_comments;
  3812.            tmp_feature.set_require(sp,hc,a_assertion);
  3813.         end;
  3814.      end;
  3815.      if a_keyword(fz_local) then
  3816.         a_local_var_list(pos(start_line,start_column));
  3817.      end;
  3818.      Result := a_routine_body; 
  3819.      if a_keyword(fz_ensure) then
  3820.         !!sp.make(start_line,start_column);
  3821.         in_ensure := true;
  3822.         if a_keyword(fz_then) then
  3823.            hc := get_comments;
  3824.            al := a_assertion;
  3825.            if hc /= Void or else al /= Void then
  3826.           !!ea.make(sp,hc,al);
  3827.           ea.set_ensure_then;
  3828.            end;
  3829.            Result.set_ensure_assertion(ea);
  3830.         else
  3831.            hc := get_comments;
  3832.            al := a_assertion;
  3833.            if hc /= Void or else al /= Void then
  3834.           !!ea.make(sp,hc,al);
  3835.            end;
  3836.            Result.set_ensure_assertion(ea);
  3837.         end;
  3838.         in_ensure := false;
  3839.      end;
  3840.      if a_keyword(fz_rescue) then
  3841.         in_rescue := true;
  3842.         Result.set_rescue_compound(a_compound2(fz_rescue,fz_end));
  3843.         in_rescue := false;
  3844.      else
  3845.         if not a_keyword(fz_end) then
  3846.            wcp("A routine must be ended with %"end%".");
  3847.         end;
  3848.      end; 
  3849.      local_vars := Void;
  3850.       end;
  3851.    
  3852.    a_routine_body: ROUTINE is
  3853.      --++ routine_body -> "deferred" |
  3854.      --++                 "external" external |
  3855.      --++                 "do" compound |
  3856.      --++                 "once" compound
  3857.      --++
  3858.       do   
  3859.      if a_keyword(fz_deferred) then
  3860.         last_base_class.set_is_deferred;
  3861.         Result := tmp_feature.to_deferred_routine;
  3862.      elseif a_keyword(fz_external) then
  3863.         Result := a_external;
  3864.      elseif a_keyword(fz_do) then
  3865.         tmp_feature.set_routine_body(a_compound1("routine body"));
  3866.         Result := tmp_feature.to_procedure_or_function;
  3867.      elseif a_keyword(fz_once) then
  3868.         tmp_feature.set_routine_body(a_compound1("once routine body"));
  3869.         Result := tmp_feature.to_once_routine;
  3870.      else
  3871.         fcp("Routine body expected.");
  3872.      end;
  3873.       end;
  3874.    
  3875.    a_r1(left_part: like last_expression) is
  3876.      --++ r1 -> "implies" e1 r1 |
  3877.      --++       ^
  3878.      --++
  3879.       local
  3880.      infix_implies: CALL_INFIX_IMPLIES;
  3881.      sp: POSITION;
  3882.       do
  3883.      if a_keyword(us_implies) then
  3884.         !!sp.make(start_line,start_column);
  3885.         if a_e1 then
  3886.            !!infix_implies.make(left_part,sp,last_expression);
  3887.            a_r1(infix_implies);
  3888.         else
  3889.            error(sp,"Expression expected after 'implies'.");
  3890.         end;
  3891.      else
  3892.         last_expression := left_part;
  3893.      end;
  3894.       end;
  3895.    
  3896.    a_r2(left_part: like last_expression) is
  3897.      --++ r2 -> "or else" e2 r2 |
  3898.      --++       "or" e2 r2 |
  3899.      --++       "xor" e2 r2 |
  3900.      --++       ^
  3901.      --++
  3902.       local
  3903.      infix_or_else: CALL_INFIX_OR_ELSE;
  3904.      infix_or: CALL_INFIX_OR;
  3905.      infix_xor: CALL_INFIX_XOR;
  3906.      sp: POSITION;
  3907.       do
  3908.      if a_keyword(us_or) then
  3909.         !!sp.make(start_line,start_column);
  3910.         if a_keyword(fz_else) then
  3911.            if a_e2 then
  3912.           !!infix_or_else.make(left_part,sp,last_expression);
  3913.           a_r2(infix_or_else);
  3914.            else
  3915.           err_exp(sp,us_or_else); 
  3916.            end;
  3917.         else
  3918.            if a_e2 then
  3919.           !!infix_or.make(left_part,sp,last_expression);
  3920.           a_r2(infix_or);
  3921.            else
  3922.           err_exp(sp,us_or); 
  3923.            end;
  3924.         end;
  3925.      elseif a_keyword(us_xor) then
  3926.         !!sp.make(start_line,start_column);
  3927.         if a_e2 then
  3928.            !!infix_xor.make(left_part,sp,last_expression);
  3929.            a_r2(infix_xor);
  3930.         else
  3931.            err_exp(sp,us_xor); 
  3932.         end;
  3933.      else
  3934.         last_expression := left_part;
  3935.      end;
  3936.       end;
  3937.    
  3938.    a_r3(left_part: like last_expression) is
  3939.      --++ r3 -> "and then" e3 r3 |
  3940.      --++       "and" e3 r3 |
  3941.      --++       ^
  3942.      --++
  3943.       local
  3944.      infix_and_then: CALL_INFIX_AND_THEN;
  3945.      infix_and: CALL_INFIX_AND;
  3946.      sp: POSITION;
  3947.       do
  3948.      if a_keyword(us_and) then
  3949.         !!sp.make(start_line,start_column);
  3950.         if a_keyword(fz_then) then
  3951.            if a_e3 then
  3952.           !!infix_and_then.make(left_part,sp,last_expression);
  3953.           a_r3(infix_and_then);
  3954.            else
  3955.           err_exp(sp,us_and_then); 
  3956.            end;
  3957.         else
  3958.            if a_e3 then
  3959.           !!infix_and.make(left_part,sp,last_expression);
  3960.           a_r3(infix_and);
  3961.            else
  3962.           err_exp(sp,us_and); 
  3963.            end;
  3964.         end;
  3965.      else
  3966.         last_expression := left_part;
  3967.      end;
  3968.       end;
  3969.    
  3970.    a_r4(left_part: like last_expression) is
  3971.      --++ r4 -> "=" e4 r4 |
  3972.      --++       "/=" e4 r4 |
  3973.      --++       "<=" e4 r4 |
  3974.      --++       "<" e4 r4 |
  3975.      --++       ">=" e4 r4 |
  3976.      --++       ">" e4 r4 |
  3977.      --++       ^
  3978.      --++
  3979.       local
  3980.      infix_eq: CALL_INFIX_EQ;
  3981.      infix_neq: CALL_INFIX_NEQ;
  3982.      infix_le: CALL_INFIX_LE;
  3983.      infix_lt: CALL_INFIX_LT;
  3984.      infix_ge: CALL_INFIX_GE;
  3985.      infix_gt: CALL_INFIX_GT;
  3986.      sp: POSITION;
  3987.       do
  3988.      if skip1('=') then
  3989.         !!sp.make(start_line,start_column);
  3990.         if a_e4 then
  3991.            !!infix_eq.make(left_part,sp,last_expression);
  3992.            a_r4(infix_eq);
  3993.         else
  3994.            err_exp(sp,us_eq);
  3995.         end;
  3996.      elseif skip2('/','=') then
  3997.         !!sp.make(start_line,start_column);
  3998.         if a_e4 then
  3999.            !!infix_neq.make(left_part,sp,last_expression);
  4000.            a_r4(infix_neq);
  4001.         else
  4002.            err_exp(sp,us_neq);
  4003.         end;
  4004.      elseif skip2('<','=') then
  4005.         !!sp.make(start_line,start_column);
  4006.         if a_e4 then
  4007.            !!infix_le.make(left_part,sp,last_expression);
  4008.            a_r4(infix_le);
  4009.         else
  4010.            err_exp(sp,us_le);
  4011.         end;
  4012.      elseif skip2('>','=') then
  4013.         !!sp.make(start_line,start_column);
  4014.         if a_e4 then
  4015.            !!infix_ge.make(left_part,sp,last_expression);
  4016.            a_r4(infix_ge);
  4017.         else
  4018.            err_exp(sp,us_ge);
  4019.         end;
  4020.      elseif skip1('<') then
  4021.         !!sp.make(start_line,start_column);
  4022.         if a_e4 then
  4023.            !!infix_lt.make(left_part,sp,last_expression);
  4024.            a_r4(infix_lt);
  4025.         else
  4026.            err_exp(sp,us_lt);
  4027.         end;
  4028.      elseif skip1unless2('>','>') then 
  4029.         !!sp.make(start_line,start_column);
  4030.         if a_e4 then
  4031.            !!infix_gt.make(left_part,sp,last_expression);
  4032.            a_r4(infix_gt);
  4033.         else
  4034.            err_exp(sp,us_gt);
  4035.         end;
  4036.      else
  4037.         last_expression := left_part;
  4038.      end;
  4039.       end;
  4040.    
  4041.    a_r5(left_part: like last_expression) is
  4042.      --++ r5 -> "+" e5 r5 |
  4043.      --++       "-" e5 r5 |
  4044.      --++       ^
  4045.      --++
  4046.       local
  4047.      infix_plus: CALL_INFIX_PLUS;
  4048.      infix_minus: CALL_INFIX_MINUS;
  4049.      sp: POSITION;
  4050.       do
  4051.      if skip1('+') then
  4052.         !!sp.make(start_line,start_column);
  4053.         if a_e5 then
  4054.            !!infix_plus.make(left_part,sp,last_expression);
  4055.            a_r5(infix_plus);
  4056.         else
  4057.            err_exp(sp,us_plus); 
  4058.         end;
  4059.      elseif skip1('-') then
  4060.         !!sp.make(start_line,start_column);
  4061.         if a_e5 then
  4062.            !!infix_minus.make(left_part,sp,last_expression);
  4063.            a_r5(infix_minus);
  4064.         else
  4065.            err_exp(sp,us_minus); 
  4066.         end;
  4067.      else
  4068.         last_expression := left_part;
  4069.      end;
  4070.       end;
  4071.    
  4072.    a_r6(left_part: like last_expression) is
  4073.      --++ r6 -> "*" e6 r6 |
  4074.      --++       "//" e6 r6 |
  4075.      --++       "\\" e6 r6 |
  4076.      --++       "/" e6 r6 |
  4077.      --++       ^
  4078.      --++
  4079.       local
  4080.      infix_times: CALL_INFIX_TIMES;
  4081.      infix_int_div: CALL_INFIX_INT_DIV;
  4082.      infix_int_rem: CALL_INFIX_INT_REM;
  4083.      infix_div: CALL_INFIX_DIV;
  4084.      sp: POSITION;
  4085.       do
  4086.      if skip1('*') then
  4087.         !!sp.make(start_line,start_column);
  4088.         if a_e6 then
  4089.            !!infix_times.make(left_part,sp,last_expression);
  4090.            a_r6(infix_times);
  4091.         else
  4092.            err_exp(sp,us_muls); 
  4093.         end;
  4094.      elseif skip2('/','/') then
  4095.         !!sp.make(start_line,start_column);
  4096.         if a_e6 then
  4097.            !!infix_int_div.make(left_part,sp,last_expression);
  4098.            a_r6(infix_int_div);
  4099.         else
  4100.            err_exp(sp,"//"); 
  4101.         end;
  4102.      elseif skip2('\','\') then
  4103.         !!sp.make(start_line,start_column);
  4104.         if a_e6 then
  4105.            !!infix_int_rem.make(left_part,sp,last_expression);
  4106.            a_r6(infix_int_rem);
  4107.         else
  4108.            err_exp(sp,"\\"); 
  4109.         end;
  4110.      elseif skip1unless2('/','=') then 
  4111.         !!sp.make(start_line,start_column);
  4112.         if a_e6 then
  4113.            !!infix_div.make(left_part,sp,last_expression);
  4114.            a_r6(infix_div);
  4115.         else
  4116.            err_exp(sp,us_slash); 
  4117.         end;
  4118.      else
  4119.         last_expression := left_part;
  4120.      end;
  4121.       end;
  4122.    
  4123.    a_r7(left_part: like last_expression) is
  4124.      --++ r7 -> "^" e7 r7 |
  4125.      --++       ^
  4126.      --++
  4127.       local
  4128.      infix_power: CALL_INFIX_POWER;
  4129.      sp: POSITION;
  4130.       do
  4131.      if skip1('^') then
  4132.         !!sp.make(start_line,start_column);
  4133.         if a_e7 then
  4134.            !!infix_power.make(left_part,sp,last_expression);
  4135.            a_r7(infix_power);
  4136.         else
  4137.            err_exp(sp,"^"); 
  4138.         end;
  4139.      else
  4140.         last_expression := left_part;
  4141.      end;
  4142.       end;
  4143.    
  4144.    a_r8(left_part: like last_expression) is
  4145.      --++ r8 -> free_operator e8 r8 |
  4146.      --++       ^
  4147.      --++
  4148.       local
  4149.      infix_name: INFIX_NAME;
  4150.      infix_freeop: CALL_INFIX_FREEOP;
  4151.       do
  4152.      if a_free_operator then
  4153.         infix_name := tmp_name.to_infix_name_use;
  4154.         if a_e8 then
  4155.            !!infix_freeop.make(left_part,infix_name,last_expression);
  4156.            a_r8(infix_freeop);
  4157.         else
  4158.            err_exp(infix_name.start_position,infix_name.to_string); 
  4159.         end;
  4160.      else
  4161.         last_expression := left_part;
  4162.      end;
  4163.       end;
  4164.    
  4165.    a_r10(do_instruction: BOOLEAN; t: EXPRESSION; fn: FEATURE_NAME; 
  4166.          eal: EFFECTIVE_ARG_LIST) is
  4167.      --++ r10 -> "." after_a_dot |
  4168.      --++        ^ 
  4169.      --++
  4170.       do
  4171.      if skip1unless2('.','.') then
  4172.         a_after_a_dot(do_instruction,to_call(t,fn,eal));
  4173.      else
  4174.         if do_instruction then
  4175.            last_instruction := to_proc_call(t,fn,eal);
  4176.            last_expression := Void;
  4177.         else
  4178.            last_expression := to_call(t,fn,eal);
  4179.            last_instruction := Void;
  4180.         end;
  4181.      end;
  4182.       end;
  4183.    
  4184.    a_select_list is
  4185.      --++ select_list -> feature_list
  4186.      --++
  4187.       do
  4188.      if a_feature_list then
  4189.         last_parent.set_select(last_feature_list);
  4190.      end;
  4191.       end;
  4192.    
  4193.    a_strip: BOOLEAN is
  4194.      --++ a_strip -> "strip" "(" {identifier "," ...} ")"
  4195.       local
  4196.      sp: POSITION;
  4197.       do
  4198.      if a_keyword(fz_strip) then
  4199.         !!sp.make(start_line,start_column);
  4200.         if skip1('(') then
  4201.            ok := a_feature_list; 
  4202.            !E_STRIP!last_expression.make(sp,last_feature_list);
  4203.            if not skip1(')') then
  4204.           fcp("')' expected to end a strip expression.");
  4205.            end;
  4206.            Result := true;
  4207.         else
  4208.            fcp("'(' expected to begin a strip list.");
  4209.         end;
  4210.      end;
  4211.       end;
  4212.    
  4213.    a_tag_mark: BOOLEAN is
  4214.      --++ tag_mark -> identifier ":"
  4215.      --++
  4216.       do
  4217.      if a_identifier then
  4218.         if skip1unless2(':','=') then
  4219.            Result := true;
  4220.            last_tag_mark := tmp_name.to_tag_name;
  4221.         else
  4222.            last_tag_mark := Void;
  4223.            go_back_at(tmp_name.li,tmp_name.co);
  4224.         end;
  4225.      else
  4226.         last_tag_mark := Void;
  4227.      end;
  4228.       end;
  4229.    
  4230.    a_then_part_list(ifthenelse: IFTHENELSE) is
  4231.      --++ then_part_list -> {then_part "elseif"}+
  4232.      --++
  4233.       do
  4234.      from
  4235.         if not a_then_part(ifthenelse) then
  4236.            fcp("In %"if ... then ...%".");
  4237.         end;
  4238.      until
  4239.         not a_keyword(fz_elseif)
  4240.      loop
  4241.         if not a_then_part(ifthenelse) then
  4242.            fcp("In %"elseif ... then ...%".");
  4243.         end;
  4244.      end;
  4245.       end;
  4246.    
  4247.    a_then_part(ifthenelse: IFTHENELSE): BOOLEAN is
  4248.      --++ then_part -> expression "then"
  4249.      --++
  4250.       local
  4251.      expression: EXPRESSION;
  4252.       do
  4253.      if a_expression then
  4254.         Result := true;
  4255.         expression := last_expression.add_comment(get_comments);
  4256.         if not a_keyword(fz_then) then
  4257.            wcp("Added %"then%".");
  4258.         end;
  4259.         ifthenelse.add_if_then(expression,a_compound1("then part"));
  4260.      end;
  4261.       end;
  4262.    
  4263.    a_top_level_instruction: GLOBALS is 
  4264.      -- For construction allowed on top-level of the interpretor.
  4265.      -- top_level_instruction -> compound | manifest_constant
  4266.      --
  4267.       do
  4268.      -- not_yet_implemented;
  4269.       end;
  4270.    
  4271.    a_type: BOOLEAN is
  4272.      --++ type -> "like" <anchor> | "expanded" class_type | BIT <constant>
  4273.      --++         type_formal_generic | class_type
  4274.      --++
  4275.       local 
  4276.      sp: POSITION;
  4277.      argument_name2: ARGUMENT_NAME2;
  4278.       do
  4279.      Result := true;
  4280.      if a_keyword(fz_like) then
  4281.         !!sp.make(start_line,start_column);
  4282.         if a_identifier then
  4283.            if a_current then
  4284.           !TYPE_LIKE_CURRENT!last_type.make(sp,last_expression);
  4285.            elseif a_argument then
  4286.           argument_name2 ?= last_expression;
  4287.           !TYPE_LIKE_ARGUMENT!last_type.make(sp,argument_name2);
  4288.            else
  4289.           !TYPE_LIKE_FEATURE!last_type.make(sp,
  4290.                                              tmp_name.to_simple_feature_name);
  4291.            end;
  4292.         else
  4293.            fcp("Anchor expected. An anchor could be `Current', %
  4294.            %a feature name or an argument name.");
  4295.         end;
  4296.      elseif a_keyword(fz_expanded) then
  4297.         !!sp.make(start_line,start_column);
  4298.         if a_class_type then
  4299.            !TYPE_EXPANDED!last_type.make(sp,last_class_type);
  4300.         else
  4301.            fcp("Must find a class type after %"expanded%".");
  4302.         end;
  4303.      elseif a_keyword(us_bit) then
  4304.         !!sp.make(start_line,start_column);
  4305.         if a_integer then
  4306.            !TYPE_BIT_1!last_type.make(sp,last_integer_constant);
  4307.         elseif a_identifier then
  4308.            !TYPE_BIT_2!last_type.make(sp,tmp_name.to_simple_feature_name);
  4309.         else
  4310.            fcp("Expected constant for BIT_N type declaration.");
  4311.         end;
  4312.      elseif a_type_formal_generic then
  4313.         last_type := last_type_formal_generic;
  4314.      elseif a_class_type then
  4315.         last_type := last_class_type;
  4316.      else
  4317.         Result := false;
  4318.      end;
  4319.       end;
  4320.    
  4321.    a_unary: BOOLEAN is
  4322.      --++ unary -> "not" | "+" | "-"
  4323.      --++
  4324.       do
  4325.      if a_keyword(us_not) then
  4326.         !!last_prefix.make(us_not,pos(start_line,start_column));
  4327.         Result := true;
  4328.      elseif skip1('+') then
  4329.         !!last_prefix.make(us_plus,pos(start_line,start_column));
  4330.         Result := true;
  4331.      elseif skip1('-') then
  4332.         !!last_prefix.make(us_minus,pos(start_line,start_column));
  4333.         Result := true;
  4334.      end;
  4335.       end;
  4336.       
  4337.    a_undefine_list is
  4338.      --++ undefine_list -> feature_list
  4339.      --++
  4340.       do
  4341.      if a_feature_list then
  4342.         last_parent.set_undefine(last_feature_list)
  4343.      end;
  4344.       end;
  4345.    
  4346.    a_when_part(i: E_INSPECT): BOOLEAN is
  4347.      --++ when_part -> "when" {when_part_item "," ...} then compound
  4348.      --++
  4349.      --++ when_part_item -> constant ".." constant |
  4350.      --++                   constant
  4351.      --++
  4352.      --++ constant -> character_constant | integer_constant | identifier
  4353.      --++
  4354.       local
  4355.      state: INTEGER;
  4356.      -- state 0 : sepator read, waiting a constant or "then".
  4357.      -- state 1 : first constant read.
  4358.      -- state 2 : ".." read.
  4359.      -- state 3 : slice read.
  4360.      -- state 4 : end.
  4361.      e_when: E_WHEN;
  4362.      constant: EXPRESSION;
  4363.       do
  4364.      if a_keyword(fz_when) then
  4365.         from
  4366.            Result := true;
  4367.            !!e_when.make(pos(start_line,start_column),get_comments);
  4368.         until
  4369.            state > 3
  4370.         loop
  4371.            inspect
  4372.           state
  4373.            when 0 then
  4374.           if a_constant then
  4375.              constant := last_expression;
  4376.              state := 1;
  4377.           elseif a_keyword(fz_then) then
  4378.              if constant /= Void then
  4379.             e_when.add_value(constant);
  4380.              end;
  4381.              e_when.set_compound(a_compound1("when item"));
  4382.              i.add_when(e_when);
  4383.              state := 4;
  4384.           elseif cc = ',' then
  4385.              wcp(em7);
  4386.              ok := skip1(',');
  4387.           else
  4388.              fcp(em4);
  4389.              state := 4;
  4390.           end;
  4391.            when 1 then
  4392.           if a_keyword(fz_then) then
  4393.              if constant /= Void then
  4394.             e_when.add_value(constant);
  4395.              end;
  4396.              e_when.set_compound(a_compound1("when item"));
  4397.              i.add_when(e_when);
  4398.              state := 4;
  4399.           elseif skip2('.','.') then
  4400.              state := 2;
  4401.           elseif skip1(',') then
  4402.              e_when.add_value(constant);
  4403.              constant := Void;
  4404.              state := 0;
  4405.           else
  4406.              fcp(em4);
  4407.              state := 4;
  4408.           end;
  4409.            when 2 then
  4410.           if a_constant then
  4411.              e_when.add_slice(constant,last_expression);
  4412.              constant := Void;
  4413.              state := 3;
  4414.           else
  4415.              fcp(em4);
  4416.              state := 4;
  4417.           end;
  4418.            else -- state = 3
  4419.           if skip1(',') then
  4420.              state := 0;
  4421.           elseif a_keyword(fz_then) then
  4422.              e_when.set_compound(a_compound1("when item"));
  4423.              i.add_when(e_when);
  4424.              state := 4;
  4425.           elseif a_constant then
  4426.              constant := last_expression;
  4427.              warning(tmp_name.start_position,em5);
  4428.              state := 1;
  4429.           else
  4430.              fcp(em4);
  4431.              state := 4;
  4432.           end;
  4433.            end;
  4434.         end;
  4435.      end;
  4436.       end;
  4437.    
  4438. feature {NONE}
  4439.    
  4440.    to_call(t: EXPRESSION; fn: FEATURE_NAME; 
  4441.            eal: EFFECTIVE_ARG_LIST): EXPRESSION is
  4442.       require
  4443.      t /= Void;
  4444.       do
  4445.      if fn = Void then
  4446.         check
  4447.            eal = Void;
  4448.         end;
  4449.         Result := t;
  4450.      elseif eal = Void then
  4451.         !CALL_0_C!Result.make(t,fn);
  4452.      elseif eal.count = 1 then
  4453.         !CALL_1_C!Result.make(t,fn,eal);
  4454.      else
  4455.         !CALL_N!Result.make(t,fn,eal);
  4456.      end;
  4457.       end;
  4458.  
  4459.    to_proc_call(t: EXPRESSION; fn: FEATURE_NAME; 
  4460.                 eal: EFFECTIVE_ARG_LIST): PROC_CALL is
  4461.       do
  4462.      if fn = Void then
  4463.         fcp("An expression has a result value. %
  4464.         %This is not an instruction.");
  4465.      elseif eal = Void then
  4466.         !PROC_CALL_0!Result.make(t,fn);
  4467.      elseif eal.count = 1 then
  4468.         !PROC_CALL_1!Result.make(t,fn,eal);
  4469.      else
  4470.         !PROC_CALL_N!Result.make(t,fn,eal);
  4471.      end;
  4472.       end;
  4473.  
  4474. feature {NONE}
  4475.  
  4476.    wcpefnc(old_name, new_name: STRING) is
  4477.       do
  4478.      eh.append("For readability, the keyword %"");
  4479.      eh.append(old_name);
  4480.      eh.append("%" is now %"");
  4481.      eh.append(new_name);
  4482.      wcp("%". You should update your Eiffel code now.");
  4483.       end;
  4484.  
  4485. feature {NONE}
  4486.    
  4487.    em1 : STRING is "Underscore in fractionnal part must group 3 digits.";
  4488.    em2 : STRING is "Feature name expected.";
  4489.    em3 : STRING is "Index value expected (%"indexing ...%").";
  4490.    em4 : STRING is "Error in inspect.";
  4491.    em5 : STRING is "Added %",%".";
  4492.    em6 : STRING is "Added %";%".";
  4493.    em7 : STRING is "Unexpected comma (deleted)."   
  4494.    em8 : STRING is "Unexpected new line in manifest string.";
  4495.    em9 : STRING is "Underscore in number must group 3 digits.";
  4496.    em10: STRING is "Bad character constant.";
  4497.    em11: STRING is "Bad clients list.";
  4498.    em12: STRING is "Deleted extra coma.";
  4499.    em13: STRING is "Deleted extra separator.";
  4500.    em14: STRING is "`Result' must only be used inside a function."
  4501.    em15: STRING is "Class name should use only uppercase letters.";
  4502.    em16: STRING is "Name of the current class expected.";
  4503.    em17: STRING is "Feature name expected after '$' (VUAR.4).";
  4504.    em18: STRING is "Type mark expected.";
  4505.    em19: STRING is "Added %" here.";
  4506.    em20: STRING is "Unexpected character."   
  4507.  
  4508. feature {NONE}
  4509.  
  4510.    forbidden_class: ARRAY[STRING] is
  4511.       once
  4512.      Result := <<us_none>>;
  4513.       end;
  4514.  
  4515.    lcs: STRING is
  4516.       -- Last Comment String.
  4517.       once
  4518.      !!Result.make(80);
  4519.       end;
  4520.  
  4521.    tmp_string: STRING is
  4522.       once
  4523.      !!Result.make(80);
  4524.       end;
  4525.  
  4526. feature {NONE}
  4527.  
  4528.    a_identifier1: BOOLEAN is
  4529.      -- Case Insensitive (option -case_insensitive).
  4530.       require
  4531.      case_insensitive
  4532.       local
  4533.      state: INTEGER;
  4534.      do_warning: BOOLEAN;
  4535.      -- state 0 : first letter read.
  4536.      -- state 1 : end.
  4537.       do
  4538.      if cc.is_letter then
  4539.         from
  4540.            tmp_name.initialize(line,column);
  4541.            tmp_name.extend(cc.to_lower);
  4542.         until
  4543.            state > 0
  4544.         loop
  4545.            next_char;
  4546.            inspect
  4547.           cc
  4548.            when 'a'..'z','0'..'9','_' then
  4549.           tmp_name.extend(cc);
  4550.            when 'A'..'Z' then
  4551.           tmp_name.extend(cc.to_lower);
  4552.            else
  4553.           state := 1;
  4554.            end;
  4555.         end;
  4556.         if tmp_name.isa_keyword then
  4557.            from  
  4558.           state := tmp_name.count;
  4559.            until
  4560.           state = 0
  4561.            loop
  4562.           state := state - 1;
  4563.           prev_char;
  4564.            end;
  4565.         else
  4566.            Result := true;
  4567.            skip_comments;
  4568.         end;
  4569.      end;
  4570.       end;
  4571.    
  4572.    a_identifier2: BOOLEAN is
  4573.      -- Case Sensitivity for identifiers (default).
  4574.       require
  4575.      not case_insensitive
  4576.       local
  4577.      state: INTEGER;
  4578.      do_warning: BOOLEAN;
  4579.      -- state 0 : first letter read.
  4580.      -- state 1 : end.
  4581.       do
  4582.      if cc.is_letter then
  4583.         from
  4584.            tmp_name.initialize(line,column);
  4585.            tmp_name.extend(cc);
  4586.         until
  4587.            state > 0
  4588.         loop
  4589.            next_char;
  4590.            inspect
  4591.           cc
  4592.            when 'a'..'z','0'..'9','_' then
  4593.           tmp_name.extend(cc);
  4594.            when 'A'..'Z' then
  4595.           do_warning := true;
  4596.           tmp_name.extend(cc);
  4597.            else
  4598.           state := 1;
  4599.            end;
  4600.         end;
  4601.         if tmp_name.isa_keyword then
  4602.            from  
  4603.           state := tmp_name.count;
  4604.            until
  4605.           state = 0
  4606.            loop
  4607.           state := state - 1;
  4608.           prev_char;
  4609.            end;
  4610.         else
  4611.            Result := true;
  4612.            skip_comments;
  4613.            if do_warning then
  4614.           warning(tmp_name.start_position,
  4615.           "Identifier should use only lowercase letters.");
  4616.            end;
  4617.         end;
  4618.      end;
  4619.       end;
  4620.  
  4621. feature {COMPILE_TO_C,COMPILE_TO_JVM}
  4622.  
  4623.    set_drop_comments is
  4624.       do
  4625.      drop_comments := true;
  4626.       end;
  4627.  
  4628. feature {NONE}
  4629.  
  4630.    faof: FIXED_ARRAY[E_FEATURE] is
  4631.       once
  4632.      !!Result.with_capacity(256);
  4633.       end;
  4634.  
  4635. end -- EIFFEL_PARSER
  4636.  
  4637.