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