Imported Upstream version 20170430
[platform/upstream/byacc.git] / output.c
index 53223de..d52d920 100644 (file)
--- a/output.c
+++ b/output.c
@@ -1,14 +1,24 @@
-/* $Id: output.c,v 1.38 2010/12/29 18:35:38 Christos.Zoulas Exp $ */
+/* $Id: output.c,v 1.81 2017/04/30 23:23:32 tom Exp $ */
 
 #include "defs.h"
 
 #define StaticOrR      (rflag ? "" : "static ")
 #define CountLine(fp)   (!rflag || ((fp) == code_file))
 
+#if defined(YYBTYACC)
+#define PER_STATE 3
+#else
+#define PER_STATE 2
+#endif
+
 static int nvectors;
 static int nentries;
 static Value_t **froms;
 static Value_t **tos;
+#if defined(YYBTYACC)
+static Value_t *conflicts = NULL;
+static Value_t nconflicts = 0;
+#endif
 static Value_t *tally;
 static Value_t *width;
 static Value_t *state_count;
@@ -19,36 +29,74 @@ static int maxtable;
 static Value_t *table;
 static Value_t *check;
 static int lowzero;
-static int high;
+static long high;
 
 static void
-putc_code(int c)
+putc_code(FILE * fp, int c)
 {
-    if (c == '\n')
+    if ((c == '\n') && (fp == code_file))
        ++outline;
-    putc(c, code_file);
+    putc(c, fp);
 }
 
 static void
-putl_code(const char *s)
+putl_code(FILE * fp, const char *s)
 {
-    ++outline;
-    fputs(s, code_file);
+    if (fp == code_file)
+       ++outline;
+    fputs(s, fp);
 }
 
 static void
-puts_code(const char *s)
+puts_code(FILE * fp, const char *s)
 {
-    fputs(s, code_file);
+    fputs(s, fp);
 }
 
 static void
-write_code_lineno(void)
+puts_param_types(FILE * fp, param *list, int more)
 {
-    if (!lflag)
+    param *p;
+
+    if (list != 0)
+    {
+       for (p = list; p; p = p->next)
+       {
+           size_t len_type = strlen(p->type);
+           fprintf(fp, "%s%s%s%s%s", p->type,
+                   (((len_type != 0) && (p->type[len_type - 1] == '*'))
+                    ? ""
+                    : " "),
+                   p->name, p->type2,
+                   ((more || p->next) ? ", " : ""));
+       }
+    }
+    else
+    {
+       if (!more)
+           fprintf(fp, "void");
+    }
+}
+
+static void
+puts_param_names(FILE * fp, param *list, int more)
+{
+    param *p;
+
+    for (p = list; p; p = p->next)
+    {
+       fprintf(fp, "%s%s", p->name,
+               ((more || p->next) ? ", " : ""));
+    }
+}
+
+static void
+write_code_lineno(FILE * fp)
+{
+    if (!lflag && (fp == code_file))
     {
        ++outline;
-       fprintf(code_file, line_format, outline, code_file_name);
+       fprintf(fp, line_format, outline + 1, code_file_name);
     }
 }
 
@@ -104,6 +152,9 @@ output_prefix(FILE * fp)
        define_prefixed(fp, "yylhs");
        define_prefixed(fp, "yylen");
        define_prefixed(fp, "yydefred");
+#if defined(YYBTYACC)
+       define_prefixed(fp, "yystos");
+#endif
        define_prefixed(fp, "yydgoto");
        define_prefixed(fp, "yysindex");
        define_prefixed(fp, "yyrindex");
@@ -112,6 +163,22 @@ output_prefix(FILE * fp)
        define_prefixed(fp, "yycheck");
        define_prefixed(fp, "yyname");
        define_prefixed(fp, "yyrule");
+#if defined(YYBTYACC)
+       if (locations)
+       {
+           define_prefixed(fp, "yyloc");
+           define_prefixed(fp, "yylloc");
+       }
+       putc_code(fp, '\n');
+       putl_code(fp, "#if YYBTYACC\n");
+
+       define_prefixed(fp, "yycindex");
+       define_prefixed(fp, "yyctable");
+
+       putc_code(fp, '\n');
+       putl_code(fp, "#endif /* YYBTYACC */\n");
+       putc_code(fp, '\n');
+#endif
     }
     if (CountLine(fp))
        ++outline;
@@ -147,7 +214,7 @@ start_int_table(const char *name, int value)
     if (need < 6)
        need = 6;
     fprintf(output_file,
-           "%sconst short %s%s[] = {%*d,",
+           "%sconst YYINT %s%s[] = {%*d,",
            StaticOrR, symbol_prefix, name, need, value);
 }
 
@@ -155,8 +222,8 @@ static void
 start_str_table(const char *name)
 {
     fprintf(output_file,
-           "%sconst char *%s%s[] = {",
-           StaticOrR, "yy", name);
+           "%sconst char *const %s%s[] = {",
+           StaticOrR, symbol_prefix, name);
     output_newline();
 }
 
@@ -168,11 +235,59 @@ end_table(void)
 }
 
 static void
