* sim/ucsim/configure.in,
[fw/sdcc] / src / SDCCsymt.c
index f68a60e57c48fdc6055d9d004abceb32f74c6c00..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);
@@ -1000,6 +1011,23 @@ addSymChain (symbol * symHead)
              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;
@@ -1012,7 +1040,18 @@ addSymChain (symbol * symHead)
            werror (E_EXTERN_MISMATCH, sym->name);
           else
            werror (E_DUPLICATE, sym->name);
-         printFromToType (csym->type, sym->type);
+         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;
        }
 
@@ -1201,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              */
 /*------------------------------------------------------------------*/
@@ -1313,7 +1417,7 @@ checkSClass (symbol * sym, int isProto)
       }
     }
   }
-  
+
   /* automatic symbols cannot be given   */
   /* an absolute address ignore it      */
   if (sym->level &&
@@ -1484,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 */
@@ -1502,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 */
@@ -1521,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;
 }
 
@@ -2115,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    */
@@ -2198,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);
 
        }
@@ -2213,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);
@@ -2603,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;
@@ -2647,7 +2943,7 @@ sym_link *floatType;
 static char *
 _mangleFunctionName(char *in)
 {
-  if (port->getMangledFunctionName) 
+  if (port->getMangledFunctionName)
     {
       return port->getMangledFunctionName(in);
     }
@@ -2971,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;    
+}