]> git.saurik.com Git - bison.git/blobdiff - src/lex.c
.
[bison.git] / src / lex.c
index cf4f7e5752202d95ac6fc62a7357eceb445e60b3..4bd0a6f26344d4fbc883b38f6c5543166255b27a 100644 (file)
--- a/src/lex.c
+++ b/src/lex.c
@@ -1,5 +1,5 @@
 /* Token-reader for Bison's input parser,
 /* Token-reader for Bison's input parser,
-   Copyright (C) 1984, 1986, 1989, 1992, 2000 Free Software Foundation, Inc.
+   Copyright 1984, 1986, 1989, 1992, 2000, 2001 Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
 
 
    This file is part of Bison, the GNU Compiler Compiler.
 
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-
-/*
-   lex is the entry point.  It is called from reader.c.
-   It returns one of the token-type codes defined in lex.h.
-   When an identifier is seen, the code IDENTIFIER is returned
-   and the name is looked up in the symbol table using symtab.c;
-   symval is set to a pointer to the entry found.  */
-
-#include <stdio.h>
 #include "system.h"
 #include "system.h"
+#include "getargs.h"
 #include "files.h"
 #include "getopt.h"            /* for optarg */
 #include "symtab.h"
 #include "lex.h"
 #include "files.h"
 #include "getopt.h"            /* for optarg */
 #include "symtab.h"
 #include "lex.h"
-#include "alloc.h"
+#include "xalloc.h"
 #include "complain.h"
 #include "complain.h"
-
-/* flags set by % directives */
-extern int definesflag;        /* for -d */
-extern int toknumflag;         /* for -k */
-extern int noparserflag;       /* for -n */
-extern int fixed_outfiles;     /* for -y */
-extern int nolinesflag;        /* for -l */
-extern int rawtoknumflag;      /* for -r */
-extern int verboseflag;        /* for -v */
-extern int debugflag;                  /* for -t */
-extern char *spec_name_prefix;         /* for -p */
-extern char *spec_file_prefix; /* for -b */
-/*spec_outfile is declared in files.h, for -o */
-
-extern int translations;
-
-void init_lex PARAMS((void));
-char *grow_token_buffer PARAMS((char *));
-int skip_white_space PARAMS((void));
-int safegetc PARAMS((FILE *));
-int literalchar PARAMS((char **, int *, char));
-void unlex PARAMS((int));
-int lex PARAMS((void));
-int parse_percent_token PARAMS((void));
-
-/* functions from main.c */
-extern char *printable_version PARAMS((int));
+#include "gram.h"
+#include "quote.h"
 
 /* Buffer for storing the current token.  */
 
 /* Buffer for storing the current token.  */
-char *token_buffer;
-
-/* Allocated size of token_buffer, not including space for terminator.  */
-int maxtoken;
+struct obstack token_obstack;
+const char *token_buffer = NULL;
 
 bucket *symval;
 int numval;
 
 bucket *symval;
 int numval;
@@ -78,29 +43,18 @@ static bucket *unlexed_symval;      /* by the next call to lex */
 void
 init_lex (void)
 {
 void
 init_lex (void)
 {
-  maxtoken = 100;
-  token_buffer = NEW2 (maxtoken + 1, char);
+  obstack_init (&token_obstack);
   unlexed = -1;
 }
 
 
   unlexed = -1;
 }
 
 
