Previous Up Next

The error handler module
(errors)

Introduction

This module contains the error handler that is responsible for generating error messages during the first (scanning and parsing) pass. During other passes, errors are reported by the procedures that perform the tests, and thus do not use this module. The error handler makes use of the binary identifier tree module [bintree] and the listing generator [listing].

1 General procedures

Before the error handler can be used the procedure init errors must be called to initialize the error handler. Further, the procedure fin errors must be called to close the error handler, and to report in the listing file the number and kinds of errors. The headers of these procedures are:

2 Kinds of errors

There are four different kinds of errors. These are, in decreasing level of severity: syntactical errors, fatal errors, normal errors and warnings.

Syntactical error messages are used to report errors that are purely syntactical.

Fatal errors are used both to report implementation errors and serious errors. Implementation errors occur when the implementation limits are exceeded, which means that the size of the grammar is too large to be handled by the current implementation. Serious errors indicate violation of semantical restrictions on the input grammar as a whole.

Normal errors are used for errors that point out deficiencies in the grammar that need to be resolved.

Warnings are used to signal errors that do not make the input incorrect, and for errors that are related to normal errors that were previously found.

Skipping errors are a special kind of (syntactical) errors, because they are not reported by the main error procedure but by two separate procedures. The four error kinds are represented in the type terror kind which is defined by:

Syntactical errors, and fatal errors are always reported in the listing and on the terminal. Whether the two other kinds of errors are reported depends on the value of the variable min error kind of type terror kind. All errors with a kind equal to or larger than the value of this variable are reported. This value is determined by the options in the input file [parser 2].

The type errors is used to enumerate all the errors (except the skipping errors) that can be reported by the error handler. Each error is represented by a mnemonic that consists of three characters and a single character prefix that indicates its kind. The possible prefix characters are s for syntactical error, m for missing (a kind of syntactical) error, i for implementation error, f for fatal (serious) error, e for normal error, w for a warning and b for errors that can both be reported as a normal error and as a warning.

3 Error reporting procedures

In this section we describe all the error reporting procedures, starting with the elementary procedures.

3.1 Skipping reporting procedures

We first deal with the two skipping procedures because they are not used by the other error reporting procedures. These procedures are invoked when skipping starts and ends, respectively. They print the characters "<" and ">" under the echoed input lines to indicate the part of the input that was skipped between their successive calls. The positions are determined by the first and last position of the last two symbols scanned by the scanner module. The number of skipping errors is updated. Massive skipping actions (over more than one line of the input) are reported with a message on the terminal. The headers of the two procedures are:

3.2 Main error reporting procedure

There is one main procedure for reporting errors to the error handler. This procedure generates an error message in the listing and on the terminal depending on the current option setting as described in section 2 The header of this procedure is:

We make uses of the VAX-Pascal facility to allow default parameters. The last two arguments are optional, and need not be given when the procedure is called.

The first parameter nr indicates the error that has to be reported. The second parameter s of type alfa is include in some of the error messages that are printed in the listing and echoed on the terminal. The last parameter reduced is only valid for errors that can occur both as a normal error and as a warning. Such errors are reduced to warnings when the parameter reduced has the value TRUE, otherwise they remain a normal error.

When the procedure is called the following actions are carried out:

3.2.1 Detecting implementation errors by the binary identifier tree module

There are a number of implementation errors, which are detected by the binary identifier tree module [bintree], and thus cannot make use of the procedure error, because this module makes use of the definitions of the binary identifier module. The global procedure impl errors is used to overcome this problem. It is called in the binary identifier tree module to report the implementation errors detected by that module.

3.3 Reporting errors concerning the identifiers

The procedures described here are used when errors occur in the identifiers that are encountered in the input. They all generate error messages using the main error reporting procedure. Once an error is reported concerning an identifier, these procedures make use of the error status [bintree 4] to reduce normal errors into warnings, and they also update the error status.

3.3.1 Missing or wrong identifiers

The following procedures are used when a certain kind of identifier [bintree 1.10] is not found in the input:

The first procedure should be used when the identifier, represented by the first parameter name ptr, is not of the identifier kind, represented by the other parameter kind2. The error status is used to reduce the severity of the error. When the identifier has a concluded status or when the identifier has been used before as an identifier of the kind represented by the parameter kind2 a warning is generated, instead of a normal error. The fact that this identifier is used as an identifier of the kind represented by the parameter kind2 is stored, by updating the error status.

