* sim/ucsim/configure.in,
[fw/sdcc] / src / SDCC.y
index 2a32289536b19ed64375f9e1f3d15028a86bb98f..c5944eaf8dd0e8b4fce9aa2c398fc8810dd7228e 100644 (file)
 #include "SDCCval.h"
 #include "SDCCmem.h"
 #include "SDCCast.h"
+#include "port.h"
+#include "newalloc.h"
+#include "SDCCerr.h"
+#include "SDCCutil.h"
 
 extern int yyerror (char *);
 extern FILE    *yyin;
-extern char srcLstFname[];
 int NestLevel = 0 ;     /* current NestLevel       */
 int stackPtr  = 1 ;     /* stack pointer           */
 int xstackPtr = 0 ;     /* xstack pointer          */
 int reentrant = 0 ; 
 int blockNo   = 0 ;     /* sequential block number  */
 int currBlockno=0 ;
+int inCritical= 0 ;
+int seqPointNo= 1 ;    /* sequence point number */
+int ignoreTypedefType=0;
 extern int yylex();
 int yyparse(void);
 extern int noLineno ;
@@ -54,51 +60,58 @@ 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;
+
+#define YYDEBUG 1
 
 %}
+%expect 6
+
 %union {
     symbol     *sym ;      /* symbol table pointer       */
     structdef  *sdef;      /* structure definition       */
     char       yychar[SDCC_NAME_MAX+1];
-    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[MAX_INLINEASM]; /* inlined assembler code */
-    ast       *asts;     /* expression tree            */
+    const char *yyinline;  /* inlined assembler code     */
+    ast        *asts;      /* expression tree            */
 }
 
 %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
 %token <yyint> SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
 %token <yyint> XOR_ASSIGN OR_ASSIGN
 %token TYPEDEF EXTERN STATIC AUTO REGISTER CODE EEPROM INTERRUPT SFR AT SBIT
-%token REENTRANT USING  XDATA DATA IDATA PDATA VAR_ARGS CRITICAL NONBANKED
+%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 CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN 
+%token STRUCT UNION ENUM ELIPSIS RANGE FAR
+%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN
+%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
+%token DUMMY_READ_VOLATILE ENDCRITICAL SWAP
 
 %type <yyint>  Interrupt_storage
-%type <sym> identifier  declarator  declarator2 enumerator_list enumerator
-%type <sym> struct_declarator
+%type <sym> identifier  declarator  declarator2 declarator3 enumerator_list enumerator
+%type <sym> struct_declarator function_declarator function_declarator2
 %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 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
-%type <lnk> using_reentrant using_reentrant_interrupt enum_specifier
-%type <lnk> abstract_declarator abstract_declarator2 far_near_pointer far_near
+%type <lnk> declaration_specifiers sfr_reg_bit sfr_attributes type_specifier2
+%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
@@ -110,6 +123,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
 
@@ -123,8 +137,28 @@ file
    ;
 
 external_definition
