* sim/ucsim/configure.in,
[fw/sdcc] / src / SDCCsymt.c
index c6cd281a0e6c778db6792c74ba383fa2d00ff002..4ceceaf007bd50c5a55f08ee18cb4d8d12a879cb 100644 (file)
 #include "common.h"
 #include "newalloc.h"
 
+#include "SDCCsymt.h"
+
 value *aggregateToPointer (value *val);
+void printTypeChainRaw (sym_link * start, FILE * of);
 
 void printFromToType(sym_link *from, sym_link *to) {
   fprintf (stderr, "from type '");
@@ -48,6 +51,7 @@ char *nounName(sym_link *sl) {
     case V_VOID: return "void";
     case V_STRUCT: return "struct";
     case V_LABEL: return "label";
+    case V_BITFIELD: return "bitfield";
     case V_BIT: return "bit";
     case V_SBIT: return "sbit";
     case V_DOUBLE: return "double";
@@ -138,7 +142,7 @@ addSym (bucket ** stab,
   bp->sym = sym;               /* update the symbol pointer  */
   bp->level = level;           /* update the nest level      */
   bp->block = block;
-  strcpy (bp->name, sname);    /* copy the name into place */
+  strncpyz (bp->name, sname, sizeof(bp->name));        /* copy the name into place */
 
   /* if this is the first entry */
   if (stab[i] == NULL)
@@ -287,10 +291,11 @@ newSymbol (char *name, int scope)
 
   sym = Safe_alloc ( sizeof (symbol));
 
-  strcpy (sym->name, name);    /* copy the name    */
+  strncpyz (sym->name, name, sizeof(sym->name));       /* copy the name */
   sym->level = scope;          /* set the level    */
   sym->block = currBlockno;
-  sym->lineDef = yylineno;     /* set the line number */
+  sym->lineDef = mylineno;     /* set the line number */
+  sym->fileDef = currFname;
   return sym;
 }
 
@@ -298,11 +303,12 @@ newSymbol (char *name, int scope)
 /* newLink - creates a new link (declarator,specifier)              */
 /*------------------------------------------------------------------*/
 sym_link *
-newLink ()
+newLink (SYM_LINK_CLASS select)
 {
   sym_link *p;
 
   p = Safe_alloc ( sizeof (sym_link));
+  p->class=select;
 
   return p;
 }
@@ -317,9 +323,40 @@ newStruct (char *tag)
 
   s = Safe_alloc ( sizeof (structdef));
 
-  strcpy (s->tag, tag);                /* copy the tag            */
+  strncpyz (s->tag, tag, sizeof(s->tag));              /* copy the tag */
   return s;
 }
+  
+/*------------------------------------------------------------------*/
+/* sclsFromPtr - Return the storage class a pointer points into.    */
+/*               S_FIXED is returned for generic pointers or other  */
+/*               unexpected cases                                   */
+/*------------------------------------------------------------------*/
+STORAGE_CLASS
+sclsFromPtr(sym_link *ptr)
+{
+  switch (DCL_TYPE (ptr))
+    {
+    case POINTER:
+      return S_DATA;
+    case GPOINTER:
+      return S_FIXED;
+    case FPOINTER:
+      return S_XDATA;
+    case CPOINTER:
+      return S_CODE;
+    case IPOINTER:
+      return S_IDATA;
+    case PPOINTER:
+      return S_PDATA;
+    case EEPPOINTER:
+      return S_EEPROM;
+    case FUNCTION:
+      return S_CODE;
+    default:
+      return S_FIXED;
+    }
+}
 
 /*------------------------------------------------------------------*/
 /* pointerTypes - do the computation for the pointer types          */
@@ -347,8 +384,6 @@ pointerTypes (sym_link * ptr, sym_link * type)
      storage class of the type */
   if (IS_SPEC (type))
     {
-      DCL_PTR_CONST (ptr) = SPEC_CONST (type);
-      DCL_PTR_VOLATILE (ptr) = SPEC_VOLATILE (type);
       switch (SPEC_SCLS (type))
        {
        case S_XDATA:
@@ -364,20 +399,17 @@ pointerTypes (sym_link * ptr, sym_link * type)
          DCL_TYPE (ptr) = POINTER;
          break;
        case S_CODE:
-         DCL_PTR_CONST (ptr) = port->mem.code_ro;
          DCL_TYPE (ptr) = CPOINTER;
          break;
        case S_EEPROM:
          DCL_TYPE (ptr) = EEPPOINTER;
          break;
        default:
-         DCL_TYPE (ptr) = GPOINTER;
+         DCL_TYPE (ptr) = port->unqualified_pointer;
          break;
        }
       /* the storage class of type ends here */
-      SPEC_SCLS (type) =
-       SPEC_CONST (type) =
-       SPEC_VOLATILE (type) = 0;
+      SPEC_SCLS (type) = 0;
     }
 
   /* now change all the remaining unknown pointers
@@ -385,7 +417,7 @@ pointerTypes (sym_link * ptr, sym_link * type)
   while (ptr)
     {
       if (!IS_SPEC (ptr) && DCL_TYPE (ptr) == UPOINTER)
-       DCL_TYPE (ptr) = GPOINTER;
+       DCL_TYPE (ptr) = port->unqualified_pointer;
       ptr = ptr->next;
     }
 
@@ -394,10 +426,9 @@ pointerTypes (sym_link * ptr, sym_link * type)
   while (type)
     {
       if (!IS_SPEC (type) && DCL_TYPE (type) == UPOINTER)
-       DCL_TYPE (type) = GPOINTER;
+       DCL_TYPE (type) = port->unqualified_pointer;
       type = type->next;
     }
-
 }
 
 /*------------------------------------------------------------------*/
@@ -422,7 +453,7 @@ addDecl (symbol * sym, int type, sym_link * p)
     }
   else
     {
-      head = tail = newLink ();
+      head = tail = newLink (DECLARATOR);
       DCL_TYPE (head) = type;
     }
 
@@ -467,12 +498,9 @@ addDecl (symbol * sym, int type, sym_link * p)
     {
       if (!IS_SPEC (sym->etype))
        {
-         sym->etype = sym->etype->next = newLink ();
-         sym->etype->class = SPECIFIER;
+         sym->etype = sym->etype->next = newLink (SPECIFIER);
        }
       SPEC_SCLS (sym->etype) = SPEC_SCLS (DCL_TSPEC (p));
-      SPEC_CONST (sym->etype) = SPEC_CONST (DCL_TSPEC (p));
-      SPEC_VOLATILE (sym->etype) = SPEC_VOLATILE (DCL_TSPEC (p));
       DCL_TSPEC (p) = NULL;
     }
 