The second procedure should be used for reporting a missing identifier of the kind represented by the parameter kind. This procedure will always generate a normal error.

The third procedure is a combination of the first two procedures, and is used when the first parameter name ptr could be equal to NIL. When the first parameter is equal to NIL the procedure missing is called, otherwise the procedure wrong is called with the same arguments.

3.3.2 Doubly defined identifiers

Most of the identifiers are defined by enumerations in the input file, which can be followed by a more specific definition. The following two procedures are used to report errors detected in the definition of identifiers in the input file:

The first procedure is used in enumerations of identifiers, where double enumeration is not a serious error. The second procedure is used in an enumeration of definitions, where an identifier cannot be defined more than once with a different definition. Both procedures generate an error, if the kind of the identifier represented by the first parameter name ptr is not equal to the value of the second parameter wanted, and when an error is generated the error status of the identifier is updated. Whenever the identifier represented by name ptr has the right kind the first procedure generates a warning, and the second procedure generates an error message.

4 Formal types

Attributes and semantic functions have type definitions. The typing of the expressions in the semantic assignments is checked by making use of these type definitions. These types are implemented making use of formal types as defined in [bintree 1.9]. This module contains two procedures to manipulate these formal types. A formal type consists of a pointer to a node, describing its name, and a boolean that says whether the type has been deduced from the context in which it was used. When a type is deduced it has the concluded status.

There are two special formal types to represent an undefined type and an error type, which are represented in a special way. The undefined type, stored in the variable und type [bintree 2.4] is represented as a type with no name (pointer to NIL), and not having the concluded status. The error type, stored in the variable err type also has no name, but has the concluded status.

The following procedure is used to assign a type that is deduced from its context. The header of the procedure is:

This procedure assigns the formal type represented by the second argument type2 to the first argument type1, as a deduced formal type, but only if the second argument is not an undefined formal type.

The next procedure is used for testing the equality of two formal types. The header of the procedure is:

This procedure compares the two formal types represented by the arguments type1 and type2. If they are equal, or if one of them is equal to the error formal type, then nothing is done. Otherwise, if one of them is equal to the undefined formal type, the other formal type is assigned to this formal type, as a deduced formal type. If both types are neither error nor undefined formal types, and not equal to each other, an error message is generated. This error message is a warning when at least one of the formal types is a deduced formal type, otherwise it is a normal error.

If this procedure is always used for comparing types, the undefined types are updated to deduced formal types whenever this is possible.

5 Interface

This module uses declarations from the following modules:

Exported types

The following types are exported by this module:

Exported variables

The following variables are exported

Exported procedures and functions

The following procedures and functions are exported, followed by a short description of their usage:

This procedure is used to show the start of skipped input. This is done by printing a "<"-pointer under the first skipped position in the input line, and by giving a message on the output. See subsection 3.1

This procedure is used to show the end of skipped input. This is done by printing a ">"-pointer under the last skipped position, and a message on the terminal if a massive skipping action occurred over more then one line, indicating a serious error. See subsection 3.1

This procedure prints an error message of kind err kind, for error number nr, on the listing. This is the procedure that normally will be used from other modules to indicate errors. See subsection 3.2

This procedure is used for implementation errors that could occur in one of the modules from which the error handler module uses the declarations. See subsection 3.2.1

This procedure prints an error message for an incorrect name, pointed to by name ptr, which should have been of kind kind2. If name is concluded or used before as a name of kind2, a warning is given, otherwise a normal error message. It is recorded that this name is used as kind kind2. See subsection 3.3.1

This procedure prints a normal error message for a missing name of kind kind. See subsection 3.3.1

This procedure prints an error message for a missing or incorrect name, pointed to by name ptr, which should have been of kind kind. See subsection 3.3.1

This procedure prints an error message for a double enumerated name. Depending on the kind of name, pointed to by name ptr, and wanted, a warning or a normal error message is generated. See subsection 3.3.2

This procedure prints an error message for a double defined name. Depending on the kind of name, pointed to by name ptr, and wanted, a warning or a normal error message is generated. See subsection 3.3.2

