home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / nasm097s.zip / LABELS.C < prev    next >
C/C++ Source or Header  |  1997-10-02  |  9KB  |  318 lines

  1. /* labels.c  label handling for the Netwide Assembler
  2.  *
  3.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  4.  * Julian Hall. All rights reserved. The software is
  5.  * redistributable under the licence given in the file "Licence"
  6.  * distributed in the NASM archive.
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include "nasm.h"
  13. #include "nasmlib.h"
  14.  
  15. /*
  16.  * A local label is one that begins with exactly one period. Things
  17.  * that begin with _two_ periods are NASM-specific things.
  18.  */
  19. #define islocal(l) ((l)[0] == '.' && (l)[1] != '.')
  20.  
  21. #define LABEL_BLOCK  320           /* no. of labels/block */
  22. #define LBLK_SIZE    (LABEL_BLOCK*sizeof(union label))
  23. #define LABEL_HASHES 32               /* no. of hash table entries */
  24.  
  25. #define END_LIST -3               /* don't clash with NO_SEG! */
  26. #define END_BLOCK -2
  27. #define BOGUS_VALUE -4
  28.  
  29. #define PERMTS_SIZE  4096           /* size of text blocks */
  30.  
  31. /* values for label.defn.is_global */
  32. #define DEFINED_BIT 1
  33. #define GLOBAL_BIT 2
  34. #define EXTERN_BIT 4
  35.  
  36. #define NOT_DEFINED_YET 0
  37. #define TYPE_MASK 3
  38. #define LOCAL_SYMBOL (DEFINED_BIT)
  39. #define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
  40. #define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
  41.  
  42. union label {                   /* actual label structures */
  43.     struct {
  44.     long segment, offset;
  45.         char *label, *special;
  46.     int is_global;
  47.     } defn;
  48.     struct {
  49.     long movingon, dummy;
  50.     union label *next;
  51.     } admin;
  52. };
  53.  
  54. struct permts {                   /* permanent text storage */
  55.     struct permts *next;           /* for the linked list */
  56.     int size, usage;               /* size and used space in ... */
  57.     char data[PERMTS_SIZE];           /* ... the data block itself */
  58. };
  59.  
  60. static union label *ltab[LABEL_HASHES];/* using a hash table */
  61. static union label *lfree[LABEL_HASHES];/* pointer into the above */
  62. static struct permts *perm_head;      /* start of perm. text storage */
  63. static struct permts *perm_tail;      /* end of perm. text storage */
  64.  
  65. static void init_block (union label *blk);
  66. static char *perm_copy (char *string1, char *string2);
  67.  
  68. static char *prevlabel;
  69.  
  70. static int initialised = FALSE;
  71.  
  72. /*
  73.  * Internal routine: finds the `union label' corresponding to the
  74.  * given label name. Creates a new one, if it isn't found, and if
  75.  * `create' is TRUE.
  76.  */
  77. static union label *find_label (char *label, int create) {
  78.     int hash = 0;
  79.     char *p, *prev;
  80.     int prevlen;
  81.     union label *lptr;
  82.  
  83.     if (islocal(label))
  84.     prev = prevlabel;
  85.     else
  86.     prev = "";
  87.     prevlen = strlen(prev);
  88.     p = prev;
  89.     while (*p) hash += *p++;
  90.     p = label;
  91.     while (*p) hash += *p++;
  92.     hash %= LABEL_HASHES;
  93.     lptr = ltab[hash];
  94.     while (lptr->admin.movingon != END_LIST) {
  95.     if (lptr->admin.movingon == END_BLOCK) {
  96.         lptr = lptr->admin.next;
  97.         if (!lptr)
  98.         break;
  99.     }
  100.     if (!strncmp(lptr->defn.label, prev, prevlen) &&
  101.         !strcmp(lptr->defn.label+prevlen, label))
  102.         return lptr;
  103.     lptr++;
  104.     }
  105.     if (create) {
  106.     if (lfree[hash]->admin.movingon == END_BLOCK) {
  107.         /*
  108.          * must allocate a new block
  109.          */
  110.         lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
  111.         lfree[hash] = lfree[hash]->admin.next;
  112.         init_block(lfree[hash]);
  113.     }
  114.  
  115.     lfree[hash]->admin.movingon = BOGUS_VALUE;
  116.     lfree[hash]->defn.label = perm_copy (prev, label);
  117.     lfree[hash]->defn.special = NULL;
  118.     lfree[hash]->defn.is_global = NOT_DEFINED_YET;
  119.     return lfree[hash]++;
  120.     } else
  121.     return NULL;
  122. }
  123.  
  124. int lookup_label (char *label, long *segment, long *offset) {
  125.     union label *lptr;
  126.  
  127.     if (!initialised)
  128.     return 0;
  129.  
  130.     lptr = find_label (label, 0);
  131.     if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
  132.     *segment = lptr->defn.segment;
  133.     *offset = lptr->defn.offset;
  134.     return 1;
  135.     } else
  136.     return 0;
  137. }
  138.  
  139. int is_extern (char *label) {
  140.     union label *lptr;
  141.  
  142.     if (!initialised)
  143.     return 0;
  144.  
  145.     lptr = find_label (label, 0);
  146.     if (lptr && (lptr->defn.is_global & EXTERN_BIT))
  147.     return 1;
  148.     else
  149.     return 0;
  150. }
  151.  
  152. void define_label_stub (char *label, efunc error) {
  153.     union label *lptr;
  154.  
  155.     if (!islocal(label)) {
  156.     lptr = find_label (label, 1);
  157.     if (!lptr)
  158.         error (ERR_PANIC, "can't find label `%s' on pass two", label);
  159.     if (*label != '.')
  160.         prevlabel = lptr->defn.label;
  161.     }
  162. }
  163.  
  164. void define_label (char *label, long segment, long offset, char *special,
  165.            int is_norm, int isextrn, struct ofmt *ofmt, efunc error) {
  166.     union label *lptr;
  167.  
  168.     lptr = find_label (label, 1);
  169.     if (lptr->defn.is_global & DEFINED_BIT) {
  170.     error(ERR_NONFATAL, "symbol `%s' redefined", label);
  171.     return;
  172.     }
  173.     lptr->defn.is_global |= DEFINED_BIT;
  174.     if (isextrn)
  175.     lptr->defn.is_global |= EXTERN_BIT;
  176.  
  177.     if (label[0] != '.' && is_norm)    /* not local, but not special either */
  178.     prevlabel = lptr->defn.label;
  179.     else if (label[0] == '.' && label[1] != '.' && !*prevlabel)
  180.     error(ERR_NONFATAL, "attempt to define a local label before any"
  181.           " non-local labels");
  182.  
  183.     lptr->defn.segment = segment;
  184.     lptr->defn.offset = offset;
  185.  
  186.     ofmt->symdef (lptr->defn.label, segment, offset,
  187.           !!(lptr->defn.is_global & GLOBAL_BIT),
  188.           special ? special : lptr->defn.special);
  189. }
  190.  
  191. void define_common (char *label, long segment, long size, char *special,
  192.             struct ofmt *ofmt, efunc error) {
  193.     union label *lptr;
  194.  
  195.     lptr = find_label (label, 1);
  196.     if (lptr->defn.is_global & DEFINED_BIT) {
  197.     error(ERR_NONFATAL, "symbol `%s' redefined", label);
  198.     return;
  199.     }
  200.     lptr->defn.is_global |= DEFINED_BIT;
  201.  
  202.     if (label[0] != '.')           /* not local, but not special either */
  203.     prevlabel = lptr->defn.label;
  204.     else
  205.     error(ERR_NONFATAL, "attempt to define a local label as a "
  206.           "common variable");
  207.  
  208.     lptr->defn.segment = segment;
  209.     lptr->defn.offset = 0;
  210.  
  211.     ofmt->symdef (lptr->defn.label, segment, size, 2,
  212.           special ? special : lptr->defn.special);
  213. }
  214.  
  215. void declare_as_global (char *label, char *special, efunc error) {
  216.     union label *lptr;
  217.  
  218.     if (islocal(label)) {
  219.     error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
  220.           " global", label);
  221.     return;
  222.     }
  223.     lptr = find_label (label, 1);
  224.     switch (lptr->defn.is_global & TYPE_MASK) {
  225.       case NOT_DEFINED_YET:
  226.     lptr->defn.is_global = GLOBAL_PLACEHOLDER;
  227.     lptr->defn.special = special ? perm_copy(special, "") : NULL;
  228.     break;
  229.       case GLOBAL_PLACEHOLDER:           /* already done: silently ignore */
  230.       case GLOBAL_SYMBOL:
  231.     break;
  232.       case LOCAL_SYMBOL:
  233.     if (!lptr->defn.is_global & EXTERN_BIT)
  234.         error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
  235.           " appear before symbol definition", label);
  236.     break;
  237.     }
  238. }
  239.  
  240. int init_labels (void) {
  241.     int i;
  242.  
  243.     for (i=0; i<LABEL_HASHES; i++) {
  244.     ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
  245.     if (!ltab[i])
  246.         return -1;               /* can't initialise, panic */
  247.     init_block (ltab[i]);
  248.     lfree[i] = ltab[i];
  249.     }
  250.  
  251.     perm_head = perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
  252.     if (!perm_head)
  253.         return -1;
  254.  
  255.     perm_head->next = NULL;
  256.     perm_head->size = PERMTS_SIZE;
  257.     perm_head->usage = 0;
  258.  
  259.     prevlabel = "";
  260.  
  261.     initialised = TRUE;
  262.  
  263.     return 0;
  264. }
  265.  
  266. void cleanup_labels (void) {
  267.     int i;
  268.  
  269.     initialised = FALSE;
  270.  
  271.     for (i=0; i<LABEL_HASHES; i++) {
  272.     union label *lptr, *lhold;
  273.  
  274.     lptr = lhold = ltab[i];
  275.  
  276.     while (lptr) {
  277.         while (lptr->admin.movingon != END_BLOCK) lptr++;
  278.         lptr = lptr->admin.next;
  279.         nasm_free (lhold);
  280.         lhold = lptr;
  281.     }
  282.     }
  283.  
  284.     while (perm_head) {
  285.     perm_tail = perm_head;
  286.     perm_head = perm_head->next;
  287.     nasm_free (perm_tail);
  288.     }
  289. }
  290.  
  291. static void init_block (union label *blk) {
  292.     int j;
  293.  
  294.     for (j=0; j<LABEL_BLOCK-1; j++)
  295.         blk[j].admin.movingon = END_LIST;
  296.     blk[LABEL_BLOCK-1].admin.movingon = END_BLOCK;
  297.     blk[LABEL_BLOCK-1].admin.next = NULL;
  298. }
  299.  
  300. static char *perm_copy (char *string1, char *string2) {
  301.     char *p, *q;
  302.     int len = strlen(string1)+strlen(string2)+1;
  303.  
  304.     if (perm_tail->size - perm_tail->usage < len) {
  305.     perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
  306.     perm_tail = perm_tail->next;
  307.     perm_tail->next = NULL;
  308.     perm_tail->size = PERMTS_SIZE;
  309.     perm_tail->usage = 0;
  310.     }
  311.     p = q = perm_tail->data + perm_tail->usage;
  312.     while ( (*q = *string1++) ) q++;
  313.     while ( (*q++ = *string2++) );
  314.     perm_tail->usage = q - perm_tail->data;
  315.  
  316.     return p;
  317. }
  318.