@@ -508,7 +536,7 @@ void checkTypeSanity(sym_link *etype, char *name) {
   noun=nounName(etype);
 
   if (getenv("DEBUG_SANITY")) {
-    fprintf (stderr, "checking sanity for %s %x\n", name, (int)etype);
+    fprintf (stderr, "checking sanity for %s %p\n", name, etype);
   }
 
   if ((SPEC_NOUN(etype)==V_CHAR || 
@@ -540,6 +568,14 @@ void checkTypeSanity(sym_link *etype, char *name) {
     SPEC_NOUN(etype)=V_INT;
   }
 
+  /* ISO/IEC 9899 J.3.9 implementation defined behaviour: */
+  /* a "plain" int bitfield is unsigned */
+  if (SPEC_NOUN(etype)==V_BIT ||
+      SPEC_NOUN(etype)==V_SBIT) {
+    if (!etype->select.s._signed)
+      SPEC_USIGN(etype) = 1;
+  }
+
   if (etype->select.s._signed && SPEC_USIGN(etype)) {
     // signed AND unsigned 
     werror (E_SIGNED_AND_UNSIGNED_INVALID, noun, name);
@@ -557,8 +593,6 @@ void checkTypeSanity(sym_link *etype, char *name) {
 sym_link *
 mergeSpec (sym_link * dest, sym_link * src, char *name)
 {
-  sym_link *symlink=dest;
-
   if (!IS_SPEC(dest) || !IS_SPEC(src)) {
 #if 0
     werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "cannot merge declarator");
@@ -621,7 +655,10 @@ mergeSpec (sym_link * dest, sym_link * src, char *name)
   SPEC_BLEN (dest) |= SPEC_BLEN (src);
   SPEC_BSTR (dest) |= SPEC_BSTR (src);
   SPEC_TYPEDEF (dest) |= SPEC_TYPEDEF (src);
-
+  SPEC_ENUM (dest) |= SPEC_ENUM (src);
+  if (SPEC_ARGREG(src) && !SPEC_ARGREG(dest))
+      SPEC_ARGREG(dest) = SPEC_ARGREG(src);
+  
   if (IS_STRUCT (dest) && SPEC_STRUCT (dest) == NULL)
     SPEC_STRUCT (dest) = SPEC_STRUCT (src);
 
@@ -633,27 +670,13 @@ mergeSpec (sym_link * dest, sym_link * src, char *name)
   FUNC_ISREENT(dest) |= FUNC_ISREENT(src);
   FUNC_ISNAKED(dest) |= FUNC_ISNAKED(src);
   FUNC_ISISR(dest) |= FUNC_ISISR(src);
+  FUNC_ISJAVANATIVE(dest) |= FUNC_ISJAVANATIVE(src);
+  FUNC_ISBUILTIN(dest) |= FUNC_ISBUILTIN(src);
+  FUNC_ISOVERLAY(dest) |= FUNC_ISOVERLAY(src);
   FUNC_INTNO(dest) |= FUNC_INTNO(src);
   FUNC_REGBANK(dest) |= FUNC_REGBANK(src);
 
-  return symlink;
-}
-
-/*------------------------------------------------------------------*/
-/* cloneSpec - copies the entire spec and returns a new spec        */
-/*------------------------------------------------------------------*/
-sym_link *
-cloneSpec (sym_link * src)
-{
-  sym_link *spec;
-
-  /* go thru chain till we find the specifier */
-  while (src && src->class != SPECIFIER)
-    src = src->next;
-
-  spec = newLink ();
-  memcpy (spec, src, sizeof (sym_link));
-  return spec;
+  return dest;
 }
 
 /*------------------------------------------------------------------*/
@@ -665,7 +688,7 @@ genSymName (int level)
   static int gCount = 0;
   static char gname[SDCC_NAME_MAX + 1];
 
-  sprintf (gname, "__%04d%04d", level, gCount++);
+  SNPRINTF (gname, sizeof(gname), "__%04d%04d", level, gCount++);
   return gname;
 }
 
@@ -692,8 +715,7 @@ newCharLink ()
 {
   sym_link *p;
 
-  p = newLink ();
-  p->class = SPECIFIER;
+  p = newLink (SPECIFIER);
   SPEC_NOUN (p) = V_CHAR;
 
   return p;
@@ -707,8 +729,7 @@ newFloatLink ()
 {
   sym_link *p;
 
-  p = newLink ();
-  p->class = SPECIFIER;
+  p = newLink (SPECIFIER);
   SPEC_NOUN (p) = V_FLOAT;
 
   return p;
@@ -722,8 +743,7 @@ newLongLink ()
 {
   sym_link *p;
 
-  p = newLink ();
-  p->class = SPECIFIER;
+  p = newLink (SPECIFIER);
   SPEC_NOUN (p) = V_INT;
   SPEC_LONG (p) = 1;
 
@@ -738,8 +758,7 @@ newIntLink ()
 {
   sym_link *p;
 
-  p = newLink ();
-  p->class = SPECIFIER;
+  p = newLink (SPECIFIER);
   SPEC_NOUN (p) = V_INT;
 
   return p;
@@ -771,8 +790,9 @@ getSize (sym_link * p)
        case V_LABEL:
          return 0;
        case V_SBIT:
-         return BITSIZE;
        case V_BIT:
+         return BITSIZE;
+       case V_BITFIELD:
          return ((SPEC_BLEN (p) / 8) + (SPEC_BLEN (p) % 8 ? 1 : 0));
        default:
          return 0;
@@ -783,7 +803,13 @@ getSize (sym_link * p)
   switch (DCL_TYPE (p))
     {
     case ARRAY:
-      return DCL_ELEM (p) * getSize (p->next);
+      if (DCL_ELEM(p)) {
+       return DCL_ELEM (p) * getSize (p->next);
+      } else {
+         //    werror (E_INTERNAL_ERROR, __FILE__, __LINE__, 
+         //    "can not tell the size of an array[]");
+       return 0;
+      }
     case IPOINTER:
     case PPOINTER:
     case POINTER:
@@ -829,8 +855,9 @@ bitsForType (sym_link * p)
        case V_LABEL:
          return 0;
        case V_SBIT:
-         return 1;
        case V_BIT:
+         return 1;
+       case V_BITFIELD:
          return SPEC_BLEN (p);
        default:
          return 0;
@@ -957,36 +984,85 @@ addSymChain (symbol * symHead)
 {
   symbol *sym = symHead;
   symbol *csym = NULL;
+  int error = 0;
 
   for (; sym != NULL; sym = sym->next)
     {
       changePointer(sym);
       checkTypeSanity(sym->etype, sym->name);
 
+      if (!sym->level && !(IS_SPEC(sym->etype) && IS_TYPEDEF(sym->etype)))
+        checkDecl (sym, 0);
+      
       /* if already exists in the symbol table then check if
          one of them is an extern definition if yes then
          then check if the type match, if the types match then
          delete the current entry and add the new entry      */
       if ((csym = findSymWithLevel (SymbolTab, sym)) &&
          csym->level == sym->level) {
-       
-       /* one definition extern ? */
-       if (IS_EXTERN (csym->etype) || IS_EXTERN (sym->etype)) {
-         /* do types match ? */
-         if (compareType (csym->type, sym->type) != 1) {
-           /* no then error */
-           werror (E_EXTERN_MISMATCH, csym->name);
-           continue;
+
+       /* If the previous definition was for an array with incomplete */
+       /* type, and the new definition has completed the type, update */
+       /* the original type to match */
+       if (IS_DECL(csym->type) && DCL_TYPE(csym->type)==ARRAY
+           && IS_DECL(sym->type) && DCL_TYPE(sym->type)==ARRAY)
+         {
+           if (!DCL_ELEM(csym->type) && DCL_ELEM(sym->type))
+             DCL_ELEM(csym->type) = DCL_ELEM(sym->type);
+         }
+
+       #if 0
+       /* If only one of the definitions used the "at" keyword, copy */
+       /* the address to the other. */
+       if (IS_SPEC(csym->etype) && SPEC_ABSA(csym->etype)
+           && IS_SPEC(sym->etype) && !SPEC_ABSA(sym->etype))
+         {
+           SPEC_ABSA (sym->etype) = 1;
+           SPEC_ADDR (sym->etype) = SPEC_ADDR (csym->etype);
          }
-         /* delete current entry */
-         deleteSym (SymbolTab, csym, csym->name);
-       } else {
-         /* not extern */
-         werror (E_DUPLICATE, sym->name);
+       if (IS_SPEC(csym->etype) && !SPEC_ABSA(csym->etype)
+           && IS_SPEC(sym->etype) && SPEC_ABSA(sym->etype))
+         {
+           SPEC_ABSA (csym->etype) = 1;
+           SPEC_ADDR (csym->etype) = SPEC_ADDR (sym->etype);
+         }
+       #endif
+  
+        error = 0;        
+        if (csym->ival && sym->ival)
+          error = 1;
+       if (compareTypeExact (csym->type, sym->type, sym->level) != 1)
+          error = 1;
+        
+        if (error) {
+          /* one definition extern ? */
+         if (IS_EXTERN (csym->etype) || IS_EXTERN (sym->etype))
+           werror (E_EXTERN_MISMATCH, sym->name);
+          else
+           werror (E_DUPLICATE, sym->name);
+         werrorfl (csym->fileDef, csym->lineDef, E_PREVIOUS_DEF);
+         #if 0
+         fprintf (stderr, "from type '");
+         printTypeChain (csym->type, stderr);
+         if (IS_SPEC (csym->etype) && SPEC_ABSA (csym->etype))
+           fprintf(stderr, " at 0x%x", SPEC_ADDR (csym->etype));
+         fprintf (stderr, "'\nto type '");
+         printTypeChain (sym->type, stderr);
+         if (IS_SPEC (sym->etype) && SPEC_ABSA (sym->etype))
+           fprintf(stderr, " at 0x%x", SPEC_ADDR (sym->etype));
+         fprintf (stderr, "'\n");
+         #endif
          continue;
        }
-      }
 
+       if (csym->ival && !sym->ival)
+         sym->ival = csym->ival;
+
+       /* delete current entry */
+       deleteSym (SymbolTab, csym, csym->name);
+       deleteFromSeg(csym);
+      }
+      
       /* add new entry */
       addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
     }
@@ -1009,7 +1085,7 @@ funcInChain (sym_link * lnk)
 }
 
 /*------------------------------------------------------------------*/
-/* structElemType - returns the type info of a sturct member        */
+/* structElemType - returns the type info of a struct member        */
 /*------------------------------------------------------------------*/
 sym_link *
 structElemType (sym_link * stype, value * id)
@@ -1018,25 +1094,31 @@ structElemType (sym_link * stype, value * id)
   sym_link *type, *etype;
   sym_link *petype = getSpec (stype);
 
-  if (!fields || !id)
-    return NULL;
+  if (fields && id) {
+    
+    /* look for the id */
+    while (fields)
+      {
+       if (strcmp (fields->rname, id->name) == 0)
+         {
+           type = copyLinkChain (fields->type);
+           etype = getSpec (type);
+           SPEC_SCLS (etype) = (SPEC_SCLS (petype) == S_REGISTER ?
+                                SPEC_SCLS (etype) : SPEC_SCLS (petype));
+            if (IS_SPEC (type))
+              SPEC_CONST (type) |= SPEC_CONST (stype);
+            else
+              DCL_PTR_CONST (type) |= SPEC_CONST (stype);
+           return type;
+         }
+       fields = fields->next;
+      }
+  }
 
-  /* look for the id */
-  while (fields)
-    {
-      if (strcmp (fields->rname, id->name) == 0)
-       {
-         type = copyLinkChain (fields->type);
-         etype = getSpec (type);
-         SPEC_SCLS (etype) = (SPEC_SCLS (petype) == S_REGISTER ?
-                              SPEC_SCLS (etype) : SPEC_SCLS (petype));
-         return type;
-       }
-      fields = fields->next;
-    }
   werror (E_NOT_MEMBER, id->name);
-
-  return NULL;
+    
+  // the show must go on
+  return newIntLink();
 }
 
 /*------------------------------------------------------------------*/
@@ -1071,116 +1153,235 @@ compStructSize (int su, structdef * sdef)
     while (loop) {
 
        /* create the internal name for this variable */
-       sprintf (loop->rname, "_%s", loop->name);
-       loop->offset = (su == UNION ? sum = 0 : sum);
+       SNPRINTF (loop->rname, sizeof(loop->rname), "_%s", loop->name);
+       if (su == UNION) {
+           sum = 0;
+           bitOffset = 0;
+       }
        SPEC_VOLATILE (loop->etype) |= (su == UNION ? 1 : 0);
 
        /* if this is a bit field  */
        if (loop->bitVar) {
 
            /* change it to a unsigned bit */
-           SPEC_NOUN (loop->etype) = V_BIT;
+           SPEC_NOUN (loop->etype) = V_BITFIELD;
            SPEC_USIGN (loop->etype) = 1;
-           /* check if this fit into the remaining   */
-           /* bits of this byte else align it to the */
-           /* next byte boundary                     */
-           if ((SPEC_BLEN (loop->etype) = loop->bitVar) <= (8 - bitOffset)) {
-               SPEC_BSTR (loop->etype) = bitOffset;
-               if ((bitOffset += (loop->bitVar % 8)) == 8)
-                   sum++;
-           }
-           else /* does not fit */ {
-               bitOffset = 0;
-               SPEC_BSTR (loop->etype) = bitOffset;
-               sum += (loop->bitVar / 8);
-               bitOffset += (loop->bitVar % 8);
+           SPEC_BLEN (loop->etype) = loop->bitVar;
+
+           if (loop->bitVar == BITVAR_PAD) {
+               /* A zero length bitfield forces padding */
+               SPEC_BSTR (loop->etype) = bitOffset;
+               SPEC_BLEN (loop->etype) = 0;
+               bitOffset = 8;
+               loop->offset = sum;
            }
-           /* if this is the last field then pad */
-           if (!loop->next && bitOffset && bitOffset != 8) {
-               bitOffset = 0;
-               sum++;
+           else {
+               if (bitOffset == 8) {
+                   bitOffset = 0;
+                   sum++;
+               }
+               /* check if this fit into the remaining   */
+               /* bits of this byte else align it to the */
+               /* next byte boundary                     */
+               if (loop->bitVar <= (8 - bitOffset)) {
+                   /* fits into current byte */
+                   loop->offset = sum;
+                   SPEC_BSTR (loop->etype) = bitOffset;
+                   bitOffset += loop->bitVar;
+               }
+               else if (!bitOffset) {
+                   /* does not fit, but is already byte aligned */
+                   loop->offset = sum;
+                   SPEC_BSTR (loop->etype) = bitOffset;
+                   bitOffset += loop->bitVar;
+               } 
+               else {
+                   /* does not fit; need to realign first */
+                   sum++;
+                   loop->offset = (su == UNION ? sum = 0 : sum);
+                   bitOffset = 0;
+                   SPEC_BSTR (loop->etype) = bitOffset;
+                   bitOffset += loop->bitVar;
+               }
+               while (bitOffset>8) {
+                   bitOffset -= 8;
+                   sum++;
+               } 
            }
        }
        else {
+           /* This is a non-bit field. Make sure we are */
+           /* byte aligned first */
+           if (bitOffset) {
+               sum++;
+               loop->offset = (su == UNION ? sum = 0 : sum);
+               bitOffset = 0;
+           }
+           loop->offset = sum;
            checkDecl (loop, 1);
            sum += getSize (loop->type);
        }
 
-#if 0 // jwk: this is done now in addDecl()
-       /* if function then do the arguments for it */
-       if (funcInChain (loop->type)) {
-           processFuncArgs (loop);
-       }
-#endif
-
        loop = loop->next;
 
-       /* if this is not a bitfield but the */
-       /* previous one was and did not take */
-       /* the whole byte then pad the rest  */
-       if ((loop && !loop->bitVar) && bitOffset) {
-           bitOffset = 0;
-           sum++;
-       }
-
        /* if union then size = sizeof larget field */
-       if (su == UNION)
+       if (su == UNION) {
+           /* For UNION, round up after each field */
+           sum += ((bitOffset+7)/8);
            usum = max (usum, sum);
+       }
 
     }
+    
+    /* For STRUCT, round up after all fields processed */
+    if (su != UNION)
+       sum += ((bitOffset+7)/8);
 
     return (su == UNION ? usum : sum);
 }
 
+/*-------------------------------------------------------------------*/
+/* promoteAnonStructs - promote anonymous struct/union's fields into */
+/*                      an enclosing struct/union                    */
+/*-------------------------------------------------------------------*/
+void
+promoteAnonStructs (int su, structdef * sdef)
+{
+  symbol *field;
+  symbol *subfield;
+  symbol **tofield;
+  symbol *nextfield;
+  symbol *dupfield;
+  int base;
+
+  tofield = &sdef->fields;
+  field = sdef->fields;
+  while (field)
+    {
+      nextfield = field->next;
+      if (!*field->name && IS_STRUCT (field->type))
+       {
+         /* Found an anonymous struct/union. Replace it */
+         /* with the fields it contains and adjust all  */
+         /* the offsets */
+         
+         base = field->offset;
+         subfield = copySymbolChain (SPEC_STRUCT (field->type)->fields);
+         if (!subfield)
+           continue;           /* just in case it's empty */
+         
+         *tofield = subfield;
+         for (;;)
+           {
+             /* check for field name conflicts resulting from promotion */
+             dupfield = sdef->fields;
+             while (dupfield && dupfield != subfield)
+               {
+                 if (*subfield->name && !strcmp (dupfield->name, subfield->name))
+                   {
+                     werrorfl (subfield->fileDef, subfield->lineDef,
+                               E_DUPLICATE_MEMBER,
+                               su==STRUCT ? "struct" : "union",
+                               subfield->name);
+                     werrorfl (dupfield->fileDef, dupfield->lineDef,
+                               E_PREVIOUS_DEF);
+                   }
+                 dupfield = dupfield->next;
+               }
+             
+             subfield->offset += base;
+             if (subfield->next)
+               subfield = subfield->next;
+             else
+               break;
+           }
+         subfield->next = nextfield;
+         tofield = &subfield->next;
+       }
+      else
+       tofield = &field->next;
+      field = nextfield;
+    }
+}
+
+
 /*------------------------------------------------------------------*/
 /* checkSClass - check the storage class specification              */
 /*------------------------------------------------------------------*/
 static void 
 checkSClass (symbol * sym, int isProto)
 {
+  sym_link *t;
+  
   if (getenv("DEBUG_SANITY")) {
     fprintf (stderr, "checkSClass: %s \n", sym->name);
   }
   
-  /* type is literal can happen foe enums change
+  /* type is literal can happen for enums change
      to auto */
   if (SPEC_SCLS (sym->etype) == S_LITERAL && !SPEC_ENUM (sym->etype))
     SPEC_SCLS (sym->etype) = S_AUTO;
   
-  /* if sfr or sbit then must also be */
-  /* volatile the initial value will be xlated */
-  /* to an absolute address */
+  /* if sfr or sbit then must also be volatile */
   if (SPEC_SCLS (sym->etype) == S_SBIT ||
       SPEC_SCLS (sym->etype) == S_SFR)
     {
       SPEC_VOLATILE (sym->etype) = 1;
-      /* if initial value given */
-      if (sym->ival)
-       {
-         SPEC_ABSA (sym->etype) = 1;
-         SPEC_ADDR (sym->etype) =
-           (int) list2int (sym->ival);
-         sym->ival = NULL;
-       }
     }
   
   /* if absolute address given then it mark it as
-     volatile */
-  if (IS_ABSOLUTE (sym->etype))
-    SPEC_VOLATILE (sym->etype) = 1;
+     volatile -- except in the PIC port */
+
+#if !OPT_DISABLE_PIC || !OPT_DISABLE_PIC16
+  /* The PIC port uses a different peep hole optimizer based on "pCode" */
+  if (!TARGET_IS_PIC && !TARGET_IS_PIC16)
+#endif
+
+    if (IS_ABSOLUTE (sym->etype))
+      SPEC_VOLATILE (sym->etype) = 1;
   
+  /* If code memory is read only, then pointers to code memory */
+  /* implicitly point to constants -- make this explicit       */
+  t = sym->type;
+  while (t && t->next) {
+    if (IS_CODEPTR(t) && port->mem.code_ro) {
+      if (IS_SPEC(t->next)) {
+        SPEC_CONST (t->next) = 1;
+      } else {
+        DCL_PTR_CONST (t->next) = 1;
+      }
+    }
+    t = t->next;
+  }
+
   /* global variables declared const put into code */
+  /* if no other storage class specified */
   if (sym->level == 0 &&
-      SPEC_CONST (sym->etype)) {
-    SPEC_SCLS (sym->etype) = S_CODE;
+      SPEC_SCLS(sym->etype) == S_FIXED &&
+      !IS_FUNC(sym->type)) {
+    /* find the first non-array link */
+    t = sym->type;
+    while (IS_ARRAY(t))
+      t = t->next;
+    if (IS_CONSTANT (t)) {
+      SPEC_SCLS (sym->etype) = S_CODE;
+    }
   }
-  
+
   /* global variable in code space is a constant */
   if (sym->level == 0 &&
       SPEC_SCLS (sym->etype) == S_CODE &&
-      port->mem.code_ro)
-    SPEC_CONST (sym->etype) = 1;
-  
+      port->mem.code_ro) {
+    /* find the first non-array link */
+    t = sym->type;
+    while (IS_ARRAY(t))
+      t = t->next;
+    if (IS_SPEC(t)) {
+      SPEC_CONST (t) = 1;
+    } else {
+      DCL_PTR_CONST (t) = 1;
+    }
+  }
 
   /* if bit variable then no storage class can be */
   /* specified since bit is already a storage */
@@ -1201,7 +1402,7 @@ checkSClass (symbol * sym, int isProto)
       sym->ival = NULL;
     }
 
-  /* if this is an atomatic symbol */
+  /* if this is an automatic symbol */
   if (sym->level && (options.stackAuto || reentrant)) {
     if ((SPEC_SCLS (sym->etype) == S_AUTO ||
         SPEC_SCLS (sym->etype) == S_FIXED ||
@@ -1216,7 +1417,7 @@ checkSClass (symbol * sym, int isProto)
       }
     }
   }
-  
+
   /* automatic symbols cannot be given   */
   /* an absolute address ignore it      */
   if (sym->level &&
@@ -1232,6 +1433,7 @@ checkSClass (symbol * sym, int isProto)
   if ((IS_ARRAY (sym->type) || IS_PTR (sym->type)) &&
       (SPEC_NOUN (sym->etype) == V_BIT ||
        SPEC_NOUN (sym->etype) == V_SBIT ||
+       SPEC_NOUN (sym->etype) == V_BITFIELD ||
        SPEC_SCLS (sym->etype) == S_SFR))
     werror (E_BIT_ARRAY, sym->name);
 
@@ -1271,7 +1473,8 @@ checkSClass (symbol * sym, int isProto)
           * control this allcoation, but the code was originally that way, and
           * changing it for non-390 ports breaks the compiler badly.
           */
-         bool useXdata = TARGET_IS_DS390 ? 1 : options.useXstack;
+         bool useXdata = (TARGET_IS_DS390 || TARGET_IS_DS400) ? 
+               1 : options.useXstack;
          SPEC_SCLS (sym->etype) = (useXdata ?
                                    S_XDATA : S_FIXED);
        }
@@ -1293,7 +1496,7 @@ changePointer (symbol * sym)
   for (p = sym->type; p; p = p->next)
     {
       if (!IS_SPEC (p) && DCL_TYPE (p) == UPOINTER)
-       DCL_TYPE (p) = GPOINTER;
+       DCL_TYPE (p) = port->unqualified_pointer;
       if (IS_PTR (p) && IS_FUNC (p->next))
        DCL_TYPE (p) = CPOINTER;
     }
@@ -1326,11 +1529,11 @@ copyLinkChain (sym_link * p)
   sym_link *head, *curr, *loop;
 
   curr = p;
-  head = loop = (curr ? newLink () : (void *) NULL);
+  head = loop = (curr ? newLink (p->class) : (void *) NULL);
   while (curr)
     {
       memcpy (loop, curr, sizeof (sym_link));  /* copy it */
-      loop->next = (curr->next ? newLink () : (void *) NULL);
+      loop->next = (curr->next ? newLink (curr->next->class) : (void *) NULL);
       loop = loop->next;
       curr = curr->next;
     }
@@ -1385,16 +1588,86 @@ cleanUpLevel (bucket ** table, int level)
     }
 }
 
+/*------------------------------------------------------------------*/
+/* computeTypeOr - computes the resultant type from two types       */
+/*------------------------------------------------------------------*/
+static sym_link *
+computeTypeOr (sym_link * etype1, sym_link * etype2, sym_link * reType)
+{
+  /* sanity check */
+  assert (IS_CHAR (etype1) && IS_CHAR (etype2));
+
+  if (SPEC_USIGN (etype1) == SPEC_USIGN (etype2))
+    {
+      SPEC_USIGN (reType) = SPEC_USIGN (etype1);
+      return reType;
+    }
+  
+  if (SPEC_USIGN (etype1))
+    {
+      if (   IS_LITERAL (etype2)
+         && floatFromVal (valFromType (etype2)) >= 0)
+       SPEC_USIGN (reType) = 1;
+      else
+       {
+         /* promote to int */
+         SPEC_USIGN (reType) = 0;
+         SPEC_NOUN (reType) = V_INT;
+       }
+    }
+  else /* etype1 signed */
+    {
+      if (   IS_LITERAL (etype2)
+         && floatFromVal (valFromType (etype2)) <= 127)
+       SPEC_USIGN (reType) = 0;
+      else
+       {
+         /* promote to int */
+         SPEC_USIGN (reType) = 0;
+         SPEC_NOUN (reType) = V_INT;
+       }
+    }
+
+  if (SPEC_USIGN (etype2))
+    {
+      if (   IS_LITERAL (etype1)
+         && floatFromVal (valFromType (etype1)) >= 0)
+       SPEC_USIGN (reType) = 1;
+      else
+       {
+         /* promote to int */
+         SPEC_USIGN (reType) = 0;
+         SPEC_NOUN (reType) = V_INT;
+       }
+    }
+  else /* etype2 signed */
+    {
+      if (   IS_LITERAL (etype1)
+         && floatFromVal (valFromType (etype1)) <= 127)
+       SPEC_USIGN (reType) = 0;
+      else
+       {
+         /* promote to int */
+         SPEC_USIGN (reType) = 0;
+         SPEC_NOUN (reType) = V_INT;
+       }
+    }
+  return reType;
+}
+
 /*------------------------------------------------------------------*/
 /* computeType - computes the resultant type from two types         */
 /*------------------------------------------------------------------*/
 sym_link *
-computeType (sym_link * type1, sym_link * type2)
+computeType (sym_link * type1, sym_link * type2,
+             RESULT_TYPE resultType, char op)
 {
   sym_link *rType;
   sym_link *reType;
   sym_link *etype1 = getSpec (type1);
-  sym_link *etype2 = getSpec (type2);
+  sym_link *etype2;
+
+  etype2 = type2 ? getSpec (type2) : type1;
 
   /* if one of them is a float then result is a float */
   /* here we assume that the types passed are okay */
@@ -1403,18 +1676,34 @@ computeType (sym_link * type1, sym_link * type2)
   if (IS_FLOAT (etype1) || IS_FLOAT (etype2))
     rType = newFloatLink ();
   else
+    /* if both are bitvars choose the larger one */
+  if (IS_BITVAR (etype1) && IS_BITVAR (etype2))
+    {
+      rType = SPEC_BLEN (etype1) >= SPEC_BLEN (etype2) ?
+               copyLinkChain (type1) : copyLinkChain (type1);
+    }
     /* if only one of them is a bit variable
        then the other one prevails */
-  if (IS_BITVAR (etype1) && !IS_BITVAR (etype2))
-    rType = copyLinkChain (type2);
+  else if (IS_BITVAR (etype1) && !IS_BITVAR (etype2))
+    {
+      rType = copyLinkChain (type2);
+      /* bitfield can have up to 16 bits */
+      if (getSize (etype1) > 1)
+        SPEC_NOUN (getSpec (rType)) = V_INT;
+    }
   else if (IS_BITVAR (etype2) && !IS_BITVAR (etype1))
-    rType = copyLinkChain (type1);
+    {
+      rType = copyLinkChain (type1);
+      /* bitfield can have up to 16 bits */
+      if (getSize (etype2) > 1)
+        SPEC_NOUN (getSpec (rType)) = V_INT;
+    }
   else
-    /* if one of them is a pointer then that
+    /* if one of them is a pointer or array then that
        prevails */
-  if (IS_PTR (type1))
+  if (IS_PTR (type1) || IS_ARRAY (type1))
     rType = copyLinkChain (type1);
-  else if (IS_PTR (type2))
+  else if (IS_PTR (type2) || IS_ARRAY (type2))
     rType = copyLinkChain (type2);
   else if (getSize (type1) > getSize (type2))
     rType = copyLinkChain (type1);
@@ -1423,25 +1712,128 @@ computeType (sym_link * type1, sym_link * type2)
 
   reType = getSpec (rType);
 
-  /* if either of them unsigned but not val then make this unsigned */
-  if (((!IS_LITERAL(type1) && SPEC_USIGN (etype1)) || 
-       (!IS_LITERAL(type2) && SPEC_USIGN (etype2))) && 
-      !IS_FLOAT (reType))
-    SPEC_USIGN (reType) = 1;
-  else
-    SPEC_USIGN (reType) = 0;
-  
+  /* avoid conflicting types */
+  reType->select.s._signed = 0;
+
   /* if result is a literal then make not so */
   if (IS_LITERAL (reType))
     SPEC_SCLS (reType) = S_REGISTER;
 
+  switch (resultType)
+    {
+      case RESULT_TYPE_CHAR:
+       if (IS_BITVAR (reType))
+         {
+           SPEC_NOUN (reType) = V_CHAR;
+           SPEC_SCLS (reType) = 0;
+           SPEC_USIGN (reType) = 0;
+           return rType;
+         }
+       break;
+      case RESULT_TYPE_INT:
+      case RESULT_TYPE_NONE:
+       if (IS_BIT (reType))
+         {
+           SPEC_NOUN (reType) = V_CHAR;
+           SPEC_SCLS (reType) = 0;
+           SPEC_USIGN (reType) = 0;
+           return rType;
+         }
+       else if (IS_BITFIELD (reType))
+         {
+           /* could be smarter, but it depends on the op */
+           /* this is for the worst case: a multiplication of 4 * 4 bit */
+           SPEC_NOUN (reType) = SPEC_BLEN (reType) <= 4 ? V_CHAR : V_INT;
+           SPEC_SCLS (reType) = 0;
+           SPEC_USIGN (reType) = 0;
+           return rType;
+         }
+       else if (IS_CHAR (reType))
+         {
+           if (op == '|' || op == '^')
+             return computeTypeOr (etype1, etype2, reType);
+           else if (   op == '&'
+                    && SPEC_USIGN (etype1) != SPEC_USIGN (etype2))
+             {
+               SPEC_USIGN (reType) = 1;
+               return rType;
+             }
+           else
+             {
+               SPEC_NOUN (reType) = V_INT;
+               SPEC_USIGN (reType) = 0;
+               return rType;
+             }
+         }
+       break;
+      default:
+       break;
+    }
+
+  /* SDCC's sign promotion:
+     - if one or both operands are unsigned, the resultant type will be unsigned
+       (except char, see below)
+     - if an operand is promoted to a larger type (char -> int, int -> long),
+       the larger type will be signed
+
+     SDCC tries hard to avoid promotion to int and does 8 bit calculation as
+     much as possible. We're leaving ISO IEC 9899 here and have to extrapolate
+     the standard. The standard demands, that the result has to be the same
+     "as if" the promotion would have been performed:
+
+     - if the result of an operation with two char's is promoted to a
+       larger type, the result will be signed.
+
+     More sophisticated are these:
+     - if the result of an operation with two char's is a char again,
+       the result will only then be unsigned, if both operands are
+       unsigned. In all other cases the result will be signed.
+
+       This seems to be contradictionary to the first two rules, but it makes
+       real sense (all types are char's):
+
+       A signed char can be negative; this must be preserved in the result
+               -1 * 100 = -100;
+
+       Only if both operands are unsigned it's safe to make the result
+       unsigned; this helps to avoid overflow:
+               2 * 100 =  200;
+
+     - ToDo: document '|', '^' and '&'
+     
+     Homework: - why is (200 * 200 < 0) true?
+              - why is { char l = 200, r = 200; (r * l > 0) } true?
+  */
+
+  if (!IS_FLOAT (reType)
+      && (   (SPEC_USIGN (etype1)
+              /* if this operand is promoted to a larger type,
+                then it will be promoted to a signed type */
+             && !(getSize (etype1) < getSize (reType))
+              /* char require special handling */
+             && !IS_CHAR (etype1))
+         || /* same for 2nd operand */  
+            (SPEC_USIGN (etype2)
+             && !(getSize (etype2) < getSize (reType))
+             && !IS_CHAR (etype2))
+         || /* if both are 'unsigned char' and not promoted
+               let the result be unsigned too */
+            (   SPEC_USIGN (etype1)
+             && SPEC_USIGN (etype2)
+             && IS_CHAR (etype1)
+             && IS_CHAR (etype2)
+             && IS_CHAR (reType))))
+    SPEC_USIGN (reType) = 1;
+  else
+    SPEC_USIGN (reType) = 0;
+
   return rType;
 }
 
 /*--------------------------------------------------------------------*/
 /* compareType - will do type check return 1 if match, -1 if castable */
 /*--------------------------------------------------------------------*/
-int 
+int
 compareType (sym_link * dest, sym_link * src)
 {
   if (!dest && !src)
@@ -1464,6 +1856,9 @@ compareType (sym_link * dest, sym_link * src)
            }
            return compareType (dest->next, src->next);
          }
+         if (IS_PTR (dest) && IS_GENPTR (src) && IS_VOID(src->next)) {
+           return 1;
+         }
          if (IS_PTR (src) && IS_GENPTR (dest))
            return -1;
          if (IS_PTR (dest) && IS_ARRAY (src)) {
@@ -1471,7 +1866,6 @@ compareType (sym_link * dest, sym_link * src)
            int res=compareType (dest, val->type);
            Safe_free(val->type);
            Safe_free(val);
-           //return res ? -1 : 0;
            return res;
          }
          if (IS_PTR (dest) && IS_FUNC (dest->next) && IS_FUNC (src))
@@ -1533,20 +1927,200 @@ compareType (sym_link * dest, sym_link * src)
   return 1;
 }
 
+/*--------------------------------------------------------------------*/
+/* compareTypeExact - will do type check return 1 if match exactly    */
+/*--------------------------------------------------------------------*/
+int
+compareTypeExact (sym_link * dest, sym_link * src, int level)
+{
+  STORAGE_CLASS srcScls, destScls;
+  
+  if (!dest && !src)
+    return 1;
+
+  if (dest && !src)
+    return 0;
+
+  if (src && !dest)
+    return 0;
+
+  /* if dest is a declarator then */
+  if (IS_DECL (dest))
+    {
+      if (IS_DECL (src))
+       {
+         if (DCL_TYPE (src) == DCL_TYPE (dest)) {
+           if ((DCL_TYPE (src) == ARRAY) && (DCL_ELEM (src) != DCL_ELEM (dest)))
+             return 0;
+           if (DCL_PTR_CONST (src) != DCL_PTR_CONST (dest))
+             return 0;
+           if (DCL_PTR_VOLATILE (src) != DCL_PTR_VOLATILE (dest))
+             return 0;
+           if (IS_FUNC(src))
+              {
+               value *exargs, *acargs, *checkValue;
+
+                /* verify function return type */
+               if (!compareTypeExact (dest->next, src->next, -1))
+                 return 0;
+               if (FUNC_ISISR (dest) != FUNC_ISISR (src))
+                 return 0;
+               if (FUNC_REGBANK (dest) != FUNC_REGBANK (src))
+                 return 0;
+               if (IFFUNC_ISNAKED (dest) != IFFUNC_ISNAKED (src))
+                 return 0;
+               #if 0
+                if (IFFUNC_ISREENT (dest) != IFFUNC_ISREENT (src) && argCnt>1)
+                 return 0;
+                #endif
+
+               /* compare expected args with actual args */
+               exargs = FUNC_ARGS(dest);
+               acargs = FUNC_ARGS(src);
+
+               /* for all the expected args do */
+               for (; exargs && acargs; exargs = exargs->next, acargs = acargs->next)
+                 {
+                   //checkTypeSanity(acargs->etype, acargs->name);
+
+                   if (IS_AGGREGATE (acargs->type))
+                     {
+                       checkValue = copyValue (acargs);
+                       aggregateToPointer (checkValue);
+                     }
+                   else
+                     checkValue = acargs;
+
+                    #if 0
+                   if (!compareTypeExact (exargs->type, checkValue->type, -1))
+                      return 0;
+                    #endif
+                 }
+
+                 /* if one them ended we have a problem */
+                 if ((exargs && !acargs && !IS_VOID (exargs->type)) ||
+                     (!exargs && acargs && !IS_VOID (acargs->type)))
+                   return 0;                  
+                  return 1;
+              }
+           return compareTypeExact (dest->next, src->next, level);
+         }
+          return 0;
+       }
+      return 0;
+    }
+
+  /* if one is a specifier and the other is not */
+  if ((IS_SPEC (src) && !IS_SPEC (dest)) ||
+      (IS_SPEC (dest) && !IS_SPEC (src)))
+    return 0;
+
+  /* if one of them is a void then ok */
+  if (SPEC_NOUN (dest) != SPEC_NOUN (src))
+    return 0;
+
+  /* if they are both bitfields then if the lengths
+     and starts don't match */
+  if (IS_BITFIELD (dest) && IS_BITFIELD (src) &&
+      (SPEC_BLEN (dest) != SPEC_BLEN (src) ||
+       SPEC_BSTR (dest) != SPEC_BSTR (src)))
+    return 0;
+
+  if (IS_INTEGRAL (dest))
+    {
+      /* signedness must match */
+      if (SPEC_USIGN (dest) != SPEC_USIGN (src))
+       return 0;
+      /* size must match */
+      if (SPEC_LONG (dest) != SPEC_LONG (src))
+       return 0;
+      if (SPEC_SHORT (dest) != SPEC_SHORT (src))
+       return 0;
+    }
+  
+  if (IS_STRUCT (dest))
+    {
+      if (SPEC_STRUCT (dest) != SPEC_STRUCT (src))
+       return 0;
+    }
+
+  if (SPEC_CONST (dest) != SPEC_CONST (src))
+    return 0;
+  if (SPEC_VOLATILE (dest) != SPEC_VOLATILE (src))
+    return 0;
+  if (SPEC_STAT (dest) != SPEC_STAT (src))
+    return 0;
+  if (SPEC_ABSA (dest) != SPEC_ABSA (src))
+    return 0;
+  if (SPEC_ABSA (dest) && SPEC_ADDR (dest) != SPEC_ADDR (src))
+    return 0;
+      
+  destScls = SPEC_SCLS (dest);
+  srcScls = SPEC_SCLS (src);
+  
+  /* Compensate for const to const code change in checkSClass() */
+  if (!level & port->mem.code_ro && SPEC_CONST (dest))
+    {
+      if (srcScls == S_CODE && destScls == S_FIXED)
+       destScls = S_CODE;
+      if (destScls == S_CODE && srcScls == S_FIXED)
+       srcScls = S_CODE;
+    }
+
+  /* compensate for allocGlobal() */  
+  if ((srcScls == S_FIXED || srcScls == S_AUTO)
+      && port->mem.default_globl_map == xdata
+      && !level)
+    srcScls = S_XDATA;
+  
+  if (level>0 && !SPEC_STAT (dest))
+    {
+      /* Compensate for hack-o-matic in checkSClass() */
+      if (options.stackAuto || (currFunc && IFFUNC_ISREENT (currFunc->type)))
+       {
+         if (destScls == S_FIXED)
+           destScls = (options.useXstack ? S_XSTACK : S_STACK);
+         if (srcScls == S_FIXED)
+           srcScls = (options.useXstack ? S_XSTACK : S_STACK);
+       }
+      else if (TARGET_IS_DS390 || TARGET_IS_DS400 || options.useXstack)
+       {
+         if (destScls == S_FIXED)
+           destScls = S_XDATA;
+         if (srcScls == S_FIXED)
+           srcScls = S_XDATA;
+       }
+    }
+
+  if (srcScls != destScls)
+    {
+      #if 0
+      printf ("level = %d\n", level);
+      printf ("SPEC_SCLS (src) = %d, SPEC_SCLS (dest) = %d\n",
+               SPEC_SCLS (src), SPEC_SCLS (dest));
+      printf ("srcScls = %d, destScls = %d\n",srcScls, destScls);
+      #endif
+      return 0;
+    }
+  
+  return 1;
+}
+
 /*------------------------------------------------------------------*/
 /* inCalleeSaveList - return 1 if found in callee save list          */
 /*------------------------------------------------------------------*/
-bool 
-inCalleeSaveList (char *s)
+static int
+calleeCmp(void *p1, void *p2)
 {
-  int i;
-
-  if (options.all_callee_saves) return 1;
-  for (i = 0; options.calleeSaves[i]; i++)
-    if (strcmp (options.calleeSaves[i], s) == 0)
-      return 1;
+  return (strcmp((char *)p1, (char *)(p2)) == 0);
+}
 
-  return 0;
+bool
+inCalleeSaveList(char *s)
+{
+  if (options.all_callee_saves)
+    return 1;
+  return isinSetWith(options.calleeSavesSet, s, calleeCmp);
 }
 
 /*-----------------------------------------------------------------*/
@@ -1566,7 +2140,7 @@ aggregateToPointer (value * val)
          sym_link *p = val->type;
 
          werror (W_STRUCT_AS_ARG, val->name);
-         val->type = newLink ();
+         val->type = newLink (DECLARATOR);
          val->type->next = p;
        }
 
@@ -1584,23 +2158,8 @@ aggregateToPointer (value * val)
          if (SPEC_OCLS(val->etype)) {
            DCL_TYPE(val->type)=PTR_TYPE(SPEC_OCLS(val->etype));
          } else {
-#if 1
            // this happens for (external) function parameters
-           DCL_TYPE (val->type) = GPOINTER;
-#else
-           if (TARGET_IS_DS390) {
-             /* The AUTO and REGISTER classes should probably
-              * also become generic pointers, but I haven't yet
-              * devised a test case for that.
-              */
-             DCL_TYPE (val->type) = GPOINTER;
-             break;
-           }
-           if (options.model==MODEL_LARGE) {
-             DCL_TYPE (val->type) = FPOINTER;
-             break;
-           }
-#endif
+           DCL_TYPE (val->type) = port->unqualified_pointer;
          }
          break;
        case S_AUTO:
@@ -1618,7 +2177,7 @@ aggregateToPointer (value * val)
          DCL_TYPE (val->type) = EEPPOINTER;
          break;
        default:
-         DCL_TYPE (val->type) = GPOINTER;
+         DCL_TYPE (val->type) = port->unqualified_pointer;
        }
       
       /* is there is a symbol associated then */
@@ -1645,6 +2204,12 @@ checkFunction (symbol * sym, symbol *csym)
     fprintf (stderr, "checkFunction: %s ", sym->name);
   }
 
+  if (!IS_DECL(sym->type) || DCL_TYPE(sym->type)!=FUNCTION)
+    {
+      werror(E_SYNTAX_ERROR, sym->name);
+      return 0;
+    }
+    
   /* make sure the type is complete and sane */
   checkTypeSanity(((symbol *)sym)->etype, ((symbol *)sym)->name);
 
@@ -1672,7 +2237,7 @@ checkFunction (symbol * sym, symbol *csym)
 
   /* check if this function is defined as calleeSaves
      then mark it as such */
-    FUNC_CALLEESAVES(sym->type) = inCalleeSaveList (sym->name);
+  FUNC_CALLEESAVES(sym->type) = inCalleeSaveList (sym->name);
 
   /* if interrupt service routine  */
   /* then it cannot have arguments */
@@ -1684,6 +2249,27 @@ checkFunction (symbol * sym, symbol *csym)
       }
     }
 
