Skip to content

Commit

Permalink
Merge pull request orangeduck#50 from petermlm/master
Browse files Browse the repository at this point in the history
Tree Traversal
  • Loading branch information
orangeduck committed Jun 5, 2016
2 parents b93399d + 913cc58 commit 5f9863f
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 2 deletions.
50 changes: 48 additions & 2 deletions examples/tree_traversal.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ int main(int argc, char *argv[]) {
mpc_parser_t *Input = mpc_new("input");
mpc_parser_t *Node = mpc_new("node");
mpc_parser_t *Leaf = mpc_new("leaf");
mpc_ast_t *ast, *tree, *child, *child_sub;
mpc_ast_t *ast, *tree, *child, *child_sub, *ast_next;
mpc_ast_trav_t *trav;
mpc_result_t r;
int index, lb;
int index, lb, i;

mpca_lang(MPCA_LANG_PREDICTIVE,
" node : '(' <node> ',' /foo/ ',' <node> ')' | <leaf>;"
Expand Down Expand Up @@ -65,6 +66,51 @@ int main(int argc, char *argv[]) {
child_sub = mpc_ast_get_child_lb(child, "node|leaf|regex", lb);
}

/* Traversal */
printf("Pre order tree traversal.\n");
trav = mpc_ast_traverse_start(ast, mpc_ast_trav_order_pre);

ast_next = mpc_ast_traverse_next(&trav);

while(ast_next != NULL) {
printf("Tag: %s; Contents: %s\n",
ast_next->tag,
ast_next->contents);
ast_next = mpc_ast_traverse_next(&trav);
}

mpc_ast_traverse_free(&trav);

printf("Post order tree traversal.\n");

trav = mpc_ast_traverse_start(ast, mpc_ast_trav_order_post);

ast_next = mpc_ast_traverse_next(&trav);

while(ast_next != NULL) {
printf("Tag: %s; Contents: %s\n",
ast_next->tag,
ast_next->contents);
ast_next = mpc_ast_traverse_next(&trav);
}

mpc_ast_traverse_free(&trav);

printf("Partial traversal.\n");

trav = mpc_ast_traverse_start(ast, mpc_ast_trav_order_post);

ast_next = mpc_ast_traverse_next(&trav);

for(i=0; i<2 && ast_next != NULL; i++) {
printf("Tag: %s; Contents: %s\n",
ast_next->tag,
ast_next->contents);
ast_next = mpc_ast_traverse_next(&trav);
}

mpc_ast_traverse_free(&trav);

/* Clean up and return */
mpc_cleanup(3, Node, Leaf, Input);
mpc_ast_delete(ast);
Expand Down
136 changes: 136 additions & 0 deletions mpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2808,6 +2808,142 @@ mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb) {
return NULL;
}

mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast,
mpc_ast_trav_order_t order)
{
mpc_ast_trav_t *trav, *n_trav;
mpc_ast_t *cnode = ast;

/* Create the traversal structure */
trav = malloc(sizeof(mpc_ast_trav_t));
trav->curr_node = cnode;
trav->parent = NULL;
trav->curr_child = 0;
trav->order = order;

/* Get start node */
switch(order) {
case mpc_ast_trav_order_pre:
/* Nothing else is needed for pre order start */
break;

case mpc_ast_trav_order_post:
while(cnode->children_num > 0) {
cnode = cnode->children[0];

n_trav = malloc(sizeof(mpc_ast_trav_t));
n_trav->curr_node = cnode;
n_trav->parent = trav;
n_trav->curr_child = 0;
n_trav->order = order;

trav = n_trav;
}

break;

default:
/* Unreachable, but compiler complaints */
break;
}

return trav;
}

mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav) {
mpc_ast_trav_t *n_trav, *to_free;
mpc_ast_t *ret = NULL;
int cchild;

/* The end of traversal was reached */
if(*trav == NULL) return NULL;

switch((*trav)->order) {
case mpc_ast_trav_order_pre:
ret = (*trav)->curr_node;

/* If there aren't any more children, go up */
while(*trav != NULL &&
(*trav)->curr_child >= (*trav)->curr_node->children_num)
{
to_free = *trav;
*trav = (*trav)->parent;
free(to_free);
}

/* If trav is NULL, the end was reached */
if(*trav == NULL) {
break;
}

/* Go to next child */
n_trav = malloc(sizeof(mpc_ast_trav_t));

cchild = (*trav)->curr_child;
n_trav->curr_node = (*trav)->curr_node->children[cchild];
n_trav->parent = *trav;
n_trav->curr_child = 0;
n_trav->order = (*trav)->order;

(*trav)->curr_child++;
*trav = n_trav;

break;

case mpc_ast_trav_order_post:
ret = (*trav)->curr_node;

/* Move up tree to the parent If the parent doesn't have any more nodes,
* then this is the current node. If it does, move down to its left most
* child. Also, free the previous traversal node */
to_free = *trav;
*trav = (*trav)->parent;
free(to_free);

if(*trav == NULL)
break;

/* Next child */
(*trav)->curr_child++;

/* If there aren't any more children, this is the next node */
if((*trav)->curr_child >= (*trav)->curr_node->children_num) {
break;
}

/* If there are still more children, find the leftmost child from this
* node */
while((*trav)->curr_node->children_num > 0) {
n_trav = malloc(sizeof(mpc_ast_trav_t));

cchild = (*trav)->curr_child;
n_trav->curr_node = (*trav)->curr_node->children[cchild];
n_trav->parent = *trav;
n_trav->curr_child = 0;
n_trav->order = (*trav)->order;

*trav = n_trav;
}

default:
/* Unreachable, but compiler complaints */
break;
}

return ret;
}

void mpc_ast_traverse_free(mpc_ast_trav_t **trav) {
mpc_ast_trav_t *n_trav;

/* Go through parents until all are free */
while(*trav != NULL) {
n_trav = (*trav)->parent;
free(*trav);
*trav = n_trav;
}
}

mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **xs) {

int i, j;
Expand Down
19 changes: 19 additions & 0 deletions mpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,25 @@ int mpc_ast_get_index_lb(mpc_ast_t *ast, const char *tag, int lb);
mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, const char *tag);
mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb);

typedef enum {
mpc_ast_trav_order_pre,
mpc_ast_trav_order_post
} mpc_ast_trav_order_t;

typedef struct mpc_ast_trav_t {
mpc_ast_t *curr_node;
struct mpc_ast_trav_t *parent;
int curr_child;
mpc_ast_trav_order_t order;
} mpc_ast_trav_t;

mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast,
mpc_ast_trav_order_t order);

mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav);

void mpc_ast_traverse_free(mpc_ast_trav_t **trav);

/*
** Warning: This function currently doesn't test for equality of the `state` member!
*/
Expand Down

0 comments on commit 5f9863f

Please sign in to comment.