/* $Id: timetab.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 <string.h>
#include "common.h"
#include "header.h"

static int   default_saves = 0;
static short default_rule;

static BOOLEAN *is_terminal;

/*********************************************************************/
/*                            REMAP_SYMBOLS:                         */
/*********************************************************************/
/* We now remap the symbols in the unified Table based on frequency. */
/* We also remap the states based on frequency.                      */
/*********************************************************************/
static void remap_symbols(void)
{
    struct goto_header_type   go_to;
    struct shift_header_type  sh;
    struct reduce_header_type red;

    short *frequency_symbol,
          *frequency_count,
          *row_size;

    int symbol,
        state_no,
        i,
        j,
        k;

    ordered_state = Allocate_short_array(max_la_state + 1);
    symbol_map = Allocate_short_array(num_symbols + 1);
    is_terminal = Allocate_boolean_array(num_symbols + 1);
    frequency_symbol = Allocate_short_array(num_symbols + 1);
    frequency_count = Allocate_short_array(num_symbols + 1);
    row_size = Allocate_short_array(max_la_state + 1);

    fprintf(syslis, "\n");

/*********************************************************************/
/*     The variable FREQUENCY_SYMBOL is used to hold the symbols     */
/* in the grammar,  and the variable FREQUENCY_COUNT is used         */
/* correspondingly to hold the number of actions defined on each     */
/* symbol.                                                           */
/* ORDERED_STATE and ROW_SIZE are used in a similar fashion for      */
/* states.                                                           */
/*********************************************************************/
    for (i = 1; i <= num_symbols; i++)
    {
        frequency_symbol[i] = i;
        frequency_count[i] = 0;
    }
    for ALL_STATES(state_no)
    {
        ordered_state[state_no] = state_no;
        row_size[state_no] = 0;
        sh = shift[statset[state_no].shift_number];
        for (i = 1; i <= sh.size; i++)
        {
            row_size[state_no]++;
            symbol = SHIFT_SYMBOL(sh, i);
            frequency_count[symbol]++;
        }

        go_to =  statset[state_no].go_to;
        for (i = 1; i <= go_to.size; i++)
        {
            row_size[state_no]++;
            symbol = GOTO_SYMBOL(go_to, i);
            frequency_count[symbol]++;
        }

        red =  reduce[state_no];
        default_rule = REDUCE_RULE_NO(red, 0);
        for (i = 1; i <= red.size; i++)
        {
            if (REDUCE_RULE_NO(red, i) != default_rule)
            {
                row_size[state_no]++;
                symbol = REDUCE_SYMBOL(red, i);
                frequency_count[symbol]++;
            }
            else
                default_saves++;
        }
    }
    sprintf(msg_line,
            "Number of Reductions saved by default: %d", default_saves);
    PRNT(msg_line);

    for ALL_LA_STATES(state_no)
    {
        ordered_state[state_no] = state_no;
        row_size[state_no] = 0;
        sh = shift[lastats[state_no].shift_number];
        for (i = 1; i <= sh.size; i++)
        {
            row_size[state_no]++;
            symbol = SHIFT_SYMBOL(sh, i);
            frequency_count[symbol]++;
        }
        red =  lastats[state_no].reduce;
        default_rule = REDUCE_RULE_NO(red, 0);
        for (i = 1; i <= red.size; i++)
        {
            if (REDUCE_RULE_NO(red, i) != default_rule)
            {
                row_size[state_no]++;
                symbol = REDUCE_SYMBOL(red, i);
                frequency_count[symbol]++;
            }
            else
                default_saves++;
        }
    }

 /*********************************************************************/
 /*     The non-terminals are sorted in descending order based on the */
 /* number of actions defined on them.                                */
 /*     The terminals are sorted in descending order based on the     */
 /* number of actions defined on them.                                */
 /*********************************************************************/
    sortdes(frequency_symbol, frequency_count,
            1, num_terminals, max_la_state);

    sortdes(frequency_symbol, frequency_count,
            num_terminals + 1, num_symbols, max_la_state);

    for (last_symbol = num_symbols;
         last_symbol > num_terminals; last_symbol--)
         if (frequency_count[last_symbol] != 0)
             break;

/*********************************************************************/
/* We now merge the two sorted arrays of symbols giving precedence to*/
/* the terminals.  Note that we can guarantee that the terminal array*/
/* will be depleted first since it has precedence, and we know that  */
/* there exists at least one non-terminal: the accept non-terminal,  */
/* on which no action is defined.                                    */
/* As we merge the symbols, we keep track of which ones are terminals*/
/* and which ones are non-terminals.  We also keep track of the new  */
/* mapping for the symbols in SYMBOL_MAP.                            */
/*********************************************************************/
    i = 1;
    j = num_terminals + 1;
    k = 0;
    while (i <= num_terminals)
    {
        k++;
        if (frequency_count[i] >= frequency_count[j])
        {
            symbol = frequency_symbol[i];
            is_terminal[k] = TRUE;
            i++;
        }
        else
        {
            symbol = frequency_symbol[j];
            is_terminal[k] = FALSE;
            j++;
        }
        symbol_map[symbol] = k;
    }
    symbol_map[DEFAULT_SYMBOL] = DEFAULT_SYMBOL;

/*********************************************************************/
/* Process the remaining non-terminal and useless terminal symbols.  */
/*********************************************************************/
    for (; j <= num_symbols; j++)
    {
        k++;
        symbol = frequency_symbol[j];
        is_terminal[k] = FALSE;
        symbol_map[symbol] = k;
    }

    eoft_image = symbol_map[eoft_image];
    if (error_maps_bit)
    {
        error_image = symbol_map[error_image];
        eolt_image = symbol_map[eolt_image];
    }

/*********************************************************************/
/*    All symbol entries in the state automaton are updated based on */
/* the new mapping of the symbols.                                   */
/* The states are sorted in descending order based on the number of  */
/* actions defined on them.                                          */
/*********************************************************************/
    for ALL_STATES(state_no)
    {
        go_to =  statset[state_no].go_to;
        for (i = 1; i <= go_to.size; i++)    /* Remap Goto map */
            GOTO_SYMBOL(go_to, i) = symbol_map[GOTO_SYMBOL(go_to, i)];
        red =  reduce[state_no];
        for (i = 1; i <= red.size; i++)
            REDUCE_SYMBOL(red, i) = symbol_map[REDUCE_SYMBOL(red, i)];
    }

    for ALL_LA_STATES(state_no)
    {
        red =  lastats[state_no].reduce;
        for (i = 1; i <= red.size; i++)
            REDUCE_SYMBOL(red, i) = symbol_map[REDUCE_SYMBOL(red, i)];
    }

    for (i = 1; i <= num_shift_maps; i++)
    {
        sh = shift[i];
        for (j = 1; j <= sh.size; j++)
            SHIFT_SYMBOL(sh, j) = symbol_map[SHIFT_SYMBOL(sh, j)];
    }

    sortdes(ordered_state, row_size, 1, max_la_state, num_symbols);

    ffree(frequency_symbol);
    ffree(frequency_count);
    ffree(row_size);

    return;
}