This procedure assigns the formal type of type2 to type1 as a concluded formal type, only if type2 is not undefined. See section 4

This procedure compares two types. If they are equal, or one of them is an formal error type, nothing is done. Otherwise first is tested whether one of them is undefined, if so the other type is assigned the formal type of this type, as a concluded formal type. If not so an error message is generated, where the kind of error depends on whether at least one of them is a concluded formal type. See section 4

This procedure initializes the error counters, together with the error position pointer. See section 1

This procedure prints the number of errors that occurred on the listing. See section 1

6 The listing

This section contains the complete listing of the error handler module:

ENVIRONMENT ('errors.pen'),
     INHERIT ('definitions.pen',
              '[-.screen]screen.pen',
              'listing.pen',
              'bintree.pen',
              'perform.pen')]

MODULE errors;

(*  This module contains the procedures used for error handling.              *)

6.1 Constant declarations

[HIDDEN]
CONST
  mis_keyw      ='MISSING KEYWORD : ';
  sym_exp       ='SYMBOL EXPECTED : ';
  elem_rep_in   ='ELEMENT NAME REPEATED IN ';
  name_rep      =' NAME REPEATED';
  attr_def_rep  =' ATTRIBUTE DEFINITION REPEATED';
  attr_at_elem_rep = ' ATTRIBUTE AT ELEMENT DEFINITION REPEATED';
  n_mto_def     =' NAME MORE THAN ONCE DEFINED';
  n_ny_def      ='NAME NOT YET DEFINED AS ';
  arg_in_def    =' ARGUMENTS IN APPLICATION';
  arg_in_appl   =' ARGUMENTS IN FUNCTION APPLICATION';
  no_alt_in     ='NO ALTERNATIVE IN ';
  no_error_pos  = -3;


6.2 Typing

TYPE
  terror_kind   = (t_war, t_err, t_fat, t_syn);

                (* Mnemonics:                         |  called in procedure: *)
  errors        (*------------------------------------+-----------------------*)
   = ( s_ich,   (* Illegal CHaracter                                          *)
       s_ntl,   (* Name Too Long                                              *)
       s_iof,   (* Integer OverFlow                                           *)
       m_qux,   (* QUote eXpected                                             *)
       m_sex,   (* Symbol EXpected                                            *)
       m_nex,   (* Name EXpected                                              *)
       m_ky1,   (* Missing Keywords (followers of options)                    *)
       b_wro,   (* WROng name                         |  wrong                *)
       e_nnd,   (* Name Not Defined                   |  missing              *)
       w_nar,   (* NAme Repeated                      |  double_use           *)
       e_ndd,   (* Name Double Defined                |                       *)
       e_nad,   (* Name Already Defined               |                       *)
       b_tcf,   (* Type ConFlict                      |  testtypes            *)
       e_uop,   (* Undefined OPtion                   |  read_one_option      *)
       e_pgn,   (* Parser Generator Error                                     *)
       e_fbn,   (* ForBidden Name                                             *)
       s_mk1,   (* Missing Keywords 1 : NODE (TYPES)                          *)
       s_mk2,   (* Missing Keywords 2 : RULES                                 *)
       s_mk3,   (* Missing Keywords 3 : ROOT                                  *)
       s_rbc,   (* Rubbish Before Case symbol                                 *)
       s_scm,   (* Superfluous CoMma                                          *)
       s_nex,   (* Name EXpected                                              *)
       s_ure,   (* UnRecognizable Expression                                  *)
       s_urr,   (* UnRecognizable Rule                                        *)
       s_arr,   (* ARRow symbol expected                                      *)
       m_pna,   (* missing Part NAme                                          *)
       m_saa,   (* missing Starters of Attribute Assignment                   *)
       m_sal,   (* missing Starters of seLector                               *)
       i_iln,   (* ILlegal Name for this implementation                       *)
       e_nye,   (* Not Yet defined Element            |  exp_element          *)
       e_esc,   (* Element Should be Class            |  is_class             *)
       e_nyc,   (* Not Yet defined Class              |                       *)
       e_nyt,   (* Not Yet defined Type               |  exp_type             *)
       w_era,   (* Element Repeated at Attribute      |  read_one_attribute   *)
       b_aap,   (* Attribute is APplied               |  assigned_attr        *)
       b_aas,   (* Attribute is ASsigned              |  applied_attr         *)
       w_idr,   (* Input attr Definition Repeated     |  set_all_io_attr      *)
       w_odr,   (* Output attr Definition Repeated    |                       *)
       b_nea,   (* Not Element Attribute pair         |  set_io_attr_at_elem  *)
       w_iar,   (* Input Attr at Element Repeated     |                       *)
       w_oar,   (* Output Attr at Element Repeated    |                       *)
       e_nip,   (* Name not In Part names             |  exp_test_partname    *)
       e_eps,   (* Element in Previous Selector       |  exp_selectors        *)
       w_ers,   (* Element Repeated in Selector       |                       *)
       w_ese,   (* Empty SElector                     |                       *)
       b_tfa,   (* Too Few Arguments                  |  read_test            *)
       b_tma,   (* Too Many Arguments                 |                       *)
       e_nyf,   (* Not Yet defined Function           |  exp_sem_func_expr    *)
       e_npn,   (* No Part Name found                 |  exp_case_expr        *)
       e_nae,   (* No Alternatives in case Expression |                       *)
       w_wpc,   (* Wrong Part name add in Conflict    |  process_partnames    *)
       e_wpn,   (* Wrong Part Name                    |                       *)
       f_con,   (* CONflict in rules                  |  test_consistency     *)
       w_naa,   (* No Alternatives in sel. Assignment |  exp_sel_ass          *)
       w_nat,   (* Nothing Added in Tree rule         |  exp_tree_def         *)
       e_dpn,   (* Double Part Name in tree rule      |                       *)
       w_itl,   (* Information Tree rule Lost         |  exp_tree_rule        *)
       w_etr,   (* Empty Tree Rule                    |                       *)
       f_rtr,   (* Repeated Tree Rule at element      |                       *)
       f_itr,   (* Indirect Tree Rule at element      |                       *)
       w_erc,   (* Element Repeated in Class          |  exp_cl_elements      *)
       f_etc,   (* Element in Two Classes             |                       *)
       f_rec,   (* RECursice class definition         |                       *)
       f_rcr,   (* Repeated Class Rule at class       |  exp_class_rule       *)
       i_tme,   (* Too Many Elements                  |  init_node (BINTREE)  *)
       i_tma,   (* Too Many Attributes                |                       *)
       i_tmp    (* Too Many Part names                |  exp_tree_def         *)
      );

  error_set = [HIDDEN] SET OF errors;

