]> git.saurik.com Git - bison.git/blobdiff - src/files.c
* src/lalr.c (transpose): Free the memory allocated to the
[bison.git] / src / files.c
index b2f84a2ab94c4875e0772e5f7c2118da6881cd85..d86415216c41cedb7741c973f12addd8dbaf5987 100644 (file)
@@ -1,5 +1,5 @@
 /* Open and close files for bison,
 /* Open and close files for bison,
-   Copyright 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.
 
 #include "system.h"
 #include "getargs.h"
 #include "files.h"
 #include "system.h"
 #include "getargs.h"
 #include "files.h"
-#include "xalloc.h"
 #include "gram.h"
 #include "gram.h"
+#include "error.h"
 #include "complain.h"
 
 FILE *finput = NULL;
 #include "complain.h"
 
 FILE *finput = NULL;
-FILE *foutput = NULL;
 
 struct obstack action_obstack;
 struct obstack attrs_obstack;
 struct obstack table_obstack;
 struct obstack defines_obstack;
 struct obstack guard_obstack;
 
 struct obstack action_obstack;
 struct obstack attrs_obstack;
 struct obstack table_obstack;
 struct obstack defines_obstack;
 struct obstack guard_obstack;
+struct obstack output_obstack;
 
 
-char *spec_outfile;    /* for -o. */
-char *spec_file_prefix; /* for -b. */
-char *spec_name_prefix; /* for -p. */
+char *spec_outfile = NULL;     /* for -o. */
+char *spec_file_prefix = NULL; /* for -b. */
+char *spec_name_prefix = NULL; /* for -p. */
+char *spec_verbose_file = NULL;   /* for --verbose. */
+char *spec_graph_file = NULL;   /* for -g. */
+char *spec_defines_file = NULL; /* for --defines. */
 
 
-char *infile;
-char *attrsfile;
+char *infile = NULL;
+char *attrsfile = NULL;
 
 
-static char *base_name;
-static char *short_base_name;
+static char *base_name = NULL;
+static char *short_base_name = NULL;
 
 
+/* C source file extension (the parser source).  */
+const char *src_extension = NULL;
+/* Header file extension (if option ``-d'' is specified).  */
+const char *header_extension = NULL;
 \f
 \f
+
 /*--------------------------.
 | Is SUFFIX ending STRING?  |
 `--------------------------*/
 /*--------------------------.
 | Is SUFFIX ending STRING?  |
 `--------------------------*/
@@ -78,6 +86,49 @@ stringappend (const char *string1, const char *string2)
   return res;
 }
 
   return res;
 }
 
