* as/hc08/lkaomf51.c (OutputName),
[fw/sdcc] / src / SDCCsymt.c
index 35360f205052fbecca4a9b47538cd5220e1a60bc..e86314e249c577ce9def84216ca7f2ffca63735c 100644 (file)
@@ -24,6 +24,8 @@
 #include "common.h"
 #include "newalloc.h"
 
+#include "SDCCsymt.h"
+
 value *aggregateToPointer (value *val);
 void printTypeChainRaw (sym_link * start, FILE * of);
 
@@ -41,10 +43,11 @@ char *nounName(sym_link *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,11 +60,11 @@ 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             */
@@ -107,14 +110,14 @@ hashKey (const char *s)
 /*-----------------------------------------------------------------*/
 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 +140,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 */
@@ -173,25 +176,25 @@ 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;
     }
@@ -210,7 +213,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 +241,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 +274,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 +292,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 = mylineno;      /* set the line number */
+  sym->fileDef = currFname;
   return sym;
 }
 
@@ -320,7 +324,7 @@ 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;
 }
   
@@ -382,29 +386,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 +418,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 +427,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;
     }
 }
@@ -446,7 +450,7 @@ addDecl (symbol * sym, int type, sym_link * p)
     {
       tail = head = p;
       while (tail->next)
-       tail = tail->next;
+        tail = tail->next;
     }
   else
     {
@@ -463,25 +467,25 @@ addDecl (symbol * sym, int type, sym_link * p)
   else
     {
       if (IS_SPEC (sym->etype) && IS_SPEC (head) && head == tail)
-       {
-         sym->etype = mergeSpec (sym->etype, head, sym->name);
-       }
+        {
+          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;
-           }
-       }
+        {
+          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;
+            }
+        }
     }
 
   /* if the type is an unknown pointer and has
@@ -494,9 +498,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;
     }
@@ -538,24 +542,26 @@ void checkTypeSanity(sym_link *etype, char *name) {
 
   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_FIXED16X16 ||
        SPEC_NOUN(etype)==V_DOUBLE || 
        SPEC_NOUN(etype)==V_VOID) && 
-      (etype->select.s._signed || SPEC_USIGN(etype))) {
+      (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. 
@@ -565,11 +571,19 @@ void checkTypeSanity(sym_link *etype, char *name) {
     SPEC_NOUN(etype)=V_INT;
   }
 
-  if (etype->select.s._signed && SPEC_USIGN(etype)) {
+  /* 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,7 +613,7 @@ 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);
     }
@@ -611,7 +625,7 @@ mergeSpec (sym_link * dest, sym_link * src, char *name)
       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);
     }
@@ -631,9 +645,9 @@ 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_CONST(dest) |= SPEC_CONST (src);
@@ -724,6 +738,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,7 +782,21 @@ 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 
 getSize (sym_link * p)
@@ -763,41 +805,43 @@ getSize (sym_link * p)
   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 +851,7 @@ getSize (sym_link * p)
     case FPOINTER:
     case CPOINTER:
     case FUNCTION:
-      return (FPTRSIZE);
+      return (IFFUNC_BANKED (p) ? GPTRSIZE : FPTRSIZE);
     case GPOINTER:
       return (GPTRSIZE);
 
@@ -816,6 +860,43 @@ 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      */
 /*------------------------------------------------------------------*/
@@ -827,30 +908,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  */
@@ -969,43 +1052,97 @@ reverseLink (sym_link * type)
 /* addSymChain - adds a symbol chain to the symboltable             */
 /*------------------------------------------------------------------*/
 void 
-addSymChain (symbol * symHead)
+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 (!sym->level && !(IS_SPEC(sym->etype) && IS_TYPEDEF(sym->etype)))
+        checkDecl (sym, 0);
+      
       /* if already exists in the symbol table then check if
          one of them is an extern definition if yes then
          then check if the type match, if the types match then
          delete the current entry and add the new entry      */
       if ((csym = findSymWithLevel (SymbolTab, sym)) &&
-         csym->level == sym->level) {
-       
-       /* one definition extern ? */
-       if (IS_EXTERN (csym->etype) || IS_EXTERN (sym->etype)) {
-         /* do types match ? */
-         if (compareType (csym->type, sym->type) != 1) {
-           /* no then error */
-           werror (E_EXTERN_MISMATCH, csym->name);
-           continue;
-         }
-       } 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 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;
+
+        /* 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);
     }
@@ -1021,7 +1158,7 @@ funcInChain (sym_link * lnk)
   while (lnk)
     {
       if (IS_FUNC (lnk))
-       return 1;
+        return 1;
       lnk = lnk->next;
     }
   return 0;
@@ -1042,19 +1179,19 @@ structElemType (sym_link * stype, value * 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));
             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;
       }
   }
 
@@ -1095,94 +1232,190 @@ compStructSize (int su, structdef * sdef)
     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);
-       }
+        /* 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;
+            /* 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;
+
+            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 {
+                                       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);
+        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              */
 /*------------------------------------------------------------------*/
@@ -1195,8 +1428,7 @@ checkSClass (symbol * sym, int isProto)
     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;
   
@@ -1218,6 +1450,26 @@ 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,20 +1534,22 @@ 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 &&
@@ -1309,6 +1563,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,35 +1582,37 @@ 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) &&
+        !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);
+        }
     }
 }
 
