Ok. I should have read your original post in detail... Sorry. :-)

Anyway, a couple of quick thoughts then a chunk of code and im off for the
weekend.

First :Try using here docs instead of q{}.  They make your grammer much
cleaner. (and avoid potential issues with \ which i suspect you may be
suffering).
Second:I wonder if using reserved words as rule names is part of the
weirdness you describe.
Third :>  atom: /(\w+)/ { $return = ::get_value($1); 1; }
       This is better written (IMO) as
         >  atom: /\w+/ { $return = ::get_value($item[1]);}

K, heres a quick little parser I whipped together that does what you had in
mind.
Maybe you can use it to resolve your issues.  (Its not fully tested, and I
had to make up a few things since I didnt have the full rules of your
grammer handy)

The output is after the __END__ tag.

hth. Yves

use Parse::RecDescent;
use warnings;
use strict;

my %symbols;

sub symbol_fetch{
   my $symbol=shift;
   unless (exists $symbols{$symbol}) {
         warn "Fetching from nonexiststant $symbol\n";
         $symbols{$symbol}=0;
   }
   print "Fetched $symbol=$symbols{$symbol}\n";
   return $symbols{$symbol}
}

sub symbol_store{
   my $symbol=shift;
   my $value =shift;
   $symbols{$symbol}=$value;
   print "Stored $value into $symbol\n";
   return $value
}


my $grammar=<<'GRAMMAR';


statements : statement(s) /\Z/
           | <error>

statement  : conj_atom '::' action[$item{conj_atom}]
           | <error>

action     : {print "\$arg[0] is ".($arg[0]?"True":"False")."\n"; undef}
           | 'define'   '(' symbol ')'  { $arg[0] &&
::symbol_store($item{symbol},1); 1}
           | 'undefine' '(' symbol ')'  { $arg[0] &&
::symbol_store($item{symbol},0); 1}
           | 'print'    '(' /[^)]+/ ')' { $arg[0] && print $item[3],"\n"; 1}

conj_atom  : conj  {$return=$item{conj}}
           | atom  {$return=$item{atom}}

conj       :<leftop: disj_atom '.' disj_atom>
{       $return=1;
        foreach my $item (@{$item[1]}) {
                $return&&=$item;
                last if !$return;
        }
        $return
}

disj_atom  : disj {$return=$item{disj}}
           | atom {$return=$item{atom}}

disj       :<leftop: atom '|' atom>
{       $return=0;
        foreach my $item (@{$item[1]}) {
                $return||=$item;
                last if $return;
        }
        $return
}

atom       : '!' atom             {$return=!$item{atom} }
           | '(' conj_atom ')'    {$return=$item{conj_atom}}
           | symbol               {$return=::symbol_fetch($item{symbol})}

symbol     : /\w+/ { $return=$item[1]; }

GRAMMAR

#$::RD_HINT=1;
#$::RD_TRACE=1;

my $parser=Parse::RecDescent->new($grammar) or die "Bad grammar!\n";
defined $parser->statements(<<TEST) or die "Cant parse!"
!a       :: define(a)
a|b|c    :: define(hello)
a.b.hello:: print(hello is defined)
a        :: print(a is defined)
!c       :: define(c)
c.(a|b)  :: print(c and a or b)
TEST

__END__
Fetching from nonexiststant a
Fetching from nonexiststant b
Fetching from nonexiststant c
Fetched a=0
$arg[0] is True
Stored 1 into a
Fetched a=1
Fetched b=0
Fetched c=0
$arg[0] is True
Stored 1 into hello
Fetched a=1
Fetched b=0
Fetched hello=1
$arg[0] is False
Fetched a=1
$arg[0] is True
a is defined
Fetched c=0
$arg[0] is True
Stored 1 into c
Fetched c=1
Fetched a=1
Fetched b=0
$arg[0] is True
c and a or b



> -----Original Message-----
> From: Ted Zlatanov [mailto:[EMAIL PROTECTED]]
> Sent: 2002/03/14 21:09
> To: Orton, Yves
> Cc: [EMAIL PROTECTED]
> Subject: Re: evaluating parsed expressions
> 
> 
> Thanks for the suggestions.  I don't want to keep a symbol table,
> because it would have to be cleared every time I re-run the parser.
> The state of the defined classes (and thus the logical value of each
> symbol) may change with each invocation of the parser (once per
> configuration line).  I'm not parsing a static file, each line may
> actually define a new class or undefine an old one.  Something like
> this (define/undefine syntax is not important):
> 
>  # start with a,c,d defined
>  a.c.d:: define(hello) # will run
>  a.c.hello:: undefine(a) # will run
>  a:: anything() # will not run
> 
> A simplified version of my unsuccessful grammars:
> 
>  or: atom '|' atom { $return = $item[1] || $item[3]; 1; }
>  atom: /(\w+)/ { $return = ::get_value($1); 1; }
> 
> did not work for me.  The parser would always break off at the 'or'
> without descending into the atom evaluation, or I would get weird
> parsing errors.  I ended up having each parsed element return a
> subroutine that, when evaluated with the matched parameters, will do
> the right thing.  See my previous message for the gory details.
> 
> I hope my explanations are making this clearer.  I keep having the
> feeling the answer is very simple, I just don't get it :)
> 
> Thanks
> Ted
> 
> 

Reply via email to