143 lines
3.7 KiB
C
143 lines
3.7 KiB
C
#include "vslc.h"
|
|
|
|
#include "stdarg.h"
|
|
#include "stdlib.h"
|
|
|
|
/* #include "nodetypes.h" */
|
|
|
|
// Global root for abstract syntax tree
|
|
node_t* root;
|
|
|
|
// Declarations of helper functions defined further down in this file
|
|
static void node_print(node_t* node, int nesting);
|
|
static void destroy_subtree(node_t* discard);
|
|
|
|
// Initialize a node with the given type and children
|
|
node_t* node_create(node_type_t type, size_t n_children, ...)
|
|
{
|
|
node_t *node = malloc(sizeof(node_t));
|
|
node->type = type;
|
|
node->n_children = n_children;
|
|
node->children = malloc(sizeof(node_t) * n_children);
|
|
|
|
va_list args;
|
|
va_start(args, n_children);
|
|
for (int i = 0; i < n_children; i++) {
|
|
node->children[i] = va_arg(args, node_t*);
|
|
}
|
|
va_end(args);
|
|
|
|
return node;
|
|
}
|
|
|
|
// Append an element to the given LIST node, returns the list node
|
|
node_t* append_to_list_node(node_t* list_node, node_t* element)
|
|
{
|
|
assert(list_node->type == LIST);
|
|
|
|
// Calculate the minimum size of the new allocation
|
|
size_t min_allocation_size = list_node->n_children + 1;
|
|
|
|
// Round up to the next power of two
|
|
size_t new_allocation_size = 1;
|
|
while (new_allocation_size < min_allocation_size)
|
|
new_allocation_size *= 2;
|
|
|
|
// Resize the allocation
|
|
list_node->children = realloc(list_node->children, new_allocation_size * sizeof(node_t*));
|
|
|
|
// Insert the new element and increase child count by 1
|
|
list_node->children[list_node->n_children] = element;
|
|
list_node->n_children++;
|
|
|
|
return list_node;
|
|
}
|
|
|
|
// Outputs the entire syntax tree to the terminal
|
|
void print_syntax_tree(void)
|
|
{
|
|
// If the environment variable GRAPHVIZ_OUTPUT is set, print a GraphViz graph in the dot format
|
|
if (getenv("GRAPHVIZ_OUTPUT") != NULL)
|
|
graphviz_node_print(root);
|
|
else
|
|
node_print(root, 0);
|
|
}
|
|
|
|
// Frees all memory held by the syntax tree
|
|
void destroy_syntax_tree(void)
|
|
{
|
|
destroy_subtree(root);
|
|
root = NULL;
|
|
}
|
|
|
|
// The rest of this file contains private helper functions used by the above functions
|
|
|
|
// Prints out the given node and all its children recursively
|
|
static void node_print(node_t* node, int nesting)
|
|
{
|
|
// Indent the line based on how deep the node is in the syntax tree
|
|
printf("%*s", nesting, "");
|
|
|
|
if (node == NULL)
|
|
{
|
|
printf("(NULL)\n");
|
|
return;
|
|
}
|
|
|
|
printf("%s", NODE_TYPE_NAMES[node->type]);
|
|
|
|
// For nodes with extra data, include it in the printout
|
|
switch (node->type)
|
|
{
|
|
case OPERATOR:
|
|
printf(" (%s)", node->data.operator);
|
|
break;
|
|
case IDENTIFIER:
|
|
printf(" (%s)", node->data.identifier);
|
|
break;
|
|
case NUMBER_LITERAL:
|
|
printf(" (%ld)", node->data.number_literal);
|
|
break;
|
|
case STRING_LITERAL:
|
|
printf(" (%s)", node->data.string_literal);
|
|
break;
|
|
case STRING_LIST_REFERENCE:
|
|
printf(" (%zu)", node->data.string_list_index);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
putchar('\n');
|
|
|
|
// Recursively print children, with some more indentation
|
|
for (size_t i = 0; i < node->n_children; i++)
|
|
node_print(node->children[i], nesting + 1);
|
|
}
|
|
|
|
// Frees the memory owned by the given node, but does not touch its children
|
|
static void node_finalize(node_t* discard)
|
|
{
|
|
if (discard->type == IDENTIFIER || discard->type == STRING_LITERAL)
|
|
free(&discard->data);
|
|
free(discard->children);
|
|
free(discard);
|
|
}
|
|
|
|
// Recursively frees the memory owned by the given node, and all its children
|
|
static void destroy_subtree(node_t* discard)
|
|
{
|
|
if (discard->n_children == 0)
|
|
node_finalize(discard);
|
|
for (int i = 0; i < discard->n_children; i++) {
|
|
node_t *child = discard->children[i];
|
|
destroy_subtree(child);
|
|
}
|
|
}
|
|
|
|
// Definition of the global string array NODE_TYPE_NAMES
|
|
const char* NODE_TYPE_NAMES[NODE_TYPE_COUNT] = {
|
|
#define NODE_TYPE(node_type) #node_type
|
|
#include "nodetypes.h"
|
|
};
|