fixed bug #516625
[fw/sdcc] / src / SDCC.y
index afb2e5a9232caded83d00de708aeacac31bf783e..4a7ac6cfc2e3ac0beb8062c66926002ba08a90db 100644 (file)
@@ -58,6 +58,8 @@ STACK_DCL(blockNum,int,MAX_NEST_LEVEL*3)
 value *cenum = NULL  ;  /* current enumeration  type chain*/
 
 %}
+%expect 6
+
 %union {
     symbol     *sym ;      /* symbol table pointer       */
     structdef  *sdef;      /* structure definition       */
@@ -72,7 +74,7 @@ value *cenum = NULL  ;  /* current enumeration  type chain*/
 
 %token <yychar> IDENTIFIER TYPE_NAME
 %token <val>   CONSTANT   STRING_LITERAL
-%token SIZEOF 
+%token SIZEOF TYPEOF 
 %token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
 %token AND_OP OR_OP 
 %token <yyint> MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
@@ -81,14 +83,14 @@ value *cenum = NULL  ;  /* current enumeration  type chain*/
 %token TYPEDEF EXTERN STATIC AUTO REGISTER CODE EEPROM INTERRUPT SFR AT SBIT
 %token REENTRANT USING  XDATA DATA IDATA PDATA VAR_ARGS CRITICAL NONBANKED BANKED
 %token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID BIT
-%token STRUCT UNION ENUM ELIPSIS RANGE FAR _XDATA _CODE _GENERIC _NEAR _PDATA _IDATA _EEPROM
+%token STRUCT UNION ENUM ELIPSIS RANGE FAR
 %token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN
-%token NAKED
+%token NAKED JAVANATIVE OVERLAY
 %token <yyinline> INLINEASM
 %token IFX ADDRESS_OF GET_VALUE_AT_ADDRESS SPIL UNSPIL GETHBIT
 %token BITWISEAND UNARYMINUS IPUSH IPOP PCALL  ENDFUNCTION JUMPTABLE
 %token RRC RLC 
-%token CAST CALL PARAM NULLOP BLOCK LABEL RECEIVE SEND
+%token CAST CALL PARAM NULLOP BLOCK LABEL RECEIVE SEND ARRAYINIT
 
 %type <yyint>  Interrupt_storage
 %type <sym> identifier  declarator  declarator2 enumerator_list enumerator
@@ -96,12 +98,12 @@ value *cenum = NULL  ;  /* current enumeration  type chain*/
 %type <sym> struct_declarator_list  struct_declaration   struct_declaration_list
 %type <sym> declaration init_declarator_list init_declarator
 %type <sym> declaration_list identifier_list parameter_identifier_list
-%type <sym> declarator2_using_reentrant while do for
+%type <sym> declarator2_function_attributes while do for
 %type <lnk> pointer type_specifier_list type_specifier type_name
 %type <lnk> storage_class_specifier struct_or_union_specifier
 %type <lnk> declaration_specifiers  sfr_reg_bit type_specifier2
-%type <lnk> using_reentrant using_reentrant_interrupt enum_specifier
-%type <lnk> abstract_declarator abstract_declarator2 far_near_pointer far_near
+%type <lnk> function_attribute function_attributes enum_specifier
+%type <lnk> abstract_declarator abstract_declarator2 unqualified_pointer
 %type <val> parameter_type_list parameter_list parameter_declaration opt_assign_expr
 %type <sdef> stag opt_stag
 %type <asts> primary_expr
@@ -126,7 +128,9 @@ file
    ;
 
 external_definition
-   : function_definition     { blockNo=0;}
+   : function_definition     { 
+                               blockNo=0;
+                             }
    | declaration             { 
                               if ($1 && $1->type
                                && IS_FUNC($1->type))
@@ -165,41 +169,48 @@ function_definition
                                }
    ;
 
-using_reentrant
-   : using_reentrant_interrupt
-   | using_reentrant_interrupt using_reentrant { $$ = mergeSpec($1,$2); }
+function_attribute
+   : function_attributes
+   | function_attributes function_attribute { $$ = mergeSpec($1,$2,"function_attribute"); }
    ;
 
-using_reentrant_interrupt
+function_attributes
    :  USING CONSTANT {
                         $$ = newLink() ;
                         $$->class = SPECIFIER   ;
-                        SPEC_BNKF($$) = 1;
-                        SPEC_BANK($$) = (int) floatFromVal($2);                       
+                       FUNC_REGBANK($$) = (int) floatFromVal($2);
                      }
    |  REENTRANT      {  $$ = newLink ();
                         $$->class = SPECIFIER   ;
-                        SPEC_RENT($$) = 1;
+                       FUNC_ISREENT($$)=1;
                      }
    |  CRITICAL       {  $$ = newLink ();
                         $$->class = SPECIFIER   ;
-                        SPEC_CRTCL($$) = 1;
+                       FUNC_ISCRITICAL($$) = 1;
                      }
    |  NAKED          {  $$ = newLink ();
                         $$->class = SPECIFIER   ;
-                        SPEC_NAKED($$) = 1;
+                       FUNC_ISNAKED($$)=1;
+                     }
+   |  JAVANATIVE     {  $$ = newLink ();
+                        $$->class = SPECIFIER   ;
+                       FUNC_ISJAVANATIVE($$)=1;
+                     }
+   |  OVERLAY        {  $$ = newLink ();
+                        $$->class = SPECIFIER   ;
+                       FUNC_ISOVERLAY($$)=1;
                      }
    |  NONBANKED      {$$ = newLink ();
                         $$->class = SPECIFIER   ;
-                        SPEC_NONBANKED($$) = 1;
-                       if (SPEC_BANKED($$)) {
+                        FUNC_NONBANKED($$) = 1;
+                       if (FUNC_BANKED($$)) {
                            werror(W_BANKED_WITH_NONBANKED);
                        }
                      }
    |  BANKED         {$$ = newLink ();
                         $$->class = SPECIFIER   ;
-                        SPEC_BANKED($$) = 1;
-                       if (SPEC_NONBANKED($$)) {
+                        FUNC_BANKED($$) = 1;
+                       if (FUNC_NONBANKED($$)) {
                            werror(W_BANKED_WITH_NONBANKED);
                        }
                        if (SPEC_STAT($$)) {
@@ -210,8 +221,8 @@ using_reentrant_interrupt
                      {
                         $$ = newLink () ;
                         $$->class = SPECIFIER ;
-                        SPEC_INTN($$) = $1 ;
-                        SPEC_INTRTN($$) = 1;
+                        FUNC_INTNO($$) = $1 ;
+                        FUNC_ISISR($$) = 1;
                      }
    ;
 
@@ -275,6 +286,7 @@ unary_expr
    | unary_operator cast_expr { $$ = newNode($1,$2,NULL)    ;  }
    | SIZEOF unary_expr        { $$ = newNode(SIZEOF,NULL,$2);  }
    | SIZEOF '(' type_name ')' { $$ = newAst_VALUE(sizeofOp($3)); }
+   | TYPEOF unary_expr        { $$ = newNode(TYPEOF,NULL,$2);  }
    ;
               
 unary_operator
@@ -394,34 +406,34 @@ assignment_expr
                                     $$ = newNode($2,$1,$3);
                                     break;
                             case MUL_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('*',copyAst($1),$3));
+                                    $$ = newNode('=',$1,newNode('*',removeIncDecOps(copyAst($1)),$3));
                                     break;
                             case DIV_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('/',copyAst($1),$3));
+                                    $$ = newNode('=',$1,newNode('/',removeIncDecOps(copyAst($1)),$3));
                                     break;
                             case MOD_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('%',copyAst($1),$3));
+                                    $$ = newNode('=',$1,newNode('%',removeIncDecOps(copyAst($1)),$3));
                                     break;
                             case ADD_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('+',copyAst($1),$3));
+                                    $$ = newNode('=',$1,newNode('+',removeIncDecOps(copyAst($1)),$3));
                                     break;
                             case SUB_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('-',copyAst($1),$3));
