/* * param.c - Parameters and values * * Copyright 2012 by Werner Almesberger * * This program 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. */ #include #include #include "util.h" #include "lang.h" #include "param.h" static GTree *tree; static int duplicate(const char *a, const struct equiv *b) { while (b) { if (a == b->name) return 1; b = b->next; } return 0; } static void check_duplicates(const struct names *n) { const struct names *na, *nb; const struct equiv *ea; for (na = n; na; na = na->next) { for (ea = na->equiv; ea; ea = ea->next) { if (duplicate(ea->name, ea->next)) yyerrorf("duplicate name \"%s\"", ea->name); for (nb = na->next; nb; nb = nb->next) if (duplicate(ea->name, nb->equiv)) yyerrorf("duplicate name \"%s\"", ea->name); } } } static gint comp(gconstpointer a, gconstpointer b) { return a == b ? 0 : a < b ? -1 : 1; } void register_nameset(const char *name, const struct names *set) { if (!tree) tree = g_tree_new(comp); if (g_tree_lookup(tree, name)) yyerrorf("duplicate name set \"%s\"", name); check_duplicates(set); g_tree_insert(tree, (void *) name, (void *) set); } const struct names *find_nameset(const char *name) { return tree ? g_tree_lookup(tree, name) : NULL; } struct lookup_data { const struct names *first_name; const char *name; }; static gboolean rev_traverse(gpointer key, gpointer value, gpointer data) { struct lookup_data *d = data; if (d->first_name == value) { d->name = key; return TRUE; } return FALSE; } const char *nameset_rev_lookup(const struct names *first_name) { struct lookup_data data = { .first_name = first_name, .name = NULL, }; g_tree_foreach(tree, rev_traverse, (void *) &data); return data.name; } #define MKOPS(type) \ const struct param_ops param_ops_##type = { \ .eval = eval_##type, \ .comp = comp_##type, \ .dump = dump_##type, \ } MKOPS(name); MKOPS(set); MKOPS(abs); MKOPS(rel); /* ----- Parameters as general-purpose (string) variables ------------------ */ struct param *make_var(const char *name, enum relop op, const char *val) { struct param *var; var = alloc_type(struct param); var->u.name = unique(name); var->op = op; var->value.u.s = unique(val); var->next = NULL; return var; } const char *var_lookup(const struct param *vars, const char *name) { while (vars) { if (vars->u.name == name) return vars->value.u.s; vars = vars->next; } return NULL; } /* * The variables in list "a" have lower priority than those in list "b", * i.e., a variable in "a" is only picked if there is no variable with the * same name in "b". */ struct param *merge_vars(const struct param *a, const struct param *b) { const struct param *v; struct param *res, **last = &res; while (a) { for (v = b; v; v = v->next) if (a->u.name == v->u.name) break; if (!v) { *last = alloc_type(struct param); **last = *a; last = &(*last)->next; } a = a->next; } for (v = b; v; v = v->next) { *last = alloc_type(struct param); **last = *v; last = &(*last)->next; } *last = NULL; return res; } void free_vars(struct param *vars) { struct param *next; while (vars) { next = vars->next; free(vars); vars = next; } }