RE: evaluating parsed expressions

[email protected] ("Orton, Yves")
Newsgroups perl.recdescent
Message-ID <71B318898201D311845C0008C75DAD1C06F1E449@defra1ex2>
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
> 
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.