1/* Muscle table manager for Bison.
2
3   Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software
4   Foundation, Inc.
5
6   This file is part of Bison, the GNU Compiler Compiler.
7
8   Bison is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2, or (at your option)
11   any later version.
12
13   Bison is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with Bison; see the file COPYING.  If not, write to
20   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21   Boston, MA 02110-1301, USA.  */
22
23#include <config.h>
24#include "system.h"
25
26#include <hash.h>
27#include <quotearg.h>
28
29#include "files.h"
30#include "muscle_tab.h"
31#include "getargs.h"
32
33typedef struct
34{
35  const char *key;
36  char *value;
37} muscle_entry;
38
39/* An obstack used to create some entries.  */
40struct obstack muscle_obstack;
41
42/* Initial capacity of muscles hash table.  */
43#define HT_INITIAL_CAPACITY 257
44
45static struct hash_table *muscle_table = NULL;
46
47static bool
48hash_compare_muscles (void const *x, void const *y)
49{
50  muscle_entry const *m1 = x;
51  muscle_entry const *m2 = y;
52  return strcmp (m1->key, m2->key) == 0;
53}
54
55static size_t
56hash_muscle (const void *x, size_t tablesize)
57{
58  muscle_entry const *m = x;
59  return hash_string (m->key, tablesize);
60}
61
62/*-----------------------------------------------------------------.
63| Create the MUSCLE_TABLE, and initialize it with default values.  |
64| Also set up the MUSCLE_OBSTACK.                                  |
65`-----------------------------------------------------------------*/
66
67void
68muscle_init (void)
69{
70  /* Initialize the muscle obstack.  */
71  obstack_init (&muscle_obstack);
72
73  muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
74				  hash_compare_muscles, free);
75
76  /* Version and input file.  */
77  MUSCLE_INSERT_STRING ("version", VERSION);
78  MUSCLE_INSERT_C_STRING ("file_name", grammar_file);
79}
80
81
82/*------------------------------------------------------------.
83| Free all the memory consumed by the muscle machinery only.  |
84`------------------------------------------------------------*/
85
86void
87muscle_free (void)
88{
89  hash_free (muscle_table);
90  obstack_free (&muscle_obstack, NULL);
91}
92
93
94
95/*------------------------------------------------------------.
96| Insert (KEY, VALUE).  If KEY already existed, overwrite the |
97| previous value.                                             |
98`------------------------------------------------------------*/
99
100void
101muscle_insert (const char *key, char *value)
102{
103  muscle_entry probe;
104  muscle_entry *entry;
105
106  probe.key = key;
107  entry = hash_lookup (muscle_table, &probe);
108
109  if (!entry)
110    {
111      /* First insertion in the hash. */
112      entry = xmalloc (sizeof *entry);
113      entry->key = key;
114      hash_insert (muscle_table, entry);
115    }
116  entry->value = value;
117}
118
119
120/*-------------------------------------------------------------------.
121| Append VALUE to the current value of KEY.  If KEY did not already  |
122| exist, create it.  Use MUSCLE_OBSTACK.  De-allocate the previously |
123| associated value.  Copy VALUE and SEPARATOR.                       |
124`-------------------------------------------------------------------*/
125
126void
127muscle_grow (const char *key, const char *val, const char *separator)
128{
129  muscle_entry probe;
130  muscle_entry *entry = NULL;
131
132  probe.key = key;
133  entry = hash_lookup (muscle_table, &probe);
134
135  if (!entry)
136    {
137      /* First insertion in the hash. */
138      entry = xmalloc (sizeof *entry);
139      entry->key = key;
140      hash_insert (muscle_table, entry);
141      entry->value = xstrdup (val);
142    }
143  else
144    {
145      /* Grow the current value. */
146      char *new_val;
147      obstack_sgrow (&muscle_obstack, entry->value);
148      free (entry->value);
149      obstack_sgrow (&muscle_obstack, separator);
150      obstack_sgrow (&muscle_obstack, val);
151      obstack_1grow (&muscle_obstack, 0);
152      new_val = obstack_finish (&muscle_obstack);
153      entry->value = xstrdup (new_val);
154      obstack_free (&muscle_obstack, new_val);
155    }
156}
157
158
159/*------------------------------------------------------------------.
160| Append VALUE to the current value of KEY, using muscle_grow.  But |
161| in addition, issue a synchronization line for the location LOC.   |
162`------------------------------------------------------------------*/
163
164void
165muscle_code_grow (const char *key, const char *val, location loc)
166{
167  char *extension = NULL;
168  obstack_fgrow1 (&muscle_obstack, "]b4_syncline(%d, [[", loc.start.line);
169  MUSCLE_OBSTACK_SGROW (&muscle_obstack,
170			quotearg_style (c_quoting_style, loc.start.file));
171  obstack_sgrow (&muscle_obstack, "]])[\n");
172  obstack_sgrow (&muscle_obstack, val);
173  obstack_1grow (&muscle_obstack, 0);
174  extension = obstack_finish (&muscle_obstack);
175  muscle_grow (key, extension, "");
176}
177
178
179/*-------------------------------------------------------------------.
180| MUSCLE is an M4 list of pairs.  Create or extend it with the pair  |
181| (A1, A2).  Note that because the muscle values are output *double* |
182| quoted, one needs to strip the first level of quotes to reach the  |
183| list itself.                                                       |
184`-------------------------------------------------------------------*/
185
186void muscle_pair_list_grow (const char *muscle,
187			    const char *a1, const char *a2)
188{
189  char *pair;
190  obstack_fgrow2 (&muscle_obstack, "[[[%s]], [[%s]]]", a1, a2);
191  obstack_1grow (&muscle_obstack, 0);
192  pair = obstack_finish (&muscle_obstack);
193  muscle_grow (muscle, pair, ",\n");
194  obstack_free (&muscle_obstack, pair);
195}
196
197/*-------------------------------.
198| Find the value of muscle KEY.  |
199`-------------------------------*/
200
201char *
202muscle_find (const char *key)
203{
204  muscle_entry probe;
205  muscle_entry *result = NULL;
206
207  probe.key = key;
208  result = hash_lookup (muscle_table, &probe);
209  return result ? result->value : NULL;
210}
211
212
213/*------------------------------------------------.
214| Output the definition of ENTRY as a m4_define.  |
215`------------------------------------------------*/
216
217static inline bool
218muscle_m4_output (muscle_entry *entry, FILE *out)
219{
220  fprintf (out, "m4_define([b4_%s],\n", entry->key);
221  fprintf (out, "[[%s]])\n\n\n", entry->value);
222  return true;
223}
224
225static bool
226muscle_m4_output_processor (void *entry, void *out)
227{
228  return muscle_m4_output (entry, out);
229}
230
231
232/*----------------------------------------------------------------.
233| Output the definition of all the current muscles into a list of |
234| m4_defines.                                                     |
235`----------------------------------------------------------------*/
236
237void
238muscles_m4_output (FILE *out)
239{
240  hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
241}
242