+output_stype(FILE * fp)
+{
+    if (!unionized && ntags == 0)
+    {
+       putc_code(fp, '\n');
+       putl_code(fp, "#if "
+                 "! defined(YYSTYPE) && "
+                 "! defined(YYSTYPE_IS_DECLARED)\n");
+       putl_code(fp, "/* Default: YYSTYPE is the semantic value type. */\n");
+       putl_code(fp, "typedef int YYSTYPE;\n");
+       putl_code(fp, "# define YYSTYPE_IS_DECLARED 1\n");
+       putl_code(fp, "#endif\n");
+    }
+}
+
+#if defined(YYBTYACC)
+static void
+output_ltype(FILE * fp)
+{
+    putc_code(fp, '\n');
+    putl_code(fp, "#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED\n");
+    putl_code(fp, "/* Default: YYLTYPE is the text position type. */\n");
+    putl_code(fp, "typedef struct YYLTYPE\n");
+    putl_code(fp, "{\n");
+    putl_code(fp, "    int first_line;\n");
+    putl_code(fp, "    int first_column;\n");
+    putl_code(fp, "    int last_line;\n");
+    putl_code(fp, "    int last_column;\n");
+    putl_code(fp, "    unsigned source;\n");
+    putl_code(fp, "} YYLTYPE;\n");
+    putl_code(fp, "#define YYLTYPE_IS_DECLARED 1\n");
+    putl_code(fp, "#endif\n");
+    putl_code(fp, "#define YYRHSLOC(rhs, k) ((rhs)[k])\n");
+}
+#endif
+
+static void
+output_YYINT_typedef(FILE * fp)
+{
+    /* generate the type used to index the various parser tables */
+    if (CountLine(fp))
+       ++outline;
+    fprintf(fp, "typedef %s YYINT;\n", CONCAT1("", YYINT));
+}
+
+static void
 output_rule_data(void)
 {
     int i;
     int j;
 
+    output_YYINT_typedef(output_file);
+
     start_int_table("lhs", symbol_value[start_symbol]);
 
     j = 10;
@@ -232,27 +347,127 @@ output_yydefred(void)
     end_table();
 }
 
+#if defined(YYBTYACC)
+static void
+output_accessing_symbols(void)
+{
+    int i, j;
+    int *translate;
+
+    if (nstates != 0)
+    {
+       translate = TMALLOC(int, nstates);
+       NO_SPACE(translate);
+
+       for (i = 0; i < nstates; ++i)
+       {
+           int gsymb = accessing_symbol[i];
+
+           translate[i] = symbol_pval[gsymb];
+       }
+
+       putl_code(output_file,
+                 "#if defined(YYDESTRUCT_CALL) || defined(YYSTYPE_TOSTRING)\n");
+       /* yystos[] may be unused, depending on compile-time defines */
+       start_int_table("stos", translate[0]);
+
+       j = 10;
+       for (i = 1; i < nstates; ++i)
+       {
+           if (j < 10)
+               ++j;
+           else
+           {
+               output_newline();
+               j = 1;
+           }
+
+           output_int(translate[i]);
+       }
+
+       end_table();
+       FREE(translate);
+       putl_code(output_file,
+                 "#endif /* YYDESTRUCT_CALL || YYSTYPE_TOSTRING */\n");
+    }
+}
+
+static Value_t
+find_conflict_base(int cbase)
+{
+    int i, j;
+
+    for (i = 0; i < cbase; i++)
+    {
+       for (j = 0; j + cbase < nconflicts; j++)
+       {
+           if (conflicts[i + j] != conflicts[cbase + j])
+               break;
+       }
+       if (j + cbase >= nconflicts)
+           break;
+    }
+    return (Value_t)i;
+}
+#endif
+
 static void
 token_actions(void)
 {
     int i, j;
     Value_t shiftcount, reducecount;
+#if defined(YYBTYACC)
+    Value_t conflictcount = 0;
+    Value_t csym = -1;
+    Value_t cbase = 0;
+#endif
     int max, min;
     Value_t *actionrow, *r, *s;
     action *p;
 
-    actionrow = NEW2(2 * ntokens, Value_t);
+    actionrow = NEW2(PER_STATE * ntokens, Value_t);
     for (i = 0; i < nstates; ++i)
     {
        if (parser[i])
        {
-           for (j = 0; j < 2 * ntokens; ++j)
+           for (j = 0; j < PER_STATE * ntokens; ++j)
                actionrow[j] = 0;
 
            shiftcount = 0;
            reducecount = 0;
+#if defined(YYBTYACC)
+           if (backtrack)
+           {
+               conflictcount = 0;
+               csym = -1;
+               cbase = nconflicts;
+           }
+#endif
            for (p = parser[i]; p; p = p->next)
            {
+#if defined(YYBTYACC)
+               if (backtrack)
+               {
+                   if (csym != -1 && csym != p->symbol)
+                   {
+                       conflictcount++;
+                       conflicts[nconflicts++] = -1;
+                       j = find_conflict_base(cbase);
+                       actionrow[csym + 2 * ntokens] = (Value_t)(j + 1);
+                       if (j == cbase)
+                       {
+                           cbase = nconflicts;
+                       }
+                       else
+                       {
+                           if (conflicts[cbase] == -1)
+                               cbase++;
+                           nconflicts = cbase;
+                       }
+                       csym = -1;
+                   }
+               }
+#endif
                if (p->suppressed == 0)
                {
                    if (p->action_code == SHIFT)
@@ -266,17 +481,65 @@ token_actions(void)
                        actionrow[p->symbol + ntokens] = p->number;
                    }
                }
+#if defined(YYBTYACC)
+               else if (backtrack && p->suppressed == 1)
+               {
+                   csym = p->symbol;
+                   if (p->action_code == SHIFT)
+                   {
+                       conflicts[nconflicts++] = p->number;
+                   }
+                   else if (p->action_code == REDUCE && p->number != defred[i])
+                   {
+                       if (cbase == nconflicts)
+                       {
+                           if (cbase)
+                               cbase--;
+                           else
+                               conflicts[nconflicts++] = -1;
+                       }
+                       conflicts[nconflicts++] = (Value_t)(p->number - 2);
+                   }
+               }
+#endif
+           }
+#if defined(YYBTYACC)
+           if (backtrack && csym != -1)
+           {
+               conflictcount++;
+               conflicts[nconflicts++] = -1;
+               j = find_conflict_base(cbase);
+               actionrow[csym + 2 * ntokens] = (Value_t)(j + 1);
+               if (j == cbase)
+               {
+                   cbase = nconflicts;
+               }
+               else
+               {
+                   if (conflicts[cbase] == -1)
+                       cbase++;
+                   nconflicts = cbase;
+               }
            }
+#endif
 
            tally[i] = shiftcount;
            tally[nstates + i] = reducecount;
+#if defined(YYBTYACC)
+           if (backtrack)
+               tally[2 * nstates + i] = conflictcount;
+#endif
            width[i] = 0;
            width[nstates + i] = 0;
+#if defined(YYBTYACC)
+           if (backtrack)
+               width[2 * nstates + i] = 0;
+#endif
            if (shiftcount > 0)
            {
                froms[i] = r = NEW2(shiftcount, Value_t);
                tos[i] = s = NEW2(shiftcount, Value_t);
-               min = MAXSHORT;
+               min = MAXYYINT;
                max = 0;
                for (j = 0; j < ntokens; ++j)
                {
@@ -290,13 +553,13 @@ token_actions(void)
                        *s++ = actionrow[j];
                    }
                }
-               width[i] = (Value_t) (max - min + 1);
+               width[i] = (Value_t)(max - min + 1);
            }
            if (reducecount > 0)
            {
                froms[nstates + i] = r = NEW2(reducecount, Value_t);
                tos[nstates + i] = s = NEW2(reducecount, Value_t);
-               min = MAXSHORT;
+               min = MAXYYINT;
                max = 0;
                for (j = 0; j < ntokens; ++j)
                {
@@ -307,11 +570,33 @@ token_actions(void)
                        if (max < symbol_value[j])
                            max = symbol_value[j];
                        *r++ = symbol_value[j];
-                       *s++ = (Value_t) (actionrow[ntokens + j] - 2);
+                       *s++ = (Value_t)(actionrow[ntokens + j] - 2);
+                   }
+               }
+               width[nstates + i] = (Value_t)(max - min + 1);
+           }
+#if defined(YYBTYACC)
+           if (backtrack && conflictcount > 0)
+           {
+               froms[2 * nstates + i] = r = NEW2(conflictcount, Value_t);
+               tos[2 * nstates + i] = s = NEW2(conflictcount, Value_t);
+               min = MAXYYINT;
+               max = 0;
+               for (j = 0; j < ntokens; ++j)
+               {
+                   if (actionrow[2 * ntokens + j])
+                   {
+                       if (min > symbol_value[j])
+                           min = symbol_value[j];
+                       if (max < symbol_value[j])
+                           max = symbol_value[j];
+                       *r++ = symbol_value[j];
+                       *s++ = (Value_t)(actionrow[2 * ntokens + j] - 1);
                    }
                }
-               width[nstates + i] = (Value_t) (max - min + 1);
+               width[2 * nstates + i] = (Value_t)(max - min + 1);
            }
