diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common.h | 31 | ||||
-rw-r--r-- | src/darray.h | 81 | ||||
-rw-r--r-- | src/errors.c | 68 | ||||
-rw-r--r-- | src/errors.h | 54 | ||||
-rw-r--r-- | src/hashtable.h | 180 | ||||
-rw-r--r-- | src/main.c | 95 | ||||
-rw-r--r-- | src/nodes.c | 133 | ||||
-rw-r--r-- | src/nodes.h | 88 | ||||
-rw-r--r-- | src/string_view.c | 49 | ||||
-rw-r--r-- | src/string_view.h | 28 | ||||
-rw-r--r-- | src/viz.c | 350 | ||||
-rw-r--r-- | src/x86asm_compiler.h (renamed from src/compiler.h) | 0 |
12 files changed, 89 insertions, 1068 deletions
diff --git a/src/common.h b/src/common.h deleted file mode 100644 index 08e78a8..0000000 --- a/src/common.h +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | #ifndef BDL_COMMON_H | ||
2 | #define BDL_COMMON_H | ||
3 | |||
4 | #include <assert.h> | ||
5 | #include <stdbool.h> | ||
6 | #include <stddef.h> | ||
7 | #include <stdint.h> | ||
8 | |||
9 | typedef uint8_t u8; | ||
10 | typedef uint16_t u16; | ||
11 | typedef uint32_t u32; | ||
12 | typedef uint64_t u64; | ||
13 | typedef int8_t s8; | ||
14 | typedef int16_t s16; | ||
15 | typedef int32_t s32; | ||
16 | typedef int64_t s64; | ||
17 | typedef volatile u8 vu8; | ||
18 | typedef volatile u16 vu16; | ||
19 | typedef volatile u32 vu32; | ||
20 | typedef volatile u64 vu64; | ||
21 | typedef volatile s8 vs8; | ||
22 | typedef volatile s16 vs16; | ||
23 | typedef volatile s32 vs32; | ||
24 | typedef volatile s64 vs64; | ||
25 | |||
26 | #define KB(N) ((u64)(N) * 1024) | ||
27 | #define MB(N) ((u64)KB(N) * 1024) | ||
28 | #define GB(N) ((u64)MB(N) * 1024) | ||
29 | #define TB(N) ((u64)GB(N) * 1024) | ||
30 | |||
31 | #endif // BDL_COMMON_H | ||
diff --git a/src/darray.h b/src/darray.h deleted file mode 100644 index fa4e293..0000000 --- a/src/darray.h +++ /dev/null | |||
@@ -1,81 +0,0 @@ | |||
1 | #ifndef BDL_DARRAY_H | ||
2 | #define BDL_DARRAY_H | ||
3 | |||
4 | #include <string.h> | ||
5 | |||
6 | typedef struct ArrayHeader { | ||
7 | size_t size; | ||
8 | size_t cap; | ||
9 | } ArrayHeader; | ||
10 | |||
11 | // Header/Size/capacity accessors. | ||
12 | #define array_head(ARR) ((ArrayHeader *)((char *)(ARR) - sizeof(ArrayHeader))) | ||
13 | #define array_size(ARR) ((ARR) ? array_head(ARR)->size : 0) | ||
14 | #define array_cap(ARR) ((ARR) ? array_head(ARR)->cap : 0) | ||
15 | |||
16 | // Initialize a dynamic array ARR with N elements. The initialization doesn't | ||
17 | // zero out the data, so thread carefully.. | ||
18 | #define array_init(ARR,N) ((ARR) = _array_reserve(N, sizeof(*(ARR)))) | ||
19 | |||
20 | // Push a given element T to the dynamic array ARR. | ||
21 | #define array_push(ARR, T) \ | ||
22 | ((ARR) = _array_maybe_grow(ARR, sizeof(T)), \ | ||
23 | (ARR)[array_head(ARR)->size++] = (T)) | ||
24 | |||
25 | // Return the last element of the array. Can be used to build stacks. | ||
26 | #define array_pop(ARR) (ARR)[--array_head(ARR)->size] | ||
27 | |||
28 | // Return the value stored at the OFFSET position from the tail of the array. | ||
29 | #define array_peek(ARR, OFFSET) (ARR)[array_head(ARR)->size - 1 - (OFFSET)] | ||
30 | |||
31 | // Insert N bytes from the SRC array into the ARR dynamic array. | ||
32 | #define array_insert(ARR, SRC, N) \ | ||
33 | ((ARR) = _array_insert(ARR, SRC, N, sizeof(*(ARR)))) | ||
34 | |||
35 | // Free the memory from the original allocated position. | ||
36 | #define array_free(ARR) ((ARR) ? free(array_head(ARR)), (ARR) = NULL : 0) | ||
37 | |||
38 | static inline void * | ||
39 | _array_reserve(size_t num_elem, size_t type_size) { | ||
40 | char *p = malloc(num_elem * type_size + sizeof(ArrayHeader)); | ||
41 | p += sizeof(ArrayHeader); | ||
42 | array_head(p)->size = 0; | ||
43 | array_head(p)->cap = num_elem; | ||
44 | return p; | ||
45 | } | ||
46 | |||
47 | static inline void * | ||
48 | _array_maybe_grow(void *arr, size_t type_size) { | ||
49 | ArrayHeader *head = array_head(arr); | ||
50 | if (head->cap == head->size) { | ||
51 | if (head->cap == 0) { | ||
52 | head->cap++; | ||
53 | } else { | ||
54 | head->cap *= 2; | ||
55 | } | ||
56 | head = realloc(head, head->cap * type_size + sizeof(ArrayHeader)); | ||
57 | } | ||
58 | arr = (char *)head + sizeof(ArrayHeader); | ||
59 | return arr; | ||
60 | } | ||
61 | |||
62 | static inline | ||
63 | char * _array_insert(char *arr, const char *src, size_t n_bytes, size_t type_size) { | ||
64 | ArrayHeader *head = array_head(arr); | ||
65 | size_t new_size = n_bytes + head->size; | ||
66 | if (new_size > head->cap * type_size) { | ||
67 | if (head->cap == 0) { | ||
68 | head->cap = 1; | ||
69 | } | ||
70 | while (new_size >= head->cap * type_size) { | ||
71 | head->cap *= 2; | ||
72 | } | ||
73 | head = realloc(head, head->cap * type_size + sizeof(ArrayHeader)); | ||
74 | } | ||
75 | arr = (char *)head + sizeof(ArrayHeader); | ||
76 | memcpy((arr + head->size), src, n_bytes); | ||
77 | head->size = new_size; | ||
78 | return arr; | ||
79 | } | ||
80 | |||
81 | #endif // BDL_DARRAY_H | ||
diff --git a/src/errors.c b/src/errors.c deleted file mode 100644 index e854cf0..0000000 --- a/src/errors.c +++ /dev/null | |||
@@ -1,68 +0,0 @@ | |||
1 | #include "errors.h" | ||
2 | |||
3 | static const char* error_msgs[] = { | ||
4 | [ERR_UNKNOWN] = "error: something unexpected happened", | ||
5 | [ERR_UNMATCHED_STRING] = "error: unmatched string delimiter", | ||
6 | [ERR_UNMATCHED_PAREN] = "error: unbalanced parentheses", | ||
7 | [ERR_UNKNOWN_TOK_TYPE] = "error: unknown token type", | ||
8 | [ERR_MALFORMED_NUMBER] = "error: malformed number token", | ||
9 | [ERR_MALFORMED_EXPR] = "error: malformed expression", | ||
10 | [ERR_UNIMPLEMENTED] = "error: not implemented", | ||
11 | [ERR_NOT_A_NUMBER] = "error: expected a number", | ||
12 | [ERR_NOT_A_SYMBOL] = "error: expected a symbol", | ||
13 | [ERR_NOT_A_STRING] = "error: expected a string", | ||
14 | [ERR_NOT_A_TYPE] = "error: expected a type", | ||
15 | [ERR_NOT_A_BOOL] = "error: expected a bool", | ||
16 | [ERR_NOT_A_LPAREN] = "error: expected opening parentheses (lparen)", | ||
17 | [ERR_NOT_A_RPAREN] = "error: expected closing parentheses (rparen)", | ||
18 | [ERR_SYMBOL_REDEF] = "error: symbol redefinition", | ||
19 | [ERR_UNKNOWN_SYMBOL] = "error: unknown symbol", | ||
20 | [ERR_TYPE_REDEF] = "error: type redefinition", | ||
21 | [ERR_UNKNOWN_TYPE] = "error: unknown type", | ||
22 | [ERR_WRONG_RET_TYPE] = "error: return type don't match type signature", | ||
23 | [ERR_WRONG_COND_TYPE] = "error: conditional expression is not boolean", | ||
24 | [ERR_WRONG_TYPE_T_F] = "error: unmatched types between true and false expression", | ||
25 | [ERR_WRONG_TYPE_NUM] = "error: non numeric argument types", | ||
26 | [ERR_WRONG_TYPE_BOOL] = "error: non bool argument types", | ||
27 | [ERR_WRONG_TYPE_FUN] = "error: not a function", | ||
28 | [ERR_BAD_ARGS] = "error: arguments don't match expected types", | ||
29 | [ERR_TYPE_MISMATCH] = "error: type mismatch", | ||
30 | }; | ||
31 | |||
32 | static Error current_error = {.value = ERR_OK}; | ||
33 | |||
34 | void | ||
35 | push_error(ErrorType type, ErrorValue value, size_t line, size_t col) { | ||
36 | if (has_errors()) { | ||
37 | return; | ||
38 | } | ||
39 | current_error.type = type; | ||
40 | current_error.value = value; | ||
41 | current_error.line = line; | ||
42 | current_error.col = col; | ||
43 | } | ||
44 | |||
45 | bool | ||
46 | has_errors(void) { | ||
47 | return current_error.value != ERR_OK; | ||
48 | } | ||
49 | |||
50 | void | ||
51 | check_errors(const char *file_name) { | ||
52 | if (!has_errors()) { | ||
53 | return; | ||
54 | } | ||
55 | fprintf(stderr, "%s", file_name); | ||
56 | if (current_error.line != 0) { | ||
57 | fprintf(stderr, ":%ld:%ld", current_error.line, current_error.col); | ||
58 | } | ||
59 | switch (current_error.type) { | ||
60 | case ERR_TYPE_LEXER: { fprintf(stderr, ": [lexer] "); } break; | ||
61 | case ERR_TYPE_PARSER: { fprintf(stderr, ": [parser] "); } break; | ||
62 | case ERR_TYPE_SEMANTIC: { fprintf(stderr, ": [semantic] "); } break; | ||
63 | case ERR_TYPE_BASM: { fprintf(stderr, ": [basm] "); } break; | ||
64 | default: break; | ||
65 | } | ||
66 | fprintf(stderr, "%s\n", error_msgs[current_error.value]); | ||
67 | exit(EXIT_FAILURE); | ||
68 | } | ||
diff --git a/src/errors.h b/src/errors.h deleted file mode 100644 index 8ddba25..0000000 --- a/src/errors.h +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | #ifndef BDL_ERRORS_H | ||
2 | #define BDL_ERRORS_H | ||
3 | |||
4 | #include "common.h" | ||
5 | |||
6 | typedef enum ErrorType { | ||
7 | ERR_TYPE_LEXER, | ||
8 | ERR_TYPE_PARSER, | ||
9 | ERR_TYPE_SEMANTIC, | ||
10 | ERR_TYPE_BASM, | ||
11 | } ErrorType; | ||
12 | |||
13 | typedef enum ErrorValue { | ||
14 | ERR_UNKNOWN = 0, | ||
15 | ERR_UNMATCHED_STRING, | ||
16 | ERR_UNKNOWN_TOK_TYPE, | ||
17 | ERR_UNMATCHED_PAREN, | ||
18 | ERR_MALFORMED_NUMBER, | ||
19 | ERR_MALFORMED_EXPR, | ||
20 | ERR_UNIMPLEMENTED, | ||
21 | ERR_NOT_A_NUMBER, | ||
22 | ERR_NOT_A_SYMBOL, | ||
23 | ERR_NOT_A_STRING, | ||
24 | ERR_NOT_A_TYPE, | ||
25 | ERR_NOT_A_BOOL, | ||
26 | ERR_NOT_A_LPAREN, | ||
27 | ERR_NOT_A_RPAREN, | ||
28 | ERR_SYMBOL_REDEF, | ||
29 | ERR_UNKNOWN_SYMBOL, | ||
30 | ERR_TYPE_REDEF, | ||
31 | ERR_UNKNOWN_TYPE, | ||
32 | ERR_WRONG_RET_TYPE, | ||
33 | ERR_WRONG_COND_TYPE, | ||
34 | ERR_WRONG_TYPE_T_F, | ||
35 | ERR_WRONG_TYPE_NUM, | ||
36 | ERR_WRONG_TYPE_BOOL, | ||
37 | ERR_WRONG_TYPE_FUN, | ||
38 | ERR_TYPE_MISMATCH, | ||
39 | ERR_BAD_ARGS, | ||
40 | ERR_OK, | ||
41 | } ErrorValue; | ||
42 | |||
43 | typedef struct Error { | ||
44 | ErrorType type; | ||
45 | ErrorValue value; | ||
46 | size_t line; | ||
47 | size_t col; | ||
48 | } Error; | ||
49 | |||
50 | void push_error(ErrorType type, ErrorValue value, size_t line, size_t col); | ||
51 | void check_errors(const char *file_name); | ||
52 | bool has_errors(void); | ||
53 | |||
54 | #endif // BDL_ERRORS_H | ||
diff --git a/src/hashtable.h b/src/hashtable.h deleted file mode 100644 index faa8591..0000000 --- a/src/hashtable.h +++ /dev/null | |||
@@ -1,180 +0,0 @@ | |||
1 | #ifndef BDL_HASHTABLE_H | ||
2 | #define BDL_HASHTABLE_H | ||
3 | |||
4 | #include "darray.h" | ||
5 | |||
6 | // Minimum table capacity. | ||
7 | #define HT_MIN_CAP 4 | ||
8 | #define HT_MIN_SHIFT 2 | ||
9 | |||
10 | // Adjust the load factor threshold at which the table will grow on insertion. | ||
11 | #define HT_LOAD_THRESHOLD 0.8 | ||
12 | |||
13 | typedef struct HashTablePair { | ||
14 | void *key; | ||
15 | void *value; | ||
16 | } HashTablePair; | ||
17 | |||
18 | struct HashTable; | ||
19 | typedef uint64_t (HashFunction)(const struct HashTable *table, void *bytes); | ||
20 | typedef bool (EqFunc)(void *a, void *b); | ||
21 | |||
22 | typedef struct HashTable { | ||
23 | // All available key-value pairs as a dynamic array. | ||
24 | HashTablePair *pairs; | ||
25 | |||
26 | // Hash function. | ||
27 | HashFunction *hash_func; | ||
28 | |||
29 | // Equality function. | ||
30 | EqFunc *eq_func; | ||
31 | |||
32 | // This table expects the number of buckets to grow in powers of two. To | ||
33 | // speedup the default hashing, we memoize the number of bits equivalent to | ||
34 | // that power of 2: | ||
35 | // | ||
36 | // cap := 1024 = 2 ^ 10, shift_amount := 10 | ||
37 | // | ||
38 | uint8_t shift_amount; | ||
39 | } HashTable; | ||
40 | |||
41 | // Hash a byte stream using a circular shift + XOR hash function. | ||
42 | static inline uint64_t | ||
43 | _xor_shift_hash(const char *key, size_t n) { | ||
44 | uint64_t hash = 0x65d9d65f6a19574f; | ||
45 | char *last = (char *)key + n; | ||
46 | while (key != last) { | ||
47 | hash ^= (uint64_t)*key++; | ||
48 | hash = (hash << 8) | (hash >> (64 - 8)); | ||
49 | } | ||
50 | return hash; | ||
51 | } | ||
52 | |||
53 | // Use Fibonacci hashing to map a hash to a value in range of the table. | ||
54 | static inline uint64_t | ||
55 | _fibonacci_hash(uint64_t hash, size_t shift_amount) { | ||
56 | return (hash * UINT64_C(11400714819323198485)) >> (64 - shift_amount); | ||
57 | } | ||
58 | |||
59 | static inline float | ||
60 | ht_load_factor(const HashTable *table) { | ||
61 | return (float)array_size(table->pairs) / (float)array_cap(table->pairs); | ||
62 | } | ||
63 | |||
64 | HashTable * | ||
65 | ht_init(HashFunction *hash_func, EqFunc *eq_func) { | ||
66 | HashTable *table = malloc(sizeof(HashTable)); | ||
67 | *table = (HashTable){0}; | ||
68 | array_init(table->pairs, HT_MIN_CAP); | ||
69 | for (size_t i = 0; i < array_cap(table->pairs); i++) { | ||
70 | table->pairs[i] = (HashTablePair){NULL, NULL}; | ||
71 | } | ||
72 | table->shift_amount = HT_MIN_SHIFT; | ||
73 | table->hash_func = hash_func; | ||
74 | table->eq_func = eq_func; | ||
75 | return table; | ||
76 | } | ||
77 | |||
78 | void | ||
79 | _ht_insert(HashTable *table, void *key, void *value) { | ||
80 | size_t position = table->hash_func(table, key); | ||
81 | size_t probe_position = position; | ||
82 | |||
83 | // Verify the key in that position is free. If not, use linear probing to | ||
84 | // find the next free slot. | ||
85 | HashTablePair *pairs = table->pairs; | ||
86 | bool update = false; | ||
87 | while (true) { | ||
88 | if (pairs[probe_position].key == NULL) { | ||
89 | array_head(pairs)->size++; | ||
90 | break; | ||
91 | } | ||
92 | if (table->eq_func(pairs[probe_position].key, key)) { | ||
93 | update = true; | ||
94 | break; | ||
95 | } | ||
96 | if (probe_position == array_cap(pairs) - 1) { | ||
97 | probe_position = 0; | ||
98 | } else { | ||
99 | probe_position++; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | if (!update) { | ||
104 | pairs[probe_position].key = key; | ||
105 | pairs[probe_position].value = value; | ||
106 | } else { | ||
107 | pairs[probe_position].value = value; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | void | ||
112 | _ht_maybe_grow(HashTable *table) { | ||
113 | if (ht_load_factor(table) < HT_LOAD_THRESHOLD) { | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | // Create a new array with 2x capacity. | ||
118 | HashTablePair *old_pairs = table->pairs; | ||
119 | table->pairs = NULL; | ||
120 | array_init(table->pairs, array_cap(old_pairs) * 2); | ||
121 | for (size_t i = 0; i < array_cap(table->pairs); i++) { | ||
122 | table->pairs[i] = (HashTablePair){NULL, NULL}; | ||
123 | } | ||
124 | table->shift_amount++; | ||
125 | |||
126 | // Hash everything in the table for the new array capacity. | ||
127 | for (size_t i = 0; i < array_cap(old_pairs); i++) { | ||
128 | if (old_pairs[i].key != NULL) { | ||
129 | _ht_insert(table, old_pairs[i].key, old_pairs[i].value); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | // Free old arrays. | ||
134 | array_free(old_pairs); | ||
135 | } | ||
136 | |||
137 | void | ||
138 | ht_insert(HashTable *table, void *key, void *value) { | ||
139 | _ht_maybe_grow(table); | ||
140 | _ht_insert(table, key, value); | ||
141 | return; | ||
142 | } | ||
143 | |||
144 | void * | ||
145 | ht_lookup(const HashTable *table, void *key) { | ||
146 | size_t position = table->hash_func(table, key); | ||
147 | size_t probe_position = position; | ||
148 | |||
149 | // Verify the key in that position is the same. If not perform linear | ||
150 | // probing to find it. | ||
151 | HashTablePair *pairs = table->pairs; | ||
152 | while (true) { | ||
153 | if (pairs[probe_position].key == NULL) { | ||
154 | return NULL; | ||
155 | } | ||
156 | if (table->eq_func(pairs[probe_position].key, key)) { | ||
157 | break; | ||
158 | } | ||
159 | if (probe_position == array_cap(pairs) - 1) { | ||
160 | probe_position = 0; | ||
161 | } else { | ||
162 | probe_position++; | ||
163 | } | ||
164 | if (probe_position == position) { | ||
165 | return NULL; | ||
166 | } | ||
167 | } | ||
168 | return pairs[probe_position].value; | ||
169 | } | ||
170 | |||
171 | void | ||
172 | ht_free(HashTable *table) { | ||
173 | if (table == NULL) { | ||
174 | return; | ||
175 | } | ||
176 | array_free(table->pairs); | ||
177 | free(table); | ||
178 | } | ||
179 | |||
180 | #endif // BDL_HASHTABLE_H | ||
@@ -30,13 +30,20 @@ typedef enum { | |||
30 | SYM_PARAM, | 30 | SYM_PARAM, |
31 | SYM_ENUM, | 31 | SYM_ENUM, |
32 | SYM_ENUM_FIELD, | 32 | SYM_ENUM_FIELD, |
33 | SYM_STRUCT, | ||
34 | SYM_STRUCT_FIELD, | ||
33 | } SymbolKind; | 35 | } SymbolKind; |
34 | 36 | ||
35 | Str sym_kind_str[] = { | 37 | Str sym_kind_str[] = { |
36 | [SYM_UNKNOWN] = cstr("UNKNOWN "), [SYM_BUILTIN] = cstr("BUILTIN "), | 38 | [SYM_UNKNOWN] = cstr("UNKNOWN "), |
37 | [SYM_FUN] = cstr("FUNCTION "), [SYM_VAR] = cstr("VARIABLE "), | 39 | [SYM_BUILTIN] = cstr("BUILTIN "), |
38 | [SYM_PARAM] = cstr("PARAMETER "), [SYM_ENUM] = cstr("ENUM "), | 40 | [SYM_FUN] = cstr("FUNCTION "), |
39 | [SYM_ENUM_FIELD] = cstr("ENUM FIELD"), | 41 | [SYM_VAR] = cstr("VARIABLE "), |
42 | [SYM_PARAM] = cstr("PARAMETER "), | ||
43 | [SYM_ENUM] = cstr("ENUM "), | ||
44 | [SYM_ENUM_FIELD] = cstr("ENUM FIELD "), | ||
45 | [SYM_STRUCT] = cstr("STRUCT "), | ||
46 | [SYM_STRUCT_FIELD] = cstr("STRUCT FIELD "), | ||
40 | }; | 47 | }; |
41 | 48 | ||
42 | typedef struct Symbol { | 49 | typedef struct Symbol { |
@@ -85,6 +92,69 @@ find_symbol(Scope *scope, Str symbol) { | |||
85 | } | 92 | } |
86 | 93 | ||
87 | void | 94 | void |
95 | graph_scope(Scope *scope, Arena a) { | ||
96 | if (!scope->symbols) { | ||
97 | return; | ||
98 | } | ||
99 | SymbolMapIter iter = symmap_iterator(scope->symbols, &a); | ||
100 | SymbolMap *sym = symmap_next(&iter, &a); | ||
101 | print( | ||
102 | "%d[shape=\"none\" label=<\ | ||
103 | <TABLE ALIGN=\"left\" STYLE=\"rounded\" BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"6\" COLUMNS=\"*\">\ | ||
104 | <TR style=\"rounded\" ><TD COLSPAN=\"2\">ID: %d</TD></TR>", | ||
105 | scope->id, scope->id); | ||
106 | print( | ||
107 | "<TR ><TD ALIGN=\"left\" > NAME</TD><TD ALIGN=\"left\" > " | ||
108 | "KIND</TD></TR>"); | ||
109 | while (sym) { | ||
110 | print( | ||
111 | "<TR><TD ALIGN=\"left\"> %s </TD><TD ALIGN=\"left\"> %s </TD></TR>", | ||
112 | sym->val.name, sym_kind_str[sym->val.kind]); | ||
113 | SymbolMapIter field_iter = symmap_iterator(sym->val.fields, &a); | ||
114 | SymbolMap *field = symmap_next(&field_iter, &a); | ||
115 | while (field) { | ||
116 | print( | ||
117 | "<TR><TD ALIGN=\"left\"> %s.%s </TD><TD ALIGN=\"left\"> %s " | ||
118 | "</TD></TR>", | ||
119 | sym->val.name, field->val.name, sym_kind_str[field->val.kind]); | ||
120 | field = symmap_next(&field_iter, &a); | ||
121 | } | ||
122 | sym = symmap_next(&iter, &a); | ||
123 | } | ||
124 | println("</TABLE>>];"); | ||
125 | sz this_id = scope->id; | ||
126 | while (scope->parent) { | ||
127 | if (scope->parent->symbols) { | ||
128 | println("%d:n->%d:s;", this_id, scope->parent->id); | ||
129 | break; | ||
130 | } else { | ||
131 | scope = scope->parent; | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | void | ||
137 | graph_symbols(Scope **scopes, Arena a) { | ||
138 | if (scopes == NULL) return; | ||
139 | println("digraph symbols {"); | ||
140 | println("rankdir=BT;"); | ||
141 | println("ranksep=\"0.95 equally\";"); | ||
142 | println("nodesep=\"0.5 equally\";"); | ||
143 | println("overlap=scale;"); | ||
144 | println("bgcolor=\"transparent\";"); | ||
145 | for (sz i = 0; i < array_size(scopes); i++) { | ||
146 | Scope *scope = scopes[i]; | ||
147 | if (!scope) { | ||
148 | continue; | ||
149 | } | ||
150 | println("subgraph %d {", i); | ||
151 | graph_scope(scope, a); | ||
152 | println("}"); | ||
153 | } | ||
154 | println("}"); | ||
155 | } | ||
156 | |||
157 | void | ||
88 | analyzer_symbols(Analyzer *a, Node *node, Scope *scope) { | 158 | analyzer_symbols(Analyzer *a, Node *node, Scope *scope) { |
89 | assert(a); | 159 | assert(a); |
90 | assert(scope); | 160 | assert(scope); |
@@ -158,6 +228,7 @@ analyzer_symbols(Analyzer *a, Node *node, Scope *scope) { | |||
158 | analyzer_symbols(a, expr, next); | 228 | analyzer_symbols(a, expr, next); |
159 | } | 229 | } |
160 | } break; | 230 | } break; |
231 | case NODE_STRUCT: | ||
161 | case NODE_ENUM: { | 232 | case NODE_ENUM: { |
162 | Str symbol = node->value.str; | 233 | Str symbol = node->value.str; |
163 | if (symmap_lookup(&scope->symbols, symbol) != NULL) { | 234 | if (symmap_lookup(&scope->symbols, symbol) != NULL) { |
@@ -168,7 +239,10 @@ analyzer_symbols(Analyzer *a, Node *node, Scope *scope) { | |||
168 | } | 239 | } |
169 | SymbolMap *map = symmap_insert( | 240 | SymbolMap *map = symmap_insert( |
170 | &scope->symbols, symbol, | 241 | &scope->symbols, symbol, |
171 | (Symbol){.kind = SYM_ENUM, .name = symbol}, a->storage); | 242 | (Symbol){ |
243 | .kind = node->kind == NODE_ENUM ? SYM_ENUM : SYM_STRUCT, | ||
244 | .name = symbol}, | ||
245 | a->storage); | ||
172 | // TODO: symcheck the value expression? | 246 | // TODO: symcheck the value expression? |
173 | for (sz i = 0; i < array_size(node->struct_field); i++) { | 247 | for (sz i = 0; i < array_size(node->struct_field); i++) { |
174 | Node *field = node->struct_field[i]; | 248 | Node *field = node->struct_field[i]; |
@@ -179,7 +253,10 @@ analyzer_symbols(Analyzer *a, Node *node, Scope *scope) { | |||
179 | a->file_name, field->line, field->col, symbol, | 253 | a->file_name, field->line, field->col, symbol, |
180 | field_name); | 254 | field_name); |
181 | } | 255 | } |
182 | Symbol s = (Symbol){.kind = SYM_ENUM_FIELD, .name = field_name}; | 256 | Symbol s = |
257 | (Symbol){.kind = node->kind == NODE_ENUM ? SYM_ENUM_FIELD | ||
258 | : SYM_STRUCT_FIELD, | ||
259 | .name = field_name}; | ||
183 | symmap_insert(&map->val.fields, field_name, s, a->storage); | 260 | symmap_insert(&map->val.fields, field_name, s, a->storage); |
184 | } | 261 | } |
185 | } break; | 262 | } break; |
@@ -404,6 +481,11 @@ process_file(Str path) { | |||
404 | symbolic_analysis(&analyzer, &parser); | 481 | symbolic_analysis(&analyzer, &parser); |
405 | 482 | ||
406 | // Printing symbol tables. | 483 | // Printing symbol tables. |
484 | if (mode == PRINT_SYMTABLES) { | ||
485 | graph_symbols(analyzer.scopes, lexer_arena); | ||
486 | } | ||
487 | |||
488 | #if DEBUG == 1 | ||
407 | for (sz i = 0; i < array_size(analyzer.scopes); i++) { | 489 | for (sz i = 0; i < array_size(analyzer.scopes); i++) { |
408 | Arena scratch = lexer_arena; | 490 | Arena scratch = lexer_arena; |
409 | Scope *scope = analyzer.scopes[i]; | 491 | Scope *scope = analyzer.scopes[i]; |
@@ -424,6 +506,7 @@ process_file(Str path) { | |||
424 | sym = symmap_next(&iter, &lexer_arena); | 506 | sym = symmap_next(&iter, &lexer_arena); |
425 | } | 507 | } |
426 | } | 508 | } |
509 | #endif | ||
427 | 510 | ||
428 | // TODO: Type checking. | 511 | // TODO: Type checking. |
429 | 512 | ||
diff --git a/src/nodes.c b/src/nodes.c deleted file mode 100644 index 6978acc..0000000 --- a/src/nodes.c +++ /dev/null | |||
@@ -1,133 +0,0 @@ | |||
1 | #include "nodes.h" | ||
2 | |||
3 | static size_t node_gen_id = 0; | ||
4 | |||
5 | Node * | ||
6 | alloc_node(NodeType type) { | ||
7 | // TODO: Use a bump allocator? | ||
8 | // TODO: Free memory! | ||
9 | Node *node = malloc(sizeof(Node)); | ||
10 | node->id = node_gen_id++; | ||
11 | node->type = type; | ||
12 | node->line = 0; | ||
13 | node->col = 0; | ||
14 | node->expr_type = NULL; | ||
15 | return node; | ||
16 | } | ||
17 | |||
18 | void | ||
19 | print_node(Node *node) { | ||
20 | if (node == NULL) { | ||
21 | return; | ||
22 | } | ||
23 | switch (node->type) { | ||
24 | case NODE_NUMBER: { | ||
25 | if (node->number.negative) { | ||
26 | printf("-"); | ||
27 | } | ||
28 | if (node->number.fractional != 0) { | ||
29 | printf("%zu.%zu", node->number.integral, node->number.fractional); | ||
30 | } else { | ||
31 | printf("%zu", node->number.integral); | ||
32 | } | ||
33 | } break; | ||
34 | case NODE_SYMBOL: | ||
35 | case NODE_TYPE: | ||
36 | case NODE_STRING: { | ||
37 | sv_write(&node->string); | ||
38 | } break; | ||
39 | case NODE_BOOL: { | ||
40 | if (node->boolean) { | ||
41 | printf("true"); | ||
42 | } else { | ||
43 | printf("false"); | ||
44 | } | ||
45 | } break; | ||
46 | case NODE_BUILTIN: { | ||
47 | printf("({%s}", token_str[node->builtin.type]); | ||
48 | size_t n_args = array_size(node->builtin.args); | ||
49 | if (n_args != 0) { | ||
50 | printf(" "); | ||
51 | } | ||
52 | for (size_t i = 0; i < n_args; ++i) { | ||
53 | print_node(node->builtin.args[i]); | ||
54 | if (i < n_args - 1) { | ||
55 | printf(" "); | ||
56 | } | ||
57 | } | ||
58 | printf(")"); | ||
59 | } break; | ||
60 | case NODE_DEF: { | ||
61 | printf("(def "); | ||
62 | print_node(node->def.symbol); | ||
63 | printf(":"); | ||
64 | print_node(node->def.type); | ||
65 | printf(" "); | ||
66 | print_node(node->def.value); | ||
67 | printf(")"); | ||
68 | } break; | ||
69 | case NODE_SET: { | ||
70 | printf("(set "); | ||
71 | print_node(node->def.symbol); | ||
72 | printf(" "); | ||
73 | print_node(node->def.value); | ||
74 | printf(")"); | ||
75 | } break; | ||
76 | case NODE_BLOCK: { | ||
77 | size_t n_expr = array_size(node->block.expr); | ||
78 | printf("{"); | ||
79 | for (size_t i = 0; i < n_expr; ++i) { | ||
80 | printf(" "); | ||
81 | print_node(node->block.expr[i]); | ||
82 | } | ||
83 | printf(" }"); | ||
84 | } break; | ||
85 | case NODE_IF: { | ||
86 | printf("(if "); | ||
87 | print_node(node->ifexpr.cond); | ||
88 | printf(" "); | ||
89 | print_node(node->ifexpr.expr_true); | ||
90 | if (node->ifexpr.expr_false != NULL) { | ||
91 | printf(" "); | ||
92 | print_node(node->ifexpr.expr_false); | ||
93 | } | ||
94 | printf(")"); | ||
95 | } break; | ||
96 | case NODE_FUN: { | ||
97 | printf("(fun "); | ||
98 | print_node(node->fun.name); | ||
99 | printf(" ("); | ||
100 | size_t n_params = array_size(node->fun.param_names); | ||
101 | for (size_t i = 0; i < n_params; ++i) { | ||
102 | print_node(node->fun.param_names[i]); | ||
103 | printf(":"); | ||
104 | print_node(node->fun.param_types[i]); | ||
105 | if (i < n_params - 1) { | ||
106 | printf(" "); | ||
107 | } | ||
108 | } | ||
109 | printf(")"); | ||
110 | printf(": "); | ||
111 | print_node(node->fun.return_type); | ||
112 | printf(" "); | ||
113 | print_node(node->fun.body); | ||
114 | printf(")"); | ||
115 | } break; | ||
116 | case NODE_FUNCALL: { | ||
117 | printf("("); | ||
118 | print_node(node->funcall.name); | ||
119 | size_t n_args = array_size(node->funcall.args); | ||
120 | if (n_args != 0) { | ||
121 | printf(" "); | ||
122 | } | ||
123 | for (size_t i = 0; i < n_args; ++i) { | ||
124 | print_node(node->funcall.args[i]); | ||
125 | if (i < n_args - 1) { | ||
126 | printf(" "); | ||
127 | } | ||
128 | } | ||
129 | printf(")"); | ||
130 | } break; | ||
131 | default: { printf("{#unknown#}"); } break; | ||
132 | } | ||
133 | } | ||
diff --git a/src/nodes.h b/src/nodes.h deleted file mode 100644 index af10573..0000000 --- a/src/nodes.h +++ /dev/null | |||
@@ -1,88 +0,0 @@ | |||
1 | #ifndef BDL_NODES_H | ||
2 | #define BDL_NODES_H | ||
3 | |||
4 | typedef enum NodeType { | ||
5 | NODE_BUILTIN, | ||
6 | NODE_NUMBER, | ||
7 | NODE_BOOL, | ||
8 | NODE_STRING, | ||
9 | NODE_SYMBOL, | ||
10 | NODE_TYPE, | ||
11 | NODE_DEF, | ||
12 | NODE_SET, | ||
13 | NODE_FUN, | ||
14 | NODE_BLOCK, | ||
15 | NODE_IF, | ||
16 | NODE_FUNCALL, | ||
17 | } NodeType; | ||
18 | |||
19 | typedef struct Node { | ||
20 | size_t id; | ||
21 | NodeType type; | ||
22 | size_t line; | ||
23 | size_t col; | ||
24 | struct Type *expr_type; | ||
25 | |||
26 | union { | ||
27 | // Numbers. | ||
28 | struct { | ||
29 | bool negative; | ||
30 | size_t integral; | ||
31 | size_t fractional; | ||
32 | } number; | ||
33 | |||
34 | // String/symbol/type. | ||
35 | StringView string; | ||
36 | |||
37 | // Boolean. | ||
38 | bool boolean; | ||
39 | |||
40 | // Builtin primitive. | ||
41 | struct { | ||
42 | TokenType type; | ||
43 | struct Node **args; | ||
44 | } builtin; | ||
45 | |||
46 | // Function call. | ||
47 | struct { | ||
48 | struct Node *name; | ||
49 | struct Node **args; | ||
50 | } funcall; | ||
51 | |||
52 | // Variable definition. | ||
53 | struct { | ||
54 | struct Node *symbol; | ||
55 | struct Node *value; | ||
56 | struct Node *type; | ||
57 | } def; | ||
58 | |||
59 | // Variable assignment. | ||
60 | struct { | ||
61 | struct Node *symbol; | ||
62 | struct Node *value; | ||
63 | } set; | ||
64 | |||
65 | // Function definition. | ||
66 | struct { | ||
67 | struct Node *name; | ||
68 | struct Node **param_names; | ||
69 | struct Node **param_types; | ||
70 | struct Node *return_type; | ||
71 | struct Node *body; | ||
72 | } fun; | ||
73 | |||
74 | // Block statements. | ||
75 | struct { | ||
76 | struct Node **expr; | ||
77 | } block; | ||
78 | |||
79 | // If statement. | ||
80 | struct { | ||
81 | struct Node *cond; | ||
82 | struct Node *expr_true; | ||
83 | struct Node *expr_false; | ||
84 | } ifexpr; | ||
85 | }; | ||
86 | } Node; | ||
87 | |||
88 | #endif // BDL_NODES_H | ||
diff --git a/src/string_view.c b/src/string_view.c deleted file mode 100644 index 4e9df5c..0000000 --- a/src/string_view.c +++ /dev/null | |||
@@ -1,49 +0,0 @@ | |||
1 | #include "string_view.h" | ||
2 | |||
3 | char | ||
4 | sv_next(StringView *sv) { | ||
5 | if (sv->n == 0) { | ||
6 | return '\0'; | ||
7 | } | ||
8 | char c = sv->start[0]; | ||
9 | sv->start++; | ||
10 | sv->n--; | ||
11 | return c; | ||
12 | } | ||
13 | |||
14 | void | ||
15 | sv_rewind(StringView *sv) { | ||
16 | if (sv->start == 0) { | ||
17 | return; | ||
18 | } | ||
19 | sv->start--; | ||
20 | sv->n++; | ||
21 | } | ||
22 | |||
23 | char | ||
24 | sv_peek(const StringView *sv) { | ||
25 | if (sv->n == 0) { | ||
26 | return '\0'; | ||
27 | } | ||
28 | return sv->start[0]; | ||
29 | } | ||
30 | |||
31 | bool | ||
32 | sv_equal(const StringView *a, const StringView *b) { | ||
33 | if (a->n != b->n) { | ||
34 | return false; | ||
35 | } | ||
36 | for (size_t i = 0; i < a->n; i++) { | ||
37 | if (a->start[i] != b->start[i]) { | ||
38 | return false; | ||
39 | } | ||
40 | } | ||
41 | return true; | ||
42 | } | ||
43 | |||
44 | void | ||
45 | sv_write(const StringView *sv) { | ||
46 | for (size_t i = 0; i < sv->n; i++) { | ||
47 | putchar(sv->start[i]); | ||
48 | } | ||
49 | } | ||
diff --git a/src/string_view.h b/src/string_view.h deleted file mode 100644 index cb0f488..0000000 --- a/src/string_view.h +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | #ifndef BDL_STRINGVIEW_H | ||
2 | #define BDL_STRINGVIEW_H | ||
3 | |||
4 | #include "common.h" | ||
5 | |||
6 | typedef struct StringView { | ||
7 | char *start; | ||
8 | size_t n; | ||
9 | } StringView; | ||
10 | |||
11 | // Consume a character in the stream. | ||
12 | char sv_next(StringView *sv); | ||
13 | |||
14 | // Rewind a character in the stream. | ||
15 | void sv_rewind(StringView *sv); | ||
16 | |||
17 | // Check what is the current character in the stream. | ||
18 | char sv_peek(const StringView *sv); | ||
19 | |||
20 | // Compare if the arguments are the same. | ||
21 | bool sv_equal(const StringView *a, const StringView *b); | ||
22 | |||
23 | // Write a character to the given output stream. | ||
24 | void sv_write(const StringView *sv); | ||
25 | |||
26 | #define STRING(STR) (StringView){(STR), sizeof(STR) - 1} | ||
27 | |||
28 | #endif // BDL_STRINGVIEW_H | ||
diff --git a/src/viz.c b/src/viz.c deleted file mode 100644 index ebe1a4c..0000000 --- a/src/viz.c +++ /dev/null | |||
@@ -1,350 +0,0 @@ | |||
1 | static const char* node_str[] = { | ||
2 | [NODE_BUILTIN] = "BUILTIN", | ||
3 | [NODE_NUMBER] = "NUMBER", | ||
4 | [NODE_BOOL] = "BOOL", | ||
5 | [NODE_STRING] = "STRING", | ||
6 | [NODE_SYMBOL] = "SYMBOL", | ||
7 | [NODE_TYPE] = "TYPE", | ||
8 | [NODE_DEF] = "DEF", | ||
9 | [NODE_SET] = "SET", | ||
10 | [NODE_FUN] = "FUN", | ||
11 | [NODE_BLOCK] = "BLOCK", | ||
12 | [NODE_IF] = "IF", | ||
13 | [NODE_FUNCALL] = "FUNCALL", | ||
14 | }; | ||
15 | |||
16 | void | ||
17 | viz_node(Node *node) { | ||
18 | if (node == NULL) { | ||
19 | return; | ||
20 | } | ||
21 | printf("%zu [width=2.5,shape=Mrecord,label=\"", node->id); | ||
22 | printf("<top> %s -- [%4ld:%-4ld] ", node_str[node->type], node->line, node->col); | ||
23 | if (node->expr_type != NULL) { | ||
24 | printf("| T: "); | ||
25 | sv_write(&node->expr_type->name); | ||
26 | } | ||
27 | switch (node->type) { | ||
28 | case NODE_NUMBER: { | ||
29 | printf("| Value: "); | ||
30 | if (node->number.negative) { | ||
31 | printf("-"); | ||
32 | } | ||
33 | if (node->number.fractional != 0) { | ||
34 | printf("%zu.%zu", node->number.integral, node->number.fractional); | ||
35 | } else { | ||
36 | printf("%zu", node->number.integral); | ||
37 | } | ||
38 | printf("\"];\n"); | ||
39 | } break; | ||
40 | case NODE_SYMBOL: | ||
41 | case NODE_TYPE: | ||
42 | case NODE_STRING: { | ||
43 | printf(" | Value: "); | ||
44 | sv_write(&node->string); | ||
45 | printf("\"];\n"); | ||
46 | } break; | ||
47 | case NODE_BOOL: { | ||
48 | printf(" | Value: "); | ||
49 | if (node->boolean) { | ||
50 | printf("true"); | ||
51 | } else { | ||
52 | printf("false"); | ||
53 | } | ||
54 | printf("\"];\n"); | ||
55 | } break; | ||
56 | case NODE_BUILTIN: { | ||
57 | printf(" | Name: %s", token_str[node->builtin.type]); | ||
58 | printf(" | <args> Args: "); | ||
59 | printf("\"];\n"); | ||
60 | size_t n_args = array_size(node->builtin.args); | ||
61 | for (size_t i = 0; i < n_args; ++i) { | ||
62 | viz_node(node->builtin.args[i]); | ||
63 | printf("%zu:args:e->%zu:top:w;\n", node->id, node->builtin.args[i]->id); | ||
64 | } | ||
65 | } break; | ||
66 | case NODE_DEF: { | ||
67 | printf(" | Name: "); | ||
68 | sv_write(&node->def.symbol->string); | ||
69 | printf(" | Type: "); | ||
70 | sv_write(&node->def.type->string); | ||
71 | printf(" | <val> Expr: "); | ||
72 | printf("\"];\n"); | ||
73 | viz_node(node->def.value); | ||
74 | printf("%zu:val:e->%zu:top:w;\n", node->id, node->def.value->id); | ||
75 | } break; | ||
76 | case NODE_SET: { | ||
77 | printf(" | Name: "); | ||
78 | sv_write(&node->set.symbol->string); | ||
79 | printf(" | <val> Expr: "); | ||
80 | printf("\"];\n"); | ||
81 | viz_node(node->set.value); | ||
82 | printf("%zu:val:e->%zu:top:w;\n", node->id, node->def.value->id); | ||
83 | } break; | ||
84 | case NODE_BLOCK: { | ||
85 | printf(" | <expr> Exprs: "); | ||
86 | printf("\"];\n"); | ||
87 | size_t n_expr = array_size(node->block.expr); | ||
88 | for (size_t i = 0; i < n_expr; ++i) { | ||
89 | viz_node(node->block.expr[i]); | ||
90 | printf("%zu:expr:e->%zu:top:w;\n", node->id, node->block.expr[i]->id); | ||
91 | } | ||
92 | } break; | ||
93 | case NODE_IF: { | ||
94 | printf(" | <cond> Cond: "); | ||
95 | printf(" | <t> ExprTrue:"); | ||
96 | if (node->ifexpr.expr_false != NULL) { | ||
97 | printf(" | <f> ExprFalse: "); | ||
98 | } | ||
99 | printf("\"];\n"); | ||
100 | viz_node(node->ifexpr.cond); | ||
101 | printf("%zu:cond:e->%zu:top:w;\n", node->id, node->ifexpr.cond->id); | ||
102 | viz_node(node->ifexpr.expr_true); | ||
103 | printf("%zu:t:e->%zu:top:w;\n", node->id, node->ifexpr.expr_true->id); | ||
104 | if (node->ifexpr.expr_false != NULL) { | ||
105 | viz_node(node->ifexpr.expr_false); | ||
106 | printf("%zu:f:e->%zu:top:w;\n", node->id, node->ifexpr.expr_false->id); | ||
107 | } | ||
108 | } break; | ||
109 | case NODE_FUN: { | ||
110 | printf(" | Name: "); | ||
111 | sv_write(&node->fun.name->string); | ||
112 | printf(" | Type: "); | ||
113 | printf("("); | ||
114 | size_t n_params = array_size(node->fun.param_names); | ||
115 | for (size_t i = 0; i < n_params; ++i) { | ||
116 | printf(":"); | ||
117 | sv_write(&node->fun.param_types[i]->string); | ||
118 | if (i < n_params - 1) { | ||
119 | printf(" "); | ||
120 | } | ||
121 | } | ||
122 | printf("):"); | ||
123 | sv_write(&node->fun.return_type->string); | ||
124 | if (n_params > 0) { | ||
125 | printf(" | Parameters: ("); | ||
126 | for (size_t i = 0; i < n_params; ++i) { | ||
127 | sv_write(&node->fun.param_names[i]->string); | ||
128 | if (i < n_params - 1) { | ||
129 | printf(" "); | ||
130 | } | ||
131 | } | ||
132 | printf(")"); | ||
133 | } | ||
134 | printf(" | <bod> Body: "); | ||
135 | printf("\"];\n"); | ||
136 | viz_node(node->fun.body); | ||
137 | printf("%zu:bod:e->%zu:top:w;\n", node->id, node->fun.body->id); | ||
138 | } break; | ||
139 | case NODE_FUNCALL: { | ||
140 | printf(" | Name: "); | ||
141 | sv_write(&node->funcall.name->string); | ||
142 | printf(" | <args> Args: "); | ||
143 | printf("\"];\n"); | ||
144 | size_t n_args = array_size(node->funcall.args); | ||
145 | for (size_t i = 0; i < n_args; ++i) { | ||
146 | viz_node(node->funcall.args[i]); | ||
147 | printf("%zu:args:e->%zu:top:w;\n", node->id, | ||
148 | node->funcall.args[i]->id); | ||
149 | } | ||
150 | } break; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | void | ||
155 | viz_ast(Root *roots) { | ||
156 | if (roots == NULL) { | ||
157 | return; | ||
158 | } | ||
159 | printf("digraph ast {\n"); | ||
160 | printf("rankdir=LR;\n"); | ||
161 | printf("ranksep=\"0.95 equally\";\n"); | ||
162 | printf("nodesep=\"0.5 equally\";\n"); | ||
163 | printf("overlap=scale;\n"); | ||
164 | printf("bgcolor=\"transparent\";\n"); | ||
165 | for (size_t i = 0; i < array_size(roots); ++i) { | ||
166 | printf("subgraph %zu {\n", i); | ||
167 | Node *root = roots[array_size(roots) - 1 - i]; | ||
168 | viz_node(root); | ||
169 | printf("}\n"); | ||
170 | } | ||
171 | printf("}\n"); | ||
172 | } | ||
173 | |||
174 | void | ||
175 | viz_symtables(Scope **scopes) { | ||
176 | printf("digraph symtables {\n"); | ||
177 | printf("rankdir=RL;\n"); | ||
178 | printf("bgcolor=\"transparent\";\n"); | ||
179 | for (size_t i = 0; i < array_size(scopes); ++i) { | ||
180 | Scope *scope = scopes[i]; | ||
181 | if (array_size(scope->symbols->pairs) == 0) { | ||
182 | continue; | ||
183 | } | ||
184 | printf("%zu [shape=none,label=<", scope->id); | ||
185 | printf("<table border=\"1\" cellborder=\"0\">\n"); | ||
186 | printf("<tr><td>NAME</td><td>KIND</td><td>TYPE</td></tr>"); | ||
187 | for (size_t j = 0; j < array_cap(scope->symbols->pairs); ++j) { | ||
188 | HashTablePair pair = scope->symbols->pairs[j]; | ||
189 | if (pair.key == NULL) { | ||
190 | continue; | ||
191 | } | ||
192 | Symbol *sym = pair.value; | ||
193 | printf("<tr>"); | ||
194 | printf("<td>"); | ||
195 | print_node(sym->name); | ||
196 | printf("</td>"); | ||
197 | switch (sym->type) { | ||
198 | case SYMBOL_PAR: { | ||
199 | printf("<td>par</td>"); | ||
200 | printf("<td>"); | ||
201 | print_node(sym->var.type); | ||
202 | printf("</td>"); | ||
203 | } break; | ||
204 | case SYMBOL_VAR: { | ||
205 | printf("<td>var</td>"); | ||
206 | printf("<td>"); | ||
207 | print_node(sym->var.type); | ||
208 | printf("</td>"); | ||
209 | } break; | ||
210 | case SYMBOL_FUN: { | ||
211 | printf("<td>fun</td>"); | ||
212 | printf("<td>"); | ||
213 | printf("("); | ||
214 | size_t n_params = array_size(sym->fun.param_types); | ||
215 | for (size_t k = 0; k < n_params; ++k) { | ||
216 | print_node(sym->fun.param_types[k]); | ||
217 | if (k < n_params - 1) { | ||
218 | printf(" "); | ||
219 | } | ||
220 | } | ||
221 | printf(")"); | ||
222 | printf(":"); | ||
223 | print_node(sym->fun.return_type); | ||
224 | printf("</td>"); | ||
225 | } break; | ||
226 | } | ||
227 | printf("</tr>\n"); | ||
228 | } | ||
229 | printf("</table>\n"); | ||
230 | printf(">];\n"); | ||
231 | |||
232 | if (scope->parent != NULL) { | ||
233 | printf("%zu -> %zu\n", scope->id, scope->parent->id); | ||
234 | } | ||
235 | } | ||
236 | printf("}\n"); | ||
237 | } | ||
238 | |||
239 | static const char* basm_op_str[] = { | ||
240 | [OP_ADD] = "add ", | ||
241 | [OP_SUB] = "sub ", | ||
242 | [OP_MUL] = "mul ", | ||
243 | [OP_DIV] = "div ", | ||
244 | [OP_MOD] = "mod ", | ||
245 | [OP_LD8] = "ld8 ", | ||
246 | [OP_LD16] = "ld16 ", | ||
247 | [OP_LD32] = "ld32 ", | ||
248 | [OP_LD64] = "ld64 ", | ||
249 | [OP_ST8] = "st8 ", | ||
250 | [OP_ST16] = "st16 ", | ||
251 | [OP_ST32] = "st32 ", | ||
252 | [OP_ST64] = "st64 ", | ||
253 | [OP_CP8] = "cp8 ", | ||
254 | [OP_CP16] = "cp16 ", | ||
255 | [OP_CP32] = "cp32 ", | ||
256 | [OP_CP64] = "cp64 ", | ||
257 | [OP_NOT] = "not ", | ||
258 | [OP_AND] = "and ", | ||
259 | [OP_OR] = "or ", | ||
260 | [OP_XOR] = "xor ", | ||
261 | [OP_LSHIFT] = "lshift", | ||
262 | [OP_RSHIFT] = "rshift", | ||
263 | [OP_LROT] = "lrot ", | ||
264 | [OP_RROT] = "rrot ", | ||
265 | [OP_LABEL] = "lab ", | ||
266 | [OP_JMP] = "jmp ", | ||
267 | [OP_JMP_TRUE] = "jt ", | ||
268 | [OP_JMP_FALSE] = "jf ", | ||
269 | [OP_JMP_EQ] = "jeq ", | ||
270 | [OP_JMP_NEQ] = "jne ", | ||
271 | [OP_JMP_GT] = "jgt ", | ||
272 | [OP_JMP_LT] = "jlt ", | ||
273 | [OP_JMP_GE] = "jge ", | ||
274 | [OP_JMP_LE] = "jle ", | ||
275 | [OP_RETURN] = "ret ", | ||
276 | }; | ||
277 | |||
278 | void | ||
279 | viz_operand(Operand op) { | ||
280 | switch (op.type) { | ||
281 | case OP_TYPE_LABEL: { | ||
282 | printf("l%zu", op.id); | ||
283 | } break; | ||
284 | case OP_TYPE_REG: { | ||
285 | printf("r%zu", op.id); | ||
286 | } break; | ||
287 | case OP_TYPE_CONST: { | ||
288 | printf("%lld", op.constant.uval); | ||
289 | } break; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | void | ||
294 | viz_instruction(Instruction *inst, LineInfo *line) { | ||
295 | printf("[%6ld:%-6ld] ", line->line, line->col); | ||
296 | printf("%s", basm_op_str[inst->op]); | ||
297 | switch (inst->op) { | ||
298 | case OP_ST8: | ||
299 | case OP_ST16: | ||
300 | case OP_ST32: | ||
301 | case OP_ST64: | ||
302 | case OP_LD8: | ||
303 | case OP_LD16: | ||
304 | case OP_LD32: | ||
305 | case OP_LD64: { | ||
306 | printf(" "); | ||
307 | viz_operand(inst->dst); | ||
308 | printf(", "); | ||
309 | viz_operand(inst->src_a); | ||
310 | if (inst->src_a.type != OP_TYPE_CONST) { | ||
311 | printf(", "); | ||
312 | viz_operand(inst->src_b); | ||
313 | } | ||
314 | } break; | ||
315 | case OP_RETURN: | ||
316 | case OP_JMP: | ||
317 | case OP_LABEL: { | ||
318 | printf(" "); | ||
319 | viz_operand(inst->dst); | ||
320 | } break; | ||
321 | case OP_CP8: | ||
322 | case OP_CP16: | ||
323 | case OP_CP32: | ||
324 | case OP_CP64: | ||
325 | case OP_JMP_TRUE: | ||
326 | case OP_JMP_FALSE: { | ||
327 | printf(" "); | ||
328 | viz_operand(inst->dst); | ||
329 | printf(", "); | ||
330 | viz_operand(inst->src_a); | ||
331 | } break; | ||
332 | default: { | ||
333 | printf(" "); | ||
334 | viz_operand(inst->dst); | ||
335 | printf(", "); | ||
336 | viz_operand(inst->src_a); | ||
337 | printf(", "); | ||
338 | viz_operand(inst->src_b); | ||
339 | } break; | ||
340 | } | ||
341 | printf("\n"); | ||
342 | } | ||
343 | |||
344 | void | ||
345 | viz_basm(ProgramBASM *program) { | ||
346 | for (size_t i = 0; i < array_size(program->inst); ++i) { | ||
347 | viz_instruction(&program->inst[i], &program->lines[i]); | ||
348 | } | ||
349 | |||
350 | } | ||
diff --git a/src/compiler.h b/src/x86asm_compiler.h index 6ca4467..6ca4467 100644 --- a/src/compiler.h +++ b/src/x86asm_compiler.h | |||