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 10369 : append_symbol(struct linked_list **plist, Symbol *sp)
31 : {
32 10369 : if (sp->entry) {
33 112 : linked_list_unlink(sp->entry->list, sp->entry);
34 112 : sp->entry = NULL;
35 : }
36 10369 : if (!data_in_list(sp, *plist)) {
37 10369 : linked_list_append(plist, sp);
38 10369 : sp->entry = (*plist)->tail;
39 : }
40 10369 : }
41 :
42 : struct table_entry {
43 : Symbol *sym;
44 : };
45 :
46 : /* Calculate the hash of a string. */
47 : static size_t
48 285574 : hash_symbol_hasher(void const *data, unsigned n_buckets)
49 : {
50 285574 : struct table_entry const *t = data;
51 285574 : if (!t->sym)
52 19544 : return ((size_t) data) % n_buckets;
53 266030 : return hash_string(t->sym->name, n_buckets);
54 : }
55 :
56 : /* Compare two strings for equality. */
57 : static bool
58 418873 : hash_symbol_compare(void const *data1, void const *data2)
59 : {
60 418873 : struct table_entry const *t1 = data1;
61 418873 : struct table_entry const *t2 = data2;
62 418873 : return t1->sym && t2->sym && strcmp(t1->sym->name, t2->sym->name) == 0;
63 : }
64 :
65 : Symbol *
66 223733 : lookup(const char *name)
67 : {
68 : Symbol s, *sym;
69 : struct table_entry t, *tp;
70 :
71 223733 : if (!symbol_table)
72 0 : return NULL;
73 223733 : s.name = (char*) name;
74 223733 : t.sym = &s;
75 223733 : tp = hash_lookup(symbol_table, &t);
76 223733 : if (tp) {
77 188245 : sym = tp->sym;
78 376490 : while (sym->type == SymToken && sym->flag == symbol_alias)
79 0 : sym = sym->alias;
80 : } else
81 35488 : sym = NULL;
82 223733 : 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 18302 : install(char *name, int flags)
89 : {
90 : Symbol *sym;
91 : struct table_entry *tp, *ret;
92 :
93 18302 : sym = xmalloc(sizeof(*sym));
94 18302 : memset(sym, 0, sizeof(*sym));
95 18302 : sym->type = SymUndefined;
96 18302 : sym->name = name;
97 :
98 18302 : tp = xmalloc(sizeof(*tp));
99 18302 : tp->sym = sym;
100 :
101 18302 : if (((flags & INSTALL_CHECK_LOCAL) &&
102 27223 : canonical_filename && strcmp(filename, canonical_filename)) ||
103 16954 : (flags & INSTALL_UNIT_LOCAL)) {
104 1556 : sym->flag = symbol_temp;
105 1556 : append_symbol(&static_symbol_list, sym);
106 : } else
107 16746 : sym->flag = symbol_none;
108 :
109 36604 : if (! ((symbol_table
110 21 : || (symbol_table = hash_initialize (0, 0,
111 : hash_symbol_hasher,
112 : hash_symbol_compare, 0)))
113 18302 : && (ret = hash_insert (symbol_table, tp))))
114 0 : xalloc_die ();
115 :
116 18302 : if (ret != tp) {
117 1423 : if (flags & INSTALL_OVERWRITE) {
118 0 : free(sym);
119 0 : free(tp);
120 0 : return ret->sym;
121 : }
122 1423 : if (ret->sym->type != SymUndefined)
123 1423 : sym->next = ret->sym;
124 1423 : ret->sym = sym;
125 1423 : free(tp);
126 : }
127 18302 : sym->owner = ret;
128 18302 : return sym;
129 : }
130 :
131 : void
132 22484 : ident_change_storage(Symbol *sp, enum storage storage)
133 : {
134 22484 : if (sp->storage == storage)
135 36149 : return;
136 8819 : if (sp->storage == StaticStorage)
137 : /* FIXME */;
138 :
139 8819 : switch (storage) {
140 : case StaticStorage:
141 1581 : append_symbol(&static_symbol_list, sp);
142 1581 : break;
143 : case AutoStorage:
144 7232 : append_symbol(&auto_symbol_list, sp);
145 7232 : break;
146 : default:
147 6 : break;
148 : }
149 8819 : sp->storage = storage;
150 : }
151 :
152 : Symbol *
153 17501 : install_ident(char *name, enum storage storage)
154 : {
155 : Symbol *sp;
156 :
157 17501 : sp = install(name,
158 : storage != AutoStorage ?
159 : INSTALL_CHECK_LOCAL : INSTALL_DEFAULT);
160 17501 : sp->type = SymIdentifier;
161 17501 : sp->arity = -1;
162 17501 : sp->storage = ExternStorage;
163 17501 : sp->decl = NULL;
164 17501 : sp->source = NULL;
165 17501 : sp->def_line = -1;
166 17501 : sp->ref_line = NULL;
167 17501 : sp->caller = sp->callee = NULL;
168 17501 : sp->level = -1;
169 17501 : ident_change_storage(sp, storage);
170 17501 : return sp;
171 : }
172 :
173 : /* Unlink the symbol from the table entry */
174 : static void
175 10257 : unlink_symbol(Symbol *sym)
176 : {
177 10257 : Symbol *s, *prev = NULL;
178 10257 : struct table_entry *tp = sym->owner;
179 20514 : for (s = tp->sym; s; ) {
180 10257 : Symbol *next = s->next;
181 10257 : if (s == sym) {
182 10257 : if (prev)
183 0 : prev->next = next;
184 : else
185 10257 : tp->sym = next;
186 10257 : break;
187 : } else
188 0 : prev = s;
189 0 : s = next;
190 : }
191 :
192 10257 : sym->owner = NULL;
193 10257 : }
194 :
195 : /* Unlink and free the first symbol from the table entry */
196 : static void
197 8788 : delete_symbol(Symbol *sym)
198 : {
199 8788 : 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 8788 : if (sym->ref_line == NULL && !(reverse_tree && sym->callee)) {
203 7538 : linked_list_destroy(&sym->ref_line);
204 7538 : linked_list_destroy(&sym->caller);
205 7538 : linked_list_destroy(&sym->callee);
206 7538 : free(sym);
207 : }
208 8788 : }
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 229 : delete_statics()
238 : {
239 229 : if (static_symbol_list) {
240 177 : static_symbol_list->free_data = static_free;
241 177 : linked_list_destroy(&static_symbol_list);
242 : }
243 229 : }
244 :
245 : /* See NOTE above */
246 :
247 : /* Delete from the symbol table all auto variables with given nesting
248 : level. */
249 : int
250 19982 : delete_level_autos(void *data, void *call_data)
251 : {
252 19982 : int level = *(int*)call_data;
253 19982 : Symbol *s = data;
254 19982 : if (s->level == level) {
255 6650 : delete_symbol(s);
256 6650 : return 1;
257 : }
258 13332 : return 0;
259 : }
260 :
261 : int
262 211177 : delete_level_statics(void *data, void *call_data)
263 : {
264 211177 : int level = *(int*)call_data;
265 211177 : Symbol *s = data;
266 211177 : if (s->level == level) {
267 16 : unlink_symbol(s);
268 16 : return 1;
269 : }
270 211161 : return 0;
271 : }
272 :
273 : void
274 8401 : delete_autos(int level)
275 : {
276 8401 : linked_list_iterate(&auto_symbol_list, delete_level_autos, &level);
277 8401 : linked_list_iterate(&static_symbol_list, delete_level_statics, &level);
278 8401 : }
279 :
280 : struct collect_data {
281 : Symbol **sym;
282 : int (*sel)(Symbol *p);
283 : size_t index;
284 : };
285 :
286 : static bool
287 57118 : collect_processor(void *data, void *proc_data)
288 : {
289 57118 : struct table_entry *t = data;
290 57118 : struct collect_data *cd = proc_data;
291 : Symbol *s;
292 84378 : for (s = t->sym; s; s = s->next) {
293 27260 : if (cd->sel(s)) {
294 17232 : if (cd->sym)
295 8616 : cd->sym[cd->index] = s;
296 17232 : cd->index++;
297 : }
298 : }
299 57118 : return true;
300 : }
301 :
302 : size_t
303 37 : collect_symbols(Symbol ***return_sym, int (*sel)(Symbol *p),
304 : size_t reserved_slots)
305 : {
306 : struct collect_data cdata;
307 :
308 37 : cdata.sym = NULL;
309 37 : cdata.index = 0;
310 37 : cdata.sel = sel;
311 37 : hash_do_for_each (symbol_table, collect_processor, &cdata);
312 37 : cdata.sym = calloc(cdata.index + reserved_slots, sizeof(*cdata.sym));
313 37 : if (!cdata.sym)
314 0 : xalloc_die();
315 37 : cdata.index = 0;
316 37 : hash_do_for_each (symbol_table, collect_processor, &cdata);
317 37 : *return_sym = cdata.sym;
318 37 : return cdata.index;
319 : }
320 :
321 : size_t
322 16 : 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 16 : snum = 0;
330 16 : 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 16 : num = collect_symbols(&symbols, symbol_is_function, snum);
336 :
337 : /* Collect static functions */
338 16 : if (snum)
339 627 : for (p = linked_list_head(static_func_list); p; p = p->next)
340 615 : symbols[num++] = p->data;
341 16 : *return_sym = symbols;
342 16 : return num;
343 : }
344 :
345 :
346 :
347 : /* Special handling for function parameters */
348 :
349 : int
350 8286 : delete_parms_itr(void *data, void *call_data)
351 : {
352 8286 : int level = *(int*)call_data;
353 8286 : Symbol *s = data;
354 8286 : struct table_entry *t = s->owner;
355 :
356 8286 : if (!t)
357 0 : return 1;
358 8286 : if (s->type == SymIdentifier && s->storage == AutoStorage
359 8286 : && s->flag == symbol_parm && s->level > level) {
360 582 : delete_symbol(s);
361 582 : return 1;
362 : }
363 7704 : return 0;
364 : }
365 :
366 : /* Delete all parameters with parameter nesting level greater than LEVEL */
367 : void
368 11854 : delete_parms(int level)
369 : {
370 11854 : linked_list_iterate(&auto_symbol_list, delete_parms_itr, &level);
371 11854 : }
372 :
373 : /* Redeclare all saved parameters as automatic variables with the
374 : given nesting level */
375 : void
376 3039 : move_parms(int level)
377 : {
378 : struct linked_list_entry *p;
379 :
380 7027 : for (p = linked_list_head(auto_symbol_list); p; p = p->next) {
381 3988 : Symbol *s = p->data;
382 :
383 3988 : if (s->type == SymIdentifier && s->storage == AutoStorage
384 3988 : && s->flag == symbol_parm) {
385 3988 : s->level = level;
386 3988 : s->flag = symbol_none;
387 : }
388 : }
389 3039 : }
390 :
|