# # This software is Copyright 2005 by Elsevier Inc. You may use it # under the terms of the license at http://perl.plover.com/hop/LICENSE.txt . # ### ### Parser::Debug.pm ### ## Chapter 8 section 4.5 package Parser::Debug; use base 'Exporter'; use Parser ':all'; @EXPORT_OK = @Parser::EXPORT_OK; %EXPORT_TAGS = %Parser::EXPORT_TAGS; my $CON = 'A'; sub concatenate { my $id; if (ref $_[0]) { $id = "Unnamed concatenation $CON"; $CON++ } else { $id = shift } my @p = @_ return \&n ll if @p == 0; return $p[ ] if @p == 1; my $parser = parser { my $input = shift; debug "Looking for $id\n"; my $v; my @values; my ($q, $np) = (0, scalar @p); for (@p) { $q++; unless (($v, $input) = $_->($input)) { debug "Failed concatenated component $q/$np\n"; return; } debug "Matched concatenated component $q/$np\n"; push @values, $v; } debug "Finished matching $id\n"; return \@values; }; $N{$parser} = $id; return $parser; } ## Chapter 8 section 4.5 sub debug ($) { return unless $DEBUG || $ENV{DEBUG}; my $msg = shift; my $i = 0; $i++ while caller($i); $I = "| " x ($i-2); print $I, $msg; } ## Chapter 8 section 4.5 sub star { my $p = shift; my ($p_star, $conc); $p_star = alternate(T($conc = concatenate($p, parser { $p_star->(@_) }), sub { my ($first, $rest) = @_; [$first, @$rest]; }), \&null_list); $N{$p_star} = "star($N{$p})"; $N{$conc} = "$N{$p} $N{$p_star}"; return $p_star; } ## Chapter 8 section 4.7.1 sub error { my ($checker, $continuation) = @_; my $p; $p = parser { my $input = shift; debug "Error in $N{$continuation}\n"; debug "Discarding up to $N{$checker}\n"; my @discarded; while (defined($input)) { my $h = head($input); if (my (undef, $result) = $checker->($input)) { debug "Discarding $N{$checker}\n"; push @discarded, $N{$checker}; $input = $result; last; } else { debug "Discarding token [@$h]\n"; push @discarded, $h->[1]; drop($input); } } warn "Erroneous input: ignoring '@discarded'\n" if @discarded; return unless defined $input; debug "Continuing with $N{$continuation} after error recovery\n"; $continuation->($input); }; $N{$p} = "errhandler($N{$continuation} -> $N{$checker})"; return $p; }