Imported Upstream version 20221229
[platform/upstream/byacc.git] / reader.c
index 812db44..5e8ca67 100644 (file)
--- a/reader.c
+++ b/reader.c
@@ -1,11 +1,11 @@
-/* $Id: reader.c,v 1.60 2016/03/25 00:51:07 tom Exp $ */
+/* $Id: reader.c,v 1.91 2022/01/09 18:04:58 tom Exp $ */
 
 #include "defs.h"
 
 /*  The line size must be a positive integer.  One hundred was chosen  */
 /*  because few lines in Yacc input grammars exceed 100 characters.    */
 /*  Note that if a line exceeds LINESIZE characters, the line buffer   */
-/*  will be expanded to accomodate it.                                 */
+/*  will be expanded to accommodate it.                                        */
 
 #define LINESIZE 100
 
 /* this is a hard limit, but seems more than adequate */
 #define MAXARGS        20
 
+#define begin_case(f,n) fprintf(f, "case %d:\n", (int)(n))
+
+#define end_case(f) \
+           fprintf(f, "\n"); \
+           fprintf_lineno(f, 1, ""); \
+           fprintf(f, "break;\n")
+
 static void start_rule(bucket *bp, int s_lineno);
 #if defined(YYBTYACC)
+static void copy_initial_action(void);
 static void copy_destructor(void);
 static char *process_destructor_XX(char *code, char *tag);
 #endif
@@ -43,6 +51,9 @@ static bucket *goal;
 static Value_t prec;
 static int gensym;
 static char last_was_action;
+#if defined(YYBTYACC)
+static int trialaction;
+#endif
 
 static int maxitems;
 static bucket **pitem;
@@ -58,6 +69,13 @@ char line_format[] = "#line %d \"%s\"\n";
 param *lex_param;
 param *parse_param;
 
+static const char *code_keys[] =
+{
+    "", "requires", "provides", "top", "imports",
+};
+
+struct code_lines code_lines[CODE_MAX];
+
 #if defined(YYBTYACC)
 int destructor = 0;    /* =1 if at least one %destructor */
 
@@ -104,56 +122,203 @@ cachec(int c)
     ++cinc;
 }
 
-static void
-get_line(void)
+typedef enum
 {
-    FILE *f = input_file;
-    int c;
-    int i;
+    ldSPC1,
+    ldSPC2,
+    ldNAME,
+    ldSPC3,
+    ldNUM,
+    ldSPC4,
+    ldFILE,
+    ldOK,
+    ldERR
+}
+LINE_DIR;
 
-    if (saw_eof || (c = getc(f)) == EOF)
+/*
+ * Expect this pattern:
+ *     /^[[:space:]]*#[[:space:]]*
+ *       line[[:space:]]+
+ *       [[:digit:]]+
+ *       ([[:space:]]*|[[:space:]]+"[^"]+")/
+ */
+static int
+line_directive(void)
+{
+#define UNLESS(what) if (what) { ld = ldERR; break; }
+    int n;
+    int line_1st = -1;
+    int name_1st = -1;
+    int name_end = -1;
+    LINE_DIR ld = ldSPC1;
+    for (n = 0; (ld <= ldOK) && (line[n] != '\0'); ++n)
     {
-       if (line)
+       int ch = UCH(line[n]);
+       switch (ld)
        {
-           FREE(line);
-           line = 0;
+       case ldSPC1:
+           if (isspace(UCH(ch)))
+           {
+               break;
+           }
+           else
+               UNLESS(ch != '#');
+           ld = ldSPC2;
+           break;
+       case ldSPC2:
+           if (isspace(UCH(ch)))
+           {
+               break;
+           }
+           /* FALLTHRU */
+       case ldNAME:
+           UNLESS(strncmp(line + n, "line", 4));
+           n += 4;
+           if (line[n] == '\0')
+           {
+               ld = ldOK;
+               break;
+           }
+           else
+               UNLESS(!isspace(UCH(line[n])));
+           ld = ldSPC3;
+           break;
+       case ldSPC3:
+           if (isspace(UCH(ch)))
+           {
+               break;
+           }
+           else
+               UNLESS(!isdigit(UCH(ch)));
+           line_1st = n;
+           ld = ldNUM;         /* this is needed, but cppcheck says no... */
+           /* FALLTHRU */
+       case ldNUM:
+           if (isdigit(UCH(ch)))
+           {
+               break;
+           }
+           else
+               UNLESS(!isspace(UCH(ch)));
+           ld = ldSPC4;
+           break;
+       case ldSPC4:
+           if (isspace(UCH(ch)))
+           {
+               break;
+           }
+           else
+               UNLESS(ch != '"');
+           UNLESS(line[n + 1] == '"');
+           ld = ldFILE;
+           name_1st = n;
+           break;
+       case ldFILE:
+           if (ch != '"')
+           {
+               break;
+           }
+           ld = ldOK;
+           name_end = n;
+           /* FALLTHRU */
+       case ldERR:
+       case ldOK:
+           break;
        }
-       cptr = 0;
-       saw_eof = 1;
-       return;
     }
 
-    if (line == 0 || linesize != (LINESIZE + 1))
+    if (ld == ldOK)
     {
-       if (line)
-           FREE(line);
-       linesize = LINESIZE + 1;
-       line = TMALLOC(char, linesize);
-       NO_SPACE(line);
+       size_t need = (size_t)(name_end - name_1st);
+       if ((long)need > (long)input_file_name_len)
+       {
+           input_file_name_len = ((need + 1) * 3) / 2;
+           input_file_name = TREALLOC(char, input_file_name, input_file_name_len);
+           NO_SPACE(input_file_name);
+       }
+       if ((long)need > 0)
+       {
+           memcpy(input_file_name, line + name_1st + 1, need - 1);
+           input_file_name[need - 1] = '\0';
+       }
+       else
+       {
+           input_file_name[0] = '\0';
+       }
     }
 
-    i = 0;
-    ++lineno;
-    for (;;)
+    if (ld >= ldNUM && ld < ldERR)
     {
-       line[i++] = (char)c;
-       if (c == '\n')
-           break;
-       if ((i + 3) >= linesize)
+       if (line_1st >= 0)
        {
-           linesize += LINESIZE;
-           line = TREALLOC(char, line, linesize);
-           NO_SPACE(line);
+           lineno = (int)strtol(line + line_1st, NULL, 10) - 1;
        }
-       c = getc(f);
-       if (c == EOF)
+       else
        {
-           line[i++] = '\n';
+           lineno = 0;
+       }
+    }
+
+    return (ld == ldOK);
+#undef UNLESS
+}
+
+static void
+get_line(void)
+{
+    FILE *f = input_file;
+
+    do
+    {
+       int c;
+       int i;
+
+       if (saw_eof || (c = getc(f)) == EOF)
+       {
+           if (line)
+           {
+               FREE(line);
+               line = 0;
+           }
+           cptr = 0;
            saw_eof = 1;
-           break;
+           return;
+       }
+
+       if (line == NULL || linesize != (LINESIZE + 1))
+       {
+           if (line)
+               FREE(line);
+           linesize = LINESIZE + 1;
+           line = TMALLOC(char, linesize);
+           NO_SPACE(line);
+       }
+
+       i = 0;
+       ++lineno;
+       for (;;)
+       {
+           line[i++] = (char)c;
+           if (c == '\n')
+               break;
+           if ((i + 3) >= linesize)
+           {
+               linesize += LINESIZE;
+               line = TREALLOC(char, line, linesize);
+               NO_SPACE(line);
+           }
+           c = getc(f);
+           if (c == EOF)
+           {
+               line[i++] = '\n';
+               saw_eof = 1;
+               break;
+           }
        }
+       line[i] = '\0';
     }
-    line[i] = '\0';
+    while (line_directive());
     cptr = line;
     return;
 }