-char *
-grow_token_buffer (char *p)
-{
-  int offset = p - token_buffer;
-  maxtoken *= 2;
-  token_buffer = (char *) xrealloc(token_buffer, maxtoken + 1);
-  return token_buffer + offset;
-}
-
-
 int
 skip_white_space (void)
 {
 int
 skip_white_space (void)
 {
-  register int c;
-  register int inside;
+  int c;
+  int inside;
 
 
-  c = getc(finput);
+  c = getc (finput);
 
   for (;;)
     {
 
   for (;;)
     {
@@ -109,7 +63,8 @@ skip_white_space (void)
       switch (c)
        {
        case '/':
       switch (c)
        {
        case '/':
-         c = getc(finput);
+         /* FIXME: Should probably be merged with copy_comment.  */
+         c = getc (finput);
          if (c != '*' && c != '/')
            {
              complain (_("unexpected `/' found and ignored"));
          if (c != '*' && c != '/')
            {
              complain (_("unexpected `/' found and ignored"));
@@ -117,7 +72,7 @@ skip_white_space (void)
            }
          cplus_comment = (c == '/');
 
            }
          cplus_comment = (c == '/');
 
-         c = getc(finput);
+         c = getc (finput);
 
          inside = 1;
          while (inside)
 
          inside = 1;
          while (inside)
@@ -125,12 +80,12 @@ skip_white_space (void)
              if (!cplus_comment && c == '*')
                {
                  while (c == '*')
              if (!cplus_comment && c == '*')
                {
                  while (c == '*')
-                   c = getc(finput);
+                   c = getc (finput);
 
                  if (c == '/')
                    {
                      inside = 0;
 
                  if (c == '/')
                    {
                      inside = 0;
-                     c = getc(finput);
+                     c = getc (finput);
                    }
                }
              else if (c == '\n')
                    }
                }
              else if (c == '\n')
@@ -138,12 +93,12 @@ skip_white_space (void)
                  lineno++;
                  if (cplus_comment)
                    inside = 0;
                  lineno++;
                  if (cplus_comment)
                    inside = 0;
-                 c = getc(finput);
+                 c = getc (finput);
                }
              else if (c == EOF)
                fatal (_("unterminated comment"));
              else
                }
              else if (c == EOF)
                fatal (_("unterminated comment"));
              else
-               c = getc(finput);
+               c = getc (finput);
            }
 
          break;
            }
 
          break;
@@ -154,44 +109,56 @@ skip_white_space (void)
        case ' ':
        case '\t':
        case '\f':
        case ' ':
        case '\t':
        case '\f':
-         c = getc(finput);
+         c = getc (finput);
          break;
 
        default:
          break;
 
        default:
-         return (c);
+         return c;
        }
     }
 }
 
        }
     }
 }
 
-/* do a getc, but give error message if EOF encountered */
-int
-safegetc (FILE *f)
+
+/*-----------------------------------------------------.
+| Do a getc, but give error message if EOF encountered |
+`-----------------------------------------------------*/
+
+static int
+xgetc (FILE *f)
 {
 {
-  register int c = getc(f);
+  int c = getc (f);
   if (c == EOF)
     fatal (_("unexpected end of file"));
   return c;
 }
 
   if (c == EOF)
     fatal (_("unexpected end of file"));
   return c;
 }
 
-/* read one literal character from finput.  process \ escapes.
-   append the normalized string version of the char to *pp.
-   assign the character code to *pcode
-   return 1 unless the character is an unescaped `term' or \n
-       report error for \n
-*/
-int
-literalchar (char **pp, int *pcode, char term)
+
+/*------------------------------------------------------------------.
+| Read one literal character from finput.  Process \ escapes.       |
+| Append the normalized string version of the char to OUT.  Assign  |
+| the character code to *PCODE. Return 1 unless the character is an |
+| unescaped `term' or \n report error for \n.                       |
+`------------------------------------------------------------------*/
+
+/* FIXME: We could directly work in the obstack, but that would make
+   it more difficult to move to quotearg some day.  So for the time
+   being, I prefer have literalchar behave like quotearg, and change
+   my mind later if I was wrong.  */
+
+static int
+literalchar (struct obstack *out, int *pcode, char term)
 {
 {
-  register int c;
-  register char *p;
-  register int code;
+  int c;
+  char buf[4096];
+  char *cp;
+  int code;
   int wasquote = 0;
 
   int wasquote = 0;
 
-  c = safegetc(finput);
+  c = xgetc (finput);
   if (c == '\n')
     {
       complain (_("unescaped newline in constant"));
   if (c == '\n')
     {
       complain (_("unescaped newline in constant"));
-      ungetc(c, finput);
+      ungetc (c, finput);
       code = '?';
       wasquote = 1;
     }
       code = '?';
       wasquote = 1;
     }
@@ -203,17 +170,27 @@ literalchar (char **pp, int *pcode, char term)
     }
   else
     {
     }
   else
     {
-      c = safegetc(finput);
-      if (c == 't')  code = '\t';
-      else if (c == 'n')  code = '\n';
-      else if (c == 'a')  code = '\007';
-      else if (c == 'r')  code = '\r';
-      else if (c == 'f')  code = '\f';
-      else if (c == 'b')  code = '\b';
-      else if (c == 'v')  code = '\013';
-      else if (c == '\\')  code = '\\';
-      else if (c == '\'')  code = '\'';
-      else if (c == '\"')  code = '\"';
+      c = xgetc (finput);
+      if (c == 't')
+       code = '\t';
+      else if (c == 'n')
+       code = '\n';
+      else if (c == 'a')
+       code = '\007';
+      else if (c == 'r')
+       code = '\r';
+      else if (c == 'f')
+       code = '\f';
+      else if (c == 'b')
+       code = '\b';
+      else if (c == 'v')
+       code = '\013';
+      else if (c == '\\')
+       code = '\\';
+      else if (c == '\'')
+       code = '\'';
+      else if (c == '\"')
+       code = '\"';
       else if (c <= '7' && c >= '0')
        {
          code = 0;
       else if (c <= '7' && c >= '0')
        {
          code = 0;
@@ -227,71 +204,111 @@ literalchar (char **pp, int *pcode, char term)
                  code &= 0xFF;
                  break;
                }
                  code &= 0xFF;
                  break;
                }
-             c = safegetc(finput);
+             c = xgetc (finput);
            }
            }
