root/usr.bin/lex/gen.c
/*      $OpenBSD: gen.c,v 1.16 2024/11/09 18:03:44 op Exp $     */

/* gen - actual generation (writing) of flex scanners */

/*  Copyright (c) 1990 The Regents of the University of California. */
/*  All rights reserved. */

/*  This code is derived from software contributed to Berkeley by */
/*  Vern Paxson. */

/*  The United States Government has rights in this work pursuant */
/*  to contract no. DE-AC03-76SF00098 between the United States */
/*  Department of Energy and the University of California. */

/*  This file is part of flex. */

/*  Redistribution and use in source and binary forms, with or without */
/*  modification, are permitted provided that the following conditions */
/*  are met: */

/*  1. Redistributions of source code must retain the above copyright */
/*     notice, this list of conditions and the following disclaimer. */
/*  2. Redistributions in binary form must reproduce the above copyright */
/*     notice, this list of conditions and the following disclaimer in the */
/*     documentation and/or other materials provided with the distribution. */

/*  Neither the name of the University nor the names of its contributors */
/*  may be used to endorse or promote products derived from this software */
/*  without specific prior written permission. */

/*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/*  PURPOSE. */

#include "flexdef.h"
#include "tables.h"


/* declare functions that have forward references */

void gen_next_state PROTO((int));
void genecs PROTO((void));
void indent_put2s PROTO((const char *, const char *));
void indent_puts PROTO((const char *));


static int indent_level = 0;    /* each level is 8 spaces */

#define indent_up() (++indent_level)
#define indent_down() (--indent_level)
#define set_indent(indent_val) indent_level = indent_val

/* Almost everything is done in terms of arrays starting at 1, so provide
 * a null entry for the zero element of all C arrays.  (The exception
 * to this is that the fast table representation generally uses the
 * 0 elements of its arrays, too.)
 */

static const char *
get_int16_decl(void)
{
        return (gentables)
        ? "static yyconst flex_int16_t %s[%d] =\n    {   0,\n"
        : "static yyconst flex_int16_t * %s = 0;\n";
}


static const char *
get_int32_decl(void)
{
        return (gentables)
        ? "static yyconst flex_int32_t %s[%d] =\n    {   0,\n"
        : "static yyconst flex_int32_t * %s = 0;\n";
}

static const char *
get_state_decl(void)
{
        return (gentables)
        ? "static yyconst yy_state_type %s[%d] =\n    {   0,\n"
        : "static yyconst yy_state_type * %s = 0;\n";
}

/* Indent to the current level. */

void 
do_indent(void)
{
        int i = indent_level * 8;

        while (i >= 8) {
                outc('\t');
                i -= 8;
        }

        while (i > 0) {
                outc(' ');
                --i;
        }
}


/** Make the table for possible eol matches.
 *  @return the newly allocated rule_can_match_eol table
 */
static struct yytbl_data *
mkeoltbl(void)
{
        int i;
        flex_int8_t *tdata = NULL;
        struct yytbl_data *tbl;

        tbl = calloc(1, sizeof(struct yytbl_data));
        yytbl_data_init(tbl, YYTD_ID_RULE_CAN_MATCH_EOL);
        tbl->td_flags = YYTD_DATA8;
        tbl->td_lolen = num_rules + 1;
        tbl->td_data = tdata =
            calloc(tbl->td_lolen, sizeof(flex_int8_t));

        for (i = 1; i <= num_rules; i++)
                tdata[i] = rule_has_nl[i] ? 1 : 0;

        buf_prints(&yydmap_buf,
            "\t{YYTD_ID_RULE_CAN_MATCH_EOL, (void**)&yy_rule_can_match_eol, sizeof(%s)},\n",
            "flex_int32_t");
        return tbl;
}

/* Generate the table for possible eol matches. */
static void 
geneoltbl(void)
{
        int i;

        outn("m4_ifdef( [[M4_YY_USE_LINENO]],[[");
        outn("/* Table of booleans, true if rule could match eol. */");
        out_str_dec(get_int32_decl(), "yy_rule_can_match_eol",
            num_rules + 1);

        if (gentables) {
                for (i = 1; i <= num_rules; i++) {
                        out_dec("%d, ", rule_has_nl[i] ? 1 : 0);
                        /* format nicely, 20 numbers per line. */
                        if ((i % 20) == 19)
                                out("\n    ");
                }
                out("    };\n");
        }
        outn("]])");
}


/* Generate the code to keep backing-up information. */

void 
gen_backing_up(void)
{
        if (reject || num_backing_up == 0)
                return;

        if (fullspd)
                indent_puts("if ( yy_current_state[-1].yy_nxt )");
        else
                indent_puts("if ( yy_accept[yy_current_state] )");

        indent_up();
        indent_puts("{");
        indent_puts("YY_G(yy_last_accepting_state) = yy_current_state;");
        indent_puts("YY_G(yy_last_accepting_cpos) = yy_cp;");
        indent_puts("}");
        indent_down();
}


/* Generate the code to perform the backing up. */

void 
gen_bu_action(void)
{
        if (reject || num_backing_up == 0)
                return;

        set_indent(3);

        indent_puts("case 0: /* must back up */");
        indent_puts("/* undo the effects of YY_DO_BEFORE_ACTION */");
        indent_puts("*yy_cp = YY_G(yy_hold_char);");

        if (fullspd || fulltbl)
                indent_puts("yy_cp = YY_G(yy_last_accepting_cpos) + 1;");
        else
                /*
                 * Backing-up info for compressed tables is taken \after/
                 * yy_cp has been incremented for the next state.
                 */
                indent_puts("yy_cp = YY_G(yy_last_accepting_cpos);");

        indent_puts("yy_current_state = YY_G(yy_last_accepting_state);");
        indent_puts("goto yy_find_action;");
        outc('\n');

        set_indent(0);
}

/** mkctbl - make full speed compressed transition table
 * This is an array of structs; each struct a pair of integers.
 * You should call mkssltbl() immediately after this.
 * Then, I think, mkecstbl(). Arrrg.
 * @return the newly allocated trans table
 */

static struct yytbl_data *
mkctbl(void)
{
        int i;
        struct yytbl_data *tbl = NULL;
        flex_int32_t *tdata = NULL, curr = 0;
        int end_of_buffer_action = num_rules + 1;

        buf_prints(&yydmap_buf,
            "\t{YYTD_ID_TRANSITION, (void**)&yy_transition, sizeof(%s)},\n",
            ((tblend + numecs + 1) >= INT16_MAX
                || long_align) ? "flex_int32_t" : "flex_int16_t");

        tbl = calloc(1, sizeof(struct yytbl_data));
        yytbl_data_init(tbl, YYTD_ID_TRANSITION);
        tbl->td_flags = YYTD_DATA32 | YYTD_STRUCT;
        tbl->td_hilen = 0;
        tbl->td_lolen = tblend + numecs + 1;    /* number of structs */

        tbl->td_data = tdata =
            calloc(tbl->td_lolen * 2, sizeof(flex_int32_t));

        /*
         * We want the transition to be represented as the offset to the next
         * state, not the actual state number, which is what it currently is.
         * The offset is base[nxt[i]] - (base of current state)].  That's
         * just the difference between the starting points of the two
         * involved states (to - from).
         * 
         * First, though, we need to find some way to put in our end-of-buffer
         * flags and states.  We do this by making a state with absolutely no
         * transitions.  We put it at the end of the table.
         */

        /*
         * We need to have room in nxt/chk for two more slots: One for the
         * action and one for the end-of-buffer transition.  We now *assume*
         * that we're guaranteed the only character we'll try to index this
         * nxt/chk pair with is EOB, i.e., 0, so we don't have to make sure
         * there's room for jam entries for other characters.
         */

        while (tblend + 2 >= current_max_xpairs)
                expand_nxt_chk();

        while (lastdfa + 1 >= current_max_dfas)
                increase_max_dfas();

        base[lastdfa + 1] = tblend + 2;
        nxt[tblend + 1] = end_of_buffer_action;
        chk[tblend + 1] = numecs + 1;
        chk[tblend + 2] = 1;    /* anything but EOB */

        /* So that "make test" won't show arb. differences. */
        nxt[tblend + 2] = 0;

        /*
         * Make sure every state has an end-of-buffer transition and an
         * action #.
         */
        for (i = 0; i <= lastdfa; ++i) {
                int anum = dfaacc[i].dfaacc_state;
                int offset = base[i];

                chk[offset] = EOB_POSITION;
                chk[offset - 1] = ACTION_POSITION;
                nxt[offset - 1] = anum; /* action number */
        }

        for (i = 0; i <= tblend; ++i) {
                if (chk[i] == EOB_POSITION) {
                        tdata[curr++] = 0;
                        tdata[curr++] = base[lastdfa + 1] - i;
                } else if (chk[i] == ACTION_POSITION) {
                        tdata[curr++] = 0;
                        tdata[curr++] = nxt[i];
                } else if (chk[i] > numecs || chk[i] == 0) {
                        tdata[curr++] = 0;
                        tdata[curr++] = 0;
                } else {        /* verify, transition */

                        tdata[curr++] = chk[i];
                        tdata[curr++] = base[nxt[i]] - (i - chk[i]);
                }
        }


        /* Here's the final, end-of-buffer state. */
        tdata[curr++] = chk[tblend + 1];
        tdata[curr++] = nxt[tblend + 1];

        tdata[curr++] = chk[tblend + 2];
        tdata[curr++] = nxt[tblend + 2];

        return tbl;
}