+                                    $$ = newNode('=',$1,newNode('-',removeIncDecOps(copyAst($1)),$3));
                                     break;
                             case LEFT_ASSIGN:
-                                    $$ = newNode('=',$1,newNode(LEFT_OP,copyAst($1),$3));
+                                    $$ = newNode('=',$1,newNode(LEFT_OP,removeIncDecOps(copyAst($1)),$3));
                                     break;
                             case RIGHT_ASSIGN:
-                                    $$ = newNode('=',$1,newNode(RIGHT_OP,copyAst($1),$3));
+                                    $$ = newNode('=',$1,newNode(RIGHT_OP,removeIncDecOps(copyAst($1)),$3));
                                     break;
                             case AND_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('&',copyAst($1),$3));
+                                    $$ = newNode('=',$1,newNode('&',removeIncDecOps(copyAst($1)),$3));
                                     break;
                             case XOR_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('^',copyAst($1),$3));
+                                    $$ = newNode('=',$1,newNode('^',removeIncDecOps(copyAst($1)),$3));
                                     break;
                             case OR_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('|',copyAst($1),$3));
+                                    $$ = newNode('=',$1,newNode('|',removeIncDecOps(copyAst($1)),$3));
                                     break;
                             default :
                                     $$ = NULL;
@@ -480,11 +492,11 @@ declaration_specifiers
        sym_link *lnk = $2 ;
        while (lnk && !IS_SPEC(lnk->next))
         lnk = lnk->next;