/*********************************************************************/
/*                          OVERLAP_TABLES:                          */
/*********************************************************************/
/* We now overlap the State automaton table, or more precisely,  we  */
/* compute the starting position in a vector where each of its rows  */
/* may be placed without clobbering elements in another row.         */
/* The starting positions are stored in the vector STATE_INDEX.      */
/*********************************************************************/
static void overlap_tables(void)
{
    struct goto_header_type  go_to;
    struct shift_header_type  sh;
    struct reduce_header_type red;

    short *symbol_list;

    int symbol,
        state_no,
        root_symbol,
        max_indx,
        indx,
        percentage,
        k_bytes,
        k,
        i;

    long num_bytes;

    state_index = Allocate_int_array(max_la_state + 1);

    symbol_list = Allocate_short_array(num_symbols + 1);

    num_entries -= default_saves;
    increment_size = MAX((num_entries*increment/100), (num_symbols + 1));
    table_size = MIN((num_entries + increment_size), MAX_TABLE_SIZE);

/*********************************************************************/
/* Allocate space for table, and initialize the AVAIL_POOL list.     */
/* The variable FIRST_INDEX keeps track of the first element in the  */
/* doubly-linked list, and LAST_ELEMENT keeps track of the last      */
/* element in the list.                                              */
/* The variable MAX_INDX is used to keep track of the maximum        */
/* starting position for a row that has been used.                   */
/*********************************************************************/
    next = Allocate_int_array(table_size + 1);
    previous = Allocate_int_array(table_size + 1);

    first_index = 1;
    next[first_index] = first_index + 1; /* Should be constant-folded */
    previous[first_index] = NIL;
    for (indx = 2; indx < (int) table_size; indx++)
    {
        next[indx] = indx + 1;
        previous[indx] = indx - 1;
    }
    last_index = table_size;
    previous[last_index] = last_index - 1;
    next[last_index] = NIL;

    max_indx = first_index;

/*********************************************************************/
/* We now iterate over all the states in their new sorted order as   */
/* indicated by the variable STATE_NO, and deternime an "overlap"    */
/* position for them.                                                */
/*********************************************************************/
    for (k = 1; k <= (int) max_la_state; k++)
    {
        state_no = ordered_state[k];

/*********************************************************************/
/* First, we iterate over all actions defined in STATE_NO, and       */
/* create a set with all the symbols involved.                       */
/*********************************************************************/
        root_symbol = NIL;
        if (state_no > (int) num_states)
        {
            sh = shift[lastats[state_no].shift_number];
            red = lastats[state_no].reduce;
        }
        else
        {
            go_to = statset[state_no].go_to;
            for (i = 1; i <= go_to.size; i++)
            {
                symbol = GOTO_SYMBOL(go_to, i);
                symbol_list[symbol] = root_symbol;
                root_symbol = symbol;
            }
            sh = shift[statset[state_no].shift_number];
            red = reduce[state_no];
        }

        for (i = 1; i <= sh.size; i++)
        {
            symbol = SHIFT_SYMBOL(sh, i);
            symbol_list[symbol] = root_symbol;
            root_symbol = symbol;
        }
        symbol_list[0] = root_symbol;
        root_symbol = 0;

        default_rule = REDUCE_RULE_NO(red, 0);
        for (i = 1; i <= red.size; i++)
        {
            if (REDUCE_RULE_NO(red, i) != default_rule)
            {
                symbol = REDUCE_SYMBOL(red, i);
                symbol_list[symbol] = root_symbol;
                root_symbol = symbol;
            }
        }

/*********************************************************************/
/* INDX is set to the beginning of the list of available slots and   */
/* we try to determine if it might be a valid starting position. If  */
/* not, INDX is moved to the next element, and we repeat the process */
/* until a valid position is found.                                  */
/*********************************************************************/
        indx = first_index;

look_for_match_in_table:
        if (indx == NIL)
            indx = table_size + 1;
        if (indx + num_symbols > (int) table_size)
            reallocate();

        for (symbol = root_symbol;
             symbol != NIL; symbol = symbol_list[symbol])
        {
            if (next[indx + symbol] == OMEGA)
            {
                indx = next[indx];
                goto look_for_match_in_table;
            }
        }

/*********************************************************************/
/* At this stage, a position(INDX), was found to overlay the row in  */
/* question.  Remove elements associated with all positions that     */
/* will be taken by row from the doubly-linked list.                 */
/* NOTE that since SYMBOLs start at 1, the first index can never be  */
/* a candidate (==> I = INDX + SYMBOL) in this loop.                 */
/*********************************************************************/
        if (indx > max_indx)
            max_indx = indx;

        state_index[state_no] = indx;

        for (symbol = root_symbol;
             symbol != NIL; symbol = symbol_list[symbol])
        {
            i = indx + symbol;
            if (first_index == last_index)
                first_index = NIL;
            else if (i == first_index)
            {
                first_index = next[first_index];
                previous[first_index] = NIL;
            }
            else if (i == last_index)
            {
                last_index = previous[last_index];
                next[last_index] = NIL;
            }
            else
            {
                next[previous[i]] = next[i];
                previous[next[i]] = previous[i];
            }
            next[i] = OMEGA;
        }
    }

/*********************************************************************/
/* Update all global counters, and compute ACCEPT_ACTION and         */
/* ERROR_ACTION.                                                     */
/*********************************************************************/
    table_size = max_indx + num_symbols;
    accept_act = max_indx + num_rules + 1;
    error_act = accept_act + 1;

    for (action_size = table_size; action_size >= max_indx; action_size--)
         if (next[action_size] == OMEGA)
             break;

    printf("\n");
    sprintf(msg_line,"Length of Check table: %ld", table_size);
    PRNT(msg_line);

    sprintf(msg_line,"Length of Action table: %ld", action_size);
    PRNT(msg_line);

    sprintf(msg_line,
            "Number of entries in Action Table: %d", num_entries);
    PRNT(msg_line);

    percentage = ((action_size - num_entries) * 1000) / num_entries;
    sprintf(msg_line, "Percentage of increase: %d.%d%%",
                      percentage / 10, percentage % 10);
    PRNT(msg_line);

    if (byte_bit)
    {
        num_bytes = 2 * action_size + table_size;
        if ((! goto_default_bit) && (! nt_check_bit))
        {
            for (; (last_symbol >= 1) && (! is_terminal[last_symbol]);
                last_symbol--);
        }
        sprintf(msg_line,
                "Highest symbol in Check Table: %d", last_symbol);
        PRNT(msg_line);
        if (last_symbol > 255)
            num_bytes += table_size;
    }
    else
        num_bytes = 2 * (action_size + table_size);

    if (goto_default_bit)
        num_bytes += ((long) 2 * num_symbols);

    k_bytes = (num_bytes / 1024) + 1;

    sprintf(msg_line,
            "Storage Required for Tables: %ld Bytes, %dK",
            num_bytes, k_bytes);
    PRNT(msg_line);

    num_bytes = (long) 4 * num_rules;
    if (byte_bit)
    {
        num_bytes -= num_rules;
        if (num_symbols < 256)
            num_bytes -= num_rules;
    }
    sprintf(msg_line,
            "Storage Required for Rules: %ld Bytes", num_bytes);
    PRNT(msg_line);

    return;
}


