* fixed GCC 4.4.0 mingw compilation:
[fw/sdcc] / src / SDCCsymt.c
index 35360f205052fbecca4a9b47538cd5220e1a60bc..6692939f2cb1e7442958e6012b44d7726fd11d1d 100644 (file)
@@ -23,6 +23,9 @@
 
 #include "common.h"
 #include "newalloc.h"
+#include "dbuf_string.h"
+
+#include "SDCCsymt.h"
 
 value *aggregateToPointer (value *val);
 void printTypeChainRaw (sym_link * start, FILE * of);
@@ -37,14 +40,15 @@ void printFromToType(sym_link *from, sym_link *to) {
 
 /* noun strings */
 char *nounName(sym_link *sl) {
-  switch (SPEC_NOUN(sl)) 
+  switch (SPEC_NOUN(sl))
     {
     case V_INT: {
       if (SPEC_LONG(sl)) return "long";
-      if (sl->select.s._short) return "short";
+      if (SPEC_SHORT(sl)) return "short";
       return "int";
     }
     case V_FLOAT: return "float";
+    case V_FIXED16X16: return "fixed16x16";
     case V_CHAR: return "char";
     case V_VOID: return "void";
     case V_STRUCT: return "struct";
@@ -57,16 +61,16 @@ char *nounName(sym_link *sl) {
   return "unknown";
 };
 
-bucket *SymbolTab[256];                /* the symbol    table  */
-bucket *StructTab[256];                /* the structure table  */
-bucket *TypedefTab[256];       /* the typedef   table  */
-bucket *LabelTab[256];         /* the Label     table  */
-bucket *enumTab[256];          /* enumerated    table  */
+bucket *SymbolTab[256];         /* the symbol    table  */
+bucket *StructTab[256];         /* the structure table  */
+bucket *TypedefTab[256];        /* the typedef   table  */
+bucket *LabelTab[256];          /* the Label     table  */
+bucket *enumTab[256];           /* enumerated    table  */
 
 /*------------------------------------------------------------------*/
 /* initSymt () - initialises symbol table related stuff             */
 /*------------------------------------------------------------------*/
-void 
+void
 initSymt ()
 {
   int i = 0;
@@ -77,7 +81,7 @@ initSymt ()
 
 }
 /*-----------------------------------------------------------------*/
-/* newBucket - allocates & returns a new bucket        */
+/* newBucket - allocates & returns a new bucket                    */
 /*-----------------------------------------------------------------*/
 bucket *
 newBucket ()
@@ -92,7 +96,7 @@ newBucket ()
 /*-----------------------------------------------------------------*/
 /* hashKey - computes the hashkey given a symbol name              */
 /*-----------------------------------------------------------------*/
-int 
+int
 hashKey (const char *s)
 {
   unsigned long key = 0;
@@ -105,16 +109,16 @@ hashKey (const char *s)
 /*-----------------------------------------------------------------*/
 /* addSym - adds a symbol to the hash Table                        */
 /*-----------------------------------------------------------------*/
-void 
+void
 addSym (bucket ** stab,
-       void *sym,
-       char *sname,
-       int level,
-       int block,
-       int checkType)
+        void *sym,
+        char *sname,
+        int level,
+        int block,
+        int checkType)
 {
-  int i;                       /* index into the hash Table */
-  bucket *bp;                  /* temp bucket    *         */
+  int i;                        /* index into the hash Table */
+  bucket *bp;                   /* temp bucket    *          */
 
   if (checkType) {
     symbol *csym = (symbol *)sym;
@@ -137,15 +141,15 @@ addSym (bucket ** stab,
   /* get a free entry */
   bp = Safe_alloc ( sizeof (bucket));
 
-  bp->sym = sym;               /* update the symbol pointer  */
-  bp->level = level;           /* update the nest level      */
+  bp->sym = sym;                /* update the symbol pointer */
+  bp->level = level;            /* update the nest level     */
   bp->block = block;
-  strncpyz (bp->name, sname, sizeof(bp->name));        /* 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)
     {
-      bp->prev = bp->next = (void *) NULL;     /* point to nothing */
+      bp->prev = bp->next = (void *) NULL;      /* point to nothing */
       stab[i] = bp;
     }
   /* not first entry then add @ head of list */
@@ -159,9 +163,9 @@ addSym (bucket ** stab,
 }
 
 /*-----------------------------------------------------------------*/
-/* deleteSym - deletes a symbol from the hash Table  entry     */
+/* deleteSym - deletes a symbol from the hash Table entry          */
 /*-----------------------------------------------------------------*/
-void 
+void
 deleteSym (bucket ** stab, void *sym, char *sname)
 {
   int i = 0;
@@ -173,33 +177,33 @@ deleteSym (bucket ** stab, void *sym, char *sname)
   /* find the symbol */
   while (bp)
     {
-      if (bp->sym == sym)      /* found it then break out */
-       break;                  /* of the loop       */
+      if (bp->sym == sym)       /* found it then break out */
+        break;                  /* of the loop       */
       bp = bp->next;
     }
 
-  if (!bp)                     /* did not find it */
+  if (!bp)                      /* did not find it */
     return;
+
   /* if this is the first one in the chain */
   if (!bp->prev)
     {
       stab[i] = bp->next;
-      if (stab[i])             /* if chain ! empty */
-       stab[i]->prev = (void *) NULL;
+      if (stab[i])              /* if chain ! empty */
+        stab[i]->prev = (void *) NULL;
     }
   /* middle || end of chain */
   else
     {
-      if (bp->next)            /* if not end of chain */
-       bp->next->prev = bp->prev;
+      if (bp->next)             /* if not end of chain */
+        bp->next->prev = bp->prev;
 
       bp->prev->next = bp->next;
     }
-
 }
 
 /*-----------------------------------------------------------------*/
-/* findSym - finds a symbol in a table           */
+/* findSym - finds a symbol in a table                             */
 /*-----------------------------------------------------------------*/
 void *
 findSym (bucket ** stab, void *sym, const char *sname)
@@ -210,7 +214,7 @@ findSym (bucket ** stab, void *sym, const char *sname)
   while (bp)
     {
       if (bp->sym == sym || strcmp (bp->name, sname) == 0)
-       break;
+        break;
       bp = bp->next;
     }
 
@@ -238,20 +242,20 @@ findSymWithLevel (bucket ** stab, symbol * sym)
   while (bp)
     {
       if (strcmp (bp->name, sym->name) == 0 && bp->level <= sym->level)
-       {
-         /* if this is parameter then nothing else need to be checked */
-         if (((symbol *) (bp->sym))->_isparm)
-           return (bp->sym);
-         /* if levels match then block numbers should also match */
-         if (bp->level && bp->level == sym->level && bp->block == sym->block)
-           return (bp->sym);
-         /* if levels don't match then we are okay */
-         if (bp->level && bp->level != sym->level && bp->block <= sym->block)
-           return (bp->sym);
-         /* if this is a global variable then we are ok too */
-         if (bp->level == 0)
-           return (bp->sym);
-       }
+        {
+          /* if this is parameter then nothing else need to be checked */
+          if (((symbol *) (bp->sym))->_isparm)
+            return (bp->sym);
+          /* if levels match then block numbers should also match */
+          if (bp->level && bp->level == sym->level && bp->block == sym->block)
+            return (bp->sym);
+          /* if levels don't match then we are okay */
+          if (bp->level && bp->level != sym->level && bp->block <= sym->block)
+            return (bp->sym);
+          /* if this is a global variable then we are ok too */
+          if (bp->level == 0)
+            return (bp->sym);
+        }
 
       bp = bp->next;
     }
@@ -271,8 +275,8 @@ findSymWithBlock (bucket ** stab, symbol * sym, int block)
   while (bp)
     {
       if (strcmp (bp->name, sym->name) == 0 &&
-         bp->block <= block)
-       break;
+          bp->block <= block)
+        break;
       bp = bp->next;
     }
 
@@ -289,10 +293,11 @@ newSymbol (char *name, int scope)
 
   sym = Safe_alloc ( sizeof (symbol));
 
-  strncpyz (sym->name, name, sizeof(sym->name));       /* copy the name */
-  sym->level = scope;          /* set the level    */
+  strncpyz (sym->name, name, sizeof(sym->name)); /* copy the name */
+  sym->level = scope;           /* set the level */
   sym->block = currBlockno;
-  sym->lineDef = mylineno;     /* set the line number */
+  sym->lineDef = lexLineno;    /* set the line number */
+  sym->fileDef = lexFilename;
   return sym;
 }
 
@@ -320,10 +325,10 @@ newStruct (char *tag)
 
   s = Safe_alloc ( sizeof (structdef));
 
-  strncpyz (s->tag, tag, sizeof(s->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  */
@@ -358,7 +363,7 @@ sclsFromPtr(sym_link *ptr)
 /*------------------------------------------------------------------*/
 /* pointerTypes - do the computation for the pointer types          */
 /*------------------------------------------------------------------*/
-void 
+void
 pointerTypes (sym_link * ptr, sym_link * type)
 {
   if (IS_SPEC (ptr))
@@ -371,7 +376,7 @@ pointerTypes (sym_link * ptr, sym_link * type)
   /* could not find it */
   if (!ptr || IS_SPEC (ptr))
     return;
-  
+
   if (IS_PTR(ptr) && DCL_TYPE(ptr)!=UPOINTER) {
     pointerTypes (ptr->next, type);
     return;
@@ -382,29 +387,29 @@ pointerTypes (sym_link * ptr, sym_link * type)
   if (IS_SPEC (type))
     {
       switch (SPEC_SCLS (type))
-       {
-       case S_XDATA:
-         DCL_TYPE (ptr) = FPOINTER;
-         break;
-       case S_IDATA:
-         DCL_TYPE (ptr) = IPOINTER;
-         break;
-       case S_PDATA:
-         DCL_TYPE (ptr) = PPOINTER;
-         break;
-       case S_DATA:
-         DCL_TYPE (ptr) = POINTER;
-         break;
-       case S_CODE:
-         DCL_TYPE (ptr) = CPOINTER;
-         break;
-       case S_EEPROM:
-         DCL_TYPE (ptr) = EEPPOINTER;
-         break;
-       default:
-         DCL_TYPE (ptr) = port->unqualified_pointer;
-         break;
-       }
+        {
+        case S_XDATA:
+          DCL_TYPE (ptr) = FPOINTER;
+          break;
+        case S_IDATA:
+          DCL_TYPE (ptr) = IPOINTER;
+          break;
+        case S_PDATA:
+          DCL_TYPE (ptr) = PPOINTER;
+          break;
+        case S_DATA:
+          DCL_TYPE (ptr) = POINTER;
+          break;
+        case S_CODE:
+          DCL_TYPE (ptr) = CPOINTER;
+          break;
+        case S_EEPROM:
+          DCL_TYPE (ptr) = EEPPOINTER;
+          break;
+        default:
+          DCL_TYPE (ptr) = port->unqualified_pointer;
+          break;
+        }
       /* the storage class of type ends here */
       SPEC_SCLS (type) = 0;
     }
@@ -414,7 +419,7 @@ pointerTypes (sym_link * ptr, sym_link * type)
   while (ptr)
     {
       if (!IS_SPEC (ptr) && DCL_TYPE (ptr) == UPOINTER)
-       DCL_TYPE (ptr) = port->unqualified_pointer;
+        DCL_TYPE (ptr) = port->unqualified_pointer;
       ptr = ptr->next;
     }
 
@@ -423,7 +428,7 @@ pointerTypes (sym_link * ptr, sym_link * type)
   while (type)
     {
       if (!IS_SPEC (type) && DCL_TYPE (type) == UPOINTER)
-       DCL_TYPE (type) = port->unqualified_pointer;
+        DCL_TYPE (type) = port->unqualified_pointer;
       type = type->next;
     }
 }
@@ -431,9 +436,10 @@ pointerTypes (sym_link * ptr, sym_link * type)
 /*------------------------------------------------------------------*/
 /* addDecl - adds a declarator @ the end of a chain                 */
 /*------------------------------------------------------------------*/
-void 
+void
 addDecl (symbol * sym, int type, sym_link * p)
 {
+  static sym_link *empty = NULL;
   sym_link *head;
   sym_link *tail;
   sym_link *t;
@@ -441,12 +447,15 @@ addDecl (symbol * sym, int type, sym_link * p)
   if (getenv("SDCC_DEBUG_FUNCTION_POINTERS"))
     fprintf (stderr, "SDCCsymt.c:addDecl(%s,%d,%p)\n", sym->name, type, p);
 
+  if (empty == NULL)
+    empty = newLink(SPECIFIER);
+
   /* if we are passed a link then set head & tail */
   if (p)
     {
       tail = head = p;
       while (tail->next)
-       tail = tail->next;
+        tail = tail->next;
     }
   else
     {
@@ -460,28 +469,28 @@ addDecl (symbol * sym, int type, sym_link * p)
       sym->type = head;
       sym->etype = tail;
     }
+  else if (IS_SPEC (sym->etype) && IS_SPEC (head) && head == tail)
+    {
+      sym->etype = mergeSpec (sym->etype, head, sym->name);
+    }
+  else if (IS_SPEC (sym->etype) && !IS_SPEC (head) && head == tail)
+    {
+      t = sym->type;
+      while (t->next != sym->etype)
+        t = t->next;
+      t->next = head;
+      tail->next = sym->etype;
+    }
+  else if (IS_FUNC (sym->type) && IS_SPEC (sym->type->next) &&
+           !memcmp(sym->type->next, empty, sizeof(sym_link)))
+    {
+      sym->type->next = head;
+      sym->etype = tail;
+    }
   else
     {
-      if (IS_SPEC (sym->etype) && IS_SPEC (head) && head == tail)
-       {
-         sym->etype = mergeSpec (sym->etype, head, sym->name);
-       }
-      else
-       {
-         if (IS_SPEC (sym->etype) && !IS_SPEC (head) && head == tail)
-           {
-             t = sym->type;
-             while (t->next != sym->etype)
-               t = t->next;
-             t->next = head;
-             tail->next = sym->etype;
-           }
-         else
-           {
-             sym->etype->next = head;
-             sym->etype = tail;
-           }
-       }
+      sym->etype->next = head;
+      sym->etype = tail;
     }
 
   /* if the type is an unknown pointer and has
@@ -494,9 +503,9 @@ addDecl (symbol * sym, int type, sym_link * p)
       DCL_TSPEC (p))
     {
       if (!IS_SPEC (sym->etype))
-       {
-         sym->etype = sym->etype->next = newLink (SPECIFIER);
-       }
+        {
+          sym->etype = sym->etype->next = newLink (SPECIFIER);
+        }
       SPEC_SCLS (sym->etype) = SPEC_SCLS (DCL_TSPEC (p));
       DCL_TSPEC (p) = NULL;
     }
@@ -536,44 +545,53 @@ void checkTypeSanity(sym_link *etype, char *name) {
     fprintf (stderr, "checking sanity for %s %p\n", name, etype);
   }
 
-  if ((SPEC_NOUN(etype)==V_CHAR || 
-       SPEC_NOUN(etype)==V_FLOAT || 
-       SPEC_NOUN(etype)==V_DOUBLE || 
+  if ((SPEC_NOUN(etype)==V_CHAR ||
+       SPEC_NOUN(etype)==V_FLOAT ||
+       SPEC_NOUN(etype)==V_FIXED16X16 ||
+       SPEC_NOUN(etype)==V_DOUBLE ||
        SPEC_NOUN(etype)==V_VOID) &&
-      (etype->select.s._short || SPEC_LONG(etype))) {
+      (SPEC_SHORT(etype) || SPEC_LONG(etype))) {
     // long or short for char float double or void
     werror (E_LONG_OR_SHORT_INVALID, noun, name);
   }
-  if ((SPEC_NOUN(etype)==V_FLOAT || 
-       SPEC_NOUN(etype)==V_DOUBLE || 
-       SPEC_NOUN(etype)==V_VOID) && 
-      (etype->select.s._signed || SPEC_USIGN(etype))) {
+  if ((SPEC_NOUN(etype)==V_FLOAT ||
+       SPEC_NOUN(etype)==V_FIXED16X16 ||
+       SPEC_NOUN(etype)==V_DOUBLE ||
+       SPEC_NOUN(etype)==V_VOID) &&
+      (etype->select.s.b_signed || SPEC_USIGN(etype))) {
     // signed or unsigned for float double or void
     werror (E_SIGNED_OR_UNSIGNED_INVALID, noun, name);
   }
 
   // special case for "short"
-  if (etype->select.s._short) {
+  if (SPEC_SHORT(etype)) {
     SPEC_NOUN(etype) = options.shortis8bits ? V_CHAR : V_INT;
-    etype->select.s._short = 0;
+    SPEC_SHORT(etype) = 0;
   }
 
-  /* if no noun e.g. 
+  /* if no noun e.g.
      "const a;" or "data b;" or "signed s" or "long l"
      assume an int */
   if (!SPEC_NOUN(etype)) {
     SPEC_NOUN(etype)=V_INT;
   }
 
-  if (etype->select.s._signed && SPEC_USIGN(etype)) {
-    // signed AND unsigned 
+  /* 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.b_signed)
+      SPEC_USIGN(etype) = 1;
+  }
+
+  if (etype->select.s.b_signed && SPEC_USIGN(etype)) {
+    // signed AND unsigned
     werror (E_SIGNED_AND_UNSIGNED_INVALID, noun, name);
   }
-  if (etype->select.s._short && SPEC_LONG(etype)) {
+  if (SPEC_SHORT(etype) && SPEC_LONG(etype)) {
     // short AND long
     werror (E_LONG_AND_SHORT_INVALID, noun, name);
   }
-
 }
 
 /*------------------------------------------------------------------*/
@@ -599,19 +617,19 @@ mergeSpec (sym_link * dest, sym_link * src, char *name)
     } else {
       /* we shouldn't redeclare the type */
       if (getenv("DEBUG_SANITY")) {
-       fprintf (stderr, "mergeSpec: ");
+        fprintf (stderr, "mergeSpec: ");
       }
       werror(E_TWO_OR_MORE_DATA_TYPES, name);
     }
   }
-  
+
   if (SPEC_SCLS(src)) {
     /* if destination has no storage class */
     if (!SPEC_SCLS (dest) || SPEC_SCLS(dest)==S_REGISTER) {
       SPEC_SCLS (dest) = SPEC_SCLS (src);
     } else {
       if (getenv("DEBUG_SANITY")) {
-       fprintf (stderr, "mergeSpec: ");
+        fprintf (stderr, "mergeSpec: ");
       }
       werror(E_TWO_OR_MORE_STORAGE_CLASSES, name);
     }
@@ -619,7 +637,7 @@ mergeSpec (sym_link * dest, sym_link * src, char *name)
 
   /* copy all the specifications  */
 
-  // we really should do: 
+  // we really should do:
 #if 0
   if (SPEC_what(src)) {
     if (SPEC_what(dest)) {
@@ -631,14 +649,16 @@ mergeSpec (sym_link * dest, sym_link * src, char *name)
   // but there are more important thing right now
 
   SPEC_LONG (dest) |= SPEC_LONG (src);
-  dest->select.s._short|=src->select.s._short;
+  SPEC_SHORT(dest) |= SPEC_SHORT(src);
   SPEC_USIGN (dest) |= SPEC_USIGN (src);
-  dest->select.s._signed|=src->select.s._signed;
+  dest->select.s.b_signed|=src->select.s.b_signed;
   SPEC_STAT (dest) |= SPEC_STAT (src);
   SPEC_EXTR (dest) |= SPEC_EXTR (src);
+  SPEC_INLINE (dest) |= SPEC_INLINE (src);
   SPEC_CONST(dest) |= SPEC_CONST (src);
   SPEC_ABSA (dest) |= SPEC_ABSA (src);
   SPEC_VOLATILE (dest) |= SPEC_VOLATILE (src);
+  SPEC_RESTRICT (dest) |= SPEC_RESTRICT (src);
   SPEC_ADDR (dest) |= SPEC_ADDR (src);
   SPEC_OCLS (dest) = SPEC_OCLS (src);
   SPEC_BLEN (dest) |= SPEC_BLEN (src);
@@ -647,11 +667,11 @@ mergeSpec (sym_link * dest, sym_link * src, char *name)
   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);
 
-  /* these are the only function attributes that will be set 
+  /* these are the only function attributes that will be set
      in a specifier while parsing */
   FUNC_NONBANKED(dest) |= FUNC_NONBANKED(src);
   FUNC_BANKED(dest) |= FUNC_BANKED(src);
@@ -664,13 +684,14 @@ mergeSpec (sym_link * dest, sym_link * src, char *name)
   FUNC_ISOVERLAY(dest) |= FUNC_ISOVERLAY(src);
   FUNC_INTNO(dest) |= FUNC_INTNO(src);
   FUNC_REGBANK(dest) |= FUNC_REGBANK(src);
+  FUNC_ISINLINE (dest) |= FUNC_ISINLINE (src);
 
   return dest;
 }
 
-/*------------------------------------------------------------------*/
+/*-------------------------------------------------------------------*/
 /* genSymName - generates and returns a name used for anonymous vars */
-/*------------------------------------------------------------------*/
+/*-------------------------------------------------------------------*/
 char *
 genSymName (int level)
 {
@@ -724,6 +745,20 @@ newFloatLink ()
   return p;
 }
 
+/*------------------------------------------------------------------*/
+/* newFixed16x16Link - a new Float type                             */
+/*------------------------------------------------------------------*/
+sym_link *
+newFixed16x16Link ()
+{
+  sym_link *p;
+
+  p = newLink (SPECIFIER);
+  SPEC_NOUN (p) = V_FIXED16X16;
+
+  return p;
+}
+
 /*------------------------------------------------------------------*/
 /* newLongLink() - new long type                                    */
 /*------------------------------------------------------------------*/
@@ -754,50 +789,66 @@ newIntLink ()
 }
 
 /*------------------------------------------------------------------*/
-/* getSize - returns size of a type chain in bits                   */
+/* newBoolLink() - creates an bool type                             */
+/*------------------------------------------------------------------*/
+sym_link *
+newBoolLink ()
+{
+  sym_link *p;
+
+  p = newLink (SPECIFIER);
+  SPEC_NOUN (p) = V_BIT;
+
+  return p;
+}
+
+/*------------------------------------------------------------------*/
+/* getSize - returns size of a type chain in bytes                  */
 /*------------------------------------------------------------------*/
-unsigned int 
+unsigned int
 getSize (sym_link * p)
 {
   /* if nothing return 0 */
   if (!p)
     return 0;
   if (IS_SPEC (p))
-    {                          /* if this is the specifier then */
+    {                           /* if this is the specifier then */
       switch (SPEC_NOUN (p))
-       {                       /* depending on the specifier type */
-       case V_INT:
-         return (IS_LONG (p) ? LONGSIZE : INTSIZE);
-       case V_FLOAT:
-         return FLOATSIZE;
-       case V_CHAR:
-         return CHARSIZE;
-       case V_VOID:
-         return 0;
-       case V_STRUCT:
-         return SPEC_STRUCT (p)->size;
-       case V_LABEL:
-         return 0;
-       case V_SBIT:
-       case V_BIT:
-         return BITSIZE;
-       case V_BITFIELD:
-         return ((SPEC_BLEN (p) / 8) + (SPEC_BLEN (p) % 8 ? 1 : 0));
-       default:
-         return 0;
-       }
-    }
-
-  /* this is a specifier  */
+        {                       /* depending on the specifier type */
+        case V_INT:
+          return (IS_LONG (p) ? LONGSIZE : INTSIZE);
+        case V_FLOAT:
+          return FLOATSIZE;
+        case V_FIXED16X16:
+          return (4);
+        case V_CHAR:
+          return CHARSIZE;
+        case V_VOID:
+          return 0;
+        case V_STRUCT:
+          return SPEC_STRUCT (p)->size;
+        case V_LABEL:
+          return 0;
+        case V_SBIT:
+        case V_BIT:
+          return BITSIZE;
+        case V_BITFIELD:
+          return ((SPEC_BLEN (p) / 8) + (SPEC_BLEN (p) % 8 ? 1 : 0));
+        default:
+          return 0;
+        }
+    }
+
+  /* this is a declarator */
   switch (DCL_TYPE (p))
     {
     case ARRAY:
       if (DCL_ELEM(p)) {
-       return DCL_ELEM (p) * getSize (p->next);
+        return DCL_ELEM (p) * getSize (p->next);
       } else {
-         //    werror (E_INTERNAL_ERROR, __FILE__, __LINE__, 
-         //    "can not tell the size of an array[]");
-       return 0;
+          //    werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+          //    "can not tell the size of an array[]");
+        return 0;
       }
     case IPOINTER:
     case PPOINTER:
@@ -807,7 +858,7 @@ getSize (sym_link * p)
     case FPOINTER:
     case CPOINTER:
     case FUNCTION:
-      return (FPTRSIZE);
+      return (IFFUNC_BANKED (p) ? GPTRSIZE : FPTRSIZE);
     case GPOINTER:
       return (GPTRSIZE);
 
@@ -816,10 +867,47 @@ getSize (sym_link * p)
     }
 }
 
+/*------------------------------------------------------------------*/
+/* checkStructFlexArray - check tree behind a struct                */
+/*------------------------------------------------------------------*/
+static bool
+checkStructFlexArray (symbol *sym, sym_link *p)
+{
+  /* if nothing return FALSE */
+  if (!p)
+    return FALSE;
+
+  if (IS_SPEC (p))
+    {
+      /* (nested) struct with flexible array member? */
+      if (IS_STRUCT (p) && SPEC_STRUCT (p)->b_flexArrayMember)
+        {
+          werror (W_INVALID_FLEXARRAY);
+          return FALSE;
+        }
+      return FALSE;
+    }
+
+  /* this is a declarator */
+  if (IS_ARRAY (p))
+    {
+      /* flexible array member? */
+      if (!DCL_ELEM(p))
+        {
+          if (!options.std_c99)
+            werror (W_C89_NO_FLEXARRAY);
+          return TRUE;
+        }
+      /* walk tree */
+      return checkStructFlexArray (sym, p->next);
+    }
+  return FALSE;
+}
+
 /*------------------------------------------------------------------*/
 /* bitsForType - returns # of bits required to store this type      */
 /*------------------------------------------------------------------*/
-unsigned int 
+unsigned int
 bitsForType (sym_link * p)
 {
   /* if nothing return 0 */
@@ -827,30 +915,32 @@ bitsForType (sym_link * p)
     return 0;
 
   if (IS_SPEC (p))
-    {                          /* if this is the specifier then */
+    {                           /* if this is the specifier then */
 
       switch (SPEC_NOUN (p))
-       {                       /* depending on the specifier type */
-       case V_INT:
-         return (IS_LONG (p) ? LONGSIZE * 8 : INTSIZE * 8);
-       case V_FLOAT:
-         return FLOATSIZE * 8;
-       case V_CHAR:
-         return CHARSIZE * 8;
-       case V_VOID:
-         return 0;
-       case V_STRUCT:
-         return SPEC_STRUCT (p)->size * 8;
-       case V_LABEL:
-         return 0;
-       case V_SBIT:
-       case V_BIT:
-         return 1;
-       case V_BITFIELD:
-         return SPEC_BLEN (p);
-       default:
-         return 0;
-       }
+        {                       /* depending on the specifier type */
+        case V_INT:
+          return (IS_LONG (p) ? LONGSIZE * 8 : INTSIZE * 8);
+        case V_FLOAT:
+          return FLOATSIZE * 8;
+        case V_FIXED16X16:
+          return (32);
+        case V_CHAR:
+          return CHARSIZE * 8;
+        case V_VOID:
+          return 0;
+        case V_STRUCT:
+          return SPEC_STRUCT (p)->size * 8;
+        case V_LABEL:
+          return 0;
+        case V_SBIT:
+        case V_BIT:
+          return 1;
+        case V_BITFIELD:
+          return SPEC_BLEN (p);
+        default:
+          return 0;
+        }
     }
 
   /* this is a specifier  */
@@ -916,7 +1006,7 @@ copySymbol (symbol * src)
 }
 
 /*------------------------------------------------------------------*/
-/* reverseSyms - reverses the links for a symbol chain      */
+/* reverseSyms - reverses the links for a symbol chain              */
 /*------------------------------------------------------------------*/
 symbol *
 reverseSyms (symbol * sym)
@@ -941,7 +1031,7 @@ reverseSyms (symbol * sym)
 }
 
 /*------------------------------------------------------------------*/
-/* reverseLink - reverses the links for a type chain        */
+/* reverseLink - reverses the links for a type chain                */
 /*------------------------------------------------------------------*/
 sym_link *
 reverseLink (sym_link * type)
@@ -968,43 +1058,117 @@ reverseLink (sym_link * type)
 /*------------------------------------------------------------------*/
 /* addSymChain - adds a symbol chain to the symboltable             */
 /*------------------------------------------------------------------*/
-void 
-addSymChain (symbol * symHead)
+void
+addSymChain (symbol ** symHead)
 {
-  symbol *sym = symHead;
+  symbol *sym = *symHead;
   symbol *csym = NULL;
+  symbol **symPtrPtr;
+  int error = 0;
 
   for (; sym != NULL; sym = sym->next)
     {
-      changePointer(sym);
+      changePointer(sym->type);
       checkTypeSanity(sym->etype, sym->name);
 
-      /* 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 (!sym->level && !(IS_SPEC(sym->etype) && IS_TYPEDEF(sym->etype)))
+        checkDecl (sym, 0);
+      else
+        {
+          /* if this is an array without any dimension
+             then update the dimension from the initial value */
+          if (IS_ARRAY (sym->type) && !DCL_ELEM (sym->type))
+            DCL_ELEM (sym->type) = getNelements (sym->type, sym->ival);
+        }
+
+      /* if already exists in the symbol table on the same level */
       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;
-         }
-       } else {
-         /* not extern */
-         if (compareType (csym->type, sym->type) != 1) {
-           werror (E_DUPLICATE, sym->name);
-           continue;
-         }
-       }
-       /* delete current entry */
-       deleteSym (SymbolTab, csym, csym->name);
-       deleteFromSeg(csym);
-      }
+          csym->level == sym->level)
+        {
+          /* if not formal parameter and not in file scope
+             then show symbol redefined error
+             else check if symbols have compatible types */
+          if (!sym->_isparm && sym->level > 0)
+            error = 1;
+          else
+            {
+              /* 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);
+                }
+              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;
+
+          if (!csym->cdef && !sym->cdef && IS_EXTERN (sym->etype))
+            {
+              /* if none of symbols is a compiler defined function
+                 and at least one is not extern
+                 then set the new symbol to non extern */
+              SPEC_EXTR(sym->etype) = SPEC_EXTR(csym->etype);
+            }
+
+          /* delete current entry */
+          deleteSym (SymbolTab, csym, csym->name);
+          deleteFromSeg(csym);
+
+          symPtrPtr = symHead;
+          while (*symPtrPtr && *symPtrPtr != csym)
+            symPtrPtr = &(*symPtrPtr)->next;
+          if (*symPtrPtr == csym)
+            *symPtrPtr = csym->next;
+        }
 
       /* add new entry */
       addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
@@ -1015,13 +1179,13 @@ addSymChain (symbol * symHead)
 /*------------------------------------------------------------------*/
 /* funcInChain - DCL Type 'FUNCTION' found in type chain            */
 /*------------------------------------------------------------------*/
-int 
+int
 funcInChain (sym_link * lnk)
 {
   while (lnk)
     {
       if (IS_FUNC (lnk))
-       return 1;
+        return 1;
       lnk = lnk->next;
     }
   return 0;
@@ -1038,28 +1202,30 @@ structElemType (sym_link * stype, value * id)
   sym_link *petype = getSpec (stype);
 
   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 (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));
+            SPEC_OCLS (etype) = (SPEC_SCLS (petype) == S_REGISTER ?
+                                 SPEC_OCLS (etype) : SPEC_OCLS (petype));
             if (IS_SPEC (type))
               SPEC_CONST (type) |= SPEC_CONST (stype);
             else
               DCL_PTR_CONST (type) |= SPEC_CONST (stype);
-           return type;
-         }
-       fields = fields->next;
+            return type;
+          }
+        fields = fields->next;
       }
   }
 
   werror (E_NOT_MEMBER, id->name);
