* src/SDCCast.c (removePostIncDecOps, removePreIncDecOps),
[fw/sdcc] / src / SDCC.y
index c558c6c7390b131bdc5824dc1588c2f5e9ae4598..fa781d1db136076e8c841b677f2fd7fbca7922b5 100644 (file)
@@ -44,6 +44,7 @@ int xstackPtr = 0 ;     /* xstack pointer          */
 int reentrant = 0 ; 
 int blockNo   = 0 ;     /* sequential block number  */
 int currBlockno=0 ;
+int inCritical= 0 ;
 extern int yylex();
 int yyparse(void);
 extern int noLineno ;
@@ -57,6 +58,7 @@ STACK_DCL(swStk   ,ast   *,MAX_NEST_LEVEL)
 STACK_DCL(blockNum,int,MAX_NEST_LEVEL*3)
 
 value *cenum = NULL  ;  /* current enumeration  type chain*/
+bool uselessDecl = TRUE;
 
 %}
 %expect 6
@@ -65,12 +67,12 @@ value *cenum = NULL  ;  /* current enumeration  type chain*/
     symbol     *sym ;      /* symbol table pointer       */
     structdef  *sdef;      /* structure definition       */
     char       yychar[SDCC_NAME_MAX+1];
-    sym_link       *lnk ;      /* declarator  or specifier   */
+    sym_link   *lnk ;      /* declarator  or specifier   */
     int        yyint;      /* integer value returned     */
     value      *val ;      /* for integer constant       */
     initList   *ilist;     /* initial list               */
-    char       *yyinline; /* inlined assembler code */
-    ast       *asts;     /* expression tree            */
+    const char *yyinline;  /* inlined assembler code     */
+    ast        *asts;      /* expression tree            */
 }
 
 %token <yychar> IDENTIFIER TYPE_NAME
@@ -92,6 +94,7 @@ value *cenum = NULL  ;  /* current enumeration  type chain*/
 %token BITWISEAND UNARYMINUS IPUSH IPOP PCALL  ENDFUNCTION JUMPTABLE
 %token RRC RLC 
 %token CAST CALL PARAM NULLOP BLOCK LABEL RECEIVE SEND ARRAYINIT
+%token DUMMY_READ_VOLATILE ENDCRITICAL SWAP
 
 %type <yyint>  Interrupt_storage
 %type <sym> identifier  declarator  declarator2 enumerator_list enumerator
@@ -99,7 +102,7 @@ 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_function_attributes while do for
+%type <sym> declarator2_function_attributes while do for critical
 %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
@@ -116,6 +119,7 @@ value *cenum = NULL  ;  /* current enumeration  type chain*/
 %type <asts> statement_list statement labeled_statement compound_statement
 %type <asts> expression_statement selection_statement iteration_statement
 %type <asts> jump_statement function_body else_statement string_literal
+%type <asts> critical_statement
 %type <ilist> initializer initializer_list
 %type <yyint> unary_operator  assignment_operator struct_or_union
 
