Skip to content

Commit 3ccda63

Browse files
committed
genksyms: fix 6 shift/reduce conflicts and 5 reduce/reduce conflicts
The genksyms parser has ambiguities in its grammar, which are currently suppressed by a workaround in scripts/genksyms/Makefile. Building genksyms with W=1 generates the following warnings: YACC scripts/genksyms/parse.tab.[ch] scripts/genksyms/parse.y: warning: 9 shift/reduce conflicts [-Wconflicts-sr] scripts/genksyms/parse.y: warning: 5 reduce/reduce conflicts [-Wconflicts-rr] scripts/genksyms/parse.y: note: rerun with option '-Wcounterexamples' to generate conflict counterexamples The comment in the parser describes the current problem: /* This wasn't really a typedef name but an identifier that shadows one. */ Consider the following simple C code: typedef int foo; void my_func(foo foo) {} In the function parameter list (foo foo), the first 'foo' is a type specifier (typedef'ed as 'int'), while the second 'foo' is an identifier. However, the lexer cannot distinguish between the two. Since 'foo' is already typedef'ed, the lexer returns TYPE for both instances, instead of returning IDENT for the second one. To support shadowed identifiers, TYPE can be reduced to either a simple_type_specifier or a direct_abstract_declarator, which creates a grammatical ambiguity. Without analyzing the grammar context, it is very difficult to resolve this correctly. This commit introduces a flag, dont_want_type_specifier, which allows the parser to inform the lexer whether an identifier is expected. When dont_want_type_specifier is true, the type lookup is suppressed, and the lexer returns IDENT regardless of any preceding typedef. After this commit, only 3 shift/reduce conflicts will remain. Signed-off-by: Masahiro Yamada <[email protected]> Acked-by: Nicolas Schier <[email protected]>
1 parent bc3a812 commit 3ccda63

File tree

3 files changed

+26
-23
lines changed

3 files changed

+26
-23
lines changed

scripts/genksyms/genksyms.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#ifndef MODUTILS_GENKSYMS_H
1313
#define MODUTILS_GENKSYMS_H 1
1414

15+
#include <stdbool.h>
1516
#include <stdio.h>
1617

1718
#include <list_types.h>
@@ -66,6 +67,8 @@ struct string_list *copy_list_range(struct string_list *start,
6667
int yylex(void);
6768
int yyparse(void);
6869

70+
extern bool dont_want_type_specifier;
71+
6972
void error_with_pos(const char *, ...) __attribute__ ((format(printf, 1, 2)));
7073

7174
/*----------------------------------------------------------------------*/

scripts/genksyms/lex.l

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
%{
1313

1414
#include <limits.h>
15+
#include <stdbool.h>
1516
#include <stdlib.h>
1617
#include <string.h>
1718
#include <ctype.h>
@@ -113,6 +114,12 @@ MC_TOKEN ([~%^&*+=|<>/-]=)|(&&)|("||")|(->)|(<<)|(>>)
113114
/* The second stage lexer. Here we incorporate knowledge of the state
114115
of the parser to tailor the tokens that are returned. */
115116
117+
/*
118+
* The lexer cannot distinguish whether a typedef'ed string is a TYPE or an
119+
* IDENT. We need a hint from the parser to handle this accurately.
120+
*/
121+
bool dont_want_type_specifier;
122+
116123
int
117124
yylex(void)
118125
{
@@ -207,7 +214,7 @@ repeat:
207214
goto repeat;
208215
}
209216
}
210-
if (!suppress_type_lookup)
217+
if (!suppress_type_lookup && !dont_want_type_specifier)
211218
{
212219
if (find_symbol(yytext, SYM_TYPEDEF, 1))
213220
token = TYPE;

scripts/genksyms/parse.y

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
%{
1313

1414
#include <assert.h>
15+
#include <stdbool.h>
1516
#include <stdlib.h>
1617
#include <string.h>
1718
#include "genksyms.h"
@@ -148,6 +149,7 @@ simple_declaration:
148149
current_name = NULL;
149150
}
150151
$$ = $3;
152+
dont_want_type_specifier = false;
151153
}
152154
;
153155

@@ -169,6 +171,7 @@ init_declarator_list:
169171
is_typedef ? SYM_TYPEDEF : SYM_NORMAL, decl, is_extern);
170172
current_name = NULL;
171173
$$ = $1;
174+
dont_want_type_specifier = true;
172175
}
173176
| init_declarator_list ',' init_declarator
174177
{ struct string_list *decl = *$3;
@@ -184,6 +187,7 @@ init_declarator_list:
184187
is_typedef ? SYM_TYPEDEF : SYM_NORMAL, decl, is_extern);
185188
current_name = NULL;
186189
$$ = $3;
190+
dont_want_type_specifier = true;
187191
}
188192
;
189193