+
+/*-----------------------------------------------------------------.
+| Computes the macro name used to avoid double inclusion in the    |
+| header of the parser and store it in header_macro_name.  Be sure |
+| to produce valid CPP names (don't start with digit, remain       |
+| alphanumerical + underscore).                                    |
+`-----------------------------------------------------------------*/
+
+static char *
+compute_header_macro (void)
+{
+  const char *prefix = "BISON_";
+  char *macro_name, *cp;
+
+  if (spec_defines_file)
+    {
+      macro_name = XMALLOC (char,
+                           strlen (prefix) +
+                           strlen (spec_defines_file) + 1);
+      cp = stpcpy (macro_name, prefix);
+      cp = stpcpy (cp, spec_defines_file);
+    }
+  else
+    {
+      macro_name = XMALLOC (char,
+                           strlen (prefix) +
+                           strlen (base_name) +
+                           strlen (header_extension) + 1);
+      cp = stpcpy (macro_name, prefix);
+      cp = stpcpy (cp, base_name);
+      cp = stpcpy (cp, header_extension);
+    }
+
+  for (cp = macro_name; *cp; ++cp)
+    if (islower (*cp))
+      *cp = toupper (*cp);
+    else if (!isalnum (*cp))
+      *cp = '_';
+
+  return macro_name;
+}
+
+
 /*-----------------------------------------------------------------.
 | Try to open file NAME with mode MODE, and print an error message |
 | if fails.                                                        |
 /*-----------------------------------------------------------------.
 | Try to open file NAME with mode MODE, and print an error message |
 | if fails.                                                        |
@@ -127,38 +178,144 @@ obstack_save (struct obstack *obs, const char *filename)
   xfclose (out);
 }
 
   xfclose (out);
 }
 
+/*---------------------------------------------------------------------.
+| Output double inclusion protection macros and saves defines_obstack  |
+`---------------------------------------------------------------------*/
+
+static void
+defines_obstack_save (const char *filename)
+{
+  FILE *out = xfopen (filename, "w");
+  size_t size = obstack_object_size (&defines_obstack);
+  char *macro_name = compute_header_macro ();
+
+  fprintf (out, "#ifndef %s\n", macro_name);
+  fprintf (out, "# define %s\n\n", macro_name);
+  fwrite (obstack_finish (&defines_obstack), 1, size, out);
+  fprintf (out, "\n#endif /* not %s */\n", macro_name);
+
+  free (macro_name);
+  xfclose (out);
+}
 
 /*------------------------------------------------------------------.
 | Return the path to the skeleton which locaction might be given in |
 
 /*------------------------------------------------------------------.
 | Return the path to the skeleton which locaction might be given in |
-| ENVVAR, otherwise return SKELETON.                                |
+| ENVVAR, otherwise return SKELETON_NAME.                           |
 `------------------------------------------------------------------*/
 
 const char *
 `------------------------------------------------------------------*/
 
 const char *
-skeleton_find (const char *envvar, const char *skeleton)
+skeleton_find (const char *envvar, const char *skeleton_name)
 {
   const char *res = getenv (envvar);
 
 {
   const char *res = getenv (envvar);
 
-#ifdef MSDOS
-  const char *cp;
-
-  /* File doesn't exist in current directory; try in INIT directory.  */
-  if (!res && (cp = getenv ("INIT")))
+#if defined (MSDOS) || defined (_WIN32)
+  if (!res)
     {
     {
-      res = XMALLOC (char, strlen (cp) + strlen (skeleton) + 2);
-      sprintf (res, "%s%c%s", cp, '/', skeleton);
+      /* Skeleton file name without path */
+      const char *skel_name = strrchr (skeleton_name, '/');
+      if (!skel_name)
+        skel_name = strrchr (skeleton_name, '\\');
+      if (!skel_name)
+        skel_name = skeleton_name;
+      else
+        ++skel_name;
+
+      /* File doesn't exist in current directory; try in INIT directory.  */
+      const char *cp = getenv ("INIT");
+      if (cp)
+       {
+         res = XMALLOC (char, strlen (cp) + strlen (skel_name) + 2);
+         sprintf (res, "%s%c%s", cp, '\\', skel_name);
+       }
+      else if (access (skel_name, 4) == 0) /* Look in current dir. */
+        res = skel_name;
+      else
+       {
+         /* Look in program locations dir. */
+         extern char *program_name;
+         cp = strrchr(program_name, '\\');
+         if (!cp)
+           return skeleton_name;
+         else
+           ++cp;
+         res = XMALLOC (char, cp - program_name + strlen (skel_name) + 1);
+         strncpy (res, program_name, cp - program_name);
+         strcpy (res + (cp - program_name), skel_name);
+       }
     }
     }
-#endif /* !MSDOS */
-
+#endif /* defined (MSDOS) || defined (_WIN32) */
   if (!res)
   if (!res)
-    res = skeleton;
+    res = skeleton_name;
 
   return res;
 }
 
   return res;
 }
-
 \f
 \f
-/*----------------------------------------.
-| Compute BASE_NAME and SHORT_BASE_NAME.  |
-`----------------------------------------*/
+
+/*----------------------------------------------------------------.
+| Compute BASE_NAME, SHORT_BASE_NAME and output files extensions. |
+`----------------------------------------------------------------*/
+
+/* Replace all characters FROM by TO in the string IN.
+   and returns a new allocated string.  */
+static char *
+tr (const char *in, char from, char to)
+{
+  char *temp;
+  char *out;
+
+  out = XMALLOC (char, strlen (in) + 1);
+
+  for (temp = out; *in; in++, out++)
+    if (*in == from)
+      *out = to;
+    else
+      *out = *in;
+  *out = 0;
+  return (temp);
+}
+
+/* Gets the extension index in FILENAME. Returns 0 if fails to
+   find an extension.  */
+static int
+get_extension_index (const char *filename)
+{
+  int len;
+
+  len = strlen (filename);
+
+  if (filename[len-- - 1] == '.')
+    return (0);
+
+  while ((len > 0) && (filename[len - 1] != '.'))
+    if (filename[len - 1] == '/')
+      return (0);
+    else
+      len--;
+
+  return (len - 1);
+}
+
+/* Computes extensions from the grammar file extension. */
+static void
+compute_exts_from_gf (const char *ext)
+{
+  src_extension = tr (ext, 'y', 'c');
+  src_extension = tr (src_extension, 'Y', 'C');
+  header_extension = tr (ext, 'y', 'h');
+  header_extension = tr (header_extension, 'Y', 'H');
+}
+
+/* Computes extensions from the given c source file extension. */
+static void
+compute_exts_from_src (const char *ext)
+{
+  /* We use this function when the user specifies `-o' or `--output',
+     so the extenions must be computed unconditionally from the file name
+     given by this option.  */
+  src_extension = xstrdup (ext);
+  header_extension = tr (ext, 'c', 'h');
+  header_extension = tr (header_extension, 'C', 'H');
+}
 
 /* FIXME: Should use xstrndup. */
 
 
 /* FIXME: Should use xstrndup. */
 
