diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-06-28 15:58:01 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-06-28 15:58:01 +0300 |
commit | eb6e7c7cee0c998f5b403074201992c22383a553 (patch) | |
tree | 08537200d56b35bbfffe37fa6a7c1e63855954d0 | |
parent | 4b66e93d434d2a4fe8fd3f277e222de768475605 (diff) | |
download | cflow-eb6e7c7cee0c998f5b403074201992c22383a553.tar.gz cflow-eb6e7c7cee0c998f5b403074201992c22383a553.tar.bz2 |
Provide a general-purpose type for singly-linked list.
* src/cflow.h (Cons, Consptr, CAR, CDR): Remove
(struct linked_list_entry): New type.
(struct linked_list): New type.
(linked_list_free_data_fp): New typedef.
(struct symbol): Change types of ref_line, callee and caller
to struct linked_list. All usages changed.
(linked_list_head): New define.
(linked_list_create, linked_list_destroy)
(linked_list_append, linked_list_prepend): New prototypes.
(cleanup, append_to_list): Remove
* src/main.c (arglist): Change type to struct linked_list
* src/output.c, src/parser.c, src/symbol.c: Use new
linked list functions.
-rw-r--r-- | src/cflow.h | 34 | ||||
-rw-r--r-- | src/main.c | 16 | ||||
-rw-r--r-- | src/output.c | 41 | ||||
-rw-r--r-- | src/parser.c | 14 | ||||
-rw-r--r-- | src/symbol.c | 183 |
5 files changed, 119 insertions, 169 deletions
diff --git a/src/cflow.h b/src/cflow.h index 7a38682..c6712c9 100644 --- a/src/cflow.h +++ b/src/cflow.h @@ -1,8 +1,8 @@ /* This file is part of GNU cflow - Copyright (C) 1997,2005,2007 Sergey Poznyakoff + Copyright (C) 1997,2005,2007,2009 Sergey Poznyakoff GNU cflow is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @@ -42,21 +42,25 @@ #if !HAVE_SETLOCALE # define setlocale(category, locale) /* empty */ #endif #define NUMITEMS(a) sizeof(a)/sizeof((a)[0]) -typedef struct cons *Consptr; -typedef struct cons Cons; -struct cons { - Consptr car; - Consptr cdr; +struct linked_list_entry { + struct linked_list_entry *next; + void *data; }; -#define CAR(a) (a)->car -#define CDR(a) (a)->cdr +typedef void (*linked_list_free_data_fp) (void*); + +struct linked_list { + linked_list_free_data_fp free_data; + struct linked_list_entry *head, *tail; +}; + +#define linked_list_head(list) ((list) ? (list)->head : NULL) enum symtype { SymUndefined, /* Undefined or deleted symbol */ SymToken, /* A token */ SymIdentifier /* Function or variable */ }; @@ -94,26 +98,26 @@ struct symbol { int expand_line; /* Output line when this symbol was first expanded */ int token_type; /* Type of the token */ char *source; /* Source file */ int def_line; /* Source line */ - Consptr ref_line; /* Referenced in */ + struct linked_list *ref_line; /* Referenced in */ int level; /* Block nesting level (for local vars), Parameter nesting level (for params) */ char *decl; /* Declaration */ enum storage storage; /* Storage type */ int arity; /* Number of parameters or -1 for variables */ int recursive; /* Is the function recursive */ - Consptr caller; /* List of callers */ - Consptr callee; /* List of callees */ + struct linked_list *caller; /* List of callers */ + struct linked_list *callee; /* List of callees */ }; /* Output flags */ #define PRINT_XREF 0x01 #define PRINT_TREE 0x02 @@ -159,16 +163,18 @@ extern unsigned input_file_count; Symbol *lookup(char*); Symbol *install(char*); void delete_autos(int level); void delete_statics(void); void delete_parms(int level); void move_parms(int level); -void cleanup(void); int collect_symbols(Symbol ***, int (*sel)()); -Consptr append_to_list(Consptr *, void *); -int symbol_in_list(Symbol *sym, Consptr list); +struct linked_list *linked_list_create(linked_list_free_data_fp fun); +void linked_list_destroy(struct linked_list **plist); +void linked_list_append(struct linked_list **plist, void *data); +void linked_list_prepend(struct linked_list **plist, void *data); +int symbol_in_list(Symbol *sym, struct linked_list *list); int get_token(void); int source(char *name); void init_lex(int debug_level); void set_preprocessor(const char *arg); void pp_option(const char *arg); @@ -215,13 +215,13 @@ char *level_end[] = { "", "" }; char *level_begin = ""; int preprocess_option = 0; /* Do they want to preprocess sources? */ char *start_name = "main"; /* Name of start symbol */ -Consptr arglist; /* List of command line arguments */ +struct linked_list *arglist; /* List of command line arguments */ /* Given the option_type array and (possibly abbreviated) option argument * find the type corresponding to that argument. * Return 0 if the argument does not match any one of OPTYPE entries */ static int @@ -484,13 +484,13 @@ set_level_indent(const char *str) } } static void add_name(const char *name) { - append_to_list(&arglist, (void*) name); + linked_list_append(&arglist, (void*) name); } static void add_preproc_option(int key, const char *arg) { char *opt = xmalloc(3 + strlen(arg)); @@ -766,35 +766,35 @@ main(int argc, char **argv) if (print_option == 0) print_option = PRINT_TREE; init(); - if (arglist) - /* See comment to cleanup_processor */ - for (arglist = CAR(arglist); arglist; arglist = CDR(arglist)) { - char *s = (char*)CAR(arglist); + if (arglist) { + struct linked_list_entry *p; + + for (p = arglist->head; p; p = p->next) { + char *s = (char*)p->data; if (s[0] == '-') pp_option(s); else if (source(s) == 0) yyparse(); } + } argc -= index; argv += index; while (argc--) { if (source(*argv++) == 0) yyparse(); } if (input_file_count == 0) error(1, 0, _("no input files")); - cleanup(); - output(); return 0; } diff --git a/src/output.c b/src/output.c index 7e604f4..f33d0ae 100644 --- a/src/output.c +++ b/src/output.c @@ -1,8 +1,8 @@ /* This file is part of GNU cflow - Copyright (C) 1997,2005,2007 Sergey Poznyakoff + Copyright (C) 1997,2005,2007,2009 Sergey Poznyakoff GNU cflow is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @@ -197,18 +197,19 @@ clear_active(Symbol *sym) sym->active = 0; } /* Cross-reference output */ void -print_refs(char *name, Consptr cons) +print_refs(char *name, struct linked_list *reflist) { Ref *refptr; + struct linked_list_entry *p; - for ( ; cons; cons = CDR(cons)) { - refptr = (Ref*)CAR(cons); + for (p = linked_list_head(reflist); p; p = p->next) { + refptr = (Ref*)p->data; fprintf(outfile, "%s %s:%d\n", name, refptr->source, refptr->line); } } @@ -268,93 +269,93 @@ xref_output() /* Scan call tree. Mark the recursive calls */ static void scan_tree(int lev, Symbol *sym) { - Consptr cons; + struct linked_list_entry *p; if (sym->type == SymUndefined) return; if (sym->active) { sym->recursive = 1; return; } sym->active = 1; - for (cons = sym->callee; cons; cons = CDR(cons)) { - scan_tree(lev+1, (Symbol*)CAR(cons)); + for (p = linked_list_head(sym->callee); p; p = p->next) { + scan_tree(lev+1, (Symbol*)p->data); } sym->active = 0; } static void set_active(Symbol *sym) { sym->active = out_line; } static int -is_printable(Consptr cons) +is_printable(struct linked_list_entry *p) { - return cons != NULL && include_symbol((Symbol*)CAR(cons)); + return p != NULL && include_symbol((Symbol*)p->data); } static int -is_last(Consptr cons) +is_last(struct linked_list_entry *p) { - while (cons = CDR(cons)) - if (is_printable(cons)) + while (p = p->next) + if (is_printable(p)) return 0; return 1; } /* Produce direct call tree output */ static void direct_tree(int lev, int last, Symbol *sym) { - Consptr cons; + struct linked_list_entry *p; int rc; if (sym->type == SymUndefined || (max_depth && lev >= max_depth) || !include_symbol(sym)) return; rc = print_symbol(1, lev, last, sym); newline(); if (rc || sym->active) return; set_active(sym); - for (cons = sym->callee; cons; cons = CDR(cons)) { - set_level_mark(lev+1, is_printable(CDR(cons))); - direct_tree(lev+1, is_last(cons), (Symbol*)CAR(cons)); + for (p = linked_list_head(sym->callee); p; p = p->next) { + set_level_mark(lev+1, is_printable(p->next)); + direct_tree(lev+1, is_last(p), (Symbol*)p->data); } clear_active(sym); } /* Produce reverse call tree output */ static void inverted_tree(int lev, int last, Symbol *sym) { - Consptr cons; + struct linked_list_entry *p; int rc; if (sym->type == SymUndefined || (max_depth && lev >= max_depth) || !include_symbol(sym)) return; rc = print_symbol(0, lev, last, sym); newline(); if (rc || sym->active) return; set_active(sym); - for (cons = sym->caller; cons; cons = CDR(cons)) { - set_level_mark(lev+1, is_printable(CDR(cons))); - inverted_tree(lev+1, is_last(cons), (Symbol*)CAR(cons)); + for (p = linked_list_head(sym->caller); p; p = p->next) { + set_level_mark(lev+1, is_printable(p->next)); + inverted_tree(lev+1, is_last(p), (Symbol*)p->data); } clear_active(sym); } static void tree_output() diff --git a/src/parser.c b/src/parser.c index 911bf58..26ac25d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,8 +1,8 @@ /* This file is part of GNU cflow - Copyright (C) 1997, 2005, 2006, 2007 Sergey Poznyakoff + Copyright (C) 1997, 2005, 2006, 2007, 2009 Sergey Poznyakoff GNU cflow is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @@ -1074,13 +1074,15 @@ add_reference(char *name, int line) if (sp->storage == AutoStorage || (sp->storage == StaticStorage && globals_only())) return NULL; refptr = xmalloc(sizeof(*refptr)); refptr->source = filename; refptr->line = line; - append_to_list(&sp->ref_line, refptr); + if (!sp->ref_line) + sp->ref_line = linked_list_create(free); + linked_list_append(&sp->ref_line, refptr); return sp; } void call(char *name, int line) @@ -1091,26 +1093,26 @@ call(char *name, int line) if (!sp) return; if (sp->arity < 0) sp->arity = 0; if (caller) { if (!symbol_in_list(caller, sp->caller)) - append_to_list(&sp->caller, caller); + linked_list_append(&sp->caller, caller); if (!symbol_in_list(sp, caller->callee)) - append_to_list(&caller->callee, sp); + linked_list_append(&caller->callee, sp); } } void reference(char *name, int line) { Symbol *sp = add_reference(name, line); if (!sp) return; if (caller) { if (!symbol_in_list(caller, sp->caller)) - append_to_list(&sp->caller, caller); + linked_list_append(&sp->caller, caller); if (!symbol_in_list(sp, caller->callee)) - append_to_list(&caller->callee, sp); + linked_list_append(&caller->callee, sp); } } diff --git a/src/symbol.c b/src/symbol.c index 4fe5f85..e3ccd7c 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -1,8 +1,8 @@ /* This file is part of GNU cflow - Copyright (C) 1997, 2005, 2006, 2007 Sergey Poznyakoff + Copyright (C) 1997, 2005, 2006, 2007, 2009 Sergey Poznyakoff GNU cflow is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @@ -107,24 +107,25 @@ unlink_symbol(struct table_entry *tp) static void delete_symbol(struct table_entry *tp) { Symbol *s = unlink_symbol(tp); /* The symbol could have been referenced even if it is static in -i^s mode. See tests/static.at for details. */ - if (s->ref_line == NULL) + if (s->ref_line == NULL) { + linked_list_destroy(&s->ref_line); + linked_list_destroy(&s->caller); + linked_list_destroy(&s->callee); free(s); } - -static void cleanup_symbol_refs(Symbol *sym); +} /* Delete from the symbol table all static symbols defined in the current source. If the user requested static symbols in the listing, the symbol is not deleted, as it may have been referenced by other symbols. Instead, - it is unlinked from its table entry and cleanup_symbol_refs() is - called, so that its reference tables become usable. + it is unlinked from its table entry. NOTE: This takes advantage of the fact that install() uses LIFO strategy, so we don't have to check the name of the source where the symbol was defined. */ static bool static_processor(void *data, void *proc_data) @@ -134,13 +135,13 @@ static_processor(void *data, void *proc_data) if (t->sym && t->sym->type == SymIdentifier && t->sym->storage == StaticStorage) { if (globals_only()) delete_symbol(t); else - cleanup_symbol_refs(unlink_symbol(t)); + unlink_symbol(t); } return true; } static bool temp_processor(void *data, void *proc_data) @@ -171,13 +172,13 @@ auto_processor(void *data, void *proc_data) switch (s->storage) { case AutoStorage: delete_symbol(t); break; case StaticStorage: - cleanup_symbol_refs(unlink_symbol(t)); + unlink_symbol(t); break; default: break; } } @@ -190,54 +191,12 @@ auto_processor(void *data, void *proc_data) void delete_autos(int level) { hash_do_for_each (symbol_table, auto_processor, &level); } - -/* Make all list pointers of the SYM ready for final processing. - * This means for each list replace its entry point with its CAR - * and throw away the first cons. The first cons holds pointers - * to the head and tail of the list and is used to speed up appends. - * - * TODO: The memory is not reclaimed - */ -static void -cleanup_symbol_refs(Symbol *sym) -{ - if (sym && sym->type == SymIdentifier) { - if (sym->ref_line) - sym->ref_line = CAR(sym->ref_line); - if (sym->caller) - sym->caller = CAR(sym->caller); - if (sym->callee) - sym->callee = CAR(sym->callee); - } -} - -static bool -cleanup_processor(void *data, void *proc_data) -{ - struct table_entry *t = data; - Symbol *sym; - for (sym = t->sym; sym; sym = sym->next) { - cleanup_symbol_refs(sym); - } - return true; -} - - -/* Clean up all symbols from the auxiliary information. - * See the comment for cleanup_symbol() above - */ -void -cleanup() -{ - hash_do_for_each (symbol_table, cleanup_processor, NULL); -} - struct collect_data { Symbol **sym; int (*sel)(Symbol *p); size_t index; }; @@ -321,100 +280,82 @@ void move_parms(int level) { hash_do_for_each (symbol_table, move_parm_processor, &level); } -typedef struct bucket Bucket; -struct bucket { - Bucket *next; /* Next bucket */ - int free; - Cons cons[1]; -}; - -static int bucket_nodes = 512; -static Bucket *root_bucket, *last_bucket; -void -alloc_new_bucket() +static struct linked_list * +deref_linked_list (struct linked_list **plist) { - Bucket *bp; - - bp = malloc(sizeof(*bp) + sizeof(Cons)*(bucket_nodes-1)); - if (!bp) - return; - bp->next = NULL; - bp->free = 0; - if (!root_bucket) - root_bucket = last_bucket = bp; - else { - last_bucket->next = bp; - last_bucket = bp; + if (!*plist) { + struct linked_list *list = xmalloc(sizeof(*list)); + list->free_data = NULL; + list->head = list->tail = NULL; + *plist = list; } + return *plist; } -Consptr -alloc_cons_from_bucket() + +struct linked_list * +linked_list_create(linked_list_free_data_fp fun) { - if (!last_bucket || last_bucket->free == bucket_nodes) - return NULL; - return &last_bucket->cons[last_bucket->free++]; + struct linked_list *list = xmalloc(sizeof(*list)); + list->free_data = fun; + list->head = list->tail = NULL; + return list; } -Consptr -alloc_cons() +void +linked_list_append(struct linked_list **plist, void *data) { - Consptr cp; - - cp = alloc_cons_from_bucket(); - if (!cp) { - alloc_new_bucket(); - if ((cp = alloc_cons_from_bucket()) == NULL) { - error(2, 0, _("not enough core")); - } - } - CAR(cp) = CDR(cp) = NULL; - return cp; + struct linked_list *list = deref_linked_list (plist); + struct linked_list_entry *entry = xmalloc(sizeof(*entry)); + entry->next = NULL; + entry->data = data; + if (list->tail) + list->tail->next = entry; + else + list->head = entry; + list->tail = entry; } -/* Append a new cons to the tail of the list - * ROOT_PTR points to a `root cons'. - * CAR is the car value of the cons to be created. - * - * Note: Car of the root cons points to the head of the list, - * cdr of root cons points to the tail of the list. - */ -Consptr -append_to_list(Consptr *root_ptr, void *car) +void +linked_list_prepend(struct linked_list **plist, void *data) { - Consptr root, cons; - - if (!*root_ptr) { - *root_ptr = alloc_cons(); - /* both car and cdr are guaranteed to be NULL */ + struct linked_list *list = deref_linked_list (plist); + struct linked_list_entry *entry = xmalloc(sizeof(*entry)); + entry->next = list->head; + entry->data = data; + list->head = entry; + if (!list->tail) + list->tail = entry; } - root = *root_ptr; - cons = alloc_cons(); - if (!CAR(root)) - CAR(root) = cons; +void +linked_list_destroy(struct linked_list **plist) +{ + if (plist && *plist) { + struct linked_list *list = *plist; + struct linked_list_entry *p; - /* Maintain linked list */ - if (CDR(root)) - CDR(CDR(root)) = cons; - CDR(root) = cons; - CAR(cons) = car; - return cons; + for (p = list->head; p; p = p->next) { + if (list->free_data) + list->free_data(p->data); + free(p); + } + free(list); + *plist = NULL; + } } int -symbol_in_list(Symbol *sym, Consptr list) +symbol_in_list(Symbol *sym, struct linked_list *list) { - Consptr cons; + struct linked_list_entry *p; - if (!list) - return 0; - for (cons = CAR(list); cons; cons = CDR(cons)) - if ((Symbol*)CAR(cons) == sym) + for (p = linked_list_head(list); p; p = p->next) + if ((Symbol*)p->data == sym) return 1; return 0; } |