diff options
Diffstat (limited to 'scripts/genksyms/genksyms.c')
-rw-r--r-- | scripts/genksyms/genksyms.c | 71 |
1 files changed, 66 insertions, 5 deletions
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index 4a35081..f9e7553 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -62,6 +62,7 @@ static const struct { [SYM_ENUM] = {'e', "enum"}, [SYM_STRUCT] = {'s', "struct"}, [SYM_UNION] = {'u', "union"}, + [SYM_ENUM_CONST] = {'E', "enum constant"}, }; static int equal_list(struct string_list *a, struct string_list *b); @@ -149,10 +150,16 @@ static unsigned long crc32(const char *s) static enum symbol_type map_to_ns(enum symbol_type t) { - if (t == SYM_TYPEDEF) - t = SYM_NORMAL; - else if (t == SYM_UNION) - t = SYM_STRUCT; + switch (t) { + case SYM_ENUM_CONST: + case SYM_NORMAL: + case SYM_TYPEDEF: + return SYM_NORMAL; + case SYM_ENUM: + case SYM_STRUCT: + case SYM_UNION: + return SYM_STRUCT; + } return t; } @@ -191,10 +198,47 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type, struct string_list *defn, int is_extern, int is_reference) { - unsigned long h = crc32(name) % HASH_BUCKETS; + unsigned long h; struct symbol *sym; enum symbol_status status = STATUS_UNCHANGED; + /* The parser adds symbols in the order their declaration completes, + * so it is safe to store the value of the previous enum constant in + * a static variable. + */ + static int enum_counter; + static struct string_list *last_enum_expr; + + if (type == SYM_ENUM_CONST) { + if (defn) { + free_list(last_enum_expr, NULL); + last_enum_expr = copy_list_range(defn, NULL); + enum_counter = 1; + } else { + struct string_list *expr; + char buf[20]; + + snprintf(buf, sizeof(buf), "%d", enum_counter++); + if (last_enum_expr) { + expr = copy_list_range(last_enum_expr, NULL); + defn = concat_list(mk_node("("), + expr, + mk_node(")"), + mk_node("+"), + mk_node(buf), NULL); + } else { + defn = mk_node(buf); + } + } + } else if (type == SYM_ENUM) { + free_list(last_enum_expr, NULL); + last_enum_expr = NULL; + enum_counter = 0; + if (!name) + /* Anonymous enum definition, nothing more to do */ + return NULL; + } + h = crc32(name) % HASH_BUCKETS; for (sym = symtab[h]; sym; sym = sym->hash_next) { if (map_to_ns(sym->type) == map_to_ns(type) && strcmp(name, sym->name) == 0) { @@ -343,6 +387,22 @@ struct string_list *copy_node(struct string_list *node) return newnode; } +struct string_list *copy_list_range(struct string_list *start, + struct string_list *end) +{ + struct string_list *res, *n; + + if (start == end) + return NULL; + n = res = copy_node(start); + for (start = start->next; start != end; start = start->next) { + n->next = copy_node(start); + n = n->next; + } + n->next = NULL; + return res; +} + static int equal_list(struct string_list *a, struct string_list *b) { while (a && b) { @@ -512,6 +572,7 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc) crc = partial_crc32_one(' ', crc); break; + case SYM_ENUM_CONST: case SYM_TYPEDEF: subsym = find_symbol(cur->string, cur->tag, 0); /* FIXME: Bad reference files can segfault here. */ |