+#endif
        }
     }
     FREE(actionrow);
@@ -376,7 +661,7 @@ save_column(int symbol, int default_state)
     if (count == 0)
        return;
 
-    symno = symbol_value[symbol] + 2 * nstates;
+    symno = symbol_value[symbol] + PER_STATE * nstates;
 
     froms[symno] = sp1 = sp = NEW2(count, Value_t);
     tos[symno] = sp2 = NEW2(count, Value_t);
@@ -391,7 +676,7 @@ save_column(int symbol, int default_state)
     }
 
     tally[symno] = count;
-    width[symno] = (Value_t) (sp1[-1] - sp[0] + 1);
+    width[symno] = (Value_t)(sp1[-1] - sp[0] + 1);
 }
 
 static void
@@ -475,6 +760,11 @@ sort_actions(void)
 /*  Matching_vector is poorly designed.  The test could easily be made */
 /*  faster.  Also, it depends on the vectors being in a specific       */
 /*  order.                                                             */
+#if defined(YYBTYACC)
+/*                                                                     */
+/*  Not really any point in checking for matching conflicts -- it is    */
+/*  extremely unlikely to occur, and conflicts are (hopefully) rare.    */
+#endif
 
 static int
 matching_vector(int vector)
@@ -556,10 +846,10 @@ pack_vector(int vector)
                }
                while (newmax <= loc);
 
-               table = (Value_t *) REALLOC(table, (unsigned)newmax * sizeof(Value_t));
+               table = TREALLOC(Value_t, table, newmax);
                NO_SPACE(table);
 
-               check = (Value_t *) REALLOC(check, (unsigned)newmax * sizeof(Value_t));
+               check = TREALLOC(Value_t, check, newmax);
                NO_SPACE(check);
 
                for (l = maxtable; l < newmax; ++l)
@@ -622,7 +912,7 @@ pack_table(void)
        state = matching_vector(i);
 
        if (state < 0)
-           place = (Value_t) pack_vector(i);
+           place = (Value_t)pack_vector(i);
        else
            place = base[state];
 
@@ -638,9 +928,11 @@ pack_table(void)
            FREE(tos[i]);
     }
 
-    FREE(froms);
-    FREE(tos);
-    FREE(pos);
+    DO_FREE(froms);
+    DO_FREE(tos);
+    DO_FREE(tally);
+    DO_FREE(width);
+    DO_FREE(pos);
 }
 
 static void
@@ -684,10 +976,32 @@ output_base(void)
 
     end_table();
 
-    start_int_table("gindex", base[2 * nstates]);
+#if defined(YYBTYACC)
+    output_line("#if YYBTYACC");
+    start_int_table("cindex", base[2 * nstates]);
 
     j = 10;