-         ungetc(c, finput);
+         ungetc (c, finput);
        }
       else if (c == 'x')
        {
        }
       else if (c == 'x')
        {
-         c = safegetc(finput);
+         c = xgetc (finput);
          code = 0;
          while (1)
            {
              if (c >= '0' && c <= '9')
          code = 0;
          while (1)
            {
              if (c >= '0' && c <= '9')
-               code *= 16,  code += c - '0';
+               code *= 16, code += c - '0';
              else if (c >= 'a' && c <= 'f')
              else if (c >= 'a' && c <= 'f')
-               code *= 16,  code += c - 'a' + 10;
+               code *= 16, code += c - 'a' + 10;
              else if (c >= 'A' && c <= 'F')
              else if (c >= 'A' && c <= 'F')
-               code *= 16,  code += c - 'A' + 10;
+               code *= 16, code += c - 'A' + 10;
              else
                break;
              else
                break;
-             if (code >= 256 || code<0)
+             if (code >= 256 || code < 0)
                {
                {
-                 complain (_("hexadecimal value above 255: `\\x%x'"),
-                           code);
+                 complain (_("hexadecimal value above 255: `\\x%x'"), code);
                  code &= 0xFF;
                  break;
                }
                  code &= 0xFF;
                  break;
                }
-             c = safegetc(finput);
+             c = xgetc (finput);
            }
            }
-         ungetc(c, finput);
+         ungetc (c, finput);
        }
       else
        {
        }
       else
        {
+         char badchar [] = "c";
+         badchar[0] = c;
          complain (_("unknown escape sequence: `\\' followed by `%s'"),
          complain (_("unknown escape sequence: `\\' followed by `%s'"),
-                   printable_version(c));
+                   quote (badchar));
          code = '?';
        }
          code = '?';
        }
-    } /* has \ */
+    }                          /* has \ */
 
 
-  /* now fill token_buffer with the canonical name for this character
-     as a literal token.  Do not use what the user typed,
-     so that `\012' and `\n' can be interchangeable.  */
+  /* now fill BUF with the canonical name for this character as a
+     literal token.  Do not use what the user typed, so that `\012'
+     and `\n' can be interchangeable.  */
 
 
-  p = *pp;
+  cp = buf;
   if (code == term && wasquote)
   if (code == term && wasquote)
-    *p++ = code;
-  else if (code == '\\')  {*p++ = '\\'; *p++ = '\\';}
-  else if (code == '\'')  {*p++ = '\\'; *p++ = '\'';}
-  else if (code == '\"')  {*p++ = '\\'; *p++ = '\"';}
+    *cp++ = code;
+  else if (code == '\\')
+    {
+      *cp++ = '\\';
+      *cp++ = '\\';
+    }
+  else if (code == '\'')
+    {
+      *cp++ = '\\';
+      *cp++ = '\'';
+    }
+  else if (code == '\"')
+    {
+      *cp++ = '\\';
+      *cp++ = '\"';
+    }
   else if (code >= 040 && code < 0177)
   else if (code >= 040 && code < 0177)
