the next step towards advanced typechecking
[fw/sdcc] / src / SDCCsymt.c
index ae8532460892b8ddb0efa3e22d1fe4d8a95b091c..b70f3af3df49a1b27133e237a2d4a213b11da0a6 100644 (file)
 #include "common.h"
 #include "newalloc.h"
 
+/* noun strings */
+char *nounName(sym_link *sl) {
+  switch (SPEC_NOUN(sl)) 
+    {
+    case V_INT: {
+      if (SPEC_LONG(sl)) return "long";
+      if (sl->select.s._short) return "short";
+      return "int";
+    }
+    case V_FLOAT: return "float";
+    case V_CHAR: return "char";
+    case V_VOID: return "void";
+    case V_STRUCT: return "struct";
+    case V_LABEL: return "label";
+    case V_BIT: return "bit";
+    case V_SBIT: return "sbit";
+    case V_DOUBLE: return "double";
+    }
+  return "unknown";
+};
+
 bucket *SymbolTab[256];                /* the symbol    table  */
 bucket *StructTab[256];                /* the structure table  */
 bucket *TypedefTab[256];       /* the typedef   table  */
@@ -77,11 +98,20 @@ addSym (bucket ** stab,
        void *sym,
        char *sname,
        int level,
-       int block)
+       int block,
+       int checkType)
 {
   int i;                       /* index into the hash Table */
   bucket *bp;                  /* temp bucket    *         */
 
+  if (checkType) {
+    if (getenv("DEBUG_SANITY")) {
+      fprintf (stderr, "addSym: %s ", sname);
+    }
+    /* make sure the type is complete and sane */
+    checkTypeSanity(((symbol *)sym)->etype, ((symbol *)sym)->name);
+  }
+
   /* the symbols are always added at the head of the list  */
   i = hashKey (sname);
   /* get a free entry */
@@ -424,26 +454,121 @@ addDecl (symbol * sym, int type, sym_link * p)
   return;
 }
 
+/*------------------------------------------------------------------
+  checkTypeSanity: prevent the user from doing e.g.:
+  unsigned float uf;
+  ------------------------------------------------------------------*/
+void checkTypeSanity(sym_link *etype, char *name) {
+  char *noun;
+
+  if (!etype) {
+    if (getenv("DEBUG_SANITY")) {
+      fprintf (stderr, "sanity check skipped for %s (etype==0)\n", name);
+    }
+    return;
+  }
+
+  if (!IS_SPEC(etype)) {
+    if (getenv("DEBUG_SANITY")) {
+      fprintf (stderr, "sanity check skipped for %s (!IS_SPEC)\n", name);
+    }
+    return;
+  }
+
+  noun=nounName(etype);
+
+  if (getenv("DEBUG_SANITY")) {
+    fprintf (stderr, "checking sanity for %s %x\n", name, (int)etype);
+  }
+
+  if ((SPEC_NOUN(etype)==V_CHAR || 
+       SPEC_NOUN(etype)==V_FLOAT || 
+       SPEC_NOUN(etype)==V_DOUBLE || 
+       SPEC_NOUN(etype)==V_VOID) &&
+      (etype->select.s._short || SPEC_LONG(etype))) {
+    // long or short for char float double or void
+    werror (E_LONG_OR_SHORT_INVALID, noun, name);
+  }
+  if ((SPEC_NOUN(etype)==V_FLOAT || 
+       SPEC_NOUN(etype)==V_DOUBLE || 
+       SPEC_NOUN(etype)==V_VOID) && 
+      (etype->select.s._signed || SPEC_USIGN(etype))) {
+    // 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) {
+    SPEC_NOUN(etype) = options.shortisint ? V_INT : V_CHAR;
+    etype->select.s._short = 0;
+  }
+
+  /* if no noun e.g. 
+     "const a;" or "data b;" or "signed s" or "long l"
+     assume an int */
+  if (!SPEC_NOUN(etype)) {
+    SPEC_NOUN(etype)=V_INT;
+  }
+
+  if (etype->select.s._signed && SPEC_USIGN(etype)) {
+    // signed AND unsigned 
+    werror (E_SIGNED_AND_UNSIGNED_INVALID, noun, name);
+  }
+  if (etype->select.s._short && SPEC_LONG(etype)) {
+    // short AND long
+    werror (E_LONG_AND_SHORT_INVALID, noun, name);
+  }
+
+}
+
 /*------------------------------------------------------------------*/