@@ -1363,20 +1620,20 @@ checkSClass (symbol * sym, int isProto)
 /* changePointer - change pointer to functions                      */
 /*------------------------------------------------------------------*/
 void 
-changePointer (symbol * sym)
+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;
     }
 }
 
@@ -1387,8 +1644,8 @@ 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 +1663,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,7 +1677,6 @@ copyLinkChain (sym_link * p)
   return head;
 }
 
-
 /*------------------------------------------------------------------*/
 /* cleanUpBlock - cleansup the symbol table specified for all the   */
 /*                symbols in the given block                        */
@@ -1434,12 +1691,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);
+            }
+        }
     }
 }
 
@@ -1457,25 +1714,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 +1811,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 (type1);
+                          
+  /* 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,22 +1851,138 @@ 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_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;
 }
 
@@ -1541,33 +2005,46 @@ 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 compareType (dest->next, src->next);
+            }
+
+          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) ||
+               ((DCL_TYPE(src) == POINTER) && (DCL_TYPE(dest) == IPOINTER))
+             ))
+            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;
+        }
       else if (IS_PTR (dest) && IS_INTEGRAL (src))
-       return -1;
+        return -1;
       else
-       return 0;
+        return 0;
     }
 
   /* if one is a specifier and the other is not */
@@ -1595,20 +2072,25 @@ 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;
@@ -1619,6 +2101,185 @@ compareType (sym_link * dest, sym_link * src)
   return 1;
 }
 