-    *p++ = code;
-  else if (code == '\t')  {*p++ = '\\'; *p++ = 't';}
-  else if (code == '\n')  {*p++ = '\\'; *p++ = 'n';}
-  else if (code == '\r')  {*p++ = '\\'; *p++ = 'r';}
-  else if (code == '\v')  {*p++ = '\\'; *p++ = 'v';}
-  else if (code == '\b')  {*p++ = '\\'; *p++ = 'b';}
-  else if (code == '\f')  {*p++ = '\\'; *p++ = 'f';}
+    *cp++ = code;
+  else if (code == '\t')
+    {
+      *cp++ = '\\';
+      *cp++ = 't';
+    }
+  else if (code == '\n')
+    {
+      *cp++ = '\\';
+      *cp++ = 'n';
+    }
+  else if (code == '\r')
+    {
+      *cp++ = '\\';
+      *cp++ = 'r';
+    }
+  else if (code == '\v')
+    {
+      *cp++ = '\\';
+      *cp++ = 'v';
+    }
+  else if (code == '\b')
+    {
+      *cp++ = '\\';
+      *cp++ = 'b';
+    }
+  else if (code == '\f')
+    {
+      *cp++ = '\\';
+      *cp++ = 'f';
+    }
   else
     {
   else
     {
-      *p++ = '\\';
-      *p++ = code / 0100 + '0';
-      *p++ = ((code / 010) & 07) + '0';
-      *p++ = (code & 07) + '0';
+      *cp++ = '\\';
+      *cp++ = code / 0100 + '0';
+      *cp++ = ((code / 010) & 07) + '0';
+      *cp++ = (code & 07) + '0';
     }
     }
-  *pp = p;
+  *cp = '\0';
+
+  if (out)
+    obstack_sgrow (out, buf);
   *pcode = code;
   *pcode = code;
-  return  ! wasquote;
+  return !wasquote;
 }
 
 
 }
 
 
@@ -302,253 +319,247 @@ unlex (int token)
   unlexed_symval = symval;
 }
 
   unlexed_symval = symval;
 }
 