-/* mergeSpec - merges two specifiers and returns the new one       */
+/* mergeSpec - merges two specifiers and returns the new one        */
 /*------------------------------------------------------------------*/
 sym_link *
 mergeSpec (sym_link * dest, sym_link * src)
 {
-  /* if noun different then src overrides */
-  if (SPEC_NOUN (dest) != SPEC_NOUN (src) && !SPEC_NOUN (dest))
-    SPEC_NOUN (dest) = SPEC_NOUN (src);
-
-  /* if destination has no storage class */
-  if (!SPEC_SCLS (dest) || 
-      ((SPEC_SCLS(dest) == S_CONSTANT || SPEC_SCLS(dest) == S_REGISTER) && 
-       SPEC_SCLS (src)))
-    SPEC_SCLS (dest) = SPEC_SCLS (src);
-  /* special case for const */
+
+  if (SPEC_NOUN(src)) {
+    if (!SPEC_NOUN(dest)) {
+      SPEC_NOUN(dest)=SPEC_NOUN(src);
+    } else {
+      /* we shouldn't redeclare the type */
+      if (getenv("DEBUG_SANITY")) {
+       fprintf (stderr, "mergeSpec: ");
+      }
+      werror(E_TWO_OR_MORE_DATA_TYPES, yylval.yychar);
+    }
+  }
+  
+  if (SPEC_SCLS(src)) {
+    /* if destination has no storage class */
+    if (!SPEC_SCLS (dest) || SPEC_SCLS(dest)==S_REGISTER) {
+      SPEC_SCLS (dest) = SPEC_SCLS (src);
+    } else {
+      if (getenv("DEBUG_SANITY")) {
+       fprintf (stderr, "mergeSpec: ");
+      }
+      werror(E_TWO_OR_MORE_STORAGE_CLASSES, yylval.yychar);
+    }
+  }
+
   /* copy all the specifications  */
+
+  // we really should do: 
+#if 0
+  if (SPEC_what(src)) {
+    if (SPEC_what(dest)) {
+      werror(W_DUPLICATE_SPEC, "what");
+    }
+    SPEC_what(dst)|=SPEC_what(src);
+  }
+#endif
+  // but there are more important thing right now
+
   SPEC_LONG (dest) |= SPEC_LONG (src);
-  SPEC_SHORT (dest) |= SPEC_SHORT (src);
+  dest->select.s._short|=src->select.s._short;
   SPEC_USIGN (dest) |= SPEC_USIGN (src);
+  dest->select.s._signed|=src->select.s._signed;
   SPEC_STAT (dest) |= SPEC_STAT (src);
   SPEC_EXTR (dest) |= SPEC_EXTR (src);
   SPEC_ABSA (dest) |= SPEC_ABSA (src);
@@ -458,6 +583,7 @@ mergeSpec (sym_link * dest, sym_link * src)
   SPEC_BSTR (dest) |= SPEC_BSTR (src);
   SPEC_TYPEDEF (dest) |= SPEC_TYPEDEF (src);
   SPEC_NONBANKED (dest) |= SPEC_NONBANKED (src);
+  SPEC_NAKED (dest) |= SPEC_NAKED (src);
 
   if (IS_STRUCT (dest) && SPEC_STRUCT (dest) == NULL)
     SPEC_STRUCT (dest) = SPEC_STRUCT (src);
@@ -511,7 +637,7 @@ getSpec (sym_link * p)
 }
 
 /*------------------------------------------------------------------*/
-/* newCharLink() - creates an int type                              */
+/* newCharLink() - creates an char type                             */
 /*------------------------------------------------------------------*/
 sym_link *
 newCharLink ()