-    
+
   // the show must go on
   return newIntLink();
 }
@@ -1084,129 +1250,245 @@ getStructElement (structdef * sdef, symbol * sym)
 /*------------------------------------------------------------------*/
 /* compStructSize - computes the size of a structure                */
 /*------------------------------------------------------------------*/
-int 
+int
 compStructSize (int su, structdef * sdef)
 {
-    int sum = 0, usum = 0;
-    int bitOffset = 0;
-    symbol *loop;
-
-    /* for the identifiers  */
-    loop = sdef->fields;
-    while (loop) {
-
-       /* create the internal name for this variable */
-       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_BITFIELD;
-           SPEC_USIGN (loop->etype) = 1;
-           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;
-           }
-           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);
-       }
-
-       loop = loop->next;
-
-       /* if union then size = sizeof larget field */
-       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);
+  int sum = 0, usum = 0;
+  int bitOffset = 0;
+  symbol *loop;
+
+  /* for the identifiers  */
+  loop = sdef->fields;
+  while (loop) {
+
+    /* create the internal name for this variable */
+    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) {
+
+      SPEC_BUNNAMED (loop->etype) = loop->bitUnnamed;
+
+      /* change it to a unsigned bit */
+      SPEC_NOUN (loop->etype) = V_BITFIELD;
+      /* ISO/IEC 9899 J.3.9 implementation defined behaviour: */
+      /* a "plain" int bitfield is unsigned */
+      if (!loop->etype->select.s.b_signed)
+        SPEC_USIGN(loop->etype) = 1;
+
+      if (loop->bitVar == BITVAR_PAD) {
+        /* A zero length bitfield forces padding */
+        SPEC_BLEN (loop->etype) = 0;
+        SPEC_BSTR (loop->etype) = bitOffset;
+        if (bitOffset > 0)
+          bitOffset = 8; /* padding is not needed when at bit 0 */
+        loop->offset = sum;
+      }
+      else {
+        SPEC_BLEN (loop->etype) = loop->bitVar;
+
+        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 {
+          if( TARGET_IS_PIC16 && getenv("PIC16_PACKED_BITFIELDS") ) {
+            /* if PIC16 && enviroment variable is set, then
+             * tightly pack bitfields, this means that when a
+             * bitfield goes beyond byte alignment, do not
+             * automatically start allocatint from next byte,
+             * but also use the available bits first */
+            fprintf(stderr, ": packing bitfields in structures\n");
+            SPEC_BSTR (loop->etype) = bitOffset;
+            bitOffset += loop->bitVar;
+            loop->offset = (su == UNION ? sum = 0 : sum);
+          } 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);
+
+      /* search for "flexibel array members" */
+      /* and do some syntax checks */
+      if (   su == STRUCT
+          && checkStructFlexArray (loop, loop->type))
+        {
+          /* found a "flexible array member" */
+          sdef->b_flexArrayMember = TRUE;
+          /* is another struct-member following? */
+          if (loop->next)
+            werror (E_FLEXARRAY_NOTATEND);
+          /* is it the first struct-member? */
+          else if (loop == sdef->fields)
+            werror (E_FLEXARRAY_INEMPTYSTRCT);
+        }
+    }
+
+    loop = loop->next;
+
+    /* if union then size = sizeof largest field */
+    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 
+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 for enums change
-     to auto */
+
+  /* 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 */
   if (SPEC_SCLS (sym->etype) == S_SBIT ||
       SPEC_SCLS (sym->etype) == S_SFR)
     {
       SPEC_VOLATILE (sym->etype) = 1;
     }
-  
+
+  /* make sure restrict is only used with pointers */
+  if (SPEC_RESTRICT (sym->etype))
+    {
+      werrorfl (sym->fileDef, sym->lineDef, E_BAD_RESTRICT);
+      SPEC_RESTRICT (sym->etype) = 0;
+    }
+  t = sym->type;
+  while (t)
+    {
+      if (IS_DECL (t) && DCL_PTR_RESTRICT (t) && !IS_PTR (t))
+        {
+          werrorfl (sym->fileDef, sym->lineDef, E_BAD_RESTRICT);
+          DCL_PTR_RESTRICT (t) = 0;
+          break;
+        }
+      t = t->next;
+    }
+
   /* if absolute address given then it mark it as
      volatile -- except in the PIC port */
 
@@ -1217,7 +1499,27 @@ checkSClass (symbol * sym, int isProto)
 
     if (IS_ABSOLUTE (sym->etype))
       SPEC_VOLATILE (sym->etype) = 1;
-  
+
+  if (TARGET_IS_MCS51 &&
+      IS_ABSOLUTE (sym->etype) &&
+      SPEC_SCLS (sym->etype) == S_SFR)
+    {
+      int n, size;
+      unsigned addr;
+
+      if (SPEC_NOUN (sym->etype) == V_CHAR)
+        size = 8;
+      else if (SPEC_LONG (sym->etype) == 0)
+        size = 16;
+      else
+        size = 32;
+
+      addr = SPEC_ADDR (sym->etype);
+      for (n=0; n<size; n+=8)
+        if (((addr >> n) & 0xFF) < 0x80)
+          werror (W_SFR_ABSRANGE, sym->name);
+    }
+
   /* If code memory is read only, then pointers to code memory */
   /* implicitly point to constants -- make this explicit       */
   t = sym->type;
@@ -1282,23 +1584,25 @@ checkSClass (symbol * sym, int isProto)
 
   /* 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 ||
-        SPEC_SCLS (sym->etype) == S_REGISTER ||
-        SPEC_SCLS (sym->etype) == S_STACK ||
-        SPEC_SCLS (sym->etype) == S_XSTACK)) {
-      SPEC_SCLS (sym->etype) = S_AUTO;
-    } else {
-      /* storage class may only be specified for statics */
-      if (!IS_STATIC(sym->etype)) {
-       werror (E_AUTO_ASSUMED, sym->name);
+    if (SPEC_SCLS (sym->etype) != S_BIT) {
+      if ((SPEC_SCLS (sym->etype) == S_AUTO ||
+           SPEC_SCLS (sym->etype) == S_FIXED ||
+           SPEC_SCLS (sym->etype) == S_REGISTER ||
+           SPEC_SCLS (sym->etype) == S_STACK ||
+           SPEC_SCLS (sym->etype) == S_XSTACK)) {
+        SPEC_SCLS (sym->etype) = S_AUTO;
+      } else {
+        /* storage class may only be specified for statics */
+        if (!IS_STATIC(sym->etype)) {
+          werror (E_AUTO_ASSUMED, sym->name);
+        }
       }
     }
   }
-  
+
   /* automatic symbols cannot be given   */
   /* an absolute address ignore it      */
-  if (sym->level &&
+  if (sym->level && !IS_STATIC(sym->etype) &&
       SPEC_ABSA (sym->etype) &&
       (options.stackAuto || reentrant))
     {
@@ -1309,6 +1613,7 @@ checkSClass (symbol * sym, int isProto)
   /* arrays & pointers cannot be defined for bits   */
   /* SBITS or SFRs or BIT                           */
   if ((IS_ARRAY (sym->type) || IS_PTR (sym->type)) &&
+      !IS_FUNCPTR (sym->type) &&
       (SPEC_NOUN (sym->etype) == V_BIT ||
        SPEC_NOUN (sym->etype) == V_SBIT ||
        SPEC_NOUN (sym->etype) == V_BITFIELD ||
@@ -1327,68 +1632,71 @@ checkSClass (symbol * sym, int isProto)
     /* variables declared in CODE space must have */
     /* initializers if not an extern */
     if (SPEC_SCLS (sym->etype) == S_CODE &&
-       sym->ival == NULL &&
-       //!sym->level &&
-       port->mem.code_ro &&
-       !IS_EXTERN (sym->etype) &&
-       !funcInChain (sym->type))
+        sym->ival == NULL &&
+        !sym->_isparm &&
+        //!sym->level &&
+        port->mem.code_ro &&
+        !IS_EXTERN (sym->etype) &&
+        !SPEC_ABSA (sym->etype) &&
+        !funcInChain (sym->type))
       werror (E_CODE_NO_INIT, sym->name);
   }
 
   /* if parameter or local variable then change */
   /* the storage class to reflect where the var will go */
-  if (sym->level && SPEC_SCLS (sym->etype) == S_FIXED &&
-      !IS_STATIC(sym->etype))
+  if (sym->level && SPEC_SCLS (sym->etype) == S_FIXED
+   && !IS_STATIC(sym->etype)
+      )
     {
       if (options.stackAuto || (currFunc && IFFUNC_ISREENT (currFunc->type)))
-       {
-         SPEC_SCLS (sym->etype) = (options.useXstack ?
-                                   S_XSTACK : S_STACK);
-       }
+        {
+          SPEC_SCLS (sym->etype) = (options.useXstack ?
+                                    S_XSTACK : S_STACK);
+        }
       else
-       {
-         /* hack-o-matic! I see no reason why the useXstack option should ever
-          * 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 || TARGET_IS_DS400) ? 
-               1 : options.useXstack;
-         SPEC_SCLS (sym->etype) = (useXdata ?
-                                   S_XDATA : S_FIXED);
-       }
+        {
+          /* hack-o-matic! I see no reason why the useXstack option should ever
+           * control this allocation, but the code was originally that way, and
+           * changing it for non-390 ports breaks the compiler badly.
+           */
+          bool useXdata = (TARGET_IS_DS390 || TARGET_IS_DS400) ?
+                1 : options.useXstack;
+          SPEC_SCLS (sym->etype) = (useXdata ?
+                                    S_XDATA : S_FIXED);
+        }
     }
 }
 
 /*------------------------------------------------------------------*/
 /* changePointer - change pointer to functions                      */
 /*------------------------------------------------------------------*/
-void 
-changePointer (symbol * sym)
+void
+changePointer (sym_link * p)
 {
-  sym_link *p;
 
   /* go thru the chain of declarations   */
   /* if we find a pointer to a function  */
-  /* unconditionally change it to a ptr  */
-  /* to code area                        */
-  for (p = sym->type; p; p = p->next)
+  /* change it to a ptr to code area     */
+  /* unless the function is banked.      */
+  for (; p; p = p->next)
     {
       if (!IS_SPEC (p) && DCL_TYPE (p) == UPOINTER)
-       DCL_TYPE (p) = port->unqualified_pointer;
+        DCL_TYPE (p) = port->unqualified_pointer;
       if (IS_PTR (p) && IS_FUNC (p->next))
-       DCL_TYPE (p) = CPOINTER;
+        if (!IFFUNC_BANKED(p->next))
+        DCL_TYPE (p) = CPOINTER;
     }
 }
 
 /*------------------------------------------------------------------*/
-/* checkDecl - does semantic validation of a declaration                   */
+/* checkDecl - does semantic validation of a declaration            */
 /*------------------------------------------------------------------*/
-int 
+int
 checkDecl (symbol * sym, int isProto)
 {
 
-  checkSClass (sym, isProto);          /* check the storage class      */
-  changePointer (sym);         /* change pointers if required */
+  checkSClass (sym, isProto);        /* check the storage class     */
+  changePointer (sym->type);         /* change pointers if required */
 
   /* if this is an array without any dimension
      then update the dimension from the initial value */
@@ -1406,11 +1714,12 @@ copyLinkChain (sym_link * p)
 {
   sym_link *head, *curr, *loop;
 
+  /* note: v_struct and v_struct->fields are not copied! */
   curr = p;
   head = loop = (curr ? newLink (p->class) : (void *) NULL);
   while (curr)
     {
-      memcpy (loop, curr, sizeof (sym_link));  /* copy it */
+      memcpy (loop, curr, sizeof (sym_link));   /* copy it */
       loop->next = (curr->next ? newLink (curr->next->class) : (void *) NULL);
       loop = loop->next;
       curr = curr->next;
@@ -1419,12 +1728,11 @@ copyLinkChain (sym_link * p)
   return head;
 }
 
-
 /*------------------------------------------------------------------*/
 /* cleanUpBlock - cleansup the symbol table specified for all the   */
 /*                symbols in the given block                        */
 /*------------------------------------------------------------------*/
-void 
+void
 cleanUpBlock (bucket ** table, int block)
 {
   int i;
@@ -1434,12 +1742,12 @@ cleanUpBlock (bucket ** table, int block)
   for (i = 0; i < 256; i++)
     {
       for (chain = table[i]; chain; chain = chain->next)
-       {
-         if (chain->block >= block)
-           {
-             deleteSym (table, chain->sym, chain->name);
-           }
-       }
+        {
+          if (chain->block >= block)
+            {
+              deleteSym (table, chain->sym, chain->name);
+            }
+        }
     }
 }
 
@@ -1447,7 +1755,7 @@ cleanUpBlock (bucket ** table, int block)
 /* cleanUpLevel - cleansup the symbol table specified for all the   */
 /*                symbols in the given level                        */
 /*------------------------------------------------------------------*/
-void 
+void
 cleanUpLevel (bucket ** table, int level)
 {
   int i;
@@ -1457,25 +1765,96 @@ cleanUpLevel (bucket ** table, int level)
   for (i = 0; i < 256; i++)
     {
       for (chain = table[i]; chain; chain = chain->next)
-       {
-         if (chain->level >= level)
-           {
-             deleteSym (table, chain->sym, chain->name);
-           }
-       }
+        {
+          if (chain->level >= level)
+            {
+              deleteSym (table, chain->sym, chain->name);
+            }
+        }
+    }
+}
+
+/*------------------------------------------------------------------*/
+/* 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_BIT (etype1))
+          && (IS_CHAR (etype2) || IS_BIT (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, int 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 */
@@ -1483,17 +1862,37 @@ computeType (sym_link * type1, sym_link * type2)
   /* which ever is greater in size */
   if (IS_FLOAT (etype1) || IS_FLOAT (etype2))
     rType = newFloatLink ();
-  else
-    /* if only one of them is a bit variable
-       then the other one prevails */
-  if (IS_BITVAR (etype1) && !IS_BITVAR (etype2))
-    rType = copyLinkChain (type2);
+  /* if both are fixed16x16 then result is float */
+  else if (IS_FIXED16X16(etype1) && IS_FIXED16X16(etype2))
+    rType = newFixed16x16Link();
+  else if (IS_FIXED16X16(etype1) && IS_FLOAT (etype2))
+    rType = newFloatLink ();
+  else if (IS_FLOAT (etype1) && IS_FIXED16X16 (etype2) )
+    rType = newFloatLink ();
+
+  /* if both are bitvars choose the larger one */
+  else if (IS_BITVAR (etype1) && IS_BITVAR (etype2))
+    rType = SPEC_BLEN (etype1) >= SPEC_BLEN (etype2) ?
+            copyLinkChain (type1) : copyLinkChain (type2);
+
+  /* if only one of them is a bit variable then the other one prevails */
+  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);
-  else
-    /* if one of them is a pointer or array then that
-       prevails */
-  if (IS_PTR (type1) || IS_ARRAY (type1))
+    {
+      rType = copyLinkChain (type1);
+      /* bitfield can have up to 16 bits */
+      if (getSize (etype2) > 1)
+        SPEC_NOUN (getSpec (rType)) = V_INT;
+    }
+  /* if one of them is a pointer or array then that
+     prevails */
+  else if (IS_PTR (type1) || IS_ARRAY (type1))
     rType = copyLinkChain (type1);
   else if (IS_PTR (type2) || IS_ARRAY (type2))
     rType = copyLinkChain (type2);
@@ -1503,27 +1902,174 @@ computeType (sym_link * type1, sym_link * type2)
     rType = copyLinkChain (type2);
 
   reType = getSpec (rType);
-#if 0
-  if (SPEC_NOUN (reType) == V_CHAR)
-    SPEC_NOUN (reType) = V_INT;
-#endif
 
-  /* if either of them unsigned but not val then make this unsigned */
-  if ((SPEC_USIGN (etype1) || SPEC_USIGN (etype2)) &&
-      !IS_FLOAT (reType))
-    SPEC_USIGN (reType) = 1;
-  else
-    SPEC_USIGN (reType) = 0;
+  /* avoid conflicting types */
+  reType->select.s.b_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_IFX:
+        if (TARGET_IS_HC08)
+          break;
+        //fallthrough
+      case RESULT_TYPE_BIT:
+        if (op == ':')
+          {
+            SPEC_NOUN (reType) = V_BIT;
+            return rType;
+          }
+        break;
+      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:
+      case RESULT_TYPE_OTHER:
+        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))
+          {
+            /* promotion of some special cases */
+            switch (op)
+              {
+                case '|':
+                case '^':
+                  return computeTypeOr (etype1, etype2, reType);
+                case '&':
+                  if (SPEC_USIGN (etype1) != SPEC_USIGN (etype2))
+                    {
+                      SPEC_USIGN (reType) = 1;
+                      return rType;
+                    }
+                  break;
+                case '*':
+                  SPEC_NOUN (reType) = V_INT;
+                  SPEC_USIGN (reType) = 0;
+                  return rType;
+                case '/':
+                  /* if both are unsigned char then no promotion required */
+                  if (!(SPEC_USIGN (etype1) && SPEC_USIGN (etype2)))
+                    {
+                      SPEC_NOUN (reType) = V_INT;
+                      SPEC_USIGN (reType) = 0;
+                      return rType;
+                    }
+                  break;
+                default:
+                  break;
+              }
+          }
+        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 */
+              && !(bitsForType (etype1) < bitsForType (reType))
+              /* char require special handling */
+              && !IS_CHAR (etype1))
+          || /* same for 2nd operand */
+             (SPEC_USIGN (etype2)
+              && !(bitsForType (etype2) < bitsForType (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;
 }
 
+int
+comparePtrType (sym_link * dest, sym_link * src, bool bMustCast)
+{
+  int res;
+
+  if (IS_VOID (src->next) && IS_VOID (dest->next))
+    return bMustCast ? -1 : 1;
+  if ((IS_VOID (src->next) && !IS_VOID (dest->next)) ||
+      (!IS_VOID (src->next) && IS_VOID (dest->next)) )
+    return -1;
+  res = compareType (dest->next, src->next);
+  if (res == 1)
+    return bMustCast ? -1 : 1;
+  else if (res == -2)
+    return -2;
+  else
+    return 0;
+}
+
 /*--------------------------------------------------------------------*/
-/* compareType - will do type check return 1 if match, -1 if castable */
+/* compareType - will do type check return 1 if match, 0 if no match, */
+/*               -1 if castable, -2 if only signedness differs        */
 /*--------------------------------------------------------------------*/
 int
 compareType (sym_link * dest, sym_link * src)
@@ -1541,35 +2087,57 @@ compareType (sym_link * dest, sym_link * src)
   if (IS_DECL (dest))
     {
       if (IS_DECL (src))
-       {
-         if (DCL_TYPE (src) == DCL_TYPE (dest)) {
-           if (IS_FUNC(src)) {
-             //checkFunction(src,dest);
-           }
-           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)) {
-           value *val=aggregateToPointer (valFromType(src));
-           int res=compareType (dest, val->type);
-           Safe_free(val->type);
-           Safe_free(val);
-           return res;
-         }
-         if (IS_PTR (dest) && IS_FUNC (dest->next) && IS_FUNC (src))
-           return compareType (dest->next, src);
-         return 0;
-       }
+        {
+          /* banked function pointer */
+          if (IS_GENPTR (dest) && IS_GENPTR (src))
+            {
+              if (IS_FUNC (src->next) && IS_VOID(dest->next))
+                return -1;
+              if (IS_FUNC (dest->next) && IS_VOID(src->next))
+                return -1;
+              return comparePtrType(dest, src, FALSE);
+            }
+
+          if (DCL_TYPE (src) == DCL_TYPE (dest))
+            {
+              if (IS_FUNC(src))
+                {
+                  //checkFunction(src,dest);
+                }
+              return comparePtrType(dest, src, FALSE);
+            }
+          if (IS_PTR (dest) && IS_GENPTR (src) && IS_VOID(src->next))
+            {
+              return -1;
+            }
+          if (IS_PTR (src) &&
+              (IS_GENPTR (dest) ||
+               ((DCL_TYPE(src) == POINTER) && (DCL_TYPE(dest) == IPOINTER))
+             ))
+            {
+              return comparePtrType(dest, src, TRUE);
+            }
+          if (IS_PTR (dest) && IS_ARRAY (src))
+            {
+              value *val=aggregateToPointer (valFromType(src));
+              int res=compareType (dest, val->type);
+              Safe_free(val->type);
+              Safe_free(val);
+              return res;
+            }
+          if (IS_PTR (dest) && IS_FUNC (dest->next) && IS_FUNC (src))
+            return compareType (dest->next, src);
+          return 0;
+        }
       else if (IS_PTR (dest) && IS_INTEGRAL (src))
-       return -1;
+        return -1;
       else
-       return 0;
+        return 0;
     }
 
+  if (IS_PTR (src) && IS_VOID (dest))
+    return -1;
+
   /* if one is a specifier and the other is not */
   if ((IS_SPEC (src) && !IS_SPEC (dest)) ||
       (IS_SPEC (dest) && !IS_SPEC (src)))
@@ -1595,32 +2163,216 @@ compareType (sym_link * dest, sym_link * src)
   if (SPEC_NOUN (dest) != SPEC_NOUN (src))
     {
       if (SPEC_USIGN (dest) == SPEC_USIGN (src) &&
-         IS_INTEGRAL (dest) && IS_INTEGRAL (src) &&
-         getSize (dest) == getSize (src))
-       return 1;
+          IS_INTEGRAL (dest) && IS_INTEGRAL (src) &&
+          /* I would prefer
+          bitsForType (dest) == bitsForType (src))
+             instead of the next two lines, but the regression tests fail with
+             them; I guess it's a problem with replaceCheaperOp  */
+          getSize (dest) == getSize (src) &&
+          (IS_BIT (dest) == IS_BIT (src)))
+        return 1;
       else if (IS_ARITHMETIC (dest) && IS_ARITHMETIC (src))
-       return -1;
+        return -1;
       else
-       return 0;
+        return 0;
     }
   else if (IS_STRUCT (dest))
     {
       if (SPEC_STRUCT (dest) != SPEC_STRUCT (src))
-       return 0;
+        return 0;
       else
-       return 1;
+        return 1;
     }
   if (SPEC_LONG (dest) != SPEC_LONG (src))
     return -1;
 
   if (SPEC_USIGN (dest) != SPEC_USIGN (src))
