]> git.saurik.com Git - bison.git/blobdiff - src/muscle_tab.c
Fix push parsing memory leak reported by Brandon Lucia at
[bison.git] / src / muscle_tab.c
index 5d02e5b7a7a1a7219615aa94a201f9b2d845ea15..732fc2758580413bc21f515ff086cd06987dd226 100644 (file)
@@ -1,6 +1,6 @@
 /* Muscle table manager for Bison.
 
 /* Muscle table manager for Bison.
 
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
    Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
    Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
@@ -26,6 +26,7 @@
 #include <hash.h>
 #include <quotearg.h>
 
 #include <hash.h>
 #include <quotearg.h>
 
+#include "complain.h"
 #include "files.h"
 #include "muscle_tab.h"
 #include "getargs.h"
 #include "files.h"
 #include "muscle_tab.h"
 #include "getargs.h"
@@ -191,18 +192,15 @@ muscle_code_grow (const char *key, const char *val, location loc)
 }
 
 
 }
 
 
-/*-------------------------------------------------------------------.
-| MUSCLE is an M4 list of pairs.  Create or extend it with the pair  |
-| (A1, A2).  Note that because the muscle values are output *double* |
-| quoted, one needs to strip the first level of quotes to reach the  |
-| list itself.                                                       |
-`-------------------------------------------------------------------*/
-
 void muscle_pair_list_grow (const char *muscle,
                            const char *a1, const char *a2)
 {
   char *pair;
 void muscle_pair_list_grow (const char *muscle,
                            const char *a1, const char *a2)
 {
   char *pair;
-  obstack_fgrow2 (&muscle_obstack, "[[[%s]], [[%s]]]", a1, a2);
+  obstack_sgrow (&muscle_obstack, "[[[");
+  MUSCLE_OBSTACK_SGROW (&muscle_obstack, a1);
+  obstack_sgrow (&muscle_obstack, "]], [[");
+  MUSCLE_OBSTACK_SGROW (&muscle_obstack, a2);
+  obstack_sgrow (&muscle_obstack, "]]]");
   obstack_1grow (&muscle_obstack, 0);
   pair = obstack_finish (&muscle_obstack);
   muscle_grow (muscle, pair, ",\n");
   obstack_1grow (&muscle_obstack, 0);
   pair = obstack_finish (&muscle_obstack);
   muscle_grow (muscle, pair, ",\n");
@@ -252,6 +250,313 @@ muscle_find (char const *key)
 }
 
 
 }
 
 