/*********************************************************************/
/*                         PRINT_TABLES:                             */
/*********************************************************************/
/* We now write out the tables to the SYSTAB file.                   */
/*********************************************************************/
static void print_tables(void)
{
    int *action,
        *check;

    struct goto_header_type   go_to;
    struct shift_header_type  sh;
    struct reduce_header_type red;

    int la_shift_count = 0,
        shift_count = 0,
        goto_count = 0,
        default_count = 0,
        reduce_count = 0,
        shift_reduce_count = 0,
        goto_reduce_count = 0;

    int indx,
        la_state_offset,
        act,
        result_act,
        i,
        j,
        k,
        symbol,
        state_no;

    char *tok;

    long offset;

    state_list = Allocate_short_array(max_la_state + 1);

    check = next;
    action = previous;

    offset = error_act;
    if (read_reduce_bit)
        offset += num_rules;
    la_state_offset = offset;

    if (offset > (MAX_TABLE_SIZE + 1))
    {
        sprintf(msg_line, "Table contains entries that are > "
                "%d; Processing stopped.", MAX_TABLE_SIZE + 1);
        PRNTERR(msg_line);
        exit(12);
    }

/*********************************************************************/
/* Initialize all unfilled slots with default values.                */
/*********************************************************************/
    indx = first_index;
    for (i = indx; (i != NIL) && (i <= (int) action_size); i = indx)
    {
        indx = next[i];

        check[i] = DEFAULT_SYMBOL;
        action[i] = error_act;
    }
    for (i = (int) action_size + 1; i <= (int) table_size; i++)
        check[i] = DEFAULT_SYMBOL;

/*********************************************************************/
/* We set the rest of the table with the proper table entries.       */
/*********************************************************************/
    for (state_no = 1; state_no <= (int) max_la_state; state_no++)
    {
        indx = state_index[state_no];
        if (state_no > (int) num_states)
        {
            sh = shift[lastats[state_no].shift_number];
            red = lastats[state_no].reduce;
        }
        else
        {
            go_to = statset[state_no].go_to;
            for (j = 1; j <= go_to.size; j++)
            {
                symbol = GOTO_SYMBOL(go_to, j);
                i = indx + symbol;
                if (goto_default_bit || nt_check_bit)
                    check[i] = symbol;
                else
                    check[i] = DEFAULT_SYMBOL;
                act = GOTO_ACTION(go_to, j);
                if (act > 0)
                {
                    action[i] = state_index[act] + num_rules;
                    goto_count++;
                }
                else
                {
                    action[i] = -act;
                    goto_reduce_count++;
                }
            }
            sh = shift[statset[state_no].shift_number];
            red = reduce[state_no];
        }

        for (j = 1; j <= sh.size; j++)
        {
            symbol = SHIFT_SYMBOL(sh, j);
            i = indx + symbol;
            check[i] = symbol;
            act = SHIFT_ACTION(sh, j);
            if (act > (int) num_states)
            {
                result_act = la_state_offset + state_index[act];
                la_shift_count++;
            }
            else if (act > 0)
            {
                result_act = state_index[act] + num_rules;
                shift_count++;
            }
            else
            {
                result_act = -act + error_act;
                shift_reduce_count++;
            }

            if (result_act > (MAX_TABLE_SIZE + 1))
            {
                sprintf(msg_line,
                    "Table contains look-ahead shift entry that is >"
                    " %d; Processing stopped.", MAX_TABLE_SIZE + 1);
                PRNTERR(msg_line);
                return;
            }

            action[i] = result_act;
        }

/*********************************************************************/
/*   We now initialize the elements reserved for reduce actions in   */
/* the current state.                                                */
/*********************************************************************/
        default_rule = REDUCE_RULE_NO(red, 0);
        for (j = 1; j <= red.size; j++)
        {
            if (REDUCE_RULE_NO(red, j) != default_rule)
            {
                symbol = REDUCE_SYMBOL(red, j);
                i = indx + symbol;
                check[i] = symbol;
                act = REDUCE_RULE_NO(red, j);
                if (rules[act].lhs == accept_image)
                    action[i] = accept_act;
                else
                    action[i] = act;
                reduce_count++;
            }
        }

/*********************************************************************/
/*   We now initialize the element reserved for the DEFAULT reduce   */
/* action of the current state.  If error maps are requested,  the   */
/* default slot is initialized to the original state number, and the */
/* corresponding element of the DEFAULT_REDUCE array is initialized. */
/* Otherwise it is initialized to the rule number in question.       */
/*********************************************************************/
        i = indx + DEFAULT_SYMBOL;
        check[i] = DEFAULT_SYMBOL;
        act = REDUCE_RULE_NO(red, 0);
        if (act == OMEGA)
            action[i] = error_act;
        else
        {
            action[i] = act;
            default_count++;
        }
    }

    PRNT("\n\nActions in Compressed Tables:");
    sprintf(msg_line,"     Number of Shifts: %d",shift_count);
    PRNT(msg_line);

    sprintf(msg_line,"     Number of Shift/Reduces: %d",shift_reduce_count);
    PRNT(msg_line);

    if (max_la_state > num_states)
    {
        sprintf(msg_line,
                "     Number of Look-Ahead Shifts: %d", la_shift_count);
        PRNT(msg_line);
    }

    sprintf(msg_line,"     Number of Gotos: %d",goto_count);
    PRNT(msg_line);

    sprintf(msg_line,
            "     Number of Goto/Reduces: %d",goto_reduce_count);
    PRNT(msg_line);

    sprintf(msg_line,"     Number of Reduces: %d",reduce_count);
    PRNT(msg_line);

    sprintf(msg_line,"     Number of Defaults: %d",default_count);
    PRNT(msg_line);

/*********************************************************************/
/* Prepare Header with proper information, and write it out.         */
/*********************************************************************/
    output_buffer[0] = 'T';
    output_buffer[1] = (goto_default_bit ? '1' : '0');
    output_buffer[2] = (nt_check_bit ? '1' : '0');
    output_buffer[3] = (read_reduce_bit ? '1' : '0');
    output_buffer[4] = (single_productions_bit ? '1' : '0');
    if (default_opt == 0)
        output_buffer[5] = '0';
    else if (default_opt == 1)
        output_buffer[5] = '1';
    else if (default_opt == 2)
        output_buffer[5] = '2';
    else if (default_opt == 3)
        output_buffer[5] = '3';
    else if (default_opt == 4)
        output_buffer[5] = '4';
    else
        output_buffer[5] = '5';
    output_buffer[6] = (rules[1].lhs == accept_image ? '1' : '0');
    output_buffer[7] = (error_maps_bit ? '1' : '0');
    output_buffer[8] = (byte_bit && last_symbol <= 255 ? '1' : '0');
    output_buffer[9] = escape;

    output_ptr = &output_buffer[0] + 10;
    field(num_terminals, 5);
    field(num_symbols, 5);
    field(num_rules, 5);
    field(num_states, 5);
    field(table_size, 5);
    field(action_size, 5);
    field(state_index[1] + num_rules, 5);
    field(eoft_image, 5);
    field(accept_act, 5);
    field(error_act, 5);
    field(la_state_offset, 5);
    field(lalr_level, 5);
    *output_ptr++ = '\n';

    /*********************************************************/
    /* We write the terminal symbols map.                    */
    /*********************************************************/
    for (symbol = 1; symbol <= num_symbols; symbol++)
    {
        if (is_terminal[symbol_map[symbol]])
        {
            int len;

            if (last_terminal < symbol_map[symbol])
                last_terminal = symbol_map[symbol];
            tok = RETRIEVE_STRING(symbol);
            if (tok[0] == '\n')  /* We're dealing with special symbol?  */
                tok[0] = escape; /* replace initial marker with escape. */
            len = strlen(tok);
            field(symbol_map[symbol], 4);
            field(len, 4);
            if (len <= 64)
                strcpy(output_ptr, tok);
            else
            {
                memcpy(output_ptr, tok, 64);
                output_ptr += 64;
                *output_ptr++ = '\n';
                *output_ptr = '\0';
                BUFFER_CHECK(systab);
                tok += 64;
                for (len = strlen(tok); len > 72; len = strlen(tok))
                {
                    memcpy(output_ptr, tok, 72);
                    output_ptr += 72;
                    *output_ptr++ = '\n';
                    BUFFER_CHECK(systab);
                    tok += 72;
                }
                memcpy(output_ptr, tok, len);
            }
            output_ptr += len;
            *output_ptr++ = '\n';
            BUFFER_CHECK(systab);
        }
    }

    /*********************************************************/
    /* We write the non-terminal symbols map.                */
    /*********************************************************/
    for (symbol = 1; symbol <= num_symbols; symbol++)
    {
        if (! is_terminal[symbol_map[symbol]])
        {
            int len;

            if (last_non_terminal < symbol_map[symbol])
                last_non_terminal = symbol_map[symbol];
            tok = RETRIEVE_STRING(symbol);
            if (tok[0] == '\n')  /* we're dealing with special symbol?  */
                tok[0] = escape; /* replace initial marker with escape. */
            len = strlen(tok);
            field(symbol_map[symbol], 4);
            field(len, 4);
            if (len <= 64)
                strcpy(output_ptr, tok);
            else
            {
                memcpy(output_ptr, tok, 64);
                output_ptr += 64;
                *output_ptr++ = '\n';
                BUFFER_CHECK(systab);
                tok += 64;
                for (len = strlen(tok); len > 72; len = strlen(tok))
                {
                    memcpy(output_ptr, tok, 72);
                    output_ptr += 72;
                    *output_ptr++ = '\n';
                    BUFFER_CHECK(systab);
                    tok += 72;
                }
                memcpy(output_ptr, tok, len);
            }
            output_ptr += len;
            *output_ptr++ = '\n';
            BUFFER_CHECK(systab);
        }
    }

    /*********************************************************************/
    /* Write size of right hand side of rules followed by CHECK table.   */
    /*********************************************************************/
    k = 0;
    for (i = 1; i <= num_rules; i++)
    {
        field(RHS_SIZE(i), 4);
        k++;
        if (k == 18)
        {
            *output_ptr++ = '\n';
            BUFFER_CHECK(systab);
            k = 0;
        }
    }

    for (i = 1; i <= (int) table_size; i++)
    {
        field(check[i], 4);
        k++;
        if (k == 18)
        {
            *output_ptr++ = '\n';
            BUFFER_CHECK(systab);
            k = 0;
        }
    }

    if (k != 0)
    {
        *output_ptr++ = '\n';
        BUFFER_CHECK(systab);
    }

    /*********************************************************************/
    /* Write left hand side symbol of rules followed by ACTION table.    */
    /*********************************************************************/
    k = 0;
    for (i = 1; i <= num_rules; i++)
    {
        field(symbol_map[rules[i].lhs], 6);
        k++;
        if (k == 12)
        {
            *output_ptr++ = '\n';
            BUFFER_CHECK(systab);
            k = 0;
        }
    }

    for (i = 1; i <= (int) action_size; i++)
    {
        field(action[i], 6);
        k++;
        if (k == 12)
        {
            *output_ptr++ = '\n';
            BUFFER_CHECK(systab);
            k = 0;
        }
    }

    if (k != 0)
    {
        *output_ptr++ = '\n';
        BUFFER_CHECK(systab);
    }

    /******************************************************************/
    /* If GOTO_DEFAULT is requested, we print out the GOTODEF vector  */
    /* after rearranging its elements based on the new ordering of the*/
    /* symbols.  The array TEMP is used to hold the GOTODEF values.   */
    /******************************************************************/
    if (goto_default_bit)
    {
        short *default_map;

        default_map = Allocate_short_array(num_symbols + 1);

        for (i = 0; i <= num_symbols; i++)
           default_map[i] = error_act;

        for ALL_NON_TERMINALS(symbol)
        {
            act = gotodef[symbol];
            if (act < 0)
                result_act = -act;
            else if (act > 0)
                result_act = state_index[act] + num_rules;
            else
                result_act = error_act;
            default_map[symbol_map[symbol]] = result_act;
        }

        k = 0;
        for (symbol = 1; symbol <= num_symbols; symbol++)
        {
            k++;
            field(default_map[symbol], 6);
            if (k == 12)
            {
                *output_ptr++ = '\n';
                BUFFER_CHECK(systab);
                k = 0;
            }
        }

        if (k != 0)
        {
            *output_ptr++ = '\n';
            BUFFER_CHECK(systab);
        }
    }

/*********************************************************************/
/* We first sort the new state numbers.  A bucket sort technique     */
/* is used using the ACTION vector as a base to simulate the         */
/* buckets.  NOTE: the iteration over the buckets is done backward   */
/* because we also construct a list of the original state numbers    */
/* that reflects the permutation of the new state numbers.           */
/* During the backward iteration,  we construct the list as a stack. */
/*********************************************************************/
    if (error_maps_bit || states_bit)
    {
        int max_indx;

        max_indx = accept_act - num_rules - 1;
        for (i = 1; i <= max_indx; i++)
            action[i] = OMEGA;
        for ALL_STATES(state_no)
            action[state_index[state_no]] = state_no;

        j = num_states + 1;
        for (i = max_indx; i >= 1; i--)
        {
            state_no = action[i];
            if (state_no != OMEGA)
            {
                j--;
                ordered_state[j] = i + num_rules;
                state_list[j] = state_no;
            }
        }
    }

    ffree(next);
    ffree(previous);

/*********************************************************************/
/* If ERROR_MAPS are requested, we print them out in the following   */
/* order:                                                            */
/*                                                                   */
/*    1) The FOLLOW map (NEWFOLL)                                    */
/*    2) The SORTED_STATE vector                                     */
/*    3) The ORIGINAL_STATE vector                                   */
/*    4) The map from states into valid symbols on which actions are */
/*       defined within the state in question: ACTION_SYMBOLS        */
/*    5) The map from each symbol into the set of states that can    */
/*       possibly be reached after a transition on the symbol in     */
/*       question: TRANSITION_STATES                                 */
/*                                                                   */
/*********************************************************************/
    if (error_maps_bit)
        process_error_maps();

    fwrite(output_buffer, sizeof(char),
           output_ptr - &output_buffer[0], systab);

    return;
}


/*********************************************************************/
/*                            CMPRTIM:                               */
/*********************************************************************/
/* In this routine we compress the State tables and write them out   */
/* to a file.  The emphasis here is in generating tables that allow  */
/* fast access. The terminal and non-terminal tables are compressed  */
/* together, so as to achieve maximum speed efficiency.              */
/* Otherwise, the compression technique used in this table is        */
/* analoguous to the technique used in the routine CMPRSPA.          */
/*********************************************************************/
void cmprtim(void)
{
    remap_symbols();
    overlap_tables();
    if (c_bit || cpp_bit || java_bit)
        print_time_parser();
    else
        print_tables();

    return;
}