-   : function_definition     { blockNo=0;}
+   : function_definition     { 
+                               blockNo=0;
+                             }
    | declaration             { 
+                              ignoreTypedefType = 0;
+                              if ($1 && $1->type
+                               && IS_FUNC($1->type))
+                              {
+                                  /* The only legal storage classes for 
+                                   * a function prototype (declaration)
+                                   * are extern and static. extern is the
+                                   * default. Thus, if this function isn't
+                                   * explicitly marked static, mark it
+                                   * extern.
+                                   */
+                                  if ($1->etype 
+                                   && IS_SPEC($1->etype)
+                                   && !SPEC_STAT($1->etype))
+                                  {
+                                       SPEC_EXTR($1->etype) = 1;
+                                  }
+                              }
                                addSymChain ($1);
                                allocVariables ($1) ;
                               cleanUpLevel (SymbolTab,1);
@@ -132,12 +166,12 @@ external_definition
    ;
 
 function_definition
-   : declarator function_body  {   /* function type not specified */
+   : function_declarator function_body  {   /* function type not specified */
                                    /* assume it to be 'int'       */
                                    addDecl($1,0,newIntLink());
                                   $$ = createFunction($1,$2); 
                                } 
-   | declaration_specifiers declarator function_body  
+   | declaration_specifiers function_declarator function_body  
                                 {   
                                    pointerTypes($2->type,copyLinkChain($1));
                                    addDecl($2,0,$1); 
@@ -145,36 +179,51 @@ 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);                       
+                        $$ = newLink(SPECIFIER) ;
+                       FUNC_REGBANK($$) = (int) floatFromVal($2);
+                     }
+   |  REENTRANT      {  $$ = newLink (SPECIFIER);
+                       FUNC_ISREENT($$)=1;
+                     }
+   |  CRITICAL       {  $$ = newLink (SPECIFIER);
+                       FUNC_ISCRITICAL($$) = 1;
                      }
-   |  REENTRANT      {  $$ = newLink ();
-                        $$->class = SPECIFIER   ;
-                        SPEC_RENT($$) = 1;
+   |  NAKED          {  $$ = newLink (SPECIFIER);
+                       FUNC_ISNAKED($$)=1;
                      }
-   |  CRITICAL       {  $$ = newLink ();
-                        $$->class = SPECIFIER   ;
-                        SPEC_CRTCL($$) = 1;
+   |  JAVANATIVE     {  $$ = newLink (SPECIFIER);
+                       FUNC_ISJAVANATIVE($$)=1;
                      }
-   |  NONBANKED      {$$ = newLink ();
-                        $$->class = SPECIFIER   ;
-                        SPEC_NONBANKED($$) = 1;
+   |  OVERLAY        {  $$ = newLink (SPECIFIER);
+                       FUNC_ISOVERLAY($$)=1;
+                     }
+   |  NONBANKED      {$$ = newLink (SPECIFIER);
+                        FUNC_NONBANKED($$) = 1;
+                       if (FUNC_BANKED($$)) {
+                           werror(W_BANKED_WITH_NONBANKED);
+                       }
+                     }
+   |  BANKED         {$$ = newLink (SPECIFIER);
+                        FUNC_BANKED($$) = 1;
+                       if (FUNC_NONBANKED($$)) {
+                           werror(W_BANKED_WITH_NONBANKED);
+                       }
+                       if (SPEC_STAT($$)) {
+                           werror(W_BANKED_WITH_STATIC);
+                       }
                      }
    |  Interrupt_storage
                      {
-                        $$ = newLink () ;
-                        $$->class = SPECIFIER ;
-                        SPEC_INTN($$) = $1 ;
-                        SPEC_INTRTN($$) = 1;
+                        $$ = newLink (SPECIFIER) ;
+                        FUNC_INTNO($$) = $1 ;
+                        FUNC_ISISR($$) = 1;
                      }
    ;
 
@@ -188,14 +237,14 @@ function_body
    ;
 
 primary_expr
-   : identifier      {  $$ = newAst(EX_VALUE,symbolVal($1));  }
-   | CONSTANT        {  $$ = newAst(EX_VALUE,$1);  }
+   : identifier      {  $$ = newAst_VALUE(symbolVal($1));  }
+   | CONSTANT        {  $$ = newAst_VALUE($1);  }
    | string_literal  
    | '(' expr ')'    {  $$ = $2 ;                   }
    ;
          
 string_literal
-    : STRING_LITERAL                   { $$ = newAst(EX_VALUE,$1); }
+    : STRING_LITERAL                   { $$ = newAst_VALUE($1); }
     ;
 
 postfix_expr
@@ -211,14 +260,14 @@ postfix_expr
                      {    
                        $3 = newSymbol($3->name,NestLevel);
                        $3->implicit = 1;
-                       $$ = newNode(PTR_OP,newNode('&',$1,NULL),newAst(EX_VALUE,symbolVal($3)));
+                       $$ = newNode(PTR_OP,newNode('&',$1,NULL),newAst_VALUE(symbolVal($3)));
 /*                     $$ = newNode('.',$1,newAst(EX_VALUE,symbolVal($3))) ;                   */
                      }
    | postfix_expr PTR_OP identifier    
                       { 
                        $3 = newSymbol($3->name,NestLevel);
                        $3->implicit = 1;                       
-                       $$ = newNode(PTR_OP,$1,newAst(EX_VALUE,symbolVal($3)));
+                       $$ = newNode(PTR_OP,$1,newAst_VALUE(symbolVal($3)));
                      }
    | postfix_expr INC_OP   
                       {        $$ = newNode(INC_OP,$1,NULL);}
@@ -237,7 +286,8 @@ unary_expr
    | DEC_OP unary_expr        { $$ = newNode(DEC_OP,NULL,$2);  }
    | unary_operator cast_expr { $$ = newNode($1,$2,NULL)    ;  }
    | SIZEOF unary_expr        { $$ = newNode(SIZEOF,NULL,$2);  }
-   | SIZEOF '(' type_name ')' { $$ = newAst(EX_VALUE,sizeofOp($3)); }
+   | SIZEOF '(' type_name ')' { $$ = newAst_VALUE(sizeofOp($3)); }
+   | TYPEOF unary_expr        { $$ = newNode(TYPEOF,NULL,$2);  }
    ;
               
 unary_operator
@@ -251,7 +301,7 @@ unary_operator
 
 cast_expr
    : unary_expr
-   | '(' type_name ')' cast_expr { $$ = newNode(CAST,newAst(EX_LINK,$2),$4); }
+   | '(' type_name ')' cast_expr { $$ = newNode(CAST,newAst_LINK($2),$4); }
    ;
 
 multiplicative_expr
@@ -275,41 +325,40 @@ shift_expr
 
 relational_expr
    : shift_expr
-   | relational_expr '<' shift_expr    { $$ = newNode('<',$1,$3); }
-   | relational_expr '>' shift_expr    { $$ = newNode('>',$1,$3); }
+   | relational_expr '<' shift_expr    { 
+       $$ = (port->lt_nge ? 
+             newNode('!',newNode(GE_OP,$1,$3),NULL) :
+             newNode('<', $1,$3));
+   }
+   | relational_expr '>' shift_expr    { 
+          $$ = (port->gt_nle ? 
+                newNode('!',newNode(LE_OP,$1,$3),NULL) :
+                newNode('>',$1,$3));
+   }
    | relational_expr LE_OP shift_expr  { 
-       /* $$ = newNode(LE_OP,$1,$3); */
-       /* getting 8051 specific here : will change
-         LE_OP operation to "not greater than" i.e.
-         ( a <= b ) === ( ! ( a > b )) */
-       $$ = newNode('!', 
-                   newNode('>', $1 , $3 ),
-                   NULL);
+          $$ = (port->le_ngt ? 
+                newNode('!', newNode('>', $1 , $3 ), NULL) :
+                newNode(LE_OP,$1,$3));
    }
    | relational_expr GE_OP shift_expr  { 
-       /* $$ = newNode(GE_OP,$1,$3) ; */
-       /* getting 8051 specific here : will change
-         GE_OP operation to "not less than" i.e.
-         ( a >= b ) === ( ! ( a < b )) */
-       $$ = newNode('!',
-                   newNode('<', $1 , $3 ),
-                   NULL);
+          $$ = (port->ge_nlt ? 
+                newNode('!', newNode('<', $1 , $3 ), NULL) :
+                newNode(GE_OP,$1,$3));
    }
    ;
 
 equality_expr
    : relational_expr
-   | equality_expr EQ_OP relational_expr  { $$ = newNode(EQ_OP,$1,$3);}
-   | equality_expr NE_OP relational_expr  
-          { 
-              /* $$ = newNode(NE_OP,$1,$3); */
-             /* NE_OP changed :            
-                expr1 != expr2 is equivalent to
-                (! expr1 == expr2) */
-             $$ = newNode('!',
-                          newNode(EQ_OP,$1,$3),
-                          NULL);
-         }       
+   | equality_expr EQ_OP relational_expr  { 
+    $$ = (port->eq_nne ? 
+         newNode('!',newNode(NE_OP,$1,$3),NULL) : 
+         newNode(EQ_OP,$1,$3));
+   }
+   | equality_expr NE_OP relational_expr { 
+       $$ = (port->ne_neq ? 
+            newNode('!', newNode(EQ_OP,$1,$3), NULL) : 
+            newNode(NE_OP,$1,$3));
+   }       
    ;
 
 and_expr
@@ -329,21 +378,21 @@ inclusive_or_expr
 
 logical_and_expr
    : inclusive_or_expr
-   | logical_and_expr AND_OP inclusive_or_expr 
-                                 { $$ = newNode(AND_OP,$1,$3);}
+   | logical_and_expr AND_OP { seqPointNo++;} inclusive_or_expr 
+                                 { $$ = newNode(AND_OP,$1,$4);}
    ;
 
 logical_or_expr
    : logical_and_expr
-   | logical_or_expr OR_OP logical_and_expr  
-                                 { $$ = newNode(OR_OP,$1,$3); }
+   | logical_or_expr OR_OP { seqPointNo++;} logical_and_expr  
+                                 { $$ = newNode(OR_OP,$1,$4); }
    ;
 
 conditional_expr
    : logical_or_expr
-   | logical_or_expr '?' logical_or_expr ':' conditional_expr  
+   | logical_or_expr '?' { seqPointNo++;} logical_or_expr ':' conditional_expr  
                      {
-                        $$ = newNode(':',$3,$5) ;
+                        $$ = newNode(':',$4,$6) ;
                         $$ = newNode('?',$1,$$) ;
                      }                        
    ;
@@ -358,31 +407,45 @@ assignment_expr
                                     $$ = newNode($2,$1,$3);
                                     break;
                             case MUL_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('*',copyAst($1),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('*',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case DIV_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('/',copyAst($1),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('/',removePreIncDecOps(copyAst($1)),$3));
+                                    break;
+                            case MOD_ASSIGN:
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('%',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case ADD_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('+',copyAst($1),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('+',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case SUB_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('-',copyAst($1),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('-',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case LEFT_ASSIGN:
-                                    $$ = newNode('=',$1,newNode(LEFT_OP,copyAst($1),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode(LEFT_OP,removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case RIGHT_ASSIGN:
-                                    $$ = newNode('=',$1,newNode(RIGHT_OP,copyAst($1),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode(RIGHT_OP,removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case AND_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('&',copyAst($1),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('&',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case XOR_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('^',copyAst($1),$3));
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('^',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             case OR_ASSIGN:
-                                    $$ = newNode('=',$1,newNode('|',copyAst($1),$3));
+                                    /* $$ = newNode('=',$1,newNode('|',removeIncDecOps(copyAst($1)),$3)); */
+                                    $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+                                                      newNode('|',removePreIncDecOps(copyAst($1)),$3));
                                     break;
                             default :
                                     $$ = NULL;
@@ -407,7 +470,7 @@ assignment_operator
 
 expr
    : assignment_expr
-   | expr ',' assignment_expr { $$ = newNode(',',$1,$3);}
+   | expr ',' { seqPointNo++;} assignment_expr { $$ = newNode(',',$1,$4);}
    ;
 
 constant_expr
@@ -415,19 +478,26 @@ 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 */
          symbol *sym , *sym1;
 
          for (sym1 = sym = reverseSyms($2);sym != NULL;sym = sym->next) {
-            link *lnk = copyLinkChain($1);
+            sym_link *lnk = copyLinkChain($1);
             /* do the pointer stuff */
             pointerTypes(sym->type,lnk);
             addDecl (sym,0,lnk) ;
         }
         
+         uselessDecl = TRUE;
         $$ = sym1 ;
       }
    ;
@@ -438,28 +508,28 @@ declaration_specifiers
      /* if the decl $2 is not a specifier */
      /* find the spec and replace it      */
      if ( !IS_SPEC($2)) {
-       link *lnk = $2 ;
+       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, "storage_class_specifier declaration_specifiers - skipped");
        $$ = $2 ;
      }
      else
-       $$ = mergeSpec($1,$2); 
+       $$ = mergeSpec($1,$2, "storage_class_specifier declaration_specifiers");
    }
    | type_specifier                                { $$ = $1; }
    | type_specifier declaration_specifiers          { 
      /* if the decl $2 is not a specifier */
      /* find the spec and replace it      */
      if ( !IS_SPEC($2)) {
-       link *lnk = $2 ;
+       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, "type_specifier declaration_specifiers - skipped");
        $$ = $2 ;
      }
      else
-       $$ = mergeSpec($1,$2); 
+       $$ = mergeSpec($1,$2, "type_specifier declaration_specifiers");
    }
    ;
 
@@ -476,195 +546,253 @@ 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 ;
                }
    ;
 
 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
    : type_specifier2
-   | type_specifier2 AT CONSTANT
+   | type_specifier2 AT constant_expr
         {
-           /* add this to the storage class specifier  */
+          /* add this to the storage class specifier  */
            SPEC_ABSA($1) = 1;   /* set the absolute addr flag */
            /* now get the abs addr from value */
-           SPEC_ADDR($1) = (int) floatFromVal ($3) ;
+           SPEC_ADDR($1) = (int) floatFromVal(constExprValue($3,TRUE)) ;
         }
    ;
 
 type_specifier2
    : CHAR   {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
                SPEC_NOUN($$) = V_CHAR  ;
+              ignoreTypedefType = 1;
             }
    | SHORT  {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
-               SPEC_LONG($$) = 0      ;
-              SPEC_SHORT($$) = 1        ;
+               $$=newLink(SPECIFIER);
+              $$->select.s._short = 1 ;
+              ignoreTypedefType = 1;
             }
    | INT    {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
                SPEC_NOUN($$) = V_INT   ;
+              ignoreTypedefType = 1;
             }
    | LONG   {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
-               SPEC_LONG($$) = 1       ;
-              SPEC_SHORT($$) = 0;
+               $$=newLink(SPECIFIER);
+              SPEC_LONG($$) = 1       ;
+              ignoreTypedefType = 1;
             }
    | SIGNED {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
-               SPEC_USIGN($$) = 0       ;
+               $$=newLink(SPECIFIER);
+               $$->select.s._signed = 1;
+              ignoreTypedefType = 1;
             }
    | UNSIGNED  {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
-               SPEC_USIGN($$) = 1       ;
+               $$=newLink(SPECIFIER);
+               SPEC_USIGN($$) = 1      ;
+              ignoreTypedefType = 1;
             }
    | VOID   {
-               $$=newLink();
-               $$->class = SPECIFIER   ;
+               $$=newLink(SPECIFIER);
                SPEC_NOUN($$) = V_VOID  ;
+              ignoreTypedefType = 1;
             }
    | CONST  {
-               $$=newLink();
-              $$->class = SPECIFIER ;
-              SPEC_SCLS($$) = S_CONSTANT ;
+               $$=newLink(SPECIFIER);
               SPEC_CONST($$) = 1;
             }
    | VOLATILE  {
-               $$=newLink();
-              $$->class = SPECIFIER ;
+               $$=newLink(SPECIFIER);
               SPEC_VOLATILE($$) = 1 ;
             }
    | FLOAT  {
-               $$=newLink();
+               $$=newLink(SPECIFIER);
               SPEC_NOUN($$) = V_FLOAT;
-              $$->class = SPECIFIER ;
+              ignoreTypedefType = 1;
             }
    | 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;
               SPEC_BSTR($$) = 0;
+              ignoreTypedefType = 1;
             }
 
-   | struct_or_union_specifier
+   | struct_or_union_specifier  {
+                                   uselessDecl = FALSE;
+                                   $$ = $1 ;
+                                  ignoreTypedefType = 1;
+                                }
    | enum_specifier     {                           
                            cenum = NULL ;
+                           uselessDecl = FALSE;
+                           ignoreTypedefType = 1;
                            $$ = $1 ;                              
                         }
    | TYPE_NAME    
          {
             symbol *sym;
-            link   *p  ;
-
+            sym_link   *p  ;
             sym = findSym(TypedefTab,NULL,$1) ;
             $$ = p = copyLinkChain(sym->type);
            SPEC_TYPEDEF(getSpec(p)) = 0;
+            ignoreTypedefType = 1;
          }
    | sfr_reg_bit
    ;
 
 sfr_reg_bit
    :  SBIT  {
-               $$ = newLink() ;
-               $$->class = SPECIFIER ;
+               $$ = newLink(SPECIFIER) ;
                SPEC_NOUN($$) = V_SBIT;
                SPEC_SCLS($$) = S_SBIT;
+              SPEC_BLEN($$) = 1;
+              SPEC_BSTR($$) = 0;
+              ignoreTypedefType = 1;
             }
-   |  SFR   {
-               $$ = newLink() ;
-               $$->class = SPECIFIER ;
-               SPEC_NOUN($$) = V_CHAR;
-               SPEC_SCLS($$) = S_SFR ;
-              SPEC_USIGN($$) = 1 ;
+   |  sfr_attributes
+   ;
+
+sfr_attributes
+   : SFR    {
+               $$ = newLink(SPECIFIER) ;
+               FUNC_REGBANK($$) = 0;
+               SPEC_NOUN($$)    = V_CHAR;
+               SPEC_SCLS($$)    = S_SFR ;
+               SPEC_USIGN($$)   = 1 ;
+              ignoreTypedefType = 1;
+            }
+   | SFR BANKED {
+               $$ = newLink(SPECIFIER) ;
+               FUNC_REGBANK($$) = 1;
+               SPEC_NOUN($$)    = V_CHAR;
+               SPEC_SCLS($$)    = S_SFR ;
+               SPEC_USIGN($$)   = 1 ;
+              ignoreTypedefType = 1;
             }
    ;
 
 struct_or_union_specifier
-   : struct_or_union opt_stag '{' struct_declaration_list '}'
+   : struct_or_union opt_stag
+        {
+           if (!$2->type)
+             {
+               $2->type = $1;
+             }
+           else
+             {
+               if ($2->type != $1)
+                 werror(E_BAD_TAG, $2->tag, $1==STRUCT ? "struct" : "union");
+             }
+
+       }
+           '{' struct_declaration_list '}'
         {
            structdef *sdef ;
+          symbol *sym, *dsym;
 
-           /* Create a structdef   */
+          // check for errors in structure members
+          for (sym=$5; sym; sym=sym->next) {
+            if (IS_ABSOLUTE(sym->etype)) {
+              werrorfl(sym->fileDef, sym->lineDef, E_NOT_ALLOWED, "'at'");
+              SPEC_ABSA(sym->etype) = 0;
+            }
+            if (IS_SPEC(sym->etype) && SPEC_SCLS(sym->etype)) {
+              werrorfl(sym->fileDef, sym->lineDef, E_NOT_ALLOWED, "storage class");
+              printTypeChainRaw (sym->type,NULL);
+              SPEC_SCLS(sym->etype) = 0;
+            }
+            for (dsym=sym->next; dsym; dsym=dsym->next) {
+              if (*dsym->name && strcmp(sym->name, dsym->name)==0) {
+                werrorfl(sym->fileDef, sym->lineDef, E_DUPLICATE_MEMBER, 
+                       $1==STRUCT ? "struct" : "union", sym->name);
+                werrorfl(dsym->fileDef, dsym->lineDef, E_PREVIOUS_DEF);
+              }
+            }
+          }
+
+           /* Create a structdef   */     
            sdef = $2 ;
-           sdef->fields   = reverseSyms($4) ;   /* link the fields */
+           sdef->fields   = reverseSyms($5) ;   /* link the fields */
            sdef->size  = compStructSize($1,sdef);   /* update size of  */
-
+          promoteAnonStructs ($1, sdef);
+          
            /* 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 ;
+            SPEC_STRUCT($$) = $2;
+
+           if (!$2->type)
+             {
+               $2->type = $1;
+             }
+           else
+             {
+               if ($2->type != $1)
+                 werror(E_BAD_TAG, $2->tag, $1==STRUCT ? "struct" : "union");
+             }
          }
    ;
 
@@ -674,34 +802,34 @@ 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
    | 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;
        }
    ;
@@ -712,17 +840,23 @@ struct_declaration
            /* add this type to all the symbols */
            symbol *sym ;
            for ( sym = $2 ; sym != NULL ; sym = sym->next ) {
+              sym_link *btype = copyLinkChain($1);
               
-              pointerTypes(sym->type,copyLinkChain($1));
+              /* make the symbol one level up */
+              sym->level-- ;
+
+              pointerTypes(sym->type,btype);
               if (!sym->type) {
-                  sym->type = copyLinkChain($1);
+                  sym->type = btype;
                   sym->etype = getSpec(sym->type);
               }
               else
-                  addDecl (sym,0,cloneSpec($1));              
-              
+                addDecl (sym,0,btype);
+              /* make sure the type is complete and sane */
+              checkTypeSanity(sym->etype, sym->name);
           }
-           $$ = $2;
+          ignoreTypedefType = 0;
+          $$ = $2;
        }
    ;
 
@@ -736,173 +870,289 @@ struct_declarator_list
    ;
 
 struct_declarator
-   : declarator
-   | ':' constant_expr  {  
+   : declarator 
+   | ':' 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;
                         }
+   | { $$ = newSymbol ("", NestLevel) ; }
+   
    ;
 
 enum_specifier
    : ENUM            '{' enumerator_list '}' {
-                                                addSymChain ($3);
-                                                allocVariables(reverseSyms($3)) ;
-                                                $$ = copyLinkChain(cenum->type);
-                                             }
-   | 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);
-                                               addSymChain ($4);
-                                                allocVariables (reverseSyms($4));
-                                                $$ = copyLinkChain(cenum->type);
-                                                SPEC_SCLS(getSpec($$)) = 0 ;
-                                             }
-   | ENUM identifier                         {
-                                                symbol *csym ;
+          $$ = newEnumType ($3);       //copyLinkChain(cenum->type);
+          SPEC_SCLS(getSpec($$)) = 0;
+         }
 
-                                                /* check the enumerator table */
-                                                if ((csym = findSym(enumTab,$2,$2->name)))
-                                                   $$ = copyLinkChain(csym->type);
-                                                else  {
-                                                   $$ = newLink() ;
-                                                   $$->class = SPECIFIER   ;
-                                                   SPEC_NOUN($$) = V_INT   ;
-                                                }
+   | ENUM identifier '{' enumerator_list '}' {
+     symbol *csym ;
+     sym_link *enumtype;
 
-                                                SPEC_SCLS(getSpec($$)) = 0 ;
-                                             }
+     csym=findSym(enumTab,$2,$2->name);
+     if ((csym && csym->level == $2->level))
+       {
+         werrorfl($2->fileDef, $2->lineDef, E_DUPLICATE_TYPEDEF,csym->name);
+         werrorfl(csym->fileDef, csym->lineDef, E_PREVIOUS_DEF);
+       }
+     
+     enumtype = newEnumType ($4);      //copyLinkChain(cenum->type);
+     SPEC_SCLS(getSpec(enumtype)) = 0;
+     $2->type = enumtype;
+     
+     /* add this to the enumerator table */
+     if (!csym)
+       addSym ( enumTab,$2,$2->name,$2->level,$2->block, 0);
+     $$ = copyLinkChain(enumtype);
+   }
+   | 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   ;
+     }
+   }
    ;
 
 enumerator_list
    : enumerator
-   | enumerator_list ',' enumerator {
-                                       $3->next = $1 ;
-                                       $$ = $3  ;
-                                    }
+   | enumerator_list ',' {
+                         }
+   | enumerator_list ',' enumerator
+     {
+       symbol *dsym;
+       
+       for (dsym=$1; dsym; dsym=dsym->next)
+         {
+          if (strcmp($3->name, dsym->name)==0)
+            {
+              werrorfl($3->fileDef, $3->lineDef, E_DUPLICATE_MEMBER, "enum", $3->name);
+              werrorfl(dsym->fileDef, dsym->lineDef, E_PREVIOUS_DEF);
+            }
+        }
+       
+       $3->next = $1 ;
+       $$ = $3  ;
+     }
    ;
 
 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
    :  '='   constant_expr  {
                               value *val ;
-                                                       
-                              val = constExprValue($2,TRUE);                         
+
+                              val = constExprValue($2,TRUE);
+                             if (!IS_INT(val->type) && !IS_CHAR(val->type))
+                               {
+                                 werror(E_ENUM_NON_INTEGER);
+                                 SNPRINTF(lbuff, sizeof(lbuff), 
+                                         "%d",(int) floatFromVal(val));
+                                 val = constVal(lbuff);
+                               }
                               $$ = cenum = val ;
                            }                           
    |                       {                              
                               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);
                               }   
                            }
    ;
 
 declarator
-   : declarator2_using_reentrant       { $$ = $1; }
-   | pointer declarator2_using_reentrant
+   : declarator3                       { $$ = $1 ; } 
+   | pointer declarator3
          {
             addDecl ($2,0,reverseLink($1));
             $$ = $2 ;
          }
    ;
 
-declarator2_using_reentrant
-   : declarator2                 { $$ = $1 ; } 
-   | declarator2 using_reentrant  { addDecl ($1,0,$2); }     
+declarator3
+   : declarator2_function_attributes   { $$ = $1 ; }
+   | declarator2                       { $$ = $1 ; }
+   ;
+
+function_declarator
+   : declarator2_function_attributes   { $$ = $1; }
+   | pointer declarator2_function_attributes
+         {
+            addDecl ($2,0,reverseLink($1));
+            $$ = $2 ;
+         }
+   ;
+   
+declarator2_function_attributes
+   : function_declarator2                { $$ = $1 ; } 
+   | function_declarator2 function_attribute  { 
+           // copy the functionAttributes (not the args and hasVargs !!)
+           struct value *args;
+           unsigned hasVargs;
+           sym_link *funcType=$1->type;
+
+          while (funcType && !IS_FUNC(funcType))
+            funcType = funcType->next;
+          
+          if (!funcType)
+            werror (E_FUNC_ATTR);
+          else
+            {
+              args=FUNC_ARGS(funcType);
+               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
    : identifier
    | '(' declarator ')'     { $$ = $2; }
-   | declarator2 '[' ']'
+   | declarator3 '[' ']'
          {
-            link   *p;
+            sym_link   *p;
 
-            p = newLink ();
+            p = newLink (DECLARATOR);
             DCL_TYPE(p) = ARRAY ;
             DCL_ELEM(p) = 0     ;
             addDecl($1,0,p);
          }
-   | declarator2 '[' constant_expr ']'
+   | declarator3 '[' constant_expr ']'
          {
-            link   *p ;
+            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 ();
-               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 ')'
+   ;
+
+function_declarator2
+   : declarator2 '('  ')'      {  addDecl ($1,FUNCTION,NULL) ;   }
+   | declarator2 '('            { NestLevel++ ; currBlockno++;  }
+                     parameter_type_list ')'
          {
+             sym_link *funcType;
           
             addDecl ($1,FUNCTION,NULL) ;
+
+            funcType = $1->type;
+            while (funcType && !IS_FUNC(funcType))
+              funcType = funcType->next;
           
-            $1->hasVargs = IS_VARG($4);
-            $1->args = reverseVal($4)  ;
+            assert (funcType);
+            
+            FUNC_HASVARARGS(funcType) = IS_VARG($4);
+            FUNC_ARGS(funcType) = reverseVal($4);
             
             /* nest level was incremented to take care of the parms  */
             NestLevel-- ;
             currBlockno--;
+
+            // if this was a pointer (to a function)
+            if (!IS_FUNC($1->type))
+              cleanUpLevel(SymbolTab,NestLevel+1);
+            
             $$ = $1;
          }
    | declarator2 '(' parameter_identifier_list ')'
          {        
           werror(E_OLD_STYLE,$1->name) ;         
-          
-          /* assume it returns an it */
+          /* assume it returns an int */
           $1->type = $1->etype = newIntLink();
           $$ = $1 ;
          }
    ;
-
+   
 pointer
-   : far_near_pointer { $$ = $1 ;}
-   | far_near_pointer type_specifier_list   
+   : unqualified_pointer { $$ = $1 ;}
+   | unqualified_pointer type_specifier_list   
          {
-            $$ = $1  ;         
-            DCL_TSPEC($1) = $2;
+            $$ = $1  ;
+             if (IS_SPEC($2)) {
+                DCL_TSPEC($1) = $2;
+                 DCL_PTR_CONST($1) = SPEC_CONST($2);
+                 DCL_PTR_VOLATILE($1) = SPEC_VOLATILE($2);
+             }
+             else
+                 werror (W_PTR_TYPE_INVALID);
         }
-   | 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) {
@@ -922,13 +1172,15 @@ pointer
                     DCL_TYPE($3) = POINTER ;
                     break;
                 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 
@@ -937,31 +1189,30 @@ pointer
         }
    ;
 
-far_near_pointer
-   :  far_near '*'   {
-                        if ($1 == NULL) {
-                           $$ = newLink();
-                           DCL_TYPE($$) = POINTER ;
-                        }
-                        else
-                           $$ = $1 ;
+unqualified_pointer
+   :  '*'   
+      {
+       $$ = newLink(DECLARATOR);
+       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 type_specifier skipped");
+       $$ = $2 ;
+     }
+     else
+       $$ = mergeSpec($1,$2, "type_specifier_list type_specifier");
+   }
    ;
 
 parameter_identifier_list
@@ -984,11 +1235,11 @@ parameter_type_list
        ;
 
 parameter_list
-   : parameter_declaration 
+   : parameter_declaration
    | parameter_list ',' parameter_declaration
          {
             $3->next = $1 ;
-            $$ = $3 ;      
+            $$ = $3 ;
          }
    ;
 
@@ -1001,48 +1252,58 @@ parameter_declaration
                  for (loop=$2;loop;loop->_isparm=1,loop=loop->next);
                  addSymChain ($2);
                  $$ = symbolVal($2);
+                 ignoreTypedefType = 0;
                }
    | type_name { 
                   $$ = newValue() ; 
                   $$->type = $1;
                   $$->etype = getSpec($$->type);
+                  ignoreTypedefType = 0;
                }
    ;
 
 type_name
-   : type_specifier_list  { $$ = $1 ;}
+   : type_specifier_list  { $$ = $1; ignoreTypedefType = 0;}
    | type_specifier_list abstract_declarator 
                {
                 /* go to the end of the list */
-                link *p;
+                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 ;
+                ignoreTypedefType = 0;
                }   
    ;
 
 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
    : '(' 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 ;
@@ -1050,15 +1311,41 @@ abstract_declarator2
    | abstract_declarator2 '[' constant_expr ']'
                                     {
                                        value *val ;
-                                       $$ = newLink ();
+                                       $$ = newLink (DECLARATOR);
                                        DCL_TYPE($$) = ARRAY ;
                                        DCL_ELEM($$) = (int) floatFromVal(val = constExprValue($3,TRUE));
                                        $$->next = $1 ;
                                     }
    | '(' ')'                        { $$ = 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(DECLARATOR);
+     DCL_TYPE(p) = FUNCTION;
+     if (!$1) {
+       // ((void (code *) ()) 0) ()
+       $1=newLink(DECLARATOR);
+       DCL_TYPE($1)=CPOINTER;
+       $$ = $1;
+     }
+     $1->next=p;
+   }
+   | abstract_declarator2 '(' { NestLevel++ ; currBlockno++; } parameter_type_list ')' {
+       sym_link *p=newLink(DECLARATOR);
+       DCL_TYPE(p) = FUNCTION;
+          
+       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);
+   }
    ;
 
 initializer
@@ -1079,21 +1366,60 @@ statement
    | selection_statement
    | iteration_statement
    | jump_statement
+   | critical_statement
    | INLINEASM  ';'      {
-                            ast *ex = newNode(INLINEASM,NULL,NULL);
-                           ALLOC_ATOMIC(ex->values.inlineasm,strlen($1));
-                           strcpy(ex->values.inlineasm,$1);                        
+                            ast *ex;
+                           seqPointNo++;
+                           ex = newNode(INLINEASM,NULL,NULL);
+                           ex->values.inlineasm = strdup($1);
+                           seqPointNo++;
                            $$ = ex;
-                         }   
+                         } 
    ;
 
+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);  }   
-   | CASE constant_expr ':' statement  {  $$ = createCase(STACK_PEEK(swStk),$2,$4); }
-   | DEFAULT ':' statement             {  $$ = createDefault(STACK_PEEK(swStk),$3); }
+//   : identifier ':' statement          {  $$ = createLabel($1,$3);  }   
+   : identifier ':'                    {  $$ = createLabel($1,NULL);  }   
+   | CASE constant_expr ':' statement
+     {
+       if (STACK_EMPTY(swStk))
+         $$ = createCase(NULL,$2,$4);
+       else
+         $$ = createCase(STACK_PEEK(swStk),$2,$4);
+     }
+   | DEFAULT { $<asts>$ = newNode(DEFAULT,NULL,NULL); } ':' statement
+     {
+       if (STACK_EMPTY(swStk))
+         $$ = createDefault(NULL,$<asts>2,$4);
+       else
+         $$ = createDefault(STACK_PEEK(swStk),$<asts>2,$4);
+     }
    ;
 
-start_block : '{' { STACK_PUSH(blockNum,currBlockno); currBlockno = ++blockNo ;  }
+start_block : '{'
+              {
+               STACK_PUSH(blockNum,currBlockno);
+               currBlockno = ++blockNo ;
+               ignoreTypedefType = 0;
+             }
             ;
 
 end_block   : '}'     { currBlockno = STACK_POP(blockNum); }           
@@ -1122,6 +1448,7 @@ declaration_list
        }
        else
         $$ = $1 ;
+       ignoreTypedefType = 0;
      }
 
    | declaration_list declaration
@@ -1144,6 +1471,7 @@ declaration_list
         else
           $$ = $2 ;
        }