@@ -585,7 +711,7 @@ getSize (sym_link * p)
       switch (SPEC_NOUN (p))
        {                       /* depending on the specifier type */
        case V_INT:
-         return (IS_LONG (p) ? LONGSIZE : (IS_SHORT (p) ? SHORTSIZE : INTSIZE));
+         return (IS_LONG (p) ? LONGSIZE : INTSIZE);
        case V_FLOAT:
          return FLOATSIZE;
        case V_CHAR:
@@ -644,7 +770,7 @@ bitsForType (sym_link * p)
       switch (SPEC_NOUN (p))
        {                       /* depending on the specifier type */
        case V_INT:
-         return (IS_LONG (p) ? LONGSIZE * 8 : (IS_SHORT (p) ? SHORTSIZE * 8 : INTSIZE * 8));
+         return (IS_LONG (p) ? LONGSIZE * 8 : INTSIZE * 8);
        case V_FLOAT:
          return FLOATSIZE * 8;
        case V_CHAR:
@@ -788,9 +914,11 @@ addSymChain (symbol * symHead)
   symbol *sym = symHead;
   symbol *csym = NULL;
 
+
   for (; sym != NULL; sym = sym->next)
     {
       changePointer(sym);
+
       /* if already exists in the symbol table then check if
          the previous was an extern definition if yes then
          then check if the type match, if the types match then
@@ -810,7 +938,7 @@ addSymChain (symbol * symHead)
              /* delete current entry */
              deleteSym (SymbolTab, csym, csym->name);
              /* add new entry */
-             addSym (SymbolTab, sym, sym->name, sym->level, sym->block);
+             addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
            }
          else                  /* not extern */
            werror (E_DUPLICATE, sym->name);
@@ -828,8 +956,7 @@ addSymChain (symbol * symHead)
                werror (W_EXTERN_MISMATCH, csym->name);
            }
        }
-
-      addSym (SymbolTab, sym, sym->name, sym->level, sym->block);
+      addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
     }
 }
 
@@ -1055,7 +1182,6 @@ checkSClass (symbol * sym)
        SPEC_SCLS (sym->etype) != S_XSTACK &&
        SPEC_SCLS (sym->etype) != S_CONSTANT))
     {
-
       werror (E_AUTO_ASSUMED, sym->name);
       SPEC_SCLS (sym->etype) = S_AUTO;
     }