+/*--------------------------------------------------------------------*/
+/* compareTypeExact - will do type check return 1 if match exactly    */
+/*--------------------------------------------------------------------*/
+int
+compareTypeExact (sym_link * dest, sym_link * src, int level)
+{
+  STORAGE_CLASS srcScls, destScls;
+  
+  if (!dest && !src)
+    return 1;
+
+  if (dest && !src)
+    return 0;
+
+  if (src && !dest)
+    return 0;
+
+  /* if dest is a declarator then */
+  if (IS_DECL (dest))
+    {
+      if (IS_DECL (src))
+        {
+          if (DCL_TYPE (src) == DCL_TYPE (dest)) {
+            if ((DCL_TYPE (src) == ARRAY) && (DCL_ELEM (src) != DCL_ELEM (dest)))
+              return 0;
+            if (DCL_PTR_CONST (src) != DCL_PTR_CONST (dest))
+              return 0;
+            if (DCL_PTR_VOLATILE (src) != DCL_PTR_VOLATILE (dest))
+              return 0;
+            if (IS_FUNC(src))
+              {
+                value *exargs, *acargs, *checkValue;
+
+                /* verify function return type */
+                if (!compareTypeExact (dest->next, src->next, -1))
+                  return 0;
+                if (FUNC_ISISR (dest) != FUNC_ISISR (src))
+                  return 0;
+                if (FUNC_REGBANK (dest) != FUNC_REGBANK (src))
+                  return 0;
+                if (IFFUNC_ISNAKED (dest) != IFFUNC_ISNAKED (src))
+                  return 0;
+                #if 0
+                if (IFFUNC_ISREENT (dest) != IFFUNC_ISREENT (src) && argCnt>1)
+                  return 0;
+                #endif
+
+                /* compare expected args with actual args */
+                exargs = FUNC_ARGS(dest);
+                acargs = FUNC_ARGS(src);
+
+                /* for all the expected args do */
+                for (; exargs && acargs; exargs = exargs->next, acargs = acargs->next)
+                  {
+                    //checkTypeSanity(acargs->etype, acargs->name);
+
+                    if (IS_AGGREGATE (acargs->type))
+                      {
+                        checkValue = copyValue (acargs);
+                        aggregateToPointer (checkValue);
+                      }
+                    else
+                      checkValue = acargs;
+
+                    #if 0
+                    if (!compareTypeExact (exargs->type, checkValue->type, -1))
+                      return 0;
+                    #endif
+                  }
+
+                  /* if one them ended we have a problem */
+                  if ((exargs && !acargs && !IS_VOID (exargs->type)) ||
+                      (!exargs && acargs && !IS_VOID (acargs->type)))
+                    return 0;                  
+                  return 1;
+              }
+            return compareTypeExact (dest->next, src->next, level);
+          }
+          return 0;
+        }
+      return 0;
+    }
+
+  /* if one is a specifier and the other is not */
+  if ((IS_SPEC (src) && !IS_SPEC (dest)) ||
+      (IS_SPEC (dest) && !IS_SPEC (src)))
+    return 0;
+
+  /* if one of them is a void then ok */
+  if (SPEC_NOUN (dest) != SPEC_NOUN (src))
+    return 0;
+
+  /* if they are both bitfields then if the lengths
+     and starts don't match */
+  if (IS_BITFIELD (dest) && IS_BITFIELD (src) &&
+      (SPEC_BLEN (dest) != SPEC_BLEN (src) ||
+       SPEC_BSTR (dest) != SPEC_BSTR (src)))
+    return 0;
+
+  if (IS_INTEGRAL (dest))
+    {
+      /* signedness must match */
+      if (SPEC_USIGN (dest) != SPEC_USIGN (src))
+        return 0;
+      /* size must match */
+      if (SPEC_LONG (dest) != SPEC_LONG (src))
+        return 0;
+      if (SPEC_SHORT (dest) != SPEC_SHORT (src))
+        return 0;
+    }
+  
+  if (IS_STRUCT (dest))
+    {
+      if (SPEC_STRUCT (dest) != SPEC_STRUCT (src))
+        return 0;
+    }
+
+  if (SPEC_CONST (dest) != SPEC_CONST (src))
+    return 0;
+  if (SPEC_VOLATILE (dest) != SPEC_VOLATILE (src))
+    return 0;
+  if (SPEC_STAT (dest) != SPEC_STAT (src))
+    return 0;
+  if (SPEC_ABSA (dest) != SPEC_ABSA (src))
+    return 0;
+  if (SPEC_ABSA (dest) && SPEC_ADDR (dest) != SPEC_ADDR (src))
+    return 0;
+      
+  destScls = SPEC_SCLS (dest);
+  srcScls = SPEC_SCLS (src);
+  
+  /* Compensate for const to const code change in checkSClass() */
+  if (!level & port->mem.code_ro && SPEC_CONST (dest))
+    {
+      if (srcScls == S_CODE && destScls == S_FIXED)
+        destScls = S_CODE;
+      if (destScls == S_CODE && srcScls == S_FIXED)
+        srcScls = S_CODE;
+    }
+
+  /* compensate for allocGlobal() */  
+  if ((srcScls == S_FIXED || srcScls == S_AUTO)
+      && port->mem.default_globl_map == xdata
+      && !level)
+    srcScls = S_XDATA;
+  
+  if (level>0 && !SPEC_STAT (dest))
+    {
+      /* Compensate for hack-o-matic in checkSClass() */
+      if (options.stackAuto || (currFunc && IFFUNC_ISREENT (currFunc->type)))
+        {
+          if (destScls == S_FIXED)
+            destScls = (options.useXstack ? S_XSTACK : S_STACK);
+          if (srcScls == S_FIXED)
+            srcScls = (options.useXstack ? S_XSTACK : S_STACK);
+        }
+      else if (TARGET_IS_DS390 || TARGET_IS_DS400 || options.useXstack)
+        {
+          if (destScls == S_FIXED)
+            destScls = S_XDATA;
+          if (srcScls == S_FIXED)
+            srcScls = S_XDATA;
+        }
+    }
+
+  if (srcScls != destScls)
+    {
+      #if 0
+      printf ("level = %d\n", level);
+      printf ("SPEC_SCLS (src) = %d, SPEC_SCLS (dest) = %d\n",
+                SPEC_SCLS (src), SPEC_SCLS (dest));
+      printf ("srcScls = %d, destScls = %d\n",srcScls, destScls);
+      #endif
+      return 0;
+    }
+  
+  return 1;
+}
+
 /*------------------------------------------------------------------*/
 /* inCalleeSaveList - return 1 if found in callee save list          */
 /*------------------------------------------------------------------*/
@@ -1648,58 +2309,58 @@ 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:
+        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;
 }
@@ -1717,6 +2378,12 @@ checkFunction (symbol * sym, symbol *csym)
     fprintf (stderr, "checkFunction: %s ", sym->name);
   }
 
+  if (!IS_DECL(sym->type) || DCL_TYPE(sym->type)!=FUNCTION)
+    {
+      werror(E_SYNTAX_ERROR, sym->name);
+      return 0;
+    }
+    
   /* make sure the type is complete and sane */
   checkTypeSanity(((symbol *)sym)->etype, ((symbol *)sym)->name);
 