-       lnk->next = mergeSpec($1,lnk->next);
+       lnk->next = mergeSpec($1,lnk->next, yytext);
        $$ = $2 ;
      }
      else
-       $$ = mergeSpec($1,$2); 
+       $$ = mergeSpec($1,$2, yytext);
    }
    | type_specifier                                { $$ = $1; }
    | type_specifier declaration_specifiers          { 
@@ -494,11 +506,11 @@ declaration_specifiers
        sym_link *lnk = $2 ;
        while (lnk && !IS_SPEC(lnk->next))
         lnk = lnk->next;
-       lnk->next = mergeSpec($1,lnk->next);
+       lnk->next = mergeSpec($1,lnk->next, yytext);
        $$ = $2 ;
      }
      else
-       $$ = mergeSpec($1,$2); 
+       $$ = mergeSpec($1,$2, yytext);
    }
    ;
 
@@ -565,7 +577,7 @@ type_specifier2
    | SHORT  {
                $$=newLink();
                $$->class = SPECIFIER   ;
-              SPEC_SHORT($$) = 1      ;
+              $$->select.s._short = 1 ;
             }
    | INT    {
                $$=newLink();
@@ -580,7 +592,7 @@ type_specifier2
    | SIGNED {
                $$=newLink();
                $$->class = SPECIFIER   ;
-               SPEC_SIGNED($$) = 1     ;
+               $$->select.s._signed = 1;
             }
    | UNSIGNED  {
                $$=newLink();
@@ -595,7 +607,6 @@ type_specifier2
    | CONST  {
                $$=newLink();
               $$->class = SPECIFIER ;
-              //SPEC_SCLS($$) = S_CONSTANT ;
               SPEC_CONST($$) = 1;
             }
    | VOLATILE  {
@@ -710,24 +721,23 @@ struct_or_union
    ;
 
 opt_stag
-   : stag
-   |  {  /* synthesize a name add to structtable */
-         $$ = newStruct(genSymName(NestLevel)) ;
-         $$->level = NestLevel ;
-         addSym (StructTab, $$, $$->tag,$$->level,currBlockno) ;
-      }
-   ;
+: stag
+|  {  /* synthesize a name add to structtable */
+     $$ = newStruct(genSymName(NestLevel)) ;
+     $$->level = NestLevel ;
+     addSym (StructTab, $$, $$->tag,$$->level,currBlockno, 0);
+};
 
 stag
-   :  identifier  {  /* add name to structure table */
-                     $$ = findSymWithBlock (StructTab,$1,currBlockno);
-                     if (! $$ ) {
-                        $$ = newStruct($1->name) ;
-                        $$->level = NestLevel ;
-                        addSym (StructTab, $$, $$->tag,$$->level,currBlockno) ;                         
-                     }
-                  }
-   ;
+:  identifier  {  /* add name to structure table */
+     $$ = findSymWithBlock (StructTab,$1,currBlockno);
+     if (! $$ ) {
+       $$ = newStruct($1->name) ;
+       $$->level = NestLevel ;
+       addSym (StructTab, $$, $$->tag,$$->level,currBlockno,0);
+     }
+};
+
 
 struct_declaration_list
    : struct_declaration
@@ -749,15 +759,18 @@ struct_declaration
            symbol *sym ;
            for ( sym = $2 ; sym != NULL ; sym = sym->next ) {
               
+              /* make the symbol one level up */
+              sym->level-- ;
+
               pointerTypes(sym->type,copyLinkChain($1));
               if (!sym->type) {
                   sym->type = copyLinkChain($1);
                   sym->etype = getSpec(sym->type);
-                  /* make sure the type is complete and sane */
-                  checkTypeSanity(sym->etype, sym->name);
               }
               else
                   addDecl (sym,0,cloneSpec($1));              
+              /* make sure the type is complete and sane */
+              checkTypeSanity(sym->etype, sym->name);
           }
            $$ = $2;
        }
@@ -773,7 +786,7 @@ struct_declarator_list
    ;
 
 struct_declarator
-   : declarator
+   : declarator 
    | ':' constant_expr  {  
                            $$ = newSymbol (genSymName(NestLevel),NestLevel) ; 
                            $$->bitVar = (int) floatFromVal(constExprValue($2,TRUE));
@@ -786,8 +799,8 @@ struct_declarator
 
 enum_specifier
    : ENUM            '{' enumerator_list '}' {
-                                                addSymChain ($3);
-                                                allocVariables(reverseSyms($3)) ;
+                                                //addSymChain ($3);
+                                                //allocVariables(reverseSyms($3)) ;
                                                 $$ = copyLinkChain(cenum->type);
                                              }
    | ENUM identifier '{' enumerator_list '}' {
@@ -800,9 +813,9 @@ enum_specifier
                                                    (csym && csym->level == $2->level))
                                                    werror(E_DUPLICATE_TYPEDEF,csym->name);
 
-                                                addSym ( enumTab,$2,$2->name,$2->level,$2->block);
-                                               addSymChain ($4);
-                                                allocVariables (reverseSyms($4));
+                                                addSym ( enumTab,$2,$2->name,$2->level,$2->block, 0);
+                                               //addSymChain ($4);
+                                                //allocVariables (reverseSyms($4));
                                                 $$ = copyLinkChain(cenum->type);
                                                 SPEC_SCLS(getSpec($$)) = 0 ;
                                              }
@@ -824,6 +837,8 @@ enum_specifier
 
 enumerator_list
    : enumerator
+   | enumerator_list ',' {
+                         }
    | enumerator_list ',' enumerator {
                                        $3->next = $1 ;
                                        $$ = $3  ;
@@ -831,15 +846,17 @@ enumerator_list
    ;
 
 enumerator
-   : identifier opt_assign_expr  {
-                                    /* make the symbol one level up */
-                                    $1->level-- ;
-                                    $1->type = copyLinkChain($2->type); 
-                                    $1->etype= getSpec($1->type);
-                                   SPEC_ENUM($1->etype) = 1;
-                                    $$ = $1 ;
-
-                                 }
+   : identifier opt_assign_expr  
+     {
+       /* make the symbol one level up */
+       $1->level-- ;
+       $1->type = copyLinkChain($2->type); 
+       $1->etype= getSpec($1->type);
+       SPEC_ENUM($1->etype) = 1;
+       $$ = $1 ;
+       // do this now, so we can use it for the next enums in the list
+       addSymChain($1);
+     }
    ;
 
 opt_assign_expr
@@ -862,17 +879,34 @@ opt_assign_expr
    ;
 
 declarator
-   : declarator2_using_reentrant       { $$ = $1; }
-   | pointer declarator2_using_reentrant
+   : declarator2_function_attributes   { $$ = $1; }
+   | pointer declarator2_function_attributes
          {
             addDecl ($2,0,reverseLink($1));
             $$ = $2 ;
          }
    ;
 
-declarator2_using_reentrant
+declarator2_function_attributes
    : declarator2                 { $$ = $1 ; } 
-   | declarator2 using_reentrant  { addDecl ($1,0,$2); }     
+   | declarator2 function_attribute  { 
+       // copy the functionAttributes (not the args and hasVargs !!)
+       sym_link *funcType=$1->etype;
+       struct value *args=FUNC_ARGS(funcType);
+       unsigned hasVargs=FUNC_HASVARARGS(funcType);
+
+       memcpy (&funcType->funcAttrs, &$2->funcAttrs, 
+              sizeof($2->funcAttrs));
+
+       FUNC_ARGS(funcType)=args;
+       FUNC_HASVARARGS(funcType)=hasVargs;
+
+       // just to be sure
+       memset (&$2->funcAttrs, 0,
+              sizeof($2->funcAttrs));
+       
+       addDecl ($1,0,$2); 
+   }     
    ;
 
 declarator2
@@ -909,12 +943,24 @@ declarator2
           
             addDecl ($1,FUNCTION,NULL) ;
           
-            $1->hasVargs = IS_VARG($4);
-            $1->args = reverseVal($4)  ;
+            FUNC_HASVARARGS($1->type) = IS_VARG($4);
+            FUNC_ARGS($1->type) = reverseVal($4);
             
             /* nest level was incremented to take care of the parms  */
             NestLevel-- ;
             currBlockno--;
+
+            // if this was a pointer (to a function)
+            if (IS_PTR($1->type)) {
+              // move the args and hasVargs to the function
+              FUNC_ARGS($1->etype)=FUNC_ARGS($1->type);
+              FUNC_HASVARARGS($1->etype)=FUNC_HASVARARGS($1->type);
+              memset (&$1->type->funcAttrs, 0,
+                      sizeof($1->type->funcAttrs));
+              // remove the symbol args (if any)
+              cleanUpLevel(SymbolTab,NestLevel+1);
+            }
+            
             $$ = $1;
          }
    | declarator2 '(' parameter_identifier_list ')'
@@ -928,18 +974,19 @@ declarator2
    ;
 
 pointer
-   : far_near_pointer { $$ = $1 ;}
-   | far_near_pointer type_specifier_list   
+   : unqualified_pointer { $$ = $1 ;}
+   | unqualified_pointer type_specifier_list   
          {
             $$ = $1  ;         
             DCL_TSPEC($1) = $2;
         }
-   | far_near_pointer pointer         
+   | unqualified_pointer pointer         
          {
             $$ = $1 ;          
             $$->next = $2 ;
+            DCL_TYPE($2)=port->unqualified_pointer;
         }
-   | far_near_pointer type_specifier_list pointer
+   | unqualified_pointer type_specifier_list pointer
          {
             $$ = $1 ;               
             if (IS_SPEC($2) && DCL_TYPE($3) == UPOINTER) {
@@ -961,11 +1008,13 @@ pointer
                 case S_CODE:
                     DCL_PTR_CONST($3) = 1;
                     DCL_TYPE($3) = CPOINTER ;
+                    break;
                 case S_EEPROM:
                     DCL_TYPE($3) = EEPPOINTER;
                     break;
                 default:
-                    werror(W_PTR_TYPE_INVALID);
+                  // this could be just "constant" 
+                  // werror(W_PTR_TYPE_INVALID);
                 }
             }
             else 
@@ -974,31 +1023,30 @@ pointer
         }
    ;
 
-far_near_pointer
-   :  far_near '*'   {
-                        if ($1 == NULL) {
-                           $$ = newLink();
-                           DCL_TYPE($$) = POINTER ;
-                        }
-                        else
-                           $$ = $1 ;
+unqualified_pointer
+   :  '*'   
+      {
+       $$ = newLink();
+       DCL_TYPE($$)=UPOINTER;
       }
    ;
 
-far_near
-   : _XDATA    { $$ = newLink() ; DCL_TYPE($$) = FPOINTER ; }
-   | _CODE     { $$ = newLink() ; DCL_TYPE($$) = CPOINTER ;  DCL_PTR_CONST($$) = 1;}
-   | _PDATA    { $$ = newLink() ; DCL_TYPE($$) = PPOINTER ; } 
-   | _IDATA    { $$ = newLink() ; DCL_TYPE($$) = IPOINTER ; }
-   | _NEAR     { $$ = NULL ; }
-   | _GENERIC  { $$ = newLink() ; DCL_TYPE($$) = GPOINTER ; } 
-   | _EEPROM   { $$ = newLink() ; DCL_TYPE($$) = EEPPOINTER ;} 
-   |           { $$ = newLink() ; DCL_TYPE($$) = UPOINTER ; }
-   ;
-
 type_specifier_list
    : type_specifier
-   | type_specifier_list type_specifier         {  $$ = mergeSpec ($1,$2); }
+   //| type_specifier_list type_specifier         {  $$ = mergeSpec ($1,$2, "type_specifier_list"); }
+   | type_specifier_list type_specifier {
+     /* if the decl $2 is not a specifier */
+     /* find the spec and replace it      */
+     if ( !IS_SPEC($2)) {
+       sym_link *lnk = $2 ;
+       while (lnk && !IS_SPEC(lnk->next))
+        lnk = lnk->next;
+       lnk->next = mergeSpec($1,lnk->next, "type_specifier_list");
+       $$ = $2 ;
+     }
+     else
+       $$ = mergeSpec($1,$2, "type_specifier_list");
+   }
    ;
 
 parameter_identifier_list
@@ -1094,9 +1142,29 @@ abstract_declarator2
                                     }
    | '(' ')'                        { $$ = NULL;}
    | '(' parameter_type_list ')'    { $$ = NULL;}   
-   | abstract_declarator2 '(' ')'
-   | abstract_declarator2 '(' parameter_type_list ')'
-   ;
+   | abstract_declarator2 '(' ')' {
+     // $1 must be a pointer to a function
+     sym_link *p=newLink();
+     DCL_TYPE(p) = FUNCTION;
+     $1->next=p;
+   }
+   | abstract_declarator2 '(' parameter_type_list ')' {
+     if (!IS_VOID($3->type)) {
+       // 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();
+       DCL_TYPE(p) = FUNCTION;
+       if (!$1) {
+        // ((void (code *) (void)) 0) ()
+        $1=newLink();
+        DCL_TYPE($1)=CPOINTER;
+        $$ = $1;
+       }
+       $1->next=p;
+     }
+   }
 
 initializer
    : assignment_expr                { $$ = newiList(INIT_NODE,$1); }
@@ -1118,14 +1186,15 @@ statement
    | jump_statement
    | INLINEASM  ';'      {
                             ast *ex = newNode(INLINEASM,NULL,NULL);
-                           ex->values.inlineasm = Safe_calloc(1,strlen($1)+1);
+                           ex->values.inlineasm = malloc(strlen($1)+1);
                            strcpy(ex->values.inlineasm,$1);                        
                            $$ = ex;
-                         }   
+                         } 
    ;
 
 labeled_statement
-   : identifier ':' statement          {  $$ = createLabel($1,$3);  }   
+//   : identifier ':' statement          {  $$ = createLabel($1,$3);  }   
+   : identifier ':'                    {  $$ = createLabel($1,NULL);  }   
    | CASE constant_expr ':' statement  {  $$ = createCase(STACK_PEEK(swStk),$2,$4); }
    | DEFAULT ':' statement             {  $$ = createDefault(STACK_PEEK(swStk),$3); }
    ;