@@ -163,8 +328,8 @@ dup_line(void)
 {
     char *p, *s, *t;
 
-    if (line == 0)
-       return (0);
+    if (line == NULL)
+       return (NULL);
     s = line;
     while (*s != '\n')
        ++s;
@@ -182,10 +347,10 @@ static void
 skip_comment(void)
 {
     char *s;
-
-    int st_lineno = lineno;
-    char *st_line = dup_line();
-    char *st_cptr = st_line + (cptr - line);
+    struct ainfo a;
+    a.a_lineno = lineno;
+    a.a_line = dup_line();
+    a.a_cptr = a.a_line + (cptr - line);
 
     s = cptr + 2;
     for (;;)
@@ -193,14 +358,14 @@ skip_comment(void)
        if (*s == '*' && s[1] == '/')
        {
            cptr = s + 2;
-           FREE(st_line);
+           FREE(a.a_line);
            return;
        }
        if (*s == '\n')
        {
            get_line();
-           if (line == 0)
-               unterminated_comment(st_lineno, st_line, st_cptr);
+           if (line == NULL)
+               unterminated_comment(&a);
            s = cptr;
        }
        else
@@ -213,10 +378,10 @@ next_inline(void)
 {
     char *s;
 
-    if (line == 0)
+    if (line == NULL)
     {
        get_line();
-       if (line == 0)
+       if (line == NULL)
            return (EOF);
     }
 
@@ -236,7 +401,7 @@ next_inline(void)
            else if (s[1] == '/')
            {
                get_line();
-               if (line == 0)
+               if (line == NULL)
                    return (EOF);
                s = cptr;
                break;
@@ -287,17 +452,23 @@ nextc(void)
 /* *INDENT-OFF* */
 static struct keyword
 {
-    char name[13];
+    char name[16];
     int token;
 }
 keywords[] = {
     { "binary",      NONASSOC },
+    { "code",        XCODE },
+    { "debug",       NONPOSIX_DEBUG },
 #if defined(YYBTYACC)
     { "destructor",  DESTRUCTOR },
 #endif
+    { "error-verbose",ERROR_VERBOSE },
     { "expect",      EXPECT },
     { "expect-rr",   EXPECT_RR },
-    { "ident",       IDENT }, 
+    { "ident",       IDENT },
+#if defined(YYBTYACC)
+    { "initial-action", INITIAL_ACTION },
+#endif
     { "left",        LEFT },
     { "lex-param",   LEX_PARAM },
 #if defined(YYBTYACC)
@@ -306,11 +477,11 @@ keywords[] = {
     { "nonassoc",    NONASSOC },
     { "parse-param", PARSE_PARAM },
     { "pure-parser", PURE_PARSER },
-    { "right",       RIGHT }, 
+    { "right",       RIGHT },
     { "start",       START },
-    { "term",        TOKEN }, 
-    { "token",       TOKEN }, 
-    { "token-table", TOKEN_TABLE }, 
+    { "term",        TOKEN },
+    { "token",       TOKEN },
+    { "token-table", TOKEN_TABLE },
     { "type",        TYPE },
     { "union",       UNION },
     { "yacc",        POSIX_YACC },
@@ -330,21 +501,22 @@ keyword(void)
 {
     int c;
     char *t_cptr = cptr;
-    struct keyword *key;
 
     c = *++cptr;
-    if (isalpha(c))
+    if (isalpha(UCH(c)))
     {
+       struct keyword *key;
+
        cinc = 0;
        for (;;)
        {
-           if (isalpha(c))
+           if (isalpha(UCH(c)))
            {
-               if (isupper(c))
+               if (isupper(UCH(c)))
                    c = tolower(c);
                cachec(c);
            }
-           else if (isdigit(c)
+           else if (isdigit(UCH(c))
                     || c == '-'
                     || c == '.'
                     || c == '$')
@@ -386,6 +558,7 @@ keyword(void)
            return (NONASSOC);
     }
     syntax_error(lineno, line, t_cptr);
+    /*NOTREACHED */
 }
 
 static void
@@ -423,22 +596,23 @@ static char *
 copy_string(int quote)
 {
     struct mstring *temp = msnew();
-    int c;
-    int s_lineno = lineno;
-    char *s_line = dup_line();
-    char *s_cptr = s_line + (cptr - line - 1);
+    struct ainfo a;
+    a.a_lineno = lineno;
+    a.a_line = dup_line();
+    a.a_cptr = a.a_line + (cptr - line - 1);
 
     for (;;)
     {
-       c = *cptr++;
+       int c = *cptr++;
+
        mputc(temp, c);
        if (c == quote)
        {
-           FREE(s_line);
+           FREE(a.a_line);
            return msdone(temp);
        }
        if (c == '\n')
-           unterminated_string(s_lineno, s_line, s_cptr);
+           unterminated_string(&a);
        if (c == '\\')
        {
            c = *cptr++;
@@ -446,8 +620,8 @@ copy_string(int quote)
            if (c == '\n')
            {
                get_line();
-               if (line == 0)
-                   unterminated_string(s_lineno, s_line, s_cptr);
+               if (line == NULL)
+                   unterminated_string(&a);
            }
        }
     }
@@ -474,9 +648,10 @@ copy_comment(void)
     }
     else if (c == '*')
     {
-       int c_lineno = lineno;
-       char *c_line = dup_line();
-       char *c_cptr = c_line + (cptr - line - 1);
+       struct ainfo a;
+       a.a_lineno = lineno;
+       a.a_line = dup_line();
+       a.a_cptr = a.a_line + (cptr - line - 1);
 
        mputc(temp, c);
        ++cptr;
@@ -488,38 +663,160 @@ copy_comment(void)
            {
                mputc(temp, '/');
                ++cptr;
-               FREE(c_line);
+               FREE(a.a_line);
                return msdone(temp);
            }
            if (c == '\n')
            {
                get_line();
-               if (line == 0)
-                   unterminated_comment(c_lineno, c_line, c_cptr);
+               if (line == NULL)
+                   unterminated_comment(&a);
            }
        }
     }
     return msdone(temp);
 }
 
+static int
+check_key(int pos)
+{
+    const char *key = code_keys[pos];
+    while (*cptr && *key)
+       if (*key++ != *cptr++)
+           return 0;
+    if (*key || (!isspace(UCH(*cptr)) && *cptr != L_CURL))
+       return 0;
+    cptr--;
+    return 1;
+}
+
+static void
+copy_code(void)
+{
+    int c;
+    int curl;
+    int cline;
+    int on_line = 0;
+    int pos = CODE_HEADER;
+    struct mstring *code_mstr;
+
+    /* read %code <keyword> { */
+    for (;;)
+    {
+       c = *++cptr;
+       if (c == EOF)
+           unexpected_EOF();
+       if (isspace(UCH(c)))
+           continue;
+
+       if (c == L_CURL)
+           break;
+
+       if (pos == CODE_HEADER)
+       {
+           switch (UCH(c))
+           {
+           case 'r':
+               pos = CODE_REQUIRES;
+               break;
+           case 'p':
+               pos = CODE_PROVIDES;
+               break;
+           case 't':
+               pos = CODE_TOP;
+               break;
+           case 'i':
+               pos = CODE_IMPORTS;
+               break;
+           default:
+               break;
+           }
+
+           if (pos == -1 || !check_key(pos))
+           {
+               syntax_error(lineno, line, cptr);
+               /*NOTREACHED */
+           }
+       }
+    }
+
+    cptr++;                    /* skip initial curl */
+    while (*cptr && isspace(UCH(*cptr)))       /* skip space */
+       cptr++;
+    curl = 1;                  /* nesting count */
+
+    /* gather text */
+    code_lines[pos].name = code_keys[pos];
+    if ((cline = (int)code_lines[pos].num) != 0)
+    {
+       code_mstr = msrenew(code_lines[pos].lines);
+    }
+    else
+    {
+       code_mstr = msnew();
+    }
+    cline++;
+    if (!lflag)
+       msprintf(code_mstr, line_format, lineno, input_file_name);
+    for (;;)
+    {
+       c = *cptr++;
+       switch (c)
+       {
+       case '\0':
+           get_line();
+           if (line == NULL)
+           {
+               unexpected_EOF();
+               /*NOTREACHED */
+           }
+           continue;
+       case '\n':
+           cline++;
+           on_line = 0;
+           break;
+       case L_CURL:
+           curl++;
+           break;
+       case R_CURL:
+           if (--curl == 0)
+           {
+               if (on_line > 1)
+               {
+                   mputc(code_mstr, '\n');
+                   cline++;
+               }
+               code_lines[pos].lines = msdone(code_mstr);
+               code_lines[pos].num = (size_t)cline;
+               return;
+           }
+           break;
+       default:
+           break;
+       }
+       mputc(code_mstr, c);
+       on_line++;
+    }
+}
+
 static void
 copy_text(void)
 {
     int c;
     FILE *f = text_file;
     int need_newline = 0;
-    int t_lineno = lineno;
-    char *t_line = dup_line();
-    char *t_cptr = t_line + (cptr - line - 2);
+    struct ainfo a;
+    a.a_lineno = lineno;
+    a.a_line = dup_line();
+    a.a_cptr = a.a_line + (cptr - line - 2);
 
     if (*cptr == '\n')
     {
        get_line();
-       if (line == 0)
-           unterminated_text(t_lineno, t_line, t_cptr);
+       if (line == NULL)
+           unterminated_text(&a);
     }
-    if (!lflag)
-       fprintf(f, line_format, lineno, input_file_name);
+    fprintf_lineno(f, lineno, input_file_name);
 
   loop:
     c = *cptr++;
@@ -531,7 +828,7 @@ copy_text(void)
        get_line();
        if (line)
            goto loop;
-       unterminated_text(t_lineno, t_line, t_cptr);
+       unterminated_text(&a);
 
     case '\'':
     case '"':
@@ -561,7 +858,7 @@ copy_text(void)
            if (need_newline)
                putc('\n', f);
            ++cptr;
-           FREE(t_line);
+           FREE(a.a_line);
            return;
        }
        /* FALLTHRU */
@@ -594,24 +891,24 @@ copy_union(void)
 {
     int c;
     int depth;
-    int u_lineno = lineno;
-    char *u_line = dup_line();
-    char *u_cptr = u_line + (cptr - line - 6);
+    struct ainfo a;
+    a.a_lineno = lineno;
+    a.a_line = dup_line();
+    a.a_cptr = a.a_line + (cptr - line - 6);
 
     if (unionized)
        over_unionized(cptr - 6);
     unionized = 1;
 
-    if (!lflag)
-       fprintf(text_file, line_format, lineno, input_file_name);
-
     puts_both("#ifdef YYSTYPE\n");
     puts_both("#undef  YYSTYPE_IS_DECLARED\n");
     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
     puts_both("#endif\n");
     puts_both("#ifndef YYSTYPE_IS_DECLARED\n");
     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
-    puts_both("typedef union");
+
+    fprintf_lineno(text_file, lineno, input_file_name);
+    puts_both("typedef union YYSTYPE");
 
     depth = 0;
   loop:
@@ -621,8 +918,8 @@ copy_union(void)
     {
     case '\n':
        get_line();
-       if (line == 0)
-           unterminated_union(u_lineno, u_line, u_cptr);
+       if (line == NULL)
+           unterminated_union(&a);
        goto loop;
 
     case L_CURL:
@@ -634,7 +931,7 @@ copy_union(void)
        {
            puts_both(" YYSTYPE;\n");
            puts_both("#endif /* !YYSTYPE_IS_DECLARED */\n");
-           FREE(u_line);
+           FREE(a.a_line);
            return;
        }
        goto loop;
@@ -851,19 +1148,23 @@ copy_param(int k)
        }
        if (buf == 0)
        {
-           buf_size = (size_t) linesize;
+           buf_size = (size_t)linesize;
            buf = TMALLOC(char, buf_size);
+           NO_SPACE(buf);
        }
        else if (c == '\n')
        {
+           char *tmp;
+
            get_line();
-           if (line == 0)
+           if (line == NULL)
                unexpected_EOF();
            --cptr;
-           buf_size += (size_t) linesize;
-           buf = TREALLOC(char, buf, buf_size);
+           buf_size += (size_t)linesize;
+           tmp = TREALLOC(char, buf, buf_size);
+           NO_SPACE(tmp);
+           buf = tmp;
        }
-       NO_SPACE(buf);
        if (curly)
        {
            if ((state == 2) && (c == L_CURL))
@@ -893,7 +1194,7 @@ copy_param(int k)
        goto oops;
     }
 
-    buf[i--] = '\0';
+    buf[++i] = '\0';
     (void)trim_blanks(buf);
 
     comma = buf - 1;
@@ -914,13 +1215,21 @@ copy_param(int k)
        if (parms[i] == ']')
        {
            int level = 1;
-           while (i >= 0 && level > 0 && parms[i] != '[')
+           while (i >= 0)
            {
-               if (parms[i] == ']')
+               char ch = parms[i--];
+               if (ch == ']')
+               {
                    ++level;
-               else if (parms[i] == '[')
-                   --level;
-               i--;
+               }
+               else if (ch == '[')
+               {
+                   if (--level <= 1)
+                   {
+                       ++i;
+                       break;
+                   }
+               }
            }
            if (i <= 0)
                unexpected_EOF();
@@ -970,9 +1279,10 @@ get_literal(void)
     int n;
     char *s;
     bucket *bp;
-    int s_lineno = lineno;
-    char *s_line = dup_line();
-    char *s_cptr = s_line + (cptr - line);
+    struct ainfo a;
+    a.a_lineno = lineno;
+    a.a_line = dup_line();
+    a.a_cptr = a.a_line + (cptr - line);
 
     quote = *cptr++;
     cinc = 0;
@@ -982,7 +1292,7 @@ get_literal(void)
        if (c == quote)
            break;
        if (c == '\n')
-           unterminated_string(s_lineno, s_line, s_cptr);
+           unterminated_string(&a);
        if (c == '\\')
        {
            char *c_cptr = cptr - 1;
@@ -992,8 +1302,8 @@ get_literal(void)
            {
            case '\n':
                get_line();
-               if (line == 0)
-                   unterminated_string(s_lineno, s_line, s_cptr);
+               if (line == NULL)
+                   unterminated_string(&a);
                continue;
 
            case '0':
@@ -1065,7 +1375,7 @@ get_literal(void)
        }
        cachec(c);
     }
-    FREE(s_line);
+    FREE(a.a_line);
 
     n = cinc;
     s = TMALLOC(char, n);
@@ -1088,7 +1398,7 @@ get_literal(void)
            cachec('\\');
            cachec(c);
        }
-       else if (isprint(c))
+       else if (isprint(UCH(c)))
            cachec(c);
        else
        {
@@ -1143,8 +1453,6 @@ get_literal(void)
 static int
 is_reserved(char *name)
 {
-    char *s;
-
     if (strcmp(name, ".") == 0 ||
        strcmp(name, "$accept") == 0 ||
        strcmp(name, "$end") == 0)
@@ -1152,7 +1460,8 @@ is_reserved(char *name)
 
     if (name[0] == '$' && name[1] == '$' && isdigit(UCH(name[2])))
     {
-       s = name + 3;
+       char *s = name + 3;
+
        while (isdigit(UCH(*s)))
            ++s;
        if (*s == NUL)
@@ -1182,13 +1491,21 @@ static Value_t
 get_number(void)
 {
     int c;
-    Value_t n;
+    long n;
+    char *base = cptr;
 
     n = 0;
-    for (c = *cptr; isdigit(c); c = *++cptr)
-       n = (Value_t) (10 * n + (c - '0'));
+    for (c = *cptr; isdigit(UCH(c)); c = *++cptr)
+    {
+       n = (10 * n + (c - '0'));
+       if (n > MAXYYINT)
+       {
+           syntax_error(lineno, line, base);
+           /*NOTREACHED */
+       }
+    }
 
-    return (n);
+    return (Value_t)(n);
 }
 
 static char *
@@ -1235,7 +1552,7 @@ get_tag(void)
     c = nextc();
     if (c == EOF)
        unexpected_EOF();
-    if (!isalpha(c) && c != '_' && c != '$')
+    if (!IS_NAME1(c))
        illegal_tag(t_lineno, t_line, t_cptr);
 
     cinc = 0;
@@ -1256,7 +1573,7 @@ get_tag(void)
 
     FREE(t_line);
     havetags = 1;
-    return cache_tag(cache, (size_t) cinc);
+    return cache_tag(cache, (size_t)cinc);
 }
 
 #if defined(YYBTYACC)
@@ -1265,9 +1582,9 @@ scan_id(void)
 {
     char *b = cptr;
 
-    while (isalnum(*cptr) || *cptr == '_' || *cptr == '$')
+    while (IS_NAME2(UCH(*cptr)))
        cptr++;
-    return cache_tag(b, (size_t) (cptr - b));
+    return cache_tag(b, (size_t)(cptr - b));
 }
 #endif
 
@@ -1295,7 +1612,7 @@ declare_tokens(int assoc)
 
     for (;;)
     {
-       if (isalpha(c) || c == '_' || c == '.' || c == '$')
+       if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
            bp = get_name();
        else if (c == '\'' || c == '"')
            bp = get_literal();
@@ -1317,7 +1634,7 @@ declare_tokens(int assoc)
        {
            if (bp->prec && prec != bp->prec)
                reprec_warning(bp->name);
-           bp->assoc = (Assoc_t) assoc;
+           bp->assoc = (Assoc_t)assoc;
            bp->prec = prec;
        }
 
@@ -1325,7 +1642,7 @@ declare_tokens(int assoc)
        if (c == EOF)
            unexpected_EOF();
 
-       if (isdigit(c))
+       if (isdigit(UCH(c)))
        {
            value = get_number();
            if (bp->value != UNDEFINED && value != bp->value)
@@ -1361,7 +1678,7 @@ declare_expect(int assoc)
 
     for (;;)
     {
-       if (isdigit(c))
+       if (isdigit(UCH(c)))
        {
            if (assoc == EXPECT)
                SRexpect = get_number();
@@ -1374,7 +1691,7 @@ declare_expect(int assoc)
         * Spaces, tabs, and numbers are ok,
         * words, punc., etc. are syntax errors.
         */
-       else if (c == '\n' || isalpha(c) || !isspace(c))
+       else if (c == '\n' || isalpha(UCH(c)) || !isspace(UCH(c)))
        {
            syntax_error(lineno, line, cptr);
        }
@@ -1392,14 +1709,14 @@ static void
 declare_argtypes(bucket *bp)
 {
     char *tags[MAXARGS];
-    int args = 0, c;
+    int args = 0;
 
     if (bp->args >= 0)
        retyped_warning(bp->name);
     cptr++;                    /* skip open paren */
     for (;;)
     {
-       c = nextc();
+       int c = nextc();
        if (c == EOF)
            unexpected_EOF();
        if (c != '<')
@@ -1429,7 +1746,7 @@ static void
 declare_types(void)
 {
     int c;
-    bucket *bp;
+    bucket *bp = NULL;
     char *tag = NULL;
 
     c = nextc();
@@ -1443,7 +1760,7 @@ declare_types(void)
        c = nextc();
        if (c == EOF)
            unexpected_EOF();
-       if (isalpha(c) || c == '_' || c == '.' || c == '$')
+       if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
        {
            bp = get_name();
 #if defined(YYBTYACC)
@@ -1481,7 +1798,7 @@ declare_start(void)
     c = nextc();
     if (c == EOF)
        unexpected_EOF();
-    if (!isalpha(c) && c != '_' && c != '.' && c != '$')
+    if (!isalpha(UCH(c)) && c != '_' && c != '.' && c != '$')
        syntax_error(lineno, line, cptr);
     bp = get_name();
     if (bp->class == TERM)
@@ -1494,15 +1811,15 @@ declare_start(void)
 static void
 read_declarations(void)
 {
-    int c, k;
-
     cache_size = CACHE_SIZE;
     cache = TMALLOC(char, cache_size);
     NO_SPACE(cache);
 
     for (;;)
     {
-       c = nextc();
+       int k;
+       int c = nextc();
+
        if (c == EOF)
            unexpected_EOF();
        if (c != '%')
@@ -1516,6 +1833,10 @@ read_declarations(void)
            copy_ident();
            break;
 
+       case XCODE:
+           copy_code();
+           break;
+
        case TEXT:
            copy_text();
            break;
@@ -1557,6 +1878,10 @@ read_declarations(void)
            token_table = 1;
            break;
 
+       case ERROR_VERBOSE:
+           error_verbose = 1;
+           break;
+
 #if defined(YYBTYACC)
        case LOCATIONS:
            locations = 1;
@@ -1566,8 +1891,15 @@ read_declarations(void)
            destructor = 1;
            copy_destructor();
            break;
+       case INITIAL_ACTION:
+           copy_initial_action();
+           break;
 #endif
 
+       case NONPOSIX_DEBUG:
+           tflag = 1;
+           break;
+
        case POSIX_YACC:
            /* noop for bison compatibility. byacc is already designed to be posix
             * yacc compatible. */
@@ -1649,9 +1981,11 @@ copy_args(int *alen)
     struct mstring *s = msnew();
     int depth = 0, len = 1;
     char c, quote = 0;
-    int a_lineno = lineno;
-    char *a_line = dup_line();
-    char *a_cptr = a_line + (cptr - line - 1);
+    struct ainfo a;
+
+    a.a_lineno = lineno;
+    a.a_line = dup_line();
+    a.a_cptr = a.a_line + (cptr - line - 1);
 
     while ((c = *cptr++) != R_PAREN || depth || quote)
     {
@@ -1668,9 +2002,9 @@ copy_args(int *alen)
            if (!line)
            {
                if (quote)
-                   unterminated_string(a_lineno, a_line, a_cptr);
+                   unterminated_string(&a);
                else
-                   unterminated_arglist(a_lineno, a_line, a_cptr);
+                   unterminated_arglist(&a);
            }
        }
        else if (quote)
@@ -1695,7 +2029,7 @@ copy_args(int *alen)
     }
     if (alen)
        *alen = len;
-    FREE(a_line);
+    FREE(a.a_line);
     return msdone(s);
 }
 
@@ -1704,17 +2038,17 @@ parse_id(char *p, char **save)
 {
     char *b;
 
-    while (isspace(*p))
+    while (isspace(UCH(*p)))
        if (*p++ == '\n')
            rescan_lineno++;
-    if (!isalpha(*p) && *p != '_')
+    if (!isalpha(UCH(*p)) && *p != '_')
        return NULL;
     b = p;
-    while (isalnum(*p) || *p == '_' || *p == '$')
+    while (IS_NAME2(UCH(*p)))
        p++;
     if (save)
     {
-       *save = cache_tag(b, (size_t) (p - b));
+       *save = cache_tag(b, (size_t)(p - b));
     }
     return p;
 }
@@ -1724,7 +2058,7 @@ parse_int(char *p, int *save)
 {
     int neg = 0, val = 0;
 
-    while (isspace(*p))
+    while (isspace(UCH(*p)))
        if (*p++ == '\n')
            rescan_lineno++;
     if (*p == '-')
@@ -1732,9 +2066,9 @@ parse_int(char *p, int *save)
        neg = 1;
        p++;
     }
-    if (!isdigit(*p))
+    if (!isdigit(UCH(*p)))
        return NULL;
-    while (isdigit(*p))
+    while (isdigit(UCH(*p)))
        val = val * 10 + *p++ - '0';
     if (neg)
        val = -val;
@@ -1749,7 +2083,7 @@ parse_arginfo(bucket *a, char *args, int argslen)
     char *p = args, *tmp;
     int i, redec = 0;
 
-    if (a->args > 0)
+    if (a->args >= 0)
     {
        if (a->args != argslen)
            arg_number_disagree_warning(rescan_lineno, a->name);
@@ -1768,12 +2102,12 @@ parse_arginfo(bucket *a, char *args, int argslen)
        return;
     for (i = 0; i < argslen; i++)
     {
-       while (isspace(*p))
+       while (isspace(UCH(*p)))
            if (*p++ == '\n')
                rescan_lineno++;
        if (*p++ != '$')
            bad_formals();
-       while (isspace(*p))
+       while (isspace(UCH(*p)))
            if (*p++ == '\n')
                rescan_lineno++;
        if (*p == '<')
@@ -1781,7 +2115,7 @@ parse_arginfo(bucket *a, char *args, int argslen)
            havetags = 1;
            if (!(p = parse_id(p + 1, &tmp)))
                bad_formals();
-           while (isspace(*p))
+           while (isspace(UCH(*p)))
                if (*p++ == '\n')
                    rescan_lineno++;
            if (*p++ != '>')
@@ -1798,7 +2132,7 @@ parse_arginfo(bucket *a, char *args, int argslen)
            a->argtags[i] = NULL;
        if (!(p = parse_id(p, &a->argnames[i])))
            bad_formals();
-       while (isspace(*p))
+       while (isspace(UCH(*p)))
            if (*p++ == '\n')
                rescan_lineno++;
        if (*p++)
@@ -1812,7 +2146,7 @@ compile_arg(char **theptr, char *yyvaltag)
 {
     char *p = *theptr;
     struct mstring *c = msnew();
-    int i, j, n;
+    int i, n;
     Value_t *offsets = NULL, maxoffset;
     bucket **rhs;
 
@@ -1826,12 +2160,14 @@ compile_arg(char **theptr, char *yyvaltag)
     }
     if (maxoffset > 0)
     {
-       offsets = TMALLOC(Value_t, maxoffset + 1);
+       int j;
+
+       offsets = TCMALLOC(Value_t, maxoffset + 1);
        NO_SPACE(offsets);
 
        for (j = 0, i++; i < nitems; i++)
            if (pitem[i]->class != ARGUMENT)
-               offsets[++j] = (Value_t) (i - nitems + 1);
+               offsets[++j] = (Value_t)(i - nitems + 1);
     }
     rhs = pitem + nitems - 1;
 
@@ -1847,7 +2183,7 @@ compile_arg(char **theptr, char *yyvaltag)
            if (*++p == '<')
                if (!(p = parse_id(++p, &tag)) || *p++ != '>')
                    illegal_tag(rescan_lineno, NULL, NULL);
-           if (isdigit(*p) || *p == '-')
+           if (isdigit(UCH(*p)) || *p == '-')
            {
                int val;
                if (!(p = parse_int(p, &val)))
@@ -1871,7 +2207,7 @@ compile_arg(char **theptr, char *yyvaltag)
                else if (havetags)
                    unknown_rhs(val);
            }
-           else if (isalpha(*p) || *p == '_')
+           else if (isalpha(UCH(*p)) || *p == '_')
            {
                char *arg;
                if (!(p = parse_id(p, &arg)))
@@ -1883,8 +2219,8 @@ compile_arg(char **theptr, char *yyvaltag)
                    unknown_arg_warning(rescan_lineno, "$", arg, NULL, NULL);
                else if (!tag)
                    tag = plhs[nrules]->argtags[i];
-               msprintf(c, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1
-                        - n);
+               msprintf(c, "yystack.l_mark[%d]",
+                        i - plhs[nrules]->args + 1 - n);
                if (tag)
                    msprintf(c, ".%s", tag);
                else if (havetags)
@@ -1910,6 +2246,95 @@ compile_arg(char **theptr, char *yyvaltag)
     return msdone(c);
 }
 
+static int
+can_elide_arg(char **theptr, char *yyvaltag)
+{
+    char *p = *theptr;
+    int rv = 0;
+    int i, n = 0;
+    Value_t *offsets = NULL, maxoffset = 0;
+    bucket **rhs;
+    char *tag = 0;
+
+    if (*p++ != '$')
+       return 0;
+    if (*p == '<')
+    {
+       if (!(p = parse_id(++p, &tag)) || *p++ != '>')
+           return 0;
+    }
+    for (i = nitems - 1; pitem[i]; --i)
+    {
+       n++;
+       if (pitem[i]->class != ARGUMENT)
+           maxoffset++;
+    }
+    if (maxoffset > 0)
+    {
+       int j;
+
+       offsets = TCMALLOC(Value_t, maxoffset + 1);
+       NO_SPACE(offsets);
+
+       for (j = 0, i++; i < nitems; i++)
+           if (pitem[i]->class != ARGUMENT)
+               offsets[++j] = (Value_t)(i - nitems + 1);
+    }
+    rhs = pitem + nitems - 1;
+
+    if (isdigit(UCH(*p)) || *p == '-')
+    {
+       int val;
+       if (!(p = parse_int(p, &val)))
+           rv = 0;
+       else
+       {
+           if (val <= 0)
+               rv = 1 - val + n;
+           else if (val > maxoffset)
+               rv = 0;
+           else
+           {
+               i = offsets[val];
+               rv = 1 - i;
+               if (!tag)
+                   tag = rhs[i]->tag;
+           }
+       }
+    }
+    else if (isalpha(UCH(*p)) || *p == '_')
+    {
+       char *arg;
+       if (!(p = parse_id(p, &arg)))
+       {
+           FREE(offsets);
+           return 0;
+       }
+       for (i = plhs[nrules]->args - 1; i >= 0; i--)
+           if (arg == plhs[nrules]->argnames[i])
+               break;
+       if (i >= 0)
+       {
+           if (!tag)
+               tag = plhs[nrules]->argtags[i];
+           rv = plhs[nrules]->args + n - i;
+       }
+    }
+    if (tag && yyvaltag)
+    {
+       if (strcmp(tag, yyvaltag))
+           rv = 0;
+    }
+    else if (tag || yyvaltag)
+       rv = 0;
+    if (maxoffset > 0)
+       FREE(offsets);
+    if (p == 0 || *p || rv <= 0)
+       return 0;
+    *theptr = p + 1;
+    return rv;
+}
+
 #define ARG_CACHE_SIZE 1024
 static struct arg_cache
 {
@@ -1961,14 +2386,13 @@ clean_arg_cache(void)
        arg_cache[i] = NULL;
     }
 }
-#endif
+#endif /* defined(YYBTYACC) */
 
 static void
 advance_to_start(void)
 {
     int c;
     bucket *bp;
-    char *s_cptr;
     int s_lineno;
 #if defined(YYBTYACC)
     char *args = NULL;
@@ -1977,12 +2401,18 @@ advance_to_start(void)
 
     for (;;)
     {
+       char *s_cptr;
+
        c = nextc();
        if (c != '%')
            break;
        s_cptr = cptr;
        switch (keyword())
        {
+       case XCODE:
+           copy_code();
+           break;
+
        case MARK:
            no_grammar();
 
@@ -2000,7 +2430,7 @@ advance_to_start(void)
     }
 
     c = nextc();
-    if (!isalpha(c) && c != '_' && c != '.' && c != '_')
+    if (!isalpha(UCH(c)) && c != '_' && c != '.' && c != '_')
        syntax_error(lineno, line, cptr);
     bp = get_name();
     if (goal == 0)
@@ -2051,21 +2481,19 @@ start_rule(bucket *bp, int s_lineno)
 static void
 end_rule(void)
 {
-    int i;
-
     if (!last_was_action && plhs[nrules]->tag)
     {
        if (pitem[nitems - 1])
        {
+           int i;
+
            for (i = nitems - 1; (i > 0) && pitem[i]; --i)
                continue;
            if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
-               default_action_warning();
+               default_action_warning(plhs[nrules]->name);
        }
        else
-       {
-           default_action_warning();
-       }
+           default_action_warning(plhs[nrules]->name);
     }
 
     last_was_action = 0;
@@ -2093,7 +2521,7 @@ insert_empty_rule(void)
     bp->args = 0;
 #endif
 
-    nitems = (Value_t) (nitems + 2);
+    nitems = (Value_t)(nitems + 2);
     if (nitems > maxitems)
        expand_items();
     bpp = pitem + nitems - 1;
@@ -2124,13 +2552,13 @@ insert_arg_rule(char *arg, char *tag)
     {
        rule = nrules;
        insert_arg_cache(code, rule);
-       fprintf(f, "case %d:\n", rule - 2);
-       if (!lflag)
-           fprintf(f, line_format, line_number, input_file_name);
-       fprintf(f, "%s;\n", code);
-       fprintf(f, "break;\n");
+       trialaction = 1;        /* arg rules always run in trial mode */
+       begin_case(f, rule - 2);
+       fprintf_lineno(f, line_number, input_file_name);
+       fprintf(f, "%s;", code);
+       end_case(f);
        insert_empty_rule();
-       plhs[rule]->tag = tag;
+       plhs[rule]->tag = cache_tag(tag, strlen(tag));
        plhs[rule]->class = ARGUMENT;
     }
     else
@@ -2201,11 +2629,33 @@ add_symbol(void)
     }
     else if (bp->args != argslen)
        wrong_number_args_warning("", bp->name);
-    if (bp->args > 0 && argslen > 0)
+    if (args != 0)
     {
-       char *ap;
-       int i;
-       for (ap = args, i = 0; i < argslen; i++)
+       char *ap = args;
+       int i = 0;
+       int elide_cnt = can_elide_arg(&ap, bp->argtags[0]);
+
+       if (elide_cnt > argslen)
+           elide_cnt = 0;
+       if (elide_cnt)
+       {
+           for (i = 1; i < elide_cnt; i++)
+               if (can_elide_arg(&ap, bp->argtags[i]) != elide_cnt - i)
+               {
+                   elide_cnt = 0;
+                   break;
+               }
+       }
+       if (elide_cnt)
+       {
+           assert(i == elide_cnt);
+       }
+       else
+       {
+           ap = args;
+           i = 0;
+       }
+       for (; i < argslen; i++)
            ap = insert_arg_rule(ap, bp->argtags[i]);
        free(args);
     }
@@ -2223,33 +2673,34 @@ copy_action(void)
     int i, j, n;
     int depth;
 #if defined(YYBTYACC)
-    int trialaction = 0;
     int haveyyval = 0;
 #endif
     char *tag;
     FILE *f = action_file;
-    int a_lineno = lineno;
-    char *a_line = dup_line();
-    char *a_cptr = a_line + (cptr - line);
+    struct ainfo a;
     Value_t *offsets = NULL, maxoffset;
     bucket **rhs;
 
+    a.a_lineno = lineno;
+    a.a_line = dup_line();
+    a.a_cptr = a.a_line + (cptr - line);
+
     if (last_was_action)
        insert_empty_rule();
     last_was_action = 1;
+#if defined(YYBTYACC)
+    trialaction = (*cptr == L_BRAC);
+#endif
 
-    fprintf(f, "case %d:\n", nrules - 2);
+    begin_case(f, nrules - 2);
 #if defined(YYBTYACC)
     if (backtrack)
     {
-       if (*cptr != L_BRAC)
+       if (!trialaction)
            fprintf(f, "  if (!yytrial)\n");
-       else
-           trialaction = 1;
     }
 #endif
-    if (!lflag)
-       fprintf(f, line_format, lineno, input_file_name);
+    fprintf_lineno(f, lineno, input_file_name);
     if (*cptr == '=')
        ++cptr;
 
@@ -2277,7 +2728,7 @@ copy_action(void)
        {
            if (pitem[i]->class != ARGUMENT)
            {
-               offsets[++j] = (Value_t) (i - nitems + 1);
+               offsets[++j] = (Value_t)(i - nitems + 1);
            }
        }
     }
@@ -2304,7 +2755,7 @@ copy_action(void)
                FREE(d_line);
                goto loop;
            }
-           else if (isdigit(c))
+           else if (isdigit(UCH(c)))
            {
                i = get_number();
                if (i == 0)
@@ -2312,10 +2763,12 @@ copy_action(void)
                else if (i > maxoffset)
                {
                    dollar_warning(d_lineno, i);
-                   fprintf(f, "yystack.l_mark[%d].%s", i - maxoffset, tag);
+                   fprintf(f, "yystack.l_mark[%ld].%s",
+                           (long)(i - maxoffset), tag);
                }
                else if (offsets)
-                   fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
+                   fprintf(f, "yystack.l_mark[%ld].%s",
+                           (long)offsets[i], tag);
                FREE(d_line);
                goto loop;
            }
@@ -2328,7 +2781,7 @@ copy_action(void)
                goto loop;
            }
 #if defined(YYBTYACC)
-           else if (isalpha(c) || c == '_')
+           else if (isalpha(UCH(c)) || c == '_')
            {
                char *arg = scan_id();
                for (i = plhs[nrules]->args - 1; i >= 0; i--)
@@ -2336,8 +2789,8 @@ copy_action(void)
                        break;
                if (i < 0)
                    unknown_arg_warning(d_lineno, "$", arg, d_line, d_cptr);
-               fprintf(f, "yystack.l_mark[%d].%s", i - plhs[nrules]->args +
-                       1 - n, tag);
+               fprintf(f, "yystack.l_mark[%d].%s",
+                       i - plhs[nrules]->args + 1 - n, tag);
                FREE(d_line);
                goto loop;
            }
@@ -2373,7 +2826,7 @@ copy_action(void)
                tag = rhs[offsets[i]]->tag;
                if (tag == 0)
                    untyped_rhs(i, rhs[offsets[i]]->name);
-               fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
+               fprintf(f, "yystack.l_mark[%ld].%s", (long)offsets[i], tag);
            }
            else
            {
@@ -2382,10 +2835,10 @@ copy_action(void)
                else if (i > maxoffset)
                {
                    dollar_warning(lineno, i);
-                   fprintf(f, "yystack.l_mark[%d]", i - maxoffset);
+                   fprintf(f, "yystack.l_mark[%ld]", (long)(i - maxoffset));
                }
                else if (offsets)
-                   fprintf(f, "yystack.l_mark[%d]", offsets[i]);
+                   fprintf(f, "yystack.l_mark[%ld]", (long)offsets[i]);
            }
            goto loop;
        }
@@ -2399,7 +2852,7 @@ copy_action(void)
            goto loop;
        }
 #if defined(YYBTYACC)
-       else if (isalpha(cptr[1]) || cptr[1] == '_')
+       else if (isalpha(UCH(cptr[1])) || cptr[1] == '_')
        {
            char *arg;
            ++cptr;
@@ -2450,16 +2903,23 @@ copy_action(void)
                fprintf(f, "yystack.p_mark[%d]", offsets[i]);
            goto loop;
        }
+       else if (cptr[1] == '-')
+       {
+           cptr += 2;
+           i = get_number();
+           fprintf(f, "yystack.p_mark[%d]", -i - n);
+           goto loop;
+       }
     }
 #endif
-    if (isalpha(c) || c == '_' || c == '$')
+    if (IS_NAME1(c))
     {
        do
        {
            putc(c, f);
            c = *++cptr;
        }
-       while (isalnum(c) || c == '_' || c == '$');
+       while (IS_NAME2(c));
        goto loop;
     }
     ++cptr;
@@ -2484,13 +2944,12 @@ copy_action(void)
            if (c == L_CURL && !haveyyval)
            {
                fprintf(f, "  if (!yytrial)\n");
-               if (!lflag)
-                   fprintf(f, line_format, lineno, input_file_name);
+               fprintf_lineno(f, lineno, input_file_name);
                trialaction = 0;
                goto loop;
            }
-           fprintf(f, "\nbreak;\n");
-           FREE(a_line);
+           end_case(f);
+           FREE(a.a_line);
            if (maxoffset > 0)
                FREE(offsets);
            return;
@@ -2504,13 +2963,13 @@ copy_action(void)
        get_line();
        if (line)
            goto loop;
-       unterminated_action(a_lineno, a_line, a_cptr);
+       unterminated_action(&a);
 
     case ';':
        if (depth > 0)
            goto loop;
-       fprintf(f, "\nbreak;\n");
-       free(a_line);
+       end_case(f);
+       free(a.a_line);
        if (maxoffset > 0)
            FREE(offsets);
        return;
@@ -2546,14 +3005,13 @@ copy_action(void)
            if (c == L_CURL && !haveyyval)
            {
                fprintf(f, "  if (!yytrial)\n");
-               if (!lflag)
-                   fprintf(f, line_format, lineno, input_file_name);
+               fprintf_lineno(f, lineno, input_file_name);
                goto loop;
            }
        }
 #endif
-       fprintf(f, "\nbreak;\n");
-       free(a_line);
+       end_case(f);
+       free(a.a_line);
        if (maxoffset > 0)
            FREE(offsets);
        return;
@@ -2581,32 +3039,27 @@ copy_action(void)
 }
 
 #if defined(YYBTYACC)
-static void
-copy_destructor(void)
+static char *
+get_code(struct ainfo *a, const char *loc)
 {
     int c;
     int depth;
     char *tag;
-    bucket *bp;
-    struct mstring *destructor_text = msnew();
-    char *code_text;
-    int a_lineno;
-    char *a_line;
-    char *a_cptr;
+    struct mstring *code_mstr = msnew();
 
     if (!lflag)
-       msprintf(destructor_text, line_format, lineno, input_file_name);
+       msprintf(code_mstr, line_format, lineno, input_file_name);
 
     cptr = after_blanks(cptr);
     if (*cptr == L_CURL)
        /* avoid putting curly-braces in first column, to ease editing */
-       mputc(destructor_text, '\t');
+       mputc(code_mstr, '\t');
     else
        syntax_error(lineno, line, cptr);
 
-    a_lineno = lineno;
-    a_line = dup_line();
-    a_cptr = a_line + (cptr - line);
+    a->a_lineno = lineno;
+    a->a_line = dup_line();
+    a->a_cptr = a->a_line + (cptr - line);
 
     depth = 0;
   loop:
@@ -2624,7 +3077,7 @@ copy_destructor(void)
            c = *cptr;
            if (c == '$')
            {
-               msprintf(destructor_text, "(*val).%s", tag);
+               msprintf(code_mstr, "(*val).%s", tag);
                ++cptr;
                FREE(d_line);
                goto loop;
@@ -2635,7 +3088,7 @@ copy_destructor(void)
        else if (cptr[1] == '$')
        {
            /* process '$$' later; replacement is context dependent */
-           msprintf(destructor_text, "$$");
+           msprintf(code_mstr, "$$");
            cptr += 2;
            goto loop;
        }
@@ -2649,29 +3102,29 @@ copy_destructor(void)
            char *l_cptr = l_line + (cptr - line);
            syntax_error(l_lineno, l_line, l_cptr);
        }
-       msprintf(destructor_text, "(*loc)");
+       msprintf(code_mstr, "%s", loc);
        cptr += 2;
        goto loop;
     }
-    if (isalpha(c) || c == '_' || c == '$')
+    if (IS_NAME1(c))
     {
        do
        {
-           mputc(destructor_text, c);
+           mputc(code_mstr, c);
            c = *++cptr;
        }
-       while (isalnum(c) || c == '_' || c == '$');
+       while (IS_NAME2(c));
        goto loop;
     }
     ++cptr;
-    mputc(destructor_text, c);
+    mputc(code_mstr, c);
     switch (c)
     {
     case '\n':
        get_line();
        if (line)
            goto loop;
-       unterminated_action(a_lineno, a_line, a_cptr);
+       unterminated_action(a);
 
     case L_CURL:
        ++depth;
@@ -2680,13 +3133,13 @@ copy_destructor(void)
     case R_CURL:
        if (--depth > 0)
            goto loop;
-       goto process_symbols;
+       goto out;
 
     case '\'':
     case '"':
        {
            char *s = copy_string(c);
-           msprintf(destructor_text, "%s", s);
+           msprintf(code_mstr, "%s", s);
            free(s);
        }
        goto loop;
@@ -2694,7 +3147,7 @@ copy_destructor(void)
     case '/':
        {
            char *s = copy_comment();
-           msprintf(destructor_text, "%s", s);
+           msprintf(code_mstr, "%s", s);
            free(s);
        }
        goto loop;
@@ -2702,11 +3155,31 @@ copy_destructor(void)
     default:
        goto loop;
     }
-  process_symbols:
-    code_text = msdone(destructor_text);
+  out:
+    return msdone(code_mstr);
+}
+
+static void
+copy_initial_action(void)
+{
+    struct ainfo a;
+
+    initial_action = get_code(&a, "yyloc");
+    free(a.a_line);
+}
+
+static void
+copy_destructor(void)
+{
+    char *code_text;
+    struct ainfo a;
+    bucket *bp;
+
+    code_text = get_code(&a, "(*loc)");
+
     for (;;)
     {
-       c = nextc();
+       int c = nextc();
        if (c == EOF)
            unexpected_EOF();
        if (c == '<')
@@ -2722,7 +3195,7 @@ copy_destructor(void)
                    default_destructor[UNTYPED_DEFAULT] = bp;
                }
                if (bp->destructor != NULL)
-                   destructor_redeclared_warning(a_lineno, a_line, a_cptr);
+                   destructor_redeclared_warning(&a);
                else
                    /* replace "$$" with "(*val)" in destructor code */
                    bp->destructor = process_destructor_XX(code_text, NULL);
@@ -2738,7 +3211,7 @@ copy_destructor(void)
                    default_destructor[TYPED_DEFAULT] = bp;
                }
                if (bp->destructor != NULL)
-                   destructor_redeclared_warning(a_lineno, a_line, a_cptr);
+                   destructor_redeclared_warning(&a);
                else
                {
                    /* postpone re-processing destructor $$s until end of grammar spec */
@@ -2749,20 +3222,20 @@ copy_destructor(void)
            }
            else
            {                   /* "semantic type" default destructor */
-               tag = get_tag();
+               char *tag = get_tag();
                bp = lookup_type_destructor(tag);
                if (bp->destructor != NULL)
-                   destructor_redeclared_warning(a_lineno, a_line, a_cptr);
+                   destructor_redeclared_warning(&a);
                else
                    /* replace "$$" with "(*val).tag" in destructor code */
                    bp->destructor = process_destructor_XX(code_text, tag);
            }
        }
-       else if (isalpha(c) || c == '_' || c == '.' || c == '$')
+       else if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
        {                       /* "symbol" destructor */
            bp = get_name();
            if (bp->destructor != NULL)
-               destructor_redeclared_warning(a_lineno, a_line, a_cptr);
+               destructor_redeclared_warning(&a);
            else
            {
                /* postpone re-processing destructor $$s until end of grammar spec */
@@ -2774,7 +3247,7 @@ copy_destructor(void)
        else
            break;
     }
-    free(a_line);
+    free(a.a_line);
     free(code_text);
 }
 
@@ -2799,14 +3272,14 @@ process_destructor_XX(char *code, char *tag)
            msprintf(new_code, "(*val).%s", tag);
        goto loop;
     }
-    if (isalpha(c) || c == '_' || c == '$')
+    if (IS_NAME1(c))
     {
        do
        {
            mputc(new_code, c);
            c = *++codeptr;
        }
-       while (isalnum(c) || c == '_' || c == '$');
+       while (IS_NAME2(c));
        goto loop;
     }
     ++codeptr;
@@ -2885,17 +3358,28 @@ mark_symbol(void)
             ((c = cptr[4]) == 'c' || c == 'C') &&
             ((c = cptr[5], !IS_IDENT(c))))
        cptr += 5;
+    else if ((c == 'e' || c == 'E') &&
+            ((c = cptr[2]) == 'm' || c == 'M') &&
+            ((c = cptr[3]) == 'p' || c == 'P') &&
+            ((c = cptr[4]) == 't' || c == 'T') &&
+            ((c = cptr[5]) == 'y' || c == 'Y') &&
+            ((c = cptr[6], !IS_IDENT(c))))
+    {
+       cptr += 6;
+       return (1);
+    }
     else
        syntax_error(lineno, line, cptr);
 
     c = nextc();
-    if (isalpha(c) || c == '_' || c == '.' || c == '$')
+    if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
        bp = get_name();
     else if (c == '\'' || c == '"')
        bp = get_literal();
     else
     {
        syntax_error(lineno, line, cptr);
+       /*NOTREACHED */
     }
 
     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
@@ -2909,29 +3393,32 @@ mark_symbol(void)
 static void
 read_grammar(void)
 {
-    int c;
-
     initialize_grammar();
     advance_to_start();
 
     for (;;)
     {
-       c = nextc();
+       int c = nextc();
+
        if (c == EOF)
            break;
-       if (isalpha(c)
+       if (isalpha(UCH(c))
            || c == '_'
            || c == '.'
            || c == '$'
            || c == '\''
            || c == '"')
+       {
            add_symbol();
+       }
+       else if (c == L_CURL || c == '='
 #if defined(YYBTYACC)
-       else if (c == L_CURL || c == '=' || (backtrack && c == L_BRAC))
-#else
-       else if (c == L_CURL || c == '=')
+                || (backtrack && c == L_BRAC)
 #endif
+           )
+       {
            copy_action();
+       }
        else if (c == '|')
        {
            end_rule();
@@ -2973,7 +3460,8 @@ static void
 pack_names(void)
 {
     bucket *bp;
-    char *p, *s, *t;
+    char *p;
+    char *t;
 
     name_pool_size = 13;       /* 13 == sizeof("$end") + sizeof("$accept") */
     for (bp = first_symbol; bp; bp = bp->next)
@@ -2987,8 +3475,9 @@ pack_names(void)
     t = name_pool + 13;
     for (bp = first_symbol; bp; bp = bp->next)
     {
+       char *s = bp->name;
+
        p = t;
-       s = bp->name;
        while ((*t++ = *s++) != 0)
            continue;
        FREE(bp->name);
@@ -3017,14 +3506,14 @@ check_symbols(void)
 static void
 protect_string(char *src, char **des)
 {
-    unsigned len;
-    char *s;
-    char *d;
-
     *des = src;
     if (src)
     {
-       len = 1;
+       char *s;
+       char *d;
+
+       unsigned len = 1;
+
        s = src;
        while (*s)
        {
@@ -3066,8 +3555,8 @@ pack_symbols(void)
        if (bp->class == TERM)
            ++ntokens;
     }
-    start_symbol = (Value_t) ntokens;
-    nvars = (Value_t) (nsyms - ntokens);
+    start_symbol = (Value_t)ntokens;
+    nvars = (Value_t)(nsyms - ntokens);
 
     symbol_name = TMALLOC(char *, nsyms);
     NO_SPACE(symbol_name);
@@ -3102,7 +3591,7 @@ pack_symbols(void)
     v[start_symbol] = 0;
 
     i = 1;
-    j = (Value_t) (start_symbol + 1);
+    j = (Value_t)(start_symbol + 1);
     for (bp = first_symbol; bp; bp = bp->next)
     {
        if (bp->class == TERM)
@@ -3115,8 +3604,8 @@ pack_symbols(void)
     for (i = 1; i < ntokens; ++i)
        v[i]->index = i;
 
-    goal->index = (Index_t) (start_symbol + 1);
-    k = (Value_t) (start_symbol + 2);
+    goal->index = (Index_t)(start_symbol + 1);
+    k = (Value_t)(start_symbol + 2);
     while (++i < nsyms)
        if (v[i] != goal)
        {
@@ -3126,7 +3615,7 @@ pack_symbols(void)
 
     goal->value = 0;
     k = 1;
-    for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
+    for (i = (Value_t)(start_symbol + 1); i < nsyms; ++i)
     {
        if (v[i] != goal)
        {
@@ -3199,7 +3688,7 @@ pack_symbols(void)
     symbol_prec[start_symbol] = 0;
     symbol_assoc[start_symbol] = TOKEN;
 #if defined(YYBTYACC)
-    symbol_pval[start_symbol] = (Value_t) (max_tok_pval + 1);
+    symbol_pval[start_symbol] = (Value_t)(max_tok_pval + 1);
 #endif
     for (++i; i < nsyms; ++i)
     {
@@ -3209,7 +3698,7 @@ pack_symbols(void)
        symbol_prec[k] = v[i]->prec;
        symbol_assoc[k] = v[i]->assoc;
 #if defined(YYBTYACC)
-       symbol_pval[k] = (Value_t) ((max_tok_pval + 1) + v[i]->value + 1);
+       symbol_pval[k] = (Value_t)((max_tok_pval + 1) + v[i]->value + 1);
        if (destructor)
        {
            symbol_destructor[k] = v[i]->destructor;
@@ -3235,8 +3724,6 @@ pack_grammar(void)
 {
     int i;
     Value_t j;
-    Assoc_t assoc;
-    Value_t prec2;
 
     ritem = TMALLOC(Value_t, nitems);
     NO_SPACE(ritem);
@@ -3267,6 +3754,9 @@ pack_grammar(void)
     j = 4;
     for (i = 3; i < nrules; ++i)
     {
+       Assoc_t assoc;
+       Value_t prec2;
+
 #if defined(YYBTYACC)
        if (plhs[i]->args > 0)
        {
@@ -3296,7 +3786,7 @@ pack_grammar(void)
            }
            ++j;
        }
-       ritem[j] = (Value_t) - i;
+       ritem[j] = (Value_t)-i;
        ++j;
        if (rprec[i] == UNDEFINED)
        {
@@ -3358,11 +3848,11 @@ finalize_destructors(void)
 {
     int i;
     bucket *bp;
-    char *tag;
 
     for (i = 2; i < nsyms; ++i)
     {
-       tag = symbol_type_tag[i];
+       char *tag = symbol_type_tag[i];
+
        if (symbol_destructor[i] == NULL)
        {
            if (tag == NULL)
@@ -3396,8 +3886,10 @@ finalize_destructors(void)
        }
        else
        {                       /* replace "$$" with "(*val)[.tag]" in destructor code */
+           char *destructor_source = symbol_destructor[i];
            symbol_destructor[i]
-               = process_destructor_XX(symbol_destructor[i], tag);
+               = process_destructor_XX(destructor_source, tag);
+           FREE(destructor_source);
        }
     }
     /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */
@@ -3454,7 +3946,7 @@ reader(void)
 
 #ifdef NO_LEAKS
 static param *
-free_declarations(param * list)
+free_declarations(param *list)
 {
     while (list != 0)
     {