/** Make start_state_list table.
 *  @return the newly allocated start_state_list table
 */
static struct yytbl_data *
mkssltbl(void)
{
        struct yytbl_data *tbl = NULL;
        flex_int32_t *tdata = NULL;
        flex_int32_t i;

        tbl = calloc(1, sizeof(struct yytbl_data));
        yytbl_data_init(tbl, YYTD_ID_START_STATE_LIST);
        tbl->td_flags = YYTD_DATA32 | YYTD_PTRANS;
        tbl->td_hilen = 0;
        tbl->td_lolen = lastsc * 2 + 1;

        tbl->td_data = tdata =
            calloc(tbl->td_lolen, sizeof(flex_int32_t));

        for (i = 0; i <= lastsc * 2; ++i)
                tdata[i] = base[i];

        buf_prints(&yydmap_buf,
            "\t{YYTD_ID_START_STATE_LIST, (void**)&yy_start_state_list, sizeof(%s)},\n",
            "struct yy_trans_info*");

        return tbl;
}



/* genctbl - generates full speed compressed transition table */

void 
genctbl(void)
{
        int i;
        int end_of_buffer_action = num_rules + 1;

        /* Table of verify for transition and offset to next state. */
        if (gentables)
                out_dec("static yyconst struct yy_trans_info yy_transition[%d] =\n    {\n", tblend + numecs + 1);
        else
                outn("static yyconst struct yy_trans_info *yy_transition = 0;");

        /*
         * We want the transition to be represented as the offset to the next
         * state, not the actual state number, which is what it currently is.
         * The offset is base[nxt[i]] - (base of current state)].  That's
         * just the difference between the starting points of the two
         * involved states (to - from).
         * 
         * First, though, we need to find some way to put in our end-of-buffer
         * flags and states.  We do this by making a state with absolutely no
         * transitions.  We put it at the end of the table.
         */

        /*
         * We need to have room in nxt/chk for two more slots: One for the
         * action and one for the end-of-buffer transition.  We now *assume*
         * that we're guaranteed the only character we'll try to index this
         * nxt/chk pair with is EOB, i.e., 0, so we don't have to make sure
         * there's room for jam entries for other characters.
         */

        while (tblend + 2 >= current_max_xpairs)
                expand_nxt_chk();

        while (lastdfa + 1 >= current_max_dfas)
                increase_max_dfas();

        base[lastdfa + 1] = tblend + 2;
        nxt[tblend + 1] = end_of_buffer_action;
        chk[tblend + 1] = numecs + 1;
        chk[tblend + 2] = 1;    /* anything but EOB */

        /* So that "make test" won't show arb. differences. */
        nxt[tblend + 2] = 0;

        /*
         * Make sure every state has an end-of-buffer transition and an
         * action #.
         */
        for (i = 0; i <= lastdfa; ++i) {
                int anum = dfaacc[i].dfaacc_state;
                int offset = base[i];

                chk[offset] = EOB_POSITION;
                chk[offset - 1] = ACTION_POSITION;
                nxt[offset - 1] = anum; /* action number */
        }

        for (i = 0; i <= tblend; ++i) {
                if (chk[i] == EOB_POSITION)
                        transition_struct_out(0, base[lastdfa + 1] - i);

                else if (chk[i] == ACTION_POSITION)
                        transition_struct_out(0, nxt[i]);

                else if (chk[i] > numecs || chk[i] == 0)
                        transition_struct_out(0, 0);    /* unused slot */

                else            /* verify, transition */
                        transition_struct_out(chk[i],
                            base[nxt[i]] - (i -
                                chk[i]));
        }


        /* Here's the final, end-of-buffer state. */
        transition_struct_out(chk[tblend + 1], nxt[tblend + 1]);
        transition_struct_out(chk[tblend + 2], nxt[tblend + 2]);

        if (gentables)
                outn("    };\n");

        /* Table of pointers to start states. */
        if (gentables)
                out_dec("static yyconst struct yy_trans_info *yy_start_state_list[%d] =\n", lastsc * 2 + 1);
        else
                outn("static yyconst struct yy_trans_info **yy_start_state_list =0;");

        if (gentables) {
                outn("    {");

                for (i = 0; i <= lastsc * 2; ++i)
                        out_dec("    &yy_transition[%d],\n", base[i]);

                dataend();
        }
        if (useecs)
                genecs();
}


/* mkecstbl - Make equivalence-class tables.  */

static struct yytbl_data *
mkecstbl(void)
{
        int i;
        struct yytbl_data *tbl = NULL;
        flex_int32_t *tdata = NULL;

        tbl = calloc(1, sizeof(struct yytbl_data));
        yytbl_data_init(tbl, YYTD_ID_EC);
        tbl->td_flags |= YYTD_DATA32;
        tbl->td_hilen = 0;
        tbl->td_lolen = csize;

        tbl->td_data = tdata =
            calloc(tbl->td_lolen, sizeof(flex_int32_t));

        for (i = 1; i < csize; ++i) {
                ecgroup[i] = ABS(ecgroup[i]);
                tdata[i] = ecgroup[i];
        }

        buf_prints(&yydmap_buf,
            "\t{YYTD_ID_EC, (void**)&yy_ec, sizeof(%s)},\n",
            "flex_int32_t");

        return tbl;
}

/* Generate equivalence-class tables. */

void 
genecs(void)
{
        int i, j;
        int numrows;

        out_str_dec(get_int32_decl(), "yy_ec", csize);

        for (i = 1; i < csize; ++i) {
                ecgroup[i] = ABS(ecgroup[i]);
                mkdata(ecgroup[i]);
        }

        dataend();

        if (trace) {
                fputs(_("\n\nEquivalence Classes:\n\n"), stderr);

                numrows = csize / 8;

                for (j = 0; j < numrows; ++j) {
                        for (i = j; i < csize; i = i + numrows) {
                                fprintf(stderr, "%4s = %-2d",
                                    readable_form(i), ecgroup[i]);

                                putc(' ', stderr);
                        }

                        putc('\n', stderr);
                }
        }
}


/* Generate the code to find the action number. */

