diff options
Diffstat (limited to 'src/interfaces/ecpg/preproc/parse.pl')
-rw-r--r-- | src/interfaces/ecpg/preproc/parse.pl | 58 |
1 files changed, 45 insertions, 13 deletions
diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index fe8d3e51780..86d0782d456 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -1,7 +1,13 @@ #!/usr/bin/perl # src/interfaces/ecpg/preproc/parse.pl -# parser generator for ecpg version 2 -# call with backend parser as stdin +# parser generator for ecpg +# +# See README.parser for some explanation of what this does. +# +# Command-line options: +# --srcdir: where to find ecpg-provided input files (default ".") +# --parser: the backend gram.y file to read (required, no default) +# --output: where to write preproc.y (required, no default) # # Copyright (c) 2007-2024, PostgreSQL Global Development Group # @@ -148,6 +154,14 @@ dump_buffer('trailer'); close($parserfh); +# Cross-check that we don't have dead or ambiguous addon rules. +foreach (keys %addons) +{ + die "addon rule $_ was never used\n" if $addons{$_}{used} == 0; + die "addon rule $_ was matched multiple times\n" if $addons{$_}{used} > 1; +} + + sub main { line: while (<$parserfh>) @@ -487,7 +501,10 @@ sub include_addon my $rec = $addons{$block}; return 0 unless $rec; - my $rectype = (defined $rec->{type}) ? $rec->{type} : ''; + # Track usage for later cross-check + $rec->{used}++; + + my $rectype = $rec->{type}; if ($rectype eq 'rule') { dump_fields($stmt_mode, $fields, ' { '); @@ -668,10 +685,10 @@ sub dump_line } =top - load addons into cache + load ecpg.addons into %addons hash. The result is something like %addons = { - stmtClosePortalStmt => { 'type' => 'block', 'lines' => [ "{", "if (INFORMIX_MODE)" ..., "}" ] }, - stmtViewStmt => { 'type' => 'rule', 'lines' => [ "| ECPGAllocateDescr", ... ] } + stmtClosePortalStmt => { 'type' => 'block', 'lines' => [ "{", "if (INFORMIX_MODE)" ..., "}" ], 'used' => 0 }, + stmtViewStmt => { 'type' => 'rule', 'lines' => [ "| ECPGAllocateDescr", ... ], 'used' => 0 } } =cut @@ -681,17 +698,25 @@ sub preload_addons my $filename = $srcdir . "/ecpg.addons"; open(my $fh, '<', $filename) or die; - # there may be multiple lines starting ECPG: and then multiple lines of code. - # the code need to be add to all prior ECPG records. - my (@needsRules, @code, $record); + # There may be multiple "ECPG:" lines and then multiple lines of code. + # The block of code needs to be added to each of the consecutively- + # preceding "ECPG:" records. + my (@needsRules, @code); - # there may be comments before the first ECPG line, skip them + # there may be comments before the first "ECPG:" line, skip them my $skip = 1; while (<$fh>) { - if (/^ECPG:\s(\S+)\s?(\w+)?/) + if (/^ECPG:\s+(\S+)\s+(\w+)\s*$/) { + # Found an "ECPG:" line, so we're done skipping the header $skip = 0; + # Validate record type and target + die "invalid record type $2 in addon rule for $1\n" + unless ($2 eq 'block' or $2 eq 'addon' or $2 eq 'rule'); + die "duplicate addon rule for $1\n" if (exists $addons{$1}); + # If we had some preceding code lines, attach them to all + # as-yet-unfinished records. if (@code) { for my $x (@needsRules) @@ -701,20 +726,27 @@ sub preload_addons @code = (); @needsRules = (); } - $record = {}; + my $record = {}; $record->{type} = $2; $record->{lines} = []; - if (exists $addons{$1}) { die "Ga! there are dups!\n"; } + $record->{used} = 0; $addons{$1} = $record; push(@needsRules, $record); } + elsif (/^ECPG:/) + { + # Complain if preceding regex failed to match + die "incorrect syntax in ECPG line: $_\n"; + } else { + # Non-ECPG line: add to @code unless we're still skipping next if $skip; push(@code, $_); } } close($fh); + # Deal with final code block if (@code) { for my $x (@needsRules) |