/* $Id: mkred.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */
/*
 This software is subject to the terms of the IBM Jikes Compiler
 License Agreement available at the following URL:
 http://www.ibm.com/research/jikes.
 Copyright (C) 1983, 1999, International Business Machines Corporation
 and others.  All Rights Reserved.
 You must accept the terms of that agreement to use this software.
*/
static char hostfile[] = __FILE__;

#include "common.h"
#include "reduce.h"
#include "header.h"

/***********************************************************************/
/* STACK_ROOT is used in la_traverse to construct a stack of symbols.  */
/* The boolean vector SINGLE_COMPLETE_ITEM identifies states whose     */
/* kernel consists of a single final item and other conditions allows  */
/* us to compute default reductions for such states.                   */
/* The vector LA_BASE is used in COMPUTE_READ and TRACE_LALR_PATH to   */
/* identify states whose read sets can be completely computed from     */
/* their kernel items.                                                 */
/***********************************************************************/
static struct node *stack_root = NULL;
static BOOLEAN *single_complete_item;
static int *la_base;

/*****************************************************************************/
/*                                 LPGACCESS:                                */
/*****************************************************************************/
/* Given a STATE_NO and an ITEM_NO, ACCESS computes the set of states where  */
/* the rule from which ITEM_NO is derived was introduced through closure.    */
/*****************************************************************************/
struct node *lpgaccess(int state_no, int item_no)
{
    int i;

    BOOLEAN end_node;

    struct node *access_root,
                *head,
                *tail,
                *q,
                *p,
                *s;

/****************************************************************/
/* Build a list pointed to by ACCESS_ROOT originally consisting */
/* only of STATE_NO.                                            */
/****************************************************************/
    access_root = Allocate_node();
    access_root -> value = state_no;
    access_root -> next = NULL;

    for (i = item_table[item_no].dot; i > 0; i--)/*distance to travel is DOT */
    {
        head = access_root;  /* Save old ACCESS_ROOT */
        access_root = NULL;  /* Initialize ACCESS_ROOT for new list */
        for (p = head; p != NULL; tail = p, p = p -> next)
        {
            /***********************************************************/
            /* Compute set of states with transition into p->value.    */
            /***********************************************************/
            for (end_node = ((s = in_stat[p -> value]) == NULL);
                 ! end_node;
                 end_node = (s == in_stat[p -> value]))
            {
                s = s -> next;

                q = Allocate_node();
                q -> value = s -> value;
                q -> next = access_root;
                access_root = q;
            }
        }

        free_nodes(head, tail);    /* free previous list */
     }

     return(access_root);
}


/*****************************************************************************/
/*                              TRACE_LALR_PATH:                             */
/*****************************************************************************/
/* Given an item of the form: [x .A y], where x and y are arbitrary strings, */
/* and A is a non-terminal, we pretrace the path(s) in the automaton  that   */
/* will be followed in computing the look-ahead set for that item in         */
/* STATE_NO.  A number is assigned to all pairs (S, B), where S is a state,  */
/* and B is a non-terminal, involved in the paths. GOTO_INDX points to the   */
/* GOTO_ELEMENT of (STATE_NO, A).                                            */
/*****************************************************************************/
static void trace_lalr_path(int state_no, int goto_indx)
{
    int i,
        symbol,
        item,
        state;

    struct goto_header_type go_to;

    BOOLEAN contains_empty;

    struct node *p,
                *r,
                *t,
                *w;

/*********************************************************************/
/*  If STATE is a state number we first check to see if its base     */
/* look-ahead set is a special one that does not contain EMPTY and   */
/* has already been assigned a slot that can be reused.              */
/* ((LA_BASE[STATE] != OMEGA) signals this condition.)               */
/* NOTE that look-ahead follow sets are shared only when the maximum */
/* look-ahead level allowed is 1 and single productions will not be  */
/* removed. If either (or both) of these conditions is true, we need */
/* to have a unique slot assigned to each pair [S, A] (where S is a  */
/* state, and A is a non-terminal) in the automaton.                 */
/*********************************************************************/
    go_to = statset[state_no].go_to;
    state = GOTO_ACTION(go_to, goto_indx);
    if (state > 0)
    {
        if (la_base[state] != OMEGA &&
            lalr_level == 1 && (! single_productions_bit))
        {
            GOTO_LAPTR(go_to, goto_indx) = la_base[state];
            return;
        }
        r = statset[state].kernel_items;
    }
    else
        r = adequate_item[-state];

/***********************************************************************/
/* At this point, R points to a list of items which are the successors */
/* of the items needed to initialize the Look-ahead follow sets.  If   */
/* anyone of these items contains EMPTY, we trace the Digraph for other*/
/* look-ahead follow sets that may be needed, and signal this fact     */
/* using the variable CONTAINS_EMPTY.                                  */
/***********************************************************************/
    la_top++;   /* allocate new slot */
    INT_CHECK(la_top);
    GOTO_LAPTR(go_to, goto_indx) = la_top;
    contains_empty = FALSE;

    for (; r != NULL;  r = r -> next)
    {
        item = r -> value - 1;
        if (IS_IN_SET(first, item_table[item].suffix_index, empty))
        {
            contains_empty = TRUE;
            symbol = rules[item_table[item].rule_number].lhs;
            w = lpgaccess(state_no, item);
            for (t = w; t != NULL; p = t, t = t -> next)
            {
                struct goto_header_type go_to;

                go_to = statset[t -> value].go_to;

                for (i = 1; GOTO_SYMBOL(go_to, i) != symbol; i++)
                    ;

                if (GOTO_LAPTR(go_to, i) == OMEGA)
                    trace_lalr_path(t -> value, i);
            }

            free_nodes(w, p);
        }
    }

/********************************************************************/
/* If the look-ahead follow set involved does not contain EMPTY, we */
/* mark the state involved (STATE) so that other look-ahead follow  */
/* sets which may need this set may reuse the same one.             */
/* NOTE that if CONTAINS_EMPTY is false, then STATE has to denote a */
/* state number (positive value) and not a rule number (negative).  */
/********************************************************************/
    if (! contains_empty)
        la_base[state] = GOTO_LAPTR(go_to, goto_indx);

    return;
}