6.3 Variable declarations

VAR
  (* local for this module *)
  global_errors : error_set;    (* set of serious errors              *)
  nr_skipping   : [HIDDEN] integer; (* number of skipping actions             *)
  nr_errors     : [HIDDEN] ARRAY[t_war..t_syn] OF integer;
                                    (* number of other errors                 *)
  error_pos     : [HIDDEN] integer; (* position of last error in output line  *)
  err_mess      : [HIDDEN] VARYING[70] OF CHAR; (* contains error message     *)
  err_code_mess : [HIDDEN] VARYING[20] OF CHAR; (* error code message         *)

(* from PARSER, shared with this program are:                                 *)
  min_error_kind  : terror_kind; (* for options WARNINGS, ERRORS and FATAL    *)


(*      EXTERNAL PROCEDURES                                                   *)

  [EXTERNAL] FUNCTION at_start_pos : integer; EXTERN;
  [EXTERNAL] FUNCTION at_previous_pos : integer; EXTERN;
  (* this procedure returns the previous pos number (the last position of the *)
  (* previous symbol) if previous is TRUE, otherwise the start position of    *)
  (* the current symbol.                                                      *)

6.4 Skipping errors

(*  The following procedures are used for printing syntax errors, including   *)
(*  skipping actions.                                                         *)

  PROCEDURE skip_start;
  (* This procedure is used to show the start of skipped input. This is       *)
  (* done by printing a "<"-pointer under the first skipped position in the   *)
  (* input line, and by giving a message on the output                        *)
  BEGIN
    perf_nr_calls(perf_skip);
    nr_skipping := nr_skipping + 1;
    set_error_pointer('<',at_start_pos);
  END;

  PROCEDURE skip_end;
  (* This procedure is used to show the end of skipped input. This is done by *)
  (* printing a ">"-pointer under the last skipped position, and a message on *)
  (* the terminal if there occurred a massive skipping action over more then  *)
  (* one line, indicating a serious error.                                    *)
  BEGIN
    set_error_pointer('>',at_previous_pos);
    display_error_on_screen('? skipping')
  END;

