1#!/usr/bin/perl 2# src/interfaces/ecpg/preproc/check_rules.pl 3# test parser generator for ecpg 4# call with backend grammar as stdin 5# 6# Copyright (c) 2009-2019, PostgreSQL Global Development Group 7# 8# Written by Michael Meskes <meskes@postgresql.org> 9# Andy Colson <andy@squeakycode.net> 10# 11# Placed under the same license as PostgreSQL. 12# 13# Command line: [-v] [path only to ecpg.addons] [full filename of gram.y] 14# -v enables verbose mode... show's some stats... thought it might be interesting 15# 16# This script loads rule names from gram.y and sets $found{rule} = 1 for each. 17# Then it checks to make sure each rule in ecpg.addons was found in gram.y 18 19use strict; 20use warnings; 21no warnings 'uninitialized'; 22 23my $verbose = 0; 24if ($ARGV[0] eq '-v') 25{ 26 $verbose = shift; 27} 28my $path = shift || '.'; 29my $parser = shift || '../../../backend/parser/gram.y'; 30 31my $filename = $path . "/ecpg.addons"; 32if ($verbose) 33{ 34 print "parser: $parser\n"; 35 print "addons: $filename\n"; 36} 37 38my %replace_line = ( 39 'ExecuteStmtEXECUTEnameexecute_param_clause' => 40 'EXECUTE prepared_name execute_param_clause execute_rest', 41 42 'ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEnameexecute_param_clauseopt_with_data' 43 => 'CREATE OptTemp TABLE create_as_target AS EXECUTE prepared_name execute_param_clause opt_with_data execute_rest', 44 45 'ExecuteStmtCREATEOptTempTABLEIF_PNOTEXISTScreate_as_targetASEXECUTEnameexecute_param_clauseopt_with_data' 46 => 'CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS EXECUTE prepared_name execute_param_clause opt_with_data execute_rest', 47 48 'PrepareStmtPREPAREnameprep_type_clauseASPreparableStmt' => 49 'PREPARE prepared_name prep_type_clause AS PreparableStmt'); 50 51my $block = ''; 52my $yaccmode = 0; 53my $in_rule = 0; 54my $brace_indent = 0; 55my (@arr, %found); 56my $comment = 0; 57my $non_term_id = ''; 58my $cc = 0; 59 60open my $parser_fh, '<', $parser or die $!; 61while (<$parser_fh>) 62{ 63 if (/^%%/) 64 { 65 $yaccmode++; 66 } 67 68 if ($yaccmode != 1) 69 { 70 next; 71 } 72 73 chomp; # strip record separator 74 75 next if ($_ eq ''); 76 77 # Make sure any braces are split 78 s/{/ { /g; 79 s/}/ } /g; 80 81 # Any comments are split 82 s|\/\*| /* |g; 83 s|\*\/| */ |g; 84 85 # Now split the line into individual fields 86 my $n = (@arr = split(' ')); 87 88 # Go through each field in turn 89 for (my $fieldIndexer = 0; $fieldIndexer < $n; $fieldIndexer++) 90 { 91 if ($arr[$fieldIndexer] eq '*/' && $comment) 92 { 93 $comment = 0; 94 next; 95 } 96 elsif ($comment) 97 { 98 next; 99 } 100 elsif ($arr[$fieldIndexer] eq '/*') 101 { 102 103 # start of a multiline comment 104 $comment = 1; 105 next; 106 } 107 elsif ($arr[$fieldIndexer] eq '//') 108 { 109 next; 110 } 111 elsif ($arr[$fieldIndexer] eq '}') 112 { 113 $brace_indent--; 114 next; 115 } 116 elsif ($arr[$fieldIndexer] eq '{') 117 { 118 $brace_indent++; 119 next; 120 } 121 122 if ($brace_indent > 0) 123 { 124 next; 125 } 126 127 if ($arr[$fieldIndexer] eq ';' || $arr[$fieldIndexer] eq '|') 128 { 129 $block = $non_term_id . $block; 130 if ($replace_line{$block}) 131 { 132 $block = $non_term_id . $replace_line{$block}; 133 $block =~ tr/ |//d; 134 } 135 $found{$block} = 1; 136 $cc++; 137 $block = ''; 138 $in_rule = 0 if $arr[$fieldIndexer] eq ';'; 139 } 140 elsif (($arr[$fieldIndexer] =~ '[A-Za-z0-9]+:') 141 || $arr[ $fieldIndexer + 1 ] eq ':') 142 { 143 die "unterminated rule at grammar line $.\n" 144 if $in_rule; 145 $in_rule = 1; 146 $non_term_id = $arr[$fieldIndexer]; 147 $non_term_id =~ tr/://d; 148 } 149 else 150 { 151 $block = $block . $arr[$fieldIndexer]; 152 } 153 } 154} 155 156die "unterminated rule at end of grammar\n" 157 if $in_rule; 158 159close $parser_fh; 160if ($verbose) 161{ 162 print "$cc rules loaded\n"; 163} 164 165my $ret = 0; 166$cc = 0; 167 168open my $ecpg_fh, '<', $filename or die $!; 169while (<$ecpg_fh>) 170{ 171 if (!/^ECPG:/) 172 { 173 next; 174 } 175 176 my @Fld = split(' ', $_, 3); 177 $cc++; 178 if (not exists $found{ $Fld[1] }) 179 { 180 print $Fld[1], " is not used for building parser!\n"; 181 $ret = 1; 182 } 183} 184close $ecpg_fh; 185 186if ($verbose) 187{ 188 print "$cc rules checked\n"; 189} 190 191exit $ret; 192