/*****************************************************************************/
/*                               COMPUTE_READ:                               */
/*****************************************************************************/
/* COMPUTE_READ computes the number of intermediate look-ahead sets that     */
/* will be needed (in LA_TOP), allocates space for the sets(LA_SET), and    */
/* initializes them.                                                         */
/*  By intermediate look-ahead set, we mean the set of terminals that may    */
/* follow a non-terminal in a given state.                                   */
/*  These sets are initialized to the set of terminals that can immediately  */
/* follow the non-terminal in the state to which it can shift (READ set).    */
/*****************************************************************************/
static void compute_read(void)
{
    int state_no,
        item_no,
        rule_no,
        lhs_symbol,
        state,
        i,
        j,
        la_ptr;

    struct node *p,
                *q,
                *s,
                *v;

    if (lalr_level > 1 || single_productions_bit)
    {
        read_set = (SET_PTR)
                   calloc(num_states + 1,
                          sizeof(BOOLEAN_CELL) * term_set_size);
        if (read_set == NULL)
            nospace(__FILE__, __LINE__);
    }

/************************************************************************/
/*  We traverse all the states and for all complete items that requires */
/* a look-ahead set, we retrace the state digraph (with the help of the */
/* routine TRACE_LALR_PATH) and assign a unique number to all look-ahead*/
/* follow sets that it needs. A look-ahead follow set is a set of       */
/* terminal symbols associated with a pair [S, A], where S is a state,  */
/* and A is a non-terminal:                                             */
/*                                                                      */
/* [S, A] --> Follow-set                                                */
/* Follow-set = {t | t is a terminal that can be shifted on after       */
/*                      execution of a goto action on A in state S}.    */
/*                                                                      */
/* Each follow set is initialized with the set of terminals that can be */
/* shifted on in state S2, where GOTO(S, A) = S2. After initialization  */
/* a follow set F that does not contain the special terminal symbol     */
/* EMPTY is marked with the help of the array LA_BASE, and if the       */
/* highest level of look-ahead allowed is 1, then only one such set is  */
/* allocated, and shared for all pairs (S, B) whose follow set is F.    */
/************************************************************************/
    la_top = 0;
    la_base = (int *) calloc(num_states + 1, sizeof(int));
    if (la_base == NULL)
        nospace(__FILE__, __LINE__);

    for ALL_STATES(i)
        la_base[i] = OMEGA;

    for ALL_STATES(state_no)
    {
        for (p = ((lalr_level <= 1 && single_complete_item[state_no])
                  ? NULL
                  : statset[state_no].complete_items);
             p != NULL; p = p -> next)
        {
            item_no = p -> value;
            rule_no = item_table[item_no].rule_number;
            lhs_symbol = rules[rule_no].lhs;
            if (lhs_symbol != accept_image)
            {
                v = lpgaccess(state_no, item_no);
                for (s = v; s != NULL; q = s, s = s -> next)
                {
                    struct goto_header_type go_to;

                    go_to = statset[s -> value].go_to;
                    for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++)
                        ;

                    if (GOTO_LAPTR(go_to, i) == OMEGA)
                        trace_lalr_path(s -> value, i);
                }

                free_nodes(v, q);
            }
        }

    /***********************************************************************/
    /*  If the look-ahead level is greater than 1 or single productions    */
    /* actions are to be removed when possible, then we have to compute    */
    /* a Follow-set for all pairs [S, A] in the state automaton. Therefore,*/
    /* we also have to consider Shift-reduce actions as reductions, and    */
    /* trace back to their roots as well.                                  */
    /* Note that this is not necessary for Goto-reduce actions. Since      */
    /* they terminate with a non-terminal, and that non-terminal is        */
    /* followed by the empty string, and we know that it must produce a    */
    /* rule that either ends up in a reduction, a shift-reduce, or another */
    /* goto-reduce. It will therefore be taken care of automatically by    */
    /* transitive closure.                                                 */
    /***********************************************************************/
        if (lalr_level > 1 || single_productions_bit)
        {
            struct shift_header_type sh;
            struct goto_header_type  go_to;

            sh = shift[statset[state_no].shift_number];
            for (j = 1; j <= sh.size; j++)
            {
                if (SHIFT_ACTION(sh, j) < 0)
                {
                    rule_no = - SHIFT_ACTION(sh, j);
                    lhs_symbol = rules[rule_no].lhs;
                    item_no = adequate_item[rule_no] -> value - 1;
                    v = lpgaccess(state_no, item_no);
                    for (s = v; s != NULL; q = s, s = s -> next)
                    {
                        go_to = statset[s -> value].go_to;
                        for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++)
                            ;
                        if (GOTO_LAPTR(go_to, i) == OMEGA)
                            trace_lalr_path(s -> value, i);
                    }

                    free_nodes(v, q);
                }
            }

        /*******************************************************************/
        /* We also need to compute the set of terminal symbols that can be */
        /* read in a state entered via a terminal transition.              */
        /*******************************************************************/
            if (lalr_level > 1 && state_no != 1)
            {
                q = statset[state_no].kernel_items;
                item_no = q -> value - 1;
                if (item_table[item_no].symbol IS_A_TERMINAL)
                {
                    ASSIGN_SET(read_set, state_no, first,
                               item_table[item_no].suffix_index);
                    for (q = q -> next; q != NULL; q = q -> next)
                    {
                        item_no = q -> value - 1;
                        SET_UNION(read_set, state_no, first,
                                  item_table[item_no].suffix_index);
                    }
                }
            }
        }
    }


