MUSCLE_INSERT_BOOL ("token_table", token_table_flag);
MUSCLE_INSERT_INT ("tokens_number", ntokens);
MUSCLE_INSERT_INT ("nterms_number", nvars);
+ MUSCLE_INSERT_INT ("symbols_number", nsyms);
MUSCLE_INSERT_INT ("undef_token_number", undeftoken->number);
MUSCLE_INSERT_INT ("user_token_number_max", max_user_token_number);
}
+/*-------------------------------------------------------.
+| Compare two symbols by type-name, and then by number. |
+`-------------------------------------------------------*/
-/*-----------------------------------------------.
-| For each symbol type, its tags and type name. |
-`-----------------------------------------------*/
+int
+symbol_type_name_cmp (const symbol **lhs, const symbol **rhs)
+{
+ int res = UNIQSTR_CMP((*lhs)->type_name, (*rhs)->type_name);
+ if (res)
+ return res;
+ return (*lhs)->number - (*rhs)->number;
+}
+
+
+/*----------------------------------------------------------------.
+| Return a (malloc'ed) table of the symbols sorted by type-name. |
+`----------------------------------------------------------------*/
+
+static symbol **
+symbols_by_type_name ()
+{
+ typedef int (*qcmp_type) (const void *, const void *);
+ symbol **res = xmemdup (symbols, nsyms * sizeof *res);
+ qsort (res, nsyms, sizeof *res, (qcmp_type) &symbol_type_name_cmp);
+ return res;
+}
+
+
+/*------------------------------------------------------------------.
+| Define b4_type_names, which is a list of (lists of the numbers of |
+| symbols with same type-name). |
+`------------------------------------------------------------------*/
static void
type_names_output (FILE *out)
{
int i;
- char const *sep = "";
-
+ symbol **syms = symbols_by_type_name ();
fputs ("m4_define([b4_type_names],\n[", out);
- for (i = 0; i < nsyms; ++i)
+ for (i = 0; i < nsyms; /* nothing */)
{
- symbol *sym = symbols[i];
- /* Symbol-name, Symbol-number, optional typename. */
- fprintf (out, "%s[", i ? ",\n" : "");
- escaped_output (out, sym->tag);
- fprintf (out, ", %d, [[%s]]]",
- sym->number,
- sym->type_name ? sym->type_name : "");
+ // The index of the first symbol of the current type-name.
+ int i0 = i;
+ fputs (i ? ",\n[" : "[", out);
+ for (; i < nsyms && syms[i]->type_name == syms[i0]->type_name; ++i)
+ fprintf (out, "%s%d", i != i0 ? ", " : "", syms[i]->number);
+ fputs ("]", out);
}
fputs ("])\n\n", out);
+ free (syms);
+}
+
+
+/*-------------------------------------.
+| The list of all the symbol numbers. |
+`-------------------------------------*/
+
+static void
+symbol_numbers_output (FILE *out)
+{
+ int i;
+ fputs ("m4_define([b4_symbol_numbers],\n[", out);
+ for (i = 0; i < nsyms; ++i)
+ fprintf (out, "%s[%d]", i ? ", " : "", i);
+ fputs ("])\n\n", out);
}
fputs ("])\n\n", out);
}
-/*--------------------------------------.
-| Output the merge functions to OUT. |
-`--------------------------------------*/
+/*------------------------------------.
+| Output the merge functions to OUT. |
+`------------------------------------*/
static void
merger_output (FILE *out)
fputs ("]])\n\n", out);
}
+
+/*----------------------------------.
+| Whether S is a valid identifier. |
+`----------------------------------*/
+
+static bool
+is_identifier (uniqstr s)
+{
+ static char const alphanum[26 + 26 + 1 + 10] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "_"
+ "0123456789";
+ if (!s || ! memchr (alphanum, *s, sizeof alphanum - 10))
+ return false;
+ for (++s; *s; ++s)
+ if (! memchr (alphanum, *s, sizeof alphanum))
+ return false;
+ return true;
+}
+
+/*---------------------------------------.
+| Output the symbol definitions to OUT. |
+`---------------------------------------*/
+
+static void
+symbol_definitions_output (FILE *out)
+{
+ int i;
+ for (i = 0; i < nsyms; ++i)
+ {
+ symbol *sym = symbols[i];
+ const char *key;
+
+#define SET_KEY(Entry) \
+ obstack_fgrow2 (&format_obstack, "symbol(%d, %s)", i, Entry); \
+ obstack_1grow (&format_obstack, 0); \
+ key = obstack_finish (&format_obstack);
+
+ // Whether the tag is a valid identifier.
+ SET_KEY("tag_is_id");
+ MUSCLE_INSERT_INT (key, is_identifier(sym->tag));
+
+ // The inner tag.
+ SET_KEY("tag");
+ MUSCLE_INSERT_STRING (key, sym->tag);
+
+ SET_KEY("user_number");
+ MUSCLE_INSERT_INT (key, sym->user_token_number);
+
+ SET_KEY("is_token");
+ MUSCLE_INSERT_INT (key,
+ i < ntokens && sym != errtoken && sym != undeftoken);
+
+ SET_KEY("number");
+ MUSCLE_INSERT_INT (key, sym->number);
+
+ SET_KEY("has_type_name");
+ MUSCLE_INSERT_INT (key, !!sym->type_name);
+
+ SET_KEY("type_name");
+ MUSCLE_INSERT_STRING (key, sym->type_name ? sym->type_name : "");
+
+#undef SET_KEY
+ }
+}
+
+
/*--------------------------------------.
| Output the tokens definition to OUT. |
`--------------------------------------*/
muscle_insert_unsigned_int_table ("conflicting_rules", conflict_list,
0, 1, conflict_list_cnt);
}
+
+
+/*--------------------------------------------.
+| Output the definitions of all the muscles. |
+`--------------------------------------------*/
+
+static void
+muscles_output (FILE *out)
+{
+ fputs ("m4_init()\n", out);
+ merger_output (out);
+ symbol_code_props_output (out, "destructors", &symbol_destructor_get);
+ symbol_code_props_output (out, "printers", &symbol_printer_get);
+ symbol_definitions_output (out);
+ symbol_numbers_output (out);
+ token_definitions_output (out);
+ type_names_output (out);
+ user_actions_output (out);
+ // Must be last.
+ muscles_m4_output (out);
+}
\f
/*---------------------------.
| Call the skeleton parser. |
output_skeleton (void)
{
FILE *in;
- FILE *out;
int filter_fd[2];
char const *argv[9];
pid_t pid;
free (full_m4bison);
free (full_skeleton);
- out = fdopen (filter_fd[0], "w");
- if (! out)
- error (EXIT_FAILURE, get_errno (),
- "fdopen");
-
- /* Output the definitions of all the muscles. */
- fputs ("m4_init()\n", out);
-
- type_names_output (out);
- user_actions_output (out);
- merger_output (out);
- token_definitions_output (out);
- symbol_code_props_output (out, "destructors", &symbol_destructor_get);
- symbol_code_props_output (out, "printers", &symbol_printer_get);
-
- muscles_m4_output (out);
- xfclose (out);
+ if (trace_flag & trace_muscles)
+ muscles_output (stderr);
+ {
+ FILE *out = fdopen (filter_fd[0], "w");
+ if (! out)
+ error (EXIT_FAILURE, get_errno (),
+ "fdopen");
+ muscles_output (out);
+ xfclose (out);
+ }
/* Read and process m4's output. */
timevar_push (TV_M4);