note
japhy
<p>I have finally solved this problem, after months of cheating and using File::Glob to do the hard work for me. (I ran into string-length limitations with File::Glob which prevented it from working for very long boolean statements.)</p>
<p>Here is my Perl solution, translated from (obligatory shudder) PHP. Hopefully the code speaks for itself and is not in need of much documentation for explaining its logic. <b>NOTE:</b> "not" nodes are skipped, because the point of this function is to come up with lists of terms that <i>will</i> match the logic.</p>
<code>
#!/usr/bin/perl -l
use strict;
use warnings;
my $tree = ['and', ['or', 1, 2], ['not', 3], ['or', 4, 5, 6]];
my $opts = options($tree);
for my $o (@$opts) {
print "OPTION: ", join(", ", @$o);
}
sub options {
my ($tree, $opts) = @_;
if (! $opts) {
$opts = [ [] ];
options($tree, $opts);
return $opts;
}
else {
my $op = $tree->[0];
if ($op eq 'and') {
for my $val (@$tree[1 .. $#$tree]) {
if (ref($val) eq 'ARRAY' and ($val->[0] eq 'and' or $val->[0] eq 'or' or $val->[0] eq 'not')) {
my $subtree = options($val);
my @new;
for my $branch (@$subtree) {
for my $o (@$opts) {
push @new, [ @$o, @$branch ];
}
}
@$opts = @new;
}
else {
for my $o (@$opts) {
push @$o, $val;
}
}
}
}
elsif ($op eq 'or') {
my @new;
for my $val (@$tree[1 .. $#$tree]) {
if (ref($val) eq 'ARRAY' and ($val->[0] eq 'and' or $val->[0] eq 'or' or $val->[0] eq 'not')) {
my $subtree = options($val);
for my $branch (@$subtree) {
for my $o (@$opts) {
push @new, [@$o, @$branch];
}
}
}
else {
for my $o (@$opts) {
push @new, [@$o, $val];
}
}
}
@$opts = @new;
}
}
}
</code>
<!-- Node text goes above. Div tags should contain sig only -->
<div class="pmsig"><div class="pmsig-1936">
Jeffrey Pinyan (Perl, PHP [ugh], JavaScript) — <a href="http://twitter.com/PrayingTheMass">@PrayingTheMass</a><br/>
<a href="http://www.catholiccrossreference.com/"><i>Melius servire volo</i></a><br/>
<a href="http://www.prayingthemass.com/">Catholic Liturgy</a>
</div></div>
1079118
1079118