/*********************************************************************/
/*   We now allocate space for LA_INDEX and LA_SET, and initialize   */
/* all its elements as indicated in reduce.h. The array LA_BASE is   */
/* used to keep track of Follow sets that have been initialized. If  */
/* another set needs to be initialized with a value that has been    */
/* already computed, LA_BASE is used to retrieve the value.          */
/*********************************************************************/
    for ALL_STATES(i)
        la_base[i] = OMEGA;

    la_index = Allocate_short_array(la_top + 1);

    la_set = (SET_PTR)
             calloc(la_top + 1, term_set_size * sizeof(BOOLEAN_CELL));
    if (la_set == NULL)
        nospace(__FILE__, __LINE__);

    for ALL_STATES(state_no)
    {
        struct goto_header_type go_to;

        go_to = statset[state_no].go_to;
        for (i = 1; i <= go_to.size; i++)
        {
            la_ptr = GOTO_LAPTR(go_to, i);
            if (la_ptr != OMEGA)   /* Follow Look-ahead needed */
            {
                state = GOTO_ACTION(go_to, i);
                if (state > 0)
                {
                    if (la_base[state] != OMEGA)  /* already computed */
                    {
                        la_index[la_ptr] = la_index[la_base[state]];
                        ASSIGN_SET(la_set, la_ptr,
                                   la_set, la_base[state]);
                        q = NULL;
                    }
                    else
                    {
                        la_base[state] = la_ptr;
                        q = statset[state].kernel_items;
                    }
                }
                else
                    q = adequate_item[-state];
                if (q != NULL)
                {
                    item_no = q -> value - 1;
                    /* initialize with first item */
                    ASSIGN_SET(la_set, la_ptr,
                               first, item_table[item_no].suffix_index);
                    for (q = q -> next; q != NULL; q = q -> next)
                    {
                        item_no = q -> value - 1;
                        SET_UNION(la_set, la_ptr, first,
                                  item_table[item_no].suffix_index);
                    }
                    if (IS_IN_SET(la_set, la_ptr, empty))
                        la_index[la_ptr] = OMEGA;
                    else
                        la_index[la_ptr] = INFINITY;
                    if (lalr_level > 1 || single_productions_bit)
                    {
                        if(state > 0)
                        {
                            ASSIGN_SET(read_set, state, la_set, la_ptr);
                        }
                    }
                }
            }
        }
    }

    ffree(la_base);

    return;
}


