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