Recently "braceless" in the parser was changed so that an eol was no
longer added to the value. This is not correct when a %code is used
multiple times, because the syncline of the next snippet might be
appended to the last (and not ended) line of the previous snippet.
* src/muscle-tab.h (muscle_grow): Make it private.
* src/muscle-tab.c (muscle_grow): Accept a fourth argument: a required
terminator.
Adjust callers.
* tests/input.at (Multiple %code): New.
-/*-------------------------------------------------------------------.
-| Append VALUE to the current value of KEY. If KEY did not already |
-| exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously |
-| associated value. Copy VALUE and SEPARATOR. |
-`-------------------------------------------------------------------*/
+/* Append VALUE to the current value of KEY. If KEY did not already
+ exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously
+ associated value. Copy VALUE and SEPARATOR. If VALUE does not end
+ with TERMINATOR, append one. */
-void
-muscle_grow (const char *key, const char *val, const char *separator)
+static void
+muscle_grow (const char *key, const char *val,
+ const char *separator, const char *terminator)
{
muscle_entry *entry = muscle_lookup (key);
{
muscle_entry *entry = muscle_lookup (key);
+ size_t vals = strlen (val);
+ size_t terms = strlen (terminator);
- /* Grow the current value. */
- char *new_val;
- obstack_printf (&muscle_obstack, "%s%s%s", entry->value, separator, val);
+ obstack_sgrow (&muscle_obstack, entry->value);
+ obstack_sgrow (&muscle_obstack, separator);
- new_val = obstack_finish0 (&muscle_obstack);
- entry->value = entry->storage = xstrdup (new_val);
- obstack_free (&muscle_obstack, new_val);
- {
- /* First insertion in the hash. */
- entry = muscle_entry_new (key);
- entry->value = entry->storage = xstrdup (val);
- }
+ entry = muscle_entry_new (key);
+
+ obstack_sgrow (&muscle_obstack, val);
+
+ if (terms <= vals
+ && STRNEQ (val + vals - terms, terminator))
+ obstack_sgrow (&muscle_obstack, terminator);
+
+ {
+ char *new_val = obstack_finish0 (&muscle_obstack);
+ entry->value = entry->storage = xstrdup (new_val);
+ obstack_free (&muscle_obstack, new_val);
+ }
}
/*------------------------------------------------------------------.
}
/*------------------------------------------------------------------.
quotearg_style (c_quoting_style, loc.start.file));
obstack_sgrow (&muscle_obstack, ")[");
extension = obstack_finish0 (&muscle_obstack);
quotearg_style (c_quoting_style, loc.start.file));
obstack_sgrow (&muscle_obstack, ")[");
extension = obstack_finish0 (&muscle_obstack);
- muscle_grow (key, extension, "");
+ muscle_grow (key, extension, "", "");
obstack_free (&muscle_obstack, extension);
}
obstack_free (&muscle_obstack, extension);
}
muscle_code_grow (const char *key, const char *val, location loc)
{
muscle_syncline_grow (key, loc);
muscle_code_grow (const char *key, const char *val, location loc)
{
muscle_syncline_grow (key, loc);
- muscle_grow (key, val, "\n");
+ muscle_grow (key, val, "\n", "\n");
obstack_quote (&muscle_obstack, a2);
obstack_sgrow (&muscle_obstack, "]");
pair = obstack_finish0 (&muscle_obstack);
obstack_quote (&muscle_obstack, a2);
obstack_sgrow (&muscle_obstack, "]");
pair = obstack_finish0 (&muscle_obstack);
- muscle_grow (muscle, pair, ",\n");
+ muscle_grow (muscle, pair, ",\n", "");
obstack_free (&muscle_obstack, pair);
}
obstack_free (&muscle_obstack, pair);
}
obstack_escape (&muscle_obstack, bound.file);
obstack_printf (&muscle_obstack, ":%d.%d]]", bound.line, bound.column);
extension = obstack_finish0 (&muscle_obstack);
obstack_escape (&muscle_obstack, bound.file);
obstack_printf (&muscle_obstack, ":%d.%d]]", bound.line, bound.column);
extension = obstack_finish0 (&muscle_obstack);
- muscle_grow (key, extension, "");
+ muscle_grow (key, extension, "", "");
obstack_free (&muscle_obstack, extension);
}
obstack_free (&muscle_obstack, extension);
}
muscle_location_grow (char const *key, location loc)
{
muscle_boundary_grow (key, loc.start);
muscle_location_grow (char const *key, location loc)
{
muscle_boundary_grow (key, loc.start);
- muscle_grow (key, "", ", ");
+ muscle_grow (key, "", ", ", "");
muscle_boundary_grow (key, loc.end);
}
muscle_boundary_grow (key, loc.end);
}
muscle_user_name_list_grow (char const *key, char const *user_name,
location loc)
{
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_grow (key, "[[[[", ",", "");
+ muscle_grow (key, user_name, "", "");
+ muscle_grow (key, "]], ", "", "");
muscle_location_grow (key, loc);
muscle_location_grow (key, loc);
- muscle_grow (key, "]]", "");
+ muscle_grow (key, "]]", "", "");
MUSCLE_INSERT_STRING(Key, quotearg_style (c_quoting_style, Value))
MUSCLE_INSERT_STRING(Key, quotearg_style (c_quoting_style, Value))
-/* Append VALUE to the current value of KEY. If KEY did not already
- exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously
- associated value. Copy VALUE and SEPARATOR. */
-void muscle_grow (const char *key, const char *value, const char *separator);
-
-
/* Append VALUE to the current value of KEY, using muscle_grow. But
/* Append VALUE to the current value of KEY, using muscle_grow. But
- in addition, issue a synchronization line for the location LOC. */
+ in addition, issue a synchronization line for the location LOC.
+ Be sure to append on a new line. */
void muscle_code_grow (const char *key, const char *value, location loc);
void muscle_code_grow (const char *key, const char *value, location loc);
+## ---------------- ##
+## Multiple %code. ##
+## ---------------- ##
+
+AT_SETUP([Multiple %code])
+
+# Make sure that repeated arguments to %code are separated by
+# end-of-lines. At some point, a missing eol would leave synclines
+# appended to the previous value. Here, we use CPP directive to
+# introduce dependency on the absence/presence of the eol.
+AT_BISON_OPTION_PUSHDEFS
+
+AT_DATA([input.y],
+[[%code {#include <assert.h>}
+%code {#define A B}
+%code {#define B C}
+%code {#define C D}
+%code {#define D 42}
+%code {
+ ]AT_YYERROR_DECLARE[
+ ]AT_YYLEX_DECLARE[
+}
+%%
+start: %empty;
+%%
+]AT_YYERROR_DEFINE[
+]AT_YYLEX_DEFINE[
+int main (void)
+{
+ assert (A == 42);
+ return 0;
+}
+]])
+AT_FULL_COMPILE([input])
+AT_PARSER_CHECK([./input])
+
+AT_BISON_OPTION_POPDEFS
+AT_CLEANUP()
+
## ---------------- ##
## %define errors. ##
## ---------------- ##
## ---------------- ##
## %define errors. ##
## ---------------- ##