void 
gen_find_action(void)
{
        if (fullspd)
                indent_puts("yy_act = yy_current_state[-1].yy_nxt;");

        else if (fulltbl)
                indent_puts("yy_act = yy_accept[yy_current_state];");

        else if (reject) {
                indent_puts("yy_current_state = *--YY_G(yy_state_ptr);");
                indent_puts("YY_G(yy_lp) = yy_accept[yy_current_state];");

                outn("find_rule: /* we branch to this label when backing up */");

                indent_puts
                    ("for ( ; ; ) /* until we find what rule we matched */");

                indent_up();

                indent_puts("{");

                indent_puts
                    ("if ( YY_G(yy_lp) && YY_G(yy_lp) < yy_accept[yy_current_state + 1] )");
                indent_up();
                indent_puts("{");
                indent_puts("yy_act = yy_acclist[YY_G(yy_lp)];");

                if (variable_trailing_context_rules) {
                        indent_puts
                            ("if ( yy_act & YY_TRAILING_HEAD_MASK ||");
                        indent_puts("     YY_G(yy_looking_for_trail_begin) )");
                        indent_up();
                        indent_puts("{");

                        indent_puts
                            ("if ( yy_act == YY_G(yy_looking_for_trail_begin) )");
                        indent_up();
                        indent_puts("{");
                        indent_puts("YY_G(yy_looking_for_trail_begin) = 0;");
                        indent_puts("yy_act &= ~YY_TRAILING_HEAD_MASK;");
                        indent_puts("break;");
                        indent_puts("}");
                        indent_down();

                        indent_puts("}");
                        indent_down();

                        indent_puts
                            ("else if ( yy_act & YY_TRAILING_MASK )");
                        indent_up();
                        indent_puts("{");
                        indent_puts
                            ("YY_G(yy_looking_for_trail_begin) = yy_act & ~YY_TRAILING_MASK;");
                        indent_puts
                            ("YY_G(yy_looking_for_trail_begin) |= YY_TRAILING_HEAD_MASK;");

                        if (real_reject) {
                                /*
                                 * Remember matched text in case we back up
                                 * due to REJECT.
                                 */
                                indent_puts
                                    ("YY_G(yy_full_match) = yy_cp;");
                                indent_puts
                                    ("YY_G(yy_full_state) = YY_G(yy_state_ptr);");
                                indent_puts("YY_G(yy_full_lp) = YY_G(yy_lp);");
                        }
                        indent_puts("}");
                        indent_down();

                        indent_puts("else");
                        indent_up();
                        indent_puts("{");
                        indent_puts("YY_G(yy_full_match) = yy_cp;");
                        indent_puts
                            ("YY_G(yy_full_state) = YY_G(yy_state_ptr);");
                        indent_puts("YY_G(yy_full_lp) = YY_G(yy_lp);");
                        indent_puts("break;");
                        indent_puts("}");
                        indent_down();

                        indent_puts("++YY_G(yy_lp);");
                        indent_puts("goto find_rule;");
                } else {
                        /*
                         * Remember matched text in case we back up due to
                         * trailing context plus REJECT.
                         */
                        indent_up();
                        indent_puts("{");
                        indent_puts("YY_G(yy_full_match) = yy_cp;");
                        indent_puts("break;");
                        indent_puts("}");
                        indent_down();
                }

                indent_puts("}");
                indent_down();

                indent_puts("--yy_cp;");

                /*
                 * We could consolidate the following two lines with those at
                 * the beginning, but at the cost of complaints that we're
                 * branching inside a loop.
                 */
                indent_puts("yy_current_state = *--YY_G(yy_state_ptr);");
                indent_puts("YY_G(yy_lp) = yy_accept[yy_current_state];");

                indent_puts("}");

                indent_down();
        } else {                /* compressed */
                indent_puts("yy_act = yy_accept[yy_current_state];");

                if (interactive && !reject) {
                        /*
                         * Do the guaranteed-needed backing up to figure out
                         * the match.
                         */
                        indent_puts("if ( yy_act == 0 )");
                        indent_up();
                        indent_puts("{ /* have to back up */");
                        indent_puts
                            ("yy_cp = YY_G(yy_last_accepting_cpos);");
                        indent_puts
                            ("yy_current_state = YY_G(yy_last_accepting_state);");
                        indent_puts
                            ("yy_act = yy_accept[yy_current_state];");
                        indent_puts("}");
                        indent_down();
                }
        }
}

/* mkftbl - make the full table and return the struct .
 * you should call mkecstbl() after this.
 */

struct yytbl_data *
mkftbl(void)
{
        int i;
        int end_of_buffer_action = num_rules + 1;
        struct yytbl_data *tbl;
        flex_int32_t *tdata = NULL;

        tbl = calloc(1, sizeof(struct yytbl_data));
        yytbl_data_init(tbl, YYTD_ID_ACCEPT);
        tbl->td_flags |= YYTD_DATA32;
        tbl->td_hilen = 0;      /* it's a one-dimensional array */
        tbl->td_lolen = lastdfa + 1;

        tbl->td_data = tdata =
            calloc(tbl->td_lolen, sizeof(flex_int32_t));

        dfaacc[end_of_buffer_state].dfaacc_state = end_of_buffer_action;

        for (i = 1; i <= lastdfa; ++i) {
                int anum = dfaacc[i].dfaacc_state;

                tdata[i] = anum;

                if (trace && anum)
                        fprintf(stderr, _("state # %d accepts: [%d]\n"),
                            i, anum);
        }

        buf_prints(&yydmap_buf,
            "\t{YYTD_ID_ACCEPT, (void**)&yy_accept, sizeof(%s)},\n",
            long_align ? "flex_int32_t" : "flex_int16_t");
        return tbl;
}


/* genftbl - generate full transition table */

void 
genftbl(void)
{
        int i;
        int end_of_buffer_action = num_rules + 1;

        out_str_dec(long_align ? get_int32_decl() : get_int16_decl(),
            "yy_accept", lastdfa + 1);

        dfaacc[end_of_buffer_state].dfaacc_state = end_of_buffer_action;

        for (i = 1; i <= lastdfa; ++i) {
                int anum = dfaacc[i].dfaacc_state;

                mkdata(anum);

                if (trace && anum)
                        fprintf(stderr, _("state # %d accepts: [%d]\n"),
                            i, anum);
        }

        dataend();

        if (useecs)
                genecs();

        /*
         * Don't have to dump the actual full table entries - they were
         * created on-the-fly.
         */
}


/* Generate the code to find the next compressed-table state. */

void
gen_next_compressed_state(char *char_map)
{
        indent_put2s("YY_CHAR yy_c = %s;", char_map);

        /*
         * Save the backing-up info \before/ computing the next state because
         * we always compute one more state than needed - we always proceed
         * until we reach a jam state
         */
        gen_backing_up();

        indent_puts
            ("while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )");
        indent_up();
        indent_puts("{");
        indent_puts("yy_current_state = (int) yy_def[yy_current_state];");

        if (usemecs) {
                /*
                 * We've arrange it so that templates are never chained to
                 * one another.  This means we can afford to make a very
                 * simple test to see if we need to convert to yy_c's
                 * meta-equivalence class without worrying about erroneously
                 * looking up the meta-equivalence class twice
                 */
                do_indent();

                /* lastdfa + 2 is the beginning of the templates */
                out_dec("if ( yy_current_state >= %d )\n", lastdfa + 2);

                indent_up();
                indent_puts("yy_c = yy_meta[(unsigned int) yy_c];");
                indent_down();
        }
        indent_puts("}");
        indent_down();

        indent_puts
            ("yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];");
}


/* Generate the code to find the next match. */

void 
gen_next_match(void)
{
        /*
         * NOTE - changes in here should be reflected in gen_next_state() and
         * gen_NUL_trans().
         */
        char *char_map = useecs ?
        "yy_ec[YY_SC_TO_UI(*yy_cp)] " : "YY_SC_TO_UI(*yy_cp)";

        char *char_map_2 = useecs ?
        "yy_ec[YY_SC_TO_UI(*++yy_cp)] " : "YY_SC_TO_UI(*++yy_cp)";

        if (fulltbl) {
                if (gentables)
                        indent_put2s
                            ("while ( (yy_current_state = yy_nxt[yy_current_state][ %s ]) > 0 )",
                            char_map);
                else
                        indent_put2s
                            ("while ( (yy_current_state = yy_nxt[yy_current_state*YY_NXT_LOLEN +  %s ]) > 0 )",
                            char_map);

                indent_up();

                if (num_backing_up > 0) {
                        indent_puts("{");
                        gen_backing_up();
                        outc('\n');
                }
                indent_puts("++yy_cp;");

                if (num_backing_up > 0)
                        indent_puts("}");

                indent_down();

                outc('\n');
                indent_puts("yy_current_state = -yy_current_state;");
        } else if (fullspd) {
                indent_puts("{");
                indent_puts
                    ("yyconst struct yy_trans_info *yy_trans_info;\n");
                indent_puts("YY_CHAR yy_c;\n");
                indent_put2s("for ( yy_c = %s;", char_map);
                indent_puts
                    ("      (yy_trans_info = &yy_current_state[(unsigned int) yy_c])->");
                indent_puts("yy_verify == yy_c;");
                indent_put2s("      yy_c = %s )", char_map_2);

                indent_up();

                if (num_backing_up > 0)
                        indent_puts("{");

                indent_puts("yy_current_state += yy_trans_info->yy_nxt;");

                if (num_backing_up > 0) {
                        outc('\n');
                        gen_backing_up();
                        indent_puts("}");
                }
                indent_down();
                indent_puts("}");
        } else {                /* compressed */
                indent_puts("do");

                indent_up();
                indent_puts("{");

                gen_next_state(false);

                indent_puts("++yy_cp;");


                indent_puts("}");
                indent_down();

                do_indent();

                if (interactive)
                        out_dec("while ( yy_base[yy_current_state] != %d );\n", jambase);
                else
                        out_dec("while ( yy_current_state != %d );\n",
                            jamstate);

                if (!reject && !interactive) {
                        /*
                         * Do the guaranteed-needed backing up to figure out
                         * the match.
                         */
                        indent_puts
                            ("yy_cp = YY_G(yy_last_accepting_cpos);");
                        indent_puts
                            ("yy_current_state = YY_G(yy_last_accepting_state);");
                }
        }
}