@@ -167,6 +324,7 @@ compute_base_names (void)
 {
   size_t base_length;
   size_t short_base_length;
 {
   size_t base_length;
   size_t short_base_length;
+  size_t ext_index;
 
   /* If --output=foo.c was specified (SPEC_OUTFILE == foo.c),
      BASE_NAME and SHORT_BASE_NAME are `foo'.
 
   /* If --output=foo.c was specified (SPEC_OUTFILE == foo.c),
      BASE_NAME and SHORT_BASE_NAME are `foo'.
@@ -183,13 +341,24 @@ compute_base_names (void)
 #endif /* MSDOS */
       /* BASE_LENGTH includes ".tab" but not ".c".  */
       base_length = strlen (spec_outfile);
 #endif /* MSDOS */
       /* BASE_LENGTH includes ".tab" but not ".c".  */
       base_length = strlen (spec_outfile);
-      if (strsuffix (spec_outfile, ".c"))
-       base_length -= 2;
+
+      ext_index = get_extension_index (spec_outfile);
+      /* If the initial segment of extension contains 'c' or a 'C', I assume
+         that it is a C or C++ source file.  */
+      if (ext_index)
+       ext_index =
+         (strspn (spec_outfile + ext_index + 1, "cC")) ? ext_index : 0;
+      if (ext_index)
+       {
+         base_length -= strlen (spec_outfile + ext_index);
+         compute_exts_from_src (spec_outfile + ext_index);
+       }
+
+      base_name = strndup (spec_outfile, base_length);
       /* SHORT_BASE_LENGTH includes neither ".tab" nor ".c".  */
       short_base_length = base_length;
       /* SHORT_BASE_LENGTH includes neither ".tab" nor ".c".  */
       short_base_length = base_length;
-      if (strsuffix (spec_outfile, ".tab") || strsuffix (spec_outfile, "_tab"))
+      if (strsuffix (base_name, ".tab") || strsuffix (base_name, "_tab"))
        short_base_length -= 4;
        short_base_length -= 4;
-      base_name = strndup (spec_outfile, base_length);
       short_base_name = strndup (spec_outfile, short_base_length);
 
       return;
       short_base_name = strndup (spec_outfile, short_base_length);
 
       return;
@@ -205,11 +374,19 @@ compute_base_names (void)
       strlwr (spec_file_prefix);
 #endif /* MSDOS */
       short_base_name = xstrdup (spec_file_prefix);
       strlwr (spec_file_prefix);
 #endif /* MSDOS */
       short_base_name = xstrdup (spec_file_prefix);
-
       base_name = XMALLOC (char,
                           strlen (short_base_name) + strlen (EXT_TAB) + 1);
       stpcpy (stpcpy (base_name, short_base_name), EXT_TAB);
 
       base_name = XMALLOC (char,
                           strlen (short_base_name) + strlen (EXT_TAB) + 1);
       stpcpy (stpcpy (base_name, short_base_name), EXT_TAB);
 
+      /* Computes the extensions from the garmmar file name.  */
+      ext_index = get_extension_index (infile);
+      /* If the initial segment of extension contains a 'y' or a 'Y', I assume
+         that it is a yacc or bison grammar file.  */
+      if (ext_index)
+       ext_index = (strspn (infile + ext_index + 1, "yY")) ? ext_index : 0;
+      if (ext_index)
+       compute_exts_from_gf (infile + ext_index);
+
       return;
     }
 
       return;
     }
 