-    return -1;
+    return -2;
+
+  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          */
+/* inCalleeSaveList - return 1 if found in callee save list         */
 /*------------------------------------------------------------------*/
 static int
 calleeCmp(void *p1, void *p2)
@@ -1637,8 +2389,8 @@ inCalleeSaveList(char *s)
 }
 
 /*-----------------------------------------------------------------*/
-/* aggregateToPointer:  change an agggregate type function      */
-/*         argument to a pointer to that type.     */
+/* aggregateToPointer:     change an aggregate type function       */
+/*                         argument to a pointer to that type.     */
 /*-----------------------------------------------------------------*/
 value *
 aggregateToPointer (value * val)
@@ -1648,65 +2400,67 @@ aggregateToPointer (value * val)
       /* if this is a structure */
       /* then we need to add a new link */
       if (IS_STRUCT (val->type))
-       {
-         /* first lets add DECLARATOR type */
-         sym_link *p = val->type;
+        {
+          /* first lets add DECLARATOR type */
+          sym_link *p = val->type;
 
-         werror (W_STRUCT_AS_ARG, val->name);
-         val->type = newLink (DECLARATOR);
-         val->type->next = p;
-       }
+          werror (W_STRUCT_AS_ARG, val->name);
+          val->type = newLink (DECLARATOR);
+          val->type->next = p;
+        }
 
       /* change to a pointer depending on the */
       /* storage class specified        */
       switch (SPEC_SCLS (val->etype))
