/******************************************************************************* * * McStas, neutron ray-tracing package * Copyright 1997-2002, All rights reserved * Risoe National Laboratory, Roskilde, Denmark * Institut Laue Langevin, Grenoble, France * * Kernel: symtab.c * * %Identification * Written by: K.N. * Date: Jul 1, 1997 * Origin: Risoe * Release: McStas 1.6 * Version: 1.4 * * Symbol tables. * * $Id: symtab.c,v 1.16 2003/10/06 15:00:12 farhi Exp $ * * $Log: symtab.c,v $ * Revision 1.16 2003/10/06 15:00:12 farhi * Added symtab_previous function for PREVIOUS keyword * * Revision 1.15 2003/02/11 12:28:45 farhi * Variouxs bug fixes after tests in the lib directory * mcstas_r : disable output with --no-out.. flag. Fix 1D McStas output * read_table:corrected MC_SYS_DIR -> MCSTAS define * monitor_nd-lib: fix Log(signal) log(coord) * HOPG.trm: reduce 4000 points -> 400 which is enough and faster to resample * Progress_bar: precent -> percent parameter * CS: ---------------------------------------------------------------------- * * Revision 1.4 1999/04/16 07:41:31 kn * Make the value_free argument for the symtab_free function optional. * * Revision 1.3 1998/10/02 08:39:25 kn * Fixed header comment. * * Revision 1.2 1997/09/07 17:58:45 kn * Snapshot with (untested) code generation complete. * * Revision 1.1 1997/08/13 09:16:14 kn * Initial revision * *******************************************************************************/ #include #include "mcstas.h" /******************************************************************************* * A symbol table is an abstract data type that maps any name to a * corresponding symbol table entry (which can be anything). * * In this first version, we use a simple, but inefficient approach. Symbol * tables are implemented as fixed-size arrays of string and void pointer * pairs. Table lookups are performed with a linear search. But the interface * is designed to make a transition to a more efficient implementation easily * possible if and when it becomes necessary. *******************************************************************************/ struct Symbol_table { int size; /* Number of entries currently in table. */ int maxsize; /* Total size of table. */ struct Symtab_entry *entries; /* Array of pairs of names and values. */ }; #define MAXSIZE 1000 /* Max. table size. */ /* Position in a symbol table for doing traversals. */ struct Symtab_position { struct Symbol_table *symtab; /* The symbol table we are traversing. */ int index; /* Next entry to return. */ }; /******************************************************************************* * Allocate and initialize a new symbol table. *******************************************************************************/ Symtab symtab_create(void) { Symtab st; palloc(st); /* Allocate new symbol table. */ st->maxsize = MAXSIZE; nalloc(st->entries, st->maxsize); /* Allocate array for entries. */ st->size = 0; /* Empty table. */ return st; } /******************************************************************************* * Look up a name in a symbol table. Returns a void pointer to the table * entry, or NULL if not found. *******************************************************************************/ struct Symtab_entry * symtab_lookup(Symtab st, char *name) { int i; for(i = 0; i < st->size; i++) { if(!strcmp(name, st->entries[i].name)) /* Found? */ { return &(st->entries[i]); } } /* Not found. */ return NULL; } /******************************************************************************* * Add a new name to an existing symbol table along with a table entry. The * table entry is a void pointer which could eg. point to a structure * containing information relevant to the name. * * The table entry must point to memory that remains valid for the duration of * the symbol table. The name, however, may be re-used freely as a new copy is * allocated in the symbol table. *******************************************************************************/ struct Symtab_entry * symtab_add(Symtab st, char *name, void *value) { int i; /* First see if an entry for this name already exists (it shouldn't, but ...) */ for(i = 0; i < st->size; i++) { if(!strcmp(name, st->entries[i].name)) { /* Hmm ... adding an already present name. */ debugn((DEBUG_MEDIUM, "add_to_symtab: name already exists: %s.\n", name)); return &(st->entries[i]); } } /* Make sure the table is large enough. */ if(st->size >= st->maxsize) { /* No room in table. This causes the program to abort. */ fatal_error("symtab_add: symbol table too small."); } /* Add the name at the end of the table. */ i = st->size; st->size++; st->entries[i].name = str_dup(name); st->entries[i].val = value; return value; } /******************************************************************************* * Free up memory allocated to a symbol table. The caller can supply a * function value_free that will free the memory for each table entry. * Pass NULL for value_free if no freeing is necessary. *******************************************************************************/ void symtab_free(Symtab st, void (*value_free)(void *)) { int i; for(i = 0; i < st->size; i++) { str_free(st->entries[i].name); if(value_free) (*value_free)(st->entries[i].val); } memfree(st->entries); memfree(st); } /******************************************************************************* * Prepare to start traversing a symbol table. Note that an improved * implementation is free to change the order in which a traversal returns the * elements (for example if using a hash table). *******************************************************************************/ Symtab_handle symtab_iterate(Symtab s) { Symtab_handle sh; palloc(sh); sh->symtab = s; sh->index = 0; return sh; } /******************************************************************************* * Get the next element during a traversal of a symbol table. Returns NULL * when no more elements exist. *******************************************************************************/ struct Symtab_entry * symtab_next(Symtab_handle sh) { int i = sh->index; /* Check if there are any more entries. */ if(i >= sh->symtab->size) { return NULL; } else { sh->index++; return &(sh->symtab->entries[i]); } } /******************************************************************************* * Get the index-th previous element stored in the symbol table. Returns NULL * when error occurs. *******************************************************************************/ struct Symtab_entry * symtab_previous(Symtab st, int index) { if (index <= 0 || index > st->size) { return NULL; } else { return &(st->entries[st->size - index]); } } /******************************************************************************* * End a symbol table traversal, freeing the memory allocated to the handle. *******************************************************************************/ void symtab_iterate_end(Symtab_handle sh) { memfree(sh); }