diff options
Diffstat (limited to 'src/commit.c')
-rw-r--r-- | src/commit.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/src/commit.c b/src/commit.c new file mode 100644 index 00000000..473f4bbb --- /dev/null +++ b/src/commit.c @@ -0,0 +1,160 @@ +/* + * Copyright 2015 Adrian Thurston <thurston@complang.org> + */ + +/* This file is part of Colm. + * + * Colm is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Colm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Colm; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "debug.h" +#include "pdarun.h" +#include "bytecode.h" +#include "tree.h" +#include "pool.h" + +#include "internal.h" + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +//#define true 1 +//#define false 0 + +static void commit_clear_parse_tree( program_t *prg, tree_t **sp, parse_tree_t *pt ) +{ + tree_t **top = vm_ptop(); + + if ( pt == 0 ) + return; + +free_tree: + if ( pt->next != 0 ) { + vm_push_ptree( pt->next ); + } + + if ( pt->left_ignore != 0 ) { + vm_push_ptree( pt->left_ignore ); + } + + if ( pt->child != 0 ) { + vm_push_ptree( pt->child ); + } + + if ( pt->right_ignore != 0 ) { + vm_push_ptree( pt->right_ignore ); + } + + if ( pt->shadow != 0 ) { + colm_tree_downref( prg, sp, pt->shadow->tree ); + kid_free( prg, pt->shadow ); + } + + //printf( "commit_parse_tree_free %p\n", pt ); + parse_tree_free( prg, pt ); + + /* Any trees to downref? */ + if ( sp != top ) { + pt = vm_pop_ptree(); + goto free_tree; + } +} + +static int been_committed( parse_tree_t *parse_tree ) +{ + return parse_tree->flags & PF_COMMITTED; +} + + +static void commit_forward_recurse( program_t *prg, tree_t **root, parse_tree_t *pt ) +{ + tree_t **sp = root; + + parse_tree_t *lel = pt; + +recurse: + + if ( lel->child != 0 ) { + /* There are children. Must process all children first. */ + vm_push_ptree( lel ); + + lel = lel->child; + while ( lel != 0 ) { + goto recurse; + resume: + lel = lel->next; + } + + lel = vm_pop_ptree(); + } + + /* Now can execute the reduction action. */ + + commit_clear_parse_tree( prg, sp, lel->child ); + lel->child = 0; + pt->flags |= PF_COMMITTED; + + if ( sp != root ) + goto resume; +} + +void commit_clear( program_t *prg, tree_t **root, struct pda_run *pda_run ) +{ + tree_t **sp = root; + parse_tree_t *pt = pda_run->stack_top; + + /* The top level of the stack is linked right to left. This is the + * traversal order we need for committing. */ + while ( pt != 0 && !been_committed( pt ) ) { + vm_push_ptree( pt ); + pt = pt->next; + } + + while ( sp != root ) { + pt = vm_pop_ptree(); + + commit_forward_recurse( prg, sp, pt ); + + pt->flags |= PF_COMMITTED; + pt = pt->next; + } +} + +void commit_reduce( program_t *prg, tree_t **root, struct pda_run *pda_run ) +{ + tree_t **sp = root; + parse_tree_t *pt = pda_run->stack_top; + + /* The top level of the stack is linked right to left. This is the + * traversal order we need for committing. */ + while ( pt != 0 && !been_committed( pt ) ) { + vm_push_ptree( pt ); + pt = pt->next; + } + + while ( sp != root ) { + pt = vm_pop_ptree(); + + commit_clear_parse_tree( prg, sp, pt->child ); + pt->child = 0; + + pt->flags |= PF_COMMITTED; + pt = pt->next; + } +} |