-    for (i = 2 * nstates + 1; i < nvectors - 1; i++)
+    for (i = 2 * nstates + 1; i < 3 * nstates; i++)
+    {
+       if (j >= 10)
+       {
+           output_newline();
+           j = 1;
+       }
+       else
+           ++j;
+
+       output_int(base[i]);
+    }
+
+    end_table();
+    output_line("#endif");
+#endif
+
+    start_int_table("gindex", base[PER_STATE * nstates]);
+
+    j = 10;
+    for (i = PER_STATE * nstates + 1; i < nvectors - 1; i++)
     {
        if (j >= 10)
        {
@@ -710,8 +1024,15 @@ output_table(void)
     int i;
     int j;
 
+    if (high >= MAXYYINT)
+    {
+       fprintf(stderr, "YYTABLESIZE: %ld\n", high);
+       fprintf(stderr, "Table is longer than %d elements.\n", MAXYYINT);
+       done(1);
+    }
+
     ++outline;
-    fprintf(code_file, "#define YYTABLESIZE %d\n", high);
+    fprintf(code_file, "#define YYTABLESIZE %ld\n", high);
     start_int_table("table", table[0]);
 
     j = 10;
@@ -758,16 +1079,57 @@ output_check(void)
     FREE(check);
 }
 
+#if defined(YYBTYACC)
+static void
+output_ctable(void)
+{
+    int i;
+    int j;
+    int limit = (conflicts != 0) ? nconflicts : 0;
+
+    if (limit < high)
+       limit = (int)high;
+
+    output_line("#if YYBTYACC");
+    start_int_table("ctable", conflicts ? conflicts[0] : -1);
+
+    j = 10;
+    for (i = 1; i < limit; i++)
+    {
+       if (j >= 10)
+       {
+           output_newline();
+           j = 1;
+       }
+       else
+           ++j;
+
+       output_int((conflicts != 0 && i < nconflicts) ? conflicts[i] : -1);
+    }
+
+    if (conflicts)
+       FREE(conflicts);
+
+    end_table();
+    output_line("#endif");
+}
+#endif
+
 static void
 output_actions(void)
 {
-    nvectors = 2 * nstates + nvars;
+    nvectors = PER_STATE * nstates + nvars;
 
     froms = NEW2(nvectors, Value_t *);
     tos = NEW2(nvectors, Value_t *);
     tally = NEW2(nvectors, Value_t);
     width = NEW2(nvectors, Value_t);
 
+#if defined(YYBTYACC)
+    if (backtrack && (SRtotal + RRtotal) != 0)
+       conflicts = NEW2(4 * (SRtotal + RRtotal), Value_t);
+#endif
+
     token_actions();
     FREE(lookaheads);
     FREE(LA);
@@ -775,7 +1137,7 @@ output_actions(void)
     FREE(accessing_symbol);
 
     goto_actions();
-    FREE(goto_map + ntokens);
+    FREE(goto_base);
     FREE(from_state);
     FREE(to_state);
 
@@ -784,6 +1146,9 @@ output_actions(void)
     output_base();
     output_table();
     output_check();
+#if defined(YYBTYACC)
+    output_ctable();
+#endif
 }
 
 static int
@@ -817,8 +1182,26 @@ is_C_identifier(char *name)
     return (1);
 }
 
+#if USE_HEADER_GUARDS
 static void
-output_defines(void)
+start_defines_file(void)
+{
+    fprintf(defines_file, "#ifndef _%s_defines_h_\n", symbol_prefix);
+    fprintf(defines_file, "#define _%s_defines_h_\n\n", symbol_prefix);
+}
+
+static void
+end_defines_file(void)
+{
+    fprintf(defines_file, "\n#endif /* _%s_defines_h_ */\n", symbol_prefix);
+}
+#else
+#define start_defines_file()   /* nothing */
+#define end_defines_file()     /* nothing */
+#endif
+
+static void
+output_defines(FILE * fp)
 {
     int c, i;
     char *s;
@@ -826,53 +1209,67 @@ output_defines(void)
     for (i = 2; i < ntokens; ++i)
     {
        s = symbol_name[i];
-       if (is_C_identifier(s))
+       if (is_C_identifier(s) && (!sflag || *s != '"'))
        {
-           puts_code("#define ");
-           if (dflag)
-               fprintf(defines_file, "#define ");
+           fprintf(fp, "#define ");
            c = *s;
            if (c == '"')
            {
                while ((c = *++s) != '"')
                {
-                   putc(c, code_file);
-                   if (dflag)
-                       putc(c, defines_file);
+                   putc(c, fp);
                }
            }
            else
            {
                do
                {
-                   putc(c, code_file);
-                   if (dflag)
-                       putc(c, defines_file);
+                   putc(c, fp);
                }
                while ((c = *++s) != 0);
            }
-           ++outline;
-           fprintf(code_file, " %d\n", symbol_value[i]);
-           if (dflag)
-               fprintf(defines_file, " %d\n", symbol_value[i]);
+           if (fp == code_file)
+               ++outline;
+           fprintf(fp, " %d\n", symbol_value[i]);
        }
     }
 
-    ++outline;
-    fprintf(code_file, "#define YYERRCODE %d\n", symbol_value[1]);
+    if (fp == code_file)
+       ++outline;
+    if (fp != defines_file || iflag)
+       fprintf(fp, "#define YYERRCODE %d\n", symbol_value[1]);
+
+    if (token_table && rflag && fp != externs_file)
+    {
+       if (fp == code_file)
+           ++outline;
+       fputs("#undef yytname\n", fp);
+       if (fp == code_file)
+           ++outline;
+       fputs("#define yytname yyname\n", fp);
+    }
 
-    if (dflag && unionized)
+    if (fp == defines_file || (iflag && !dflag))
     {
-       rewind(union_file);
-       while ((c = getc(union_file)) != EOF)
-           putc(c, defines_file);
-       fprintf(defines_file, "extern YYSTYPE %slval;\n",
-               symbol_prefix);
+       if (unionized)
+       {
+           if (union_file != 0)
+           {
+               rewind(union_file);
+               while ((c = getc(union_file)) != EOF)
+                   putc_code(fp, c);
+           }
+           fprintf(fp, "extern YYSTYPE %slval;\n", symbol_prefix);
+       }
+#if defined(YYBTYACC)
+       if (locations)
+           output_ltype(fp);
+#endif
     }
 }
 
 static void
