From 55ecfb3b7713172f76ddbff022fa4d6a80d0661a Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Fri, 8 Apr 2022 08:25:48 -0300 Subject: Add initial implementation of AST vizualization --- src/lexer.c | 72 ++++++++++++++-------------- src/main.c | 6 +-- src/nodes.c | 3 ++ src/nodes.h | 1 + src/parser.c | 2 +- src/viz.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 196 insertions(+), 40 deletions(-) create mode 100644 src/viz.c (limited to 'src') 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 @@ #include "errors.h" static const char* token_str[] = { - [TOKEN_UNKNOWN] = "TOKEN_UNKNOWN", - [TOKEN_LPAREN] = "TOKEN_LPAREN", - [TOKEN_RPAREN] = "TOKEN_RPAREN", - [TOKEN_LSQUARE] = "TOKEN_LSQUARE", - [TOKEN_RSQUARE] = "TOKEN_RSQUARE", - [TOKEN_LCURLY] = "TOKEN_LCURLY", - [TOKEN_RCURLY] = "TOKEN_RCURLY", - [TOKEN_NUMBER] = "TOKEN_NUMBER", - [TOKEN_SYMBOL] = "TOKEN_SYMBOL", - [TOKEN_STRING] = "TOKEN_STRING", - [TOKEN_NIL] = "TOKEN_NIL", - [TOKEN_TRUE] = "TOKEN_TRUE", - [TOKEN_FALSE] = "TOKEN_FALSE", - [TOKEN_LAMBDA] = "TOKEN_LAMBDA", - [TOKEN_IF] = "TOKEN_IF", - [TOKEN_DEF] = "TOKEN_DEF", - [TOKEN_SET] = "TOKEN_SET", - [TOKEN_FUN] = "TOKEN_FUN", - [TOKEN_STRUCT] = "TOKEN_STRUCT", - [TOKEN_ADD] = "TOKEN_ADD", - [TOKEN_SUB] = "TOKEN_SUB", - [TOKEN_MUL] = "TOKEN_MUL", - [TOKEN_DIV] = "TOKEN_DIV", - [TOKEN_MOD] = "TOKEN_MOD", - [TOKEN_NOT] = "TOKEN_NOT", - [TOKEN_AND] = "TOKEN_AND", - [TOKEN_OR] = "TOKEN_OR", - [TOKEN_EQ] = "TOKEN_EQ", - [TOKEN_LT] = "TOKEN_LT", - [TOKEN_GT] = "TOKEN_GT", - [TOKEN_LE] = "TOKEN_LE", - [TOKEN_GE] = "TOKEN_GE", - [TOKEN_COLON] = "TOKEN_COLON", - [TOKEN_DOT] = "TOKEN_DOT", - [TOKEN_AT] = "TOKEN_AT", - [TOKEN_EOF] = "TOKEN_EOF", + [TOKEN_UNKNOWN] = "UNKNOWN", + [TOKEN_LPAREN] = "LPAREN", + [TOKEN_RPAREN] = "RPAREN", + [TOKEN_LSQUARE] = "LSQUARE", + [TOKEN_RSQUARE] = "RSQUARE", + [TOKEN_LCURLY] = "LCURLY", + [TOKEN_RCURLY] = "RCURLY", + [TOKEN_NUMBER] = "NUMBER", + [TOKEN_SYMBOL] = "SYMBOL", + [TOKEN_STRING] = "STRING", + [TOKEN_NIL] = "NIL", + [TOKEN_TRUE] = "TRUE", + [TOKEN_FALSE] = "FALSE", + [TOKEN_LAMBDA] = "LAMBDA", + [TOKEN_IF] = "IF", + [TOKEN_DEF] = "DEF", + [TOKEN_SET] = "SET", + [TOKEN_FUN] = "FUN", + [TOKEN_STRUCT] = "STRUCT", + [TOKEN_ADD] = "ADD", + [TOKEN_SUB] = "SUB", + [TOKEN_MUL] = "MUL", + [TOKEN_DIV] = "DIV", + [TOKEN_MOD] = "MOD", + [TOKEN_NOT] = "NOT", + [TOKEN_AND] = "AND", + [TOKEN_OR] = "OR", + [TOKEN_EQ] = "EQ", + [TOKEN_LT] = "LT", + [TOKEN_GT] = "GT", + [TOKEN_LE] = "LE", + [TOKEN_GE] = "GE", + [TOKEN_COLON] = "COLON", + [TOKEN_DOT] = "DOT", + [TOKEN_AT] = "AT", + [TOKEN_EOF] = "EOF", }; typedef struct Keyword { diff --git a/src/main.c b/src/main.c index 961905f..a0d26d0 100644 --- a/src/main.c +++ b/src/main.c @@ -9,8 +9,7 @@ #include "lexer.c" #include "nodes.c" #include "parser.c" -// #include "ir.h" -// #include "compiler.h" +#include "viz.c" void init(void) { @@ -29,8 +28,9 @@ process_source(const StringView *source, const char *file_name) { check_errors(file_name); // Parser. - parse(tokens); + ParseTree *parse_tree = parse(tokens); check_errors(file_name); + viz_ast(parse_tree); } 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 @@ #include "nodes.h" +static size_t node_gen_id = 0; + Node * alloc_node(NodeType type) { // TODO: Use a bump allocator? // TODO: Free memory! Node *node = malloc(sizeof(Node)); + node->id = node_gen_id++; node->type = type; node->line = 0; 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 { } TypeClass; typedef struct Node { + size_t id; NodeType type; size_t line; 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) { if (c == '+') { c = sv_next(&tok.value); } - if (c == '0') { + if (c == '0' && sv_peek(&tok.value) != '\0') { c = sv_next(&tok.value); if (c == 'x') { 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 @@ +static const char* node_str[] = { + [NODE_BUILTIN] = "BUILTIN", + [NODE_NUMBER] = "NUMBER", + [NODE_BOOL] = "BOOL", + [NODE_STRING] = "STRING", + [NODE_SYMBOL] = "SYMBOL", + [NODE_TYPE] = "TYPE", + [NODE_DEF] = "DEF", + [NODE_SET] = "SET", + [NODE_FUN] = "FUN", + [NODE_BLOCK] = "BLOCK", + [NODE_IF] = "IF", +}; + +void +viz_node(Node *node) { + if (node == NULL) { + return; + } + printf("%zu [width=2.5,shape=Mrecord,label=\"", node->id); + printf(" %s -- [%4ld:%-4ld] ", node_str[node->type], node->line, node->col); + switch (node->type) { + case NODE_NUMBER: { + printf("| Value: "); + if (node->number.negative) { + printf("-"); + } + if (node->number.fractional != 0) { + printf("%zu.%zu", node->number.integral, node->number.fractional); + } else { + printf("%zu", node->number.integral); + } + printf("\"];\n"); + } break; + case NODE_SYMBOL: + case NODE_TYPE: + case NODE_STRING: { + printf(" | Value: "); + sv_write(&node->string); + printf("\"];\n"); + } break; + case NODE_BOOL: { + printf(" | Value: "); + if (node->boolean) { + printf("true"); + } else { + printf("false"); + } + printf("\"];\n"); + } break; + case NODE_BUILTIN: { + printf(" | Name: %s", token_str[node->builtin.type]); + printf(" | Args: "); + printf("\"];\n"); + size_t n_args = array_size(node->builtin.args); + for (size_t i = 0; i < n_args; ++i) { + viz_node(node->builtin.args[i]); + printf("%zu:args:e->%zu:top:w;\n", node->id, node->builtin.args[i]->id); + } + } break; + case NODE_DEF: { + printf(" | Name: "); + sv_write(&node->def.symbol->string); + printf(" | Type: "); + sv_write(&node->def.type->string); + printf(" | Expr: "); + printf("\"];\n"); + viz_node(node->def.value); + printf("%zu:val:e->%zu:top:w;\n", node->id, node->def.value->id); + } break; + case NODE_SET: { + printf(" | Name: "); + sv_write(&node->set.symbol->string); + printf(" | Expr: "); + printf("\"];\n"); + viz_node(node->set.value); + printf("%zu:val:e->%zu:top:w;\n", node->id, node->def.value->id); + } break; + case NODE_BLOCK: { + printf(" | Exprs: "); + printf("\"];\n"); + size_t n_expr = array_size(node->block.expr); + for (size_t i = 0; i < n_expr; ++i) { + viz_node(node->block.expr[i]); + printf("%zu:expr:e->%zu:top:w;\n", node->id, node->block.expr[i]->id); + } + } break; + case NODE_IF: { + printf(" | Cond: "); + printf(" | ExprTrue:"); + if (node->ifexpr.expr_false != NULL) { + printf(" | ExprFalse: "); + } + printf("\"];\n"); + viz_node(node->ifexpr.cond); + printf("%zu:cond:e->%zu:top:w;\n", node->id, node->ifexpr.cond->id); + viz_node(node->ifexpr.expr_true); + printf("%zu:t:e->%zu:top:w;\n", node->id, node->ifexpr.expr_true->id); + if (node->ifexpr.expr_false != NULL) { + viz_node(node->ifexpr.expr_false); + printf("%zu:f:e->%zu:top:w;\n", node->id, node->ifexpr.expr_false->id); + } + } break; + case NODE_FUN: { + printf(" | Name: "); + sv_write(&node->fun.name->string); + printf(" | Type: "); + printf("("); + size_t n_params = array_size(node->fun.param_names); + for (size_t i = 0; i < n_params; ++i) { + printf(":"); + sv_write(&node->fun.param_types[i]->string); + if (i < n_params - 1) { + printf(" "); + } + } + printf("):"); + sv_write(&node->fun.return_type->string); + if (n_params > 0) { + printf(" | Parameters: ("); + for (size_t i = 0; i < n_params; ++i) { + sv_write(&node->fun.param_names[i]->string); + if (i < n_params - 1) { + printf(" "); + } + } + printf(")"); + } + printf(" | Body: "); + printf("\"];\n"); + viz_node(node->fun.body); + printf("%zu:bod:e->%zu:top:w;\n", node->id, node->fun.body->id); + } break; + } +} + +void +viz_ast(ParseTree *parse_tree) { + printf("digraph ast {\n"); + printf("rankdir=LR;\n"); + printf("ranksep=\"0.95 equally\";\n"); + printf("nodesep=\"0.5 equally\";\n"); + printf("overlap=scale;\n"); + for (size_t i = 0; i < array_size(parse_tree->roots); ++i) { + printf("subgraph %zu {\n", i); + Node *root = parse_tree->roots[array_size(parse_tree->roots) - 1 - i]; + viz_node(root); + printf("}\n"); + } + printf("}\n"); +} + -- cgit v1.2.1