summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Sotoudeh <matthew@masot.net>2024-04-06 22:26:40 -0700
committerMatthew Sotoudeh <matthew@masot.net>2024-04-06 22:26:40 -0700
commit3b2c111d0250a341c5bfd4faa9ba1e84dd1f6321 (patch)
tree792af37d406dd48462a8fc8185b6e0130b5eefe1
parent2a6b1e134982847f1b6d90fd1e163a16821a4a6e (diff)
support source-level line numbers
-rw-r--r--gamma_version/examples/Makefile3
-rw-r--r--gamma_version/examples/hashmap_line_nos.c110
-rw-r--r--gamma_version/gamma.h4
-rw-r--r--gamma_version/lexer.l44
-rw-r--r--gamma_version/mangler.c1
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) {
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback