/* Copyright (C) 1996-1997 Id Software, Inc. 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 the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See file, 'COPYING', for details. */ static const char rcsid[] = "$Id$"; #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include #include #include #include #include "qfcc.h" #include "def.h" #include "expr.h" #include "struct.h" #include "type.h" typedef struct locref_s { struct locref_s *next; int ofs; int size; } locref_t; def_t def_void = { &type_void, "temp" }; def_t def_function = { &type_function, "temp" }; def_t def_ret, def_parms[MAX_PARMS]; static def_t *free_temps[4]; // indexted by type size static def_t temp_scope; static def_t *free_defs; static defspace_t *free_spaces; static scope_t *free_scopes; static locref_t *free_free_locs; static hashtab_t *defs_by_name; static const char * defs_get_key (void *_def, void *_tab) { def_t *def = (def_t *) _def; hashtab_t **tab = (hashtab_t **) _tab; if (tab == &defs_by_name) { return def->name; } return ""; } static def_t * check_for_name (type_t *type, const char *name, scope_t *scope, int allocate) { def_t *def; if (!defs_by_name) { defs_by_name = Hash_NewTable (16381, defs_get_key, 0, &defs_by_name); } if (!name) return 0; if (scope->type == sc_global && (find_struct (name) || get_enum (name))) { error (0, "%s redeclared", name); return 0; } // see if the name is already in use def = (def_t *) Hash_Find (defs_by_name, name); if (def) { if (allocate && scope == def->scope) if (type && def->type != type) error (0, "Type mismatch on redeclaration of %s", name); if (!allocate || def->scope == scope) return def; } return 0; } static int grow_space (defspace_t *space) { space->max_size += 1024; return 1; } defspace_t * new_defspace (void) { defspace_t *space; ALLOC (1024, defspace_t, spaces, space); space->grow = grow_space; return space; } 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; } static const char *vector_component_names[] = {"%s_x", "%s_y", "%s_z"}; static void vector_component (def_t *vec, int comp, scope_t *scope) { def_t *d; d = new_def (&type_float, va (vector_component_names[comp], vec->name), scope); d->used = 1; d->parent = vec; d->ofs = vec->ofs + comp; Hash_Add (defs_by_name, d); } static void vector_field_component (def_t *vec, int comp, scope_t *scope) { def_t *d; d = new_def (&type_floatfield, va (vector_component_names[comp], vec->name), scope); d->used = 1; // always `used' d->parent = vec; d->ofs = vec->ofs + comp; G_INT (d->ofs) = G_INT (vec->ofs) + comp; Hash_Add (defs_by_name, d); } /* 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, int allocate) { def_t *def = check_for_name (type, name, scope, allocate); if (def || !allocate) return def; // allocate a new def def = new_def (type, name, scope); if (name) Hash_Add (defs_by_name, def); if (type->type == ev_field && type->aux_type == &type_vector) def->ofs = new_location (type->aux_type, scope->space); else def->ofs = new_location (type, scope->space); /* make automatic defs for the vectors elements .origin can be accessed as .origin_x, .origin_y, and .origin_z */ if (type->type == ev_vector && name) { vector_component (def, 0, scope); vector_component (def, 1, scope); vector_component (def, 2, scope); } if (type->type == ev_field) { G_INT (def->ofs) = new_location (type->aux_type, pr.entity_data); if (type->aux_type->type == ev_vector) { vector_field_component (def, 0, scope); vector_field_component (def, 1, scope); vector_field_component (def, 2, scope); } } return def; } def_t * new_def (type_t *type, const char *name, scope_t *scope) { def_t *def; ALLOC (16384, def_t, defs, def); *scope->tail = def; scope->tail = &def->def_next; scope->num_defs++; def->return_addr = __builtin_return_address (0); def->name = name ? strdup (name) : 0; def->type = type; def->scope = scope; def->space = scope->space; def->global = scope->type == sc_global; def->file = s_file; def->line = pr_source_line; return def; } int new_location (type_t *type, defspace_t *space) { int size = type_size (type); int ofs; locref_t *loc; locref_t **l = &space->free_locs; while (*l && (*l)->size < size) l = &(*l)->next; if ((loc = *l)) { ofs = loc->ofs; if (loc->size == size) { *l = loc->next; } else { loc->ofs += size; loc->size -= size; } return ofs; } ofs = space->size; space->size += size; if (space->size > space->max_size) space->grow (space); return ofs; } void free_location (def_t *def) { int size = type_size (def->type); locref_t *loc; for (loc = def->space->free_locs; loc; loc = loc->next) { if (def->ofs + size == loc->ofs) { loc->size += size; loc->ofs = def->ofs; return; } else if (loc->ofs + loc->size == def->ofs) { loc->size += size; if (loc->next && loc->next->ofs == loc->ofs + loc->size) { loc->size += loc->next->size; loc->next = loc->next->next; } return; } } ALLOC (1024, locref_t, free_locs, loc); loc->ofs = def->ofs; loc->size = size; loc->next = def->space->free_locs; def->space->free_locs = loc; } def_t * get_tempdef (type_t *type, scope_t *scope) { int size = type_size (type); def_t *def; if (free_temps[size]) { def = free_temps[size]; free_temps[size] = def->next; def->type = type; } else { def = new_def (type, 0, scope); def->ofs = new_location (type, scope->space); } def->freed = def->removed = def->users = 0; def->next = temp_scope.next; 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) printf ("%s:%d: warning: %s %3d %3d %d\n", pr.strings + d->file, d->line, pr_type_name[d->type->type], d->ofs, d->users, d->managed); size = type_size (d->type); 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) { int i; def_t *d; 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) printf ("%s:%d: warning: %s %3d %3d %d\n", pr.strings + d->file, d->line, pr_type_name[d->type->type], d->ofs, d->users, d->managed); 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; warning (&e, "unused variable `%s'", def->name); } if (!def->removed) { Hash_Del (defs_by_name, 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->aux_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; } }