-       {
-       case S_IDATA:
-         DCL_TYPE (val->type) = IPOINTER;
-         break;
-       case S_PDATA:
-         DCL_TYPE (val->type) = PPOINTER;
-         break;
-       case S_FIXED:
-         if (SPEC_OCLS(val->etype)) {
-           DCL_TYPE(val->type)=PTR_TYPE(SPEC_OCLS(val->etype));
-         } else {
-           // this happens for (external) function parameters
-           DCL_TYPE (val->type) = port->unqualified_pointer;
-         }
-         break;
-       case S_AUTO:
-       case S_DATA:
-       case S_REGISTER:
-         DCL_TYPE (val->type) = POINTER;
-         break;
-       case S_CODE:
-         DCL_TYPE (val->type) = CPOINTER;
-         break;
-       case S_XDATA:
-         DCL_TYPE (val->type) = FPOINTER;
-         break;
-       case S_EEPROM:
-         DCL_TYPE (val->type) = EEPPOINTER;
-         break;
-       default:
-         DCL_TYPE (val->type) = port->unqualified_pointer;
-       }
-      
+        {
+        case S_IDATA:
+          DCL_TYPE (val->type) = IPOINTER;
+          break;
+        case S_PDATA:
+          DCL_TYPE (val->type) = PPOINTER;
+          break;
+        case S_FIXED:
+          if (SPEC_OCLS(val->etype)) {
+            DCL_TYPE(val->type)=PTR_TYPE(SPEC_OCLS(val->etype));
+          } else {
+            // this happens for (external) function parameters
+            DCL_TYPE (val->type) = port->unqualified_pointer;
+          }
+          break;
+        case S_AUTO:
+          DCL_TYPE (val->type) = PTR_TYPE(SPEC_OCLS(val->etype));
+          break;
+        case S_DATA:
+        case S_REGISTER:
+          DCL_TYPE (val->type) = POINTER;
+          break;
+        case S_CODE:
+          DCL_TYPE (val->type) = CPOINTER;
+          break;
+        case S_XDATA:
+          DCL_TYPE (val->type) = FPOINTER;
+          break;
+        case S_EEPROM:
+          DCL_TYPE (val->type) = EEPPOINTER;
+          break;
+        default:
+          DCL_TYPE (val->type) = port->unqualified_pointer;
+        }
+
       /* is there is a symbol associated then */
       /* change the type of the symbol as well */
       if (val->sym)