@@ -224,8 +401,18 @@ compute_base_names (void)
     /* BASE_LENGTH gets length of BASE_NAME, sans ".y" suffix if any.  */
 
     base_length = strlen (name_base);
     /* BASE_LENGTH gets length of BASE_NAME, sans ".y" suffix if any.  */
 
     base_length = strlen (name_base);
-    if (strsuffix (name_base, ".y"))
-      base_length -= 2;
+
+    ext_index = get_extension_index (name_base);
+    /* If the initial segment of extension contains a 'y' or a 'Y', I assume
+       that it is a yacc or bison grammar file.  */
+    if (ext_index)
+      ext_index = (strspn (name_base + ext_index + 1, "yY")) ? ext_index : 0;
+    if (ext_index)
+      {
+       base_length -= strlen (name_base + ext_index);
+       compute_exts_from_gf (name_base + ext_index);
+      }
+
     short_base_length = base_length;
     short_base_name = strndup (name_base, short_base_length);
 
     short_base_length = base_length;
     short_base_name = strndup (name_base, short_base_length);
 
@@ -237,6 +424,38 @@ compute_base_names (void)
   }
 }
 
   }
 }
 
+/*-------------------------------------------------------.
+| Close the open files, compute the output files names.  |
+`-------------------------------------------------------*/
+
+void
+compute_output_file_names (void)
+{
+  compute_base_names ();
+
+  /* If not yet done. */
+  if (!src_extension)
+    src_extension = ".c";
+  if (!header_extension)
+    header_extension = ".h";
+
+  /* It the defines filename if not given, we create it.  */
+  if (!spec_defines_file)
+    spec_defines_file = stringappend (base_name, header_extension);
+
+  /* It the graph filename if not given, we create it.  */
+  if (!spec_graph_file)
+    spec_graph_file = stringappend (short_base_name, ".vcg");
+
+  spec_verbose_file = stringappend (short_base_name, EXT_OUTPUT);
+
+  attrsfile = stringappend (short_base_name, EXT_STYPE_H);
+#ifndef MSDOS
+  attrsfile = stringappend (attrsfile, header_extension);
+#endif /* MSDOS */
+
+}
+
 /*-----------------------------------------------------------------.
 | Open the input file.  Look for the skeletons.  Find the names of |
 | the output files.  Prepare the obstacks.                         |
 /*-----------------------------------------------------------------.
 | Open the input file.  Look for the skeletons.  Find the names of |
 | the output files.  Prepare the obstacks.                         |
@@ -245,57 +464,70 @@ compute_base_names (void)
 void
 open_files (void)
 {
 void
 open_files (void)
 {
-  compute_base_names ();
-
   finput = xfopen (infile, "r");
 
   finput = xfopen (infile, "r");
 
-  if (verbose_flag)
-    /* We used to use just .out if spec_name_prefix (-p) was used, but
-       that conflicts with Posix.  */
-    foutput = xfopen (stringappend (base_name, EXT_OUTPUT), "w");
-
-  attrsfile = stringappend (short_base_name, EXT_STYPE_H);
-
   /* Initialize the obstacks. */
   obstack_init (&action_obstack);
   obstack_init (&attrs_obstack);
   obstack_init (&table_obstack);
   obstack_init (&defines_obstack);
   obstack_init (&guard_obstack);
   /* Initialize the obstacks. */
   obstack_init (&action_obstack);
   obstack_init (&attrs_obstack);
   obstack_init (&table_obstack);
   obstack_init (&defines_obstack);
   obstack_init (&guard_obstack);