-output_stored_text(void)
+output_stored_text(FILE * fp)
 {
     int c;
     FILE *in;
@@ -883,28 +1280,28 @@ output_stored_text(void)
     in = text_file;
     if ((c = getc(in)) == EOF)
        return;
-    putc_code(c);
+    putc_code(fp, c);
     while ((c = getc(in)) != EOF)
     {
-       putc_code(c);
+       putc_code(fp, c);
     }
-    write_code_lineno();
+    write_code_lineno(fp);
 }
 
 static void
 output_debug(void)
 {
-    int i, j, k, max;
+    int i, j, k, max, maxtok;
     const char **symnam;
     const char *s;
 
     ++outline;
     fprintf(code_file, "#define YYFINAL %d\n", final_state);
 
-    putl_code("#ifndef YYDEBUG\n");
+    putl_code(code_file, "#ifndef YYDEBUG\n");
     ++outline;
     fprintf(code_file, "#define YYDEBUG %d\n", tflag);
-    putl_code("#endif\n");
+    putl_code(code_file, "#endif\n");
 
     if (rflag)
     {
@@ -913,30 +1310,72 @@ output_debug(void)
        fprintf(output_file, "#endif\n");
     }
 
-    max = 0;
-    for (i = 2; i < ntokens; ++i)
-       if (symbol_value[i] > max)
-           max = symbol_value[i];
+    maxtok = 0;
+    for (i = 0; i < ntokens; ++i)
+       if (symbol_value[i] > maxtok)
+           maxtok = symbol_value[i];
+
+    /* symbol_value[$accept] = -1         */
+    /* symbol_value[<goal>]  = 0          */
+    /* remaining non-terminals start at 1 */
+    max = maxtok;
+    for (i = ntokens; i < nsyms; ++i)
+       if (((maxtok + 1) + (symbol_value[i] + 1)) > max)
+           max = (maxtok + 1) + (symbol_value[i] + 1);
 
     ++outline;
-    fprintf(code_file, "#define YYMAXTOKEN %d\n", max);
+    fprintf(code_file, "#define YYMAXTOKEN %d\n", maxtok);
 
-    symnam = (const char **)MALLOC((unsigned)(max + 1) * sizeof(char *));
+    ++outline;
+    fprintf(code_file, "#define YYUNDFTOKEN %d\n", max + 1);
+
+    ++outline;
+    fprintf(code_file, "#define YYTRANSLATE(a) ((a) > YYMAXTOKEN ? "
+           "YYUNDFTOKEN : (a))\n");
+
+    symnam = TMALLOC(const char *, max + 2);
     NO_SPACE(symnam);
 
-    /* Note that it is  not necessary to initialize the element         */
+    /* Note that it is not necessary to initialize the element          */
     /* symnam[max].                                                     */
+#if defined(YYBTYACC)
     for (i = 0; i < max; ++i)
        symnam[i] = 0;
+    for (i = nsyms - 1; i >= 0; --i)
+       symnam[symbol_pval[i]] = symbol_name[i];
+    symnam[max + 1] = "illegal-symbol";
+#else
+    for (i = 0; i <= max; ++i)
+       symnam[i] = 0;
     for (i = ntokens - 1; i >= 2; --i)
        symnam[symbol_value[i]] = symbol_name[i];
     symnam[0] = "end-of-file";
+    symnam[max + 1] = "illegal-symbol";
+#endif
 
-    output_line("#if YYDEBUG");
+    /*
+     * bison's yytname[] array is roughly the same as byacc's yyname[] array.
+     * The difference is that byacc does not predefine "$undefined".
+     *
+     * If the grammar declares "%token-table", define symbol "yytname" so
+     * an application such as ntpd can build.
+     */
+    if (token_table)
+    {
+       if (!rflag)
+       {
+           output_line("#undef yytname");
+           output_line("#define yytname yyname");
+       }
+    }
+    else
+    {
+       output_line("#if YYDEBUG");
+    }
 
     start_str_table("name");
     j = 80;
-    for (i = 0; i <= max; ++i)
+    for (i = 0; i <= max + 1; ++i)
     {
        if ((s = symnam[i]) != 0)
        {
@@ -1057,6 +1496,8 @@ output_debug(void)
     end_table();
     FREE(symnam);
 
+    if (token_table)
+       output_line("#if YYDEBUG");
     start_str_table("rule");
     for (i = 2; i < nrules; ++i)
     {
@@ -1111,29 +1552,50 @@ output_debug(void)
     output_line("#endif");
 }
 
+#if defined(YYBTYACC)
 static void
-output_pure_parser(void)
+output_backtracking_parser(FILE * fp)
 {
-    putc_code('\n');
+    putl_code(fp, "#undef YYBTYACC\n");
+#if defined(YYBTYACC)
+    if (backtrack)
+    {
+       putl_code(fp, "#define YYBTYACC 1\n");
+       putl_code(fp,
+                 "#define YYDEBUGSTR (yytrial ? YYPREFIX \"debug(trial)\" : YYPREFIX \"debug\")\n");
+    }
+    else
+#endif
+    {
+       putl_code(fp, "#define YYBTYACC 0\n");
+       putl_code(fp, "#define YYDEBUGSTR YYPREFIX \"debug\"\n");
+    }
+}
+#endif
 
-    outline += 1;
-    fprintf(code_file, "#define YYPURE %d\n", pure_parser);
+static void
+output_pure_parser(FILE * fp)
+{
+    putc_code(fp, '\n');
 
-    putc_code('\n');
+    if (fp == code_file)
+       ++outline;
+    fprintf(fp, "#define YYPURE %d\n", pure_parser);
+    putc_code(fp, '\n');
 }
 
+#if defined(YY_NO_LEAKS)
 static void
-output_stype(void)
+output_no_leaks(FILE * fp)
 {
-    if (!unionized && ntags == 0)
-    {
-       putc_code('\n');
-       putl_code("#ifndef YYSTYPE\n");
-       putl_code("typedef int YYSTYPE;\n");
-       putl_code("#endif\n");
-       putc_code('\n');
-    }
+    putc_code(fp, '\n');
+
+    if (fp == code_file)
+       ++outline;
+    fputs("#define YY_NO_LEAKS 1\n", fp);
+    putc_code(fp, '\n');
 }
+#endif
 
 static void
 output_trailing_text(void)
@@ -1152,7 +1614,7 @@ output_trailing_text(void)
        if ((c = getc(in)) == EOF)
            return;
        write_input_lineno();
-       putc_code(c);
+       putc_code(code_file, c);
        last = c;
     }
     else
@@ -1160,24 +1622,24 @@ output_trailing_text(void)
        write_input_lineno();
        do
        {
-           putc_code(c);
+           putc_code(code_file, c);
        }
        while ((c = *++cptr) != '\n');
-       putc_code(c);
+       putc_code(code_file, c);
        last = '\n';
     }
 
     while ((c = getc(in)) != EOF)
     {
-       putc_code(c);
+       putc_code(code_file, c);
        last = c;
     }
 
     if (last != '\n')
     {
-       putc_code('\n');
+       putc_code(code_file, '\n');
     }
-    write_code_lineno();
+    write_code_lineno(code_file);
 }
 
 static void
