2012-03-18 18:24:12 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2012-05-22 01:46:42 +03:00
|
|
|
#include <stdlib.h>
|
2012-03-18 18:24:12 +02:00
|
|
|
#include <glib.h>
|
|
|
|
|
2012-05-22 01:46:42 +03:00
|
|
|
#include "util.h"
|
2012-04-29 04:12:33 +03:00
|
|
|
#include "lang.h"
|
2012-03-18 18:24:12 +02:00
|
|
|
#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) {
|
2012-04-25 23:14:39 +03:00
|
|
|
for (ea = na->equiv; ea; ea = ea->next) {
|
2012-03-18 18:24:12 +02:00
|
|
|
if (duplicate(ea->name, ea->next))
|
|
|
|
yyerrorf("duplicate name \"%s\"", ea->name);
|
2012-04-25 23:14:39 +03:00
|
|
|
for (nb = na->next; nb; nb = nb->next)
|
|
|
|
if (duplicate(ea->name, nb->equiv))
|
|
|
|
yyerrorf("duplicate name \"%s\"",
|
|
|
|
ea->name);
|
|
|
|
}
|
2012-03-18 18:24:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-25 23:14:39 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-18 18:24:12 +02:00
|
|
|
#define MKOPS(type) \
|
|
|
|
const struct param_ops param_ops_##type = { \
|
|
|
|
.eval = eval_##type, \
|
|
|
|
.comp = comp_##type, \
|
2012-04-25 23:14:39 +03:00
|
|
|
.dump = dump_##type, \
|
2012-03-18 18:24:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MKOPS(name);
|
|
|
|
MKOPS(set);
|
|
|
|
MKOPS(abs);
|
|
|
|
MKOPS(rel);
|
2012-05-22 01:46:42 +03:00
|
|
|
|
|
|
|
|
|
|
|
/* ----- 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 06:05:21 +03:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-22 01:46:42 +03:00
|
|
|
void free_vars(struct param *vars)
|
|
|
|
{
|
|
|
|
struct param *next;
|
|
|
|
|
|
|
|
while (vars) {
|
|
|
|
next = vars->next;
|
|
|
|
free(vars);
|
|
|
|
vars = next;
|
|
|
|
}
|
|
|
|
}
|