/* Generate the code to find the next state. */

void 
gen_next_state(int worry_about_NULs)
{                               /* NOTE - changes in here should be reflected
                                 * in gen_next_match() */
        char char_map[256];

        if (worry_about_NULs && !nultrans) {
                if (useecs)
                        snprintf(char_map, sizeof(char_map),
                            "(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : %d)",
                            NUL_ec);
                else
                        snprintf(char_map, sizeof(char_map),
                            "(*yy_cp ? YY_SC_TO_UI(*yy_cp) : %d)",
                            NUL_ec);
        } else
                strlcpy(char_map, useecs ?
                    "yy_ec[YY_SC_TO_UI(*yy_cp)] " : "YY_SC_TO_UI(*yy_cp)",
                    sizeof char_map);

        if (worry_about_NULs && nultrans) {
                if (!fulltbl && !fullspd)
                        /* Compressed tables back up *before* they match. */
                        gen_backing_up();

                indent_puts("if ( *yy_cp )");
                indent_up();
                indent_puts("{");
        }
        if (fulltbl) {
                if (gentables)
                        indent_put2s
                            ("yy_current_state = yy_nxt[yy_current_state][%s];",
                            char_map);
                else
                        indent_put2s
                            ("yy_current_state = yy_nxt[yy_current_state*YY_NXT_LOLEN + %s];",
                            char_map);
        } else if (fullspd)
                indent_put2s
                    ("yy_current_state += yy_current_state[%s].yy_nxt;",
                    char_map);

        else
                gen_next_compressed_state(char_map);

        if (worry_about_NULs && nultrans) {

                indent_puts("}");
                indent_down();
                indent_puts("else");
                indent_up();
                indent_puts
                    ("yy_current_state = yy_NUL_trans[yy_current_state];");
                indent_down();
        }
        if (fullspd || fulltbl)
                gen_backing_up();

        if (reject)
                indent_puts("*YY_G(yy_state_ptr)++ = yy_current_state;");
}


/* Generate the code to make a NUL transition. */

void 
gen_NUL_trans(void)
{                               /* NOTE - changes in here should be reflected
                                 * in gen_next_match() */
        /*
         * Only generate a definition for "yy_cp" if we'll generate code that
         * uses it.  Otherwise lint and the like complain.
         */
        int need_backing_up = (num_backing_up > 0 && !reject);

        if (need_backing_up && (!nultrans || fullspd || fulltbl))
                /*
                 * We're going to need yy_cp lying around for the call below
                 * to gen_backing_up().
                 */
                indent_puts("char *yy_cp = YY_G(yy_c_buf_p);");

        outc('\n');

        if (nultrans) {
                indent_puts
                    ("yy_current_state = yy_NUL_trans[yy_current_state];");
                indent_puts("yy_is_jam = (yy_current_state == 0);");
        } else if (fulltbl) {
                do_indent();
                if (gentables)
                        out_dec("yy_current_state = yy_nxt[yy_current_state][%d];\n", NUL_ec);
                else
                        out_dec("yy_current_state = yy_nxt[yy_current_state*YY_NXT_LOLEN + %d];\n", NUL_ec);
                indent_puts("yy_is_jam = (yy_current_state <= 0);");
        } else if (fullspd) {
                do_indent();
                out_dec("int yy_c = %d;\n", NUL_ec);

                indent_puts
                    ("yyconst struct yy_trans_info *yy_trans_info;\n");
                indent_puts
                    ("yy_trans_info = &yy_current_state[(unsigned int) yy_c];");
                indent_puts("yy_current_state += yy_trans_info->yy_nxt;");

                indent_puts
                    ("yy_is_jam = (yy_trans_info->yy_verify != yy_c);");
        } else {
                char NUL_ec_str[20];

                snprintf(NUL_ec_str, sizeof(NUL_ec_str), "%d", NUL_ec);
                gen_next_compressed_state(NUL_ec_str);

                do_indent();
                out_dec("yy_is_jam = (yy_current_state == %d);\n",
                    jamstate);

                if (reject) {
                        /*
                         * Only stack this state if it's a transition we
                         * actually make.  If we stack it on a jam, then the
                         * state stack and yy_c_buf_p get out of sync.
                         */
                        indent_puts("if ( ! yy_is_jam )");
                        indent_up();
                        indent_puts
                            ("*YY_G(yy_state_ptr)++ = yy_current_state;");
                        indent_down();
                }
        }

        /*
         * If we've entered an accepting state, back up; note that compressed
         * tables have *already* done such backing up, so we needn't bother
         * with it again.
         */
        if (need_backing_up && (fullspd || fulltbl)) {
                outc('\n');
                indent_puts("if ( ! yy_is_jam )");
                indent_up();
                indent_puts("{");
                gen_backing_up();
                indent_puts("}");
                indent_down();
        }
}


/* Generate the code to find the start state. */

void 
gen_start_state(void)
{
        if (fullspd) {
                if (bol_needed) {
                        indent_puts
                        ("yy_current_state = yy_start_state_list[YY_G(yy_start) + YY_AT_BOL()];");
                } else
                        indent_puts
                            ("yy_current_state = yy_start_state_list[YY_G(yy_start)];");
        } else {
                indent_puts("yy_current_state = YY_G(yy_start);");

                if (bol_needed)
                        indent_puts("yy_current_state += YY_AT_BOL();");

                if (reject) {
                        /* Set up for storing up states. */
                        outn("m4_ifdef( [[M4_YY_USES_REJECT]],\n[[");
                        indent_puts
                            ("YY_G(yy_state_ptr) = YY_G(yy_state_buf);");
                        indent_puts
                            ("*YY_G(yy_state_ptr)++ = yy_current_state;");
                        outn("]])");
                }
        }
}


/* gentabs - generate data statements for the transition tables */

