How to make a specific rule in Yacc to reduce first before the other rule?

170 views Asked by At

I have a question about Yacc. Here is my Yacc code for parsing the C language grammar. Note that, the code below is only some relevant parts of the complete code:

%token  IDENTIFIER I_CONSTANT F_CONSTANT STRING_LITERAL FUNC_NAME SIZEOF
%token  PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
%token  AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
%token  SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
%token  XOR_ASSIGN OR_ASSIGN
%token  TYPEDEF_NAME ENUMERATION_CONSTANT
%token  TYPEDEF EXTERN STATIC AUTO REGISTER INLINE
%token  CONST RESTRICT VOLATILE
%token  BOOL CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE VOID
%token  COMPLEX IMAGINARY
%token  STRUCT UNION ENUM ELLIPSIS
%token  CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN
%token  ALIGNAS ALIGNOF ATOMIC GENERIC NORETURN STATIC_ASSERT THREAD_LOCAL

%union{
    char* a;
    char* b;
}

%type <a>IDENTIFIER
%type <a>SIGNED UNSIGNED
%type <a>INT CHAR DOUBLE FLOAT LONG SHORT
%type <b>EXTERN STATIC AUTO REGISTER

%%
declaration
: declaration_specifiers ';'  
| declaration_specifiers init_declarator_list ';' { printf("semicolon:%s\n", $<a>3);} 
| static_assert_declaration
;

declaration_specifiers
: storage_class_specifier declaration_specifiers 
| storage_class_specifier                    
| type_specifier declaration_specifiers      
| type_specifier                             
| type_qualifier declaration_specifiers      
| type_qualifier                             
| function_specifier declaration_specifiers
| function_specifier
| alignment_specifier declaration_specifiers
| alignment_specifier
;

init_declarator_list
: init_declarator                           
| init_declarator_list ',' init_declarator  {printf("The comma:%s\n",$<a>2);} 
;

type_specifier
: VOID                                          {printf("type_specifier:%s\n",$<a>1);}
| CHAR                                          {printf("type_specifier:%s\n",$<a>1);}
| SHORT                                         {printf("type_specifier:%s\n",$<a>1);}
| INT                                           {printf("type_specifier:%s\n",$<a>1);}
| LONG                                          {printf("type_specifier:%s\n",$<a>1);}
| FLOAT                                         {printf("type_specifier:%s\n",$<a>1);}
| DOUBLE                                        {printf("type_specifier:%s\n",$<a>1);}
| SIGNED                                        {printf("type_specifier:%s\n",$<a>1);}
| UNSIGNED                                      {printf("type_specifier:%s\n",$<a>1);}
| BOOL                                          {printf("type_specifier:%s\n",$<a>1);}
| COMPLEX                                       {printf("type_specifier:%s\n",$<a>1);}
| IMAGINARY     /* non-mandated extension */    {printf("type_specifier:%s\n",$<a>1);}
| atomic_type_specifier                         {printf("type_specifier:%s\n",$<a>1);}
| struct_or_union_specifier                     {printf("type_specifier:%s\n",$<a>1);}
| enum_specifier                                {printf("type_specifier:%s\n",$<a>1);}
| TYPEDEF_NAME  {printf("type_specifier:%s\n",$<a>1);}
;

declarator
: pointer direct_declarator  
| direct_declarator  
;

direct_declarator
: IDENTIFIER {printf("The identifier: %s\n", $<a>1);}   
| '(' declarator ')'   
| direct_declarator '[' ']'     
| direct_declarator '[' '*' ']' 
| direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' 
| direct_declarator '[' STATIC assignment_expression ']' 
| direct_declarator '[' type_qualifier_list '*' ']' 
| direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' 
| direct_declarator '[' type_qualifier_list assignment_expression ']' 
| direct_declarator '[' type_qualifier_list ']'
| direct_declarator '[' assignment_expression ']' 
| direct_declarator '(' parameter_type_list ')'
| direct_declarator '(' ')' 
| direct_declarator '(' identifier_list ')' 
;

And here is my Lex code corresponding to the Yacc code (Again, these are only relevant parts):

"int"                   { yylval.a=strdup(yytext); return(INT); } /* Data Type*/
"long"                  { yylval.a=strdup(yytext); return(LONG); }
"char"                  { yylval.a=strdup(yytext); return(CHAR); }
"short"                 { yylval.a=strdup(yytext); return(SHORT); }
"signed"                { yylval.a=strdup(yytext); return(SIGNED); }
"double"                { yylval.a=strdup(yytext); return(DOUBLE); }
"unsigned"              { yylval.a=strdup(yytext); return(UNSIGNED); }
"float"                 { yylval.a=strdup(yytext); return(FLOAT); }
";"                     { yylval.a=strdup(yytext); return ';'; }
","                     { yylval.a=strdup(yytext); return ','; }

My problem is that when I enter the input in command such as:

int a,b;

It should print:

type_specifier:int
The identifier: a
The comma:,
The identifier:b
semicolon:;

but my output is

type_specifier:int
The identifier: a
The identifier: b
The comma:,
semicolon:;

What should I do to make the routine: {printf("The comma:%s\n",$<a>2);} activate between two IDENTIFIER {printf("The identifier: %s\n", $<a>1);}

References (original versions)

https://www.lysator.liu.se/c/ANSI-C-grammar-y.html

https://www.lysator.liu.se/c/ANSI-C-grammar-l.html

1

There are 1 answers

0
David Gorsline On BEST ANSWER

Your printf doesn't execute until you've completed the parsing of init_declarator. Try this instead:

| init_declarator_list ',' {printf("The comma:%s\n",$<a>2);}  init_declarator