+/*-----------------------------------------------------------------.
+| We just read `<' from FIN.  Store in TOKEN_BUFFER, the type name |
+| specified between the `<...>'.                                   |
+`-----------------------------------------------------------------*/
 
 
-int
+void
+read_type_name (FILE *fin)
+{
+  int c = getc (fin);
+
+  while (c != '>')
+    {
+      if (c == EOF)
+       fatal (_("unterminated type name at end of file"));
+      if (c == '\n')
+       {
+         complain (_("unterminated type name"));
+         ungetc (c, fin);
+         break;
+       }
+
+      obstack_1grow (&token_obstack, c);
+      c = getc (fin);
+    }
+  obstack_1grow (&token_obstack, '\0');
+  token_buffer = obstack_finish (&token_obstack);
+}
+
+
+token_t
 lex (void)
 {
 lex (void)
 {
-  register int c;
-  char *p;
+  int c;
+
+  /* Just to make sure. */
+  token_buffer = NULL;
 
   if (unlexed >= 0)
     {
       symval = unlexed_symval;
       c = unlexed;
       unlexed = -1;
 
   if (unlexed >= 0)
     {
       symval = unlexed_symval;
       c = unlexed;
       unlexed = -1;
-      return (c);
+      return c;
     }
 
     }
 
-  c = skip_white_space();
-  *token_buffer = c;   /* for error messages (token buffer always valid) */
-  token_buffer[1] = 0;
+  c = skip_white_space ();
 
   switch (c)
     {
     case EOF:
 
   switch (c)
     {
     case EOF:
-      strcpy(token_buffer, "EOF");
-      return (ENDFILE);
-
-    case 'A':  case 'B':  case 'C':  case 'D':  case 'E':
-    case 'F':  case 'G':  case 'H':  case 'I':  case 'J':
-    case 'K':  case 'L':  case 'M':  case 'N':  case 'O':
-    case 'P':  case 'Q':  case 'R':  case 'S':  case 'T':
-    case 'U':  case 'V':  case 'W':  case 'X':  case 'Y':
+      token_buffer = "EOF";
+      return tok_eof;
+
+    case 'A':    case 'B':    case 'C':    case 'D':    case 'E':
+    case 'F':    case 'G':    case 'H':    case 'I':    case 'J':
+    case 'K':    case 'L':    case 'M':    case 'N':    case 'O':
+    case 'P':    case 'Q':    case 'R':    case 'S':    case 'T':
+    case 'U':    case 'V':    case 'W':    case 'X':    case 'Y':
     case 'Z':
     case 'Z':
-    case 'a':  case 'b':  case 'c':  case 'd':  case 'e':
-    case 'f':  case 'g':  case 'h':  case 'i':  case 'j':
-    case 'k':  case 'l':  case 'm':  case 'n':  case 'o':
-    case 'p':  case 'q':  case 'r':  case 's':  case 't':
-    case 'u':  case 'v':  case 'w':  case 'x':  case 'y':
+    case 'a':    case 'b':    case 'c':    case 'd':    case 'e':
+    case 'f':    case 'g':    case 'h':    case 'i':    case 'j':
+    case 'k':    case 'l':    case 'm':    case 'n':    case 'o':
+    case 'p':    case 'q':    case 'r':    case 's':    case 't':
+    case 'u':    case 'v':    case 'w':    case 'x':    case 'y':
     case 'z':
     case 'z':
-    case '.':  case '_':
-      p = token_buffer;
-      while (isalnum(c) || c == '_' || c == '.')
-       {
-         if (p == token_buffer + maxtoken)
-           p = grow_token_buffer(p);
+    case '.':    case '_':
 
 
-         *p++ = c;
-         c = getc(finput);
+      while (isalnum (c) || c == '_' || c == '.')
+       {
+         obstack_1grow (&token_obstack, c);
+         c = getc (finput);
        }
        }
-
-      *p = 0;
-      ungetc(c, finput);
-      symval = getsym(token_buffer);
-      return (IDENTIFIER);
-
-    case '0':  case '1':  case '2':  case '3':  case '4':
-    case '5':  case '6':  case '7':  case '8':  case '9':
+      obstack_1grow (&token_obstack, '\0');
+      token_buffer = obstack_finish (&token_obstack);
+      ungetc (c, finput);
+      symval = getsym (token_buffer);
+      return tok_identifier;
+
+    case '0':    case '1':    case '2':    case '3':    case '4':
+    case '5':    case '6':    case '7':    case '8':    case '9':
       {
        numval = 0;
 
       {
        numval = 0;
 
-       p = token_buffer;
-       while (isdigit(c))
+       while (isdigit (c))
          {
          {
-           if (p == token_buffer + maxtoken)
-             p = grow_token_buffer(p);
-
-           *p++ = c;
-           numval = numval*10 + c - '0';
-           c = getc(finput);
+           obstack_1grow (&token_obstack, c);
+           numval = numval * 10 + c - '0';
+           c = getc (finput);
          }
          }
-       *p = 0;
-       ungetc(c, finput);
-       return (NUMBER);
+       obstack_1grow (&token_obstack, '\0');
+       token_buffer = obstack_finish (&token_obstack);
+       ungetc (c, finput);
+       return tok_number;
       }
 
     case '\'':
       }
 
     case '\'':
-
       /* parse the literal token and compute character code in  code  */
 
       translations = -1;
       {
        int code, discode;
       /* parse the literal token and compute character code in  code  */
 
       translations = -1;
       {
        int code, discode;
-       char discard[10], *dp;
 
 
-       p = token_buffer;
-       *p++ = '\'';
-       literalchar(&p, &code, '\'');
+       obstack_1grow (&token_obstack, '\'');
+       literalchar (&token_obstack, &code, '\'');
 
 
-       c = getc(finput);
+       c = getc (finput);
        if (c != '\'')
          {
            complain (_("use \"...\" for multi-character literal tokens"));
            while (1)
        if (c != '\'')
          {
            complain (_("use \"...\" for multi-character literal tokens"));
            while (1)
-             {
-               dp = discard;
-               if (! literalchar(&dp, &discode, '\''))
-                 break;
-             }
+             if (!literalchar (0, &discode, '\''))
+               break;
          }
          }
-       *p++ = '\'';
-       *p = 0;
-       symval = getsym(token_buffer);
-       symval->class = STOKEN;
-       if (! symval->user_token_number)
+       obstack_1grow (&token_obstack, '\'');
+       obstack_1grow (&token_obstack, '\0');
+       token_buffer = obstack_finish (&token_obstack);
+       symval = getsym (token_buffer);
+       symval->class = token_sym;
+       if (!symval->user_token_number)
          symval->user_token_number = code;
          symval->user_token_number = code;
-       return (IDENTIFIER);
+       return tok_identifier;
       }
 
     case '\"':
       }
 
     case '\"':
-
       /* parse the literal string token and treat as an identifier */
 
       translations = -1;
       {
       /* parse the literal string token and treat as an identifier */
 
       translations = -1;
       {
-       int code;       /* ignored here */
-       p = token_buffer;
-       *p++ = '\"';
-       while (literalchar(&p, &code, '\"'))  /* read up to and including " */
-         {
-           if (p >= token_buffer + maxtoken - 4)
-             p = grow_token_buffer(p);
-         }
-       *p = 0;
+       int code;               /* ignored here */
 
 
-       symval = getsym(token_buffer);
-       symval->class = STOKEN;
+       obstack_1grow (&token_obstack, '\"');
+       /* Read up to and including ".  */
+       while (literalchar (&token_obstack, &code, '\"'))
+         /* nothing */;
+       obstack_1grow (&token_obstack, '\0');
+       token_buffer = obstack_finish (&token_obstack);
 
 
-       return (IDENTIFIER);
+       symval = getsym (token_buffer);
+       symval->class = token_sym;
+
+       return tok_identifier;
       }
 
     case ',':
       }
 
     case ',':
-      return (COMMA);
+      return tok_comma;
 
     case ':':
 
     case ':':
-      return (COLON);
+      return tok_colon;
 
     case ';':
 
     case ';':
-      return (SEMICOLON);
+      return tok_semicolon;
 
     case '|':
 
     case '|':
-      return (BAR);
+      return tok_bar;
 
     case '{':
 
     case '{':
-      return (LEFT_CURLY);
+      return tok_left_curly;
 
     case '=':
       do
        {
 
     case '=':
       do
        {
-         c = getc(finput);
-         if (c == '\n') lineno++;
+         c = getc (finput);
+         if (c == '\n')
+           lineno++;
        }
        }
-      while(c==' ' || c=='\n' || c=='\t');
+      while (c == ' ' || c == '\n' || c == '\t');
 
       if (c == '{')
        {
 
       if (c == '{')
        {
-         strcpy(token_buffer, "={");
-         return(LEFT_CURLY);
+         token_buffer = "={";
+         return tok_left_curly;
        }
       else
        {
        }
       else
        {
-         ungetc(c, finput);
-         return(ILLEGAL);
+         ungetc (c, finput);
+         return tok_illegal;
        }
 
     case '<':
        }
 
     case '<':
-      p = token_buffer;
-      c = getc(finput);
-      while (c != '>')
-       {
-         if (c == EOF)
-           fatal (_("unterminated type name at end of file"));
-         if (c == '\n')
-           {
-             complain (_("unterminated type name"));
-             ungetc(c, finput);
-             break;
-           }
-
-         if (p == token_buffer + maxtoken)
-           p = grow_token_buffer(p);
-
-         *p++ = c;
-         c = getc(finput);
-       }
-      *p = 0;
-      return (TYPENAME);
-
+      read_type_name (finput);
+      return tok_typename;
 
     case '%':
 
     case '%':
-      return (parse_percent_token());
+      return parse_percent_token ();
 
     default:
 
     default:
-      return (ILLEGAL);
+      return tok_illegal;
     }
 }
 
     }
 }
 