void 
gentabs(void)
{
        int i, j, k, *accset, nacc, *acc_array, total_states;
        int end_of_buffer_action = num_rules + 1;
        struct yytbl_data *yyacc_tbl = 0, *yymeta_tbl = 0, *yybase_tbl = 0, *yydef_tbl = 0,
        *yynxt_tbl = 0, *yychk_tbl = 0, *yyacclist_tbl = 0;
        flex_int32_t *yyacc_data = 0, *yybase_data = 0, *yydef_data = 0, *yynxt_data = 0,
        *yychk_data = 0, *yyacclist_data = 0;
        flex_int32_t yybase_curr = 0, yyacclist_curr = 0, yyacc_curr = 0;

        acc_array = allocate_integer_array(current_max_dfas);
        nummt = 0;

        /*
         * The compressed table format jams by entering the "jam state",
         * losing information about the previous state in the process. In
         * order to recover the previous state, we effectively need to keep
         * backing-up information.
         */
        ++num_backing_up;

        if (reject) {
                /*
                 * Write out accepting list and pointer list.
                 * 
                 * First we generate the "yy_acclist" array.  In the process, we
                 * compute the indices that will go into the "yy_accept"
                 * array, and save the indices in the dfaacc array.
                 */
                int EOB_accepting_list[2];

                /* Set up accepting structures for the End Of Buffer state. */
                EOB_accepting_list[0] = 0;
                EOB_accepting_list[1] = end_of_buffer_action;
                accsiz[end_of_buffer_state] = 1;
                dfaacc[end_of_buffer_state].dfaacc_set =
                    EOB_accepting_list;

                out_str_dec(long_align ? get_int32_decl() :
                    get_int16_decl(), "yy_acclist", MAX(numas,
                        1) + 1);

                buf_prints(&yydmap_buf,
                    "\t{YYTD_ID_ACCLIST, (void**)&yy_acclist, sizeof(%s)},\n",
                    long_align ? "flex_int32_t" : "flex_int16_t");

                yyacclist_tbl = calloc(1, sizeof(struct yytbl_data));
                yytbl_data_init(yyacclist_tbl, YYTD_ID_ACCLIST);
                yyacclist_tbl->td_lolen = MAX(numas, 1) + 1;
                yyacclist_tbl->td_data = yyacclist_data =
                    calloc(yyacclist_tbl->td_lolen, sizeof(flex_int32_t));
                yyacclist_curr = 1;

                j = 1;          /* index into "yy_acclist" array */

                for (i = 1; i <= lastdfa; ++i) {
                        acc_array[i] = j;

                        if (accsiz[i] != 0) {
                                accset = dfaacc[i].dfaacc_set;
                                nacc = accsiz[i];

                                if (trace)
                                        fprintf(stderr,
                                            _("state # %d accepts: "),
                                            i);

                                for (k = 1; k <= nacc; ++k) {
                                        int accnum = accset[k];

                                        ++j;

                                        if (variable_trailing_context_rules
                                            && !(accnum &
                                                YY_TRAILING_HEAD_MASK)
                                            && accnum > 0
                                            && accnum <= num_rules
                                            && rule_type[accnum] ==
                                            RULE_VARIABLE) {
                                                /*
                                                 * Special hack to flag
                                                 * accepting number as part
                                                 * of trailing context rule.
                                                 */
                                                accnum |= YY_TRAILING_MASK;
                                        }
                                        mkdata(accnum);
                                        yyacclist_data[yyacclist_curr++] = accnum;

                                        if (trace) {
                                                fprintf(stderr, "[%d]",
                                                    accset[k]);

                                                if (k < nacc)
                                                        fputs(", ",
                                                            stderr);
                                                else
                                                        putc('\n',
                                                            stderr);
                                        }
                                }
                        }
                }

                /* add accepting number for the "jam" state */
                acc_array[i] = j;

                dataend();
                if (tablesext) {
                        yytbl_data_compress(yyacclist_tbl);
                        if (yytbl_data_fwrite(&tableswr, yyacclist_tbl) < 0)
                                flexerror(_("Could not write yyacclist_tbl"));
                        yytbl_data_destroy(yyacclist_tbl);
                        yyacclist_tbl = NULL;
                }
        } else {
                dfaacc[end_of_buffer_state].dfaacc_state =
                    end_of_buffer_action;

                for (i = 1; i <= lastdfa; ++i)
                        acc_array[i] = dfaacc[i].dfaacc_state;

                /* add accepting number for jam state */
                acc_array[i] = 0;
        }

        /* Begin generating yy_accept */

        /*
         * Spit out "yy_accept" array.  If we're doing "reject", it'll be
         * pointers into the "yy_acclist" array.  Otherwise it's actual
         * accepting numbers.  In either case, we just dump the numbers.
         */

        /*
         * "lastdfa + 2" is the size of "yy_accept"; includes room for C
         * arrays beginning at 0 and for "jam" state.
         */
        k = lastdfa + 2;

        if (reject)
                /*
                 * We put a "cap" on the table associating lists of accepting
                 * numbers with state numbers.  This is needed because we
                 * tell where the end of an accepting list is by looking at
                 * where the list for the next state starts.
                 */
                ++k;

        out_str_dec(long_align ? get_int32_decl() : get_int16_decl(),
            "yy_accept", k);

        buf_prints(&yydmap_buf,
            "\t{YYTD_ID_ACCEPT, (void**)&yy_accept, sizeof(%s)},\n",
            long_align ? "flex_int32_t" : "flex_int16_t");

        yyacc_tbl = calloc(1, sizeof(struct yytbl_data));
        yytbl_data_init(yyacc_tbl, YYTD_ID_ACCEPT);
        yyacc_tbl->td_lolen = k;
        yyacc_tbl->td_data = yyacc_data =
            calloc(yyacc_tbl->td_lolen, sizeof(flex_int32_t));
        yyacc_curr = 1;

        for (i = 1; i <= lastdfa; ++i) {
                mkdata(acc_array[i]);
                yyacc_data[yyacc_curr++] = acc_array[i];

                if (!reject && trace && acc_array[i])
                        fprintf(stderr, _("state # %d accepts: [%d]\n"),
                            i, acc_array[i]);
        }

        /* Add entry for "jam" state. */
        mkdata(acc_array[i]);
        yyacc_data[yyacc_curr++] = acc_array[i];

        if (reject) {
                /* Add "cap" for the list. */
                mkdata(acc_array[i]);
                yyacc_data[yyacc_curr++] = acc_array[i];
        }
        dataend();
        if (tablesext) {
                yytbl_data_compress(yyacc_tbl);
                if (yytbl_data_fwrite(&tableswr, yyacc_tbl) < 0)
                        flexerror(_("Could not write yyacc_tbl"));
                yytbl_data_destroy(yyacc_tbl);
                yyacc_tbl = NULL;
        }
        /* End generating yy_accept */

        if (useecs) {

                genecs();
                if (tablesext) {
                        struct yytbl_data *tbl;

                        tbl = mkecstbl();
                        yytbl_data_compress(tbl);
                        if (yytbl_data_fwrite(&tableswr, tbl) < 0)
                                flexerror(_("Could not write ecstbl"));
                        yytbl_data_destroy(tbl);
                        tbl = 0;
                }
        }
        if (usemecs) {
                /* Begin generating yy_meta */
                /*
                 * Write out meta-equivalence classes (used to index
                 * templates with).
                 */
                flex_int32_t *yymecs_data = NULL;
                yymeta_tbl = calloc(1, sizeof(struct yytbl_data));
                yytbl_data_init(yymeta_tbl, YYTD_ID_META);
                yymeta_tbl->td_lolen = numecs + 1;
                yymeta_tbl->td_data = yymecs_data =
                    calloc(yymeta_tbl->td_lolen,
                    sizeof(flex_int32_t));

                if (trace)
                        fputs(_("\n\nMeta-Equivalence Classes:\n"),
                            stderr);

                out_str_dec(get_int32_decl(), "yy_meta", numecs + 1);
                buf_prints(&yydmap_buf,
                    "\t{YYTD_ID_META, (void**)&yy_meta, sizeof(%s)},\n",
                    "flex_int32_t");

                for (i = 1; i <= numecs; ++i) {
                        if (trace)
                                fprintf(stderr, "%d = %d\n",
                                    i, ABS(tecbck[i]));

                        mkdata(ABS(tecbck[i]));
                        yymecs_data[i] = ABS(tecbck[i]);
                }

                dataend();
                if (tablesext) {
                        yytbl_data_compress(yymeta_tbl);
                        if (yytbl_data_fwrite(&tableswr, yymeta_tbl) < 0)
                                flexerror(_
                                    ("Could not write yymeta_tbl"));
                        yytbl_data_destroy(yymeta_tbl);
                        yymeta_tbl = NULL;
                }
                /* End generating yy_meta */
        }
        total_states = lastdfa + numtemps;

        /* Begin generating yy_base */
        out_str_dec((tblend >= INT16_MAX || long_align) ?
            get_int32_decl() : get_int16_decl(),
            "yy_base", total_states + 1);

        buf_prints(&yydmap_buf,
            "\t{YYTD_ID_BASE, (void**)&yy_base, sizeof(%s)},\n",
            (tblend >= INT16_MAX
                || long_align) ? "flex_int32_t" : "flex_int16_t");
        yybase_tbl = calloc(1, sizeof(struct yytbl_data));
        yytbl_data_init(yybase_tbl, YYTD_ID_BASE);
        yybase_tbl->td_lolen = total_states + 1;
        yybase_tbl->td_data = yybase_data =
            calloc(yybase_tbl->td_lolen,
            sizeof(flex_int32_t));
        yybase_curr = 1;

        for (i = 1; i <= lastdfa; ++i) {
                int d = def[i];

                if (base[i] == JAMSTATE)
                        base[i] = jambase;

                if (d == JAMSTATE)
                        def[i] = jamstate;

                else if (d < 0) {
                        /* Template reference. */
                        ++tmpuses;
                        def[i] = lastdfa - d + 1;
                }
                mkdata(base[i]);
                yybase_data[yybase_curr++] = base[i];
        }

        /* Generate jam state's base index. */
        mkdata(base[i]);
        yybase_data[yybase_curr++] = base[i];

        for (++i /* skip jam state */ ; i <= total_states; ++i) {
                mkdata(base[i]);
                yybase_data[yybase_curr++] = base[i];
                def[i] = jamstate;
        }

        dataend();
        if (tablesext) {
                yytbl_data_compress(yybase_tbl);
                if (yytbl_data_fwrite(&tableswr, yybase_tbl) < 0)
                        flexerror(_("Could not write yybase_tbl"));
                yytbl_data_destroy(yybase_tbl);
                yybase_tbl = NULL;
        }
        /* End generating yy_base */


        /* Begin generating yy_def */
        out_str_dec((total_states >= INT16_MAX || long_align) ?
            get_int32_decl() : get_int16_decl(),
            "yy_def", total_states + 1);

        buf_prints(&yydmap_buf,
            "\t{YYTD_ID_DEF, (void**)&yy_def, sizeof(%s)},\n",
            (total_states >= INT16_MAX
                || long_align) ? "flex_int32_t" : "flex_int16_t");

        yydef_tbl = calloc(1, sizeof(struct yytbl_data));
        yytbl_data_init(yydef_tbl, YYTD_ID_DEF);
        yydef_tbl->td_lolen = total_states + 1;
        yydef_tbl->td_data = yydef_data =
            calloc(yydef_tbl->td_lolen, sizeof(flex_int32_t));

        for (i = 1; i <= total_states; ++i) {
                mkdata(def[i]);
                yydef_data[i] = def[i];
        }

        dataend();
        if (tablesext) {
                yytbl_data_compress(yydef_tbl);
                if (yytbl_data_fwrite(&tableswr, yydef_tbl) < 0)
                        flexerror(_("Could not write yydef_tbl"));
                yytbl_data_destroy(yydef_tbl);
                yydef_tbl = NULL;
        }
        /* End generating yy_def */


        /* Begin generating yy_nxt */
        out_str_dec((total_states >= INT16_MAX || long_align) ?
            get_int32_decl() : get_int16_decl(), "yy_nxt",
            tblend + 1);

        buf_prints(&yydmap_buf,
            "\t{YYTD_ID_NXT, (void**)&yy_nxt, sizeof(%s)},\n",
            (total_states >= INT16_MAX
                || long_align) ? "flex_int32_t" : "flex_int16_t");

        yynxt_tbl = calloc(1, sizeof(struct yytbl_data));
        yytbl_data_init(yynxt_tbl, YYTD_ID_NXT);
        yynxt_tbl->td_lolen = tblend + 1;
        yynxt_tbl->td_data = yynxt_data =
            calloc(yynxt_tbl->td_lolen, sizeof(flex_int32_t));

        for (i = 1; i <= tblend; ++i) {
                /*
                 * Note, the order of the following test is important. If
                 * chk[i] is 0, then nxt[i] is undefined.
                 */
                if (chk[i] == 0 || nxt[i] == 0)
                        nxt[i] = jamstate;      /* new state is the JAM state */

                mkdata(nxt[i]);
                yynxt_data[i] = nxt[i];
        }

        dataend();
        if (tablesext) {
                yytbl_data_compress(yynxt_tbl);
                if (yytbl_data_fwrite(&tableswr, yynxt_tbl) < 0)
                        flexerror(_("Could not write yynxt_tbl"));
                yytbl_data_destroy(yynxt_tbl);
                yynxt_tbl = NULL;
        }
        /* End generating yy_nxt */

        /* Begin generating yy_chk */
        out_str_dec((total_states >= INT16_MAX || long_align) ?
            get_int32_decl() : get_int16_decl(), "yy_chk",
            tblend + 1);

        buf_prints(&yydmap_buf,
            "\t{YYTD_ID_CHK, (void**)&yy_chk, sizeof(%s)},\n",
            (total_states >= INT16_MAX
                || long_align) ? "flex_int32_t" : "flex_int16_t");

        yychk_tbl = calloc(1, sizeof(struct yytbl_data));
        yytbl_data_init(yychk_tbl, YYTD_ID_CHK);
        yychk_tbl->td_lolen = tblend + 1;
        yychk_tbl->td_data = yychk_data =
            calloc(yychk_tbl->td_lolen, sizeof(flex_int32_t));

        for (i = 1; i <= tblend; ++i) {
                if (chk[i] == 0)
                        ++nummt;

                mkdata(chk[i]);
                yychk_data[i] = chk[i];
        }

        dataend();
        if (tablesext) {
                yytbl_data_compress(yychk_tbl);
                if (yytbl_data_fwrite(&tableswr, yychk_tbl) < 0)
                        flexerror(_("Could not write yychk_tbl"));
                yytbl_data_destroy(yychk_tbl);
                yychk_tbl = NULL;
        }
        /* End generating yy_chk */

        free(acc_array);
}


