#include "dseg.h" #include #include #include #define DSEG_PANIC(msg) {fprintf(stderr, "dseg error: " msg "\n"); exit(1);} #define DEFAULT_SIZE 16 #define STRING_PATTERN "str%llu" static integral_t string_counter = 0; static integral_t hash_string(const char* str, integral_t cap) { integral_t hash = 0, i = 0; while (str[i] != 0) ADVANCE_HASH(hash, str[i++], cap); return hash; } static integral_t hash_ent(const struct dseg_entry* ent, integral_t cap) { switch (ent->type) { case ENT_STRING: return hash_string(ent->key.string, cap); } DSEG_PANIC("hash function not defined for entry type"); } static bool ent_eq(const struct dseg_entry* a, const struct dseg_entry* b) { if (a->type != b->type) return false; switch (a->type) { case ENT_STRING: return strcmp(a->key.string, b->key.string) == 0; } DSEG_PANIC("equality function not defined for entry type"); } static void ent_destroy(struct dseg_entry* entry) { free(entry->symbol); } void dseg_init(struct hash_map* dseg) { hm_init( dseg, (hm_hash_fn) hash_ent, (hm_eq_fn) ent_eq, (hm_destroy_fn) ent_destroy); } void dseg_destroy(struct hash_map* dseg) { hm_destroy(dseg); } static void ent_assign_key(struct dseg_entry* ent) { switch (ent->type) { case ENT_STRING: integral_t strnum = string_counter++; int req_sz = snprintf(NULL, 0, STRING_PATTERN, strnum); if (req_sz < 0) CCC_PANIC; req_sz += 1; // null terminator ent->symbol = ccc_alloc(req_sz); snprintf(ent->symbol, req_sz, STRING_PATTERN, strnum); break; } } const char* dseg_put(struct hash_map* dseg, struct dseg_entry entry) { struct dseg_entry** cell = (struct dseg_entry**) hm_cell_w(dseg, &entry); if (*cell != NULL) return (*cell)->symbol; struct dseg_entry* new_ent = ccc_alloc(sizeof(struct dseg_entry)); *cell = new_ent; *new_ent = entry; ent_assign_key(new_ent); return new_ent->symbol; } static inline bool is_printable(char c) { return ' ' <= c && c <= '~'; } void emit_string_data(FILE* outfile, const struct dseg_entry* ent) { const char* str = ent->key.string; fprintf(outfile, "db "); for (integral_t i = 0; str[i] != 0;) { if (is_printable(str[i])) { fprintf(outfile, "\"%c", str[i]); while (is_printable(str[++i])) fputc(str[i], outfile); fprintf(outfile, "\", "); } else { fprintf(outfile, "0x%x, ", str[i++]); } } fprintf(outfile, "0x0"); } void emit_dseg(FILE* outfile, const struct hash_map* dseg) { fprintf(outfile, "section .data\n"); for (integral_t i = 0; i < dseg->cap; i++) { const struct dseg_entry* ent = dseg->entries[i]; if (ent == NULL) continue; fprintf(outfile, "\t%s ", ent->symbol); switch (ent->type) { case ENT_STRING: emit_string_data(outfile, ent); break; } fprintf(outfile, "\n"); } }