Line data Source code
1 : /* This file is part of GNU cflow
2 : Copyright (C) 1997, 2005, 2006, 2007, 2009, 2010 Sergey Poznyakoff
3 :
4 : GNU cflow is free software; you can redistribute it and/or modify
5 : it under the terms of the GNU General Public License as published by
6 : the Free Software Foundation; either version 3 of the License, or
7 : (at your option) any later version.
8 :
9 : GNU cflow is distributed in the hope that it will be useful,
10 : but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : GNU General Public License for more details.
13 :
14 : You should have received a copy of the GNU General Public
15 : License along with GNU cflow; if not, write to the Free Software
16 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 : MA 02110-1301 USA */
18 :
19 : #include <cflow.h>
20 : #include <parser.h>
21 : #include <hash.h>
22 :
23 : static Hash_table *symbol_table;
24 :
25 : static struct linked_list *static_symbol_list;
26 : static struct linked_list *auto_symbol_list;
27 : static struct linked_list *static_func_list;
28 :
29 : static void
30 10593 : append_symbol(struct linked_list **plist, Symbol *sp)
31 : {
32 10593 : if (sp->entry) {
33 112 : linked_list_unlink(sp->entry->list, sp->entry);
34 112 : sp->entry = NULL;
35 : }
36 10593 : if (!data_in_list(sp, *plist)) {
37 10593 : linked_list_append(plist, sp);
38 10593 : sp->entry = (*plist)->tail;
39 : }
40 10593 : }
41 :
42 : struct table_entry {
43 : Symbol *sym;
44 : };
45 :
46 : /* Calculate the hash of a string. */
47 : static size_t
48 288619 : hash_symbol_hasher(void const *data, unsigned n_buckets)
49 : {
50 288619 : struct table_entry const *t = data;
51 288619 : if (!t->sym)
52 19593 : return ((size_t) data) % n_buckets;
53 269026 : return hash_string(t->sym->name, n_buckets);
54 : }
55 :
56 : /* Compare two strings for equality. */
57 : static bool
58 429462 : hash_symbol_compare(void const *data1, void const *data2)
59 : {
60 429462 : struct table_entry const *t1 = data1;
61 429462 : struct table_entry const *t2 = data2;
62 429462 : return t1->sym && t2->sym && strcmp(t1->sym->name, t2->sym->name) == 0;
63 : }
64 :
65 : Symbol *
66 226061 : lookup(const char *name)
67 : {
68 : Symbol s, *sym;
69 : struct table_entry t, *tp;
70 :
71 226061 : if (!symbol_table)
72 0 : return NULL;
73 226061 : s.name = (char*) name;
74 226061 : t.sym = &s;
75 226061 : tp = hash_lookup(symbol_table, &t);
76 226061 : if (tp) {
77 189346 : sym = tp->sym;
78 378692 : while (sym->type == SymToken && sym->flag == symbol_alias)
79 0 : sym = sym->alias;
80 : } else
81 36715 : sym = NULL;
82 226061 : return sym;
83 : }
84 :
85 : /* Install a new symbol `NAME'. If UNIT_LOCAL is set, this symbol can
86 : be local to the current compilation unit. */
87 : Symbol *
88 18692 : install(char *name, int flags)
89 : {
90 : Symbol *sym;
91 : struct table_entry *tp, *ret;
92 :
93 18692 : sym = xmalloc(sizeof(*sym));
94 18692 : memset(sym, 0, sizeof(*sym));
95 18692 : sym->type = SymUndefined;
96 18692 : sym->name = name;
97 :
98 18692 : tp = xmalloc(sizeof(*tp));
99 18692 : tp->sym = sym;
100 :
101 18692 : if (((flags & INSTALL_CHECK_LOCAL) &&
102 27835 : canonical_filename && strcmp(filename, canonical_filename)) ||
103 17344 : (flags & INSTALL_UNIT_LOCAL)) {
104 1556 : sym->flag = symbol_temp;
105 1556 : append_symbol(&static_symbol_list, sym);
106 : } else
107 17136 : sym->flag = symbol_none;
108 :
109 37384 : if (! ((symbol_table
110 19 : || (symbol_table = hash_initialize (0, 0,
111 : hash_symbol_hasher,
112 : hash_symbol_compare, 0)))
113 18692 : && (ret = hash_insert (symbol_table, tp))))
114 0 : xalloc_die ();
115 :
116 18692 : if (ret != tp) {
117 1455 : if (flags & INSTALL_OVERWRITE) {
118 0 : free(sym);
119 0 : free(tp);
120 0 : return ret->sym;
121 : }
122 1455 : if (ret->sym->type != SymUndefined)
123 1455 : sym->next = ret->sym;
124 1455 : ret->sym = sym;
125 1455 : free(tp);
126 : }
127 18692 : sym->owner = ret;
128 18692 : return sym;
129 : }
130 :
131 : void
132 23025 : ident_change_storage(Symbol *sp, enum storage storage)
133 : {
134 23025 : if (sp->storage == storage)
135 37007 : return;
136 9043 : if (sp->storage == StaticStorage)
137 : /* FIXME */;
138 :
139 9043 : switch (storage) {
140 : case StaticStorage:
141 1581 : append_symbol(&static_symbol_list, sp);
142 1581 : break;
143 : case AutoStorage:
144 7456 : append_symbol(&auto_symbol_list, sp);
145 7456 : break;
146 : default:
147 6 : break;
148 : }
149 9043 : sp->storage = storage;
150 : }
151 :
152 : Symbol *
153 17947 : install_ident(char *name, enum storage storage)
154 : {
155 : Symbol *sp;
156 :
157 17947 : sp = install(name,
158 : storage != AutoStorage ?
159 : INSTALL_CHECK_LOCAL : INSTALL_DEFAULT);
160 17947 : sp->type = SymIdentifier;
161 17947 : sp->arity = -1;
162 17947 : sp->storage = ExternStorage;
163 17947 : sp->decl = NULL;
164 17947 : sp->source = NULL;
165 17947 : sp->def_line = -1;
166 17947 : sp->ref_line = NULL;
167 17947 : sp->caller = sp->callee = NULL;
168 17947 : sp->level = -1;
169 17947 : ident_change_storage(sp, storage);
170 17947 : return sp;
171 : }
172 :
173 : /* Unlink the symbol from the table entry */
174 : static void
175 10481 : unlink_symbol(Symbol *sym)
176 : {
177 10481 : Symbol *s, *prev = NULL;
178 10481 : struct table_entry *tp = sym->owner;
179 20962 : for (s = tp->sym; s; ) {
180 10481 : Symbol *next = s->next;
181 10481 : if (s == sym) {
182 10481 : if (prev)
183 0 : prev->next = next;
184 : else
185 10481 : tp->sym = next;
186 10481 : break;
187 : } else
188 0 : prev = s;
189 0 : s = next;
190 : }
191 :
192 10481 : sym->owner = NULL;
193 10481 : }
194 :
195 : /* Unlink and free the first symbol from the table entry */
196 : static void
197 9012 : delete_symbol(Symbol *sym)
198 : {
199 9012 : unlink_symbol(sym);
200 : /* The symbol could have been referenced even if it is static
201 : in -i^s mode. See tests/static.at for details. */
202 9012 : if (sym->ref_line == NULL && !(reverse_tree && sym->callee)) {
203 7762 : linked_list_destroy(&sym->ref_line);
204 7762 : linked_list_destroy(&sym->caller);
205 7762 : linked_list_destroy(&sym->callee);
206 7762 : free(sym);
207 : }
208 9012 : }
209 :
210 : /* Delete from the symbol table all static symbols defined in the current
211 : source.
212 : If the user requested static symbols in the listing, the symbol is
213 : not deleted, as it may have been referenced by other symbols. Instead,
214 : it is unlinked from its table entry.
215 : NOTE: This takes advantage of the fact that install() uses LIFO strategy,
216 : so we don't have to check the name of the source where the symbol was
217 : defined. */
218 :
219 : static void
220 3009 : static_free(void *data)
221 : {
222 3009 : Symbol *sym = data;
223 3009 : struct table_entry *t = sym->owner;
224 :
225 3009 : if (!t)
226 3009 : return;
227 3009 : if (sym->flag == symbol_temp)
228 1556 : delete_symbol(sym);
229 : else {
230 1453 : unlink_symbol(sym);
231 1453 : if (symbol_is_function(sym))
232 892 : linked_list_append(&static_func_list, sym);
233 : }
234 : }
235 :
236 : void
237 227 : delete_statics()
238 : {
239 227 : if (static_symbol_list) {
240 177 : static_symbol_list->free_data = static_free;
241 177 : linked_list_destroy(&static_symbol_list);
242 : }
243 227 : }
244 :
245 : /* See NOTE above */
246 :
247 : /* Delete from the symbol table all auto variables with given nesting
248 : level. */
249 : int
250 19726 : delete_level_autos(void *data, void *call_data)
251 : {
252 19726 : int level = *(int*)call_data;
253 19726 : Symbol *s = data;
254 19726 : if (s->level == level) {
255 6874 : delete_symbol(s);
256 6874 : return 1;
257 : }
258 12852 : return 0;
259 : }
260 :
261 : int
262 209961 : delete_level_statics(void *data, void *call_data)
263 : {
264 209961 : int level = *(int*)call_data;
265 209961 : Symbol *s = data;
266 209961 : if (s->level == level) {
267 16 : unlink_symbol(s);
268 16 : return 1;
269 : }
270 209945 : return 0;
271 : }
272 :
273 : void
274 8432 : delete_autos(int level)
275 : {
276 8432 : linked_list_iterate(&auto_symbol_list, delete_level_autos, &level);
277 8432 : linked_list_iterate(&static_symbol_list, delete_level_statics, &level);
278 8432 : }
279 :
280 : struct collect_data {
281 : Symbol **sym;
282 : int (*sel)(Symbol *p);
283 : size_t index;
284 : };
285 :
286 : static bool
287 58290 : collect_processor(void *data, void *proc_data)
288 : {
289 58290 : struct table_entry *t = data;
290 58290 : struct collect_data *cd = proc_data;
291 : Symbol *s;
292 86074 : for (s = t->sym; s; s = s->next) {
293 27784 : if (cd->sel(s)) {
294 17830 : if (cd->sym)
295 8915 : cd->sym[cd->index] = s;
296 17830 : cd->index++;
297 : }
298 : }
299 58290 : return true;
300 : }
301 :
302 : size_t
303 33 : collect_symbols(Symbol ***return_sym, int (*sel)(Symbol *p),
304 : size_t reserved_slots)
305 : {
306 : struct collect_data cdata;
307 :
308 33 : cdata.sym = NULL;
309 33 : cdata.index = 0;
310 33 : cdata.sel = sel;
311 33 : hash_do_for_each (symbol_table, collect_processor, &cdata);
312 33 : cdata.sym = calloc(cdata.index + reserved_slots, sizeof(*cdata.sym));
313 33 : if (!cdata.sym)
314 0 : xalloc_die();
315 33 : cdata.index = 0;
316 33 : hash_do_for_each (symbol_table, collect_processor, &cdata);
317 33 : *return_sym = cdata.sym;
318 33 : return cdata.index;
319 : }
320 :
321 : size_t
322 14 : collect_functions(Symbol ***return_sym)
323 : {
324 : Symbol **symbols;
325 : size_t num, snum;
326 : struct linked_list_entry *p;
327 :
328 : /* Count static functions */
329 14 : snum = 0;
330 14 : if (static_func_list)
331 627 : for (p = linked_list_head(static_func_list); p; p = p->next)
332 615 : snum++;
333 :
334 : /* Collect global functions */
335 14 : num = collect_symbols(&symbols, symbol_is_function, snum);
336 :
337 : /* Collect static functions */
338 14 : if (snum)
339 627 : for (p = linked_list_head(static_func_list); p; p = p->next)
340 615 : symbols[num++] = p->data;
341 14 : *return_sym = symbols;
342 14 : return num;
343 : }
344 :
345 :
346 :
347 : /* Special handling for function parameters */
348 :
349 : int
350 8430 : delete_parms_itr(void *data, void *call_data)
351 : {
352 8430 : int level = *(int*)call_data;
353 8430 : Symbol *s = data;
354 8430 : struct table_entry *t = s->owner;
355 :
356 8430 : if (!t)
357 0 : return 1;
358 8430 : if (s->type == SymIdentifier && s->storage == AutoStorage
359 8430 : && s->flag == symbol_parm && s->level > level) {
360 582 : delete_symbol(s);
361 582 : return 1;
362 : }
363 7848 : return 0;
364 : }
365 :
366 : /* Delete all parameters with parameter nesting level greater than LEVEL */
367 : void
368 12093 : delete_parms(int level)
369 : {
370 12093 : linked_list_iterate(&auto_symbol_list, delete_parms_itr, &level);
371 12093 : }
372 :
373 : /* Redeclare all saved parameters as automatic variables with the
374 : given nesting level */
375 : void
376 3102 : move_parms(int level)
377 : {
378 : struct linked_list_entry *p;
379 :
380 7202 : for (p = linked_list_head(auto_symbol_list); p; p = p->next) {
381 4100 : Symbol *s = p->data;
382 :
383 4100 : if (s->type == SymIdentifier && s->storage == AutoStorage
384 4100 : && s->flag == symbol_parm) {
385 4100 : s->level = level;
386 4100 : s->flag = symbol_none;
387 : }
388 : }
389 3102 : }
390 :
|