/*****************************************************************************/
/*                                LA_TRAVERSE:                               */
/*****************************************************************************/
/* LA_TRAVERSE takes two major arguments: STATE_NO, and an index (GOTO_INDX) */
/* that points to the GOTO_ELEMENT array in STATE_NO for the non-terminal    */
/* left hand side of an item for which look-ahead is to be computed. The     */
/* look-ahead of an item of the form [x. A y] in state STATE_NO is the set   */
/* of terminals that can appear immediately after A in the context summarized*/
/* by STATE_NO. When a look-ahead set is computed, the result is placed in   */
/* an allocation of LA_ELEMENT pointed to by the LA_PTR field of the         */
/* GOTO_ELEMENT array.                                                       */
/*                                                                           */
/* The same digraph algorithm used in MKFIRST is used for this computation.  */
/*                                                                           */
/*****************************************************************************/
void la_traverse(int state_no, int goto_indx, int *stack_top)
{
    int indx;

    int symbol,
        item,
        state,
        i,
        la_ptr;

    struct goto_header_type go_to;

    struct node *r,
                *s,
                *t,
                *w;

    go_to = statset[state_no].go_to;
    la_ptr =  GOTO_LAPTR(go_to, goto_indx);

    s = Allocate_node();    /* Push LA_PTR down the stack */
    s -> value = la_ptr;
    s -> next = stack_root;
    stack_root = s;

    indx = ++(*stack_top); /* one element was pushed into the stack */
    la_index[la_ptr] = indx;

/**********************************************************************/
/* Compute STATE, action to perform on Goto symbol in question. If    */
/* STATE is positive, it denotes a state to which to shift. If it is  */
/* negative, it is a rule on which to perform a Goto-Reduce.          */
/**********************************************************************/
    state = GOTO_ACTION(go_to, goto_indx);
    if (state > 0)     /* Not a Goto-Reduce action */
        r = statset[state].kernel_items;
    else
        r = adequate_item[-state];

    for (; r != NULL; r = r -> next)
    {  /* loop over items [A -> x LHS_SYMBOL . y] */
        item = r -> value - 1;
        if IS_IN_SET(first, item_table[item].suffix_index, empty)
        {
            symbol = rules[item_table[item].rule_number].lhs;
            w = lpgaccess(state_no, item); /* states where RULE was  */
                                     /* introduced through closure   */
            for (t = w; t != NULL; s = t, t = t -> next)
            {
                struct goto_header_type go_to;

                /**********************************************************/
                /* Search for GOTO action in access-state after reducing  */
                /* RULE to its left hand side (SYMBOL). Q points to the   */
                /* GOTO_ELEMENT in question.                              */
                /**********************************************************/
                go_to = statset[t -> value].go_to;
                for (i = 1; GOTO_SYMBOL(go_to, i) != symbol; i++)
                    ;
                if (la_index[GOTO_LAPTR(go_to, i)] == OMEGA)
                    la_traverse(t -> value, i, stack_top);
                SET_UNION(la_set, la_ptr,
                          la_set, GOTO_LAPTR(go_to, i));
                la_index[la_ptr] = MIN(la_index[la_ptr],
                                       la_index[GOTO_LAPTR(go_to, i)]);
            }

            free_nodes(w, s);
        }
    }

    if (la_index[la_ptr] == indx) /* Top of a SCC */
    {
        s = stack_root;

        for (i = stack_root -> value; i != la_ptr;
             stack_root = stack_root -> next, i = stack_root -> value)
        {
            ASSIGN_SET(la_set, i, la_set, la_ptr);
            la_index[i] = INFINITY;
            (*stack_top)--; /* one element was popped from the stack; */
        }
        la_index[la_ptr] = INFINITY;
        r = stack_root; /* mark last element that is popped and ... */
        stack_root = stack_root -> next; /* ... pop it! */
        (*stack_top)--; /* one element was popped from the stack; */

        free_nodes(s, r);
    }

    return;
}

/*****************************************************************************/
/*                               COMPUTE_LA:                                 */
/*****************************************************************************/
/* COMPUTE_LA takes as argument a state number (STATE_NO), an item number    */
/* (ITEM_NO), and a set (LOOK_AHEAD).  It computes the look-ahead set of     */
/* terminals for the given item in the given state and places the answer in  */
/* the set LOOK_AHEAD.                                                       */
/*****************************************************************************/
void compute_la(int state_no, int item_no, SET_PTR look_ahead)
{
    int lhs_symbol,
        i;

    struct node *r,
                *s,
                *v;

    stack_root = NULL;
    lhs_symbol = rules[item_table[item_no].rule_number].lhs;
    if (lhs_symbol == accept_image)
    {
        ASSIGN_SET(look_ahead, 0,
                   first, item_table[item_no-1].suffix_index);
        return;
    }

    INIT_SET(look_ahead);  /* initialize set */

    v = lpgaccess(state_no, item_no);
    for (s = v; s != NULL; r = s, s = s -> next)
    {
        struct  goto_header_type go_to;

        /*****************************************************************/
        /* Search for GOTO action in Access-State after reducing rule to */
        /* its left hand side(LHS_SYMBOL). Q points to the state.        */
        /*****************************************************************/
        go_to = statset[s -> value].go_to;
        for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++)
            ;

        /***********************************************************/
        /* If look-ahead after left hand side is not yet computed, */
        /* LA_TRAVERSE the graph to compute it.                    */
        /***********************************************************/
        if (la_index[GOTO_LAPTR(go_to, i)] == OMEGA)
        {
            int stack_top = 0;
            la_traverse(s -> value, i, &stack_top);
        }
        SET_UNION(look_ahead, 0, la_set, GOTO_LAPTR(go_to, i));
    }

    RESET_BIT(look_ahead, empty); /* empty not valid look-ahead */
    free_nodes(v, r);

    return;
}


