Minor changes.
[egate.git] / fml / fmlsym.c
1 /*
2  * Copyright (c) 1995, the EUROPAGATE consortium (see below).
3  *
4  * The EUROPAGATE consortium members are:
5  *
6  *    University College Dublin
7  *    Danmarks Teknologiske Videnscenter
8  *    An Chomhairle Leabharlanna
9  *    Consejo Superior de Investigaciones Cientificas
10  *
11  * Permission to use, copy, modify, distribute, and sell this software and
12  * its documentation, in whole or in part, for any purpose, is hereby granted,
13  * provided that:
14  *
15  * 1. This copyright and permission notice appear in all copies of the
16  * software and its documentation. Notices of copyright or attribution
17  * which appear at the beginning of any file must remain unchanged.
18  *
19  * 2. The names of EUROPAGATE or the project partners may not be used to
20  * endorse or promote products derived from this software without specific
21  * prior written permission.
22  *
23  * 3. Users of this software (implementors and gateway operators) agree to
24  * inform the EUROPAGATE consortium of their use of the software. This
25  * information will be used to evaluate the EUROPAGATE project and the
26  * software, and to plan further developments. The consortium may use
27  * the information in later publications.
28  * 
29  * 4. Users of this software agree to make their best efforts, when
30  * documenting their use of the software, to acknowledge the EUROPAGATE
31  * consortium, and the role played by the software in their work.
32  *
33  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
34  * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
35  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
36  * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
37  * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
38  * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
39  * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
40  * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
41  * USE OR PERFORMANCE OF THIS SOFTWARE.
42  *
43  */
44 /*
45  * FML interpreter. Europagate, 1995
46  *
47  * $Log: fmlsym.c,v $
48  * Revision 1.5  1995/05/16 09:39:34  adam
49  * LICENSE.
50  *
51  * Revision 1.4  1995/03/02  08:06:09  adam
52  * Fml function strsub implemented. New test files marc[45].fml.
53  * New test options in fmltest.
54  *
55  * Revision 1.3  1995/02/23  08:32:06  adam
56  * Changed header.
57  *
58  * Revision 1.1.1.1  1995/02/06  13:48:10  adam
59  * First version of the FML interpreter. It's slow and memory isn't
60  * freed properly. In particular, the FML nodes aren't released yet.
61  *
62  */
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <assert.h>
66
67 #include "fmlp.h"
68
69 #define SYM_CHUNK 128
70
71 struct fml_sym {
72     struct fml_sym_info info;
73     struct fml_sym *next;
74     int level;
75     char *name;
76     struct fml_sym *level_link;
77 };
78
79 struct fml_sym_tab {
80     int level;
81     int hash;
82     struct fml_sym **array;
83     struct fml_sym *level_link_0;
84     struct fml_sym *level_link_n;
85     struct fml_sym *free_list;
86 };
87
88 static struct fml_sym *sym_alloc (struct fml_sym_tab *tab) 
89 {
90     struct fml_sym *p = tab->free_list;
91     if (!p)
92     {
93         int i;
94
95         tab->free_list = p = malloc (sizeof(*p) * SYM_CHUNK);
96         assert (p);
97         for (i = 0; i<SYM_CHUNK-1; i++)
98             p[i].next = p+i+1;
99         p[i].next = NULL;
100     }
101     tab->free_list = p->next;
102     return p;
103 }
104
105 static void sym_release (struct fml_sym_tab *tab, struct fml_sym *p)
106 {
107     p->next = tab->free_list;
108     tab->free_list = p;
109 }
110
111 struct fml_sym_tab *fml_sym_open (void)
112 {
113     struct fml_sym_tab *tab;
114     int i;
115
116     tab = malloc (sizeof (*tab));
117     if (!tab)
118         return NULL;
119     tab->level = 1;
120     tab->level_link_0 = NULL;
121     tab->level_link_n = NULL;
122     tab->free_list = NULL;
123     tab->hash = 41;
124     tab->array = malloc (sizeof(*tab->array) * tab->hash);
125     if (!tab->array)
126     {
127         free (tab);
128         return NULL;
129     }
130     for (i = 0; i<tab->hash; i++)
131         tab->array[i] = NULL;
132     return tab;
133 }
134
135 void fml_sym_close (struct fml_sym_tab **tabp)
136 {
137     struct fml_sym *sym, *sym1;
138     int i;
139     for (i = (*tabp)->hash; --i >= 0; )
140         for (sym = (*tabp)->array[i]; sym; sym = sym1)
141         {
142             sym1 = sym->next;
143             free (sym->name);
144             free (sym);
145         }
146     free (*tabp);
147     *tabp = NULL;
148 }
149
150 void fml_sym_push (struct fml_sym_tab *tab)
151 {
152     tab->level ++;
153 }
154
155 void fml_sym_pop (struct fml_sym_tab *tab, void (*ph)(struct fml_sym_info *i))
156 {
157     struct fml_sym **fsp;
158     int i;
159
160     assert (tab->level > 0);
161     for (i = tab->hash; --i >= 0; )
162     {
163         fsp = tab->array + i;
164         while (*fsp)
165         {
166             if ((*fsp)->level == tab->level)
167             {
168                 struct fml_sym *fs;
169
170                 fs = *fsp;
171                 if (ph)
172                     (*ph)(&fs->info);
173                 *fsp = (*fsp)->next;
174                 free (fs->name);
175                 sym_release (tab, fs);
176             }
177             else
178                 fsp = &(*fsp)->next;
179         }
180     }
181     tab->level--;
182 }
183
184 static unsigned fml_sym_hash (const char *s, unsigned hash)
185 {
186     unsigned long v = 0;
187     while (*s)
188         v = v*65599 + *s++;
189     return v % hash;
190 }
191
192
193 static struct fml_sym_info *sym_add (struct fml_sym_tab *tab,
194                                      const char *s, int level)
195 {
196     char *cp;
197     struct fml_sym *sym;
198     struct fml_sym **sym_entry;
199
200     cp = malloc (strlen(s)+1);
201     if (!cp)
202         return NULL;
203     strcpy (cp, s);
204
205     sym = sym_alloc (tab);
206
207     sym_entry = tab->array + fml_sym_hash (s, tab->hash);
208     sym->name = cp;
209     sym->next = *sym_entry;
210     *sym_entry = sym;
211     sym->level = level;
212     if (level)
213     {
214         sym->level_link = tab->level_link_n;
215         tab->level_link_n = sym;
216     }
217     else
218     {
219         sym->level_link = tab->level_link_0;
220         tab->level_link_0 = sym;
221     }
222     return &sym->info;
223 }
224
225 struct fml_sym_info *fml_sym_add (struct fml_sym_tab *tab, const char *s)
226 {
227     return sym_add (tab, s, 0);
228 }
229
230 struct fml_sym_info *fml_sym_add_local (struct fml_sym_tab *tab, const char *s)
231 {
232     return sym_add (tab, s, tab->level);
233 }
234
235 static struct fml_sym_info *sym_lookup (struct fml_sym_tab *tab,
236                                         const char *s, int level)
237 {
238     struct fml_sym *sym;
239     struct fml_sym *sym0 = NULL;
240     struct fml_sym **sym_entry;
241
242     sym_entry = tab->array + fml_sym_hash (s, tab->hash);
243     for (sym = *sym_entry; sym; sym = sym->next)
244         if (!strcmp (sym->name, s))
245             if (!sym0 || sym->level > sym0->level)
246                 sym0 = sym;
247     if (sym0)
248     {
249         assert (sym0->level <= tab->level);
250         if (level && sym0->level != level)
251             return NULL;
252         return &sym0->info;
253     }
254     else
255         return NULL;
256 }
257
258 struct fml_sym_info *fml_sym_lookup (struct fml_sym_tab *tab, const char *s)
259 {
260     return sym_lookup (tab, s, 0);
261 }
262
263 struct fml_sym_info *fml_sym_lookup_local (struct fml_sym_tab *tab,
264                                            const char *s)
265 {
266     return sym_lookup (tab, s, tab->level);
267 }
268