/* def.c def management and symbol tables Copyright (C) 2002 Bill Currie Copyright (C) 1996-1997 Id Software, Inc. Author: Bill Currie Date: 2002/06/09 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA */ #ifdef HAVE_CONFIG_H # include "config.h" #endif static __attribute__ ((used)) const char rcsid[] = "$Id$"; #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include #include #include #include #include "qfcc.h" #include "def.h" #include "defspace.h" #include "expr.h" #include "immediate.h" #include "options.h" #include "reloc.h" #include "strpool.h" #include "struct.h" #include "type.h" //FIXME //def_t def_void = { type_void, "def void" }; //def_t def_invalid = { type_invalid, "def invalid" }; //def_t def_function = { type_function, "def function" }; static def_t *free_temps[4]; // indexted by type size static int tempdef_counter; static def_t temp_scope; static def_t *free_defs; static scope_t *free_scopes; static hashtab_t *defs_by_name; static hashtab_t *field_defs; static const char * defs_get_key (void *_def, void *unused) { def_t *def = (def_t *) _def; return def->name; } static def_t * check_for_name (type_t *type, const char *name, scope_t *scope, storage_class_t storage) { def_t *def; if (!defs_by_name) { defs_by_name = Hash_NewTable (16381, defs_get_key, 0, 0); field_defs = Hash_NewTable (16381, defs_get_key, 0, 0); } if (!name) return 0; // see if the name is already in use def = (def_t *) Hash_Find (defs_by_name, name); if (def) { if (storage != st_none && scope == def->scope) if (type && def->type != type) { expr_t *e = new_expr (); e->line = def->line; e->file = def->file; error (0, "Type mismatch on redeclaration of %s", name); error (e, "previous declaration"); } if (storage == st_none || def->scope == scope) return def; } return 0; } scope_t * new_scope (scope_type type, defspace_t *space, scope_t *parent) { scope_t *scope; ALLOC (1024, scope_t, scopes, scope); scope->type = type; scope->space = space; scope->parent = parent; scope->tail = &scope->head; return scope; } void set_storage_bits (def_t *def, storage_class_t storage) { switch (storage) { case st_none: break; case st_system: def->system = 1; // fall through case st_global: def->global = 1; def->external = 0; def->local = 0; break; case st_extern: def->global = 1; def->external = 1; def->local = 0; break; case st_static: def->external = 0; def->global = 0; def->local = 0; break; case st_local: def->external = 0; def->global = 0; def->local = 1; break; } def->initialized = 0; } static const char *vector_component_names[] = {"%s_x", "%s_y", "%s_z"}; static void vector_component (int is_field, def_t *vec, int comp, scope_t *scope, storage_class_t storage) { def_t *d; const char *name; name = save_string (va (vector_component_names[comp], vec->name)); d = get_def (is_field ? &type_floatfield : &type_float, name, scope, st_none); if (d && d->scope == scope) { if (vec->external) { error (0, "internal error"); abort (); } } else { d = new_def (is_field ? &type_floatfield : &type_float, name, scope); } d->used = 1; d->parent = vec; d->ofs = vec->ofs + comp; set_storage_bits (d, storage); if (is_field && (storage == st_global || storage == st_static)) { G_INT (d->ofs) = G_INT (vec->ofs) + comp; reloc_def_field (d, d->ofs); } Hash_Add (defs_by_name, d); if (is_field) Hash_Add (field_defs, d); } def_t * field_def (const char *name) { return Hash_Find (field_defs, name); } /* get_def If type is NULL, it will match any type If allocate is true, a new def will be allocated if it can't be found */ def_t * get_def (type_t *type, const char *name, scope_t *scope, storage_class_t storage) { def_t *def = check_for_name (type, name, scope, storage); defspace_t *space = NULL; if (storage == st_none) return def; if (def) { if (storage != st_extern && !def->initialized) { def->file = pr.source_file; def->line = pr.source_line; } if (!def->external || storage == st_extern) return def; } else { // allocate a new def def = new_def (type, name, scope); if (name) Hash_Add (defs_by_name, def); } switch (storage) { case st_none: case st_global: case st_local: case st_system: space = scope->space; break; case st_extern: space = 0; break; case st_static: space = pr.near_data; break; } // new_def sets def->space to the scope's space, but that is generally // not valid for st_static or st_extern def->space = space; if (space) { if (type->type == ev_field && type->t.fldptr.type == &type_vector) def->ofs = defspace_new_loc (space, type_size (type->t.fldptr.type)); else def->ofs = defspace_new_loc (space, type_size (type)); } set_storage_bits (def, storage); if (name) { // make automatic defs for the vectors elements .origin can be accessed // as .origin_x, .origin_y, and .origin_z if (type->type == ev_vector) { vector_component (0, def, 0, scope, storage); vector_component (0, def, 1, scope, storage); vector_component (0, def, 2, scope, storage); } if (type->type == ev_field) { if (storage == st_global || storage == st_static) { G_INT (def->ofs) = defspace_new_loc (pr.entity_data, type_size (type->t.fldptr.type)); reloc_def_field (def, def->ofs); def->constant = 1; def->nosave = 1; } if (type->t.fldptr.type->type == ev_vector) { vector_component (1, def, 0, scope, storage); vector_component (1, def, 1, scope, storage); vector_component (1, def, 2, scope, storage); } Hash_Add (field_defs, def); } } return def; } def_t * new_def (type_t *type, const char *name, scope_t *scope) { def_t *def; ALLOC (16384, def_t, defs, def); if (scope) { *scope->tail = def; scope->tail = &def->def_next; scope->num_defs++; } def->return_addr = __builtin_return_address (0); def->name = name ? save_string (name) : 0; def->type = type; if (scope) { def->scope = scope; def->space = scope->space; } def->file = pr.source_file; def->line = pr.source_line; return def; } def_t * get_tempdef (type_t *type, scope_t *scope) { int size = type_size (type) - 1; def_t *def; if (free_temps[size]) { def = free_temps[size]; free_temps[size] = def->next; def->type = type; } else { def = new_def (type, va (".tmp%d", tempdef_counter++), scope); def->ofs = defspace_new_loc (scope->space, type_size (type)); } def->return_addr = __builtin_return_address (0); def->freed = def->removed = def->users = 0; def->next = temp_scope.next; set_storage_bits (def, st_local); temp_scope.next = def; return def; } void free_tempdefs (void) { def_t **def, *d; int size; def = &temp_scope.next; while (*def) { if ((*def)->users <= 0) { d = *def; *def = d->next; if (d->users < 0) { expr_t e; e.file = d->file; e.line = d->line; notice (&e, "temp def over-freed:%s offs:%d users:%d " "managed:%d %s", pr_type_name[d->type->type], d->ofs, d->users, d->managed, d->name); } size = type_size (d->type) - 1; if (d->expr) d->expr->e.temp.def = 0; if (!d->freed) { d->next = free_temps[size]; free_temps[size] = d; d->freed = 1; } } else { def = &(*def)->next; } } } void reset_tempdefs (void) { size_t i; def_t *d; tempdef_counter = 0; for (i = 0; i < sizeof (free_temps) / sizeof (free_temps[0]); i++) { free_temps[i] = 0; } for (d = temp_scope.next; d; d = d->next) { expr_t e; e.file = d->file; e.line = d->line; notice (&e, "temp def under-freed:%s ofs:%d users:%d managed:%d %s", pr_type_name[d->type->type], d->ofs, d->users, d->managed, d->name); } temp_scope.next = 0; } void flush_scope (scope_t *scope, int force_used) { def_t *def; for (def = scope->head; def; def = def->def_next) { if (def->name) { if (!force_used && !def->used) { expr_t e; e.line = def->line; e.file = def->file; if (options.warnings.unused) warning (&e, "unused variable `%s'", def->name); } if (!def->removed) { Hash_Del (defs_by_name, def->name); if (def->type->type == ev_field) { if (Hash_Find (field_defs, def->name) == def) Hash_Del (field_defs, def->name); } def->removed = 1; } } } } void def_initialized (def_t *d) { d->initialized = 1; if (d->type == &type_vector || (d->type->type == ev_field && d->type->t.fldptr.type == &type_vector)) { d = d->def_next; d->initialized = 1; d = d->def_next; d->initialized = 1; d = d->def_next; d->initialized = 1; } if (d->parent) { d = d->parent; if (d->type == &type_vector && d->def_next->initialized && d->def_next->def_next->initialized && d->def_next->def_next->def_next->initialized) d->initialized = 1; } } void clear_defs (void) { if (field_defs) Hash_FlushTable (field_defs); if (defs_by_name) Hash_FlushTable (defs_by_name); } void def_to_ddef (def_t *def, ddef_t *ddef, int aux) { type_t *type = def->type; if (aux) type = type->t.fldptr.type; // aux is true only for fields ddef->type = type->type; ddef->ofs = def->ofs; ddef->s_name = ReuseString (def->name); }