diff options
Diffstat (limited to 'lib/forlan.c')
-rw-r--r-- | lib/forlan.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/lib/forlan.c b/lib/forlan.c new file mode 100644 index 0000000..0854d08 --- /dev/null +++ b/lib/forlan.c @@ -0,0 +1,258 @@ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat 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 3, or (at your option) + any later version. + + Eclat 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 Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include "grecs.h" +#include "forlan.h" + +int forlan_dbg = -1; + +void +forlan_init() +{ + forlan_dbg = debug_register("forlan"); +} + +union forlan_node * +forlan_node_create(enum forlan_type type) +{ + union forlan_node *p = grecs_zalloc(sizeof(*p)); + p->type = type; + return p; +} + +static void f_dump_node(FILE *fp, union forlan_node *p, int *num, int lev); + + +static void +free_type_null(union forlan_node *p) +{ + warn("freeing undefined forlan_node"); +} + +void +dump_null(FILE *fp, union forlan_node *p, int *num, int lev) +{ + fprintf(fp, "[undefined node]\n"); +} + +static void +free_type_comp(union forlan_node *p) +{ + forlan_node_free(p->comp.node); +} +void +dump_comp(FILE *fp, union forlan_node *p, int *num, int lev) +{ + fprintf(fp, "COMP"); + if (p->comp.abs) + fprintf(fp, " ABS"); + fputc('\n', fp); + forlan_dump_node(fp, p->comp.node, num, lev + 1); +} + +static void +free_type_test(union forlan_node *p) +{ + free(p->test.comp); + free(p->test.value); +} +void +dump_test(FILE *fp, union forlan_node *p, int *num, int lev) +{ + fprintf(fp, "TEST: %s[%s]\n", p->test.comp, p->test.value); +} + +static void +free_type_func(union forlan_node *p) +{ + grecs_list_free(p->func.args); +} +void +dump_func(FILE *fp, union forlan_node *p, int *num, int lev) +{ + struct grecs_list_entry *ep; + fprintf(fp, "CALL: %s\n", p->func.fp); + if (p->func.args) + for (ep = p->func.args->head; ep; ep = ep->next) + forlan_dump_node(fp, ep->data, num, lev + 1); +} + +static void +free_type_cond(union forlan_node *p) +{ + forlan_node_free((union forlan_node *)p->cond.expr); + forlan_node_free(p->cond.iftrue); + forlan_node_free(p->cond.iffalse); +} +void +dump_cond(FILE *fp, union forlan_node *p, int *num, int lev) +{ + int n = *num; + fprintf(fp, "COND\n"); + forlan_dump_node(fp, p->cond.expr, num, lev + 1); + fprintf(fp, "%04d: %*.*sIFTRUE %04d\n", ++*num, lev, lev, "", n); + forlan_dump_node(fp, p->cond.iftrue, num, lev + 1); + fprintf(fp, "%04d: %*.*sIFFALSE %04d\n", ++*num, lev, lev, "", n); + forlan_dump_node(fp, p->cond.iffalse, num, lev + 1); +} + +static void +free_type_stmt(union forlan_node *p) +{ + forlan_node_free(p->stmt.stmt); + forlan_node_free(p->stmt.next); +} +void +dump_stmt(FILE *fp, union forlan_node *p, int *num, int lev) +{ + f_dump_node(fp, p->stmt.stmt, num, lev); + forlan_dump_node(fp, p->stmt.next, num, lev); +} + +static void +free_type_lit(union forlan_node *p) +{ + free(p->lit.string); +} +void +dump_lit(FILE *fp, union forlan_node *p, int *num, int lev) +{ + fprintf(fp, "LIT: \"%s\"\n", p->lit.string); +} + +static void +free_type_expr(union forlan_node *p) +{ + forlan_node_free(p->expr.arg[0]); + forlan_node_free(p->expr.arg[1]); +} +void +dump_expr(FILE *fp, union forlan_node *p, int *num, int lev) +{ + static char *opstr[] = { "NODE", "AND", "OR", "NOT" }; + + fprintf(fp, "%s\n", opstr[p->expr.opcode]); + forlan_dump_node(fp, p->expr.arg[0], num, lev + 1); + if (p->expr.arg[1]) + forlan_dump_node(fp, p->expr.arg[1], num, lev + 1); +} + +static void +free_type_last(union forlan_node *p) +{ +} +void +dump_last(FILE *fp, union forlan_node *p, int *num, int lev) +{ + fprintf(fp, "LAST\n"); +} + +struct forlan_node_method { + void (*f_free)(union forlan_node *); + void (*f_dump)(FILE *fp, union forlan_node *node, int *num, int lev); +}; + +static struct forlan_node_method f_tab[] = { + free_type_null, dump_null, /* Unknown/unset type */ + free_type_comp, dump_comp, /* A path component */ + free_type_test, dump_test, /* Value test (f[X]) */ + free_type_func, dump_func, /* Function call */ + free_type_cond, dump_cond, /* Conditional */ + free_type_stmt, dump_stmt, /* Statement */ + free_type_lit, dump_lit, /* Literal */ + free_type_expr, dump_expr, /* Boolean expression */ + free_type_last, dump_last, /* "last" */ +}; + +void +forlan_node_free(union forlan_node *p) +{ + if (!p) + return; + if (p->type > sizeof(f_tab) / sizeof(f_tab[0])) + abort(); + if (f_tab[p->type].f_free) + f_tab[p->type].f_free(p); + free(p); +} + +static void +stmt_list_free_entry(void *p) +{ + forlan_node_free(p); +} + +struct grecs_list * +forlan_stmt_list() +{ + struct grecs_list *lp; + + lp = grecs_list_create(); + lp->free_entry = stmt_list_free_entry; + return lp; +} + +union forlan_node * +forlan_stmt_from_list(struct grecs_list *list) +{ + union forlan_node **tail = NULL, *ret = NULL; + struct grecs_list_entry *ep; + + for (ep = list->head; ep; ep = ep->next) { + union forlan_node *sp = forlan_node_create(forlan_type_stmt); + sp->stmt.stmt = ep->data; + if (tail) + *tail = sp; + else + ret = sp; + tail = &sp->stmt.next; + } + list->free_entry = NULL; + grecs_list_free(list); + return ret; +} + +static void +f_dump_node(FILE *fp, union forlan_node *p, int *num, int lev) +{ + if (p) { + if (p->type > sizeof(f_tab) / sizeof(f_tab[0])) + abort(); + if (f_tab[p->type].f_dump) + f_tab[p->type].f_dump(fp, p, num, lev); + else + fprintf(fp, "type %d", p->type); + } else + fprintf(fp, "NULL"); +} + +void +forlan_dump_node(FILE *fp, union forlan_node *p, int *num, int lev) +{ + if (!p) + return; + ++*num; + fprintf(fp, "%04d: %*.*s", *num, lev, lev, ""); + f_dump_node(fp, p, num, lev); +} + +void +forlan_dump_tree(FILE *fp, union forlan_node *node) +{ + int n = 0; + forlan_dump_node(fp, node, &n, 0); +} |