6.4 Error printing procedure

  PROCEDURE print_error(err_kind : terror_kind; (* kind/severity of error     *)
                        err_nr : errors;   (* error number                    *)
                        err_mess : VARYING[s] OF char); (* error text         *)
  (* This procedure does the actual error printing, and is called by all of   *)
  (* the other error procedures except the above for skipping.                *)
  (* Although this procedure is available in all modules that inherit this    *)
  (* module, direct usage is not recommended.                                 *)
  (* This procedure does the following things:                                *)
  (* - First the number of errors is updated, according the kind of error:    *)
  (* - Secondly if the error has to be printed depending on the options the   *)
  (*   following will happen :                                                *)
  (*   - An error pointer is made, if it is not a global error.               *)
  (*   - The error identification is constructed in the variable ident:       *)
  (*     - the severity derived from err_kind                                 *)
  (*     - the mnemonic taken from err_nr                                     *)
  (*   - ident together with err_mess is echoed in the listing and on the     *)
  (*     screen.                                                              *)
  VAR
    ident : VARYING[100] OF char;
  BEGIN
    nr_errors[err_kind] := succ(nr_errors[err_kind]);
    IF   err_kind >= min_error_kind
    THEN BEGIN
           IF   NOT (err_nr IN global_errors)
           THEN set_error_pointer('^', at_start_pos);
           CASE err_kind OF
             t_syn : writev(ident, '? SYNTAX  ', err_nr:5);
             t_war : writev(ident, '? WARNING ', err_nr:5);
             t_err : writev(ident, '? ERROR   ', err_nr:5);
             t_fat : writev(ident, '? FATAL   ', err_nr:5)
           END;
           write(listing, ident, ' : ', err_mess);
           print_newline;
           display_error_on_screen(ident + ' : ' + err_mess)
         END;
  END;