-       {
-         val->sym->type = copyLinkChain (val->type);
-         val->sym->etype = getSpec (val->sym->type);
-       }
+        {
+          val->sym->type = copyLinkChain (val->type);
+          val->sym->etype = getSpec (val->sym->type);
+        }
     }
   return val;
 }
 /*------------------------------------------------------------------*/
 /* checkFunction - does all kinds of check on a function            */
 /*------------------------------------------------------------------*/
-int 
+int
 checkFunction (symbol * sym, symbol *csym)
 {
   value *exargs, *acargs;
@@ -1717,6 +2471,19 @@ 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;
+    }
+
+  /* move inline specifier from return type to function attributes */
+  if (IS_INLINE (sym->etype))
+    {
+      SPEC_INLINE (sym->etype) = 0;
+      FUNC_ISINLINE (sym->type) = 1;
+    }
+
   /* make sure the type is complete and sane */
   checkTypeSanity(((symbol *)sym)->etype, ((symbol *)sym)->name);
 
@@ -1735,13 +2502,6 @@ checkFunction (symbol * sym, symbol *csym)
       return 0;
     }
 
-  /* function cannot return bit */
-  if (IS_BITVAR (sym->type->next))
-    {
-      werror (E_FUNC_BIT, sym->name);
-      return 0;
-    }
-
   /* check if this function is defined as calleeSaves
      then mark it as such */
   FUNC_CALLEESAVES(sym->type) = inCalleeSaveList (sym->name);