@@ -210,7 +214,7 @@ decl_specifier:
210214
remove_node($1);
211215
$$ = $1;
212216
}
213-
| type_specifier
217+
| type_specifier { dont_want_type_specifier = true; $$ = $1; }
214218
| type_qualifier
215219
;
216220

@@ -307,15 +311,7 @@ direct_declarator:
307311
current_name = (*$1)->string;
308312
$$ = $1;
309313
}
310-
}
311-
| TYPE
312-
{ if (current_name != NULL) {
313-
error_with_pos("unexpected second declaration name");
314-
YYERROR;
315-
} else {
316-
current_name = (*$1)->string;
317-
$$ = $1;
318-
}
314+
dont_want_type_specifier = false;
319315
}
320316
| direct_declarator '(' parameter_declaration_clause ')'
321317
{ $$ = $4; }
@@ -335,8 +331,7 @@ nested_declarator:
335331
;
336332

337333
direct_nested_declarator:
338-
IDENT
339-
| TYPE
334+
IDENT { $$ = $1; dont_want_type_specifier = false; }
340335
| direct_nested_declarator '(' parameter_declaration_clause ')'
341336
{ $$ = $4; }
342337
| direct_nested_declarator '(' error ')'
@@ -362,8 +357,9 @@ parameter_declaration_list_opt:
362357

363358
parameter_declaration_list:
364359
parameter_declaration
360+
{ $$ = $1; dont_want_type_specifier = false; }
365361
| parameter_declaration_list ',' parameter_declaration
366-
{ $$ = $3; }
362+
{ $$ = $3; dont_want_type_specifier = false; }
367363
;
368364

369365
parameter_declaration:
@@ -375,6 +371,7 @@ abstract_declarator:
375371
ptr_operator abstract_declarator
376372
{ $$ = $2 ? $2 : $1; }
377373
| direct_abstract_declarator
374+
{ $$ = $1; dont_want_type_specifier = false; }
378375
;
379376

380377
direct_abstract_declarator:
@@ -385,12 +382,6 @@ direct_abstract_declarator:
385382
remove_node($1);
386383
$$ = $1;
387384
}
388-
/* This wasn't really a typedef name but an identifier that
389-
shadows one. */
390-
| TYPE
391-
{ remove_node($1);
392-
$$ = $1;
393-
}
394385
| direct_abstract_declarator '(' parameter_declaration_clause ')'
395386
{ $$ = $4; }
396387
| direct_abstract_declarator '(' error ')'
@@ -440,9 +431,9 @@ member_specification:
440431

441432
member_declaration:
442433
decl_specifier_seq_opt member_declarator_list_opt ';'
443-
{ $$ = $3; }
434+
{ $$ = $3; dont_want_type_specifier = false; }
444435
| error ';'
445-
{ $$ = $2; }
436+
{ $$ = $2; dont_want_type_specifier = false; }
446437
;
447438

448439
member_declarator_list_opt:
@@ -452,7 +443,9 @@ member_declarator_list_opt:
452443

453444
member_declarator_list:
454445
member_declarator
455-
| member_declarator_list ',' member_declarator { $$ = $3; }
446+
{ $$ = $1; dont_want_type_specifier = true; }
447+
| member_declarator_list ',' member_declarator
448+
{ $$ = $3; dont_want_type_specifier = true; }
456449
;
457450

458451
member_declarator:

0 commit comments

Comments
 (0)