@@ -1190,136 +1652,267 @@ output_semantic_actions(void)
        return;
 
     last = c;
-    putc_code(c);
+    putc_code(code_file, c);
     while ((c = getc(action_file)) != EOF)
     {
-       putc_code(c);
+       putc_code(code_file, c);
        last = c;
     }
 
     if (last != '\n')
     {
-       putc_code('\n');
+       putc_code(code_file, '\n');
     }
 
-    write_code_lineno();
+    write_code_lineno(code_file);
 }
 
 static void
-output_parse_decl(void)
+output_parse_decl(FILE * fp)
 {
-    putl_code("/* compatibility with bison */\n");
-    putl_code("#ifdef YYPARSE_PARAM\n");
-    putl_code("/* compatibility with FreeBSD */\n");
-    putl_code("# ifdef YYPARSE_PARAM_TYPE\n");
-    putl_code("#  define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM)\n");
-    putl_code("# else\n");
-    putl_code("#  define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM)\n");
-    putl_code("# endif\n");
-    putl_code("#else\n");
-
-    puts_code("# define YYPARSE_DECL() yyparse(");
-    if (!parse_param)
-       puts_code("void");
-    else
-    {
-       param *p;
-       for (p = parse_param; p; p = p->next)
-           fprintf(code_file, "%s %s%s%s", p->type, p->name, p->type2,
-                   p->next ? ", " : "");
-    }
-    putl_code(")\n");
-
-    putl_code("#endif\n");
-    putl_code("\n");
+    putc_code(fp, '\n');
+    putl_code(fp, "/* compatibility with bison */\n");
+    putl_code(fp, "#ifdef YYPARSE_PARAM\n");
+    putl_code(fp, "/* compatibility with FreeBSD */\n");
+    putl_code(fp, "# ifdef YYPARSE_PARAM_TYPE\n");
+    putl_code(fp,
+             "#  define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM)\n");
+    putl_code(fp, "# else\n");
+    putl_code(fp, "#  define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM)\n");
+    putl_code(fp, "# endif\n");
+    putl_code(fp, "#else\n");
+
+    puts_code(fp, "# define YYPARSE_DECL() yyparse(");
+    puts_param_types(fp, parse_param, 0);
+    putl_code(fp, ")\n");
+
+    putl_code(fp, "#endif\n");
 }
 
 static void