+  obstack_init (&output_obstack);
 }
 
 
 
 }
 
 
 
-/*-----------------------------------------------------.
-| Close the open files, produce all the output files.  |
-`-----------------------------------------------------*/
+/*-----------------------.
+| Close the open file..  |
+`-----------------------*/
 
 void
 
 void
-output_files (void)
+close_files (void)
 {
   xfclose (finput);
 {
   xfclose (finput);
-  xfclose (foutput);
+}
+
+/*---------------------------.
+| Produce the output files.  |
+`---------------------------*/
 
 
+void
+output_files (void)
+{
   /* Output the main file.  */
   if (spec_outfile)
     obstack_save (&table_obstack, spec_outfile);
   else
   /* Output the main file.  */
   if (spec_outfile)
     obstack_save (&table_obstack, spec_outfile);
   else
-    obstack_save (&table_obstack,  stringappend (base_name, ".c"));
+    obstack_save (&table_obstack, stringappend (base_name, src_extension));
+  obstack_free (&table_obstack, NULL);
 
   /* Output the header file if wanted. */
   if (defines_flag)
 
   /* Output the header file if wanted. */
   if (defines_flag)
-    obstack_save (&defines_obstack, stringappend (base_name, ".h"));
+    defines_obstack_save (spec_defines_file);
+  obstack_free (&defines_obstack, NULL);
+
+#if 0
+  /* Seems to be invalid now --akim. */
 
   /* If we output only the table, dump the actions in ACTFILE. */
   if (no_parser_flag)
     obstack_save (&action_obstack, stringappend (short_base_name, ".act"));
 
   /* If we output only the table, dump the actions in ACTFILE. */
   if (no_parser_flag)
     obstack_save (&action_obstack, stringappend (short_base_name, ".act"));
+  obstack_free (&action_obstack, NULL);
+#endif
 
   /* If we produced a semantic parser ATTRS_OBSTACK must be dumped
      into its own file, ATTTRSFILE.  */
   if (semantic_parser)
     {
 
   /* If we produced a semantic parser ATTRS_OBSTACK must be dumped
      into its own file, ATTTRSFILE.  */
   if (semantic_parser)
     {
+      char *temp_name;
+
       obstack_save (&attrs_obstack, attrsfile);
       obstack_save (&attrs_obstack, attrsfile);
-      obstack_save (&guard_obstack,
-                   stringappend (short_base_name, EXT_GUARD_C));
+      obstack_free (&attrs_obstack, NULL);
+      temp_name = stringappend (short_base_name, EXT_GUARD_C);
+#ifndef MSDOS
+      temp_name = stringappend (temp_name, src_extension);
+#endif /* MSDOS */
+      obstack_save (&guard_obstack, temp_name);
+      obstack_free (&guard_obstack, NULL);
     }
 }
     }
 }