diff options
author | Matthew Sotoudeh <matthew@masot.net> | 2024-04-06 22:26:40 -0700 |
---|---|---|
committer | Matthew Sotoudeh <matthew@masot.net> | 2024-04-06 22:26:40 -0700 |
commit | 3b2c111d0250a341c5bfd4faa9ba1e84dd1f6321 (patch) | |
tree | 792af37d406dd48462a8fc8185b6e0130b5eefe1 | |
parent | 2a6b1e134982847f1b6d90fd1e163a16821a4a6e (diff) |
support source-level line numbers
-rw-r--r-- | gamma_version/examples/Makefile | 3 | ||||
-rw-r--r-- | gamma_version/examples/hashmap_line_nos.c | 110 | ||||
-rw-r--r-- | gamma_version/gamma.h | 4 | ||||
-rw-r--r-- | gamma_version/lexer.l | 44 | ||||
-rw-r--r-- | gamma_version/mangler.c | 1 |
5 files changed, 161 insertions, 1 deletions
diff --git a/gamma_version/examples/Makefile b/gamma_version/examples/Makefile new file mode 100644 index 0000000..99f74ff --- /dev/null +++ b/gamma_version/examples/Makefile @@ -0,0 +1,3 @@ +GC ?= ../build/gc +CC:=$(GC) $(CC) +LD:=$(GC) $(LD) diff --git a/gamma_version/examples/hashmap_line_nos.c b/gamma_version/examples/hashmap_line_nos.c new file mode 100644 index 0000000..2c142e2 --- /dev/null +++ b/gamma_version/examples/hashmap_line_nos.c @@ -0,0 +1,110 @@ +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +// stores pointers-to-T +struct hashmap![type T] { + size_t capacity; + size_t count; + T **items; +}; + +unsigned long hashmap_hash![type T](T *a); +int hashmap_eq![type T](T *a, T *b); + +struct hashmap![T] *hashmap_init![type T]() { + struct hashmap![T] *hmap = calloc(1, sizeof(*hmap)); + hmap->capacity = 4; + hmap->count = 0; + hmap->items = calloc(hmap->capacity, sizeof(T*)); + return hmap; +} + +void hashmap_insert![type T](struct hashmap![T] *h, T *item) { + if ((h->count * 2) == h->capacity) { + size_t old_capacity = h->capacity; + T **old_items = h->items; + + h->capacity = h->capacity * 2; + h->count = 0; + h->items = calloc(h->capacity, sizeof(T*)); + for (size_t i = 0; i < old_capacity; i++) + hashmap_insert![T](h, old_items[i]); + } + + h->count += 1; + + size_t mask = h->capacity - 1; + size_t i = hashmap_hash![T](item) & mask; + while (h->items[i]) { + if (hashmap_eq![T](h->items[i], item)) return; + i = (i + 1) & mask; + } + h->items[i] = item; +} + +T *hashmap_find![type T](struct hashmap![T] *h, T *item) { + size_t mask = h->capacity - 1; + size_t i = hashmap_hash![T](item) & mask; + while (h->items[i]) { + if (hashmap_eq![T](h->items[i], item)) return h->items[i]; + i = (i + 1) & mask; + } + return 0; +} + +unsigned long hashmap_hash![const char *](const char **a) { + const char *s = *a; + // djb2 + unsigned long h = 5381; + while (*s) + h = ((h << 5) + h) + (unsigned long)(unsigned char)(*(s++)); + return h; +} +int hashmap_eq![const char *](const char **a, const char **b) { + return !strcmp(*a, *b); +} + +unsigned long hashmap_hash![int](int *a) { + return (unsigned long)*a; +} +int hashmap_eq![int](int *a, int *b) { return *a == *b; } + +T *heapify![type T](T x) { + T *heap = calloc(1, sizeof(x)); + *heap = x; + return heap; +} + +int main() { + struct hashmap![const char *] *hmap = hashmap_init![const char *](); + const char *hello = "Hello, World!"; + const char *goodbye = "Goodbye, World!"; + hashmap_insert![const char *](hmap, &hello); + if (hashmap_find![const char *](hmap, &hello)) { + printf("PASS: Found!\n"); + } else { + printf("Bad :(\n"); + } + if (!hashmap_find![const char *](hmap, &goodbye)) { + printf("PASS: Not Found!\n"); + } else { + printf("Bad :(\n"); + } + + struct hashmap![int] *intmap = hashmap_init![int](); + hashmap_insert![int](intmap, heapify![int](123)); + if (hashmap_find![int](intmap, heapify![int](123))) { + printf("PASS: Found!\n"); + } else { + printf("Bad :(\n"); + } + if (!hashmap_find![int](intmap, heapify![int](456))) { + printf("PASS: Not Found!\n"); + } else { + printf("Bad :(\n"); + } + + return 0; +} diff --git a/gamma_version/gamma.h b/gamma_version/gamma.h index 6ec36ce..673636b 100644 --- a/gamma_version/gamma.h +++ b/gamma_version/gamma.h @@ -59,6 +59,10 @@ struct call { struct chunk { char *start; char *end; + + char *line_filename; + size_t line; + struct call *defining_call; struct call *calls; struct chunk *next; diff --git a/gamma_version/lexer.l b/gamma_version/lexer.l index fa22744..1e61acf 100644 --- a/gamma_version/lexer.l +++ b/gamma_version/lexer.l @@ -22,6 +22,11 @@ uint32_t DEPTH = 0; char *FILE_PTR = 0; yyscan_t SCANNER; +// location of the last known line mark +char *LINE_MARK = 0; +char *LINE_FILE = 0; +size_t LINE = 0; + // https://stackoverflow.com/questions/47094667/getting-the-current-index-in-the-input-string-flex-lexer #define YY_USER_ACTION FILE_PTR += yyleng; @@ -39,7 +44,32 @@ void maybe_end_call(); ;[ \n\t\r]* { maybe_end_chunk(); } [)] { DEPTH--; } -^#([^\n]|[\\][\n])*?\n { } +^#([^\n]|[\\][\n])*?\n { + char *lineproc_start = FILE_PTR - yyget_leng(SCANNER); + + // check we've got two quotes + int n_quotes = 0; + for (char *c = lineproc_start; c < FILE_PTR; c++) { + n_quotes += (*c == '"'); + } + + if (n_quotes == 2) { + LINE_MARK = FILE_PTR; + sscanf(lineproc_start + 1, " %lu ", &LINE); + LINE_FILE = calloc(yyget_leng(SCANNER), sizeof(char) + 1); + while (*lineproc_start != '"') { + lineproc_start++; + assert(lineproc_start < FILE_PTR); + } + lineproc_start++; + int i = 0; + while (*lineproc_start != '"') { + LINE_FILE[i++] = *lineproc_start; + lineproc_start++; + assert(lineproc_start < FILE_PTR); + } + } +} \/\/.*\n { } \\\n { } \n { } @@ -84,6 +114,14 @@ void maybe_end_chunk() { CHUNK = CHUNK->next; CHUNK->start = FILE_PTR; NEXT_CALL = &(CHUNK->calls); + + // bring the line info up to the current location + while (LINE_MARK < FILE_PTR) { + LINE += (*LINE_MARK == '\n'); + LINE_MARK++; + } + CHUNK->line_filename = LINE_FILE; + CHUNK->line = LINE; } struct chunked_file *chunk(const char *path) { struct stat statbuf; @@ -99,6 +137,10 @@ struct chunked_file *chunk(const char *path) { CHUNK->start = FILE_PTR; NEXT_CALL = &(CHUNK->calls); + LINE_MARK = FILE_PTR; + LINE_FILE = CHUNK->line_filename = strdup(path); + LINE = CHUNK->line = 1; + char *zero_term = strndup(CHUNKED_FILE->contents, CHUNKED_FILE->end - CHUNKED_FILE->contents); yylex_init(&SCANNER); diff --git a/gamma_version/mangler.c b/gamma_version/mangler.c index 4c87102..bfe2a6f 100644 --- a/gamma_version/mangler.c +++ b/gamma_version/mangler.c @@ -32,6 +32,7 @@ struct uniq_string *read_ident(char *start, char *end, size_t *len) { void print_chunk(struct chunk *chunk, struct call *instantiation, FILE *out) { struct call *call = chunk->calls; + fprintf(out, "\n#line %lu \"%s\"\n", chunk->line, chunk->line_filename); for (char *c = chunk->start; c != chunk->end; c++) { if (call && c == call->start) { if (chunk->defining_call) { |