fixed bug #702907
[fw/sdcc] / src / SDCC.y
index 4a7ac6cfc2e3ac0beb8062c66926002ba08a90db..644ecc5196dce307a181e688905d42c00e4498a2 100644 (file)
@@ -34,6 +34,7 @@
 #include "port.h"
 #include "newalloc.h"
 #include "SDCCerr.h"
+#include "SDCCutil.h"
 
 extern int yyerror (char *);
 extern FILE    *yyin;
@@ -176,39 +177,31 @@ function_attribute
 
 function_attributes
    :  USING CONSTANT {
-                        $$ = newLink() ;
-                        $$->class = SPECIFIER   ;
+                        $$ = newLink(SPECIFIER) ;
                        FUNC_REGBANK($$) = (int) floatFromVal($2);
                      }
-   |  REENTRANT      {  $$ = newLink ();
-                        $$->class = SPECIFIER   ;
+   |  REENTRANT      {  $$ = newLink (SPECIFIER);
                        FUNC_ISREENT($$)=1;
                      }
-   |  CRITICAL       {  $$ = newLink ();
-                        $$->class = SPECIFIER   ;
+   |  CRITICAL       {  $$ = newLink (SPECIFIER);
                        FUNC_ISCRITICAL($$) = 1;
                      }
-   |  NAKED          {  $$ = newLink ();
-                        $$->class = SPECIFIER   ;
+   |  NAKED          {  $$ = newLink (SPECIFIER);
                        FUNC_ISNAKED($$)=1;
                      }
-   |  JAVANATIVE     {  $$ = newLink ();
-                        $$->class = SPECIFIER   ;
+   |  JAVANATIVE     {  $$ = newLink (SPECIFIER);
                        FUNC_ISJAVANATIVE($$)=1;
                      }
-   |  OVERLAY        {  $$ = newLink ();
-                        $$->class = SPECIFIER   ;
+   |  OVERLAY        {  $$ = newLink (SPECIFIER);
                        FUNC_ISOVERLAY($$)=1;
                      }
-   |  NONBANKED      {$$ = newLink ();
-                        $$->class = SPECIFIER   ;
+   |  NONBANKED      {$$ = newLink (SPECIFIER);
                         FUNC_NONBANKED($$) = 1;
                        if (FUNC_BANKED($$)) {
                            werror(W_BANKED_WITH_NONBANKED);
                        }
                      }
-   |  BANKED         {$$ = newLink ();
-                        $$->class = SPECIFIER   ;
+   |  BANKED         {$$ = newLink (SPECIFIER);
                         FUNC_BANKED($$) = 1;
                        if (FUNC_NONBANKED($$)) {
                            werror(W_BANKED_WITH_NONBANKED);
@@ -219,8 +212,7 @@ function_attributes
                      }
    |  Interrupt_storage
                      {
-                        $$ = newLink () ;
-                        $$->class = SPECIFIER ;
+                        $$ = newLink (SPECIFIER) ;
                         FUNC_INTNO($$) = $1 ;
                         FUNC_ISISR($$) = 1;
                      }
@@ -492,11 +484,11 @@ declaration_specifiers
        sym_link *lnk = $2 ;
        while (lnk && !IS_SPEC(lnk->next))
         lnk = lnk->next;
-       lnk->next = mergeSpec($1,lnk->next, yytext);
+       lnk->next = mergeSpec($1,lnk->next, "storage_class_specifier declaration_specifiers - skipped");
        $$ = $2 ;
      }
      else
-       $$ = mergeSpec($1,$2, yytext);
+       $$ = mergeSpec($1,$2, "storage_class_specifier declaration_specifiers");
    }
    | type_specifier                                { $$ = $1; }
    | type_specifier declaration_specifiers          { 
@@ -506,11 +498,11 @@ declaration_specifiers
        sym_link *lnk = $2 ;
        while (lnk && !IS_SPEC(lnk->next))
         lnk = lnk->next;
-       lnk->next = mergeSpec($1,lnk->next, yytext);
+       lnk->next = mergeSpec($1,lnk->next, "type_specifier declaration_specifiers - skipped");
        $$ = $2 ;
      }
      else
-       $$ = mergeSpec($1,$2, yytext);
+       $$ = mergeSpec($1,$2, "type_specifier declaration_specifiers");
    }
    ;
 
@@ -527,28 +519,23 @@ init_declarator
 
 storage_class_specifier
    : TYPEDEF   {
-                  $$ = newLink () ;
-                  $$->class = SPECIFIER ;
+                  $$ = newLink (SPECIFIER) ;
                   SPEC_TYPEDEF($$) = 1 ;
                }
    | EXTERN    {
-                  $$ = newLink();
-                  $$->class = SPECIFIER ;
+                  $$ = newLink(SPECIFIER);
                   SPEC_EXTR($$) = 1 ;
                }
    | STATIC    {
-                  $$ = newLink ();
-                  $$->class = SPECIFIER ;
+                  $$ = newLink (SPECIFIER);
                   SPEC_STAT($$) = 1 ;
                }
    | AUTO      {
-                  $$ = newLink () ;
-                  $$->class = SPECIFIER ;
+                  $$ = newLink (SPECIFIER) ;
                   SPEC_SCLS($$) = S_AUTO  ;
                }
    | REGISTER  {
-                  $$ = newLink ();
-                  $$->class = SPECIFIER ;
+                  $$ = newLink (SPECIFIER);
                   SPEC_SCLS($$) = S_REGISTER ;
                }
    ;
@@ -570,88 +557,71 @@ type_specifier
 
 type_specifier2
    : CHAR   {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
                SPEC_NOUN($$) = V_CHAR  ;
             }
    | SHORT  {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
               $$->select.s._short = 1 ;
             }
    | INT    {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
                SPEC_NOUN($$) = V_INT   ;
             }
    | LONG   {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
               SPEC_LONG($$) = 1       ;
             }
    | SIGNED {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
                $$->select.s._signed = 1;
             }
    | UNSIGNED  {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
                SPEC_USIGN($$) = 1      ;
             }
    | VOID   {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
                SPEC_NOUN($$) = V_VOID  ;
             }
    | CONST  {
-               $$=newLink();
-              $$->class = SPECIFIER ;
+               $$=newLink(SPECIFIER);
               SPEC_CONST($$) = 1;
             }
    | VOLATILE  {
-               $$=newLink();
-              $$->class = SPECIFIER ;
+               $$=newLink(SPECIFIER);
               SPEC_VOLATILE($$) = 1 ;
             }
    | FLOAT  {
-               $$=newLink();
+               $$=newLink(SPECIFIER);
               SPEC_NOUN($$) = V_FLOAT;
-              $$->class = SPECIFIER ;
             }
    | XDATA     {
-                  $$ = newLink ();
-                  $$->class = SPECIFIER ;
+                  $$ = newLink (SPECIFIER);
                   SPEC_SCLS($$) = S_XDATA  ;
                }
    | CODE      {
-                  $$ = newLink () ;
-                  $$->class = SPECIFIER  ;
+                  $$ = newLink (SPECIFIER) ;
                   SPEC_SCLS($$) = S_CODE ;                 
                }
    | EEPROM      {
-                  $$ = newLink () ;
-                  $$->class = SPECIFIER  ;
+                  $$ = newLink (SPECIFIER) ;
                   SPEC_SCLS($$) = S_EEPROM ;
                }
    | DATA      {
-                  $$ = newLink ();
-                  $$->class = SPECIFIER ;
+                  $$ = newLink (SPECIFIER);
                   SPEC_SCLS($$) = S_DATA   ;
                }
    | IDATA     {
-                  $$ = newLink ();
-                  $$->class = SPECIFIER ;
+                  $$ = newLink (SPECIFIER);
                   SPEC_SCLS($$) = S_IDATA  ;
                }
    | PDATA     { 
-                  $$ = newLink ();
-                  $$->class = SPECIFIER ;
+                  $$ = newLink (SPECIFIER);
                   SPEC_SCLS($$) = S_PDATA  ;
                }
    | BIT    {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
                SPEC_NOUN($$) = V_BIT   ;
               SPEC_SCLS($$) = S_BIT   ;
               SPEC_BLEN($$) = 1;
@@ -676,14 +646,12 @@ type_specifier2
 
 sfr_reg_bit
    :  SBIT  {
-               $$ = newLink() ;
-               $$->class = SPECIFIER ;
+               $$ = newLink(SPECIFIER) ;
                SPEC_NOUN($$) = V_SBIT;
                SPEC_SCLS($$) = S_SBIT;
             }
    |  SFR   {
-               $$ = newLink() ;
-               $$->class = SPECIFIER ;
+               $$ = newLink(SPECIFIER) ;
                SPEC_NOUN($$) = V_CHAR;
                SPEC_SCLS($$) = S_SFR ;
               SPEC_USIGN($$) = 1 ;
@@ -694,22 +662,31 @@ struct_or_union_specifier
    : struct_or_union opt_stag '{' struct_declaration_list '}'
         {
            structdef *sdef ;
+          symbol *sym, *dsym;
+
+          // check for duplicate structure members
+          for (sym=$4; sym; sym=sym->next) {
+            for (dsym=sym->next; dsym; dsym=dsym->next) {
+              if (strcmp(sym->name, dsym->name)==0) {
+                werror(E_DUPLICATE_MEMBER, 
+                       $1==STRUCT ? "struct" : "union", sym->name);
+              }
+            }
+          }
 
-           /* Create a structdef   */
+           /* Create a structdef   */     
            sdef = $2 ;
            sdef->fields   = reverseSyms($4) ;   /* link the fields */
            sdef->size  = compStructSize($1,sdef);   /* update size of  */
 
            /* Create the specifier */
-           $$ = newLink () ;
-           $$->class = SPECIFIER   ;
+           $$ = newLink (SPECIFIER) ;
            SPEC_NOUN($$) = V_STRUCT;
            SPEC_STRUCT($$)= sdef ;
         }
    | struct_or_union stag
          {
-            $$ = newLink() ;
-            $$->class = SPECIFIER   ;
+            $$ = newLink(SPECIFIER) ;
             SPEC_NOUN($$) = V_STRUCT;
             SPEC_STRUCT($$) = $2 ;
          }
@@ -743,11 +720,12 @@ struct_declaration_list
    : struct_declaration
    | struct_declaration_list struct_declaration
        {
-          symbol *sym = $2;
-          /* go to the end of the chain */
-          while (sym->next) sym = sym->next;
+          symbol *sym=$2;
 
+          /* go to the end of the chain */
+          while (sym->next) sym=sym->next;
            sym->next = $1 ;
+        
            $$ = $2;
        }
    ;
@@ -768,7 +746,7 @@ struct_declaration
                   sym->etype = getSpec(sym->type);
               }
               else
-                  addDecl (sym,0,cloneSpec($1));              
+                addDecl (sym,0,copyLinkChain($1));
               /* make sure the type is complete and sane */
               checkTypeSanity(sym->etype, sym->name);
           }
@@ -799,40 +777,55 @@ struct_declarator
 
 enum_specifier
    : ENUM            '{' enumerator_list '}' {
-                                                //addSymChain ($3);
-                                                //allocVariables(reverseSyms($3)) ;
-                                                $$ = copyLinkChain(cenum->type);
-                                             }
+           symbol *sym, *dsym;
+          char _error=0;
+
+          // check for duplicate enums
+          for (sym=$3; sym; sym=sym->next) {
+            for (dsym=sym->next; dsym; dsym=dsym->next) {
+              if (strcmp(sym->name, dsym->name)==0) {
+                werror(E_DUPLICATE_MEMBER, "enum", sym->name);
+                _error++;
+              }
+            }
+          }
+          if (_error==0) {
+            $$ = copyLinkChain(cenum->type);
+          } else {
+            $$ = newIntLink();
+            SPEC_NOUN($$)=0;
+          }
+         }
+
    | ENUM identifier '{' enumerator_list '}' {
-                                                symbol *csym ;
-
-                                                $2->type = copyLinkChain(cenum->type);
-                                                $2->etype = getSpec($2->type);
-                                                /* add this to the enumerator table */
-                                                if (!(csym=findSym(enumTab,$2,$2->name)) && 
-                                                   (csym && csym->level == $2->level))
-                                                   werror(E_DUPLICATE_TYPEDEF,csym->name);
-
-                                                addSym ( enumTab,$2,$2->name,$2->level,$2->block, 0);
-                                               //addSymChain ($4);
-                                                //allocVariables (reverseSyms($4));
-                                                $$ = copyLinkChain(cenum->type);
-                                                SPEC_SCLS(getSpec($$)) = 0 ;
-                                             }
+     symbol *csym ;
+     
+     $2->type = copyLinkChain(cenum->type);
+     $2->etype = getSpec($2->type);
+     /* add this to the enumerator table */
+     if (!(csym=findSym(enumTab,$2,$2->name)) && 
+        (csym && csym->level == $2->level))
+       werror(E_DUPLICATE_TYPEDEF,csym->name);
+     
+     addSym ( enumTab,$2,$2->name,$2->level,$2->block, 0);
+     //addSymChain ($4);
+     //allocVariables (reverseSyms($4));
+     $$ = copyLinkChain(cenum->type);
+     SPEC_SCLS(getSpec($$)) = 0 ;
+   }
    | ENUM identifier                         {
-                                                symbol *csym ;
-
-                                                /* check the enumerator table */
-                                                if ((csym = findSym(enumTab,$2,$2->name)))
-                                                   $$ = copyLinkChain(csym->type);
-                                                else  {
-                                                   $$ = newLink() ;
-                                                   $$->class = SPECIFIER   ;
-                                                   SPEC_NOUN($$) = V_INT   ;
-                                                }
-
-                                                SPEC_SCLS(getSpec($$)) = 0 ;
-                                             }
+     symbol *csym ;
+     
+     /* check the enumerator table */
+     if ((csym = findSym(enumTab,$2,$2->name)))
+       $$ = copyLinkChain(csym->type);
+     else  {
+       $$ = newLink(SPECIFIER) ;
+       SPEC_NOUN($$) = V_INT   ;
+     }
+     
+     SPEC_SCLS(getSpec($$)) = 0 ;
+   }
    ;
 
 enumerator_list
@@ -868,11 +861,13 @@ opt_assign_expr
                            }                           
    |                       {                              
                               if (cenum)  {
-                                 sprintf(lbuff,"%d",(int) floatFromVal(cenum)+1);
+                                 SNPRINTF(lbuff, sizeof(lbuff), 
+                                         "%d",(int) floatFromVal(cenum)+1);
                                  $$ = cenum = constVal(lbuff);
                               }
                               else {
-                                 sprintf(lbuff,"%d",0);
+                                 SNPRINTF(lbuff, sizeof(lbuff), 
+                                         "%d",0);
                                  $$ = cenum = constVal(lbuff);
                               }   
                            }
@@ -916,7 +911,7 @@ declarator2
          {
             sym_link   *p;
 
-            p = newLink ();
+            p = newLink (DECLARATOR);
             DCL_TYPE(p) = ARRAY ;
             DCL_ELEM(p) = 0     ;
             addDecl($1,0,p);
@@ -931,7 +926,7 @@ declarator2
             if ( SPEC_SCLS(p) != S_LITERAL)
                werror(E_CONST_EXPECTED) ;
             else {
-               p = newLink ();
+               p = newLink (DECLARATOR);
                DCL_TYPE(p) = ARRAY ;
                DCL_ELEM(p) = (int) floatFromVal(tval) ;
                addDecl($1,0,p);
@@ -1015,6 +1010,7 @@ pointer
                 default:
                   // this could be just "constant" 
                   // werror(W_PTR_TYPE_INVALID);
+                    ;
                 }
             }
             else 
@@ -1026,7 +1022,7 @@ pointer
 unqualified_pointer
    :  '*'   
       {
-       $$ = newLink();
+       $$ = newLink(DECLARATOR);
        DCL_TYPE($$)=UPOINTER;
       }
    ;
@@ -1041,11 +1037,11 @@ type_specifier_list
        sym_link *lnk = $2 ;
        while (lnk && !IS_SPEC(lnk->next))
         lnk = lnk->next;
-       lnk->next = mergeSpec($1,lnk->next, "type_specifier_list");
+       lnk->next = mergeSpec($1,lnk->next, "type_specifier_list type_specifier skipped");
        $$ = $2 ;
      }
      else