6.6 Main error procedure

  PROCEDURE error( nr:errors    (* error number *)
                 ; s:alfa := '' (* extra alfa, used with some messages *)
                 ; reduced : boolean := FALSE (* reduced severity for b_ errors*)
                 );
  (* This procedure prints an error message of kind err_kind, for error number *)
  (* nr, on the listing. This is the procedure that normally will be used from *)
  (* other modules to indicate errors.                                        *)
  (*--------------------------------------------------------------------------*)
  (* USAGES:                                                                  *)
  (* There are a number of ways this procedure can be used, because of the    *)
  (* optional parameters. The simplest way of using it is just only           *)
  (* giving the first parameter which will indicate the number of the error.  *)
  (* some error messages might also include a name of an identifier or some   *)
  (* additional information. This can be done by using the second parameter.  *)
  (* A third parameter is used for certain errors for which the severity can  *)
  (* be reduced. (see also explanation in module BINTREE).                    *)
  (* In all cases the usages of the procedure error should be according to    *)
  (* the body of the procedure.                                               *)
  VAR
    sever : terror_kind;
  BEGIN
    IF   reduced
    THEN sever := t_war
    ELSE sever := t_err;
    perf_nr_calls(perf_error);
    CASE nr OF
        (* used in module BINTREE *)
      e_pgn : print_error(t_err, nr, 'PARSERGENERATOR ERROR');
      e_fbn : print_error(t_err, nr, 'FORBIDDEN NAME');

        (* used in module SCANNER *)
      s_ich : print_error(t_syn, nr, 'ILLEGAL CHARACTER');
      m_qux : print_error(t_syn, nr, 'QUOTE EXPECTED : "' + s + '"');
      s_ntl : print_error(t_syn, nr, 'NAME TOO LONG : "' + s + '"');
      s_iof : print_error(t_syn, nr, 'INTEGER OVERFLOW');
      m_sex : print_error(t_syn, nr, s + ' SYMBOL EXPECTED');

        (* used in modules SCANNER and OPTIONS *)
      m_nex : print_error(t_syn, nr, s + ' NAME EXPECTED');
      m_ky1 : print_error(t_syn, nr, 'MISSING KEYWORD: (NON)TERMINALS');

        (* used in module OPTIONS *)
      e_uop : print_error(t_err, nr, 'UNKNOWN OPTION');

        (* used in this module *)
      b_tcf : print_error(sever, nr, 'TYPE CONFLICT');

        (* used in module PARSER *)
      s_mk1 : print_error(t_syn, nr, mis_keyw + 'NODE (TYPES)');
      s_mk2 : print_error(t_syn, nr, mis_keyw + 'RULES');
      s_mk3 : print_error(t_syn, nr, mis_keyw + 'ROOT');
      s_rbc : print_error(t_syn, nr, 'RUBBISH BEFORE CASE SYMBOL');
      s_scm : print_error(t_syn, nr, 'SUPERFLUOUS COMMA');
      s_nex : print_error(t_syn, nr, 'NAME EXPECTED');
      s_ure : print_error(t_syn, nr, 'UNRECOGNIZABLE EXPRESSION');
      s_urr : print_error(t_syn, nr, 'UNRECOGNIZABLE RULE');
      s_arr : print_error(t_syn, nr, sym_exp + '=> INSTEAD OF = SYMBOL');
      m_pna : print_error(t_syn, nr, '# OR NAME EXPECTED');
      m_sal : print_error(t_syn, nr, sym_exp + 'OTHERS : ,  (OR NAME)');
      m_saa : print_error(t_syn, nr, sym_exp + 'CASE OF # , (OR NAME)');
      i_iln : print_error(t_syn, nr, 'ILLEGAL NAME FOR THIS IMPLEMENTATION');
      w_era : print_error(t_war, nr, 'ATTRIBUTE DEFINITION');
      w_idr : print_error(t_war, nr, 'INPUT' + attr_def_rep);
      w_odr : print_error(t_war, nr, 'OUTPUT' + attr_def_rep);
      w_iar : print_error(t_war, nr, 'INPUT' + attr_at_elem_rep);
      w_oar : print_error(t_war, nr, 'OUTPUT' + attr_at_elem_rep);
      w_wpc : print_error(t_war, nr, 'WRONG PART NAME AND IN CONFLICT WITH OTHER');
      w_nat : print_error(t_war, nr, 'NOTHING ADDED IN DEFINITION OF TREE RULE');
      w_etr : print_error(t_war, nr, 'EMPTY TREE RULE');
      w_ers : print_error(t_war, nr, elem_rep_in + 'SELECTOR');
      w_naa : print_error(t_war, nr, no_alt_in + 'SELECTIVE ASSIGNMENT');
      w_erc : print_error(t_war, nr, elem_rep_in + 'CLASS RULE');
      w_ese : print_error(t_war, nr, 'EMPTY SELECTOR');
      w_itl : print_error(t_war, nr, 'INFORMATION TREE RULE LOST');
      b_nea : print_error(sever, nr, 'ATTRIBUTE NOT DEFINED AT ELEMENT');
      b_aap : print_error(sever, nr, 'ATTRIBUTE IS APPLIED ATTRIBUTE');
      b_aas : print_error(sever, nr, 'ATTRIBUTE IS ASSIGNED ATTRIBUTE');
      b_tma : print_error(sever, nr, 'TOO MANY' + arg_in_appl);
      b_tfa : print_error(sever, nr, 'TOO FEW' + arg_in_appl);
      e_nae : print_error(t_err, nr, no_alt_in + 'CASE EXPRESSION');
      e_nye : print_error(t_err, nr, n_ny_def + 'ELEMENT');
      e_nyc : print_error(t_err, nr, n_ny_def + 'CLASS');
      e_nyt : print_error(t_err, nr, n_ny_def + 'TYPE');
      e_nyf : print_error(t_err, nr, n_ny_def + 'FUNCTION');
      e_esc : print_error(t_err, nr, 'ELEMENT SHOULD BE CLASS');
      e_npn : print_error(t_err, nr, '# OR PART NAME EXPECTED');
      e_nip : print_error(t_err, nr, 'NAME NOT IN PART NAMES');
      e_wpn : print_error(t_err, nr, 'WRONG PART NAME AND NOT DEFINED AS ');
      e_eps : print_error(t_err, nr, 'ELEMENT IN PREVIOUS SELECTOR');
      e_dpn : print_error(t_err, nr, 'PART NAME USED MORE THEN ONCE IN TREE RULE');
      f_rtr : print_error(t_fat, nr, 'TREE RULE REDEFINED AT ELEMENT');
      f_rcr : print_error(t_fat, nr, 'CLASS RULE REDEFINED AT CLASS');
      f_con : print_error(t_fat, nr, 'RULES NOT CONSISTENT');
      f_itr : print_error(t_fat, nr, 'ELEMENT HAS INDIRECT TREE PRODUCTION');
      f_rec : print_error(t_fat, nr, 'RECURSIVE CLASS DEFINITION');
      f_etc : print_error(t_fat, nr, 'ELEMENT IN MORE THAN ONE CLASS');
      i_tme : print_error(t_fat, nr, 'TOO MANY ELEMENTS DEFINED');
      i_tma : print_error(t_fat, nr, 'TOO MANY ATTRIBUTES DEFINED');
      i_tmp : print_error(t_fat, nr, 'TOO MANY PART NAMES DEFINED')
    OTHERWISE print_error(t_fat, e_pgn, 'No error message specified')
    END
  END;

