f6739e910901c4d28178212c6588ede1fff6521c
[egate.git] / fml / fmlsym.c
1 /*
2  * FML interpreter. Europagate, 1995
3  *
4  * $Log: fmlsym.c,v $
5  * Revision 1.4  1995/03/02 08:06:09  adam
6  * Fml function strsub implemented. New test files marc[45].fml.
7  * New test options in fmltest.
8  *
9  * Revision 1.3  1995/02/23  08:32:06  adam
10  * Changed header.
11  *
12  * Revision 1.1.1.1  1995/02/06  13:48:10  adam
13  * First version of the FML interpreter. It's slow and memory isn't
14  * freed properly. In particular, the FML nodes aren't released yet.
15  *
16  */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <assert.h>
20
21 #include "fmlp.h"
22
23 #define SYM_CHUNK 128
24
25 struct fml_sym {
26     struct fml_sym_info info;
27     struct fml_sym *next;
28     int level;
29     char *name;
30     struct fml_sym *level_link;
31 };
32
33 struct fml_sym_tab {
34     int level;
35     int hash;
36     struct fml_sym **array;
37     struct fml_sym *level_link_0;
38     struct fml_sym *level_link_n;
39     struct fml_sym *free_list;
40 };
41
42 static struct fml_sym *sym_alloc (struct fml_sym_tab *tab) 
43 {
44     struct fml_sym *p = tab->free_list;
45     if (!p)
46     {
47         int i;
48
49         tab->free_list = p = malloc (sizeof(*p) * SYM_CHUNK);
50         assert (p);
51         for (i = 0; i<SYM_CHUNK-1; i++)
52             p[i].next = p+i+1;
53         p[i].next = NULL;
54     }
55     tab->free_list = p->next;
56     return p;
57 }
58
59 static void sym_release (struct fml_sym_tab *tab, struct fml_sym *p)
60 {
61     p->next = tab->free_list;
62     tab->free_list = p;
63 }
64
65 struct fml_sym_tab *fml_sym_open (void)
66 {
67     struct fml_sym_tab *tab;
68     int i;
69
70     tab = malloc (sizeof (*tab));
71     if (!tab)
72         return NULL;
73     tab->level = 1;
74     tab->level_link_0 = NULL;
75     tab->level_link_n = NULL;
76     tab->free_list = NULL;
77     tab->hash = 41;
78     tab->array = malloc (sizeof(*tab->array) * tab->hash);
79     if (!tab->array)
80     {
81         free (tab);
82         return NULL;
83     }
84     for (i = 0; i<tab->hash; i++)
85         tab->array[i] = NULL;
86     return tab;
87 }
88
89 void fml_sym_close (struct fml_sym_tab **tabp)
90 {
91     struct fml_sym *sym, *sym1;
92     int i;
93     for (i = (*tabp)->hash; --i >= 0; )
94         for (sym = (*tabp)->array[i]; sym; sym = sym1)
95         {
96             sym1 = sym->next;
97             free (sym->name);
98             free (sym);
99         }
100     free (*tabp);
101     *tabp = NULL;
102 }
103
104 void fml_sym_push (struct fml_sym_tab *tab)
105 {
106     tab->level ++;
107 }
108
109 void fml_sym_pop (struct fml_sym_tab *tab, void (*ph)(struct fml_sym_info *i))
110 {
111     struct fml_sym **fsp;
112     int i;
113
114     assert (tab->level > 0);
115     for (i = tab->hash; --i >= 0; )
116     {
117         fsp = tab->array + i;
118         while (*fsp)
119         {
120             if ((*fsp)->level == tab->level)
121             {
122                 struct fml_sym *fs;
123
124                 fs = *fsp;
125                 if (ph)
126                     (*ph)(&fs->info);
127                 *fsp = (*fsp)->next;
128                 free (fs->name);
129                 sym_release (tab, fs);
130             }
131             else
132                 fsp = &(*fsp)->next;
133         }
134     }
135     tab->level--;
136 }
137
138 static unsigned fml_sym_hash (const char *s, unsigned hash)
139 {
140     unsigned long v = 0;
141     while (*s)
142         v = v*65599 + *s++;
143     return v % hash;
144 }
145
146
147 static struct fml_sym_info *sym_add (struct fml_sym_tab *tab,
148                                      const char *s, int level)
149 {
150     char *cp;
151     struct fml_sym *sym;
152     struct fml_sym **sym_entry;
153
154     cp = malloc (strlen(s)+1);
155     if (!cp)
156         return NULL;
157     strcpy (cp, s);
158
159     sym = sym_alloc (tab);
160
161     sym_entry = tab->array + fml_sym_hash (s, tab->hash);
162     sym->name = cp;
163     sym->next = *sym_entry;
164     *sym_entry = sym;
165     sym->level = level;
166     if (level)
167     {
168         sym->level_link = tab->level_link_n;
169         tab->level_link_n = sym;
170     }
171     else
172     {
173         sym->level_link = tab->level_link_0;
174         tab->level_link_0 = sym;
175     }
176     return &sym->info;
177 }
178
179 struct fml_sym_info *fml_sym_add (struct fml_sym_tab *tab, const char *s)
180 {
181     return sym_add (tab, s, 0);
182 }
183
184 struct fml_sym_info *fml_sym_add_local (struct fml_sym_tab *tab, const char *s)
185 {
186     return sym_add (tab, s, tab->level);
187 }
188
189 static struct fml_sym_info *sym_lookup (struct fml_sym_tab *tab,
190                                         const char *s, int level)
191 {
192     struct fml_sym *sym;
193     struct fml_sym *sym0 = NULL;
194     struct fml_sym **sym_entry;
195
196     sym_entry = tab->array + fml_sym_hash (s, tab->hash);
197     for (sym = *sym_entry; sym; sym = sym->next)
198         if (!strcmp (sym->name, s))
199             if (!sym0 || sym->level > sym0->level)
200                 sym0 = sym;
201     if (sym0)
202     {
203         assert (sym0->level <= tab->level);
204         if (level && sym0->level != level)
205             return NULL;
206         return &sym0->info;
207     }
208     else
209         return NULL;
210 }
211
212 struct fml_sym_info *fml_sym_lookup (struct fml_sym_tab *tab, const char *s)
213 {
214     return sym_lookup (tab, s, 0);
215 }
216
217 struct fml_sym_info *fml_sym_lookup_local (struct fml_sym_tab *tab,
218                                            const char *s)
219 {
220     return sym_lookup (tab, s, tab->level);
221 }
222