@@ -1751,15 +2511,20 @@ checkFunction (symbol * sym, symbol *csym)
   if (IFFUNC_ARGS(sym->type) && FUNC_ISISR (sym->type))
     {
       if (!IS_VOID(FUNC_ARGS(sym->type)->type)) {
-       werror (E_INT_ARGS, sym->name);
-       FUNC_ARGS(sym->type)=NULL;
+        werror (E_INT_ARGS, sym->name);
+        FUNC_ARGS(sym->type)=NULL;
       }
     }
 
-  for (argCnt=1, acargs = FUNC_ARGS(sym->type); 
-       acargs; 
+  if (IFFUNC_ISSHADOWREGS(sym->type) && !FUNC_ISISR (sym->type))
+    {
+      werror (E_SHADOWREGS_NO_ISR, sym->name);
+    }
+
+  for (argCnt=1, acargs = FUNC_ARGS(sym->type);
+       acargs;
        acargs=acargs->next, argCnt++) {
-    if (!acargs->sym) { 
+    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
@@ -1770,15 +2535,18 @@ checkFunction (symbol * sym, symbol *csym)
       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) { 
+    } else if (strcmp(acargs->sym->name, acargs->sym->rname)==0) {
       // synthesized name
       werror(E_PARAM_NAME_OMITTED, sym->name, argCnt);
     }
   }
   argCnt--;
 
+  /*JCF: Mark the register bank as used*/
+  RegBankUsed[FUNC_REGBANK (sym->type)] = 1;
+
   if (!csym && !(csym = findSym (SymbolTab, sym, sym->name)))
-    return 1;                  /* not defined nothing more to check  */
+    return 1;                   /* not defined nothing more to check  */
 
   /* check if body already present */
   if (csym && IFFUNC_HASBODY(csym->type))
@@ -1800,7 +2568,10 @@ checkFunction (symbol * sym, symbol *csym)
       werror (E_PREV_DEF_CONFLICT, csym->name, "interrupt");
     }
 
-  if (FUNC_REGBANK (csym->type) != FUNC_REGBANK (sym->type))
+  /* I don't think this is necessary for interrupts. An isr is a  */
+  /* root in the calling tree.                                    */
+  if ((FUNC_REGBANK (csym->type) != FUNC_REGBANK (sym->type)) &&
+      (!FUNC_ISISR (sym->type)))
     {
       werror (E_PREV_DEF_CONFLICT, csym->name, "using");
     }
@@ -1809,7 +2580,7 @@ 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       */
@@ -1821,6 +2592,17 @@ checkFunction (symbol * sym, symbol *csym)
       werror (E_PREV_DEF_CONFLICT, csym->name, "reentrant");
     }
 
+  if (IFFUNC_ISWPARAM (csym->type) != IFFUNC_ISWPARAM (sym->type))
+    {
+      werror (E_PREV_DEF_CONFLICT, csym->name, "wparam");
+    }
+
+  if (IFFUNC_ISSHADOWREGS (csym->type) != IFFUNC_ISSHADOWREGS (sym->type))
+    {
+      werror (E_PREV_DEF_CONFLICT, csym->name, "shadowregs");
+    }
+
+
   /* compare expected args with actual args */
   exargs = FUNC_ARGS(csym->type);
   acargs = FUNC_ARGS(sym->type);
@@ -1831,7 +2613,7 @@ checkFunction (symbol * sym, symbol *csym)
        exargs = exargs->next, acargs = acargs->next, argCnt++)
     {
       if (getenv("DEBUG_SANITY")) {
-       fprintf (stderr, "checkFunction: %s ", exargs->name);
+        fprintf (stderr, "checkFunction: %s ", exargs->name);
       }
       /* make sure the type is complete and sane */
       checkTypeSanity(exargs->etype, exargs->name);
@@ -1841,21 +2623,21 @@ checkFunction (symbol * sym, symbol *csym)
        * change here.
        */
       if (IS_AGGREGATE (acargs->type))
-       {
-         checkValue = copyValue (acargs);
-         aggregateToPointer (checkValue);
-       }
+        {
+          checkValue = copyValue (acargs);
+          aggregateToPointer (checkValue);
+        }
       else
-       {
-         checkValue = acargs;
-       }
+        {
+          checkValue = acargs;
+        }
 
       if (compareType (exargs->type, checkValue->type) <= 0)
-       {
-         werror (E_ARG_TYPE, argCnt);
-         printFromToType(exargs->type, checkValue->type);
-         return 0;
-       }
+        {
+          werror (E_ARG_TYPE, argCnt);
+          printFromToType(exargs->type, checkValue->type);
+          return 0;
+        }
     }
 
   /* if one them ended we have a problem */
@@ -1889,20 +2671,36 @@ void cdbStructBlock (int block)
   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);
-           }
-       }
+        {
+          if (chain->block >= block)
+            {
+              if(debugFile)
+                debugFile->writeType((structdef *)chain->sym, chain->block, 0, NULL);
+            }
+        }
+    }
+}
+
+/*-----------------------------------------------------------------*/
+/* processFuncPtrArgs - does some processing with args of func ptrs*/
+/*-----------------------------------------------------------------*/
+void
+processFuncPtrArgs (sym_link * funcType)
+{
+  value *val = FUNC_ARGS(funcType);
+
+  /* if it is void then remove parameters */
+  if (val && IS_VOID (val->type))
+    {
+      FUNC_ARGS(funcType) = NULL;
+      return;
     }
 }
 
 /*-----------------------------------------------------------------*/
 /* processFuncArgs - does some processing with function args       */
 /*-----------------------------------------------------------------*/
-void 
+void
 processFuncArgs (symbol * func)
 {
   value *val;
@@ -1912,10 +2710,9 @@ 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    */
@@ -1938,27 +2735,33 @@ processFuncArgs (symbol * func)
 
   /* reset regparm for the port */
   (*port->reset_regparms) ();
+
   /* if any of the arguments is an aggregate */
   /* change it to pointer to the same type */
   while (val)
     {
-       int argreg = 0;
+      int argreg = 0;
+      char buffer[SDCC_NAME_MAX+1];
+
+      SNPRINTF (buffer, sizeof(buffer), "%s parameter %d", func->name, pNum);
+      checkTypeSanity (val->etype, buffer);
+
       /* mark it as a register parameter if
          the function does not have VA_ARG
          and as port dictates */
       if (!IFFUNC_HASVARARGS(funcType) &&
-         (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;
-       }
+          (argreg = (*port->reg_parm) (val->type, FUNC_ISREENT(funcType))))
+        {
+          SPEC_REGPARM (val->etype) = 1;
+          SPEC_ARGREG(val->etype) = argreg;
+        } else if (IFFUNC_ISREENT(funcType)) {
+            FUNC_HASSTACKPARM(funcType) = 1;
+        }
 
       if (IS_AGGREGATE (val->type))
-       {
-         aggregateToPointer (val);
-       }
+        {
+          aggregateToPointer (val);
+        }
 
       val = val->next;
       pNum++;
@@ -1986,38 +2789,53 @@ processFuncArgs (symbol * func)
       /* if a symbolname is not given  */
       /* synthesize a variable name */
       if (!val->sym)
-       {
-         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;
-         strncpyz (val->sym->rname, val->name, sizeof(val->sym->rname));
-         if (IS_SPEC(func->etype)) {
-           SPEC_STAT (val->etype) = SPEC_STAT (val->sym->etype) =
-             SPEC_STAT (func->etype);
-         }
-         addSymChain (val->sym);
-
-       }
-      else                     /* symbol name given create synth 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);
-         if (IS_SPEC(func->etype)) {
-           SPEC_STAT (val->etype) = SPEC_STAT (val->sym->etype) =
-             SPEC_STAT (func->etype);
-         }
-       }
+        {
+          SNPRINTF (val->name, sizeof(val->name),
+                    "_%s_PARM_%d", func->name, pNum++);
+          val->sym = newSymbol (val->name, 1);
+          if (SPEC_SCLS(val->etype) == S_BIT)
+            SPEC_OCLS (val->etype) = bit;
+          else
+            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;
+          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 */
+        {
+
+          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;
+          if (SPEC_SCLS(val->etype) == S_BIT)
+            SPEC_OCLS (val->etype) = SPEC_OCLS (val->sym->etype) = bit;
+          else
+            SPEC_OCLS (val->etype) = SPEC_OCLS (val->sym->etype) =
+              port->mem.default_local_map;
+
+          #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 (SPEC_OCLS (val->sym->etype) == pdata)
+        val->sym->iaccess = 1;
       if (!isinSet(operKeyReset, val->sym)) {
-       addSet (&operKeyReset, val->sym);
-       applyToSet (operKeyReset, resetParmKey);
+        addSet (&operKeyReset, val->sym);
+        applyToSet (operKeyReset, resetParmKey);
       }
       val = val->next;
     }
@@ -2026,7 +2844,7 @@ processFuncArgs (symbol * func)
 /*-----------------------------------------------------------------*/
 /* isSymbolEqual - compares two symbols return 1 if they match     */
 /*-----------------------------------------------------------------*/
-int 
+int
 isSymbolEqual (symbol * dest, symbol * src)
 {
   /* if pointers match then equal */
@@ -2047,7 +2865,7 @@ isSymbolEqual (symbol * dest, symbol * src)
 
 void PT(sym_link *type)
 {
-       printTypeChain(type,0);
+        printTypeChain(type,0);
 }
 /*-----------------------------------------------------------------*/
 /* printTypeChain - prints the type chain in human readable form   */
@@ -2055,10 +2873,8 @@ void PT(sym_link *type)
 void
 printTypeChain (sym_link * start, FILE * of)
 {
+  struct dbuf_s dbuf;
   int nlr = 0;
-  value *args;
-  sym_link * type, * search;
-  STORAGE_CLASS scls;
 
   if (!of)
     {
@@ -2066,8 +2882,23 @@ printTypeChain (sym_link * start, FILE * of)
       nlr = 1;
     }
 
+  dbuf_init (&dbuf, 1024);
+  dbuf_printTypeChain (start, &dbuf);
+  dbuf_write_and_destroy (&dbuf, of);
+
+  if (nlr)
+    putc ('\n', of);
+}
+
+void
+dbuf_printTypeChain (sym_link * start, struct dbuf_s *dbuf)
+{
+  value *args;
+  sym_link * type, * search;
+  STORAGE_CLASS scls;
+
   if (start==NULL) {
-    fprintf (of, "void");
+    dbuf_append_str (dbuf, "void");
     return;
   }
 
@@ -2085,145 +2916,150 @@ printTypeChain (sym_link * start, FILE * of)
   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;
-         }
+        switch (scls)
+          {
+          case S_DATA: dbuf_append_str (dbuf, "data-"); break;
+          case S_XDATA: dbuf_append_str (dbuf, "xdata-"); break;
+          case S_SFR: dbuf_append_str (dbuf, "sfr-"); break;
+          case S_SBIT: dbuf_append_str (dbuf, "sbit-"); break;
+          case S_CODE: dbuf_append_str (dbuf, "code-"); break;
+          case S_IDATA: dbuf_append_str (dbuf, "idata-"); break;
+          case S_PDATA: dbuf_append_str (dbuf, "pdata-"); break;
+          case S_LITERAL: dbuf_append_str (dbuf, "literal-"); break;
+          case S_STACK: dbuf_append_str (dbuf, "stack-"); break;
+          case S_XSTACK: dbuf_append_str (dbuf, "xstack-"); break;
+          case S_BIT: dbuf_append_str (dbuf, "bit-"); break;
+          case S_EEPROM: dbuf_append_str (dbuf, "eeprom-"); break;
+          default: break;
+          }
       }
 
       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, "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, "generic* ");
-             break;
-           case CPOINTER:
-             fprintf (of, "code* ");
-             break;
-           case FPOINTER:
-             fprintf (of, "xdata* ");
-             break;
-           case EEPPOINTER:
-             fprintf (of, "eeprom* ");
-             break;
-           case POINTER:
-             fprintf (of, "near* ");
-             break;
-           case IPOINTER:
-             fprintf (of, "idata* ");
-             break;
-           case PPOINTER:
-             fprintf (of, "pdata* ");
-             break;
-           case UPOINTER:
-             fprintf (of, "unknown* ");
-             break;
-           case ARRAY:
-             if (DCL_ELEM(type)) {
-               fprintf (of, "[%d] ", DCL_ELEM(type));
-             } else {
-               fprintf (of, "[] ");
-             }
-             break;
-           }
-       }
+        {
+          if (!IS_FUNC(type)) {
+            if (DCL_PTR_VOLATILE (type)) {
+              dbuf_append_str (dbuf, "volatile-");
+            }
+            if (DCL_PTR_CONST (type)) {
+              dbuf_append_str (dbuf, "const-");
+            }
+            if (DCL_PTR_RESTRICT (type)) {
+              dbuf_append_str (dbuf, "restrict-");
+            }
+          }
+          switch (DCL_TYPE (type))
+            {
+            case FUNCTION:
+              dbuf_printf (dbuf, "function %s %s",
+                       (IFFUNC_ISBUILTIN(type) ? "__builtin__" : " "),
+                       (IFFUNC_ISJAVANATIVE(type) ? "_JavaNative" : " "));
+              dbuf_append_str (dbuf, "( ");
+              for (args = FUNC_ARGS(type);
+                   args;
+                   args=args->next) {
+                dbuf_printTypeChain(args->type, dbuf);
+                if (args->next)
+                  dbuf_append_str (dbuf, ", ");
+              }
+              dbuf_append_str (dbuf, ") ");
+              break;
+            case GPOINTER:
+              dbuf_append_str (dbuf, "generic* ");
+              break;
+            case CPOINTER:
+              dbuf_append_str (dbuf, "code* ");
+              break;
+            case FPOINTER:
+              dbuf_append_str (dbuf, "xdata* ");
+              break;
+            case EEPPOINTER:
+              dbuf_append_str (dbuf, "eeprom* ");
+              break;
+            case POINTER:
+              dbuf_append_str (dbuf, "near* ");
+              break;
+            case IPOINTER:
+              dbuf_append_str (dbuf, "idata* ");
+              break;
+            case PPOINTER:
+              dbuf_append_str (dbuf, "pdata* ");
+              break;
+            case UPOINTER:
+              dbuf_append_str (dbuf, "unknown* ");
+              break;
+            case ARRAY:
+              if (DCL_ELEM(type)) {
+                dbuf_printf (dbuf, "[%d] ", DCL_ELEM(type));
+              } else {
+                dbuf_append_str (dbuf, "[] ");
+              }
+              break;
+            }
+        }
       else
