/*
 *  gen_first_and_follow_sets.c
 *
 *  This utility program generates  FIRST and FOLLOW set initialisers  for use
 *  within the  Objective Modula-2 compiler (objm2c).  Any changes relating to
 *  FIRST and FOLLOW sets  should be made  within the  sources of this utility
 *  program and not within the sources of compiler.
 *
 *  Author: Benjamin Kowarsch
 *
 *  This source file and any output generated by this utility program are:
 *
 *  Copyright (C) 2009 The Objective Modula-2 Project. All rights reserved.
 *
 *  and they are hereby released under the following license:
 *
 *  Redistribution  and  use  in source  and  binary forms,  with  or  without
 *  modification, are permitted provided that the following conditions are met
 *
 *  1) This file,  or any part thereof,  may  NOT  be hosted on websites which
 *     contain advertising,  unless specific prior written permission has been
 *     obtained.  The licensor will grant such permission  upon request at its
 *     sole discretion to websites the licensor does  NOT  consider abusive in
 *     their  use  of advertising.  Small notices  in the footer  of a website
 *     naming corporate rights holders,  infrastructure providers  or sponsors
 *     are not considered advertising in the context of this license.
 *
 *  2) Redistributions  of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *
 *  3) Redistributions  in binary form  must  reproduce  the  above  copyright
 *     notice,  this list of conditions  and  the following disclaimer  in the
 *     documentation and other materials provided with the distribution.
 *
 *  4) Neither the author's name nor the names of any contributors may be used
 *     to endorse  or  promote  products  derived  from this software  without
 *     specific prior written permission.
 *
 *  5) Where this list of conditions  or  the following disclaimer, in part or
 *     as a whole is overruled  or  nullified by applicable law, no permission
 *     is granted to use the software.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY  AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
 * CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT  LIMITED  TO,  PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS; OR BUSINESS
 * INTERRUPTION)  HOWEVER  CAUSED  AND ON ANY THEORY OF LIABILITY,  WHETHER IN
 * CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Version history:
 *
 *  1.00   2009-09-20   BK   new file
 *         2009-09-23   BK   s/tokenset_enumerator/tokenset_iterator
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include "objm2_tokens.h"
#include "objm2_tokenset.h"
#include "objm2_tokenset_literals.h"


// ---------------------------------------------------------------------------
// Enumeration type defining output modes
// ---------------------------------------------------------------------------

typedef enum { FIRST, FOLLOW } set_type_t;


// ---------------------------------------------------------------------------
// Arrays for FIRST and FOLLOW sets
// ---------------------------------------------------------------------------

objm2_tokenset_t _FIRST[OBJM2_NUMBER_OF_PRODUCTIONS];
objm2_tokenset_t _FOLLOW[OBJM2_NUMBER_OF_PRODUCTIONS];


// ---------------------------------------------------------------------------
// private function:  init_first_sets()
// ---------------------------------------------------------------------------
//
// Initialises the array of FIRST sets.

static void init_first_sets() {
    
    _FIRST[p_compilation_unit] =
    objm2_tokenset_from_list(TOKEN_MODULE,
                             TOKEN_DEFINITION,
                             TOKEN_IMPLEMENTATION,
                             TOKEN_PROTOCOL, 0);
    
    _FIRST[p_program_module] =
    objm2_tokenset_from_list(TOKEN_MODULE, 0);
    
    _FIRST[p_definition_of_module] =
    objm2_tokenset_from_list(TOKEN_DEFINITION, 0);
    
    _FIRST[p_implementation_of_module] =
    objm2_tokenset_from_list(TOKEN_IMPLEMENTATION, 0);
    
    _FIRST[p_protocol] =
    objm2_tokenset_from_list(TOKEN_PROTOCOL, 0);
    
    _FIRST[p_import_list] =
    objm2_tokenset_from_list(TOKEN_FROM,
                             TOKEN_IMPORT, 0);
    
    _FIRST[p_declaration] =
    objm2_tokenset_from_list(TOKEN_CONST,
                             TOKEN_TYPE,
                             TOKEN_VAR,
                             TOKEN_PROCEDURE,
                             TOKEN_CLASS,
                             TOKEN_METHOD, 0);
    
    _FIRST[p_definition] =
    objm2_tokenset_from_list(TOKEN_CONST,
                             TOKEN_TYPE,
                             TOKEN_VAR,
                             TOKEN_PROCEDURE,
                             TOKEN_CLASS,
                             TOKEN_METHOD, 0);
    
    _FIRST[p_const_declaration] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_type_declaration] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_type] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_ARRAY,
                             TOKEN_RECORD,
                             TOKEN_POINTER,
                             TOKEN_PROCEDURE,
                             TOKEN_ENUM,
                             TOKEN_LPAREN,
                             TOKEN_SET,
                             TOKEN_CLASS, 0);
    
    _FIRST[p_anonymous_type] =
    objm2_tokenset_from_list(TOKEN_ARRAY,
                             TOKEN_RECORD,
                             TOKEN_POINTER,
                             TOKEN_PROCEDURE, 0);
    
    _FIRST[p_enumeration_type] =
    objm2_tokenset_from_list(TOKEN_ENUM,
                             TOKEN_LPAREN, 0);
    
    _FIRST[p_array_type] =
    objm2_tokenset_from_list(TOKEN_ARRAY, 0);
    
    _FIRST[p_record_type] =
    objm2_tokenset_from_list(TOKEN_RECORD, 0);
    
    _FIRST[p_field_list_sequence] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_field_list] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_class_type] =
    objm2_tokenset_from_list(TOKEN_CLASS, 0);
    
    _FIRST[p_set_type] =
    objm2_tokenset_from_list(TOKEN_SET, 0);
    
    _FIRST[p_pointer_type] =
    objm2_tokenset_from_list(TOKEN_POINTER, 0);
    
    _FIRST[p_procedure_type] =
    objm2_tokenset_from_list(TOKEN_PROCEDURE, 0);
    
    _FIRST[p_formal_type_list] =
    objm2_tokenset_from_list(TOKEN_IMMUTABLE,
                             TOKEN_VAR,
                             TOKEN_ARRAY,
                             TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_attributed_formal_type] =
    objm2_tokenset_from_list(TOKEN_IMMUTABLE,
                             TOKEN_VAR,
                             TOKEN_ARRAY,
                             TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_formal_type] =
    objm2_tokenset_from_list(TOKEN_ARRAY,
                             TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_variable_declaration] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_procedure_declaration] =
    objm2_tokenset_from_list(TOKEN_PROCEDURE, 0);
    
    _FIRST[p_procedure_header] =
    objm2_tokenset_from_list(TOKEN_PROCEDURE, 0);
    
    _FIRST[p_formal_param_list] =
    objm2_tokenset_from_list(TOKEN_IMMUTABLE,
                             TOKEN_VAR,
                             TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_formal_params] =
    objm2_tokenset_from_list(TOKEN_IMMUTABLE,
                             TOKEN_VAR,
                             TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_method_declaration] =
    objm2_tokenset_from_list(TOKEN_CLASS,
                             TOKEN_METHOD, 0);
    
    _FIRST[p_method_header] =
    objm2_tokenset_from_list(TOKEN_CLASS,
                             TOKEN_METHOD, 0);
    
    _FIRST[p_method_arg] =
    objm2_tokenset_from_list(TOKEN_COLON_IDENTIFIER, 0);
    
    _FIRST[p_statement] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_LBRACKET,
                             TOKEN_IF,
                             TOKEN_CASE,
                             TOKEN_WHILE,
                             TOKEN_REPEAT,
                             TOKEN_LOOP,
                             TOKEN_FOR,
                             TOKEN_TRY,
                             TOKEN_CRITICAL,
                             TOKEN_RETURN,
                             TOKEN_EXIT, 0);
    
    _FIRST[p_statement_sequence] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_LBRACKET,
                             TOKEN_IF,
                             TOKEN_CASE,
                             TOKEN_WHILE,
                             TOKEN_REPEAT,
                             TOKEN_LOOP,
                             TOKEN_FOR,
                             TOKEN_TRY,
                             TOKEN_CRITICAL,
                             TOKEN_RETURN,
                             TOKEN_EXIT, 0);
    
    _FIRST[p_method_invocation] =
    objm2_tokenset_from_list(TOKEN_LBRACKET, 0);
    
    _FIRST[p_receiver] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_LBRACKET, 0);
    
    _FIRST[p_message] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_COLON_IDENTIFIER, 0);
    
    _FIRST[p_assignment_or_procedure_call] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_if_statement] =
    objm2_tokenset_from_list(TOKEN_IF, 0);
    
    _FIRST[p_case_statement] =
    objm2_tokenset_from_list(TOKEN_CASE, 0);
    
    _FIRST[p_case] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FIRST[p_case_label_list] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FIRST[p_case_labels] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FIRST[p_while_statement] =
    objm2_tokenset_from_list(TOKEN_WHILE, 0);
    
    _FIRST[p_repeat_statement] =
    objm2_tokenset_from_list(TOKEN_REPEAT, 0);
    
    _FIRST[p_loop_statement] =
    objm2_tokenset_from_list(TOKEN_LOOP, 0);
    
    _FIRST[p_for_statement] =
    objm2_tokenset_from_list(TOKEN_FOR, 0);
    
    _FIRST[p_try_statement] =
    objm2_tokenset_from_list(TOKEN_TRY, 0);
    
    _FIRST[p_critical_statement] =
    objm2_tokenset_from_list(TOKEN_CRITICAL, 0);
    
    _FIRST[p_const_expression] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FIRST[p_relation] =
    objm2_tokenset_from_list(TOKEN_EQUAL_OP,
                             TOKEN_NOT_EQUAL_OP,
                             TOKEN_LESS_OP,
                             TOKEN_LESS_OR_EQUAL_OP,
                             TOKEN_GREATER_OP,
                             TOKEN_GREATER_OR_EQUAL_OP,
                             TOKEN_IN,
                             TOKEN_IS, 0);
    
    _FIRST[p_simple_const_expr] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FIRST[p_add_operator] =
    objm2_tokenset_from_list(TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_OR, 0);
    
    _FIRST[p_const_term] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FIRST[p_mul_operator] =
    objm2_tokenset_from_list(TOKEN_MULTIPLY_OP,
                             TOKEN_DIVIDE_OP,
                             TOKEN_DIV,
                             TOKEN_MOD,
                             TOKEN_AND,
                             TOKEN_LOGICAL_AND_OP, 0);
    
    _FIRST[p_const_factor] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FIRST[p_designator] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_designator_tail] =
    objm2_tokenset_from_list(TOKEN_LBRACKET,
                             TOKEN_POINTER_OP, 0);
    
    _FIRST[p_expression_list] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP,
                             TOKEN_LBRACKET, 0);
    
    _FIRST[p_expression] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP,
                             TOKEN_LBRACKET, 0);
    
    _FIRST[p_simple_expression] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP,
                             TOKEN_LBRACKET, 0);
    
    _FIRST[p_term] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP,
                             TOKEN_LBRACKET, 0);
    
    _FIRST[p_factor] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP,
                             TOKEN_LBRACKET, 0);
    
    _FIRST[p_designator_or_procedure_call] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_actual_parameters] =
    objm2_tokenset_from_list(TOKEN_LPAREN, 0);
    
    _FIRST[p_structured_value] =
    objm2_tokenset_from_list(TOKEN_LBRACE, 0);
    
    _FIRST[p_value_component] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FIRST[p_qualident] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER, 0);
    
    _FIRST[p_ident_list] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER, 0);
    
} // end init_first_sets


// ---------------------------------------------------------------------------
// private function:  init_first_sets()
// ---------------------------------------------------------------------------
//
// Initialises the array of FOLLOW sets.

static void init_follow_sets() {

    _FOLLOW[p_compilation_unit] =
    objm2_tokenset_from_list(TOKEN_EOF_MARKER, 0);
    
    _FOLLOW[p_program_module] =
    objm2_tokenset_from_list(TOKEN_EOF_MARKER, 0);
    
    _FOLLOW[p_definition_of_module] =
    objm2_tokenset_from_list(TOKEN_EOF_MARKER, 0);
    
    _FOLLOW[p_implementation_of_module] =
    objm2_tokenset_from_list(TOKEN_EOF_MARKER, 0);
    
    _FOLLOW[p_protocol] =
    objm2_tokenset_from_list(TOKEN_EOF_MARKER, 0);
    
    _FOLLOW[p_import_list] =
    objm2_tokenset_from_list(TOKEN_CONST,
                             TOKEN_TYPE,
                             TOKEN_VAR,
                             TOKEN_PROCEDURE,
                             TOKEN_METHOD,
                             TOKEN_BEGIN,
                             TOKEN_END,
                             TOKEN_OPTIONAL, 0);
    
    _FOLLOW[p_declaration] =
    objm2_tokenset_from_list(TOKEN_BEGIN,
                             TOKEN_END, 0);
    
    _FOLLOW[p_definition] =
    objm2_tokenset_from_list(TOKEN_END, 0);
    
    _FOLLOW[p_const_declaration] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_type_declaration] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_type] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_anonymous_type] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_enumeration_type] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_array_type] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_record_type] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_field_list_sequence] =
    objm2_tokenset_from_list(TOKEN_END, 0);
    
    _FOLLOW[p_field_list] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_END, 0);
    
    _FOLLOW[p_class_type] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_set_type] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_pointer_type] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_procedure_type] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_formal_type_list] =
    objm2_tokenset_from_list(TOKEN_COLON,
                             TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_attributed_formal_type] =
    objm2_tokenset_from_list(TOKEN_COMMA,
                             TOKEN_COLON,
                             TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_formal_type] =
    objm2_tokenset_from_list(TOKEN_COMMA,
                             TOKEN_COLON,
                             TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_variable_declaration] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_procedure_declaration] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_procedure_header] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_formal_param_list] =
    objm2_tokenset_from_list(TOKEN_RPAREN, 0);
    
    _FOLLOW[p_formal_params] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_VARIADIC,
                             TOKEN_RPAREN, 0);
    
    _FOLLOW[p_method_declaration] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_method_header] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_method_arg] =
    objm2_tokenset_from_list(TOKEN_COLON,
                             TOKEN_SEMICOLON, 0);
    
    _FOLLOW[p_statement] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_statement_sequence] =
    objm2_tokenset_from_list(TOKEN_ELSIF,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_method_invocation] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_COLON_IDENTIFIER,
                             TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_receiver] =
    objm2_tokenset_from_list(TOKEN_IDENTIFIER,
                             TOKEN_COLON_IDENTIFIER, 0);
    
    _FOLLOW[p_message] =
    objm2_tokenset_from_list(TOKEN_RBRACKET, 0);
    
    _FOLLOW[p_assignment_or_procedure_call] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_if_statement] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_case_statement] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_case] =
    objm2_tokenset_from_list(TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_END, 0);
    
    _FOLLOW[p_case_label_list] =
    objm2_tokenset_from_list(TOKEN_COLON, 0);
    
    _FOLLOW[p_case_labels] =
    objm2_tokenset_from_list(TOKEN_COMMA,
                             TOKEN_COLON, 0);
    
    _FOLLOW[p_while_statement] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_repeat_statement] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_loop_statement] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_for_statement] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_try_statement] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_critical_statement] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_const_expression] =
    objm2_tokenset_from_list(TOKEN_RBRACKET,
                             TOKEN_SEMICOLON,
                             TOKEN_COMMA,
                             TOKEN_OF,
                             TOKEN_COLON,
                             TOKEN_DOT_DOT,
                             TOKEN_DO,
                             TOKEN_RPAREN,
                             TOKEN_BY,
                             TOKEN_LBRACE,
                             TOKEN_RBRACE, 0);
    
    _FOLLOW[p_relation] =
    objm2_tokenset_from_list(TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_IDENTIFIER,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FOLLOW[p_simple_const_expr] =
    objm2_tokenset_from_list(TOKEN_EQUAL_OP,
                             TOKEN_NOT_EQUAL_OP,
                             TOKEN_LESS_OP,
                             TOKEN_LESS_OR_EQUAL_OP,
                             TOKEN_GREATER_OP,
                             TOKEN_GREATER_OR_EQUAL_OP,
                             TOKEN_IN,
                             TOKEN_IS,
                             TOKEN_TYPE_CONVERSION_OP, 0);
    
    _FOLLOW[p_add_operator] =
    objm2_tokenset_from_list(TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_IDENTIFIER,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FOLLOW[p_const_term] =
    objm2_tokenset_from_list(TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_OR,
                             TOKEN_EQUAL_OP,
                             TOKEN_NOT_EQUAL_OP,
                             TOKEN_LESS_OP,
                             TOKEN_LESS_OR_EQUAL_OP,
                             TOKEN_GREATER_OP,
                             TOKEN_GREATER_OR_EQUAL_OP,
                             TOKEN_IN,
                             TOKEN_IS,
                             TOKEN_TYPE_CONVERSION_OP, 0);
    
    _FOLLOW[p_mul_operator] =
    objm2_tokenset_from_list(TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_IDENTIFIER,
                             TOKEN_LPAREN,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP, 0);
    
    _FOLLOW[p_const_factor] =
    objm2_tokenset_from_list(TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_OR,
                             TOKEN_MULTIPLY_OP,
                             TOKEN_DIVIDE_OP,
                             TOKEN_DIV,
                             TOKEN_MOD,
                             TOKEN_AND,
                             TOKEN_LOGICAL_AND_OP,
                             TOKEN_EQUAL_OP,
                             TOKEN_NOT_EQUAL_OP,
                             TOKEN_LESS_OP,
                             TOKEN_LESS_OR_EQUAL_OP,
                             TOKEN_GREATER_OP,
                             TOKEN_GREATER_OR_EQUAL_OP,
                             TOKEN_IN,
                             TOKEN_IS,
                             TOKEN_TYPE_CONVERSION_OP, 0);
    
    _FOLLOW[p_designator] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ASSIGN_OP,
                             TOKEN_INCREMENT_OP,
                             TOKEN_DECREMENT_OP,
                             TOKEN_LPAREN,
                             TOKEN_END, 0);
    
    _FOLLOW[p_designator_tail] =
    objm2_tokenset_from_list(TOKEN_SEMICOLON,
                             TOKEN_ASSIGN_OP,
                             TOKEN_INCREMENT_OP,
                             TOKEN_DECREMENT_OP,
                             TOKEN_LPAREN,
                             TOKEN_END, 0);
    
    _FOLLOW[p_expression_list] =
    objm2_tokenset_from_list(TOKEN_RPAREN,
                             TOKEN_RBRACKET, 0);
    
    _FOLLOW[p_expression] =
    objm2_tokenset_from_list(TOKEN_COMMA,
                             TOKEN_RPAREN,
                             TOKEN_RBRACKET,
                             TOKEN_SEMICOLON,
                             TOKEN_THEN,
                             TOKEN_ELSIF,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_OF,
                             TOKEN_DO,
                             TOKEN_UNTIL,
                             TOKEN_TO,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_simple_expression] =
    objm2_tokenset_from_list(TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_IDENTIFIER,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP,
                             TOKEN_TYPE_CONVERSION_OP,
                             TOKEN_COMMA,
                             TOKEN_RPAREN,
                             TOKEN_RBRACKET,
                             TOKEN_SEMICOLON,
                             TOKEN_THEN,
                             TOKEN_ELSIF,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_OF,
                             TOKEN_DO,
                             TOKEN_UNTIL,
                             TOKEN_TO,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_term] =
    objm2_tokenset_from_list(TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_OR,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_IDENTIFIER,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP,
                             TOKEN_TYPE_CONVERSION_OP,
                             TOKEN_COMMA,
                             TOKEN_RPAREN,
                             TOKEN_RBRACKET,
                             TOKEN_SEMICOLON,
                             TOKEN_THEN,
                             TOKEN_ELSIF,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_OF,
                             TOKEN_DO,
                             TOKEN_UNTIL,
                             TOKEN_TO,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_factor] =
    objm2_tokenset_from_list(TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_OR,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_IDENTIFIER,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP,
                             TOKEN_TYPE_CONVERSION_OP,
                             TOKEN_COMMA,
                             TOKEN_RPAREN,
                             TOKEN_RBRACKET,
                             TOKEN_SEMICOLON,
                             TOKEN_THEN,
                             TOKEN_ELSIF,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_OF,
                             TOKEN_DO,
                             TOKEN_UNTIL,
                             TOKEN_TO,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_designator_or_procedure_call] =
    objm2_tokenset_from_list(TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_OR,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_IDENTIFIER,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP,
                             TOKEN_TYPE_CONVERSION_OP,
                             TOKEN_COMMA,
                             TOKEN_RPAREN,
                             TOKEN_RBRACKET,
                             TOKEN_SEMICOLON,
                             TOKEN_THEN,
                             TOKEN_ELSIF,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_OF,
                             TOKEN_DO,
                             TOKEN_UNTIL,
                             TOKEN_TO,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_actual_parameters] =
    objm2_tokenset_from_list(TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_OR,
                             TOKEN_NUMERIC_LITERAL,
                             TOKEN_STRING_LITERAL,
                             TOKEN_IDENTIFIER,
                             TOKEN_NOT,
                             TOKEN_LOGICAL_NOT_OP,
                             TOKEN_TYPE_CONVERSION_OP,
                             TOKEN_COMMA,
                             TOKEN_RPAREN,
                             TOKEN_RBRACKET,
                             TOKEN_SEMICOLON,
                             TOKEN_THEN,
                             TOKEN_ELSIF,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_OF,
                             TOKEN_DO,
                             TOKEN_UNTIL,
                             TOKEN_TO,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_structured_value] =
    objm2_tokenset_from_list(TOKEN_COMMA,
                             TOKEN_RBRACE,
                             TOKEN_SEMICOLON,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_UNTIL,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_value_component] =
    objm2_tokenset_from_list(TOKEN_COMMA,
                             TOKEN_RBRACE, 0);
    
    _FOLLOW[p_qualident] =
    objm2_tokenset_from_list(TOKEN_COMMA,
                             TOKEN_SEMICOLON,
                             TOKEN_ASSIGN_OP,
                             TOKEN_INCREMENT_OP,
                             TOKEN_DECREMENT_OP,
                             TOKEN_LPAREN,
                             TOKEN_RPAREN,
                             TOKEN_LBRACKET,
                             TOKEN_RBRACKET,
                             TOKEN_POINTER_OP,
                             TOKEN_PLUS_OP,
                             TOKEN_MINUS_OP,
                             TOKEN_OR,
                             TOKEN_MULTIPLY_OP,
                             TOKEN_DIVIDE_OP,
                             TOKEN_DIV,
                             TOKEN_MOD,
                             TOKEN_AND,
                             TOKEN_LOGICAL_AND_OP,
                             TOKEN_EQUAL_OP,
                             TOKEN_NOT_EQUAL_OP,
                             TOKEN_LESS_OP,
                             TOKEN_LESS_OR_EQUAL_OP,
                             TOKEN_GREATER_OP,
                             TOKEN_GREATER_OR_EQUAL_OP,
                             TOKEN_IN,
                             TOKEN_IS,
                             TOKEN_TYPE_CONVERSION_OP,
                             TOKEN_THEN,
                             TOKEN_ELSIF,
                             TOKEN_ELSE,
                             TOKEN_VERTICAL_BAR,
                             TOKEN_OF,
                             TOKEN_DO,
                             TOKEN_UNTIL,
                             TOKEN_TO,
                             TOKEN_ON,
                             TOKEN_CONTINUE,
                             TOKEN_END, 0);
    
    _FOLLOW[p_ident_list] =
    objm2_tokenset_from_list(TOKEN_COLON,
                             TOKEN_SEMICOLON,
                             TOKEN_RPAREN,
                             TOKEN_END, 0);
    
} // end init_follow_sets


// ---------------------------------------------------------------------------
// private function:  generate_production_table()
// ---------------------------------------------------------------------------
//
// Generates the production master table for file objm2_production_table.h

void generate_production_table() {
    unsigned int prod_index;
    objm2_tokenset_literal_t tuples;
    objm2_tokenset_literal_status_t status;
    
    printf("\n// Productions\n");

    prod_index = 0;
    while (prod_index < OBJM2_NUMBER_OF_PRODUCTIONS) {
        
        printf("\n_add_production( _%s,\n",
               objm2_production_name(prod_index));
        
        objm2_tokenset_to_literal(_FIRST[prod_index], &tuples, &status);
        printf("    %s,   // FIRST set\n", tuples);
        
        objm2_tokenset_to_literal(_FOLLOW[prod_index], &tuples, &status);
        printf("    %s )  // FOLLOW set\n", tuples);
        
        prod_index++;
    } // end while
    
} // end generate_production_table


// ---------------------------------------------------------------------------
// private function:  generate_set_lists( mode )
// ---------------------------------------------------------------------------
//
// Generates FIRST and FOLLOW set list macros for file objm2_first_follow.h

void generate_set_lists(set_type_t mode) {
    
    unsigned int prod_index, token_count, token_index;
    const char *prod_name, *token_name, *token_identifier;
    objm2_token_t token;
    objm2_tokenset_iterator_t iterator;
    
    if (mode == FIRST)
        printf("\n\n// FIRST set lists\n");
    else
        printf("\n\n// FOLLOW set lists\n");
    
    prod_index = 0;
    while (prod_index < OBJM2_NUMBER_OF_PRODUCTIONS) {
        
        prod_name = objm2_production_name(prod_index);
        if (mode == FIRST) {
            printf("\n#define FIRST_LIST_for_%s \\\n", prod_name);
            iterator = objm2_tokenset_iterator(_FIRST[prod_index]);
        }
        else {
            printf("\n#define FOLLOW_LIST_for_%s \\\n", prod_name);
            iterator = objm2_tokenset_iterator(_FOLLOW[prod_index]);
        } // end if

        token_count = objm2_tokenset_iterator_token_count(iterator);
        printf("    %i, \\\n", token_count);
        
        token_index = 0;
        while (token_index < token_count) {
            token =
            objm2_tokenset_iterator_token_at_index(iterator,
                                                   token_index);
            token_name = objm2_token_name(token);
            token_identifier = objm2_token_identifier(token);
            
            printf("    %s", token_identifier);
            if (token_index + 1 != token_count)
                printf(", \\");
            
            printf("\n");
            
            token_index++;
        } // end while
                
        prod_index++;
    } // end while
        
} // end generate_set_lists


// ---------------------------------------------------------------------------
// main function
// ---------------------------------------------------------------------------
//
// Initialises FIRST and FOLLOW set arrays,  generates production master table
// and FIRST and FOLLOW set lists,  writing the generated data to stdout.

int main (int argc, const char **argv) {
    
    init_first_sets();

    init_follow_sets();
    
    generate_production_table();
    
    generate_set_lists(FIRST);
    
    generate_set_lists(FOLLOW);
    
    return 0;
} // end main


// END OF FILE