/* Write out a formatted string (with a secondary string argument) at the
 * current indentation level, adding a final newline.
 */

void 
indent_put2s(const char *fmt, const char *arg)
{
        do_indent();
        out_str(fmt, arg);
        outn("");
}


/* Write out a string at the current indentation level, adding a final
 * newline.
 */

void 
indent_puts(const char *str)
{
        do_indent();
        outn(str);
}


/* make_tables - generate transition tables and finishes generating output file
 */

void 
make_tables(void)
{
        int i;
        int did_eof_rule = false;
        struct yytbl_data *yynultrans_tbl;


        skelout();              /* %% [2.0] - break point in skel */

        /*
         * First, take care of YY_DO_BEFORE_ACTION depending on yymore being
         * used.
         */
        set_indent(1);

        if (yymore_used && !yytext_is_array) {
                indent_puts("YY_G(yytext_ptr) -= YY_G(yy_more_len); \\");
                indent_puts
                    ("yyleng = (size_t) (yy_cp - YY_G(yytext_ptr)); \\");
        } else
                indent_puts("yyleng = (size_t) (yy_cp - yy_bp); \\");

        /* Now also deal with copying yytext_ptr to yytext if needed. */
        skelout();              /* %% [3.0] - break point in skel */
        if (yytext_is_array) {
                if (yymore_used)
                        indent_puts
                            ("if ( yyleng + YY_G(yy_more_offset) >= YYLMAX ) \\");
                else
                        indent_puts("if ( yyleng >= YYLMAX ) \\");

                indent_up();
                indent_puts
                    ("YY_FATAL_ERROR( \"token too large, exceeds YYLMAX\" ); \\");
                indent_down();

                if (yymore_used) {
                        indent_puts
                            ("yy_flex_strncpy( &yytext[YY_G(yy_more_offset)], YY_G(yytext_ptr), yyleng + 1 M4_YY_CALL_LAST_ARG); \\");
                        indent_puts("yyleng += YY_G(yy_more_offset); \\");
                        indent_puts
                            ("YY_G(yy_prev_more_offset) = YY_G(yy_more_offset); \\");
                        indent_puts("YY_G(yy_more_offset) = 0; \\");
                } else {
                        indent_puts
                            ("yy_flex_strncpy( yytext, YY_G(yytext_ptr), yyleng + 1 M4_YY_CALL_LAST_ARG); \\");
                }
        }
        set_indent(0);

        skelout();              /* %% [4.0] - break point in skel */


        /* This is where we REALLY begin generating the tables. */

        out_dec("#define YY_NUM_RULES %d\n", num_rules);
        out_dec("#define YY_END_OF_BUFFER %d\n", num_rules + 1);

        if (fullspd) {
                /*
                 * Need to define the transet type as a size large enough to
                 * hold the biggest offset.
                 */
                int total_table_size = tblend + numecs + 1;
                char *trans_offset_type =
                (total_table_size >= INT16_MAX || long_align) ?
                "flex_int32_t" : "flex_int16_t";

                set_indent(0);
                indent_puts("struct yy_trans_info");
                indent_up();
                indent_puts("{");

                /*
                 * We require that yy_verify and yy_nxt must be of the same
                 * size int.
                 */
                indent_put2s("%s yy_verify;", trans_offset_type);

                /*
                 * In cases where its sister yy_verify *is* a "yes, there is
                 * a transition", yy_nxt is the offset (in records) to the
                 * next state.  In most cases where there is no transition,
                 * the value of yy_nxt is irrelevant.  If yy_nxt is the -1th
                 * record of a state, though, then yy_nxt is the action
                 * number for that state.
                 */

                indent_put2s("%s yy_nxt;", trans_offset_type);
                indent_puts("};");
                indent_down();
        } else {
                /*
                 * We generate a bogus 'struct yy_trans_info' data type so we
                 * can guarantee that it is always declared in the skel. This
                 * is so we can compile "sizeof(struct yy_trans_info)" in any
                 * scanner.
                 */
                indent_puts
                    ("/* This struct is not used in this scanner,");
                indent_puts("   but its presence is necessary. */");
                indent_puts("struct yy_trans_info");
                indent_up();
                indent_puts("{");
                indent_puts("flex_int32_t yy_verify;");
                indent_puts("flex_int32_t yy_nxt;");
                indent_puts("};");
                indent_down();
        }

        if (fullspd) {
                genctbl();
                if (tablesext) {
                        struct yytbl_data *tbl;

                        tbl = mkctbl();
                        yytbl_data_compress(tbl);
                        if (yytbl_data_fwrite(&tableswr, tbl) < 0)
                                flexerror(_("Could not write ftbl"));
                        yytbl_data_destroy(tbl);

                        tbl = mkssltbl();
                        yytbl_data_compress(tbl);
                        if (yytbl_data_fwrite(&tableswr, tbl) < 0)
                                flexerror(_("Could not write ssltbl"));
                        yytbl_data_destroy(tbl);
                        tbl = 0;

                        if (useecs) {
                                tbl = mkecstbl();
                                yytbl_data_compress(tbl);
                                if (yytbl_data_fwrite(&tableswr, tbl) < 0)
                                        flexerror(_
                                            ("Could not write ecstbl"));
                                yytbl_data_destroy(tbl);
                                tbl = 0;
                        }
                }
        } else if (fulltbl) {
                genftbl();
                if (tablesext) {
                        struct yytbl_data *tbl;

                        tbl = mkftbl();
                        yytbl_data_compress(tbl);
                        if (yytbl_data_fwrite(&tableswr, tbl) < 0)
                                flexerror(_("Could not write ftbl"));
                        yytbl_data_destroy(tbl);
                        tbl = 0;

                        if (useecs) {
                                tbl = mkecstbl();
                                yytbl_data_compress(tbl);
                                if (yytbl_data_fwrite(&tableswr, tbl) < 0)
                                        flexerror(_
                                            ("Could not write ecstbl"));
                                yytbl_data_destroy(tbl);
                                tbl = 0;
                        }
                }
        } else
                gentabs();

        if (do_yylineno) {

                geneoltbl();

                if (tablesext) {
                        struct yytbl_data *tbl;

                        tbl = mkeoltbl();
                        yytbl_data_compress(tbl);
                        if (yytbl_data_fwrite(&tableswr, tbl) < 0)
                                flexerror(_("Could not write eoltbl"));
                        yytbl_data_destroy(tbl);
                        tbl = 0;
                }
        }
        /*
         * Definitions for backing up.  We don't need them if REJECT is being
         * used because then we use an alternative backin-up technique
         * instead.
         */
        if (num_backing_up > 0 && !reject) {
                if (!C_plus_plus && !reentrant) {
                        indent_puts
                            ("static yy_state_type yy_last_accepting_state;");
                        indent_puts
                            ("static char *yy_last_accepting_cpos;\n");
                }
        }
        if (nultrans) {
                flex_int32_t *yynultrans_data = NULL;

                /* Begin generating yy_NUL_trans */
                out_str_dec(get_state_decl(), "yy_NUL_trans",
                    lastdfa + 1);
                buf_prints(&yydmap_buf,
                    "\t{YYTD_ID_NUL_TRANS, (void**)&yy_NUL_trans, sizeof(%s)},\n",
                    (fullspd) ? "struct yy_trans_info*" :
                    "flex_int32_t");

                yynultrans_tbl = calloc(1, sizeof(struct yytbl_data));
                yytbl_data_init(yynultrans_tbl, YYTD_ID_NUL_TRANS);
                if (fullspd)
                        yynultrans_tbl->td_flags |= YYTD_PTRANS;
                yynultrans_tbl->td_lolen = lastdfa + 1;
                yynultrans_tbl->td_data = yynultrans_data =
                    calloc(yynultrans_tbl->td_lolen,
                    sizeof(flex_int32_t));

                for (i = 1; i <= lastdfa; ++i) {
                        if (fullspd) {
                                out_dec("    &yy_transition[%d],\n",
                                    base[i]);
                                yynultrans_data[i] = base[i];
                        } else {
                                mkdata(nultrans[i]);
                                yynultrans_data[i] = nultrans[i];
                        }
                }

                dataend();
                if (tablesext) {
                        yytbl_data_compress(yynultrans_tbl);
                        if (yytbl_data_fwrite(&tableswr, yynultrans_tbl) < 0)
                                flexerror(_
                                    ("Could not write yynultrans_tbl"));
                        yytbl_data_destroy(yynultrans_tbl);
                        yynultrans_tbl = NULL;
                }
                /* End generating yy_NUL_trans */
        }
        if (!C_plus_plus && !reentrant) {
                indent_puts("extern int yy_flex_debug;");
                indent_put2s("int yy_flex_debug = %s;\n",
                    ddebug ? "1" : "0");
        }
        if (ddebug) {           /* Spit out table mapping rules to line
                                 * numbers. */
                out_str_dec(long_align ? get_int32_decl() :
                    get_int16_decl(), "yy_rule_linenum",
                    num_rules);
                for (i = 1; i < num_rules; ++i)
                        mkdata(rule_linenum[i]);
                dataend();
        }
        if (reject) {
                outn("m4_ifdef( [[M4_YY_USES_REJECT]],\n[[");
                /* Declare state buffer variables. */
                if (!C_plus_plus && !reentrant) {
                        outn("static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;");
                        outn("static char *yy_full_match;");
                        outn("static int yy_lp;");
                }
                if (variable_trailing_context_rules) {
                        if (!C_plus_plus && !reentrant) {
                                outn("static int yy_looking_for_trail_begin = 0;");
                                outn("static int yy_full_lp;");
                                outn("static int *yy_full_state;");
                        }
                        out_hex("#define YY_TRAILING_MASK 0x%x\n",
                            (unsigned int) YY_TRAILING_MASK);
                        out_hex("#define YY_TRAILING_HEAD_MASK 0x%x\n",
                            (unsigned int) YY_TRAILING_HEAD_MASK);
                }
                outn("#define REJECT \\");
                outn("{ \\");
                outn("*yy_cp = YY_G(yy_hold_char); /* undo effects of setting up yytext */ \\");
                outn("yy_cp = YY_G(yy_full_match); /* restore poss. backed-over text */ \\");

                if (variable_trailing_context_rules) {
                        outn("YY_G(yy_lp) = YY_G(yy_full_lp); /* restore orig. accepting pos. */ \\");
                        outn("YY_G(yy_state_ptr) = YY_G(yy_full_state); /* restore orig. state */ \\");
                        outn("yy_current_state = *YY_G(yy_state_ptr); /* restore curr. state */ \\");
                }
                outn("++YY_G(yy_lp); \\");
                outn("goto find_rule; \\");

                outn("}");
                outn("]])\n");
        } else {
                outn("/* The intent behind this definition is that it'll catch");
                outn(" * any uses of REJECT which flex missed.");
                outn(" */");
                outn("#define REJECT reject_used_but_not_detected");
        }

        if (yymore_used) {
                if (!C_plus_plus) {
                        if (yytext_is_array) {
                                if (!reentrant) {
                                        indent_puts("static int yy_more_offset = 0;");
                                        indent_puts("static int yy_prev_more_offset = 0;");
                                }
                        } else if (!reentrant) {
                                indent_puts
                                    ("static int yy_more_flag = 0;");
                                indent_puts
                                    ("static int yy_more_len = 0;");
                        }
                }
                if (yytext_is_array) {
                        indent_puts
                            ("#define yymore() (YY_G(yy_more_offset) = yy_flex_strlen( yytext M4_YY_CALL_LAST_ARG))");
                        indent_puts("#define YY_NEED_STRLEN");
                        indent_puts("#define YY_MORE_ADJ 0");
                        indent_puts
                            ("#define YY_RESTORE_YY_MORE_OFFSET \\");
                        indent_up();
                        indent_puts("{ \\");
                        indent_puts
                            ("YY_G(yy_more_offset) = YY_G(yy_prev_more_offset); \\");
                        indent_puts("yyleng -= YY_G(yy_more_offset); \\");
                        indent_puts("}");
                        indent_down();
                } else {
                        indent_puts
                            ("#define yymore() (YY_G(yy_more_flag) = 1)");
                        indent_puts
                            ("#define YY_MORE_ADJ YY_G(yy_more_len)");
                        indent_puts("#define YY_RESTORE_YY_MORE_OFFSET");
                }
        } else {
                indent_puts
                    ("#define yymore() yymore_used_but_not_detected");
                indent_puts("#define YY_MORE_ADJ 0");
                indent_puts("#define YY_RESTORE_YY_MORE_OFFSET");
        }

        if (!C_plus_plus) {
                if (yytext_is_array) {
                        outn("#ifndef YYLMAX");
                        outn("#define YYLMAX 8192");
                        outn("#endif\n");
                        if (!reentrant) {
                                outn("char yytext[YYLMAX];");
                                outn("char *yytext_ptr;");
                        }
                } else {
                        if (!reentrant)
                                outn("char *yytext;");
                }
        }
        out(&action_array[defs1_offset]);

        line_directive_out(stdout, 0);

        skelout();              /* %% [5.0] - break point in skel */

        if (!C_plus_plus) {
                if (use_read) {
                        outn("\terrno=0; \\");
                        outn("\twhile ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \\");
                        outn("\t{ \\");
                        outn("\t\tif( errno != EINTR) \\");
                        outn("\t\t{ \\");
                        outn("\t\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" ); \\");
                        outn("\t\t\tbreak; \\");
                        outn("\t\t} \\");
                        outn("\t\terrno=0; \\");
                        outn("\t\tclearerr(yyin); \\");
                        outn("\t}\\");
                } else {
                        outn("\tif ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \\");
                        outn("\t\t{ \\");
                        outn("\t\tint c = '*'; \\");
                        outn("\t\tsize_t n; \\");
                        outn("\t\tfor ( n = 0; n < max_size && \\");
                        outn("\t\t\t     (c = getc( yyin )) != EOF && c != '\\n'; ++n ) \\");
                        outn("\t\t\tbuf[n] = (char) c; \\");
                        outn("\t\tif ( c == '\\n' ) \\");
                        outn("\t\t\tbuf[n++] = (char) c; \\");
                        outn("\t\tif ( c == EOF && ferror( yyin ) ) \\");
                        outn("\t\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" ); \\");
                        outn("\t\tresult = n; \\");
                        outn("\t\t} \\");
                        outn("\telse \\");
                        outn("\t\t{ \\");
                        outn("\t\terrno=0; \\");
                        outn("\t\twhile ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \\");
                        outn("\t\t\t{ \\");
                        outn("\t\t\tif( errno != EINTR) \\");
                        outn("\t\t\t\t{ \\");
                        outn("\t\t\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" ); \\");
                        outn("\t\t\t\tbreak; \\");
                        outn("\t\t\t\t} \\");
                        outn("\t\t\terrno=0; \\");
                        outn("\t\t\tclearerr(yyin); \\");
                        outn("\t\t\t} \\");
                        outn("\t\t}\\");
                }
        }
        skelout();              /* %% [6.0] - break point in skel */

        indent_puts("#define YY_RULE_SETUP \\");
        indent_up();
        if (bol_needed) {
                indent_puts("if ( yyleng > 0 ) \\");
                indent_up();
                indent_puts("YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \\");
                indent_puts("\t\t(yytext[yyleng - 1] == '\\n'); \\");
                indent_down();
        }
        indent_puts("YY_USER_ACTION");
        indent_down();

        skelout();              /* %% [7.0] - break point in skel */

        /* Copy prolog to output file. */
        out(&action_array[prolog_offset]);

        line_directive_out(stdout, 0);

        skelout();              /* %% [8.0] - break point in skel */

        set_indent(2);

        if (yymore_used && !yytext_is_array) {
                indent_puts("YY_G(yy_more_len) = 0;");
                indent_puts("if ( YY_G(yy_more_flag) )");
                indent_up();
                indent_puts("{");
                indent_puts
                    ("YY_G(yy_more_len) = YY_G(yy_c_buf_p) - YY_G(yytext_ptr);");
                indent_puts("YY_G(yy_more_flag) = 0;");
                indent_puts("}");
                indent_down();
        }
        skelout();              /* %% [9.0] - break point in skel */

        gen_start_state();

        /* Note, don't use any indentation. */
        outn("yy_match:");
        gen_next_match();

        skelout();              /* %% [10.0] - break point in skel */
        set_indent(2);
        gen_find_action();

        skelout();              /* %% [11.0] - break point in skel */
        outn("m4_ifdef( [[M4_YY_USE_LINENO]],[[");
        indent_puts
            ("if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )");
        indent_up();
        indent_puts("{");
        indent_puts("yy_size_t yyl;");
        do_indent();
        out_str("for ( yyl = %s; yyl < yyleng; ++yyl )\n",
            yymore_used ? (yytext_is_array ? "YY_G(yy_prev_more_offset)" :
                "YY_G(yy_more_len)") : "0");
        indent_up();
        indent_puts("if ( yytext[yyl] == '\\n' )");
        indent_up();
        indent_puts("M4_YY_INCR_LINENO();");
        indent_down();
        indent_down();
        indent_puts("}");
        indent_down();
        outn("]])");

        skelout();              /* %% [12.0] - break point in skel */
        if (ddebug) {
                indent_puts("if ( yy_flex_debug )");
                indent_up();

                indent_puts("{");
                indent_puts("if ( yy_act == 0 )");
                indent_up();
                indent_puts(C_plus_plus ?
                    "std::cerr << \"--scanner backing up\\n\";" :
                    "fprintf( stderr, \"--scanner backing up\\n\" );");
                indent_down();

                do_indent();
                out_dec("else if ( yy_act < %d )\n", num_rules);
                indent_up();

                if (C_plus_plus) {
                        indent_puts
                            ("std::cerr << \"--accepting rule at line \" << yy_rule_linenum[yy_act] <<");
                        indent_puts
                            ("         \"(\\\"\" << yytext << \"\\\")\\n\";");
                } else {
                        indent_puts
                            ("fprintf( stderr, \"--accepting rule at line %ld (\\\"%s\\\")\\n\",");

                        indent_puts
                            ("         (long)yy_rule_linenum[yy_act], yytext );");
                }

                indent_down();

                do_indent();
                out_dec("else if ( yy_act == %d )\n", num_rules);
                indent_up();

                if (C_plus_plus) {
                        indent_puts
                            ("std::cerr << \"--accepting default rule (\\\"\" << yytext << \"\\\")\\n\";");
                } else {
                        indent_puts
                            ("fprintf( stderr, \"--accepting default rule (\\\"%s\\\")\\n\",");
                        indent_puts("         yytext );");
                }

                indent_down();

                do_indent();
                out_dec("else if ( yy_act == %d )\n", num_rules + 1);
                indent_up();

                indent_puts(C_plus_plus ?
                    "std::cerr << \"--(end of buffer or a NUL)\\n\";" :
                    "fprintf( stderr, \"--(end of buffer or a NUL)\\n\" );");

                indent_down();

                do_indent();
                outn("else");
                indent_up();

                if (C_plus_plus) {
                        indent_puts
                            ("std::cerr << \"--EOF (start condition \" << YY_START << \")\\n\";");
                } else {
                        indent_puts
                            ("fprintf( stderr, \"--EOF (start condition %d)\\n\", YY_START );");
                }

                indent_down();

                indent_puts("}");
                indent_down();
        }
        /* Copy actions to output file. */
        skelout();              /* %% [13.0] - break point in skel */
        indent_up();
        gen_bu_action();
        out(&action_array[action_offset]);

        line_directive_out(stdout, 0);

        /* generate cases for any missing EOF rules */
        for (i = 1; i <= lastsc; ++i)
                if (!sceof[i]) {
                        do_indent();
                        out_str("case YY_STATE_EOF(%s):\n", scname[i]);
                        did_eof_rule = true;
                }
        if (did_eof_rule) {
                indent_up();
                indent_puts("yyterminate();");
                indent_down();
        }
        /* Generate code for handling NUL's, if needed. */

        /*
         * First, deal with backing up and setting up yy_cp if the scanner
         * finds that it should JAM on the NUL.
         */
        skelout();              /* %% [14.0] - break point in skel */
        set_indent(4);

        if (fullspd || fulltbl)
                indent_puts("yy_cp = YY_G(yy_c_buf_p);");

        else {                  /* compressed table */
                if (!reject && !interactive) {
                        /*
                         * Do the guaranteed-needed backing up to figure out
                         * the match.
                         */
                        indent_puts
                            ("yy_cp = YY_G(yy_last_accepting_cpos);");
                        indent_puts
                            ("yy_current_state = YY_G(yy_last_accepting_state);");
                } else
                        /*
                         * Still need to initialize yy_cp, though
                         * yy_current_state was set up by
                         * yy_get_previous_state().
                         */
                        indent_puts("yy_cp = YY_G(yy_c_buf_p);");
        }


        /* Generate code for yy_get_previous_state(). */
        set_indent(1);
        skelout();              /* %% [15.0] - break point in skel */

        gen_start_state();

        set_indent(2);
        skelout();              /* %% [16.0] - break point in skel */
        gen_next_state(true);

        set_indent(1);
        skelout();              /* %% [17.0] - break point in skel */
        gen_NUL_trans();

        skelout();              /* %% [18.0] - break point in skel */
        skelout();              /* %% [19.0] - break point in skel */
        /* Update BOL and yylineno inside of input(). */
        if (bol_needed) {
                indent_puts
                    ("YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\\n');");
                if (do_yylineno) {
                        indent_puts
                            ("if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )");
                        indent_up();
                        indent_puts("M4_YY_INCR_LINENO();");
                        indent_down();
                }
        } else if (do_yylineno) {
                indent_puts("if ( c == '\\n' )");
                indent_up();
                indent_puts("M4_YY_INCR_LINENO();");
                indent_down();
        }
        skelout();

        /* Copy remainder of input to output. */

        line_directive_out(stdout, 1);

        if (sectnum == 3) {
                OUT_BEGIN_CODE();
                (void) flexscan();      /* copy remainder of input to output */
                OUT_END_CODE();
        }
}