+       ignoreTypedefType = 0;
      }
    ;
 
@@ -1154,7 +1482,7 @@ statement_list
 
 expression_statement
    : ';'                { $$ = NULL;}
-   | expr ';' 
+   | expr ';'           { $$ = $1; seqPointNo++;} 
    ;
 
 else_statement
@@ -1164,18 +1492,25 @@ else_statement
 
   
 selection_statement
-   : IF '(' expr ')'  statement else_statement { noLineno++ ; $$ = createIf ($3, $5, $6 ); noLineno--;}
+   : IF '(' expr ')' { seqPointNo++;} statement else_statement
+                           {
+                             noLineno++ ;
+                             $$ = createIf ($3, $6, $7 );
+                             noLineno--;
+                          }
    | SWITCH '(' expr ')'   { 
                               ast *ex ;                              
                               static   int swLabel = 0 ;
 
+                             seqPointNo++;
                               /* create a node for expression  */
                               ex = newNode(SWITCH,$3,NULL);
                               STACK_PUSH(swStk,ex);   /* save it in the stack */
                               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>$);   
@@ -1191,57 +1526,62 @@ 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 
+   : while '(' expr ')' { seqPointNo++;}  statement 
                          { 
                           noLineno++ ;
                           $$ = createWhile ( $1, STACK_POP(continueStack),
-                                             STACK_POP(breakStack), $3, $5 ); 
+                                             STACK_POP(breakStack), $3, $6 ); 
                           $$->lineno = $1->lineDef ;
                           noLineno-- ;
                         }
    | do statement   WHILE '(' expr ')' ';' 
                         { 
+                         seqPointNo++; 
                          noLineno++ ; 
                          $$ = createDo ( $1 , STACK_POP(continueStack), 
                                          STACK_POP(breakStack), $5, $2);
@@ -1276,41 +1616,57 @@ iteration_statement
 ;
 
 expr_opt
-       :                       { $$ = NULL ; }
-       |       expr
+       :                       { $$ = NULL ; seqPointNo++; }
+       |       expr            { $$ = $1 ; seqPointNo++; }
        ;
 
 jump_statement          
    : GOTO identifier ';'   { 
                               $2->islbl = 1;
-                              $$ = newAst(EX_VALUE,symbolVal($2)); 
+                              $$ = newAst_VALUE(symbolVal($2)); 
                               $$ = newNode(GOTO,$$,NULL);
                            }
    | CONTINUE ';'          {  
        /* make sure continue is in context */
-       if (STACK_PEEK(continueStack) == NULL) {
+       if (STACK_EMPTY(continueStack) || STACK_PEEK(continueStack) == NULL) {
           werror(E_BREAK_CONTEXT);
           $$ = NULL;
        }
        else {
-          $$ = newAst(EX_VALUE,symbolVal(STACK_PEEK(continueStack)));      
+          $$ = newAst_VALUE(symbolVal(STACK_PEEK(continueStack)));      
           $$ = newNode(GOTO,$$,NULL);
           /* mark the continue label as referenced */
           STACK_PEEK(continueStack)->isref = 1;
        }
    }
    | BREAK ';'             { 
-       if (STACK_PEEK(breakStack) == NULL) {
+       if (STACK_EMPTY(breakStack) || STACK_PEEK(breakStack) == NULL) {
           werror(E_BREAK_CONTEXT);
           $$ = NULL;
        } else {
-          $$ = newAst(EX_VALUE,symbolVal(STACK_PEEK(breakStack)));
+          $$ = newAst_VALUE(symbolVal(STACK_PEEK(breakStack)));
           $$ = newNode(GOTO,$$,NULL);
           STACK_PEEK(breakStack)->isref = 1;
        }
    }
-   | RETURN ';'            { $$ = newNode(RETURN,NULL,NULL)    ; }
-   | RETURN expr ';'       { $$ = newNode(RETURN,NULL,$2) ; } 
+   | RETURN ';'            {
+       seqPointNo++;
+       if (inCritical) {
+          werror(E_INVALID_CRITICAL);
+          $$ = NULL;
+       } else {
+          $$ = newNode(RETURN,NULL,NULL);
+       }
+   }
+   | RETURN expr ';'       {
+       seqPointNo++;
+       if (inCritical) {
+          werror(E_INVALID_CRITICAL);
+          $$ = NULL;
+       } else {
+          $$ = newNode(RETURN,NULL,$2);
+       }
+   }
    ;
 
 identifier
@@ -1318,20 +1674,3 @@ identifier
    ;
 %%
 
-extern unsigned char *yytext;
-extern int column;
-extern char *filename;
-extern int fatalError;
-
-int yyerror(char *s)
-{
-   fflush(stdout);
-
-   if ( yylineno )
-       fprintf(stderr,"\n%s(%d) %s: token -> '%s' ; column %d\n",
-               filename,yylineno,
-               s,yytext,column);
-   fatalError++;
-   return 0;
-}
-