diff --git a/README.md b/README.md index 3f37011..10650d3 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ jnz r/i16 cmp r/i16 mov r/i16/m r mov r r/i16/m +movb m r +movb r m in r/i16 out r/i16 r/i16 call r/i16 diff --git a/asm/hash.c b/asm/hash.c new file mode 100644 index 0000000..7cf258b --- /dev/null +++ b/asm/hash.c @@ -0,0 +1,50 @@ +#include "hash.h" +#include +#include + +Hasher* hasher_new() +{ + Hasher* hasher = malloc(sizeof(Hasher)); + *hasher = (Hasher) {}; + return hasher; +} + +uint64_t hasher_finish(Hasher hasher) +{ + return hasher.state; +} + +void hasher_free(Hasher* hasher) +{ + free(hasher); +} + +void hasher_hash_u64(Hasher* hasher, uint64_t v) +{ + uint64_t value = hasher->state + v; + + value ^= value >> 33; + value *= 0xff51afd7ed558ccdL; + value ^= value >> 33; + value *= 0xc4ceb9fe1a85ec53L; + value ^= value >> 33; + + hasher->state = value; +} + +void hasher_hash_u8(Hasher* hasher, uint8_t v) +{ + hasher_hash_u64(hasher, v); +} + +void string_hash(Hasher* hasher, const char* str) +{ + for (size_t i = 0; str[i] != '\0'; ++i) { + hasher_hash_u8(hasher, (uint8_t)str[i]); + } +} + +void size_hash(Hasher* hasher, size_t value) +{ + hasher_hash_u64(hasher, (uint64_t)value); +} diff --git a/asm/hash.h b/asm/hash.h new file mode 100644 index 0000000..9f61bdd --- /dev/null +++ b/asm/hash.h @@ -0,0 +1,18 @@ +#ifndef HASH_H +#define HASH_H + +#include +#include + +typedef struct { + uint64_t state; +} Hasher; + +uint64_t hasher_finish(Hasher hasher); +void hasher_hash_u64(Hasher* hasher, uint64_t v); +void hasher_hash_u8(Hasher* hasher, uint8_t v); + +void string_hash(Hasher* hasher, const char* str); +void size_hash(Hasher* hasher, size_t value); + +#endif diff --git a/asm/main.c b/asm/main.c index a0baa2b..1511ac8 100644 --- a/asm/main.c +++ b/asm/main.c @@ -1,6 +1,10 @@ +#include "hash.h" +#include "map.h" #include "parse.h" #include "report.h" +#include "vec.h" #include +#include #include #include #include @@ -12,6 +16,15 @@ typedef struct { static int parse_args(Args* args, int argc, char** argv); +DEFINE_VEC(LineVec, line_vec, PLine*) + +typedef struct { + size_t line_idx; + char* ident; +} Label; + +DEFINE_STRINGMAP(LabelMap, label_map, Label) + static char* read_text_file(const char* filename); int main(int argc, char** argv) @@ -21,6 +34,8 @@ int main(int argc, char** argv) return EXIT_FAILURE; } + LabelMap labels = {}; + char* text = read_text_file(args.input_file); if (!text) { return EXIT_FAILURE; @@ -28,9 +43,10 @@ int main(int argc, char** argv) Parser* parser = parser_new(args.input_file, text); - size_t lines_capacity = 1024; - PLine** lines = malloc(sizeof(PLine*) * lines_capacity); - size_t lines_size = 0; + LineVec lines; + line_vec_construct(&lines); + + Label* super_label = nullptr; while (!parser_done(parser)) { if (parser_next_is_const(parser)) { @@ -41,10 +57,52 @@ int main(int argc, char** argv) } else { PLabel* label; - while ((label = parser_parse_label(parser)) != nullptr) { } + while ((label = parser_parse_label(parser)) != nullptr) { + if (label->local) { + char* ident = calloc(1, + strlen(super_label->ident) + strlen(label->ident) + 2); + strcat(ident, super_label->ident); + strcat(ident, "."); + strcat(ident, label->ident); + + label_map_set(&labels, + ident, + (Label) { + .line_idx = lines.size + 1, + .ident = ident, + }); + } else { + label_map_set(&labels, + label->ident, + (Label) { + .line_idx = lines.size + 1, + .ident = strdup(label->ident), + }); + super_label = label_map_at(&labels, label->ident); + } + plabel_free(label); + } + PLine* line = parser_parse_line(parser); + + line_vec_push(&lines, line); + + printf("ident = '%s'\n", line->ident); } } + parser_free(parser); + free(text); + + for (size_t i = 0; i < lines.size; ++i) { + pline_free(lines.data[i]); + } + line_vec_destroy(&lines); + + for (size_t i = 0; i < labels.entries.size; ++i) { + free(labels.entries.data[i].value.ident); + } + label_map_destroy(&labels); + return EXIT_SUCCESS; } diff --git a/asm/map.h b/asm/map.h new file mode 100644 index 0000000..f22f10f --- /dev/null +++ b/asm/map.h @@ -0,0 +1,106 @@ +#ifndef MAP +#define MAP + +#include "hash.h" +#include "vec.h" +#include +#include + +#define DEFINE_MAP(TYPENAME, FN_PREFIX, KEY_TYPE, VALUE_TYPE, HASH_FN) \ + \ + typedef struct { \ + uint64_t keyhash; \ + VALUE_TYPE value; \ + } _internal_TYPENAME##Entry; \ + \ + DEFINE_VEC(_internal_TYPENAME##EntryVec, \ + _internal_##FN_PREFIX##_entryvec, \ + _internal_TYPENAME##Entry) \ + \ + typedef struct { \ + _internal_TYPENAME##EntryVec entries; \ + } TYPENAME; \ + \ + [[maybe_unused]] static void FN_PREFIX##_construct(TYPENAME* map) \ + { \ + *map = (TYPENAME) {}; \ + } \ + \ + [[maybe_unused]] static void FN_PREFIX##_destroy(TYPENAME* map) \ + { \ + _internal_##FN_PREFIX##_entryvec_destroy(&map->entries); \ + } \ + \ + [[maybe_unused]] static bool _internal_##FN_PREFIX##_find_entry_idx( \ + TYPENAME* map, \ + size_t* target_idx, \ + uint64_t keyhash, \ + size_t begin, \ + size_t end) \ + { \ + if (begin == end) { \ + *target_idx = begin; \ + return false; \ + } \ + size_t middle_idx = (end - begin) / 2 + begin; \ + _internal_TYPENAME##Entry* middle_entry \ + = &map->entries.data[middle_idx]; \ + if (keyhash < middle_entry->keyhash) { \ + return _internal_##FN_PREFIX##_find_entry_idx( \ + map, target_idx, keyhash, begin, middle_idx); \ + } else if (keyhash > middle_entry->keyhash) { \ + return _internal_##FN_PREFIX##_find_entry_idx( \ + map, target_idx, keyhash, middle_idx + 1, end); \ + } else { \ + *target_idx = middle_idx; \ + return true; \ + } \ + } \ + \ + [[maybe_unused]] static void FN_PREFIX##_set( \ + TYPENAME* map, KEY_TYPE key, VALUE_TYPE value) \ + { \ + Hasher hasher = {}; \ + HASH_FN(&hasher, key); \ + uint64_t keyhash = hasher_finish(hasher); \ + \ + size_t target_idx; \ + bool exists = _internal_##FN_PREFIX##_find_entry_idx( \ + map, &target_idx, keyhash, 0, map->entries.size); \ + \ + if (exists) { \ + map->entries.data[target_idx].value = value; \ + return; \ + } \ + \ + _internal_##FN_PREFIX##_entryvec_push( \ + &map->entries, (_internal_TYPENAME##Entry) {}); \ + for (size_t i = map->entries.size - 1; i > target_idx; --i) { \ + map->entries.data[i] = map->entries.data[i - 1]; \ + } \ + map->entries.data[target_idx] \ + = (_internal_TYPENAME##Entry) { keyhash, value }; \ + } \ + \ + [[maybe_unused]] static VALUE_TYPE* FN_PREFIX##_at( \ + TYPENAME* map, KEY_TYPE key) \ + { \ + Hasher hasher = {}; \ + HASH_FN(&hasher, key); \ + uint64_t keyhash = hasher_finish(hasher); \ + \ + size_t target_idx; \ + bool exists = _internal_##FN_PREFIX##_find_entry_idx( \ + map, &target_idx, keyhash, 0, map->entries.size); \ + \ + if (!exists) { \ + return nullptr; \ + } \ + \ + return &map->entries.data[target_idx].value; \ + } + +#define DEFINE_STRINGMAP(TYPENAME, FN_PREFIX, VALUE_TYPE) \ + DEFINE_MAP(TYPENAME, FN_PREFIX, const char*, VALUE_TYPE, string_hash) + +#endif diff --git a/asm/parse.c b/asm/parse.c index 15b3844..7c75d78 100644 --- a/asm/parse.c +++ b/asm/parse.c @@ -812,3 +812,31 @@ void pexpr_free(PExpr* expr) } free(expr); } + +void pconst_free(PConst* stmt) +{ + free(stmt->ident); + pexpr_free(stmt->value); + free(stmt); +} + +void pinclude_free(PInclude* stmt) +{ + free(stmt->filename); + free(stmt); +} + +void plabel_free(PLabel* stmt) +{ + free(stmt->ident); + free(stmt); +} + +void pline_free(PLine* stmt) +{ + free(stmt->ident); + for (size_t i = 0; i < stmt->ops_size; ++i) { + pexpr_free(stmt->ops[i]); + } + free(stmt); +} diff --git a/asm/parse.h b/asm/parse.h index b75f29f..3eb32f0 100644 --- a/asm/parse.h +++ b/asm/parse.h @@ -50,17 +50,23 @@ typedef struct { PExpr* value; } PConst; +void pconst_free(PConst* stmt); + typedef struct { Loc loc; char* filename; } PInclude; +void pinclude_free(PInclude* stmt); + typedef struct { Loc loc; char* ident; bool local; } PLabel; +void plabel_free(PLabel* stmt); + typedef struct { Loc loc; char* ident; @@ -68,6 +74,8 @@ typedef struct { size_t ops_size; } PLine; +void pline_free(PLine* stmt); + typedef struct Parser Parser; Parser* parser_new(const char* filename, const char* text); diff --git a/asm/vec.h b/asm/vec.h new file mode 100644 index 0000000..946a196 --- /dev/null +++ b/asm/vec.h @@ -0,0 +1,40 @@ +#ifndef VEC_H +#define VEC_H + +#include +#include + +#define DEFINE_VEC(TYPENAME, FN_PREFIX, TYPE) \ + \ + typedef struct { \ + TYPE* data; \ + size_t size; \ + size_t capacity; \ + } TYPENAME; \ + \ + [[maybe_unused]] static void FN_PREFIX##_construct(TYPENAME* vec) \ + { \ + *vec = (TYPENAME) {}; \ + } \ + \ + [[maybe_unused]] static void FN_PREFIX##_destroy(TYPENAME* vec) \ + { \ + if (vec->data) { \ + free(vec->data); \ + } \ + } \ + \ + [[maybe_unused]] static void FN_PREFIX##_push(TYPENAME* vec, TYPE value) \ + { \ + if (!vec->data || vec->capacity == 0) { \ + vec->capacity = 4; \ + vec->data = malloc(sizeof(TYPE) * vec->capacity); \ + } else if (vec->size + 1 >= vec->capacity) { \ + vec->capacity *= 2; \ + vec->data = realloc(vec->data, sizeof(TYPE) * vec->capacity); \ + } \ + vec->data[vec->size] = value; \ + vec->size += 1; \ + } + +#endif