initial setup of thesis repository
[cluster_expansion_thesis.git] / little_helpers / tikz / sketch-0.2.161 / symbol.c
blobcf02c47e15fbb783ce738484bdfbb3f69976c061
1 /* symbol.c
2 Copyright (C) 2005,2006,2007,2008 Eugene K. Ressler, Jr.
4 This file is part of Sketch, a small, simple system for making
5 3d drawings with LaTeX and the PSTricks or TikZ package.
7 Sketch is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 Sketch is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Sketch; see the file COPYING.txt. If not, see
19 http://www.gnu.org/copyleft */
21 #include <stdio.h>
22 #include <string.h>
23 #include "error.h"
24 #include "geometry.h"
25 #include "symbol.h"
27 // dragon book hash function due to as&u.
28 unsigned
29 hash (char *s)
31 unsigned h = 0, g;
33 while (*s)
35 h = (h << 4) + *s++;
36 if ((g = h & 0xf0000000L) != 0)
38 h ^= (g >> 24);
39 h ^= g;
42 return h;
45 // chain a new scope onto an existing symbol table (or NULL)
46 // and return the new table
47 SYMBOL_TABLE *
48 new_scope (SYMBOL_TABLE * sym_tab)
50 int i;
51 SYMBOL_TABLE *new_sym_tab = safe_malloc (sizeof *new_sym_tab);
52 new_sym_tab->enclosing = sym_tab;
53 for (i = 0; i < ARRAY_SIZE (new_sym_tab->head); i++)
54 new_sym_tab->head[i] = NULL;
55 return new_sym_tab;
58 // unchain the inner scope from an existing symbol table
59 // and return the next outer scope or NULL if this was
60 // the outermost scope; as a side effect, warns of unused
61 // symbols
63 // we are not worrying about freeing storage; the def nodes
64 // are needed for object names anyway
65 SYMBOL_TABLE *
66 old_scope (SYMBOL_TABLE * sym_tab)
68 int i;
69 SYMBOL *sym, *sym_next;
70 SYMBOL_TABLE *sym_tab_enclosing;
72 // warn of unreferenced symbols
73 for (i = 0; i < ARRAY_SIZE (sym_tab->head); i++)
75 for (sym = sym_tab->head[i]; sym; sym = sym_next)
77 sym_next = sym->next;
78 if (sym->n_references == 0 && !sym->def_line.include_p)
80 if (sym->obj)
81 warn (sym->def_line, "%s '%s' is never referenced",
82 object_type_str[sym->obj->tag], sym->name);
83 else
84 warn (sym->def_line, "'%s' is never referenced", sym->name);
86 safe_free (sym);
89 sym_tab_enclosing = sym_tab->enclosing;
90 safe_free (sym_tab);
91 return sym_tab_enclosing;
94 static SYMBOL *
95 lookup_in_inner_scope (SYMBOL_TABLE * sym_tab, char *name, unsigned index)
97 SYMBOL *sym;
99 for (sym = sym_tab->head[index]; sym; sym = sym->next)
100 if (strncmp (name, sym->name, sizeof sym->name - 1) == 0)
101 return sym;
102 return NULL;
105 SYMBOL *
106 lookup (SYMBOL_TABLE * sym_tab, char *name)
108 SYMBOL *sym;
109 unsigned index;
111 index = hash (name) % ARRAY_SIZE (sym_tab->head);
114 sym = lookup_in_inner_scope (sym_tab, name, index);
115 if (sym)
117 sym->n_references++;
118 return sym;
120 sym_tab = sym_tab->enclosing;
122 while (sym_tab);
123 return NULL;
126 static OBJECT *
127 lookup_with_type_check (SYMBOL_TABLE * sym_tab,
128 OBJECT_TYPE tag, SRC_LINE line, char *name)
130 SYMBOL *sym = lookup (sym_tab, name);
131 if (sym)
133 if (sym->obj)
135 if (sym->obj->tag == tag)
136 return sym->obj;
137 else
138 err (line, "expected %s to be a %s and instead it's a %s",
139 name, object_type_str[tag], object_type_str[sym->obj->tag]);
141 else
143 err (line, "%s has a null definition", name);
146 else
148 err (line, "found undefined identifier %s while looking for %s",
149 name, object_type_str[tag]);
151 return NULL;
154 void
155 look_up_tag (SYMBOL_TABLE * sym_tab, int *exists_p, SRC_LINE line, char *name)
157 SYMBOL *sym;
159 if (name)
161 sym = lookup (sym_tab, name);
162 *exists_p = sym && sym->obj && sym->obj->tag == O_TAG_DEF;
164 else
166 *exists_p = 0;
171 tag_exists_p (SYMBOL_TABLE * sym_tab, char *name)
173 int exists_p;
174 look_up_tag (sym_tab, &exists_p, no_line, name);
175 if (!exists_p)
176 err (no_line, "undefined tag %s", name);
177 return exists_p;
180 void
181 look_up_opts (SYMBOL_TABLE * sym_tab, OPTS ** r, SRC_LINE line, char *name)
183 OPTS_DEF *def =
184 (OPTS_DEF *) lookup_with_type_check (sym_tab, O_OPTS_DEF, line,
185 name);
186 *r = def ? def->opts : NULL;
189 OPTS *
190 look_up_and_append_to_opts(SYMBOL_TABLE * sym_tab, OPTS ** r, SRC_LINE line, char *name)
192 OPTS *opts;
193 look_up_opts(sym_tab, &opts, line, name);
194 if (opts)
196 if (*r == NULL)
197 *r = raw_opts();
198 cat_opts(*r, opts);
200 return *r;
203 void
204 look_up_scalar (SYMBOL_TABLE * sym_tab, FLOAT * r, SRC_LINE line, char *name)
206 SCALAR_DEF *def =
207 (SCALAR_DEF *) lookup_with_type_check (sym_tab, O_SCALAR_DEF, line,
208 name);
209 *r = def ? def->val : 0;
212 void
213 look_up_point (SYMBOL_TABLE * sym_tab, POINT_3D r, SRC_LINE line, char *name)
215 POINT_DEF *def =
216 (POINT_DEF *) lookup_with_type_check (sym_tab, O_POINT_DEF, line,
217 name);
218 if (def)
219 copy_pt_3d (r, def->p);
220 else
221 r[X] = r[Y] = r[Z] = 0;
224 void
225 look_up_vector (SYMBOL_TABLE * sym_tab, VECTOR_3D r, SRC_LINE line,
226 char *name)
228 VECTOR_DEF *def =
229 (VECTOR_DEF *) lookup_with_type_check (sym_tab, O_VECTOR_DEF, line,
230 name);
231 if (def)
232 copy_vec_3d (r, def->v);
233 else
234 zero_vec_3d (r);
237 void
238 look_up_transform (SYMBOL_TABLE * sym_tab, TRANSFORM r, SRC_LINE line,
239 char *name)
241 TRANSFORM_DEF *def =
242 (TRANSFORM_DEF *) lookup_with_type_check (sym_tab, O_TRANSFORM_DEF,
243 line, name);
244 if (def)
245 copy_transform (r, def->xf);
246 else
247 set_ident (r);
250 void
251 look_up_drawable (SYMBOL_TABLE * sym_tab, OBJECT ** r, SRC_LINE line,
252 char *name)
254 SYMBOL *sym = lookup (sym_tab, name);
255 *r = NULL;
256 if (sym)
258 if (sym->obj)
260 if (is_drawable (sym->obj))
261 *r = copy_drawable (sym->obj); // copy needed so concat of lookup result is ok
262 else
264 err (line,
265 "expected %s to be a drawable object and instead it's a %s",
266 name, object_type_str[sym->obj->tag]);
269 else
271 err (line, "%s contains no drawable objects", name);
274 else
276 err (line,
277 "found undefined identifier %s while looking for a drawable object",
278 name);
282 OBJECT *
283 remove_from_inner_scope (SYMBOL_TABLE * sym_tab, char *name, unsigned index)
285 OBJECT *r;
286 SYMBOL *sym, *prev_sym;
288 for (prev_sym = NULL, sym = sym_tab->head[index]; sym;
289 prev_sym = sym, sym = sym->next)
290 if (strncmp (name, sym->name, sizeof sym->name - 1) == 0)
292 if (prev_sym)
293 prev_sym->next = sym->next;
294 else
295 sym_tab->head[index] = sym->next;
296 r = sym->obj;
297 safe_free (sym);
298 return r;
300 return NULL;
303 OBJECT *
304 remove_symbol (SYMBOL_TABLE * sym_tab, char *name, SRC_LINE line)
306 unsigned index;
307 OBJECT *obj;
309 index = hash (name) % ARRAY_SIZE (sym_tab->head);
312 obj = remove_from_inner_scope (sym_tab, name, index);
313 if (obj)
314 return obj;
315 sym_tab = sym_tab->enclosing;
317 while (sym_tab);
318 return NULL;
321 SYMBOL *
322 new_symbol (SYMBOL_TABLE * sym_tab, char *name, char *tag,
323 OBJECT * obj, SRC_LINE def_line)
325 int exists_p;
326 unsigned index;
327 SYMBOL *sym;
329 if (!name || !name[0])
330 return NULL;
332 index = hash (name) % ARRAY_SIZE (sym_tab->head);
334 // def has a tag that is undefined, so ignore it
335 if (tag)
337 look_up_tag (sym_tab, &exists_p, def_line, tag);
338 if (!exists_p)
339 return NULL;
342 sym = lookup_in_inner_scope (sym_tab, name, index);
344 // ok to redefine if tag is given and the existing definition
345 // is default and no uses have yet occurred
346 if (sym && !(tag && !sym->tag[0] && sym->n_references == 0))
348 // symbol already defined in the inner scope; this is an error
349 if (is_no_line_p (sym->def_line))
350 err (def_line, "name %s is already defined", name);
351 else
352 err (def_line, "name %s is already defined on line %d",
353 name, sym->def_line.number);
354 return NULL;
356 if (sym)
357 warn (def_line, "def of '%s' with tag '%s' after default", name, tag);
359 // create a new symbol and fill it in
360 sym = safe_malloc (sizeof *sym);
362 // copy up chars that fit then make sure the last is \0
363 strncpy (sym->name, name, sizeof sym->name);
364 sym->name[sizeof sym->name - 1] = '\0';
366 if (strlen (name) > sizeof sym->name - 1)
367 warn (def_line, "long identifier shortened to '%s'", sym->name);
369 if (tag)
371 strncpy (sym->tag, tag, sizeof sym->tag);
372 sym->tag[sizeof sym->tag - 1] = '\0';
374 else
375 sym->tag[0] = '\0';
377 // other fields
378 sym->def_line = def_line;
379 sym->n_references = 0;
380 sym->obj = obj;
382 // push onto hash table list
383 sym->next = sym_tab->head[index];
384 sym_tab->head[index] = sym;
386 return sym;