File: promote.c

package info (click to toggle)
saml 970418-3
  • links: PTS
  • area: main
  • in suites: slink
  • size: 1,204 kB
  • ctags: 1,701
  • sloc: ansic: 17,182; sh: 2,583; yacc: 497; perl: 264; makefile: 250; python: 242
file content (124 lines) | stat: -rw-r--r-- 2,703 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
 * Copyright 1996 Thierry Bousch
 * Licensed under the Gnu Public License, Version 2
 *
 * $Id: promote.c,v 2.4 1996/09/14 09:41:55 bousch Exp $
 *
 * Conversions (called promotions) between math-types.
 */

#include <stdio.h>
#include <stdlib.h>
#include "saml.h"
#include "saml-errno.h"
#include "saml-util.h"
#include "mnode.h"

#define HASHSIZE	59
#define HASH(t1,t2)	((unsigned)(t1^t2) % HASHSIZE)

typedef s_mnode* (*CV_routine)(s_mnode*, s_mnode*);

struct pr_data {
	struct pr_data *next;
	int t1, t2;
	CV_routine cvr;
};

static struct pr_data *htable[HASHSIZE];

static CV_routine get_CV_routine (int t1, int t2)
{
	int h = HASH(t1,t2);
	struct pr_data *p;

	for (p = htable[h]; p; p = p->next)
		if (p->t1 == t1 && p->t2 == t2)
			return p->cvr;
	return NULL;
}

void register_CV_routine (int t1, int t2, void* fn)
{
	int h;
	struct pr_data *p;
	char msg[100];

	if (t1 != -1 && !MTYPE_OK(t1)) {
		sprintf(msg, "math type %d out of bounds", t1);
		saml_panic(msg);
	}
	if (!MTYPE_OK(t2)) {
		sprintf(msg, "math type %d out of bounds", t2);
		saml_panic(msg);
	}
	if (get_CV_routine(t1,t2)) {
		sprintf(msg, "conversion function %d->%d already registered",
		  t1, t2);
		saml_panic(msg);
	}
#ifdef DEBUG_MTYPES
	if (getenv("DEBUG_MTYPES"))
		fprintf(stderr, "  Conversion %d->%d\n", t1, t2);
#endif
	p = malloc(sizeof(struct pr_data));
	if (p == NULL)
		panic_out_of_memory();
	h = HASH(t1,t2);
	p->next = htable[h];
	htable[h] = p;
	p->t1 = t1;
	p->t2 = t2;
	p->cvr = fn;
}
	
static s_mnode* promote3 (s_mnode* start, int t2, s_mnode* model)
{
	int t1 = start->type;
	CV_routine fn;
	s_mnode *u, *v;

	/*
	 * First attempt: is there a function to convert from t1 to t2 ?
	 * if yes, just call it.
	 */
	if ((fn = get_CV_routine(t1,t2)) != NULL)
		return (*fn)(start, model);
	/*
	 * If t1=t2, when we assume that no conversion is necessary,
	 * otherwise a conversion routine would have been available.
	 * For the same reason, don't touch "Void" objects.
	 */
	if (t1 == t2 || t1 == ST_VOID)
		return copy_mnode(start);
	/*
	 * Perhaps a generic conversion routine to type t2 ?
	 */
	if ((fn = get_CV_routine(-1,t2)) != NULL) {
		u = (*fn)(start, model);
		if (u->type == t2) return u;
		unlink_mnode(u);
	}
	/*
	 * Last attempt: call mnode_make() to get an object of type t2,
	 * and then promote it to the model, which has the same type.
	 */
	u = mnode_make(t2, start);
	if (u->type == t2)
		v = promote3(u, t2, model);
	else
		v = mnode_error(SE_ICAST, "promote");

	unlink_mnode(u);
	return v;
}

s_mnode* mnode_promote (s_mnode* from, s_mnode* to)
{
	return promote3(from, to->type, to);
}

s_mnode* mnode_cast (s_mnode* from, int typeid)
{
	return promote3(from, typeid, NULL);
}