<?xml version="1.0" encoding="windows-1252"?>
<node id="711402" title="Re^2: How to grab Parse::RecDescent error output in a variable?" created="2008-09-15 04:07:07" updated="2008-09-15 00:07:07">
<type id="11">
note</type>
<author id="399589">
w-ber</author>
<data>
<field name="doctext">
&lt;p&gt;
About the use of &lt;code&gt;require&lt;/code&gt; in this example... Here is a complete
working example that captures Parse::RecDescent output in a dup'd anonymous
filehandle, which shows that &lt;code&gt;use&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt; are
&lt;em&gt;not&lt;/em&gt; equivalent in this case.
&lt;/p&gt;

&lt;readmore&gt;
&lt;code&gt;
use strict;

my $ParseErrorFh;

BEGIN {
    open(my $olderr, '&gt;&amp;STDERR') or die "Cannot dup STDERR: $!";
    close STDERR or die "Cannot close STDERR: $!";
    open(STDERR, '+&gt;', undef) or die "Cannot open anonymous file: $!";
    select STDERR; $| = 1;

    open($ParseErrorFh, '&gt;&amp;STDERR') or die "Cannot dup anonymous file: $!";

    require Parse::RecDescent;

    close STDERR or die "Cannot close STDERR: $!";
    open(STDERR, '&gt;&amp;', $olderr) or die "Cannot restore STDERR: $!";
}

sub parse {
    my ($grammar, $str) = @_;

    local $::RD_ERROR = 1;
    local $::RD_WARN = 2;

    seek($ParseErrorFh, 0, 0);

    my $p = Parse::RecDescent-&gt;new($grammar)
        or die "Grammar is invalid";

    my $x = $p-&gt;start($str);

    if (not defined $x) {
        seek($ParseErrorFh, 0, 0);
        die join '', grep { $_ !~ m/^\s*$/ } &lt;$ParseErrorFh&gt;;
    }

    return $x;
}

print parse('start: /foo/ | &lt;error&gt;', 'fo'), "\n";
&lt;/code&gt;

&lt;p&gt;
Running this you will get the output
&lt;/p&gt;

&lt;code&gt;
$ perl rectest.pl
        ERROR (line 1): Invalid start: Was expecting /foo/
&lt;/code&gt;

&lt;p&gt;
Now, if you change &lt;code&gt;require&lt;/code&gt; at line 13 to &lt;code&gt;use&lt;/code&gt;,
&lt;/p&gt;

&lt;code&gt;
$ perl rectest2.pl

       ERROR (line 1): Invalid start: Was expecting /foo/
Died at recdescent.pl line 34.
&lt;/code&gt;

&lt;p&gt;
Here, the first two lines are &lt;em&gt;printed to STDERR&lt;/em&gt;, while the
last one indicates that nothing is captured in the dup'd filehandle.
Regardless of what the documentation says about &lt;code&gt;use&lt;/code&gt;
being equivalent to &lt;code&gt;require Module; import Module;&lt;/code&gt;,
this example shows that it is not the case this time. 
&lt;/p&gt;
&lt;/readmore&gt;

&lt;blockquote&gt;&lt;em&gt;Anyway, it would be cleaner to re-open
Parse::RecDescent::ERROR.&lt;/em&gt;&lt;/blockquote&gt;

&lt;p&gt;
Yes, it definitely would be. This is what I tried first. Here is a complete
example (did you try to run your own example code?):
&lt;/p&gt;

&lt;code&gt;
use strict;

use Parse::RecDescent;

sub parse {
    my ($grammar, $str) = @_;

    open(local *Parse::RecDescent::ERROR, '&gt;', \my $error) 
        or die "Cannot open in-memory filehandle: $!";

    local $::RD_ERROR = 1;
    local $::RD_WARN = 2;

    my $p = Parse::RecDescent-&gt;new($grammar)
        or die "Grammar is invalid";

    my $x = $p-&gt;start($str);
    defined $x or die $error;

    return $x;
}

print parse('start: /foo/ | &lt;error&gt;', 'fo'), "\n";
&lt;/code&gt;

&lt;p&gt;
Result:
&lt;/p&gt;

&lt;code&gt;
$ perl recdescent3.pl 
Undefined format "Parse::RecDescent::ERROR" called at /usr/share/perl5/Parse/RecDescent.pm line 2910.
&lt;/code&gt;

&lt;p&gt;
Clearly &lt;code&gt;format&lt;/code&gt; has a side-effect that prevents the use of the
nice solution this time. Besides that, your re-open of &lt;code&gt;ERROR&lt;/code&gt;
requires knowledge of the package internals, while redirecting
&lt;code&gt;STDERR&lt;/code&gt; requires arguably less knowledge, and certainly not the
name of a private (albeit package global) variable.
&lt;/p&gt;


&lt;div class="pmsig"&gt;
&lt;div class="pmsig-399589"&gt;
&lt;p&gt;
-- &lt;br&gt;
say "Just Another [href://http://prometheus.frii.com/~gnat/yapc/2000-stages/slide36.html|Perl Hacker]";
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</field>
<field name="root_node">
710640</field>
<field name="parent_node">
710872</field>
</data>
</node>