+  for (argCnt=1, acargs = FUNC_ARGS(sym->type); 
+       acargs; 
+       acargs=acargs->next, argCnt++) {
+    if (!acargs->sym) { 
+      // this can happen for reentrant functions
+      werror(E_PARAM_NAME_OMITTED, sym->name, argCnt);
+      // the show must go on: synthesize a name and symbol
+      SNPRINTF (acargs->name, sizeof(acargs->name), "_%s_PARM_%d", sym->name, argCnt);
+      acargs->sym = newSymbol (acargs->name, 1);
+      SPEC_OCLS (acargs->etype) = istack;
+      acargs->sym->type = copyLinkChain (acargs->type);
+      acargs->sym->etype = getSpec (acargs->sym->type);
+      acargs->sym->_isparm = 1;
+      strncpyz (acargs->sym->rname, acargs->name, sizeof(acargs->sym->rname));
+    } else if (strcmp(acargs->sym->name, acargs->sym->rname)==0) { 
+      // synthesized name
+      werror(E_PARAM_NAME_OMITTED, sym->name, argCnt);
+    }
+  }
+  argCnt--;
+
   if (!csym && !(csym = findSym (SymbolTab, sym, sym->name)))
     return 1;                  /* not defined nothing more to check  */
 
@@ -1716,6 +2302,17 @@ checkFunction (symbol * sym, symbol *csym)
     {
       werror (E_PREV_DEF_CONFLICT, csym->name, "_naked");
     }
