Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / tools / check_keywords.pl
blob8d0d96251e580681a88a7bd24a800ca7d60103b5
1 #!/usr/bin/perl -w
3 use strict;
5 # Check that the keyword lists in gram.y and kwlist.h are sane. Run from
6 # the top directory, or pass a path to a top directory as argument.
8 # $PostgreSQL$
10 my $path;
12 if (@ARGV) {
13 $path = $ARGV[0];
14 shift @ARGV;
15 } else {
16 $path = ".";
19 $[ = 1; # set array base to 1
20 $, = ' '; # set output field separator
21 $\ = "\n"; # set output record separator
23 my %keyword_categories;
24 $keyword_categories{'unreserved_keyword'} = 'UNRESERVED_KEYWORD';
25 $keyword_categories{'col_name_keyword'} = 'COL_NAME_KEYWORD';
26 $keyword_categories{'type_func_name_keyword'} = 'TYPE_FUNC_NAME_KEYWORD';
27 $keyword_categories{'reserved_keyword'} = 'RESERVED_KEYWORD';
29 my $gram_filename = "$path/src/backend/parser/gram.y";
30 open(GRAM, $gram_filename) || die("Could not open : $gram_filename");
32 my ($S, $s, $k, $n, $kcat);
33 my $comment;
34 my @arr;
35 my %keywords;
37 line: while (<GRAM>) {
38 chomp; # strip record separator
40 $S = $_;
41 # Make sure any braces are split
42 $s = '{', $S =~ s/$s/ { /g;
43 $s = '}', $S =~ s/$s/ } /g;
44 # Any comments are split
45 $s = '[/][*]', $S =~ s#$s# /* #g;
46 $s = '[*][/]', $S =~ s#$s# */ #g;
48 if (!($kcat)) {
49 # Is this the beginning of a keyword list?
50 foreach $k (keys %keyword_categories) {
51 if ($S =~ m/^($k):/) {
52 $kcat = $k;
53 next line;
56 next line;
59 # Now split the line into individual fields
60 $n = (@arr = split(' ', $S));
62 # Ok, we're in a keyword list. Go through each field in turn
63 for (my $fieldIndexer = 1; $fieldIndexer <= $n; $fieldIndexer++) {
64 if ($arr[$fieldIndexer] eq '*/' && $comment) {
65 $comment = 0;
66 next;
68 elsif ($comment) {
69 next;
71 elsif ($arr[$fieldIndexer] eq '/*') {
72 # start of a multiline comment
73 $comment = 1;
74 next;
76 elsif ($arr[$fieldIndexer] eq '//') {
77 next line;
80 if ($arr[$fieldIndexer] eq ';') {
81 # end of keyword list
82 $kcat = '';
83 next;
86 if ($arr[$fieldIndexer] eq '|') {
87 next;
90 # Put this keyword into the right list
91 push @{$keywords{$kcat}}, $arr[$fieldIndexer];
94 close GRAM;
96 # Check that all keywords are in alphabetical order
97 my ($prevkword, $kword, $bare_kword);
98 foreach $kcat (keys %keyword_categories) {
99 $prevkword = '';
101 foreach $kword (@{$keywords{$kcat}}) {
102 # Some keyword have a _P suffix. Remove it for the comparison.
103 $bare_kword = $kword;
104 $bare_kword =~ s/_P$//;
105 if ($bare_kword le $prevkword) {
106 print "'$bare_kword' after '$prevkword' in $kcat list is misplaced";
108 $prevkword = $bare_kword;
112 # Transform the keyword lists into hashes.
113 # kwhashes is a hash of hashes, keyed by keyword category id, e.g.
114 # UNRESERVED_KEYWORD. Each inner hash is a keyed by keyword id, e.g. ABORT_P
115 # with a dummy value.
116 my %kwhashes;
117 while ( my ($kcat, $kcat_id) = each(%keyword_categories) ) {
118 @arr = @{$keywords{$kcat}};
120 my $hash;
121 foreach my $item (@arr) { $hash->{$item} = 1 }
123 $kwhashes{$kcat_id} = $hash;
126 # Now read in kwlist.h
128 my $kwlist_filename = "$path/src/include/parser/kwlist.h";
129 open(KWLIST, $kwlist_filename) || die("Could not open : $kwlist_filename");
131 my $prevkwstring = '';
132 my $bare_kwname;
133 my %kwhash;
134 kwlist_line: while (<KWLIST>) {
135 my($line) = $_;
137 if ($line =~ /^PG_KEYWORD\(\"(.*)\", (.*), (.*)\)/)
139 my($kwstring) = $1;
140 my($kwname) = $2;
141 my($kwcat_id) = $3;
143 # Check that the list is in alphabetical order
144 if ($kwstring le $prevkwstring) {
145 print "'$kwstring' after '$prevkwstring' in kwlist.h is misplaced";
147 $prevkwstring = $kwstring;
149 # Check that the keyword string is valid: all lower-case ASCII chars
150 if ($kwstring !~ /^[a-z_]*$/) {
151 print "'$kwstring' is not a valid keyword string, must be all lower-case ASCII chars";
154 # Check that the keyword name is valid: all upper-case ASCII chars
155 if ($kwname !~ /^[A-Z_]*$/) {
156 print "'$kwname' is not a valid keyword name, must be all upper-case ASCII chars";
159 # Check that the keyword string matches keyword name
160 $bare_kwname = $kwname;
161 $bare_kwname =~ s/_P$//;
162 if ($bare_kwname ne uc($kwstring)) {
163 print "keyword name '$kwname' doesn't match keyword string '$kwstring'";
166 # Check that the keyword is present in the grammar
167 %kwhash = %{$kwhashes{$kwcat_id}};
169 if (!(%kwhash)) {
170 #print "Unknown kwcat_id: $kwcat_id";
171 } else {
172 if (!($kwhash{$kwname})) {
173 print "'$kwname' not present in $kwcat_id section of gram.y";
174 } else {
175 # Remove it from the hash, so that we can complain at the end
176 # if there's keywords left that were not found in kwlist.h
177 delete $kwhashes{$kwcat_id}->{$kwname};
182 close KWLIST;
184 # Check that we've paired up all keywords from gram.y with lines in kwlist.h
185 while ( my ($kwcat, $kwcat_id) = each(%keyword_categories) ) {
186 %kwhash = %{$kwhashes{$kwcat_id}};
188 for my $kw ( keys %kwhash ) {
189 print "'$kw' found in gram.y $kwcat category, but not in kwlist.h"