* sim/ucsim/configure.in,
[fw/sdcc] / src / SDCCsymt.c
index 56da5bf1d10f54c840da8b136b92029fcd1422c2..4ceceaf007bd50c5a55f08ee18cb4d8d12a879cb 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);
 
@@ -293,6 +295,7 @@ newSymbol (char *name, int scope)
   sym->level = scope;          /* set the level    */
   sym->block = currBlockno;
   sym->lineDef = mylineno;     /* set the line number */
+  sym->fileDef = currFname;
   return sym;
 }
 
@@ -565,6 +568,14 @@ void checkTypeSanity(sym_link *etype, char *name) {
     SPEC_NOUN(etype)=V_INT;
   }
 
+  /* ISO/IEC 9899 J.3.9 implementation defined behaviour: */
+  /* a "plain" int bitfield is unsigned */
+  if (SPEC_NOUN(etype)==V_BIT ||
+      SPEC_NOUN(etype)==V_SBIT) {
+    if (!etype->select.s._signed)
+      SPEC_USIGN(etype) = 1;
+  }
+
   if (etype->select.s._signed && SPEC_USIGN(etype)) {
     // signed AND unsigned 
     werror (E_SIGNED_AND_UNSIGNED_INVALID, noun, name);
@@ -973,43 +984,85 @@ addSymChain (symbol * symHead)
 {
   symbol *sym = symHead;
   symbol *csym = NULL;
+  int error = 0;
 
   for (; sym != NULL; sym = sym->next)
     {
       changePointer(sym);
       checkTypeSanity(sym->etype, sym->name);
 
+      if (!sym->level && !(IS_SPEC(sym->etype) && IS_TYPEDEF(sym->etype)))
+        checkDecl (sym, 0);
+      
       /* if already exists in the symbol table then check if
          one of them is an extern definition if yes then
          then check if the type match, if the types match then
          delete the current entry and add the new entry      */
       if ((csym = findSymWithLevel (SymbolTab, sym)) &&
          csym->level == sym->level) {
-       
-       /* one definition extern ? */
-       if (IS_EXTERN (csym->etype) || IS_EXTERN (sym->etype)) {
-         /* do types match ? */
-         //checkDecl (sym, IS_EXTERN (sym->etype));
-         if (compareTypeExact (csym->type, sym->type, sym->level) != 1) {
-           /* no then error */
-           werror (E_EXTERN_MISMATCH, csym->name);
-           printFromToType (csym->type, sym->type);
-           continue;
+
+       /* If the previous definition was for an array with incomplete */
+       /* type, and the new definition has completed the type, update */
+       /* the original type to match */
+       if (IS_DECL(csym->type) && DCL_TYPE(csym->type)==ARRAY
+           && IS_DECL(sym->type) && DCL_TYPE(sym->type)==ARRAY)
+         {
+           if (!DCL_ELEM(csym->type) && DCL_ELEM(sym->type))
+             DCL_ELEM(csym->type) = DCL_ELEM(sym->type);
          }
-       } else {
-         /* not extern */
-         //checkDecl (sym, 0);
-         if (compareTypeExact (csym->type, sym->type, sym->level) != 1) {
-           werror (E_DUPLICATE, sym->name);
-           printFromToType (csym->type, sym->type);
-           continue;
+
+       #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);
       }
-
+      
       /* add new entry */
       addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
     }
@@ -1187,6 +1240,71 @@ compStructSize (int su, structdef * sdef)
     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              */
 /*------------------------------------------------------------------*/
@@ -1299,7 +1417,7 @@ checkSClass (symbol * sym, int isProto)
       }
     }
   }
-  
+
   /* automatic symbols cannot be given   */
   /* an absolute address ignore it      */
   if (sym->level &&
@@ -1470,16 +1588,86 @@ cleanUpLevel (bucket ** table, int level)
     }
 }
 
+/*------------------------------------------------------------------*/
+/* computeTypeOr - computes the resultant type from two types       */
+/*------------------------------------------------------------------*/
+static sym_link *
+computeTypeOr (sym_link * etype1, sym_link * etype2, sym_link * reType)
+{
+  /* sanity check */
+  assert (IS_CHAR (etype1) && IS_CHAR (etype2));
+
+  if (SPEC_USIGN (etype1) == SPEC_USIGN (etype2))
+    {
+      SPEC_USIGN (reType) = SPEC_USIGN (etype1);
+      return reType;
+    }
+  
+  if (SPEC_USIGN (etype1))
+    {
+      if (   IS_LITERAL (etype2)
+         && floatFromVal (valFromType (etype2)) >= 0)
+       SPEC_USIGN (reType) = 1;
+      else
+       {
+         /* promote to int */
+         SPEC_USIGN (reType) = 0;
+         SPEC_NOUN (reType) = V_INT;
+       }
+    }
+  else /* etype1 signed */
+    {
+      if (   IS_LITERAL (etype2)
+         && floatFromVal (valFromType (etype2)) <= 127)
+       SPEC_USIGN (reType) = 0;
+      else
+       {
+         /* promote to int */
+         SPEC_USIGN (reType) = 0;
+         SPEC_NOUN (reType) = V_INT;
+       }
+    }
+
+  if (SPEC_USIGN (etype2))
+    {
+      if (   IS_LITERAL (etype1)
+         && floatFromVal (valFromType (etype1)) >= 0)
+       SPEC_USIGN (reType) = 1;
+      else
+       {
+         /* promote to int */
+         SPEC_USIGN (reType) = 0;
+         SPEC_NOUN (reType) = V_INT;
+       }
+    }
+  else /* etype2 signed */
+    {
+      if (   IS_LITERAL (etype1)
+         && floatFromVal (valFromType (etype1)) <= 127)
+       SPEC_USIGN (reType) = 0;
+      else
+       {
+         /* promote to int */
+         SPEC_USIGN (reType) = 0;
+         SPEC_NOUN (reType) = V_INT;
+       }
+    }
+  return reType;
+}
+
 /*------------------------------------------------------------------*/
 /* computeType - computes the resultant type from two types         */
 /*------------------------------------------------------------------*/
 sym_link *
-computeType (sym_link * type1, sym_link * type2)
+computeType (sym_link * type1, sym_link * type2,
+             RESULT_TYPE resultType, char op)
 {
   sym_link *rType;
   sym_link *reType;
   sym_link *etype1 = getSpec (type1);
-  sym_link *etype2 = getSpec (type2);
+  sym_link *etype2;
+
+  etype2 = type2 ? getSpec (type2) : type1;
 
   /* if one of them is a float then result is a float */
   /* here we assume that the types passed are okay */
@@ -1488,12 +1676,28 @@ computeType (sym_link * type1, sym_link * type2)
   if (IS_FLOAT (etype1) || IS_FLOAT (etype2))
     rType = newFloatLink ();
   else
+    /* if both are bitvars choose the larger one */
+  if (IS_BITVAR (etype1) && IS_BITVAR (etype2))
+    {
+      rType = SPEC_BLEN (etype1) >= SPEC_BLEN (etype2) ?
+               copyLinkChain (type1) : copyLinkChain (type1);
+    }
     /* if only one of them is a bit variable
        then the other one prevails */
-  if (IS_BITVAR (etype1) && !IS_BITVAR (etype2))
-    rType = copyLinkChain (type2);
+  else if (IS_BITVAR (etype1) && !IS_BITVAR (etype2))
+    {
+      rType = copyLinkChain (type2);
+      /* bitfield can have up to 16 bits */
+      if (getSize (etype1) > 1)
+        SPEC_NOUN (getSpec (rType)) = V_INT;
+    }
   else if (IS_BITVAR (etype2) && !IS_BITVAR (etype1))
-    rType = copyLinkChain (type1);
+    {
+      rType = copyLinkChain (type1);
+      /* bitfield can have up to 16 bits */
+      if (getSize (etype2) > 1)
+        SPEC_NOUN (getSpec (rType)) = V_INT;
+    }
   else
     /* if one of them is a pointer or array then that
        prevails */
@@ -1507,22 +1711,122 @@ 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._signed = 0;
 
   /* if result is a literal then make not so */
   if (IS_LITERAL (reType))
     SPEC_SCLS (reType) = S_REGISTER;
 
+  switch (resultType)
+    {
+      case RESULT_TYPE_CHAR:
+       if (IS_BITVAR (reType))
+         {
+           SPEC_NOUN (reType) = V_CHAR;
+           SPEC_SCLS (reType) = 0;
+           SPEC_USIGN (reType) = 0;
+           return rType;
+         }
+       break;
+      case RESULT_TYPE_INT:
+      case RESULT_TYPE_NONE:
+       if (IS_BIT (reType))
+         {
+           SPEC_NOUN (reType) = V_CHAR;
+           SPEC_SCLS (reType) = 0;
+           SPEC_USIGN (reType) = 0;
+           return rType;
+         }
+       else if (IS_BITFIELD (reType))
+         {
+           /* could be smarter, but it depends on the op */
+           /* this is for the worst case: a multiplication of 4 * 4 bit */
+           SPEC_NOUN (reType) = SPEC_BLEN (reType) <= 4 ? V_CHAR : V_INT;
+           SPEC_SCLS (reType) = 0;
+           SPEC_USIGN (reType) = 0;
+           return rType;
+         }
+       else if (IS_CHAR (reType))
+         {
+           if (op == '|' || op == '^')
+             return computeTypeOr (etype1, etype2, reType);
+           else if (   op == '&'
+                    && SPEC_USIGN (etype1) != SPEC_USIGN (etype2))
+             {
+               SPEC_USIGN (reType) = 1;
+               return rType;
+             }
+           else
+             {
+               SPEC_NOUN (reType) = V_INT;
+               SPEC_USIGN (reType) = 0;
+               return rType;
+             }
+         }
+       break;
+      default:
+       break;
+    }
+
+  /* SDCC's sign promotion:
+     - if one or both operands are unsigned, the resultant type will be unsigned
+       (except char, see below)
+     - if an operand is promoted to a larger type (char -> int, int -> long),
+       the larger type will be signed
+
+     SDCC tries hard to avoid promotion to int and does 8 bit calculation as
+     much as possible. We're leaving ISO IEC 9899 here and have to extrapolate
+     the standard. The standard demands, that the result has to be the same
+     "as if" the promotion would have been performed:
+
+     - if the result of an operation with two char's is promoted to a
+       larger type, the result will be signed.
+
+     More sophisticated are these:
+     - if the result of an operation with two char's is a char again,
+       the result will only then be unsigned, if both operands are
+       unsigned. In all other cases the result will be signed.
+
+       This seems to be contradictionary to the first two rules, but it makes
+       real sense (all types are char's):
+
+       A signed char can be negative; this must be preserved in the result
+               -1 * 100 = -100;
+
+       Only if both operands are unsigned it's safe to make the result
+       unsigned; this helps to avoid overflow:
+               2 * 100 =  200;
+
+     - ToDo: document '|', '^' and '&'
+     
+     Homework: - why is (200 * 200 < 0) true?
+              - why is { char l = 200, r = 200; (r * l > 0) } true?
+  */
+
+  if (!IS_FLOAT (reType)
+      && (   (SPEC_USIGN (etype1)
+              /* if this operand is promoted to a larger type,
+                then it will be promoted to a signed type */
+             && !(getSize (etype1) < getSize (reType))
+              /* char require special handling */
+             && !IS_CHAR (etype1))
+         || /* same for 2nd operand */  
+            (SPEC_USIGN (etype2)
+             && !(getSize (etype2) < getSize (reType))
+             && !IS_CHAR (etype2))
+         || /* if both are 'unsigned char' and not promoted
+               let the result be unsigned too */
+            (   SPEC_USIGN (etype1)
+             && SPEC_USIGN (etype2)
+             && IS_CHAR (etype1)
+             && IS_CHAR (etype2)
+             && IS_CHAR (reType))))
+    SPEC_USIGN (reType) = 1;
+  else
+    SPEC_USIGN (reType) = 0;
+
   return rType;
 }
 
@@ -1653,7 +1957,52 @@ compareTypeExact (sym_link * dest, sym_link * src, int level)
            if (DCL_PTR_VOLATILE (src) != DCL_PTR_VOLATILE (dest))
              return 0;
            if (IS_FUNC(src))
-             return compareTypeExact (dest->next, src->next, -1);
+              {
+               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;
@@ -1701,7 +2050,11 @@ compareTypeExact (sym_link * dest, sym_link * src, int level)
     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);
   
@@ -1739,16 +2092,16 @@ compareTypeExact (sym_link * dest, sym_link * src, int level)
        }
     }
 