-/* the following table dictates the action taken for the various
-       % directives.  A setflag value causes the named flag to be
-       set.  A retval action returns the code.
-*/
-struct percent_table_struct {
-       char *name;
-       void *setflag;
-       int retval;
-} percent_table[] =
+/* the following table dictates the action taken for the various %
+   directives.  A set_flag value causes the named flag to be set.  A
+   retval action returns the code.  */
+struct percent_table_struct
 {
 {
-  {"token", NULL, TOKEN},
-  {"term", NULL, TOKEN},
-  {"nterm", NULL, NTERM},
-  {"type", NULL, TYPE},
-  {"guard", NULL, GUARD},
-  {"union", NULL, UNION},
-  {"expect", NULL, EXPECT},
-  {"thong", NULL, THONG},
-  {"start", NULL, START},
-  {"left", NULL, LEFT},
-  {"right", NULL, RIGHT},
-  {"nonassoc", NULL, NONASSOC},
-  {"binary", NULL, NONASSOC},
-  {"semantic_parser", NULL, SEMANTIC_PARSER},
-  {"pure_parser", NULL, PURE_PARSER},
-  {"prec", NULL, PREC},
-
-  {"no_lines", &nolinesflag, NOOP}, /* -l */
-  {"raw", &rawtoknumflag, NOOP}, /* -r */
-  {"token_table", &toknumflag, NOOP}, /* -k */
+  const char *name;
+  void *set_flag;
+  int retval;
+};
 
 
+struct percent_table_struct percent_table[] =
+{
+  { "token",           NULL,                   tok_token },
+  { "term",            NULL,                   tok_token },
+  { "nterm",           NULL,                   tok_nterm },
+  { "type",            NULL,                   tok_type },
+  { "guard",           NULL,                   tok_guard },
+  { "union",           NULL,                   tok_union },
+  { "expect",          NULL,                   tok_expect },
+  { "thong",           NULL,                   tok_thong },
+  { "start",           NULL,                   tok_start },
+  { "left",            NULL,                   tok_left },
+  { "right",           NULL,                   tok_right },
+  { "nonassoc",                NULL,                   tok_nonassoc },
+  { "binary",          NULL,                   tok_nonassoc },
+  { "prec",            NULL,                   tok_prec },
+  { "locations",       &locations_flag,        tok_noop },     /* -l */
+  { "no_lines",                &no_lines_flag,         tok_noop },     /* -l */
+  { "raw",             NULL,                   tok_obsolete }, /* -r */
+  { "token_table",     &token_table_flag,      tok_noop },     /* -k */
+  { "yacc",            &yacc_flag,             tok_noop },     /* -y */
+  { "fixed_output_files",&yacc_flag,           tok_noop },     /* -y */
+  { "defines",         &defines_flag,          tok_noop },     /* -d */
+  { "no_parser",       &no_parser_flag,        tok_noop },     /* -n */
 #if 0
 #if 0
-  /* These can be utilized after main is reoganized so
-     open_files() is deferred 'til after read_declarations().
-     But %{ and %union both put information into files
-     that have to be opened before read_declarations().
-     */
-  {"yacc", &fixed_outfiles, NOOP}, /* -y */
-  {"fixed_output_files", &fixed_outfiles, NOOP}, /* -y */
-  {"defines", &definesflag, NOOP}, /* -d */
-  {"no_parser", &noparserflag, NOOP}, /* -n */
-  {"output_file", &spec_outfile, SETOPT}, /* -o */
-  {"file_prefix", &spec_file_prefix, SETOPT}, /* -b */
-  {"name_prefix", &spec_name_prefix, SETOPT}, /* -p */
-
-  /* These would be acceptable, but they do not affect processing */
-  {"verbose", &verboseflag, NOOP}, /* -v */
-  {"debug", &debugflag, NOOP}, /* -t */
-  /*   {"help", <print usage stmt>, NOOP},*/   /* -h */
-  /*   {"version", <print version number> ,  NOOP},*/  /* -V */
+  /* For the time being, this is not enabled yet, while it's possible
+     though, since we use obstacks.  The only risk is with semantic
+     parsers which will output an `include' of an output file: be sure
+     that the naem included is indeed the name of the output file.  */
+  { "output_file",     &spec_outfile,          tok_setopt },   /* -o */
+  { "file_prefix",     &spec_file_prefix,      tok_setopt },   /* -b */
+  { "name_prefix",     &spec_name_prefix,      tok_setopt },   /* -p */
 #endif
 #endif
-
-  {NULL, NULL, ILLEGAL}
+  { "header_extension",        NULL,                   tok_hdrext},
+  { "source_extension",        NULL,                   tok_srcext},
+  { "verbose",         &verbose_flag,          tok_noop },     /* -v */
+  { "debug",           &debug_flag,            tok_noop },     /* -t */
+  { "semantic_parser", &semantic_parser,       tok_noop },
+  { "pure_parser",     &pure_parser,           tok_noop },
+
+  { NULL, NULL, tok_illegal}
 };
 
 /* Parse a token which starts with %.
 };
 
 /* Parse a token which starts with %.
@@ -557,71 +568,73 @@ struct percent_table_struct {
 int
 parse_percent_token (void)
 {
 int
 parse_percent_token (void)
 {
-  register int c;
-  register char *p;
-  register struct percent_table_struct *tx;
+  int c;
+  struct percent_table_struct *tx;
 
 
-  p = token_buffer;
-  c = getc(finput);
-  *p++ = '%';
-  *p++ = c;    /* for error msg */
-  *p = 0;
+  c = getc (finput);
 
   switch (c)
     {
     case '%':
 
   switch (c)
     {
     case '%':
-      return (TWO_PERCENTS);
+      return tok_two_percents;
 
     case '{':
 
     case '{':
-      return (PERCENT_LEFT_CURLY);
+      return tok_percent_left_curly;
 
     case '<':
 
     case '<':
-      return (LEFT);
+      return tok_left;
 
     case '>':
 
     case '>':
-      return (RIGHT);
+      return tok_right;
 
     case '2':
 
     case '2':
-      return (NONASSOC);
+      return tok_nonassoc;
 
     case '0':
 
     case '0':
-      return (TOKEN);
+      return tok_token;
 
     case '=':
 
     case '=':
-      return (PREC);
+      return tok_prec;
     }
     }
-  if (!isalpha(c))
-    return (ILLEGAL);
 
 
-  p = token_buffer;
-  *p++ = '%';
-  while (isalpha(c) || c == '_' || c == '-')
-    {
-      if (p == token_buffer + maxtoken)
-       p = grow_token_buffer(p);
+  if (!isalpha (c))
+    return tok_illegal;
 
 
-      if (c == '-') c = '_';
-      *p++ = c;
-      c = getc(finput);
+  obstack_1grow (&token_obstack, '%');
+  while (isalpha (c) || c == '_' || c == '-')
+    {
+      if (c == '-')
+       c = '_';
+      obstack_1grow (&token_obstack, c);
+      c = getc (finput);
     }
 
     }
 
-  ungetc(c, finput);
-
-  *p = 0;
+  ungetc (c, finput);
+  obstack_1grow (&token_obstack, '\0');
+  token_buffer = obstack_finish (&token_obstack);
 
   /* table lookup % directive */
   for (tx = percent_table; tx->name; tx++)
 
   /* table lookup % directive */
   for (tx = percent_table; tx->name; tx++)
-    if (strcmp(token_buffer+1, tx->name) == 0)
+    if (strcmp (token_buffer + 1, tx->name) == 0)
       break;
       break;
-  if (tx->retval == SETOPT)
+
+  if (tx->set_flag)
     {
     {
-      *((char **)(tx->setflag)) = optarg;
-      return NOOP;
+      *((int *) (tx->set_flag)) = 1;
+      return tok_noop;
     }
     }
-  if (tx->setflag)
+
+  switch (tx->retval)
     {
     {
-      *((int *)(tx->setflag)) = 1;
-      return NOOP;
+    case tok_setopt:
+      *((char **) (tx->set_flag)) = optarg;
+      return tok_noop;
+      break;
+
+    case tok_obsolete:
+      fatal (_("`%s' is no longer supported"), token_buffer);
+      break;
     }
     }
+
   return tx->retval;
 }
   return tx->retval;
 }