-       $$ = mergeSpec($1,$2, "type_specifier_list");
+       $$ = mergeSpec($1,$2, "type_specifier_list type_specifier");
    }
    ;
 
@@ -1101,9 +1097,13 @@ type_name
                 /* go to the end of the list */
                 sym_link *p;
                 pointerTypes($2,$1);
-                for ( p = $2 ; p->next ; p=p->next);
-                  p->next = $1 ;
-                  $$ = $2 ;
+                for ( p = $2 ; p && p->next ; p=p->next);
+                if (!p) {
+                  werror(E_SYNTAX_ERROR, yytext);
+                } else {
+                  p->next = $1 ;
+                }
+                $$ = $2 ;
                }   
    ;
 
@@ -1116,18 +1116,18 @@ abstract_declarator
 abstract_declarator2
    : '(' abstract_declarator ')'    { $$ = $2 ; }
    | '[' ']'                        {             
-                                       $$ = newLink ();
+                                       $$ = newLink (DECLARATOR);
                                        DCL_TYPE($$) = ARRAY ;
                                        DCL_ELEM($$) = 0     ;
                                     }
    | '[' constant_expr ']'          { 
                                        value *val ;
-                                       $$ = newLink ();
+                                       $$ = newLink (DECLARATOR);
                                        DCL_TYPE($$) = ARRAY ;
                                        DCL_ELEM($$) = (int) floatFromVal(val = constExprValue($2,TRUE));
                                     }
    | abstract_declarator2 '[' ']'   {
-                                       $$ = newLink ();
+                                       $$ = newLink (DECLARATOR);
                                        DCL_TYPE($$) = ARRAY ;
                                        DCL_ELEM($$) = 0     ;
                                        $$->next = $1 ;
@@ -1135,7 +1135,7 @@ abstract_declarator2
    | abstract_declarator2 '[' constant_expr ']'
                                     {
                                        value *val ;
-                                       $$ = newLink ();
+                                       $$ = newLink (DECLARATOR);
                                        DCL_TYPE($$) = ARRAY ;
                                        DCL_ELEM($$) = (int) floatFromVal(val = constExprValue($3,TRUE));
                                        $$->next = $1 ;
@@ -1144,27 +1144,34 @@ abstract_declarator2
    | '(' parameter_type_list ')'    { $$ = NULL;}   
    | abstract_declarator2 '(' ')' {
      // $1 must be a pointer to a function
-     sym_link *p=newLink();
+     sym_link *p=newLink(DECLARATOR);
      DCL_TYPE(p) = FUNCTION;
+     if (!$1) {
+       // ((void (code *) ()) 0) ()
+       $1=newLink(DECLARATOR);
+       DCL_TYPE($1)=CPOINTER;
+       $$ = $1;
+     }
      $1->next=p;
    }
    | abstract_declarator2 '(' parameter_type_list ')' {
-     if (!IS_VOID($3->type)) {
+     if (!IS_VOID($3->etype)) {
        // this is nonsense, so let's just burp something
        werror(E_TOO_FEW_PARMS);
      } else {
        // $1 must be a pointer to a function
-       sym_link *p=newLink();
+       sym_link *p=newLink(DECLARATOR);
        DCL_TYPE(p) = FUNCTION;
        if (!$1) {
         // ((void (code *) (void)) 0) ()
-        $1=newLink();
+        $1=newLink(DECLARATOR);
         DCL_TYPE($1)=CPOINTER;
         $$ = $1;
        }
        $1->next=p;
      }
    }
+   ;
 
 initializer
    : assignment_expr                { $$ = newiList(INIT_NODE,$1); }
@@ -1186,8 +1193,7 @@ statement
    | jump_statement
    | INLINEASM  ';'      {
                             ast *ex = newNode(INLINEASM,NULL,NULL);
-                           ex->values.inlineasm = malloc(strlen($1)+1);
-                           strcpy(ex->values.inlineasm,$1);                        
+                           ex->values.inlineasm = strdup($1);
                            $$ = ex;
                          } 
    ;
@@ -1281,7 +1287,8 @@ selection_statement
                               ex->values.switchVals.swNum = swLabel ;
                                  
                               /* now create the label */
-                              sprintf(lbuff,"_swBrk_%d",swLabel++);
+                              SNPRINTF(lbuff, sizeof(lbuff), 
+                                      "_swBrk_%d",swLabel++);
                               $<sym>$  =  newSymbol(lbuff,NestLevel);
                               /* put label in the break stack  */
                               STACK_PUSH(breakStack,$<sym>$);   
@@ -1297,45 +1304,49 @@ selection_statement
 while : WHILE  {  /* create and push the continue , break & body labels */
                   static int Lblnum = 0 ;
                  /* continue */
-                  sprintf (lbuff,"_whilecontinue_%d",Lblnum);
+                  SNPRINTF (lbuff, sizeof(lbuff), "_whilecontinue_%d",Lblnum);
                  STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
                  /* break */
-                 sprintf (lbuff,"_whilebreak_%d",Lblnum);
+                 SNPRINTF (lbuff, sizeof(lbuff), "_whilebreak_%d",Lblnum);
                  STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
                  /* body */
-                 sprintf (lbuff,"_whilebody_%d",Lblnum++);
+                 SNPRINTF (lbuff, sizeof(lbuff), "_whilebody_%d",Lblnum++);
                  $$ = newSymbol(lbuff,NestLevel);
                }
+   ;
 
 do : DO {  /* create and push the continue , break & body Labels */
            static int Lblnum = 0 ;
 
           /* continue */
-          sprintf(lbuff,"_docontinue_%d",Lblnum);
+          SNPRINTF(lbuff, sizeof(lbuff), "_docontinue_%d",Lblnum);
           STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
           /* break */
-          sprintf (lbuff,"_dobreak_%d",Lblnum);
+          SNPRINTF(lbuff, sizeof(lbuff), "_dobreak_%d",Lblnum);
           STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
           /* do body */
-          sprintf (lbuff,"_dobody_%d",Lblnum++);
+          SNPRINTF(lbuff, sizeof(lbuff), "_dobody_%d",Lblnum++);
           $$ = newSymbol (lbuff,NestLevel);       
         }
+   ;
+
 for : FOR { /* create & push continue, break & body labels */
             static int Lblnum = 0 ;
          
             /* continue */
-           sprintf (lbuff,"_forcontinue_%d",Lblnum);
+           SNPRINTF(lbuff, sizeof(lbuff), "_forcontinue_%d",Lblnum);
            STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
            /* break    */
-           sprintf (lbuff,"_forbreak_%d",Lblnum);
+           SNPRINTF(lbuff, sizeof(lbuff), "_forbreak_%d",Lblnum);
            STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
            /* body */
-           sprintf (lbuff,"_forbody_%d",Lblnum);
+           SNPRINTF(lbuff, sizeof(lbuff), "_forbody_%d",Lblnum);
            $$ = newSymbol(lbuff,NestLevel);
            /* condition */
-           sprintf (lbuff,"_forcond_%d",Lblnum++);
+           SNPRINTF(lbuff, sizeof(lbuff), "_forcond_%d",Lblnum++);
            STACK_PUSH(forStack,newSymbol(lbuff,NestLevel));
           }
+   ;
 
 iteration_statement  
    : while '(' expr ')'  statement