-       {
-         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, "long-");
-             fprintf (of, "int");
-             break;
-
-           case V_CHAR:
-             fprintf (of, "char");
-             break;
-
-           case V_VOID:
-             fprintf (of, "void");
-             break;
-
-           case V_FLOAT:
-             fprintf (of, "float");
-             break;
-
-           case V_STRUCT:
-             fprintf (of, "struct %s", SPEC_STRUCT (type)->tag);
-             break;
-
-           case V_SBIT:
-             fprintf (of, "sbit");
-             break;
-
-           case V_BIT:
-             fprintf (of, "bit");
-             break;
-
-           case V_BITFIELD:
-             fprintf (of, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
-             break;
-
-           case V_DOUBLE:
-             fprintf (of, "double");
-             break;
-
-           default:
-             fprintf (of, "unknown type");
-             break;
-           }
-       }
+        {
+          if (SPEC_VOLATILE (type))
+            dbuf_append_str (dbuf, "volatile-");
+          if (SPEC_CONST (type))
+            dbuf_append_str (dbuf, "const-");
+          if (SPEC_USIGN (type))
+            dbuf_append_str (dbuf, "unsigned-");
+          switch (SPEC_NOUN (type))
+            {
+            case V_INT:
+              if (IS_LONG (type))
+                dbuf_append_str (dbuf, "long-");
+              dbuf_append_str (dbuf, "int");
+              break;
+
+            case V_CHAR:
+              dbuf_append_str (dbuf, "char");
+              break;
+
+            case V_VOID:
+              dbuf_append_str (dbuf, "void");
+              break;
+
+            case V_FLOAT:
+              dbuf_append_str (dbuf, "float");
+              break;
+
+            case V_FIXED16X16:
+              dbuf_append_str (dbuf, "fixed16x16");
+              break;
+
+            case V_STRUCT:
+              dbuf_printf (dbuf, "struct %s", SPEC_STRUCT (type)->tag);
+              break;
+
+            case V_SBIT:
+              dbuf_append_str (dbuf, "sbit");
+              break;
+
+            case V_BIT:
+              dbuf_append_str (dbuf, "bit");
+              break;
+
+            case V_BITFIELD:
+              dbuf_printf (dbuf, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
+              break;
+
+            case V_DOUBLE:
+              dbuf_append_str (dbuf, "double");
+              break;
+
+            default:
+              dbuf_append_str (dbuf, "unknown type");
+              break;
+            }
+        }
       /* search entry in list before "type" */
       for (search = start; search && search->next != type;)
-       search = search->next;
+        search = search->next;
       type = search;
       if (type)
-       fputc (' ', of);
+          dbuf_append_char(dbuf, ' ');
     }
-  if (nlr)
-    fprintf (of, "\n");
 }
 
 /*--------------------------------------------------------------------*/
@@ -2249,148 +3085,158 @@ printTypeChainRaw (sym_link * start, FILE * of)
   }
 
   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, "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, "generic* ");
-             break;
-           case CPOINTER:
-             fprintf (of, "code* ");
-             break;
-           case FPOINTER:
-             fprintf (of, "xdata* ");
-             break;
-           case EEPPOINTER:
-             fprintf (of, "eeprom* ");
-             break;
-           case POINTER:
-             fprintf (of, "near* ");
-             break;
-           case IPOINTER:
-             fprintf (of, "idata* ");
-             break;
-           case PPOINTER:
-             fprintf (of, "pdata* ");
-             break;
-           case UPOINTER:
-             fprintf (of, "unknown* ");
-             break;
-           case ARRAY:
-             if (DCL_ELEM(type)) {
-               fprintf (of, "[%d] ", DCL_ELEM(type));
-             } else {
-               fprintf (of, "[] ");
-             }
-             break;
-           }
+        {
+          if (!IS_FUNC(type)) {
+            if (DCL_PTR_VOLATILE (type)) {
+              fprintf (of, "volatile-");
+            }
+            if (DCL_PTR_CONST (type)) {
+              fprintf (of, "const-");
+            }
+            if (DCL_PTR_RESTRICT (type)) {
+              fprintf (of, "restrict-");
+            }
+          }
+          switch (DCL_TYPE (type))
+            {
+            case FUNCTION:
+              if (IFFUNC_ISINLINE(type)) {
+                fprintf (of, "inline-");
+              }
+              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, "generic* ");
+              break;
+            case CPOINTER:
+              fprintf (of, "code* ");
+              break;
+            case FPOINTER:
+              fprintf (of, "xdata* ");
+              break;
+            case EEPPOINTER:
+              fprintf (of, "eeprom* ");
+              break;
+            case POINTER:
+              fprintf (of, "near* ");
+              break;
+            case IPOINTER:
+              fprintf (of, "idata* ");
+              break;
+            case PPOINTER:
+              fprintf (of, "pdata* ");
+              break;
+            case UPOINTER:
+              fprintf (of, "unknown* ");
+              break;
+            case ARRAY:
+              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 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, "long-");
-             fprintf (of, "int");
-             break;
-
-           case V_CHAR:
-             fprintf (of, "char");
-             break;
-
-           case V_VOID:
-             fprintf (of, "void");
-             break;
-
-           case V_FLOAT:
-             fprintf (of, "float");
-             break;
-
-           case V_STRUCT:
-             fprintf (of, "struct %s", SPEC_STRUCT (type)->tag);
-             break;
-
-           case V_SBIT:
-             fprintf (of, "sbit");
-             break;
-
-           case V_BIT:
-             fprintf (of, "bit");
-             break;
-
-           case V_BITFIELD:
-             fprintf (of, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
-             break;
-
-           case V_DOUBLE:
-             fprintf (of, "double");
-             break;
-
-           default:
-             fprintf (of, "unknown type");
-             break;
-           }
-       }
+        {
+        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, "long-");
+              fprintf (of, "int");
+              break;
+
+            case V_CHAR:
+              fprintf (of, "char");
+              break;
+
+            case V_VOID:
+              fprintf (of, "void");
+              break;
+
+            case V_FLOAT:
+              fprintf (of, "float");
+              break;
+
+            case V_FIXED16X16:
+              fprintf (of, "fixed16x16");
+              break;
+
+            case V_STRUCT:
+              fprintf (of, "struct %s", SPEC_STRUCT (type)->tag);
+              break;
+
+            case V_SBIT:
+              fprintf (of, "sbit");
+              break;
+
+            case V_BIT:
+              fprintf (of, "bit");
+              break;
+
+            case V_BITFIELD:
+              fprintf (of, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
+              break;
+
+            case V_DOUBLE:
+              fprintf (of, "double");
+              break;
+
+            default:
+              fprintf (of, "unknown type");
+              break;
+            }
+        }
       else
         fprintf (of, "NOT_SPEC_OR_DECL");
       type = type->next;
       if (type)
-       fputc (' ', of);
+        fputc (' ', of);
     }
   if (nlr)
     fprintf (of, "\n");
@@ -2400,8 +3246,8 @@ printTypeChainRaw (sym_link * start, FILE * of)
 /*-----------------------------------------------------------------*/
 /* powof2 - returns power of two for the number if number is pow 2 */
 /*-----------------------------------------------------------------*/
-int 
-powof2 (unsigned long num)
+int
+powof2 (TYPE_TARGET_ULONG num)
 {
   int nshifts = 0;
   int n1s = 0;
@@ -2409,13 +3255,13 @@ powof2 (unsigned long num)
   while (num)
     {
       if (num & 1)
-       n1s++;
+        n1s++;
       num >>= 1;
       nshifts++;
     }
 
   if (n1s > 1 || nshifts == 0)
-    return 0;
+    return -1;
   return nshifts - 1;
 }
 
@@ -2430,21 +3276,35 @@ symbol *__fslteq;
 symbol *__fsgt;
 symbol *__fsgteq;
 
-/* Dims: mul/div/mod, BYTE/WORD/DWORD, SIGNED/UNSIGNED */
-symbol *__muldiv[3][3][2];
+symbol *__fps16x16_add;
+symbol *__fps16x16_sub;
+symbol *__fps16x16_mul;
+symbol *__fps16x16_div;
+symbol *__fps16x16_eq;
+symbol *__fps16x16_neq;
+symbol *__fps16x16_lt;
+symbol *__fps16x16_lteq;
+symbol *__fps16x16_gt;
+symbol *__fps16x16_gteq;
+
+/* Dims: mul/div/mod, BYTE/WORD/DWORD, SIGNED/UNSIGNED/BOTH */
+symbol *__muldiv[3][3][4];
 /* Dims: BYTE/WORD/DWORD SIGNED/UNSIGNED */
 sym_link *__multypes[3][2];
 /* Dims: to/from float, BYTE/WORD/DWORD, SIGNED/USIGNED */
 symbol *__conv[2][3][2];
+/* Dims: to/from fixed16x16, BYTE/WORD/DWORD/FLOAT, SIGNED/USIGNED */
+symbol *__fp16x16conv[2][4][2];
 /* Dims: shift left/shift right, BYTE/WORD/DWORD, SIGNED/UNSIGNED */
 symbol *__rlrr[2][3][2];
 
 sym_link *floatType;
