diff --git a/src/SConscript b/src/SConscript index 9b5c868c5f2966c9305139c4805245d8c1c85c26..03308dd9dcc7b0559ff3c89dfd5b429f5c4d3a9b 100644 --- a/src/SConscript +++ b/src/SConscript @@ -49,6 +49,7 @@ misc_hammer_parts = [ 'glue.c', 'hammer.c', 'pprint.c', + 'registry.c', 'system_allocator.c'] tests = ['t_benchmark.c', diff --git a/src/hammer.h b/src/hammer.h index 508653d8fcf213bf97e7dceec7460e3e55a2f1e7..0175142e509da61fadb79b36eb6095cac1265465 100644 --- a/src/hammer.h +++ b/src/hammer.h @@ -633,4 +633,15 @@ void h_benchmark_report(FILE* stream, HBenchmarkResults* results); void h_benchmark_dump_optimized_code(FILE* stream, HBenchmarkResults* results); // }}} +// {{{ Token type registry +/// Allocate a new, unused (as far as this function knows) token type. +int h_allocate_token_type(const char* name); + +/// Get the token type associated with name. Returns -1 if name is unkown +int h_get_token_type_number(const char* name); + +/// Get the name associated with token_type. Returns NULL if the token type is unkown +const char* h_get_token_type_name(int token_type); +// }}} + #endif // #ifndef HAMMER_HAMMER__H diff --git a/src/registry.c b/src/registry.c new file mode 100644 index 0000000000000000000000000000000000000000..c59b6ea9f6e0214c279d51b3997b5770278928bc --- /dev/null +++ b/src/registry.c @@ -0,0 +1,87 @@ +/* Parser combinators for binary formats. + * Copyright (C) 2012 Meredith L. Patterson, Dan "TQ" Hirsch + * + * This program 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, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <search.h> +#include <stdlib.h> +#include "hammer.h" +#include "internal.h" + +typedef struct Entry_ { + const char* name; + int value; +} Entry; + +static void *tt_registry = NULL; +static Entry** tt_by_id = NULL; +static int tt_by_id_sz = 0; +#define TT_START TT_USER +static int tt_next = TT_START; + +/* + // TODO: These are for the extension registry, which does not yet have a good name. +static void *ext_registry = NULL; +static Entry** ext_by_id = NULL; +static int ext_by_id_sz = 0; +static int ext_next = 0; +*/ + + +static int compare_entries(const void* v1, const void* v2) { + const Entry *e1 = (Entry*)v1, *e2 = (Entry*)v2; + return strcmp(e1->name, e2->name); +} + +int h_allocate_token_type(const char* name) { + Entry* new_entry = malloc(sizeof(*new_entry)); + new_entry->name = name; + new_entry->value = -1; + Entry* probe = *(Entry**)tsearch(new_entry, &tt_registry, compare_entries); + if (probe->value != -1) { + // Token type already exists... + // TODO: treat this as a bug? + free(new_entry); + return probe->value; + } else { + // new value + probe->name = strdup(probe->name); // drop ownership of name + probe->value = tt_next++; + if ((probe->value - TT_START) >= tt_by_id_sz) { + if (tt_by_id_sz == 0) + tt_by_id = malloc(sizeof(*tt_by_id) * ((tt_by_id_sz = (tt_next - TT_START) * 16))); + else + tt_by_id = realloc(tt_by_id, sizeof(*tt_by_id) * ((tt_by_id_sz *= 2))); + } + assert(probe->value - TT_START < tt_by_id_sz); + tt_by_id[probe->value - TT_START] = probe; + return probe->value; + } +} +int h_get_token_type_number(const char* name) { + Entry e; + e.name = name; + Entry **ret = (Entry**)tfind(&e, &tt_registry, compare_entries); + if (ret == NULL) + return -1; + else + return (*ret)->value; +} +const char* h_get_token_type_name(int token_type) { + if (token_type >= tt_next || token_type < TT_START) + return NULL; + else + return tt_by_id[token_type - TT_START]->name; +} diff --git a/src/t_misc.c b/src/t_misc.c index c762c07380bc36db4426c6877d784f329d2ac0bd..74a57ca9b438e75fcbf222b4bbbc79a951c39022 100644 --- a/src/t_misc.c +++ b/src/t_misc.c @@ -1,4 +1,5 @@ #include <glib.h> +#include <string.h> #include "test_suite.h" #include "hammer.h" @@ -11,6 +12,24 @@ static void test_tt_user(void) { g_check_cmp_int32(TT_USER, >, TT_ERR); } +static void test_tt_registry(void) { + int id = h_allocate_token_type("com.upstandinghackers.test.token_type"); + g_check_cmp_int32(id, >=, TT_USER); + int id2 = h_allocate_token_type("com.upstandinghackers.test.token_type_2"); + g_check_cmp_int32(id2, !=, id); + g_check_cmp_int32(id2, >=, TT_USER); + g_check_cmp_int32(id, ==, h_get_token_type_number("com.upstandinghackers.test.token_type")); + g_check_cmp_int32(id2, ==, h_get_token_type_number("com.upstandinghackers.test.token_type_2")); + g_check_string("com.upstandinghackers.test.token_type", ==, h_get_token_type_name(id)); + g_check_string("com.upstandinghackers.test.token_type_2", ==, h_get_token_type_name(id2)); + if (h_get_token_type_name(0) != NULL) { + g_test_message("Unknown token type should not return a name"); + g_test_fail(); + } + g_check_cmp_int32(h_get_token_type_number("com.upstandinghackers.test.unkown_token_type"), ==, -1); +} + void register_misc_tests(void) { g_test_add_func("/core/misc/tt_user", test_tt_user); + g_test_add_func("/core/misc/tt_registry", test_tt_registry); }