<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#!/usr/bin/perl -sw

# PARSE AND EVALUATE LOGICAL EXPRESSIONS WITH A AUTOGENERATED OO PARSE TREE

use Parse::RecDescent;
use Data::Dumper;

    sub trace_only {
        my ($pattern) = @_;
        $RD_TRACE=1;
        my $_real_trace = \&amp;Parse::RecDescent::_trace;
        *Parse::RecDescent::_trace = sub ($;$$$) {
            my ($msg, $context, $rulename, $level) = @_;
            return if $msg !~ $pattern;
            goto &amp;{$_real_trace};
        };
    }

my $parse = Parse::RecDescent-&gt;new(&lt;&lt;'EOG');

&lt;autotree: LOGICAL&gt;
	expr	:	set | clear | disj
	set		:	'set' atom
	clear	:	'clear' atom
	disj	:	&lt;leftop: conj 'or' conj&gt;
				{ bless $item[-1], 'LOGICAL::'.$item[0] }
	conj	:	&lt;leftop: unary 'and' unary&gt;
				{ bless $item[-1], 'LOGICAL::'.$item[0] }
	unary	:	neg | bracket | atom
	bracket :	'(' expr ')'
	neg	:	'not' unary
	atom	:	/[a-z]+/i
EOG

    trace_only( qr/Matched|consumed/ );

while (&lt;DATA&gt;)
{
	my $tree = $parse-&gt;expr($_);
	print Data::Dumper-&gt;Dump([$tree]);
	print $tree-&gt;eval(), "\n" if $tree;
}

BEGIN {@var{qw(a c e)} = (1,1,1);}

sub returning
{
 	 # local $^W;
	 # print +(caller(1))[3], " returning ($_[0])\n";
	$_[0];
}

sub LOGICAL::expr::eval		{ my $type = $_[0]-&gt;{set}||$_[0]-&gt;{clear}
													 ||$_[0]-&gt;{disj};
							  returning $type-&gt;eval() }
sub LOGICAL::disj::eval     { returning join '', map {$_-&gt;eval()} @{$_[0]} }
sub LOGICAL::conj::eval     { returning ! join '', map {! $_-&gt;eval()} @{$_[0]} }
sub LOGICAL::unary::eval    { my $type = $_[0]-&gt;{neg}||$_[0]-&gt;{bracket}
												     ||$_[0]-&gt;{atom};
							  returning $type-&gt;eval() }
sub LOGICAL::bracket::eval  { returning $_[0]-&gt;{expr}-&gt;eval() }
sub LOGICAL::neg::eval	   	{ returning ! $_[0]-&gt;{unary}-&gt;eval() }
sub LOGICAL::set::eval      { returning $::var{$_[0]-&gt;{atom}-&gt;name()} = 1 }
sub LOGICAL::clear::eval    { returning $::var{$_[0]-&gt;{atom}-&gt;name()} = 0 }
sub LOGICAL::atom::eval     { returning $::var{$_[0]-&gt;{__VALUE__}} }
sub LOGICAL::atom::name     { returning $_[0]-&gt;{__VALUE__} }

__DATA__
a or b and not c or d
</pre></body></html>