+  
+  /* Really, reentrant should match regardless of argCnt, but     */
+  /* this breaks some existing code (the fp lib functions). If    */
+  /* the first argument is always passed the same way, this       */
+  /* lax checking is ok (but may not be true for in future ports) */
+  if (IFFUNC_ISREENT (csym->type) != IFFUNC_ISREENT (sym->type)
+      && argCnt>1)
+    {
+      //printf("argCnt = %d\n",argCnt);
+      werror (E_PREV_DEF_CONFLICT, csym->name, "reentrant");
+    }
 
   /* compare expected args with actual args */
   exargs = FUNC_ARGS(csym->type);
@@ -1762,6 +2359,7 @@ checkFunction (symbol * sym, symbol *csym)
   /* replace with this defition */
   sym->cdef = csym->cdef;
   deleteSym (SymbolTab, csym, csym->name);
+  deleteFromSeg(csym);
   addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
   if (IS_EXTERN (csym->etype) && !
       IS_EXTERN (sym->etype))
@@ -1771,6 +2369,29 @@ checkFunction (symbol * sym, symbol *csym)
   return 1;
 }
 
+/*------------------------------------------------------------------*/
+/* cdbStructBlock - calls struct printing for a blcks               */
+/*------------------------------------------------------------------*/
+void cdbStructBlock (int block)
+{
+  int i;
+  bucket **table = StructTab;
+  bucket *chain;
+
+  /* go thru the entire  table  */
+  for (i = 0; i < 256; i++)
+    {
+      for (chain = table[i]; chain; chain = chain->next)
+       {
+         if (chain->block >= block)
+           {
+             if(debugFile)
+               debugFile->writeType((structdef *)chain->sym, chain->block, 0, NULL);
+           }
+       }
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* processFuncArgs - does some processing with function args       */
 /*-----------------------------------------------------------------*/
@@ -1784,14 +2405,13 @@ processFuncArgs (symbol * func)
   if (getenv("SDCC_DEBUG_FUNCTION_POINTERS"))
     fprintf (stderr, "SDCCsymt.c:processFuncArgs(%s)\n", func->name);
 
-  // if this is a pointer to a function
-  if (IS_PTR(funcType)) {
+  /* find the function declaration within the type */
+  while (funcType && !IS_FUNC(funcType))
     funcType=funcType->next;
-  }
 
   /* if this function has variable argument list */
   /* then make the function a reentrant one    */
-  if (IFFUNC_HASVARARGS(funcType))
+  if (IFFUNC_HASVARARGS(funcType) || (options.stackAuto && !func->cdef))
     FUNC_ISREENT(funcType)=1;
 
   /* check if this function is defined as calleeSaves
@@ -1814,13 +2434,17 @@ processFuncArgs (symbol * func)
   /* change it to pointer to the same type */
   while (val)
     {
+       int argreg = 0;
       /* mark it as a register parameter if
          the function does not have VA_ARG
          and as port dictates */
       if (!IFFUNC_HASVARARGS(funcType) &&
-         (*port->reg_parm) (val->type))
+         (argreg = (*port->reg_parm) (val->type)))
        {
          SPEC_REGPARM (val->etype) = 1;
+         SPEC_ARGREG(val->etype) = argreg;
+       } else if (IFFUNC_ISREENT(funcType)) {
+           FUNC_HASSTACKPARM(funcType) = 1;
        }
 
       if (IS_AGGREGATE (val->type))
@@ -1855,30 +2479,45 @@ processFuncArgs (symbol * func)
       /* synthesize a variable name */
       if (!val->sym)
        {
-
-         sprintf (val->name, "_%s_PARM_%d", func->name, pNum++);
+         SNPRINTF (val->name, sizeof(val->name), 
+                   "_%s_PARM_%d", func->name, pNum++);
          val->sym = newSymbol (val->name, 1);
          SPEC_OCLS (val->etype) = port->mem.default_local_map;
          val->sym->type = copyLinkChain (val->type);
          val->sym->etype = getSpec (val->sym->type);
          val->sym->_isparm = 1;
-         strcpy (val->sym->rname, val->name);
-         SPEC_STAT (val->etype) = SPEC_STAT (val->sym->etype) =
-           SPEC_STAT (func->etype);
+         strncpyz (val->sym->rname, val->name, sizeof(val->sym->rname));
+         #if 0
+         /* ?? static functions shouldn't imply static parameters - EEP */
+         if (IS_SPEC(func->etype)) {
+           SPEC_STAT (val->etype) = SPEC_STAT (val->sym->etype) =
+             SPEC_STAT (func->etype);
+         }
+         #endif
          addSymChain (val->sym);
 
        }
       else                     /* symbol name given create synth name */
        {
 
-         sprintf (val->name, "_%s_PARM_%d", func->name, pNum++);
-         strcpy (val->sym->rname, val->name);
+         SNPRINTF (val->name, sizeof(val->name), "_%s_PARM_%d", func->name, pNum++);
+         strncpyz (val->sym->rname, val->name, sizeof(val->sym->rname));
          val->sym->_isparm = 1;
          SPEC_OCLS (val->etype) = SPEC_OCLS (val->sym->etype) =
            (options.model != MODEL_SMALL ? xdata : data);
-         SPEC_STAT (val->etype) = SPEC_STAT (val->sym->etype) =
-           SPEC_STAT (func->etype);
+         
+         #if 0
+         /* ?? static functions shouldn't imply static parameters - EEP */
+         if (IS_SPEC(func->etype)) {
+           SPEC_STAT (val->etype) = SPEC_STAT (val->sym->etype) =
+             SPEC_STAT (func->etype);
+         }
+         #endif
        }
+      if (!isinSet(operKeyReset, val->sym)) {
+       addSet (&operKeyReset, val->sym);
+       applyToSet (operKeyReset, resetParmKey);
+      }
       val = val->next;
     }
 }