-  #if 0
   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;
     }
-  #endif
   
   return 1;
 }
@@ -2052,10 +2405,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    */
@@ -2135,10 +2487,13 @@ processFuncArgs (symbol * func)
          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);
 
        }
@@ -2150,10 +2505,14 @@ processFuncArgs (symbol * func)
          val->sym->_isparm = 1;
          SPEC_OCLS (val->etype) = SPEC_OCLS (val->sym->etype) =
            (options.model != MODEL_SMALL ? xdata : data);
+         
+         #if 0
+         /* ?? static functions shouldn't imply static parameters - EEP */
          if (IS_SPEC(func->etype)) {
            SPEC_STAT (val->etype) = SPEC_STAT (val->sym->etype) =
              SPEC_STAT (func->etype);
          }
+         #endif
        }
       if (!isinSet(operKeyReset, val->sym)) {
        addSet (&operKeyReset, val->sym);
@@ -2540,8 +2899,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_UDWORD num)
 {
   int nshifts = 0;
   int n1s = 0;
@@ -2584,7 +2943,7 @@ sym_link *floatType;
 static char *
 _mangleFunctionName(char *in)
 {
-  if (port->getMangledFunctionName) 
+  if (port->getMangledFunctionName)
     {
       return port->getMangledFunctionName(in);
     }
@@ -2908,3 +3267,63 @@ sym_link *validateLink(sym_link  *l,
     exit(-1);
     return l; // never reached, makes compiler happy.
 }
+
+/*--------------------------------------------------------------------*/
+/* newEnumType - create an integer type compatible with enumerations  */
+/*--------------------------------------------------------------------*/
+sym_link *
+newEnumType (symbol *enumlist)
+{
+  int min, max, v;
+  symbol *sym;
+  sym_link *type;
+
+  if (!enumlist)
+    {
+      type = newLink (SPECIFIER);
+      SPEC_NOUN (type) = V_INT;
+      return type;
+    }
+      
+  /* Determine the range of the enumerated values */
+  sym = enumlist;
+  min = max = (int) floatFromVal (valFromType (sym->type));
+  for (sym = sym->next; sym; sym = sym->next)
+    {
+      v = (int) floatFromVal (valFromType (sym->type));
+      if (v<min)
+        min = v;
+      if (v>max)
+        max = v;
+    }
+
+  /* Determine the smallest integer type that is compatible with this range */
+  type = newLink (SPECIFIER);
+  if (min>=0 && max<=255)
+    {
+      SPEC_NOUN (type) = V_CHAR;
+      SPEC_USIGN (type) = 1;
+    }
+  else if (min>=-128 && max<=127)
+    {
+      SPEC_NOUN (type) = V_CHAR;
+    }
+  else if (min>=0 && max<=65535)
+    {
+      SPEC_NOUN (type) = V_INT;
+      SPEC_USIGN (type) = 1;
+    }
+  else if (min>=-32768 && max<=32767)
+    {
+      SPEC_NOUN (type) = V_INT;
+    }
+  else
+    {
+      SPEC_NOUN (type) = V_INT;
+      SPEC_LONG (type) = 1;
+      if (min>=0)
+        SPEC_USIGN (type) = 1;
+    }
+  
+  return type;    
+}