@@ -398,34 +402,45 @@ assignment_expr
                                     $$ = newNode($2,$1,$3);
                                     break;
                             case MUL_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('*',removeIncDecOps(copyAst($1)),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('*',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case DIV_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('/',removeIncDecOps(copyAst($1)),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('/',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case MOD_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('%',removeIncDecOps(copyAst($1)),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('%',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case ADD_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('+',removeIncDecOps(copyAst($1)),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('+',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case SUB_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('-',removeIncDecOps(copyAst($1)),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('-',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case LEFT_ASSIGN:
-                                    $$ = newNode('=',$1,newNode(LEFT_OP,removeIncDecOps(copyAst($1)),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode(LEFT_OP,removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case RIGHT_ASSIGN:
-                                    $$ = newNode('=',$1,newNode(RIGHT_OP,removeIncDecOps(copyAst($1)),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode(RIGHT_OP,removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case AND_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('&',removeIncDecOps(copyAst($1)),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('&',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case XOR_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('^',removeIncDecOps(copyAst($1)),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('^',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case OR_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('|',removeIncDecOps(copyAst($1)),$3));
+                                    /* $$ = newNode('=',$1,newNode('|',removeIncDecOps(copyAst($1)),$3)); */
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('|',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             default :
                                     $$ = NULL;
@@ -458,7 +473,13 @@ constant_expr
    ;
 
 declaration
-   : declaration_specifiers ';'  { $$ = NULL ; }
+   : declaration_specifiers ';'
+      {
+         if (uselessDecl)
+           werror(W_USELESS_DECL);
+         uselessDecl = TRUE;
+         $$ = NULL ;
+      }
    | declaration_specifiers init_declarator_list ';'
       {
          /* add the specifier list to the id */
@@ -471,6 +492,7 @@ declaration
             addDecl (sym,0,lnk) ;
         }
         
+         uselessDecl = TRUE;
         $$ = sym1 ;
       }
    ;
@@ -541,7 +563,17 @@ storage_class_specifier
    ;
 
 Interrupt_storage
-   : INTERRUPT CONSTANT  { $$ = (int) floatFromVal($2) ;  }
+   : INTERRUPT { $$ = INTNO_UNSPEC ; }
+   | INTERRUPT CONSTANT
+        { int intno = (int) floatFromVal($2);
+          if ((intno >= 0) && (intno <= INTNO_MAX))
+            $$ = intno;
+          else
+            {
+              werror(E_INT_BAD_INTNO, intno);
+              $$ = INTNO_UNSPEC;
+            }
+        }
    ;
 
 type_specifier
@@ -603,9 +635,6 @@ type_specifier2
    | CODE      {
                   $$ = newLink (SPECIFIER) ;
                   SPEC_SCLS($$) = S_CODE ;                 
-                 if (port->mem.code_ro) {
-                   SPEC_CONST($$) = 1;
-                 }
                }
    | EEPROM      {
                   $$ = newLink (SPECIFIER) ;
@@ -631,9 +660,13 @@ type_specifier2
               SPEC_BSTR($$) = 0;
             }
 
-   | struct_or_union_specifier
+   | struct_or_union_specifier  {
+                                   uselessDecl = FALSE;
+                                   $$ = $1 ;
+                                }
    | enum_specifier     {                           
                            cenum = NULL ;
+                           uselessDecl = FALSE;
                            $$ = $1 ;                              
                         }
    | TYPE_NAME    
@@ -665,8 +698,19 @@ 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  */
@@ -712,11 +756,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;
        }
    ;
@@ -756,51 +801,87 @@ struct_declarator_list
 
 struct_declarator
    : declarator 
-   | ':' constant_expr  {  
+   | ':' constant_expr  {
+                           int bitsize;
                            $$ = newSymbol (genSymName(NestLevel),NestLevel) ; 
-                           $$->bitVar = (int) floatFromVal(constExprValue($2,TRUE));
+                           bitsize= (int) floatFromVal(constExprValue($2,TRUE));
+                           if (bitsize > (port->s.int_size * 8)) {
+                             bitsize = port->s.int_size * 8;
+                             werror(E_BITFLD_SIZE, bitsize);
+                           }
+                           if (!bitsize)
+                             bitsize = BITVAR_PAD;
+                           $$->bitVar = bitsize;
                         }                        
    | declarator ':' constant_expr 
-                        { 
-                         $1->bitVar = (int) floatFromVal(constExprValue($3,TRUE));                     
+                        {
+                          int bitsize;
+                          bitsize= (int) floatFromVal(constExprValue($3,TRUE));
+                          if (bitsize > (port->s.int_size * 8)) {
+                            bitsize = port->s.int_size * 8;
+                            werror(E_BITFLD_SIZE, bitsize);
+                          }
+                          if (!bitsize) {
+                            $$ = newSymbol (genSymName(NestLevel),NestLevel) ; 
+                            $$->bitVar = BITVAR_PAD;
+                            werror(W_BITFLD_NAMED);
+                          }
+                         else
+                           $1->bitVar = bitsize;
                         }
    ;
 
 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(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
@@ -860,22 +941,32 @@ declarator
 declarator2_function_attributes
    : declarator2                 { $$ = $1 ; } 
    | 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); 
+       if ((! $1) || (! IS_FUNC($1->etype)))
+         {
+           // function_attribute is only allowed if declarator2 was
+           // an actual function
+           werror(E_FUNC_ATTR);
+           $$=$1;
+         }
+       else
+         {
+           // 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); 
+         }
    }     
    ;
 
@@ -896,16 +987,20 @@ declarator2
             sym_link   *p ;
                        value *tval;
                        
-            p = (tval = constExprValue($3,TRUE))->etype;
+            tval = constExprValue($3,TRUE);
             /* if it is not a constant then Error  */
-            if ( SPEC_SCLS(p) != S_LITERAL)
+            p = newLink (DECLARATOR);
+            DCL_TYPE(p) = ARRAY ;
+            if ( !tval || (SPEC_SCLS(tval->etype) != S_LITERAL)) {
                werror(E_CONST_EXPECTED) ;
+               /* Assume a single item array to limit the cascade */
+               /* of additional errors. */
+               DCL_ELEM(p) = 1;
+            }
             else {
-               p = newLink (DECLARATOR);
-               DCL_TYPE(p) = ARRAY ;
                DCL_ELEM(p) = (int) floatFromVal(tval) ;
-               addDecl($1,0,p);
             }                          
+            addDecl($1,0,p);
          }
    | declarator2 '('  ')'      {  addDecl ($1,FUNCTION,NULL) ;   }
    | declarator2 '(' { NestLevel++ ; currBlockno++; } parameter_type_list ')'
@@ -949,6 +1044,8 @@ pointer
          {
             $$ = $1  ;         
             DCL_TSPEC($1) = $2;
+             DCL_PTR_CONST($1) = SPEC_CONST($2);
+             DCL_PTR_VOLATILE($1) = SPEC_VOLATILE($2);
         }
    | unqualified_pointer pointer         
          {
@@ -976,7 +1073,6 @@ pointer
                     DCL_TYPE($3) = POINTER ;
                     break;
                 case S_CODE:
-                    DCL_PTR_CONST($3) = 1;
                     DCL_TYPE($3) = CPOINTER ;
                     break;
                 case S_EEPROM:
@@ -1085,7 +1181,10 @@ type_name
 abstract_declarator
    : pointer { $$ = reverseLink($1); }
    | abstract_declarator2
-   | pointer abstract_declarator2   { $1 = reverseLink($1); $1->next = $2 ; $$ = $1;} 
+   | pointer abstract_declarator2   { $1 = reverseLink($1); $1->next = $2 ; $$ = $1;
+         if (IS_PTR($1) && IS_FUNC($2))
+           DCL_TYPE($1) = CPOINTER;
+       } 
    ;
 
 abstract_declarator2
@@ -1129,22 +1228,21 @@ abstract_declarator2
      }
      $1->next=p;
    }
-   | abstract_declarator2 '(' parameter_type_list ')' {
-     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
+   | abstract_declarator2 '(' { NestLevel++ ; currBlockno++; } parameter_type_list ')' {
        sym_link *p=newLink(DECLARATOR);
        DCL_TYPE(p) = FUNCTION;
-       if (!$1) {
-        // ((void (code *) (void)) 0) ()
-        $1=newLink(DECLARATOR);
-        DCL_TYPE($1)=CPOINTER;
-        $$ = $1;
-       }
-       $1->next=p;
-     }
+          
+       FUNC_HASVARARGS(p) = IS_VARG($4);
+       FUNC_ARGS(p) = reverseVal($4);
+            
+       /* nest level was incremented to take care of the parms  */
+       NestLevel-- ;
+       currBlockno--;
+       p->next = $1;
+       $$ = p;
+
+       // remove the symbol args (if any)
+       cleanUpLevel(SymbolTab,NestLevel+1);
    }
    ;
 
@@ -1166,6 +1264,7 @@ statement
    | selection_statement
    | iteration_statement
    | jump_statement
+   | critical_statement
    | INLINEASM  ';'      {
                             ast *ex = newNode(INLINEASM,NULL,NULL);
                            ex->values.inlineasm = strdup($1);
@@ -1173,6 +1272,24 @@ statement
                          } 
    ;
 
+critical
+   : CRITICAL   {
+                  inCritical++;
+                  STACK_PUSH(continueStack,NULL);
+                  STACK_PUSH(breakStack,NULL);
+                   $$ = NULL;
+                }
+   ;
+   
+critical_statement
+   : critical statement  {
+                  STACK_POP(breakStack);
+                  STACK_POP(continueStack);
+                  inCritical--;
+                  $$ = newNode(CRITICAL,$2,NULL);
+                }
+   ;
+      
 labeled_statement
 //   : identifier ':' statement          {  $$ = createLabel($1,$3);  }   
    : identifier ':'                    {  $$ = createLabel($1,NULL);  }   
@@ -1401,8 +1518,22 @@ jump_statement
           STACK_PEEK(breakStack)->isref = 1;
        }
    }
-   | RETURN ';'            { $$ = newNode(RETURN,NULL,NULL)    ; }
-   | RETURN expr ';'       { $$ = newNode(RETURN,NULL,$2) ; } 
+   | RETURN ';'            {
+       if (inCritical) {
+          werror(E_INVALID_CRITICAL);
+          $$ = NULL;
+       } else {
+          $$ = newNode(RETURN,NULL,NULL);
+       }
+   }
+   | RETURN expr ';'       {
+       if (inCritical) {
+          werror(E_INVALID_CRITICAL);
+          $$ = NULL;
+       } else {
+          $$ = newNode(RETURN,NULL,$2);
+       }
+   }
    ;
 
 identifier