-output_lex_decl(void)
+output_lex_decl(FILE * fp)
 {
-    putl_code("/* Parameters sent to lex. */\n");
-    putl_code("#ifdef YYLEX_PARAM\n");
+    putc_code(fp, '\n');
+    putl_code(fp, "/* Parameters sent to lex. */\n");
+    putl_code(fp, "#ifdef YYLEX_PARAM\n");
     if (pure_parser)
     {
-       putl_code("# define YYLEX_DECL() yylex(YYSTYPE *yylval, "
-                 "void *YYLEX_PARAM)\n");
-       putl_code("# define YYLEX yylex(&yylval, YYLEX_PARAM)\n");
+       putl_code(fp, "# ifdef YYLEX_PARAM_TYPE\n");
+#if defined(YYBTYACC)
+       if (locations)
+       {
+           putl_code(fp, "#  define YYLEX_DECL() yylex(YYSTYPE *yylval,"
+                     " YYLTYPE *yylloc,"
+                     " YYLEX_PARAM_TYPE YYLEX_PARAM)\n");
+       }
+       else
+#endif
+       {
+           putl_code(fp, "#  define YYLEX_DECL() yylex(YYSTYPE *yylval,"
+                     " YYLEX_PARAM_TYPE YYLEX_PARAM)\n");
+       }
+       putl_code(fp, "# else\n");
+#if defined(YYBTYACC)
+       if (locations)
+       {
+           putl_code(fp, "#  define YYLEX_DECL() yylex(YYSTYPE *yylval,"
+                     " YYLTYPE *yylloc,"
+                     " void * YYLEX_PARAM)\n");
+       }
+       else
+#endif
+       {
+           putl_code(fp, "#  define YYLEX_DECL() yylex(YYSTYPE *yylval,"
+                     " void * YYLEX_PARAM)\n");
+       }
+       putl_code(fp, "# endif\n");
+#if defined(YYBTYACC)
+       if (locations)
+           putl_code(fp,
+                     "# define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)\n");
+       else
+#endif
+           putl_code(fp, "# define YYLEX yylex(&yylval, YYLEX_PARAM)\n");
     }
     else
     {
-       putl_code("# define YYLEX_DECL() yylex(void *YYLEX_PARAM)\n");
-       putl_code("# define YYLEX yylex(YYLEX_PARAM)\n");
+       putl_code(fp, "# define YYLEX_DECL() yylex(void *YYLEX_PARAM)\n");
+       putl_code(fp, "# define YYLEX yylex(YYLEX_PARAM)\n");
     }
-    putl_code("#else\n");
+    putl_code(fp, "#else\n");
     if (pure_parser && lex_param)
     {
-       param *p;
-       puts_code("# define YYLEX_DECL() yylex(YYSTYPE *yylval, ");
-       for (p = lex_param; p; p = p->next)
-           fprintf(code_file, "%s %s%s%s", p->type, p->name, p->type2,
-                   p->next ? ", " : "");
-       putl_code(")\n");
+#if defined(YYBTYACC)
+       if (locations)
+           puts_code(fp,
+                     "# define YYLEX_DECL() yylex(YYSTYPE *yylval, YYLTYPE *yylloc, ");
+       else
+#endif
+           puts_code(fp, "# define YYLEX_DECL() yylex(YYSTYPE *yylval, ");
+       puts_param_types(fp, lex_param, 0);
+       putl_code(fp, ")\n");
 
-       puts_code("# define YYLEX yylex(&yylval, ");
-       for (p = lex_param; p; p = p->next)
-           fprintf(code_file, "%s%s", p->name, p->next ? ", " : "");
-       putl_code(")\n");
+#if defined(YYBTYACC)
+       if (locations)
+           puts_code(fp, "# define YYLEX yylex(&yylval, &yylloc, ");
+       else
+#endif
+           puts_code(fp, "# define YYLEX yylex(&yylval, ");
+       puts_param_names(fp, lex_param, 0);
+       putl_code(fp, ")\n");
     }
     else if (pure_parser)
     {
-       putl_code("# define YYLEX_DECL() yylex(YYSTYPE *yylval)\n");
-       putl_code("# define YYLEX yylex(&yylval)\n");
+#if defined(YYBTYACC)
+       if (locations)
+       {
+           putl_code(fp,
+                     "# define YYLEX_DECL() yylex(YYSTYPE *yylval, YYLTYPE *yylloc)\n");
+           putl_code(fp, "# define YYLEX yylex(&yylval, &yylloc)\n");
+       }
+       else
+#endif
+       {
+           putl_code(fp, "# define YYLEX_DECL() yylex(YYSTYPE *yylval)\n");
+           putl_code(fp, "# define YYLEX yylex(&yylval)\n");
+       }
     }
     else if (lex_param)
     {
-       param *p;
-       puts_code("# define YYLEX_DECL() yylex(");
-       for (p = lex_param; p; p = p->next)
-           fprintf(code_file, "%s %s%s%s", p->type, p->name, p->type2,
-                   p->next ? ", " : "");
-       putl_code(")\n");
+       puts_code(fp, "# define YYLEX_DECL() yylex(");
+       puts_param_types(fp, lex_param, 0);
+       putl_code(fp, ")\n");
 
-       puts_code("# define YYLEX yylex(");
-       for (p = lex_param; p; p = p->next)
-           fprintf(code_file, "%s%s", p->name, p->next ? ", " : "");
-       putl_code(")\n");
+       puts_code(fp, "# define YYLEX yylex(");
+       puts_param_names(fp, lex_param, 0);
+       putl_code(fp, ")\n");
     }
     else
     {
-       putl_code("# define YYLEX_DECL() yylex(void)\n");
-       putl_code("# define YYLEX yylex()\n");
+       putl_code(fp, "# define YYLEX_DECL() yylex(void)\n");
+       putl_code(fp, "# define YYLEX yylex()\n");
     }
-    putl_code("#endif\n");
-    putl_code("\n");
+    putl_code(fp, "#endif\n");
+}
+
+static void
+output_error_decl(FILE * fp)
+{
+    putc_code(fp, '\n');
+    putl_code(fp, "/* Parameters sent to yyerror. */\n");
+    putl_code(fp, "#ifndef YYERROR_DECL\n");
+    puts_code(fp, "#define YYERROR_DECL() yyerror(");
+#if defined(YYBTYACC)
+    if (locations)
+       puts_code(fp, "YYLTYPE *loc, ");
+#endif
+    puts_param_types(fp, parse_param, 1);
+    putl_code(fp, "const char *s)\n");
+    putl_code(fp, "#endif\n");
+
+    putl_code(fp, "#ifndef YYERROR_CALL\n");
+
+    puts_code(fp, "#define YYERROR_CALL(msg) yyerror(");
+#if defined(YYBTYACC)
+    if (locations)
+       puts_code(fp, "&yylloc, ");
+#endif
+    puts_param_names(fp, parse_param, 1);
+    putl_code(fp, "msg)\n");
+
+    putl_code(fp, "#endif\n");
 }
 
+#if defined(YYBTYACC)
 static void
-output_error_decl(void)
+output_yydestruct_decl(FILE * fp)
 {
-    putl_code("/* Parameters sent to yyerror. */\n");
+    putc_code(fp, '\n');
+    putl_code(fp, "#ifndef YYDESTRUCT_DECL\n");
+
+    puts_code(fp,
+             "#define YYDESTRUCT_DECL() "
+             "yydestruct(const char *msg, int psymb, YYSTYPE *val");
+#if defined(YYBTYACC)
+    if (locations)
+       puts_code(fp, ", YYLTYPE *loc");
+#endif
     if (parse_param)
     {
-       param *p;
-
-       fprintf(code_file, "#define YYERROR_DECL() yyerror(");
-       for (p = parse_param; p; p = p->next)
-           fprintf(code_file, "%s %s%s, ", p->type, p->name, p->type2);
-       putl_code("const char *s)\n");
+       puts_code(fp, ", ");
+       puts_param_types(fp, parse_param, 0);
+    }
+    putl_code(fp, ")\n");
 
-       puts_code("#define YYERROR_CALL(msg) yyerror(");
+    putl_code(fp, "#endif\n");
 
-       for (p = parse_param; p; p = p->next)
-           fprintf(code_file, "%s, ", p->name);
+    putl_code(fp, "#ifndef YYDESTRUCT_CALL\n");
 
-       putl_code("msg)\n");
+    puts_code(fp, "#define YYDESTRUCT_CALL(msg, psymb, val");
+#if defined(YYBTYACC)
+    if (locations)
+       puts_code(fp, ", loc");
+#endif
+    puts_code(fp, ") yydestruct(msg, psymb, val");
+#if defined(YYBTYACC)
+    if (locations)
+       puts_code(fp, ", loc");
+#endif
+    if (parse_param)
+    {
+       puts_code(fp, ", ");
+       puts_param_names(fp, parse_param, 0);
     }
-    else
+    putl_code(fp, ")\n");
+
+    putl_code(fp, "#endif\n");
+}
+
+static void
+output_initial_action(void)
+{
+    if (initial_action)
+       fprintf(code_file, "%s\n", initial_action);
+}
+
+static void
+output_yydestruct_impl(void)
+{
+    int i;
+    char *s, *destructor_code;
+
+    putc_code(code_file, '\n');
+    putl_code(code_file, "/* Release memory associated with symbol. */\n");
+    putl_code(code_file, "#if ! defined YYDESTRUCT_IS_DECLARED\n");
+    putl_code(code_file, "static void\n");
+    putl_code(code_file, "YYDESTRUCT_DECL()\n");
+    putl_code(code_file, "{\n");
+    putl_code(code_file, "    switch (psymb)\n");
+    putl_code(code_file, "    {\n");
+    for (i = 2; i < nsyms; ++i)
     {
-       putl_code("#define YYERROR_DECL() yyerror(const char *s)\n");
-       putl_code("#define YYERROR_CALL(msg) yyerror(msg)\n");
+       if ((destructor_code = symbol_destructor[i]) != NULL)
+       {
+           ++outline;
+           fprintf(code_file, "\tcase %d:\n", symbol_pval[i]);
+           /* comprehend the number of lines in the destructor code */
+           for (s = destructor_code; (s = strchr(s, '\n')) != NULL; s++)
+               ++outline;
+           puts_code(code_file, destructor_code);
+           putc_code(code_file, '\n');
+           putl_code(code_file, "\tbreak;\n");
+           write_code_lineno(code_file);
+           FREE(destructor_code);
+       }
     }
-    putl_code("\n");
+    putl_code(code_file, "    }\n");
+    putl_code(code_file, "}\n");
+    putl_code(code_file, "#define YYDESTRUCT_IS_DECLARED 1\n");
+    putl_code(code_file, "#endif\n");
+
+    DO_FREE(symbol_destructor);
 }