@@ -1916,7 +2555,9 @@ void
 printTypeChain (sym_link * start, FILE * of)
 {
   int nlr = 0;
+  value *args;
   sym_link * type, * search;
+  STORAGE_CLASS scls;
 
   if (!of)
     {
@@ -1929,99 +2570,110 @@ printTypeChain (sym_link * start, FILE * of)
     return;
   }
 
-  /* print the chain as it is written in the source: */
-  /* start with the last entry                       */
+  /* Print the chain as it is written in the source: */
+  /* start with the last entry.                      */
+  /* However, the storage class at the end of the    */
+  /* chain reall applies to the first in the chain!  */
+
   for (type = start; type && type->next; type = type->next)
     ;
+  if (IS_SPEC (type))
+    scls=SPEC_SCLS(type);
+  else
+    scls=0;
   while (type)
     {
+      if (type==start) {
+       switch (scls) 
+         {
+         case S_DATA: fprintf (of, "data-"); break;
+         case S_XDATA: fprintf (of, "xdata-"); break;
+         case S_SFR: fprintf (of, "sfr-"); break;
+         case S_SBIT: fprintf (of, "sbit-"); break;
+         case S_CODE: fprintf (of, "code-"); break;
+         case S_IDATA: fprintf (of, "idata-"); break;
+         case S_PDATA: fprintf (of, "pdata-"); break;
+         case S_LITERAL: fprintf (of, "literal-"); break;
+         case S_STACK: fprintf (of, "stack-"); break;
+         case S_XSTACK: fprintf (of, "xstack-"); break;
+         case S_BIT: fprintf (of, "bit-"); break;
+         case S_EEPROM: fprintf (of, "eeprom-"); break;
+         default: break;
+         }
+      }
+
       if (IS_DECL (type))
        {
-         if (DCL_PTR_VOLATILE (type)) {
-           fprintf (of, "volatile ");
+         if (!IS_FUNC(type)) {
+           if (DCL_PTR_VOLATILE (type)) {
+             fprintf (of, "volatile-");
+           }
+           if (DCL_PTR_CONST (type)) {
+             fprintf (of, "const-");
+           }
          }
          switch (DCL_TYPE (type))
            {
            case FUNCTION:
-             fprintf (of, "function ");
+             fprintf (of, "function %s %s", 
+                      (IFFUNC_ISBUILTIN(type) ? "__builtin__" : " "),
+                      (IFFUNC_ISJAVANATIVE(type) ? "_JavaNative" : " "));
+             fprintf (of, "( ");
+             for (args = FUNC_ARGS(type); 
+                  args; 
+                  args=args->next) {
+               printTypeChain(args->type, of);
+               if (args->next)
+                 fprintf(of, ", ");
+             }
+             fprintf (of, ") ");
              break;
            case GPOINTER:
-             if (DCL_PTR_CONST (type))
-               fprintf (of, "const ");
-             fprintf (of, "generic * ");
+             fprintf (of, "generic* ");
              break;
            case CPOINTER:
-             if (DCL_PTR_CONST (type))
-               fprintf (of, "const ");
-             fprintf (of, "code * ");
+             fprintf (of, "code* ");
              break;
            case FPOINTER:
-             if (DCL_PTR_CONST (type))
-               fprintf (of, "const ");
-             fprintf (of, "xdata * ");
+             fprintf (of, "xdata* ");
              break;
            case EEPPOINTER:
-             if (DCL_PTR_CONST (type))
-               fprintf (of, "const ");
-             fprintf (of, "eeprom * ");
+             fprintf (of, "eeprom* ");
              break;
-
            case POINTER:
-             if (DCL_PTR_CONST (type))
-               fprintf (of, "const ");
-             fprintf (of, "near *");
+             fprintf (of, "near* ");
              break;
            case IPOINTER:
-             if (DCL_PTR_CONST (type))
-               fprintf (of, "const ");
-             fprintf (of, "idata * ");
+             fprintf (of, "idata* ");
              break;
            case PPOINTER:
-             if (DCL_PTR_CONST (type))
-               fprintf (of, "const ");
-             fprintf (of, "pdata * ");
+             fprintf (of, "pdata* ");
              break;
            case UPOINTER:
-             if (DCL_PTR_CONST (type))
-               fprintf (of, "const ");
-             fprintf (of, "unkown * ");
+             fprintf (of, "unknown* ");
              break;
            case ARRAY:
-             fprintf (of, "[] ");
+             if (DCL_ELEM(type)) {
+               fprintf (of, "[%d] ", DCL_ELEM(type));
+             } else {
+               fprintf (of, "[] ");
+             }
              break;
            }
        }
       else
        {
-         switch (SPEC_SCLS(type)) 
-           {
-           case S_DATA: fprintf (of, "data "); break;
-           case S_XDATA: fprintf (of, "xdata "); break;
-           case S_SFR: fprintf (of, "sfr "); break;
-           case S_SBIT: fprintf (of, "sbit "); break;
-           case S_CODE: fprintf (of, "code "); break;
-           case S_IDATA: fprintf (of, "idata "); break;
-           case S_PDATA: fprintf (of, "pdata "); break;
-           case S_LITERAL: fprintf (of, "literal "); break;
-           case S_STACK: fprintf (of, "stack "); break;
-           case S_XSTACK: fprintf (of, "xstack "); break;
-           case S_BIT: fprintf (of, "bit "); break;
-           case S_EEPROM: fprintf (of, "eeprom "); break;
-           default: break;
-           }
-
          if (SPEC_VOLATILE (type))
-           fprintf (of, "volatile ");
-         if (SPEC_USIGN (type))
-           fprintf (of, "unsigned ");
+           fprintf (of, "volatile-");
          if (SPEC_CONST (type))
-           fprintf (of, "const ");
-
+           fprintf (of, "const-");
+         if (SPEC_USIGN (type))
+           fprintf (of, "unsigned-");
          switch (SPEC_NOUN (type))
            {
            case V_INT:
              if (IS_LONG (type))
-               fprintf (of, "long ");
+               fprintf (of, "long-");
              fprintf (of, "int");
              break;
 
@@ -2046,7 +2698,11 @@ printTypeChain (sym_link * start, FILE * of)
              break;
 
            case V_BIT:
-             fprintf (of, "bit {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
+             fprintf (of, "bit");
+             break;
+
+           case V_BITFIELD:
+             fprintf (of, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
              break;
 
            case V_DOUBLE:
@@ -2058,223 +2714,193 @@ printTypeChain (sym_link * start, FILE * of)
              break;
            }
        }
-       /* search entry in list before "type" */
-    for (search = start; search && search->next != type;)
-       search = search->next;
-    type = search;
-    if (type)
-      fputc (' ', of);
+      /* search entry in list before "type" */
+      for (search = start; search && search->next != type;)
+       search = search->next;
+      type = search;
+      if (type)
+       fputc (' ', of);
     }
   if (nlr)
     fprintf (of, "\n");
 }
 
-/*-----------------------------------------------------------------*/
-/* cdbTypeInfo - print the type information for debugger           */
-/*-----------------------------------------------------------------*/
+/*--------------------------------------------------------------------*/
+/* printTypeChainRaw - prints the type chain in human readable form   */
+/*                     in the raw data structure ordering             */
+/*--------------------------------------------------------------------*/
 void
-cdbTypeInfo (sym_link * type, FILE * of)
+printTypeChainRaw (sym_link * start, FILE * of)
 {
-  fprintf (of, "{%d}", getSize (type));
+  int nlr = 0;
+  value *args;
+  sym_link * type;
+
+  if (!of)
+    {
+      of = stdout;
+      nlr = 1;
+    }
+
+  if (start==NULL) {
+    fprintf (of, "void");
+    return;
+  }
+
+  type = start;
+  
   while (type)
     {
       if (IS_DECL (type))
        {
+         if (!IS_FUNC(type)) {
+           if (DCL_PTR_VOLATILE (type)) {
+             fprintf (of, "volatile-");
+           }
+           if (DCL_PTR_CONST (type)) {
+             fprintf (of, "const-");
+           }
+         }
          switch (DCL_TYPE (type))
            {
            case FUNCTION:
-             fprintf (of, "DF,");
+             fprintf (of, "function %s %s", 
+                      (IFFUNC_ISBUILTIN(type) ? "__builtin__" : " "),
+                      (IFFUNC_ISJAVANATIVE(type) ? "_JavaNative" : " "));
+             fprintf (of, "( ");
+             for (args = FUNC_ARGS(type); 
+                  args; 
+                  args=args->next) {
+               printTypeChain(args->type, of);
+               if (args->next)
+                 fprintf(of, ", ");
+             }
+             fprintf (of, ") ");
              break;
            case GPOINTER:
-             fprintf (of, "DG,");
+             fprintf (of, "generic* ");
              break;
            case CPOINTER:
-             fprintf (of, "DC,");
+             fprintf (of, "code* ");
              break;
            case FPOINTER:
-             fprintf (of, "DX,");
+             fprintf (of, "xdata* ");
+             break;
+           case EEPPOINTER:
+             fprintf (of, "eeprom* ");
              break;
            case POINTER:
-             fprintf (of, "DD,");
+             fprintf (of, "near* ");
              break;
            case IPOINTER:
-             fprintf (of, "DI,");
+             fprintf (of, "idata* ");
              break;
            case PPOINTER:
-             fprintf (of, "DP,");
+             fprintf (of, "pdata* ");
              break;
-           case EEPPOINTER:
-             fprintf (of, "DA,");
+           case UPOINTER:
+             fprintf (of, "unknown* ");
              break;
            case ARRAY:
-             fprintf (of, "DA%d,", DCL_ELEM (type));
-             break;
-           default:
+             if (DCL_ELEM(type)) {
+               fprintf (of, "[%d] ", DCL_ELEM(type));
+             } else {
+               fprintf (of, "[] ");
+             }
              break;
            }
+          if (DCL_TSPEC(type))
+            {
+              fprintf (of, "{");
+              printTypeChainRaw(DCL_TSPEC(type), of);
+              fprintf (of, "}");
+            }
        }
-      else
+      else if (IS_SPEC (type))
        {
+       switch (SPEC_SCLS (type)) 
+         {
+         case S_DATA: fprintf (of, "data-"); break;
+         case S_XDATA: fprintf (of, "xdata-"); break;
+         case S_SFR: fprintf (of, "sfr-"); break;
+         case S_SBIT: fprintf (of, "sbit-"); break;
+         case S_CODE: fprintf (of, "code-"); break;
+         case S_IDATA: fprintf (of, "idata-"); break;
+         case S_PDATA: fprintf (of, "pdata-"); break;
+         case S_LITERAL: fprintf (of, "literal-"); break;
+         case S_STACK: fprintf (of, "stack-"); break;
+         case S_XSTACK: fprintf (of, "xstack-"); break;
+         case S_BIT: fprintf (of, "bit-"); break;
+         case S_EEPROM: fprintf (of, "eeprom-"); break;
+         default: break;
+         }
+         if (SPEC_VOLATILE (type))
+           fprintf (of, "volatile-");
+         if (SPEC_CONST (type))
+           fprintf (of, "const-");
+         if (SPEC_USIGN (type))
+           fprintf (of, "unsigned-");
          switch (SPEC_NOUN (type))
            {
            case V_INT:
              if (IS_LONG (type))
-               fprintf (of, "SL");
-             else
-               fprintf (of, "SI");
+               fprintf (of, "long-");
+             fprintf (of, "int");
              break;
 
            case V_CHAR:
-             fprintf (of, "SC");
+             fprintf (of, "char");
              break;
 
            case V_VOID:
-             fprintf (of, "SV");
+             fprintf (of, "void");
              break;
 
            case V_FLOAT:
-             fprintf (of, "SF");
+             fprintf (of, "float");
              break;
 
            case V_STRUCT:
-             fprintf (of, "ST%s", SPEC_STRUCT (type)->tag);
+             fprintf (of, "struct %s", SPEC_STRUCT (type)->tag);
              break;
 
            case V_SBIT:
-             fprintf (of, "SX");
+             fprintf (of, "sbit");
              break;
 
            case V_BIT:
-             fprintf (of, "SB%d$%d", SPEC_BSTR (type), SPEC_BLEN (type));
+             fprintf (of, "bit");
              break;
 
-           default:
+           case V_BITFIELD:
+             fprintf (of, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
              break;
-           }
-         fputs (":", of);
-         if (SPEC_USIGN (type))
-           fputs ("U", of);
-         else
-           fputs ("S", of);
-       }
-      type = type->next;
-    }
-}
-/*-----------------------------------------------------------------*/
-/* cdbSymbol - prints a symbol & its type information for debugger */
-/*-----------------------------------------------------------------*/
-void 
-cdbSymbol (symbol * sym, FILE * of, int isStructSym, int isFunc)
-{
-  memmap *map;
 
-  if (!sym)
-    return;
-  if (!of)
-    of = stdout;
+           case V_DOUBLE:
+             fprintf (of, "double");
+             break;
 
-  if (isFunc)
-    fprintf (of, "F:");
-  else
-    fprintf (of, "S:");                /* symbol record */
-  /* if this is not a structure symbol then
-     we need to figure out the scope information */
-  if (!isStructSym)
-    {
-      if (!sym->level)
-       {
-         /* global */
-         if (IS_STATIC (sym->etype))
-           fprintf (of, "F%s$", moduleName);   /* scope is file */
-         else
-           fprintf (of, "G$"); /* scope is global */
+           default:
+             fprintf (of, "unknown type");
+             break;
+           }
        }
       else
-       /* symbol is local */
-       fprintf (of, "L%s$", (sym->localof ? sym->localof->name : "-null-"));
-    }
-  else
-    fprintf (of, "S$");                /* scope is structure */
-
-  /* print the name, & mangled name */
-  fprintf (of, "%s$%d$%d(", sym->name,
-          sym->level, sym->block);
-
-  cdbTypeInfo (sym->type, of);
-  fprintf (of, "),");
-
-  /* print the address space */
-  map = SPEC_OCLS (sym->etype);
-  fprintf (of, "%c,%d,%d",
-          (map ? map->dbName : 'Z'), sym->onStack, SPEC_STAK (sym->etype));
-
-  /* if assigned to registers then output register names */
-  /* if this is a function then print
-     if is it an interrupt routine & interrupt number
-     and the register bank it is using */
-  if (isFunc)
-    fprintf (of, ",%d,%d,%d", FUNC_ISISR (sym->type),
-            FUNC_INTNO (sym->type), FUNC_REGBANK (sym->type));
-  /* alternate location to find this symbol @ : eg registers
-     or spillication */
-
-  if (!isStructSym)
-    fprintf (of, "\n");
-}
-
-/*-----------------------------------------------------------------*/
-/* cdbStruct - print a structure for debugger                      */
-/*-----------------------------------------------------------------*/
-void 
-cdbStruct (structdef * sdef, int block, FILE * of,
-          int inStruct, char *tag)
-{
-  symbol *sym;
-
-  fprintf (of, "T:");
-  /* if block # then must have function scope */
-  fprintf (of, "F%s$", moduleName);
-  fprintf (of, "%s[", (tag ? tag : sdef->tag));
-  for (sym = sdef->fields; sym; sym = sym->next)
-    {
-      fprintf (of, "({%d}", sym->offset);
-      cdbSymbol (sym, of, TRUE, FALSE);
-      fprintf (of, ")");
+        fprintf (of, "NOT_SPEC_OR_DECL");
+      type = type->next;
+      if (type)
+       fputc (' ', of);
     }
-  fprintf (of, "]");
-  if (!inStruct)
+  if (nlr)
     fprintf (of, "\n");
 }
 
-/*------------------------------------------------------------------*/
-/* cdbStructBlock - calls struct printing for a blcks               */
-/*------------------------------------------------------------------*/
-void 
-cdbStructBlock (int block, FILE * of)
-{
-  int i;
-  bucket **table = StructTab;
-  bucket *chain;
-  wassert (of);
-
-  /* go thru the entire  table  */
-  for (i = 0; i < 256; i++)
-    {
-      for (chain = table[i]; chain; chain = chain->next)
-       {
-         if (chain->block >= block)
-           {
-             cdbStruct ((structdef *) chain->sym, chain->block, of, 0, NULL);
-           }
-       }
-    }
-}
 
 /*-----------------------------------------------------------------*/
 /* powof2 - returns power of two for the number if number is pow 2 */
 /*-----------------------------------------------------------------*/
-int 
-powof2 (unsigned long num)
+int
+powof2 (TYPE_UDWORD num)
 {
   int nshifts = 0;
   int n1s = 0;
@@ -2317,7 +2943,7 @@ sym_link *floatType;
 static char *
 _mangleFunctionName(char *in)
 {
-  if (port->getMangledFunctionName) 
+  if (port->getMangledFunctionName)
     {
       return port->getMangledFunctionName(in);
     }
@@ -2327,6 +2953,109 @@ _mangleFunctionName(char *in)
     }
 }
 
+/*-----------------------------------------------------------------*/
+/* typeFromStr - create a typechain from an encoded string         */
+/* basic types -       'c' - char                                 */
+/*                     's' - short                                */
+/*                     'i' - int                                  */
+/*                     'l' - long                                 */
+/*                      'f' - float                               */
+/*                      'v' - void                                */
+/*                      '*' - pointer - default (GPOINTER)        */
+/* modifiers -          'u' - unsigned                             */
+/* pointer modifiers -  'g' - generic                              */
+/*                      'x' - xdata                                */
+/*                      'p' - code                                 */
+/*                      'd' - data                                 */                     
+/*                      'F' - function                             */                     
+/* examples : "ig*" - generic int *                               */
+/*            "cx*" - char xdata *                                 */
+/*            "ui" -  unsigned int                                 */
+/*-----------------------------------------------------------------*/
+sym_link *typeFromStr (char *s)
+{
+    sym_link *r = newLink(DECLARATOR);
+    int usign = 0;
+
+    do {
+       sym_link *nr;
+       switch (*s) {
+       case 'u' : 
+           usign = 1;
+           s++;
+           continue ;
+           break ;
+       case 'c':
+           r->class = SPECIFIER;
+           SPEC_NOUN(r) = V_CHAR;
+           break;
+       case 's':
+       case 'i':
+           r->class = SPECIFIER;
+           SPEC_NOUN(r) = V_INT;
+           break;
+       case 'l':
+           r->class = SPECIFIER;
+           SPEC_NOUN(r) = V_INT;
+           SPEC_LONG(r) = 1;
+           break;
+       case 'f':
+           r->class = SPECIFIER;
+           SPEC_NOUN(r) = V_FLOAT;
+           break;
+       case 'v':
+           r->class = SPECIFIER;
+           SPEC_NOUN(r) = V_VOID;
+           break;
+       case '*':
+           DCL_TYPE(r) = port->unqualified_pointer;
+           break;
+       case 'g':
+       case 'x':
+       case 'p':
+       case 'd':
+       case 'F':
+           assert(*(s+1)=='*');
+           nr = newLink(DECLARATOR);
+           nr->next = r;
+           r = nr;
+           switch (*s) {
+           case 'g':
+               DCL_TYPE(r) = GPOINTER;
+               break;
+           case 'x':
+               DCL_TYPE(r) = FPOINTER;
+               break;
+           case 'p':
+               DCL_TYPE(r) = CPOINTER;
+               break;
+           case 'd':
+               DCL_TYPE(r) = POINTER;
+               break;
+           case 'F':
+               DCL_TYPE(r) = FUNCTION;
+               nr = newLink(DECLARATOR);
+               nr->next = r;
+               r = nr;
+               DCL_TYPE(r) = CPOINTER;
+               break;
+           }
+           s++;
+           break;
+       default:
+           werror(E_INTERNAL_ERROR, __FILE__, __LINE__, 
+                  "typeFromStr: unknown type");
+           break;
+       }
+       if (IS_SPEC(r) && usign) {
+           SPEC_USIGN(r) = 1;
+           usign = 0;
+       }
+       s++;
+    } while (*s);
+    return r;
+}
+
 /*-----------------------------------------------------------------*/
 /* initCSupport - create functions for C support routines          */
 /*-----------------------------------------------------------------*/
@@ -2361,7 +3090,7 @@ initCSupport ()
 
   for (bwd = 0; bwd < 3; bwd++)
     {
-      sym_link *l;
+      sym_link *l = NULL;
       switch (bwd)
        {
        case 0:
@@ -2400,25 +3129,27 @@ initCSupport ()
            {
              if (tofrom)
                {
-                 sprintf (buffer, "__fs2%s%s", ssu[su], sbwd[bwd]);
-                 __conv[tofrom][bwd][su] = funcOfType (_mangleFunctionName(buffer), __multypes[bwd][su], floatType, 1, options.float_rent);
+                 SNPRINTF (buffer, sizeof(buffer), "__fs2%s%s", ssu[su], sbwd[bwd]);
+                 __conv[tofrom][bwd][su] = funcOfType (buffer, __multypes[bwd][su], floatType, 1, options.float_rent);
                }
              else
                {
-                 sprintf (buffer, "__%s%s2fs", ssu[su], sbwd[bwd]);
-                 __conv[tofrom][bwd][su] = funcOfType (_mangleFunctionName(buffer), floatType, __multypes[bwd][su], 1, options.float_rent);
+                 SNPRINTF (buffer, sizeof(buffer), "__%s%s2fs", ssu[su], sbwd[bwd]);
+                 __conv[tofrom][bwd][su] = funcOfType (buffer, floatType, __multypes[bwd][su], 1, options.float_rent);
                }
            }
        }
     }
 
+/*
   for (muldivmod = 0; muldivmod < 3; muldivmod++)
     {
       for (bwd = 0; bwd < 3; bwd++)
        {
          for (su = 0; su < 2; su++)
            {
-             sprintf (buffer, "_%s%s%s",
+             SNPRINTF (buffer, sizeof(buffer),
+                       "_%s%s%s",
                       smuldivmod[muldivmod],
                       ssu[su],
                       sbwd[bwd]);
@@ -2428,13 +3159,67 @@ initCSupport ()
        }
     }
 
+  muluint() and mulsint() resp. mululong() and mulslong() return the same result.
+  Therefore they've been merged into mulint() and mullong().
+*/
+
+  for (bwd = 0; bwd < 3; bwd++)
+    {
+      for (su = 0; su < 2; su++)
+       {
+         for (muldivmod = 1; muldivmod < 3; muldivmod++)
+           {
+             /* div and mod */
+             SNPRINTF (buffer, sizeof(buffer),
+                       "_%s%s%s",
+                      smuldivmod[muldivmod],
+                      ssu[su],
+                      sbwd[bwd]);
+             __muldiv[muldivmod][bwd][su] = funcOfType (_mangleFunctionName(buffer), __multypes[bwd][su], __multypes[bwd][su], 2, options.intlong_rent);
+             FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
+           }
+       }
+    }
+  /* mul only */
+  muldivmod = 0;
+  /* byte */
+  bwd = 0;
+  for (su = 0; su < 2; su++)
+    {
+      /* muluchar and mulschar are still separate functions, because e.g. the z80
+         port is sign/zero-extending to int before calling mulint() */
+      SNPRINTF (buffer, sizeof(buffer),
+               "_%s%s%s",
+               smuldivmod[muldivmod],
+               ssu[su],
+               sbwd[bwd]);
+      __muldiv[muldivmod][bwd][su] = funcOfType (_mangleFunctionName(buffer), __multypes[bwd][su], __multypes[bwd][su], 2, options.intlong_rent);
+      FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
+    }
+  /* signed only */
+  su = 0;
+  /* word and doubleword */
+  for (bwd = 1; bwd < 3; bwd++)
+    {
+      /* mul, int/long */
+      SNPRINTF (buffer, sizeof(buffer),
+               "_%s%s",
+               smuldivmod[muldivmod],
+               sbwd[bwd]);
+      __muldiv[muldivmod][bwd][0] = funcOfType (_mangleFunctionName(buffer), __multypes[bwd][su], __multypes[bwd][su], 2, options.intlong_rent);
+      FUNC_NONBANKED (__muldiv[muldivmod][bwd][0]->type) = 1;
+      /* signed = unsigned */
+      __muldiv[muldivmod][bwd][1] = __muldiv[muldivmod][bwd][0];
+    }
+
   for (rlrr = 0; rlrr < 2; rlrr++)
     {
       for (bwd = 0; bwd < 3; bwd++)
        {
          for (su = 0; su < 2; su++)
            {
-             sprintf (buffer, "_%s%s%s",
+             SNPRINTF (buffer, sizeof(buffer),
+                       "_%s%s%s",
                       srlrr[rlrr],
                       ssu[su],
                       sbwd[bwd]);
@@ -2444,3 +3229,101 @@ initCSupport ()
        }
     }
 }
+
+/*-----------------------------------------------------------------*/
+/* initBuiltIns - create prototypes for builtin functions          */
+/*-----------------------------------------------------------------*/
+void initBuiltIns()
+{
+    int i;
+    symbol *sym;
+
+    if (!port->builtintable) return ;
+
+    for (i = 0 ; port->builtintable[i].name ; i++) {
+       sym = funcOfTypeVarg(port->builtintable[i].name,port->builtintable[i].rtype,
+                            port->builtintable[i].nParms,port->builtintable[i].parm_types);
+       FUNC_ISBUILTIN(sym->type) = 1;
+       FUNC_ISREENT(sym->type) = 0;    /* can never be reentrant */
+    }
+}
+
+sym_link *validateLink(sym_link        *l, 
+                       const char      *macro,
+                       const char      *args,
+                       const char      select,
+                       const char      *file, 
+                       unsigned        line)
+{    
+  if (l && l->class==select)
+    {
+       return l;
+    }
+    fprintf(stderr, 
+           "Internal error: validateLink failed in %s(%s) @ %s:%u:"
+           " expected %s, got %s\n",
+           macro, args, file, line, 
+           DECLSPEC2TXT(select), l ? DECLSPEC2TXT(l->class) : "null-link");
+    exit(-1);
+    return l; // never reached, makes compiler happy.
+}
+
+/*--------------------------------------------------------------------*/
+/* newEnumType - create an integer type compatible with enumerations  */
+/*--------------------------------------------------------------------*/
+sym_link *
+newEnumType (symbol *enumlist)
+{
+  int min, max, v;
+  symbol *sym;
+  sym_link *type;
+
+  if (!enumlist)
+    {
+      type = newLink (SPECIFIER);
+      SPEC_NOUN (type) = V_INT;
+      return type;
+    }
+      
+  /* Determine the range of the enumerated values */
+  sym = enumlist;
+  min = max = (int) floatFromVal (valFromType (sym->type));
+  for (sym = sym->next; sym; sym = sym->next)
+    {
+      v = (int) floatFromVal (valFromType (sym->type));
+      if (v<min)
+        min = v;
+      if (v>max)
+        max = v;
+    }
+
+  /* Determine the smallest integer type that is compatible with this range */
+  type = newLink (SPECIFIER);
+  if (min>=0 && max<=255)
+    {
+      SPEC_NOUN (type) = V_CHAR;
+      SPEC_USIGN (type) = 1;
+    }
+  else if (min>=-128 && max<=127)
+    {
+      SPEC_NOUN (type) = V_CHAR;
+    }
+  else if (min>=0 && max<=65535)
+    {
+      SPEC_NOUN (type) = V_INT;
+      SPEC_USIGN (type) = 1;
+    }
+  else if (min>=-32768 && max<=32767)
+    {
+      SPEC_NOUN (type) = V_INT;
+    }
+  else
+    {
+      SPEC_NOUN (type) = V_INT;
+      SPEC_LONG (type) = 1;
+      if (min>=0)
+        SPEC_USIGN (type) = 1;
+    }
+  
+  return type;    
+}