/**********************************************************************/
/*                            BUILD_IN_STAT:                          */
/**********************************************************************/
/* We construct the IN_STAT map which is the inverse of the transition*/
/* map formed by GOTO and SHIFT maps.                                 */
/* This map is implemented as a table of pointers that can be indexed */
/* by the states to a circular list of integers representing other    */
/* states that contain transitions to the state in question.          */
/**********************************************************************/
static void build_in_stat(void)
{
    struct shift_header_type sh;
    struct goto_header_type  go_to;
    struct node *q;
    int state_no,
        i,
        n;

    for ALL_STATES(state_no)
    {
        n = statset[state_no].shift_number;
        sh = shift[n];
        for (i = 1; i <= sh.size; ++i)
        {
            n = SHIFT_ACTION(sh, i);
            if (n > 0 && n <= num_states) /* A shift action? */
            {
                q = Allocate_node();
                q -> value = state_no;
                if (in_stat[n] == NULL)
                    q -> next = q;
                else
                {
                    q -> next = in_stat[n] -> next;
                    in_stat[n] -> next = q;
                }
                in_stat[n] = q;
            }
        }

        go_to = statset[state_no].go_to;
        for (i = 1; i <= go_to.size; i++)
        {
            n = GOTO_ACTION(go_to, i);
            if (n > 0) /* A goto action */
            {
                q = Allocate_node();
                q -> value = state_no;
                if (in_stat[n] == NULL)
                    q -> next = q;
                else
                {
                    q -> next = in_stat[n] -> next;
                    in_stat[n] -> next = q;
                }
                in_stat[n] = q;
            }
        }
    }

    return;
}