+void
+muscle_boundary_grow (char const *key, boundary bound)
+{
+  char *extension;
+  MUSCLE_OBSTACK_SGROW (&muscle_obstack, bound.file);
+  obstack_1grow (&muscle_obstack, ':');
+  obstack_fgrow1 (&muscle_obstack, "%d", bound.line);
+  obstack_1grow (&muscle_obstack, '.');
+  obstack_fgrow1 (&muscle_obstack, "%d", bound.column);
+  obstack_1grow (&muscle_obstack, '\0');
+  extension = obstack_finish (&muscle_obstack);
+  muscle_grow (key, extension, "");
+  obstack_free (&muscle_obstack, extension);
+}
+
+void
+muscle_location_grow (char const *key, location loc)
+{
+  muscle_grow (key, "[[", "");
+  muscle_boundary_grow (key, loc.start);
+  muscle_grow (key, "]], [[", "");
+  muscle_boundary_grow (key, loc.end);
+  muscle_grow (key, "]]", "");
+}
+
+#define MUSCLE_COMMON_DECODE(Value)                                           \
+  case '$':                                                                   \
+    aver (*++(Value) == ']');                                                 \
+    aver (*++(Value) == '[');                                                 \
+    obstack_sgrow (&muscle_obstack, "$");                                     \
+    break;                                                                    \
+  case '@':                                                                   \
+    switch (*++(Value))                                                       \
+      {                                                                       \
+        case '@': obstack_sgrow (&muscle_obstack, "@" ); break;               \
+        case '{': obstack_sgrow (&muscle_obstack, "[" ); break;               \
+        case '}': obstack_sgrow (&muscle_obstack, "]" ); break;               \
+        default: aver (false); break;                                         \
+      }                                                                       \
+    break;                                                                    \
+  default:                                                                    \
+    obstack_1grow (&muscle_obstack, *(Value));                                \
+    break;
+
+/* Reverse of MUSCLE_OBSTACK_SGROW.  */
+static char *
+muscle_string_decode (char const *key)
+{
+  char const *value;
+  char *value_decoded;
+  char *result;
+
+  value = muscle_find_const (key);
+  if (!value)
+    return NULL;
+  do {
+    switch (*value)
+      {
+        MUSCLE_COMMON_DECODE (value)
+        case '[':
+        case ']':
+          aver (false);
+          break;
+      }
+  } while (*value++);
+  value_decoded = obstack_finish (&muscle_obstack);
+  result = xstrdup (value_decoded);
+  obstack_free (&muscle_obstack, value_decoded);
+  return result;
+}
+
+/* Reverse of muscle_location_grow.  */
+static location
+muscle_location_decode (char const *key)
+{
+  location loc;
+  char const *value = muscle_find_const (key);
+  aver (value);
+  aver (*value == '[');
+  aver (*++value == '[');
+  while (*++value)
+    switch (*value)
+      {
+        MUSCLE_COMMON_DECODE (value)
+        case '[':
+          aver (false);
+          break;
+        case ']':
+          {
+            char *boundary_str;
+            aver (*++value == ']');
+            obstack_1grow (&muscle_obstack, '\0');
+            boundary_str = obstack_finish (&muscle_obstack);
+            switch (*++value)
+              {
+                case ',':
+                  boundary_set_from_string (&loc.start, boundary_str);
+                  obstack_free (&muscle_obstack, boundary_str);
+                  aver (*++value == ' ');
+                  aver (*++value == '[');
+                  aver (*++value == '[');
+                  break;
+                case '\0':
+                  boundary_set_from_string (&loc.end, boundary_str);
+                  obstack_free (&muscle_obstack, boundary_str);
+                  return loc;
+                  break;
+                default:
+                  aver (false);
+                  break;
+              }
+          }
+          break;
+      }
+  aver (false);
+  return loc;
+}
+
+void
+muscle_user_name_list_grow (char const *key, char const *user_name,
+                            location loc)
+{
+  muscle_grow (key, "[[[[", ",");
+  muscle_grow (key, user_name, "");
+  muscle_grow (key, "]], ", "");
+  muscle_location_grow (key, loc);
+  muscle_grow (key, "]]", "");
+}
+
+#define MUSCLE_USER_NAME_CONVERT(NAME, PREFIX, USER_NAME, SUFFIX)    \
+do {                                                                 \
+  char *tmp;                                                         \
+  size_t length = strlen ((USER_NAME));                              \
+  tmp = xmalloc (sizeof (PREFIX) - 1 + length + sizeof (SUFFIX));    \
+  strcpy (tmp, (PREFIX));                                            \
+  strcpy (tmp + sizeof (PREFIX) - 1, (USER_NAME));                   \
+  strcpy (tmp + sizeof (PREFIX) - 1 + length, (SUFFIX));             \
+  (NAME) = uniqstr_new (tmp);                                        \
+  free (tmp);                                                        \
+} while (0)
+
+void
+muscle_percent_define_insert (char const *variable, location variable_loc,
+                              char const *value)
+{
+  char const *name;
+  char const *loc_name;
+
+  MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
+  MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
+
+  if (muscle_find_const (name))
+    {
+      warn_at (variable_loc, _("%s `%s' redefined"),
+               "%define variable", variable);
+      warn_at (muscle_location_decode (loc_name), _("previous definition"));
+    }
+  MUSCLE_INSERT_STRING (name, value);
+
+  muscle_insert (loc_name, "");
+  muscle_location_grow (loc_name, variable_loc);
+  muscle_user_name_list_grow ("percent_define_user_variables", variable,
+                              variable_loc);
+}
+
+char *
+muscle_percent_define_get (char const *variable)
+{
+  char const *name;
+  char const *usage_name;
+  char *value;
+
+  MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
+  MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
+                            variable, ")");
+
+  muscle_insert (usage_name, "");
+  value = muscle_string_decode (name);
+  if (!value)
+    value = xstrdup ("");
+  return value;
+}
+
+bool
+muscle_percent_define_ifdef (char const *variable)
+{
+  char const *name;
+  char const *usage_name;
+  char const *value;
+
+  MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
+  MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
+                            variable, ")");
+
+  value = muscle_find_const (name);
+  if (value)
+    {
+      muscle_insert (usage_name, "");
+      return true;
+    }
+
+  return false;
+}
+
+bool
+muscle_percent_define_flag_if (char const *variable)
+{
+  char const *name;
+  char const *loc_name;
+  char const *usage_name;
+  bool result = false;
+
+  MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
+  MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
+  MUSCLE_USER_NAME_CONVERT (usage_name, "percent_define_bison_variables(",
+                            variable, ")");
+
+  if (muscle_percent_define_ifdef (variable))
+    {
+      char *value = muscle_percent_define_get (variable);
+      if (value[0] == '\0' || 0 == strcmp (value, "true"))
+        result = true;
+      else if (0 == strcmp (value, "false"))
+        result = false;
+      else if (!muscle_find_const (usage_name))
+        complain_at(muscle_location_decode (loc_name),
+                    _("invalid value for %%define boolean variable `%s'"),
+                    variable);
+      free (value);
+    }
+  else
+    fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_flag_if"),
+          variable);
+
+  return result;
+}
+
+void
+muscle_percent_define_default (char const *variable, char const *value)
+{
+  char const *name;
+  char const *loc_name;
+  MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
+  MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
+  if (!muscle_find_const (name))
+    {
+      location loc;
+      MUSCLE_INSERT_STRING (name, value);
+      loc.start.file = loc.end.file = "[Bison:muscle_percent_define_default]";
+      loc.start.line = loc.start.column = 0;
+      loc.end.line = loc.end.column = 0;
+      muscle_insert (loc_name, "");
+      muscle_location_grow (loc_name, loc);
+    }
+}
+
+void
+muscle_percent_define_check_values (char const * const *values)
+{
+  for (; *values; ++values)
+    {
+      char const *variable = *values;
+      char const *name;
+      char const *loc_name;
+      char *value;
+
+      MUSCLE_USER_NAME_CONVERT (name, "percent_define(", variable, ")");
+      MUSCLE_USER_NAME_CONVERT (loc_name, "percent_define_loc(", variable, ")");
+
+      value = muscle_string_decode (name);
+      if (value)
+        {
+          bool valid = false;
+          for (++values; *values; ++values)
+            {
+              if (0 == strcmp (value, *values))
+                {
+                  valid = true;
+                  while (*values)
+                    ++values;
+                  break;
+                }
+            }
+          if (!valid)
+            complain_at(muscle_location_decode (loc_name),
+                        _("invalid value for %%define variable `%s': `%s'"),
+                        variable, value);
+          free (value);
+        }
+      else
+        fatal(_("undefined %%define variable `%s' passed to muscle_percent_define_check_values"),
+              variable);
+    }
+}
+
+void
+muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
+                          char const *code, location code_loc)
+{
+  char const *name;
+  MUSCLE_USER_NAME_CONVERT (name, "percent_code(", qualifier, ")");
+  muscle_code_grow (name, code, code_loc);
+  muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
+                               qualifier_loc);
+}
+
+
 /*------------------------------------------------.
 | Output the definition of ENTRY as a m4_define.  |
 `------------------------------------------------*/
 /*------------------------------------------------.
 | Output the definition of ENTRY as a m4_define.  |
 `------------------------------------------------*/
@@ -281,31 +586,3 @@ muscles_m4_output (FILE *out)
 {
   hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
 }
 {
   hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
 }
-
-void
-muscle_boundary_grow (char const *key, boundary bound)
-{
-  char *extension;
-  MUSCLE_OBSTACK_SGROW (&muscle_obstack, bound.file);
-  obstack_1grow (&muscle_obstack, ':');
-  obstack_fgrow1 (&muscle_obstack, "%d", bound.line);
-  obstack_1grow (&muscle_obstack, '.');
-  obstack_fgrow1 (&muscle_obstack, "%d", bound.column);
-  obstack_1grow (&muscle_obstack, '\0');
-  extension = obstack_finish (&muscle_obstack);
-  muscle_grow (key, extension, "");
-  obstack_free (&muscle_obstack, extension);
-}
-
-void
-muscle_grow_user_name_list (char const *key, char const *user_name,
-                            location loc)
-{
-  muscle_grow (key, "[[[[", ",");
-  muscle_grow (key, user_name, "");
-  muscle_grow (key, "]], [[", "");
-  muscle_boundary_grow (key, loc.start);
-  muscle_grow (key, "]], [[", "");
-  muscle_boundary_grow (key, loc.end);
-  muscle_grow (key, "]]]]", "");
-}