@@ -1735,13 +2402,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,11 +2411,17 @@ 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;
       }
     }
 
+  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++) {
@@ -1778,7 +2444,7 @@ checkFunction (symbol * sym, symbol *csym)
   argCnt--;
 
   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 +2466,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 +2478,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 +2490,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 +2511,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 +2521,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,13 +2569,29 @@ 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;
     }
 }
 
@@ -1912,10 +2608,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 +2633,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 +2687,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;
     }
@@ -2047,7 +2763,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   */
@@ -2085,142 +2801,146 @@ 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: fprintf (of, "data-"); break;
+          case S_XDATA: fprintf (of, "xdata-"); break;
+          case S_SFR: fprintf (of, "sfr-"); break;
+          case S_SBIT: fprintf (of, "sbit-"); break;
+          case S_CODE: fprintf (of, "code-"); break;
+          case S_IDATA: fprintf (of, "idata-"); break;
+          case S_PDATA: fprintf (of, "pdata-"); break;
+          case S_LITERAL: fprintf (of, "literal-"); break;
+          case S_STACK: fprintf (of, "stack-"); break;
+          case S_XSTACK: fprintf (of, "xstack-"); break;
+          case S_BIT: fprintf (of, "bit-"); break;
+          case S_EEPROM: fprintf (of, "eeprom-"); break;
+          default: break;
+          }
       }
 
       if (IS_DECL (type))
-       {
-         if (!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-");
+            }
+          }
+          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;
+            }
+        }
       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))
+            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;
+            }
+        }
       /* 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);
+        fputc (' ', of);
     }
   if (nlr)
     fprintf (of, "\n");
@@ -2253,144 +2973,148 @@ printTypeChainRaw (sym_link * start, FILE * of)
   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-");
+            }
+          }
+          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 (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 +3124,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 +3133,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 +3154,35 @@ symbol *__fslteq;
 symbol *__fsgt;
 symbol *__fsgteq;
 
+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 */
 symbol *__muldiv[3][3][2];
 /* 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 +3194,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 *                               */
+/* examples : "ig*" - generic int *                                */
 /*            "cx*" - char xdata *                                 */
 /*            "ui" -  unsigned int                                 */
 /*-----------------------------------------------------------------*/
@@ -2479,80 +3218,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;
 }
@@ -2569,7 +3312,11 @@ initCSupport ()
   };
   const char *sbwd[] =
   {
-    "char", "int", "long"
+    "char", "int", "long", "fixed16x16",
+  };
+  const char *fp16x16sbwd[] =
+  {
+    "char", "int", "long", "float",
   };
   const char *ssu[] =
   {
@@ -2588,24 +3335,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,42 +3370,80 @@ 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], 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 (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], 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], 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],
+                       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.
@@ -2667,20 +3453,53 @@ initCSupport ()
   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;
-           }
-       }
+        {
+          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],
+                   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[1][su],
+         __multypes[bwd][su],
+         2,
+         options.intlong_rent);
+      FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
     }
+  }
+
   /* mul only */
   muldivmod = 0;
   /* byte */
@@ -2690,10 +3509,10 @@ initCSupport ()
       /* muluchar and mulschar are still separate functions, because e.g. the z80
          port is sign/zero-extending to int before calling mulint() */
       SNPRINTF (buffer, sizeof(buffer),
-               "_%s%s%s",
-               smuldivmod[muldivmod],
-               ssu[su],
-               sbwd[bwd]);
+                "_%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;
     }
@@ -2704,9 +3523,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 +3535,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],
+                       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 +3561,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);
+            "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) floatFromVal (valFromType (sym->type));
+  for (sym = sym->next; sym; sym = sym->next)
+    {
+      v = (int) floatFromVal (valFromType (sym->type));
+      if (v<min)
+        min = v;
+      if (v>max)
+        max = v;
+    }
+
+  /* Determine the smallest integer type that is compatible with this range */
+  type = newLink (SPECIFIER);
+  if (min>=0 && max<=255)
+    {
+      SPEC_NOUN (type) = V_CHAR;
+      SPEC_USIGN (type) = 1;
+    }
+  else if (min>=-128 && max<=127)
+    {
+      SPEC_NOUN (type) = V_CHAR;
+    }
+  else if (min>=0 && max<=65535)
+    {
+      SPEC_NOUN (type) = V_INT;
+      SPEC_USIGN (type) = 1;
+    }
+  else if (min>=-32768 && max<=32767)
+    {
+      SPEC_NOUN (type) = V_INT;
+    }
+  else
+    {
+      SPEC_NOUN (type) = V_INT;
+      SPEC_LONG (type) = 1;
+      if (min>=0)
+        SPEC_USIGN (type) = 1;
+    }
+  
+  return type;    
+}