+#endif
 
 static void
 free_itemsets(void)
@@ -1361,64 +1954,147 @@ free_reductions(void)
 }
 
 static void
-output_yyerror_call(const char *msg)
+output_externs(FILE * fp, const char *const section[])
 {
-    puts_code("    yyerror(");
-    if (parse_param)
+    int i;
+    const char *s;
+
+    for (i = 0; (s = section[i]) != 0; ++i)
     {
-       param *p;
-       for (p = parse_param; p; p = p->next)
-           fprintf(code_file, "%s, ", p->name);
+       /* prefix non-blank lines that don't start with
+          C pre-processor directives with 'extern ' */
+       if (*s && (*s != '#'))
+           fputs("extern\t", fp);
+       if (fp == code_file)
+           ++outline;
+       fprintf(fp, "%s\n", s);
     }
-    puts_code("\"");
-    puts_code(msg);
-    putl_code("\");\n");
 }
 
 void
 output(void)
 {
+    FILE *fp;
+
     free_itemsets();
     free_shifts();
     free_reductions();
-    output_prefix(output_file);
-    output_pure_parser();
-    output_stored_text();
-    output_stype();
-    output_parse_decl();
-    output_lex_decl();
-    output_error_decl();
-    write_section(xdecls);
-    output_defines();
+
+#if defined(YYBTYACC)
+    output_backtracking_parser(output_file);
+    if (rflag)
+       output_backtracking_parser(code_file);
+#endif
+
+    if (iflag)
+    {
+       write_code_lineno(code_file);
+       ++outline;
+       fprintf(code_file, "#include \"%s\"\n", externs_file_name);
+       fp = externs_file;
+    }
+    else
+       fp = code_file;
+
+    output_prefix(fp);
+    output_pure_parser(fp);
+#if defined(YY_NO_LEAKS)
+    output_no_leaks(fp);
+#endif
+    output_stored_text(fp);
+    output_stype(fp);
+#if defined(YYBTYACC)
+    if (locations)
+       output_ltype(fp);
+#endif
+    output_parse_decl(fp);
+    output_lex_decl(fp);
+    output_error_decl(fp);
+#if defined(YYBTYACC)
+    if (destructor)
+       output_yydestruct_decl(fp);
+#endif
+    if (iflag || !rflag)
+    {
+       write_section(fp, xdecls);
+    }
+
+    if (iflag)
+    {
+       output_externs(externs_file, global_vars);
+       if (!pure_parser)
+           output_externs(externs_file, impure_vars);
+    }
+
+    if (iflag)
+    {
+       if (dflag)
+       {
+           ++outline;
+           fprintf(code_file, "#include \"%s\"\n", defines_file_name);
+       }
+       else
+           output_defines(externs_file);
+    }
+    else
+    {
+       putc_code(code_file, '\n');
+       output_defines(code_file);
+    }
+
+    if (dflag)
+    {
+       start_defines_file();
+       output_defines(defines_file);
+       end_defines_file();
+    }
+
     output_rule_data();
     output_yydefred();
+#if defined(YYBTYACC)
+    output_accessing_symbols();
+#endif
     output_actions();
     free_parser();
     output_debug();
     if (rflag)
     {
-       output_prefix(code_file);
-       write_section(xdecls);
-       write_section(tables);
+       write_section(code_file, xdecls);
+       output_YYINT_typedef(code_file);
+       write_section(code_file, tables);
+    }
+    write_section(code_file, global_vars);
+    if (!pure_parser)
+    {
+       write_section(code_file, impure_vars);
     }
-    write_section(hdr_defs);
+    write_section(code_file, hdr_defs);
     if (!pure_parser)
     {
-       write_section(hdr_vars);
+       write_section(code_file, hdr_vars);
     }
     output_trailing_text();
-    write_section(body_1);
+#if defined(YYBTYACC)
+    if (destructor)
+       output_yydestruct_impl();
+#endif
+    write_section(code_file, body_1);
     if (pure_parser)
     {
-       write_section(body_vars);
+       write_section(code_file, body_vars);
     }
-    write_section(body_2);
-    output_yyerror_call("syntax error");
-    write_section(body_3);
+    write_section(code_file, body_2);
+    if (pure_parser)
+    {
+       write_section(code_file, init_vars);
+    }
+#if defined(YYBTYACC)
+    if (initial_action)
+       output_initial_action();
+#endif
+    write_section(code_file, body_3);
     output_semantic_actions();
-    write_section(trailer);
-    output_yyerror_call("yacc stack overflow");
-    write_section(trailer_2);
+    write_section(code_file, trailer);
 }
 
 #ifdef NO_LEAKS