/* assym.c */ /* * Copyright (C) 1989-2009 Alan R. Baldwin * * 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 3 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, see . * * * Alan R. Baldwin * 721 Berkeley St. * Kent, Ohio 44240 * * With enhancements from * * John L. Hartman (JLH) * jhartman at compuserve dot com */ /* * 10-Nov-07 borutr: * - use strsto instead StoreString and include it in assym.c * for compatibility with the original asxxxx * - applied changes from 28-Oct-97 JLH: * - lookup: Use StoreString for sym construction * - change symeq() to do length-independent string compare * - change hash() to do length-independent hash calculation * - applied changes from 29-Oct-97 JLH: * - make mnemonics case insensitive ALWAYS * - make hash() case-insensitive always * - replace symeq() call in mlookup with strcmpi */ #include "asxxxx.h" /*)Module assym.c * * The module assym.c contains the functions that operate * on the mnemonic/directive and symbol structures. * * assym.c contains the following functions: * VOID allglob() * area * alookup() * int hash() * sym * lookup() * mne * mlookup() * char * new() * char * strsto() * int symeq() * VOID syminit() * VOID symglob() * * assym.c contains the static variables: * char * pnext * int bytes * used by the string store function. */ /*)Function VOID syminit() * * The function syminit() is called early in the game * to set up the hashtables. First all buckets in a * table are cleared. Then a pass is made through * the respective symbol lists, linking them into * their hash buckets. Finally the base area pointer * is set to 'dca'. * * local variables: * int h computed hash value * mne * mp pointer to a mne structure * mne ** mpp pointer to an array of * mne structure pointers * sym * sp pointer to a sym structure * sym ** spp pointer to an array of * sym structure pointers * * global variables: * area area[] single elememt area array * area dca defined as area[0] * mne * mnehash[] array of pointers to NHASH * linked mnemonic/directive lists * sym * symhash[] array of pointers to NHASH * linked symbol lists * * functions called: * none * * side effects: * (1) The symbol hash tables are initialized, * the predefined symbols are '.' and '.__.ABS.'. * (2) The mnemonic/directive hash tables are * initialized with the assembler directives * and mnemonics found in the machine dependent * file ___pst.c. * (3) The area pointer is initialized to dca (area[0]). */ VOID syminit(void) { struct mne *mp; struct mne **mpp; struct sym *sp; struct sym **spp; int h; mpp = &mnehash[0]; while (mpp < &mnehash[NHASH]) *mpp++ = NULL; mp = &mne[0]; for (;;) { h = hash(mp->m_id, 1); mp->m_mp = mnehash[h]; mnehash[h] = mp; if (mp->m_flag&S_EOL) break; ++mp; } spp = &symhash[0]; while (spp < &symhash[NHASH]) *spp++ = NULL; sp = &sym[0]; for (;;) { h = hash(sp->s_id, zflag); sp->s_sp = symhash[h]; symhash[h] = sp; if (sp->s_flag&S_EOL) break; ++sp; } areap = &dca; } /*)Function area * alookup(id) * * char * id area name string * * The function alookup() searches the area list for a * match with id. If the area is defined then a pointer * to this area is returned else a NULL is returned. * * local variables: * area * ap pointer to area structure * * global variables: * area * areap pointer to an area structure * * functions called: * int symeq() assym.c * * side effects: * none */ struct area * alookup(char *id) { struct area *ap; ap = areap; while (ap) { /* * JLH: case insensitive lookup always */ if(symeq(id, ap->a_id, 0)) return (ap); ap = ap->a_ap; } return(NULL); } /*)Function mne * mlookup(id) * * char * id mnemonic/directive name string * * The function mlookup() searches the mnemonic/directive * hash tables for a match returning a pointer to the * mne structure else it returns a NULL. * * local variables: * mne * mp pointer to mne structure * int h calculated hash value * * global variables: * mne * mnehash[] array of pointers to NHASH * linked mnemonic/directive lists * * functions called: * none * * side effects: * none */ struct mne * mlookup(char *id) { struct mne *mp; int h; /* * JLH: case insensitive lookup always */ h = hash(id, 1); mp = mnehash[h]; while (mp) { if(symeq(id, mp->m_id, 1)) return (mp); mp = mp->m_mp; } return (NULL); } /*)Function sym * lookup(id) * * char * id symbol name string * * The function lookup() searches the symbol hash tables for * a symbol name match returning a pointer to the sym structure. * If the symbol is not found then a sym structure is created, * initialized, and linked to the appropriate hash table. * A pointer to this new sym structure is returned. * * local variables: * int h computed hash value * sym * sp pointer to a sym structure * * global varaibles: * sym * symhash[] array of pointers to NHASH * linked symbol lists * int zflag disable symbol case sensitivity * * functions called: * int hash() assym.c * char * new() assym.c * char * strsto() assym.c * int symeq() assym.c * * side effects: * If the function new() fails to allocate space * for the new sym structure the assembly terminates. */ struct sym * lookup(const char *id) { struct sym *sp; int h; h = hash(id, zflag); sp = symhash[h]; while (sp) { if(symeq(id, sp->s_id, zflag)) return (sp); sp = sp->s_sp; } sp = (struct sym *) new (sizeof(struct sym)); sp->s_sp = symhash[h]; symhash[h] = sp; sp->s_tsym = NULL; sp->s_id = strsto(id); sp->s_type = S_NEW; sp->s_flag = 0; sp->s_area = NULL; sp->s_ref = 0; sp->s_addr = 0; return (sp); } /*)Function VOID symglob() * * The function symglob() will mark all symbols of * type S_NEW as global. Called at * the beginning of pass 1 if the assembly * option -g was specified. * * local variables: * sym * sp pointer to a sym structure * int i loop index * * global variables: * sym * symhash[] array of pointers to NHASH * linked symbol lists * * functions called: * none * * side effects: * Symbol types changed. */ VOID symglob(void) { struct sym *sp; int i; for (i=0; is_type == S_NEW) sp->s_flag |= S_GBL; sp = sp->s_sp; } } } /*)Function VOID allglob() * * The function allglob() will mark all symbols of * type S_USER as global. Called at * the beginning of pass 1 if the assembly * option -a was specified. * * local variables: * sym * sp pointer to a sym structure * int i loop index * * global variables: * sym * symhash[] array of pointers to NHASH * linked symbol lists * * functions called: * none * * side effects: * Symbol types changed. */ VOID allglob(void) { struct sym *sp; int i; for (i=0; is_type == S_USER) sp->s_flag |= S_GBL; sp = sp->s_sp; } } } /*)Function int symeq(p1, p2, flag) * * int flag case sensitive flag * char * p1 name string * char * p2 name string * * The function symeq() compares the two name strings for a match. * The return value is 1 for a match and 0 for no match. * * flag == 0 case sensitive compare * flag != 0 case insensitive compare * * local variables: * int n loop counter * * global variables: * char ccase[] an array of characters which * perform the case translation function * * functions called: * none * * side effects: * none * */ int symeq(const char *p1, const char *p2, int flag) { size_t n; n = strlen(p1) + 1; if(flag) { /* * Case Insensitive Compare */ do { if (ccase[*p1++ & 0x007F] != ccase[*p2++ & 0x007F]) return (0); } while (--n); } else { /* * Case Sensitive Compare */ do { if (*p1++ != *p2++) return (0); } while (--n); } return (1); } /*)Function int hash(p, flag) * * char * p pointer to string to hash * int flag case sensitive flag * * The function hash() computes a hash code using the sum * of all characters mod table size algorithm. * * flag == 0 case insensitve hash * flag != 0 case sensitive hash * * local variables: * int h accumulated character sum * * global variables: * char ccase[] an array of characters which * perform the case translation function * * functions called: * none * * side effects: * none */ int hash(const char *p, int flag) { int h; h = 0; while (*p) { if(flag) { /* * Case Insensitive Hash */ h += ccase[*p++ & 0x007F]; } else { /* * Case Sensitive Hash */ h += *p++; } } return (h&HMASK); } /*)Function char * strsto(str) * * char * str pointer to string to save * * Allocate space for "str", copy str into new space. * Return a pointer to the allocated string. * * This function based on code by * John L. Hartman * jhartman at compuserve dot com * * local variables: * int bytes bytes remaining in buffer area * int len string length + 1 * char * p pointer to head of copied string * char * pnext next location in buffer area * * global variables: * none * * functions called: * char * new() assym.c * char * strncpy() c_library * int * strlen() c_library * * side effects: * Space allocated for string, string copied * to space. Out of Space terminates assembler. */ /* * To avoid wasting memory headers on small allocations, we * allocate a big chunk and parcel it out as required. * These static variables remember our hunk. */ #define STR_SPC 1024 static char * pnext = NULL; static int bytes = 0; char * strsto(const char *str) { int len; char *p; /* * What we need, including a null. */ len = strlen(str) + 1; if (len > bytes) { /* * No space. Allocate a new hunk. * We lose the pointer to any old hunk. * We don't care, as the names are never deleted. */ pnext = (char *) new (STR_SPC); bytes = STR_SPC; } /* * Copy the name and terminating null. */ p = pnext; strncpy(p, str, len); pnext += len; bytes -= len; return(p); } /*)Function char * new(n) * * unsigned int n allocation size in bytes * * The function new() allocates n bytes of space and returns * a pointer to this memory. If no space is available the * assembly is terminated. * * local variables: * VOID * p a general pointer * * global variables: * none * * functions called: * VOID asexit() asmain.c * int fprintf() c_library * VOID * malloc() c_library * * side effects: * Memory is allocated, if allocation fails * the assembly is terminated. */ char * new(unsigned int n) { VOID *p; if ((p = (VOID *) malloc(n)) == NULL) { fprintf(stderr, "Out of space!\n"); asexit(ER_FATAL); } memset (p, 0, n); return (p); }