6.7 Other errors

(*  The errors on this page are generated by intelligent procedures that are  *)
(*  being called, when reading and checking identifiers.                      *)

  [GLOBAL]
  PROCEDURE impl_error(nr : integer);
  BEGIN
    CASE nr OF
      1 : error(i_tme);
      2 : error(i_tma)
    END
  END;

  [HIDDEN] FUNCTION name_k(kind:tnode_kind) : alfa;
  (* This procedure returns an alphabetical name of the parameter kind in     *)
  (* the listing.                                                             *)
  BEGIN
    CASE kind OF
      n_class  : name_k := 'CLASS';
      n_node   : name_k := 'NODE TYPES';
      n_elem   : name_k := 'ELEMENT';
      n_type   : name_k := 'TYPE';
      n_attr   : name_k := 'ATTRIBUTES';
      n_func   : name_k := 'FUNCTION';
      n_pascal : name_k := 'PASCAL';
      n_system : name_k := 'SYSTEM';
      n_undef  : name_k := 'UNDEFINED'
    END
  END;


(*  The following procedures are the actual error handling procedures.        *)

  PROCEDURE wrong(name_ptr:pnode; kind2:tnode_kind);
  (* This procedure prints an error message for a wrong name, pointed to by   *)
  (* name_ptr, which should have been of kind kind2. If name is concluded or  *)
  (* used before as a name of kind2, a warning is given, otherwise a normal   *)
  (* error message is generated. It is recorded that this name is used as     *)
  (* kind kind2.                                                              *)
  VAR
    sort : terror_kind;
  BEGIN
    WITH name_ptr^
    DO BEGIN
         WITH status
         DO IF kind2 IN defined
            THEN sort := t_war
            ELSE BEGIN
                   defined := defined + [kind2];
                   IF   conc
                   THEN sort := t_war
                   ELSE sort := t_err
                 END;
         print_error(sort, b_wro,
                           name_k(kind2)
                           + ' NAME EXPECTED; NAME DEFINED AS '
                           + name_k(kind));
       END
  END;

  PROCEDURE missing(kind:tnode_kind);
  (* This procedure prints a normal error message for a missing name of kind  *)
  (* kind2.                                                                   *)
  BEGIN
    print_error(t_err, e_nnd, name_k(kind)+ ' NAME EXPECTED; (NAME UNDEFINED)')
  END;

  PROCEDURE wrong_or_missing(name_ptr:pnode; kind:tnode_kind);
  (* This procedure prints an error message for a missing or wrong name,      *)
  (* pointed to by name_ptr, which should have been of kind kind.             *)
  BEGIN
    IF   name_ptr = NIL
    THEN missing(kind)
    ELSE wrong(name_ptr,kind)
  END;

  PROCEDURE double_enumerated(name_ptr:pnode; wanted:tnode_kind);
  (* This procedure prints an error message for a double enumerated name.     *)
  (* Depending on the kind of name, pointed to by name_ptr, and wanted, a     *)
  (* warning or a normal error message is generated.                          *)
  BEGIN
    WITH name_ptr^
    DO IF kind = wanted
       THEN (* name is already enumerated as kind wanted *)
            print_error(t_war, w_nar, name_k(kind) + ' NAME REPEATED')
       ELSE (* name was already defined, but not as kind wanted *)
            BEGIN
              print_error(t_err, e_nad,
                          'NAME ALREADY DEFINED AS ' + name_k(kind));
              error_define(name_ptr, wanted);
            END;
  END;

  PROCEDURE double_define(name_ptr:pnode; wanted:tnode_kind);
  (* This procedure prints an error message for a double defined name.        *)
  (* Depending on the kind of name, pointed to by name_ptr, and wanted, a     *)
  (* warning or a normal error message is generated.                          *)
  BEGIN
    WITH name_ptr^
    DO IF kind = wanted
       THEN (* name is already defined as kind wanted *)
            print_error(t_err, e_nnd, name_k(kind) + ' DEFINED MORE THEN ONCE')
       ELSE (* name was already defined, but not as kind wanted *)
            BEGIN
              print_error(t_err, e_nad,
                          'NAME ALREADY DEFINED AS ' + name_k(kind));
              error_define(name_ptr, wanted);
            END;
  END;

