aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2022-04-19 10:41:32 -0300
committerBad Diode <bd@badd10de.dev>2022-04-19 10:41:32 -0300
commitc69929cc501203829082b810bafe75a22947e00c (patch)
tree46dceba9e657a424626ab97f510b49d3b2b889cf
parent7cf1451ab52586ed9c4eeae1b1ec3b4ebaa83393 (diff)
downloadbdl-c69929cc501203829082b810bafe75a22947e00c.tar.gz
bdl-c69929cc501203829082b810bafe75a22947e00c.zip
Add viz for symbol tables
-rw-r--r--Makefile3
-rw-r--r--src/main.c11
-rw-r--r--src/semantic.c44
-rw-r--r--src/viz.c60
4 files changed, 97 insertions, 21 deletions
diff --git a/Makefile b/Makefile
index 6c898a9..6a12cc3 100644
--- a/Makefile
+++ b/Makefile
@@ -63,6 +63,9 @@ viz_par: $(BIN)
63viz_sem: $(BIN) 63viz_sem: $(BIN)
64 $(BIN) -ps example.bdl | dot -Nfontname="Iosevka Term" -Tpng > viz.png 64 $(BIN) -ps example.bdl | dot -Nfontname="Iosevka Term" -Tpng > viz.png
65 65
66viz_sym: $(BIN)
67 $(BIN) -pt example.bdl | dot -Nfontname="Iosevka Term" -Tpng > viz.png
68
66# Remove build directory. 69# Remove build directory.
67clean: 70clean:
68 rm -rf $(BUILD_DIR) 71 rm -rf $(BUILD_DIR)
diff --git a/src/main.c b/src/main.c
index 56c36d7..fc991d2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -17,6 +17,7 @@ typedef enum ExecMode {
17 PRINT_LEX, 17 PRINT_LEX,
18 PRINT_PARSE, 18 PRINT_PARSE,
19 PRINT_SEMANTIC, 19 PRINT_SEMANTIC,
20 PRINT_SYMTABLES,
20} ExecMode; 21} ExecMode;
21 22
22static ExecMode mode = RUN_NORMAL; 23static ExecMode mode = RUN_NORMAL;
@@ -46,12 +47,18 @@ process_source(const StringView *source, const char *file_name) {
46 check_errors(file_name); 47 check_errors(file_name);
47 if (mode == PRINT_PARSE) { 48 if (mode == PRINT_PARSE) {
48 viz_ast(roots); 49 viz_ast(roots);
50 return;
49 } 51 }
50 52
51 // Symbol table generation and type checking. 53 // Symbol table generation and type checking.
52 ParseTree *parse_tree = semantic_analysis(roots); 54 ParseTree *parse_tree = semantic_analysis(roots);
53 if (mode == PRINT_SEMANTIC) { 55 if (mode == PRINT_SEMANTIC) {
54 viz_ast(parse_tree->roots); 56 viz_ast(parse_tree->roots);
57 return;
58 }
59 if (mode == PRINT_SYMTABLES) {
60 viz_symtables(parse_tree->scopes);
61 return;
55 } 62 }
56} 63}
57 64
@@ -116,7 +123,7 @@ print_usage(void) {
116 printf("Usage: %s [options] <filename filename ...>\n", BIN_NAME); 123 printf("Usage: %s [options] <filename filename ...>\n", BIN_NAME);
117 printf("\n"); 124 printf("\n");
118 printf("\t-h \t\tShow usage.\n"); 125 printf("\t-h \t\tShow usage.\n");
119 printf("\t-p [l | p | s]\tPrint mode for [l]exing, [p]arsing or [s]emantic analysis\n"); 126 printf("\t-p [l|p|s|t]\tPrint mode for [l]exing, [p]arsing, [s]emantic analysis, symbol [t]ables\n");
120 printf("\n"); 127 printf("\n");
121} 128}
122 129
@@ -138,6 +145,8 @@ main(int argc, char *argv[]) {
138 mode = PRINT_PARSE; 145 mode = PRINT_PARSE;
139 } else if (optarg[0] == 's' && optarg[1] == '\0') { 146 } else if (optarg[0] == 's' && optarg[1] == '\0') {
140 mode = PRINT_SEMANTIC; 147 mode = PRINT_SEMANTIC;
148 } else if (optarg[0] == 't' && optarg[1] == '\0') {
149 mode = PRINT_SYMTABLES;
141 } else { 150 } else {
142 print_usage(); 151 print_usage();
143 return EXIT_FAILURE; 152 return EXIT_FAILURE;
diff --git a/src/semantic.c b/src/semantic.c
index 06958b9..6c9f290 100644
--- a/src/semantic.c
+++ b/src/semantic.c
@@ -1,6 +1,7 @@
1#include "hashtable.h" 1#include "hashtable.h"
2 2
3typedef struct Scope { 3typedef struct Scope {
4 size_t id;
4 struct Scope *parent; 5 struct Scope *parent;
5 HashTable *symbols; 6 HashTable *symbols;
6 HashTable *types; 7 HashTable *types;
@@ -8,8 +9,7 @@ typedef struct Scope {
8 9
9typedef struct ParseTree { 10typedef struct ParseTree {
10 Root *roots; 11 Root *roots;
11 Scope *global_scope; 12 Scope **scopes;
12 Scope *current_scope;
13} ParseTree; 13} ParseTree;
14 14
15typedef struct Type { 15typedef struct Type {
@@ -70,6 +70,7 @@ typedef struct Symbol {
70 }; 70 };
71} Symbol; 71} Symbol;
72 72
73static size_t scope_gen_id = 0;
73 74
74Symbol * 75Symbol *
75alloc_symval(Node *name, SymbolType type) { 76alloc_symval(Node *name, SymbolType type) {
@@ -110,6 +111,7 @@ bool type_eq(void *a, void *b) {
110Scope * 111Scope *
111alloc_scope(Scope *parent) { 112alloc_scope(Scope *parent) {
112 Scope *scope = malloc(sizeof(Scope)); 113 Scope *scope = malloc(sizeof(Scope));
114 scope->id = scope_gen_id++;
113 scope->parent = parent; 115 scope->parent = parent;
114 scope->symbols = ht_init(sym_hash, sym_eq); 116 scope->symbols = ht_init(sym_hash, sym_eq);
115 scope->types = ht_init(type_hash, type_eq); 117 scope->types = ht_init(type_hash, type_eq);
@@ -216,7 +218,7 @@ find_symbol(Scope *scope, Node *node) {
216} 218}
217 219
218bool 220bool
219resolve_type(Scope *scope, Node *node) { 221resolve_type(ParseTree *ast, Scope *scope, Node *node) {
220 if (node->expr_type != NULL) { 222 if (node->expr_type != NULL) {
221 return true; 223 return true;
222 } 224 }
@@ -224,7 +226,7 @@ resolve_type(Scope *scope, Node *node) {
224 case NODE_BUILTIN: { 226 case NODE_BUILTIN: {
225 for (size_t i = 0; i < array_size(node->builtin.args); ++i) { 227 for (size_t i = 0; i < array_size(node->builtin.args); ++i) {
226 Node *arg = node->builtin.args[i]; 228 Node *arg = node->builtin.args[i];
227 if (!resolve_type(scope, arg)) { 229 if (!resolve_type(ast, scope, arg)) {
228 return false; 230 return false;
229 } 231 }
230 } 232 }
@@ -311,6 +313,7 @@ resolve_type(Scope *scope, Node *node) {
311 case NODE_FUN: { 313 case NODE_FUN: {
312 // Fill up new scope with parameters 314 // Fill up new scope with parameters
313 scope = alloc_scope(scope); 315 scope = alloc_scope(scope);
316 array_push(ast->scopes, scope);
314 317
315 // Parameters. 318 // Parameters.
316 for (size_t i = 0; i < array_size(node->fun.param_names); ++i) { 319 for (size_t i = 0; i < array_size(node->fun.param_names); ++i) {
@@ -328,14 +331,14 @@ resolve_type(Scope *scope, Node *node) {
328 if (body->type == NODE_BLOCK) { 331 if (body->type == NODE_BLOCK) {
329 for (size_t i = 0; i < array_size(body->block.expr); ++i) { 332 for (size_t i = 0; i < array_size(body->block.expr); ++i) {
330 Node *expr = body->block.expr[i]; 333 Node *expr = body->block.expr[i];
331 if (!resolve_type(scope, expr)) { 334 if (!resolve_type(ast, scope, expr)) {
332 return false; 335 return false;
333 } 336 }
334 } 337 }
335 Node *last_expr = body->block.expr[array_size(body->block.expr) - 1]; 338 Node *last_expr = body->block.expr[array_size(body->block.expr) - 1];
336 node->expr_type = last_expr->expr_type; 339 node->expr_type = last_expr->expr_type;
337 } else { 340 } else {
338 if (!resolve_type(scope, body)) { 341 if (!resolve_type(ast, scope, body)) {
339 return false; 342 return false;
340 } 343 }
341 } 344 }
@@ -350,9 +353,10 @@ resolve_type(Scope *scope, Node *node) {
350 } break; 353 } break;
351 case NODE_BLOCK: { 354 case NODE_BLOCK: {
352 scope = alloc_scope(scope); 355 scope = alloc_scope(scope);
356 array_push(ast->scopes, scope);
353 for (size_t i = 0; i < array_size(node->block.expr); ++i) { 357 for (size_t i = 0; i < array_size(node->block.expr); ++i) {
354 Node *expr = node->block.expr[i]; 358 Node *expr = node->block.expr[i];
355 if (!resolve_type(scope, expr)) { 359 if (!resolve_type(ast, scope, expr)) {
356 return false; 360 return false;
357 } 361 }
358 } 362 }
@@ -360,16 +364,16 @@ resolve_type(Scope *scope, Node *node) {
360 node->expr_type = last_expr->expr_type; 364 node->expr_type = last_expr->expr_type;
361 } break; 365 } break;
362 case NODE_IF: { 366 case NODE_IF: {
363 if (!resolve_type(scope, node->ifexpr.cond)) { 367 if (!resolve_type(ast, scope, node->ifexpr.cond)) {
364 return false; 368 return false;
365 } 369 }
366 if (!resolve_type(scope, node->ifexpr.expr_true)) { 370 if (!resolve_type(ast, scope, node->ifexpr.expr_true)) {
367 return false; 371 return false;
368 } 372 }
369 Type *type_true = node->ifexpr.expr_true->expr_type; 373 Type *type_true = node->ifexpr.expr_true->expr_type;
370 node->expr_type = type_true; 374 node->expr_type = type_true;
371 if (node->ifexpr.expr_false != NULL) { 375 if (node->ifexpr.expr_false != NULL) {
372 if (!resolve_type(scope, node->ifexpr.expr_false)) { 376 if (!resolve_type(ast, scope, node->ifexpr.expr_false)) {
373 return false; 377 return false;
374 } 378 }
375 } 379 }
@@ -396,10 +400,10 @@ resolve_type(Scope *scope, Node *node) {
396 } break; 400 } break;
397 case NODE_SET: { 401 case NODE_SET: {
398 node->expr_type = &default_types[TYPE_VOID]; 402 node->expr_type = &default_types[TYPE_VOID];
399 if (!resolve_type(scope, node->set.symbol)) { 403 if (!resolve_type(ast, scope, node->set.symbol)) {
400 return false; 404 return false;
401 } 405 }
402 if (!resolve_type(scope, node->set.value)) { 406 if (!resolve_type(ast, scope, node->set.value)) {
403 return false; 407 return false;
404 } 408 }
405 Node *symbol = node->set.symbol; 409 Node *symbol = node->set.symbol;
@@ -426,7 +430,7 @@ resolve_type(Scope *scope, Node *node) {
426 430
427 node->expr_type = &default_types[TYPE_VOID]; 431 node->expr_type = &default_types[TYPE_VOID];
428 // TODO: type inference from right side when not annotated? 432 // TODO: type inference from right side when not annotated?
429 if (!resolve_type(scope, node->def.value)) { 433 if (!resolve_type(ast, scope, node->def.value)) {
430 return false; 434 return false;
431 } 435 }
432 Node *symbol = node->def.symbol; 436 Node *symbol = node->def.symbol;
@@ -455,7 +459,7 @@ resolve_type(Scope *scope, Node *node) {
455 } break; 459 } break;
456 case NODE_FUNCALL: { 460 case NODE_FUNCALL: {
457 Symbol *val = find_symbol(scope, node->funcall.name); 461 Symbol *val = find_symbol(scope, node->funcall.name);
458 if (!resolve_type(scope, node->funcall.name)) { 462 if (!resolve_type(ast, scope, node->funcall.name)) {
459 return false; 463 return false;
460 } 464 }
461 if (val->type != SYMBOL_FUN) { 465 if (val->type != SYMBOL_FUN) {
@@ -470,7 +474,7 @@ resolve_type(Scope *scope, Node *node) {
470 node->expr_type = node->funcall.name->expr_type; 474 node->expr_type = node->funcall.name->expr_type;
471 for (size_t i = 0; i < array_size(node->funcall.args); ++i) { 475 for (size_t i = 0; i < array_size(node->funcall.args); ++i) {
472 Node *arg = node->funcall.args[i]; 476 Node *arg = node->funcall.args[i];
473 if (!resolve_type(scope, arg)) { 477 if (!resolve_type(ast, scope, arg)) {
474 return false; 478 return false;
475 } 479 }
476 Node *expected = val->fun.param_types[i]; 480 Node *expected = val->fun.param_types[i];
@@ -490,18 +494,18 @@ ParseTree *
490semantic_analysis(Root *roots) { 494semantic_analysis(Root *roots) {
491 ParseTree *parse_tree = malloc(sizeof(ParseTree)); 495 ParseTree *parse_tree = malloc(sizeof(ParseTree));
492 parse_tree->roots = roots; 496 parse_tree->roots = roots;
493 parse_tree->global_scope = alloc_scope(NULL); 497 array_init(parse_tree->scopes, 0);
494 parse_tree->current_scope = parse_tree->global_scope; 498 Scope *scope = alloc_scope(NULL);
499 array_push(parse_tree->scopes, scope);
495 500
496 // Fill global scope with default types. 501 // Fill global scope with default types.
497 HashTable *types = parse_tree->global_scope->types; 502 HashTable *types = scope->types;
498 for (size_t i = 0; i < sizeof(default_types)/sizeof(Type); ++i) { 503 for (size_t i = 0; i < sizeof(default_types)/sizeof(Type); ++i) {
499 Type *type = &default_types[i]; 504 Type *type = &default_types[i];
500 ht_insert(types, &type->name, type); 505 ht_insert(types, &type->name, type);
501 } 506 }
502 507
503 // Fill up global function symbols. 508 // Fill up global function symbols.
504 Scope *scope = parse_tree->global_scope;
505 for (size_t i = 0; i < array_size(parse_tree->roots); ++i) { 509 for (size_t i = 0; i < array_size(parse_tree->roots); ++i) {
506 Node *root = parse_tree->roots[i]; 510 Node *root = parse_tree->roots[i];
507 if (root->type == NODE_FUN) { 511 if (root->type == NODE_FUN) {
@@ -518,7 +522,7 @@ semantic_analysis(Root *roots) {
518 for (size_t i = 0; i < array_size(parse_tree->roots); ++i) { 522 for (size_t i = 0; i < array_size(parse_tree->roots); ++i) {
519 // Fill up symbol tables in proper scope and resolve type of expression 523 // Fill up symbol tables in proper scope and resolve type of expression
520 // for all elements. 524 // for all elements.
521 if (!resolve_type(scope, parse_tree->roots[i])) { 525 if (!resolve_type(parse_tree, scope, parse_tree->roots[i])) {
522 return NULL; 526 return NULL;
523 } 527 }
524 } 528 }
diff --git a/src/viz.c b/src/viz.c
index d519d2c..c3b05f9 100644
--- a/src/viz.c
+++ b/src/viz.c
@@ -170,3 +170,63 @@ viz_ast(Root *roots) {
170 printf("}\n"); 170 printf("}\n");
171} 171}
172 172
173void
174viz_symtables(Scope **scopes) {
175 printf("digraph symtables {\n");
176 printf("rankdir=RL;\n");
177 printf("ranksep=\"0.95 equally\";\n");
178 printf("nodesep=\"0.5 equally\";\n");
179 printf("overlap=scale;\n");
180 for (size_t i = 0; i < array_size(scopes); ++i) {
181 Scope *scope = scopes[i];
182 if (array_size(scope->symbols->pairs) == 0) {
183 continue;
184 }
185 printf("%zu [shape=none,label=<", scope->id);
186 printf("<table border=\"1\" cellborder=\"0\">\n");
187 printf("<tr><td>NAME</td><td>KIND</td><td>TYPE</td></tr>");
188 for (size_t j = 0; j < array_cap(scope->symbols->pairs); ++j) {
189 HashTablePair pair = scope->symbols->pairs[j];
190 if (pair.key == NULL) {
191 continue;
192 }
193 Symbol *sym = pair.value;
194 printf("<tr>");
195 printf("<td>");
196 print_node(sym->name);
197 printf("</td>");
198 switch (sym->type) {
199 case SYMBOL_VAR: {
200 printf("<td>var</td>");
201 printf("<td>");
202 print_node(sym->var.type);
203 printf("</td>");
204 } break;
205 case SYMBOL_FUN: {
206 printf("<td>fun</td>");
207 printf("<td>");
208 printf("(");
209 size_t n_params = array_size(sym->fun.param_types);
210 for (size_t k = 0; k < n_params; ++k) {
211 print_node(sym->fun.param_types[k]);
212 if (k < n_params - 1) {
213 printf(" ");
214 }
215 }
216 printf(")");
217 printf(":");
218 print_node(sym->fun.return_type);
219 printf("</td>");
220 } break;
221 }
222 printf("</tr>\n");
223 }
224 printf("</table>\n");
225 printf(">];\n");
226
227 if (scope->parent != NULL) {
228 printf("%zu -> %zu\n", scope->id, scope->parent->id);
229 }
230 }
231 printf("}\n");
232}