/*****************************************************************************/
/*                                MKRDCTS:                                   */
/*****************************************************************************/
/* MKRDCTS constructs the REDUCE map and detects conflicts in the grammar.   */
/* When constructing an LALR parser, the subroutine COMPUTE_LA is invoked to */
/* compute the lalr look-ahead sets.  For an SLR parser, the FOLLOW map      */
/* computed earlier in the procedure MKFIRST is used.                        */
/*                                                                           */
/* For a complete description of the lookahead algorithm used in this        */
/* program, see Charles, PhD thesis, NYU 1991.                               */
/*****************************************************************************/
void mkrdcts(void)
{
    short *symbol_list,
          *rule_count;

    int symbol_root,
        reduce_size,
        state_no,
        item_no,
        rule_no,
        symbol,
        default_rule,
        i,
        n;

    struct node **action;

    struct node *p,
                *q,
                *r,
                *item_ptr;

    BOOLEAN *no_shift_on_error_sym;
    SET_PTR look_ahead;

/**********************************************************************/
/* Set up a pool of temporary space. If LALR(k), k > 1 is requested,  */
/* INIT_LALRK_PROCESS sets up the necessary environment for the       */
/* computation of multiple lookahead.                                 */
/**********************************************************************/
    reset_temporary_space();

    init_lalrk_process();

/**********************************************************************/
/* IN_STAT is used to construct a reverse transition map. See         */
/* BUILD_IN_STAT for more detail.                                     */
/*                                                                    */
/* RULE_COUNT is an array used to count the number of reductions on   */
/* particular rules within a given state.                             */
/*                                                                    */
/* NO_SHIFT_ON_ERROR_SYM is a vector used to identify states that     */
/* contain shift actions on the %ERROR symbol.  Such states are marked*/
/* only when DEFAULT_OPT is 5.                                        */
/*                                                                    */
/* SYMBOL_LIST is used to construct temporary lists of terminals on   */
/* which reductions are defined.                                      */
/*                                                                    */
/* When default actions are requested, the vector SINGLE_COMPLETE_ITEM*/
/* is used to identify states that contain exactly one final item.    */
/* NOTE that when the READ_REDUCE options is turned on, the LR(0)     */
/* automaton constructed contains no such state.                      */
/*                                                                    */
/* ACTION is an array that is used as the base for a mapping from     */
/* each terminal symbol into a list of actions that can be executed   */
/* on that symbol in a given state.                                   */
/*                                                                    */
/* LOOK_AHEAD is used to compute lookahead sets.                      */
/**********************************************************************/
    in_stat = (struct node **)
              calloc(num_states + 1, sizeof(struct node *));
    if (in_stat == NULL)
        nospace(__FILE__, __LINE__);

    rule_count = Allocate_short_array(num_rules + 1);
    no_shift_on_error_sym = Allocate_boolean_array(num_states + 1);
    symbol_list = Allocate_short_array(num_terminals + 1);
    single_complete_item = Allocate_boolean_array(num_states + 1);

    action = (struct node **)
             calloc(num_terminals + 1, sizeof(struct node *));
    if (action == NULL)
        nospace(__FILE__, __LINE__);

    look_ahead = (SET_PTR)
                 calloc(1, term_set_size * sizeof(BOOLEAN_CELL));
    if (look_ahead == NULL)
        nospace(__FILE__, __LINE__);

    /****************************************************************/
    /* If we will be removing single productions, we need to keep   */
    /* track of all (state, symbol) pairs on which a conflict is    */
    /* detected. The structure conflict_symbols is used as a base   */
    /* to construct that map. See ADD_CONFLICT_SYMBOL in resolve.c. */
    /* NOTE that this allocation automatically initialized all      */
    /* elements of the conflict_symbols array to NULL.              */
    /****************************************************************/
    if (single_productions_bit)
    {
        conflict_symbols = (struct node **)
                           calloc(num_states + 1, sizeof(struct node *));
        if (conflict_symbols == NULL)
            nospace(__FILE__, __LINE__);
    }

    /**********************************************************************/
    /* First, construct the IN_STAT map. Next, iterate over the states to */
    /* construct two boolean vectors.  One indicates whether there is a   */
    /* shift action on the ERROR symbol when the DEFAULT_OPT is 5.  The   */
    /* other indicates whether it is all right to take default action in  */
    /* states containing exactly one final item.                          */
    /*                                                                    */
    /* We also check whether the grammar is LR(0). I.e., whether it needs */
    /* any look-ahead at all.                                             */
    /**********************************************************************/
    build_in_stat();

    for ALL_STATES(state_no)
    {
        struct shift_header_type sh;

        no_shift_on_error_sym[state_no] = TRUE;

        if (default_opt == 5)
        {
            n = statset[state_no].shift_number;
            sh = shift[n];
            for (i = 1; i <= sh.size; ++i)
            {
                if (SHIFT_SYMBOL(sh, i) == error_image)
                    no_shift_on_error_sym[state_no] = FALSE;
            }
        }

    /**********************************************************************/
    /*   Compute whether this state is a final state.  I.e., a state that */
    /* contains only a single complete item. If so, mark it as a default  */
    /* state. Note that if the READ-REDUCE option is used, the automaton  */
    /* will not contain such states. Also, states are marked only when    */
    /* default actions are requested.                                     */
    /**********************************************************************/
        item_ptr = statset[state_no].kernel_items;
        item_no = item_ptr -> value;
        single_complete_item[state_no] =
               ((! read_reduce_bit) &&
                (! single_productions_bit) &&
                (table_opt != OPTIMIZE_TIME) &&
                (table_opt != OPTIMIZE_SPACE) &&
                (default_opt > 0) &&
                (item_ptr  -> next == NULL) &&
                (item_table[item_no].symbol == empty));

    /**********************************************************************/
    /* If a state has a complete item, and more than one kernel item      */
    /* which is different from the complete item, then this state         */
    /* requires look-ahead for the complete item.                         */
    /**********************************************************************/
        if (highest_level == 0)
        {
            r = statset[state_no].complete_items;
            if (r != NULL)
            {
                if (item_ptr -> next != NULL ||
                    item_ptr -> value != r -> value)
                    highest_level = 1;
            }
        }
    }

    /****************************************************************/
    /* We call COMPUTE_READ to perform the following tasks:         */
    /* 1) Count how many elements are needed in LA_ELEMENT: LA_TOP  */
    /* 2) Allocate space for and initialize LA_SET and LA_INDEX     */
    /****************************************************************/
    if (! slr_bit)
        compute_read();

    /****************************************************************/
    /* Allocate space for REDUCE which will be used to map each     */
    /* into its reduce map. We also initialize RULE_COUNT which     */
    /* will be used to count the number of reduce actions on each   */
    /* rule with in a given state.                                  */
    /****************************************************************/
    reduce = (struct reduce_header_type *)
             calloc(num_states + 1, sizeof(struct reduce_header_type));
    if (reduce == NULL)
        nospace(__FILE__, __LINE__);

    for ALL_RULES(i)
        rule_count[i] = 0;

    /****************************************************************/
    /* We are now ready to construct the reduce map. First, we      */
    /* initialize MAX_LA_STATE to NUM_STATES. If no lookahead       */
    /* state is added (the grammar is LALR(1)) this value will not  */
    /* change. Otherwise, MAX_LA_STATE is incremented by 1 for each */
    /* lookahead state added.                                       */
    /****************************************************************/
    max_la_state = num_states;

    /****************************************************************/
    /* We iterate over the states, compute the lookahead sets,      */
    /* resolve conflicts (if multiple lookahead is requested) and/or*/
    /* report the conflicts if requested...                         */
    /****************************************************************/
    for ALL_STATES(state_no)
    {
        struct reduce_header_type red;

        default_rule = OMEGA;
        symbol_root = NIL;

        item_ptr = statset[state_no].complete_items;
        if (item_ptr != NULL)
        {
    /**********************************************************************/
    /* Check if it is possible to take default reduction. The DEFAULT_OPT */
    /* parameter indicates what kind of default options are requested.    */
    /* The various values it can have are:                                */
    /*                                                                    */
    /*    a)   0 => no default reduction.                                 */
    /*    b)   1 => default reduction only on adequate states. I.e.,      */
    /*              states with only one complete item in their kernel.   */
    /*    c)   2 => Default on all states that contain exactly one        */
    /*              complete item not derived from an empty rule.         */
    /*    d)   3 => Default on all states that contain exactly one        */
    /*              complete item including items from empty rules.       */
    /*    e)   4 => Default reduction on all states that contain exactly  */
    /*              one item. If a state contains more than one item we   */
    /*              take Default on the item that generated the most      */
    /*              reductions. If there is a tie, one is selected at     */
    /*              random.                                               */
    /*    f)   5 => Same as 4 except that no default actions are computed */
    /*              for states that contain a shift action on the ERROR   */
    /*              symbol.                                               */
    /*                                                                    */
    /*  In the code below, we first check for category 3.  If it is not   */
    /* satisfied, then we check for the others. Note that in any case,    */
    /* default reductions are never taken on the ACCEPT rule.             */
    /*                                                                    */
    /**********************************************************************/
            item_no = item_ptr -> value;
            rule_no = item_table[item_no].rule_number;
            symbol = rules[rule_no].lhs;
            if (single_complete_item[state_no] && symbol != accept_image)
            {
                default_rule = rule_no;
                item_ptr = NULL; /* No need to check for conflicts */
            }

        /******************************************************************/
        /* Iterate over all complete items in the state, build action     */
        /* map, and check for conflicts.                                  */
        /******************************************************************/
            for (; item_ptr != NULL; item_ptr = item_ptr -> next)
            { /* for all complete items */
                item_no = item_ptr -> value;
                rule_no = item_table[item_no].rule_number;

                if (slr_bit)  /* SLR table? use Follow */
                {
                    ASSIGN_SET(look_ahead, 0, follow, rules[rule_no].lhs);
                }
                else
                    compute_la(state_no, item_no, look_ahead);

                for ALL_TERMINALS(symbol) /* for all symbols in la set */
                {
                    if (IS_ELEMENT(look_ahead, symbol))
                    {
                        p = Allocate_node();
                        p -> value = item_no;

                        if (action[symbol] == NULL)
                        {
                            symbol_list[symbol] = symbol_root;
                            symbol_root = symbol;
                        }
                        else
                        {
                            /**********************************************/
                            /* Always place the rule with the largest     */
                            /* right-hand side first in the list.         */
                            /**********************************************/
                            n = item_table[action[symbol]
                                                -> value].rule_number;
                            if (RHS_SIZE(n) >= RHS_SIZE(rule_no))
                            {
                                p -> value = action[symbol] -> value;
                                action[symbol] -> value = item_no;
                            }
                        }

                        p -> next = action[symbol];
                        action[symbol] = p;
                    }
                }
            }

        /******************************************************************/
        /* At this stage, we have constructed the ACTION map for STATE_NO.*/
        /* ACTION is a map from each symbol into a set of final items.    */
        /* The rules associated with these items are the rules by which   */
        /* to reduce when the lookahead is the symbol in question.        */
        /* SYMBOL_LIST/SYMBOL_ROOT is a list of the non-empty elements of */
        /* ACTION. If the number of elements in a set ACTION(t), for some */
        /* terminal t, is greater than one or it is not empty and STATE_NO*/
        /* contains a shift action on t then STATE_NO has one or more     */
        /* conflict(s). The procedure RESOLVE_CONFLICTS takes care of     */
        /* resolving the conflicts appropriately and returns an ACTION    */
        /* map where each element has either 0 (if the conflicts were     */
        /* shift-reduce conflicts, the shift is given precedence) or 1    */
        /* element (if the conflicts were reduce-reduce conflicts, only   */
        /* the first element in the ACTION(t) list is returned).          */
        /******************************************************************/
            if (symbol_root != NIL)
            {
                resolve_conflicts(state_no, action,
                                  symbol_list, symbol_root);

                for (symbol = symbol_root;
                     symbol != NIL; symbol = symbol_list[symbol])
                {
                    if (action[symbol] != NULL)
                    {
                        item_no = action[symbol] -> value;
                        rule_count[item_table[item_no].rule_number]++;
                    }
                }
            }
        }

    /*********************************************************************/
    /* We are now ready to compute the size of the reduce map for        */
    /* STATE_NO (reduce_size) and the default rule.                      */
    /* If the state being processed contains only a single complete item */
    /* then the DEFAULT_RULE was previously computed and the list of     */
    /* symbols is empty.                                                 */
    /* NOTE: a REDUCE_ELEMENT will be allocated for all states, even     */
    /* those that have no reductions at all. This will facilitate the    */
    /* Table Compression routines, for they can assume that such an      */
    /* object exists, and can be used for Default values.                */
    /*********************************************************************/
        reduce_size = 0;
        if (symbol_root != NIL)
        {
        /******************************************************************/
        /* Compute REDUCE_SIZE, the number of reductions in the state and */
        /* DEFAULT_RULE: the rule with the highest number of reductions   */
        /* to it.                                                         */
        /******************************************************************/
            n = 0;
            for (q = statset[state_no].complete_items;
                 q != NULL; q = q -> next)
            {
                item_no = q -> value;
                rule_no = item_table[item_no].rule_number;
                symbol = rules[rule_no].lhs;
                reduce_size += rule_count[rule_no];
                if ((rule_count[rule_no] > n) &&
                    (no_shift_on_error_sym[state_no]) &&
                    (symbol != accept_image))
                {
                    n = rule_count[rule_no];
                    default_rule = rule_no;
                }
            }

            /*********************************************************/
            /*   If the removal of single productions is requested   */
            /* and/or parsing tables will not be output, figure out  */
            /* if the level of the default option requested permits  */
            /* default actions, and compute how many reduce actions  */
            /* can be eliminated as a result.                        */
            /*********************************************************/
            if (default_opt == 0)
                default_rule = OMEGA;
            else if (table_opt != OPTIMIZE_TIME &&
                     table_opt != OPTIMIZE_SPACE &&
                     ! single_productions_bit)
            {
                q = statset[state_no].complete_items;
                if (q -> next == NULL)
                {
                    item_no = q -> value;
                    rule_no = item_table[item_no].rule_number;
                    if (default_opt > 2 ||  /* No empty rule defined */
                        (default_opt == 2 && RHS_SIZE(rule_no) != 0))
                        reduce_size -= n;
                    else
                        default_rule = OMEGA;
                }
                else if (default_opt > 3)
                    reduce_size -= n;
            }
            num_reductions += reduce_size;
        }

        /**************************************************************/
        /*   NOTE that the default fields are set for all states,     */
        /* whether or not DEFAULT actions are requested. This is      */
        /* all right since one can always check whether (DEFAULT > 0) */
        /* before using these fields.                                 */
        /**************************************************************/
        red = Allocate_reduce_map(reduce_size);
        reduce[state_no] = red;

        REDUCE_SYMBOL(red, 0)  = DEFAULT_SYMBOL;
        REDUCE_RULE_NO(red, 0) = default_rule;
        for (symbol = symbol_root;
             symbol != NIL; symbol = symbol_list[symbol])
        {
            if (action[symbol] != NULL)
            {
                rule_no = item_table[action[symbol] -> value].rule_number;
                if (rule_no != default_rule ||
                    table_opt == OPTIMIZE_SPACE ||
                    table_opt == OPTIMIZE_TIME  ||
                    single_productions_bit)
                {
                    REDUCE_SYMBOL(red, reduce_size)  = symbol;
                    REDUCE_RULE_NO(red, reduce_size) = rule_no;
                    reduce_size--;
                }

                free_nodes(action[symbol], action[symbol]);
                action[symbol] = NULL;
            }
        }

        /************************************************************/
        /* Reset RULE_COUNT elements used in this state.            */
        /************************************************************/
        for (q = statset[state_no].complete_items;
             q != NULL; q = q -> next)
        {
            rule_no = item_table[q -> value].rule_number;
            rule_count[rule_no] = 0;
        }
    } /* end for ALL_STATES*/

    printf("\n");
    fprintf(syslis,"\n\n");

/****************************************************************/
/* If the automaton required multiple lookahead, construct the  */
/* permanent lookahead states.                                  */
/****************************************************************/
    if (max_la_state > num_states)
        create_lastats();

/****************************************************************/
/* We are now finished with the LALR(k) construction of the     */
/* automaton. Clear all temporary space that was used in that   */
/* process and calculate the maximum lookahead level that was   */
/* needed.                                                      */
/****************************************************************/
    exit_lalrk_process();
    free_conflict_space();

    lalr_level = highest_level;

/****************************************************************/
/* If the removal of single productions is requested, do that.  */
/****************************************************************/
    if (single_productions_bit)
        remove_single_productions();

/****************************************************************/
/* If either more than one lookahead was needed or the removal  */
/* of single productions was requested, the automaton was       */
/* transformed with the addition of new states and new          */
/* transitions. In such a case, we reconstruct the IN_STAT map. */
/****************************************************************/
    if (lalr_level > 1 || single_productions_bit)
    {
        for ALL_STATES(state_no)
        { /* First, clear out the previous map */
            if (in_stat[state_no] != NULL)
            {
                q = in_stat[state_no] -> next; /* point to root */
                free_nodes(q, in_stat[state_no]);
                in_stat[state_no] = NULL;
            }
        }

        build_in_stat(); /* rebuild in_stat map */
    }

/******************************************************************/
/* Print informational messages and free all temporary space that */
/* was used to compute lookahead information.                     */
/******************************************************************/
    if (not_lrk)
    {
        printf("This grammar is not LR(K).\n");
        fprintf(syslis,"This grammar is not LR(K).\n");
    }
    else if (num_rr_conflicts > 0 || num_sr_conflicts > 0)
    {
        if (! slr_bit)
        {
            if (highest_level != INFINITY)
            {
                printf("This grammar is not LALR(%d).\n",
                       highest_level);
                fprintf(syslis,
                        "This grammar is not LALR(%d).\n",
                        highest_level);
            }
            else
            {
                printf("This grammar is not LALR(K).\n");
                fprintf(syslis,"This grammar is not LALR(K).\n");
            }
        }
        else
        {
            printf("This grammar is not SLR(1).\n");
            fprintf(syslis,"This grammar is not SLR(1).\n");
        }
    }
    else
    {
        if (highest_level == 0)
        {
            printf("This grammar is LR(0).\n");
            fprintf(syslis,"This grammar is LR(0).\n");
        }
        else if (slr_bit)
        {
            printf("This grammar is SLR(1).\n");
            fprintf(syslis,"This grammar is SLR(1).\n");
        }
        else
        {
            printf("This grammar is LALR(%d).\n", highest_level);
            fprintf(syslis,
                    "This grammar is LALR(%d).\n", highest_level);
        }
    }

    ffree(rule_count);
    ffree(no_shift_on_error_sym);
    ffree(symbol_list);
    ffree(single_complete_item);
    ffree(action);
    ffree(look_ahead);
    if (conflict_symbols != NULL)
        ffree(conflict_symbols);
    if (read_set != NULL)
        ffree(read_set);
    if (la_index != NULL)
        ffree(la_index);
    if (la_set != NULL)
        ffree(la_set);

    return;
} /* end mkrdcts */