@@ -1098,7 +1224,8 @@ checkSClass (symbol * sym)
 
   /* 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)
+  if (sym->level && SPEC_SCLS (sym->etype) == S_FIXED &&
+      !IS_STATIC(sym->etype))
     {
       if (options.stackAuto || (currFunc && IS_RENT (currFunc->etype)))
        {
@@ -1325,17 +1452,6 @@ checkType (sym_link * dest, sym_link * src)
       SPEC_NOUN (src) == V_VOID)
     return -1;
 
-  /* char === to short */
-  if (SPEC_NOUN (dest) == V_CHAR &&
-      SPEC_NOUN (src) == V_INT &&
-      SPEC_SHORT (src))
-    return (SPEC_USIGN (src) == SPEC_USIGN (dest) ? 1 : -2);
-
-  if (SPEC_NOUN (src) == V_CHAR &&
-      SPEC_NOUN (dest) == V_INT &&
-      SPEC_SHORT (dest))
-    return (SPEC_USIGN (src) == SPEC_USIGN (dest) ? 1 : -2);
-
   /* if they are both bitfields then if the lengths
      and starts don't match */
   if (IS_BITFIELD (dest) && IS_BITFIELD (src) &&
@@ -1365,9 +1481,6 @@ checkType (sym_link * dest, sym_link * src)
   if (SPEC_LONG (dest) != SPEC_LONG (src))
     return -1;
 
-  if (SPEC_SHORT (dest) != SPEC_SHORT (src))
-    return -1;
-
   if (SPEC_USIGN (dest) != SPEC_USIGN (src))
     return -2;
 
@@ -1466,8 +1579,16 @@ checkFunction (symbol * sym)
 {
   symbol *csym;
   value *exargs, *acargs;
+  value *checkValue;
   int argCnt = 0;
 
+  if (getenv("DEBUG_SANITY")) {
+    fprintf (stderr, "checkFunction: %s ", sym->name);
+  }
+
+  /* make sure the type is complete and sane */
+  checkTypeSanity(((symbol *)sym)->etype, ((symbol *)sym)->name);
+
   /* if not type then some kind of error */
   if (!sym->type)
     return 0;
@@ -1516,7 +1637,7 @@ checkFunction (symbol * sym)
   if (checkType (csym->type, sym->type) <= 0)
     {
       werror (E_PREV_DEF_CONFLICT, csym->name, "type");
-      werror (E_CONTINUE, "previous defintion type ");
+      werror (E_CONTINUE, "previous definition type ");
       printTypeChain (csym->type, stderr);
       fprintf (stderr, "\n");
       werror (E_CONTINUE, "current definition type ");
@@ -1546,7 +1667,12 @@ checkFunction (symbol * sym)
        exargs && acargs;
        exargs = exargs->next, acargs = acargs->next, argCnt++)
     {
-      value *checkValue;
+      if (getenv("DEBUG_SANITY")) {
+       fprintf (stderr, "checkFunction: %s ", exargs->name);
+      }
+      /* make sure the type is complete and sane */
+      checkTypeSanity(exargs->etype, exargs->name);
+
       /* If the actual argument is an array, any prototype
        * will have modified it to a pointer. Duplicate that
        * change here.
@@ -1576,7 +1702,7 @@ checkFunction (symbol * sym)
   /* replace with this defition */
   sym->cdef = csym->cdef;
   deleteSym (SymbolTab, csym, csym->name);
-  addSym (SymbolTab, sym, sym->name, sym->level, sym->block);
+  addSym (SymbolTab, sym, sym->name, sym->level, sym->block, 1);
   if (IS_EXTERN (csym->etype) && !
       IS_EXTERN (sym->etype))
     {
@@ -1620,10 +1746,8 @@ processFuncArgs (symbol * func, int ignoreName)
     {
       /* mark it as a register parameter if
          the function does not have VA_ARG
-         and as port dictates
-         not inhibited by command line option or #pragma */
+         and as port dictates */
       if (!func->hasVargs &&
-         !IS_RENT (func->etype) &&
          (*port->reg_parm) (val->type))
        {
          SPEC_REGPARM (val->etype) = 1;
@@ -1800,10 +1924,7 @@ printTypeChain (sym_link * type, FILE * of)
            case V_INT:
              if (IS_LONG (type))
                fprintf (of, "long ");
-             else if (IS_SHORT (type))
-               fprintf (of, "short ");
-             else
-               fprintf (of, "int ");
+             fprintf (of, "int ");
              break;
 
            case V_CHAR:
@@ -1830,7 +1951,12 @@ printTypeChain (sym_link * type, FILE * of)
              fprintf (of, "bit {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
              break;
 
+           case V_DOUBLE:
+             fprintf (of, "double ");
+             break;
+
            default:
+             fprintf (of, "unknown type ");
              break;
            }
        }
@@ -1891,8 +2017,6 @@ cdbTypeInfo (sym_link * type, FILE * of)
            case V_INT:
              if (IS_LONG (type))
                fprintf (of, "SL");
-             else if (IS_SHORT (type))
-               fprintf (of, "SS");
              else
                fprintf (of, "SI");
              break;
@@ -2187,7 +2311,7 @@ initCSupport ()
                       smuldivmod[muldivmod],
                       ssu[su],
                       sbwd[bwd]);
-             __muldiv[muldivmod][bwd][su] = funcOfType (buffer, __multypes[bwd][su], __multypes[bwd][su], 2, options.intlong_rent);
+              __muldiv[muldivmod][bwd][su] = funcOfType (buffer, __multypes[bwd][su], __multypes[bwd][su], 2, options.intlong_rent);
              SPEC_NONBANKED (__muldiv[muldivmod][bwd][su]->etype) = 1;
              if (bwd < port->muldiv.force_reg_param_below)
                _makeRegParam (__muldiv[muldivmod][bwd][su]);