+sym_link *fixed16x16Type;
 
 static char *
 _mangleFunctionName(char *in)
 {
-  if (port->getMangledFunctionName) 
+  if (port->getMangledFunctionName)
     {
       return port->getMangledFunctionName(in);
     }
@@ -2456,20 +3316,21 @@ _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)        */
+/* basic types -        'c' - char                                 */
+/*                      's' - short                                */
+/*                      'i' - int                                  */
+/*                      'l' - long                                 */
+/*                      'f' - float                                */
+/*                      'q' - fixed16x16                           */
+/*                      'v' - void                                 */
+/*                      '*' - pointer - default (GPOINTER)         */
 /* modifiers -          'u' - unsigned                             */
 /* pointer modifiers -  'g' - generic                              */
 /*                      'x' - xdata                                */
 /*                      'p' - code                                 */
-/*                      'd' - data                                 */                     
-/*                      'F' - function                             */                     
-/* examples : "ig*" - generic int *                               */
+/*                      'd' - data                                 */
+/*                      'F' - function                             */
+/* examples : "ig*" - generic int *                                */
 /*            "cx*" - char xdata *                                 */
 /*            "ui" -  unsigned int                                 */
 /*-----------------------------------------------------------------*/
@@ -2479,80 +3340,84 @@ sym_link *typeFromStr (char *s)
     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++;
+        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 'q':
+            r->class = SPECIFIER;
+            SPEC_NOUN(r) = V_FIXED16X16;
+            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;
 }
@@ -2560,7 +3425,7 @@ sym_link *typeFromStr (char *s)
 /*-----------------------------------------------------------------*/
 /* initCSupport - create functions for C support routines          */
 /*-----------------------------------------------------------------*/
-void 
+void
 initCSupport ()
 {
   const char *smuldivmod[] =
@@ -2569,11 +3434,15 @@ initCSupport ()
   };
   const char *sbwd[] =
   {
-    "char", "int", "long"
+    "char", "int", "long", "fixed16x16",
+  };
+  const char *fp16x16sbwd[] =
+  {
+    "char", "int", "long", "float",
   };
   const char *ssu[] =
   {
-    "s", "u"
+    "s", "su", "us", "u"
   };
   const char *srlrr[] =
   {
@@ -2588,24 +3457,25 @@ initCSupport ()
   }
 
   floatType = newFloatLink ();
+  fixed16x16Type = newFixed16x16Link ();
 
   for (bwd = 0; bwd < 3; bwd++)
     {
       sym_link *l = NULL;
       switch (bwd)
-       {
-       case 0:
-         l = newCharLink ();
-         break;
-       case 1:
-         l = newIntLink ();
-         break;
-       case 2:
-         l = newLongLink ();
-         break;
-       default:
-         assert (0);
-       }
+        {
+        case 0:
+          l = newCharLink ();
+          break;
+        case 1:
+          l = newIntLink ();
+          break;
+        case 2:
+          l = newLongLink ();
+          break;
+        default:
+          assert (0);
+        }
       __multypes[bwd][0] = l;
       __multypes[bwd][1] = copyLinkChain (l);
       SPEC_USIGN (__multypes[bwd][1]) = 1;
@@ -2622,81 +3492,165 @@ initCSupport ()
   __fsgt = funcOfType ("__fsgt", CHARTYPE, floatType, 2, options.float_rent);
   __fsgteq = funcOfType ("__fsgteq", CHARTYPE, floatType, 2, options.float_rent);
 
+  __fps16x16_add = funcOfType ("__fps16x16_add", fixed16x16Type, fixed16x16Type, 2, options.float_rent);
+  __fps16x16_sub = funcOfType ("__fps16x16_sub", fixed16x16Type, fixed16x16Type, 2, options.float_rent);
+  __fps16x16_mul = funcOfType ("__fps16x16_mul", fixed16x16Type, fixed16x16Type, 2, options.float_rent);
+  __fps16x16_div = funcOfType ("__fps16x16_div", fixed16x16Type, fixed16x16Type, 2, options.float_rent);
+  __fps16x16_eq = funcOfType ("__fps16x16_eq", CHARTYPE, fixed16x16Type, 2, options.float_rent);
+  __fps16x16_neq = funcOfType ("__fps16x16_neq", CHARTYPE, fixed16x16Type, 2, options.float_rent);
+  __fps16x16_lt = funcOfType ("__fps16x16_lt", CHARTYPE, fixed16x16Type, 2, options.float_rent);
+  __fps16x16_lteq = funcOfType ("__fps16x16_lteq", CHARTYPE, fixed16x16Type, 2, options.float_rent);
+  __fps16x16_gt = funcOfType ("__fps16x16_gt", CHARTYPE, fixed16x16Type, 2, options.float_rent);
+  __fps16x16_gteq = funcOfType ("__fps16x16_gteq", CHARTYPE, fixed16x16Type, 2, options.float_rent);
+
+
   for (tofrom = 0; tofrom < 2; tofrom++)
     {
       for (bwd = 0; bwd < 3; bwd++)
-       {
-         for (su = 0; su < 2; su++)
-           {
-             if (tofrom)
-               {
-                 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
-               {
-                 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 (su = 0; su < 2; su++)
+            {
+              if (tofrom)
+                {
+                  SNPRINTF (buffer, sizeof(buffer), "__fs2%s%s", ssu[su*3], sbwd[bwd]);
+                  __conv[tofrom][bwd][su] = funcOfType (buffer, __multypes[bwd][su], floatType, 1, options.float_rent);
+                }
+              else
+                {
+                  SNPRINTF (buffer, sizeof(buffer), "__%s%s2fs", ssu[su*3], sbwd[bwd]);
+                  __conv[tofrom][bwd][su] = funcOfType (buffer, floatType, __multypes[bwd][su], 1, options.float_rent);
+                }
+            }
+        }
+    }
+
+  for (tofrom = 0; tofrom < 2; tofrom++)
+    {
+      for (bwd = 0; bwd < 4; bwd++)
+        {
+          for (su = 0; su < 2; su++)
+            {
+              if (tofrom)
+                {
+                  SNPRINTF (buffer, sizeof(buffer), "__fps16x162%s%s", ssu[su*3], fp16x16sbwd[bwd]);
+                  if(bwd == 3) {
+                    __fp16x16conv[tofrom][bwd][su] = funcOfType (buffer, floatType, fixed16x16Type, 1, options.float_rent);
+                  } else
+                    __fp16x16conv[tofrom][bwd][su] = funcOfType (buffer, __multypes[bwd][su], fixed16x16Type, 1, options.float_rent);
+                }
+              else
+                {
+                  SNPRINTF (buffer, sizeof(buffer), "__%s%s2fps16x16", ssu[su*3], fp16x16sbwd[bwd]);
+                  if(bwd == 3) {
+                    __fp16x16conv[tofrom][bwd][su] = funcOfType (buffer, fixed16x16Type, floatType, 1, options.float_rent);
+                  } else
+                    __fp16x16conv[tofrom][bwd][su] = funcOfType (buffer, fixed16x16Type, __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++)
-           {
-             SNPRINTF (buffer, sizeof(buffer),
-                       "_%s%s%s",
-                      smuldivmod[muldivmod],
-                      ssu[su],
-                      sbwd[bwd]);
+        {
+          for (su = 0; su < 2; su++)
+            {
+              SNPRINTF (buffer, sizeof(buffer),
+                        "_%s%s%s",
+                       smuldivmod[muldivmod],
+                       ssu[su*3],
+                       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;
-           }
-       }
+              FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
+            }
+        }
     }
 
   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++)
+  for (su = 0; su < 4; su++)
+    {
+      for (muldivmod = 0; muldivmod < 3; muldivmod++)
+        {
+          /* muluchar, mulschar, mulsuchar and muluschar are separate functions, because e.g. the z80
+             port is sign/zero-extending to int before calling mulint() */
+          /* div and mod : s8_t x s8_t -> s8_t should be s8_t x s8_t -> s16_t, see below */
+          if (!TARGET_IS_PIC16 || muldivmod != 1 || su != 0)
+            {
+              SNPRINTF (buffer, sizeof(buffer),
+                  "_%s%s%s",
+                  smuldivmod[muldivmod],
+                  ssu[su],
+                  sbwd[bwd]);
+              __muldiv[muldivmod][bwd][su] = funcOfType (
+                  _mangleFunctionName(buffer),
+                  __multypes[bwd][su%2],
+                  __multypes[bwd][su/2],
+                  2,
+                  options.intlong_rent);
+              FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
+            }
+        }
+    }
+
+  for (bwd = 1; bwd < 3; bwd++)
     {
-      /* muluchar and mulschar are still separate functions, because e.g. the z80
-         port is sign/zero-extending to int before calling mulint() */
+      for (su = 0; su < 2; su++)
+        {
+          for (muldivmod = 1; muldivmod < 3; muldivmod++)
+            {
+              /* div and mod : s8_t x s8_t -> s8_t should be s8_t x s8_t -> s16_t, see below */
+              if (!TARGET_IS_PIC16 || muldivmod != 1 || bwd != 0 || su != 0)
+              {
+                SNPRINTF (buffer, sizeof(buffer),
+                    "_%s%s%s",
+                    smuldivmod[muldivmod],
+                    ssu[su*3],
+                    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;
+              }
+            }
+        }
+    }
+
+  if (TARGET_IS_PIC16)
+  {
+    /* PIC16 port wants __divschar/__modschar to return an int, so that both
+     * 100 / -4 = -25 and -128 / -1 = 128 can be handled correctly
+     * (first one would have to be sign extended, second one must not be).
+     * Similarly, modschar should be handled, but the iCode introduces cast
+     * here and forces '% : s8 x s8 -> s8' ... */
+    su = 0; bwd = 0;
+    for (muldivmod = 1; muldivmod < 2; muldivmod++) {
       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);
+          "_%s%s%s",
+          smuldivmod[muldivmod],
+          ssu[su],
+          sbwd[bwd]);
+      __muldiv[muldivmod][bwd][su] = funcOfType (
+          _mangleFunctionName(buffer),
+          __multypes[1][su],
+          __multypes[bwd][su],
+          2,
+          options.intlong_rent);
       FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
     }
+  }
+
+  /* mul only */
+  muldivmod = 0;
   /* signed only */
   su = 0;
   /* word and doubleword */
@@ -2704,9 +3658,9 @@ initCSupport ()
     {
       /* mul, int/long */
       SNPRINTF (buffer, sizeof(buffer),
-               "_%s%s",
-               smuldivmod[muldivmod],
-               sbwd[bwd]);
+                "_%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 */
@@ -2716,18 +3670,18 @@ initCSupport ()
   for (rlrr = 0; rlrr < 2; rlrr++)
     {
       for (bwd = 0; bwd < 3; bwd++)
-       {
-         for (su = 0; su < 2; su++)
-           {
-             SNPRINTF (buffer, sizeof(buffer),
-                       "_%s%s%s",
-                      srlrr[rlrr],
-                      ssu[su],
-                      sbwd[bwd]);
+        {
+          for (su = 0; su < 2; su++)
+            {
+              SNPRINTF (buffer, sizeof(buffer),
+                        "_%s%s%s",
+                       srlrr[rlrr],
+                       ssu[su*3],
+                       sbwd[bwd]);
               __rlrr[rlrr][bwd][su] = funcOfType (_mangleFunctionName(buffer), __multypes[bwd][su], __multypes[0][0], 2, options.intlong_rent);
-             FUNC_NONBANKED (__rlrr[rlrr][bwd][su]->type) = 1;
-           }
-       }
+              FUNC_NONBANKED (__rlrr[rlrr][bwd][su]->type) = 1;
+            }
+        }
     }
 }
 
@@ -2742,29 +3696,89 @@ void initBuiltIns()
     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 = 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)
-{    
+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;
+        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);
+    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(EXIT_FAILURE);
     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) ulFromVal (valFromType (sym->type));
+  for (sym = sym->next; sym; sym = sym->next)
+    {
+      v = (int) ulFromVal (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;
+}