6.8 Formal types

(*  The following procedures are for handling formal types.                   *)

  [HIDDEN] FUNCTION equal(type1, type2 : ttype) : boolean;
  (* This function returns true if type1 equals type2.                        *)
  BEGIN
    IF   type1.type_name = type2.type_name
    THEN equal := type1.conc = type2.conc
    ELSE equal := FALSE
  END;

  PROCEDURE ass_conc_type(VAR type1:ttype; type2:ttype);
  (* This procedure assigns the formal type of type2 to type1 as a concluded  *)
  (* formal type, only if type2 is not undefined.                             *)
  BEGIN
    IF   NOT equal(type2, und_type)
    THEN WITH type1
         DO BEGIN
              conc := TRUE;
              type_name := type2.type_name
            END
  END;

  PROCEDURE test_types(VAR type1,type2:ttype);
  (* This procedure compares two types. If they are equal, or one of them is  *)
  (* a formal error type, nothing is done. Otherwise first is tested whether  *)
  (* one of them is undefined, if so the other type is assigned the formal    *)
  (* type of this type, as a concluded formal type. If not so an error        *)
  (* message is generated, where the kind of error depends on whether at      *)
  (* least one of them is a concluded formal type.                            *)
  BEGIN
    IF   NOT equal(type1, type2)   THEN IF
         NOT equal(type1, err_type)     THEN IF
         NOT equal(err_type, type2)
    THEN (* They are unequal and both not equal error type *)
         IF   equal(type1, und_type)
         THEN (* type1 is an undefined formal type *)
              ass_conc_type(type1,type2)
         ELSE IF   equal(type2, und_type)
              THEN (* type2 is an undefined formal type *)
                   ass_conc_type(type2,type1)
              ELSE (* give warning if one of the types is a concluded formal  *)
                   (* type, otherwise give a error message.                   *)
                   error(b_tcf,, type1.conc OR type2.conc)
  END;

6.9. Initialization and finalization

(*  The last two procedures are for intializing and finalizing the error     *)
(*  handling process.                                                         *)

  PROCEDURE init_errors;
  (* This procedure initializes the error counters, together with the error   *)
  (* position pointer.                                                        *)
  VAR
    i  : terror_kind;
  BEGIN
    global_errors := [];
    error_pos     := no_error_pos;
    nr_skipping   := 0;
    FOR i := t_syn TO t_fat
    DO nr_errors[i] := 0;
  END;

  PROCEDURE fin_errors;
  (* This procedure prints the number of errors that occurred on the listing. *)

    PROCEDURE print(nr_of_errors : integer; of_kind : VARYING[l] OF char);
    BEGIN
      write(listing,nr_of_errors, of_kind, '(s) detected');
      print_newline(1)
    END;

  BEGIN (* of fin_errors *)
    print_newline(2);
    print(nr_errors[t_syn], ' Syntax error'   );
    print(nr_skipping     , ' Skipping action');
    print(nr_errors[t_fat], ' Fatal error'    );
    print(nr_errors[t_err], ' Error'          );
    print(nr_errors[t_war], ' Warning'        );
  END;

END.


My life as a hacker | My home page