33
33
34
34
35
35
# These hash tables define additional transformations to apply to
36
- # grammar rules.
36
+ # grammar rules. For bug-detection purposes, we count usages of
37
+ # each hash table entry in a second hash table, and verify that
38
+ # all the entries get used.
37
39
38
40
# Substitutions to apply to tokens whenever they are seen in a rule.
39
41
my %replace_token = (
44
46
' IDENT' => ' ecpg_ident' ,
45
47
' PARAM' => ' ecpg_param' ,);
46
48
49
+ my %replace_token_used ;
50
+
47
51
# This hash can provide a result type to override "void" for nonterminals
48
52
# that need that, or it can specify 'ignore' to cause us to skip the rule
49
53
# for that nonterminal. (In either case, ecpg.trailer had better provide
68
72
' plassign_target' => ' ignore' ,
69
73
' plassign_equals' => ' ignore' ,);
70
74
75
+ my %replace_types_used ;
76
+
71
77
# This hash provides an "ignore" option or substitute expansion for any
72
78
# rule or rule alternative. The hash key is the same "concattokens" tag
73
79
# used for lookup in ecpg.addons.
111
117
' PREPARE prepared_name prep_type_clause AS PreparableStmt' ,
112
118
' var_nameColId' => ' ECPGColId' );
113
119
120
+ my %replace_line_used ;
121
+
114
122
115
123
# Declare assorted state variables.
116
124
198
206
die " addon rule $_ was matched multiple times\n " if $addons {$_ }{used } > 1;
199
207
}
200
208
209
+ # Likewise cross-check that entries in our internal hash tables match something.
210
+ foreach (keys %replace_token )
211
+ {
212
+ die " replace_token entry $_ was never used\n "
213
+ if !defined ($replace_token_used {$_ });
214
+ # multiple use of a replace_token entry is fine
215
+ }
216
+
217
+ foreach (keys %replace_types )
218
+ {
219
+ die " replace_types entry $_ was never used\n "
220
+ if !defined ($replace_types_used {$_ });
221
+ die " replace_types entry $_ was matched multiple times\n "
222
+ if $replace_types_used {$_ } > 1;
223
+ }
224
+
225
+ foreach (keys %replace_line )
226
+ {
227
+ die " replace_line entry $_ was never used\n "
228
+ if !defined ($replace_line_used {$_ });
229
+ die " replace_line entry $_ was matched multiple times\n "
230
+ if $replace_line_used {$_ } > 1;
231
+ }
232
+
201
233
202
234
# Read the backend grammar.
203
235
sub main
@@ -399,6 +431,7 @@ sub main
399
431
# Apply replace_token substitution if we have one.
400
432
if (exists $replace_token { $arr [$fieldIndexer ] })
401
433
{
434
+ $replace_token_used { $arr [$fieldIndexer ] }++;
402
435
$arr [$fieldIndexer ] = $replace_token { $arr [$fieldIndexer ] };
403
436
}
404
437
@@ -424,6 +457,7 @@ sub main
424
457
&& $replace_types {$non_term_id } eq ' ignore' )
425
458
{
426
459
# We'll ignore this nonterminal and rule altogether.
460
+ $replace_types_used {$non_term_id }++;
427
461
$copymode = 0;
428
462
next line;
429
463
}
@@ -450,6 +484,7 @@ sub main
450
484
. $replace_types {$non_term_id } . ' '
451
485
. $non_term_id ;
452
486
add_to_buffer(' types' , $tstr );
487
+ $replace_types_used {$non_term_id }++;
453
488
}
454
489
455
490
# Emit the target part of the rule.
@@ -615,8 +650,10 @@ sub emit_rule
615
650
616
651
# apply replace_line substitution if any
617
652
my $rep = $replace_line {$tag };
618
- if ($rep )
653
+ if (defined $rep )
619
654
{
655
+ $replace_line_used {$tag }++;
656
+
620
657
if ($rep eq ' ignore' )
621
658
{
622
659
return 0;
0 commit comments