diff options
author | Bad Diode <bd@badd10de.dev> | 2022-04-08 08:25:48 -0300 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2022-04-08 08:25:48 -0300 |
commit | 55ecfb3b7713172f76ddbff022fa4d6a80d0661a (patch) | |
tree | 6a6baae20d67824d5f79b801b27f58cc967a3ba1 /src | |
parent | 9f934cbc0f0fd60a6938ac1c4c84edc270de94ca (diff) | |
download | bdl-55ecfb3b7713172f76ddbff022fa4d6a80d0661a.tar.gz bdl-55ecfb3b7713172f76ddbff022fa4d6a80d0661a.zip |
Add initial implementation of AST vizualization
Diffstat (limited to 'src')
-rw-r--r-- | src/lexer.c | 72 | ||||
-rw-r--r-- | src/main.c | 6 | ||||
-rw-r--r-- | src/nodes.c | 3 | ||||
-rw-r--r-- | src/nodes.h | 1 | ||||
-rw-r--r-- | src/parser.c | 2 | ||||
-rw-r--r-- | src/viz.c | 152 |
6 files changed, 196 insertions, 40 deletions
diff --git a/src/lexer.c b/src/lexer.c index b4dcaf5..a6d7c74 100644 --- a/src/lexer.c +++ b/src/lexer.c | |||
@@ -2,42 +2,42 @@ | |||
2 | #include "errors.h" | 2 | #include "errors.h" |
3 | 3 | ||
4 | static const char* token_str[] = { | 4 | static const char* token_str[] = { |
5 | [TOKEN_UNKNOWN] = "TOKEN_UNKNOWN", | 5 | [TOKEN_UNKNOWN] = "UNKNOWN", |
6 | [TOKEN_LPAREN] = "TOKEN_LPAREN", | 6 | [TOKEN_LPAREN] = "LPAREN", |
7 | [TOKEN_RPAREN] = "TOKEN_RPAREN", | 7 | [TOKEN_RPAREN] = "RPAREN", |
8 | [TOKEN_LSQUARE] = "TOKEN_LSQUARE", | 8 | [TOKEN_LSQUARE] = "LSQUARE", |
9 | [TOKEN_RSQUARE] = "TOKEN_RSQUARE", | 9 | [TOKEN_RSQUARE] = "RSQUARE", |
10 | [TOKEN_LCURLY] = "TOKEN_LCURLY", | 10 | [TOKEN_LCURLY] = "LCURLY", |
11 | [TOKEN_RCURLY] = "TOKEN_RCURLY", | 11 | [TOKEN_RCURLY] = "RCURLY", |
12 | [TOKEN_NUMBER] = "TOKEN_NUMBER", | 12 | [TOKEN_NUMBER] = "NUMBER", |
13 | [TOKEN_SYMBOL] = "TOKEN_SYMBOL", | 13 | [TOKEN_SYMBOL] = "SYMBOL", |
14 | [TOKEN_STRING] = "TOKEN_STRING", | 14 | [TOKEN_STRING] = "STRING", |
15 | [TOKEN_NIL] = "TOKEN_NIL", | 15 | [TOKEN_NIL] = "NIL", |
16 | [TOKEN_TRUE] = "TOKEN_TRUE", | 16 | [TOKEN_TRUE] = "TRUE", |
17 | [TOKEN_FALSE] = "TOKEN_FALSE", | 17 | [TOKEN_FALSE] = "FALSE", |
18 | [TOKEN_LAMBDA] = "TOKEN_LAMBDA", | 18 | [TOKEN_LAMBDA] = "LAMBDA", |
19 | [TOKEN_IF] = "TOKEN_IF", | 19 | [TOKEN_IF] = "IF", |
20 | [TOKEN_DEF] = "TOKEN_DEF", | 20 | [TOKEN_DEF] = "DEF", |
21 | [TOKEN_SET] = "TOKEN_SET", | 21 | [TOKEN_SET] = "SET", |
22 | [TOKEN_FUN] = "TOKEN_FUN", | 22 | [TOKEN_FUN] = "FUN", |
23 | [TOKEN_STRUCT] = "TOKEN_STRUCT", | 23 | [TOKEN_STRUCT] = "STRUCT", |
24 | [TOKEN_ADD] = "TOKEN_ADD", | 24 | [TOKEN_ADD] = "ADD", |
25 | [TOKEN_SUB] = "TOKEN_SUB", | 25 | [TOKEN_SUB] = "SUB", |
26 | [TOKEN_MUL] = "TOKEN_MUL", | 26 | [TOKEN_MUL] = "MUL", |
27 | [TOKEN_DIV] = "TOKEN_DIV", | 27 | [TOKEN_DIV] = "DIV", |
28 | [TOKEN_MOD] = "TOKEN_MOD", | 28 | [TOKEN_MOD] = "MOD", |
29 | [TOKEN_NOT] = "TOKEN_NOT", | 29 | [TOKEN_NOT] = "NOT", |
30 | [TOKEN_AND] = "TOKEN_AND", | 30 | [TOKEN_AND] = "AND", |
31 | [TOKEN_OR] = "TOKEN_OR", | 31 | [TOKEN_OR] = "OR", |
32 | [TOKEN_EQ] = "TOKEN_EQ", | 32 | [TOKEN_EQ] = "EQ", |
33 | [TOKEN_LT] = "TOKEN_LT", | 33 | [TOKEN_LT] = "LT", |
34 | [TOKEN_GT] = "TOKEN_GT", | 34 | [TOKEN_GT] = "GT", |
35 | [TOKEN_LE] = "TOKEN_LE", | 35 | [TOKEN_LE] = "LE", |
36 | [TOKEN_GE] = "TOKEN_GE", | 36 | [TOKEN_GE] = "GE", |
37 | [TOKEN_COLON] = "TOKEN_COLON", | 37 | [TOKEN_COLON] = "COLON", |
38 | [TOKEN_DOT] = "TOKEN_DOT", | 38 | [TOKEN_DOT] = "DOT", |
39 | [TOKEN_AT] = "TOKEN_AT", | 39 | [TOKEN_AT] = "AT", |
40 | [TOKEN_EOF] = "TOKEN_EOF", | 40 | [TOKEN_EOF] = "EOF", |
41 | }; | 41 | }; |
42 | 42 | ||
43 | typedef struct Keyword { | 43 | typedef struct Keyword { |
@@ -9,8 +9,7 @@ | |||
9 | #include "lexer.c" | 9 | #include "lexer.c" |
10 | #include "nodes.c" | 10 | #include "nodes.c" |
11 | #include "parser.c" | 11 | #include "parser.c" |
12 | // #include "ir.h" | 12 | #include "viz.c" |
13 | // #include "compiler.h" | ||
14 | 13 | ||
15 | void | 14 | void |
16 | init(void) { | 15 | init(void) { |
@@ -29,8 +28,9 @@ process_source(const StringView *source, const char *file_name) { | |||
29 | check_errors(file_name); | 28 | check_errors(file_name); |
30 | 29 | ||
31 | // Parser. | 30 | // Parser. |
32 | parse(tokens); | 31 | ParseTree *parse_tree = parse(tokens); |
33 | check_errors(file_name); | 32 | check_errors(file_name); |
33 | viz_ast(parse_tree); | ||
34 | } | 34 | } |
35 | 35 | ||
36 | void | 36 | void |
diff --git a/src/nodes.c b/src/nodes.c index 5689d18..35d123a 100644 --- a/src/nodes.c +++ b/src/nodes.c | |||
@@ -1,10 +1,13 @@ | |||
1 | #include "nodes.h" | 1 | #include "nodes.h" |
2 | 2 | ||
3 | static size_t node_gen_id = 0; | ||
4 | |||
3 | Node * | 5 | Node * |
4 | alloc_node(NodeType type) { | 6 | alloc_node(NodeType type) { |
5 | // TODO: Use a bump allocator? | 7 | // TODO: Use a bump allocator? |
6 | // TODO: Free memory! | 8 | // TODO: Free memory! |
7 | Node *node = malloc(sizeof(Node)); | 9 | Node *node = malloc(sizeof(Node)); |
10 | node->id = node_gen_id++; | ||
8 | node->type = type; | 11 | node->type = type; |
9 | node->line = 0; | 12 | node->line = 0; |
10 | node->col = 0; | 13 | node->col = 0; |
diff --git a/src/nodes.h b/src/nodes.h index 853495a..be6f7df 100644 --- a/src/nodes.h +++ b/src/nodes.h | |||
@@ -24,6 +24,7 @@ typedef enum TypeClass { | |||
24 | } TypeClass; | 24 | } TypeClass; |
25 | 25 | ||
26 | typedef struct Node { | 26 | typedef struct Node { |
27 | size_t id; | ||
27 | NodeType type; | 28 | NodeType type; |
28 | size_t line; | 29 | size_t line; |
29 | size_t col; | 30 | size_t col; |
diff --git a/src/parser.c b/src/parser.c index cf7aebb..0594d2c 100644 --- a/src/parser.c +++ b/src/parser.c | |||
@@ -54,7 +54,7 @@ parse_number(Parser *parser) { | |||
54 | if (c == '+') { | 54 | if (c == '+') { |
55 | c = sv_next(&tok.value); | 55 | c = sv_next(&tok.value); |
56 | } | 56 | } |
57 | if (c == '0') { | 57 | if (c == '0' && sv_peek(&tok.value) != '\0') { |
58 | c = sv_next(&tok.value); | 58 | c = sv_next(&tok.value); |
59 | if (c == 'x') { | 59 | if (c == 'x') { |
60 | base = 16; | 60 | base = 16; |
diff --git a/src/viz.c b/src/viz.c new file mode 100644 index 0000000..d409472 --- /dev/null +++ b/src/viz.c | |||
@@ -0,0 +1,152 @@ | |||
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 | }; | ||
14 | |||
15 | void | ||
16 | viz_node(Node *node) { | ||
17 | if (node == NULL) { | ||
18 | return; | ||
19 | } | ||
20 | printf("%zu [width=2.5,shape=Mrecord,label=\"", node->id); | ||
21 | printf("<top> %s -- [%4ld:%-4ld] ", node_str[node->type], node->line, node->col); | ||
22 | switch (node->type) { | ||
23 | case NODE_NUMBER: { | ||
24 | printf("| Value: "); | ||
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 | printf("\"];\n"); | ||
34 | } break; | ||
35 | case NODE_SYMBOL: | ||
36 | case NODE_TYPE: | ||
37 | case NODE_STRING: { | ||
38 | printf(" | Value: "); | ||
39 | sv_write(&node->string); | ||
40 | printf("\"];\n"); | ||
41 | } break; | ||
42 | case NODE_BOOL: { | ||
43 | printf(" | Value: "); | ||
44 | if (node->boolean) { | ||
45 | printf("true"); | ||
46 | } else { | ||
47 | printf("false"); | ||
48 | } | ||
49 | printf("\"];\n"); | ||
50 | } break; | ||
51 | case NODE_BUILTIN: { | ||
52 | printf(" | Name: %s", token_str[node->builtin.type]); | ||
53 | printf(" | <args> Args: "); | ||
54 | printf("\"];\n"); | ||
55 | size_t n_args = array_size(node->builtin.args); | ||
56 | for (size_t i = 0; i < n_args; ++i) { | ||
57 | viz_node(node->builtin.args[i]); | ||
58 | printf("%zu:args:e->%zu:top:w;\n", node->id, node->builtin.args[i]->id); | ||
59 | } | ||
60 | } break; | ||
61 | case NODE_DEF: { | ||
62 | printf(" | Name: "); | ||
63 | sv_write(&node->def.symbol->string); | ||
64 | printf(" | Type: "); | ||
65 | sv_write(&node->def.type->string); | ||
66 | printf(" | <val> Expr: "); | ||
67 | printf("\"];\n"); | ||
68 | viz_node(node->def.value); | ||
69 | printf("%zu:val:e->%zu:top:w;\n", node->id, node->def.value->id); | ||
70 | } break; | ||
71 | case NODE_SET: { | ||
72 | printf(" | Name: "); | ||
73 | sv_write(&node->set.symbol->string); | ||
74 | printf(" | <val> Expr: "); | ||
75 | printf("\"];\n"); | ||
76 | viz_node(node->set.value); | ||
77 | printf("%zu:val:e->%zu:top:w;\n", node->id, node->def.value->id); | ||
78 | } break; | ||
79 | case NODE_BLOCK: { | ||
80 | printf(" | <expr> Exprs: "); | ||
81 | printf("\"];\n"); | ||
82 | size_t n_expr = array_size(node->block.expr); | ||
83 | for (size_t i = 0; i < n_expr; ++i) { | ||
84 | viz_node(node->block.expr[i]); | ||
85 | printf("%zu:expr:e->%zu:top:w;\n", node->id, node->block.expr[i]->id); | ||
86 | } | ||
87 | } break; | ||
88 | case NODE_IF: { | ||
89 | printf(" | <cond> Cond: "); | ||
90 | printf(" | <t> ExprTrue:"); | ||
91 | if (node->ifexpr.expr_false != NULL) { | ||
92 | printf(" | <f> ExprFalse: "); | ||
93 | } | ||
94 | printf("\"];\n"); | ||
95 | viz_node(node->ifexpr.cond); | ||
96 | printf("%zu:cond:e->%zu:top:w;\n", node->id, node->ifexpr.cond->id); | ||
97 | viz_node(node->ifexpr.expr_true); | ||
98 | printf("%zu:t:e->%zu:top:w;\n", node->id, node->ifexpr.expr_true->id); | ||
99 | if (node->ifexpr.expr_false != NULL) { | ||
100 | viz_node(node->ifexpr.expr_false); | ||
101 | printf("%zu:f:e->%zu:top:w;\n", node->id, node->ifexpr.expr_false->id); | ||
102 | } | ||
103 | } break; | ||
104 | case NODE_FUN: { | ||
105 | printf(" | Name: "); | ||
106 | sv_write(&node->fun.name->string); | ||
107 | printf(" | Type: "); | ||
108 | printf("("); | ||
109 | size_t n_params = array_size(node->fun.param_names); | ||
110 | for (size_t i = 0; i < n_params; ++i) { | ||
111 | printf(":"); | ||
112 | sv_write(&node->fun.param_types[i]->string); | ||
113 | if (i < n_params - 1) { | ||
114 | printf(" "); | ||
115 | } | ||
116 | } | ||
117 | printf("):"); | ||
118 | sv_write(&node->fun.return_type->string); | ||
119 | if (n_params > 0) { | ||
120 | printf(" | Parameters: ("); | ||
121 | for (size_t i = 0; i < n_params; ++i) { | ||
122 | sv_write(&node->fun.param_names[i]->string); | ||
123 | if (i < n_params - 1) { | ||
124 | printf(" "); | ||
125 | } | ||
126 | } | ||
127 | printf(")"); | ||
128 | } | ||
129 | printf(" | <bod> Body: "); | ||
130 | printf("\"];\n"); | ||
131 | viz_node(node->fun.body); | ||
132 | printf("%zu:bod:e->%zu:top:w;\n", node->id, node->fun.body->id); | ||
133 | } break; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | void | ||
138 | viz_ast(ParseTree *parse_tree) { | ||
139 | printf("digraph ast {\n"); | ||
140 | printf("rankdir=LR;\n"); | ||
141 | printf("ranksep=\"0.95 equally\";\n"); | ||
142 | printf("nodesep=\"0.5 equally\";\n"); | ||
143 | printf("overlap=scale;\n"); | ||
144 | for (size_t i = 0; i < array_size(parse_tree->roots); ++i) { | ||
145 | printf("subgraph %zu {\n", i); | ||
146 | Node *root = parse_tree->roots[array_size(parse_tree->roots) - 1 - i]; | ||
147 | viz_node(root); | ||
148 | printf("}\n"); | ||
149 | } | ||
150 | printf("}\n"); | ||
151 | } | ||
152 | |||