Re: Logic expression evaluation not working. What am I doing wrong?
by Cristoforo (Curate) on Jan 04, 2016 at 02:20 UTC
|
Add an eval to that printf, printf "%b\n", eval $newExpr;.
As AnonymousMonk says, care should be taken when using 'eval'. You should check as he does that only valid characters are allowed, especially if eval'ing a string from an unknown source. The unknown string could have malicious system commands, for example, to wipe out your hard drive. | [reply] [d/l] |
Re: Logic expression evaluation not working. What am I doing wrong?
by GrandFather (Saint) on Jan 04, 2016 at 07:06 UTC
|
An interesting way to do it is to use a full blown parser. Marpa is a relatively easy way to get the job done:
use strict;
use warnings;
use Marpa::R2;
package DoStuff;
my %vars;
sub doAnd {
my @params = @_;
return $params[1] && $params[3];
}
sub doOr {
my @params = @_;
return $params[1] || $params[3];
}
sub doVarValue {
my @params = @_;
return $vars{$params[1]};
}
sub doAssign {
my @params = @_;
$vars{$params[1]} = $params[3];
return;
}
sub doVal {
my @params = @_;
my $val = 'ARRAY' eq ref $params[1] ? $params[1][1] : $params[1];
return $val;
}
sub doNVal {
my @params = @_;
my $val = 'ARRAY' eq ref $params[2] ? $params[2][1] : $params[2];
return $val ? 0 : 1;
}
sub doResult {
my @params = @_;
return $params[-1];
}
package main;
my $syntax = <<'SYNTAX';
lexeme default = latm => 1
test ::= assignments expression action => doResult
| expression action => doResult
assignments ::= assignment assignments
| assignment
assignment ::= var '=' constant action => doAssign
expression ::= expression '|' term action => doOr | term action => ::f
+irst
term ::= term '&' factor action => doAnd | factor action => ::first
factor ::= negatable action => doVal | '!' negatable action => doNVal
negatable ::= '(' expression ')' action => [values] | value action =>
+::first
value ::= var action => doVarValue
| constant action => ::first
var ~ [A-Z]
constant ~ [10]
:discard ~ spaces
spaces ~ [\s]+
SYNTAX
my $grammar = Marpa::R2::Scanless::G->new({source => \$syntax});
for my $inputs ([0, 0, 0], [0, 0, 1], [0, 1, 1], [1, 0, 1]) {
my $input = <<INPUT;
C = $inputs->[0]
Q = $inputs->[1]
T = $inputs->[2]
(!(C)&T)&!Q
INPUT
my $result = $grammar->parse(\$input, 'DoStuff');
printf "${input}Result: %d\n\n", $$result;
}
Prints:
C = 0
Q = 0
T = 0
(!(C)&T)&!Q
Result: 0
C = 0
Q = 0
T = 1
(!(C)&T)&!Q
Result: 1
C = 0
Q = 1
T = 1
(!(C)&T)&!Q
Result: 0
C = 1
Q = 0
T = 1
(!(C)&T)&!Q
Result: 0
Premature optimization is the root of all job security
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
It's a package variable, not a closure. In a sense it's a global variable, but notionally private to the package. There are other ways it could be done, but for a "simple" example it is expedient and not totally terrible.
Premature optimization is the root of all job security
| [reply] |
|
|
Re: Logic expression evaluation not working. What am I doing wrong?
by AnomalousMonk (Archbishop) on Jan 04, 2016 at 04:27 UTC
|
c:\@Work\Perl>perl -wMstrict -MData::Dump -le
"use constant OPS => qw{ ( ( ) ) ! ! | || & && };
;;
sub compile {
my ($expr, $hr_vars) = @_;
;;
my %xlate = (OPS, %$hr_vars);
;;
$expr =~ s{ (.) }
{ exists $xlate{$1}
or die qq{bad: '$1' at offset $-[1] in '$expr'};
$xlate{$1};
}xmsge;
;;
return $expr;
}
;;
my %vars = qw(Q 0 T 1 C 0);
dd \%vars;
;;
my $expr = '(!(C)&T)&!Q';
print qq{initial expr: '$expr'};
;;
my $final_expr = compile($expr, \%vars);
print qq{ final expr: '$final_expr'};
;;
my $result = eval $final_expr;
if ($@) {
print qq{eval of '$final_expr' failed: $@}
}
else {
print qq{'$final_expr' -> '$result'};
}
"
{ C => 0, Q => 0, T => 1 }
initial expr: '(!(C)&T)&!Q'
final expr: '(!(0)&&1)&&!0'
'(!(0)&&1)&&!0' -> '1'
Some thoughts:
-
Caution: Because it uses string eval, this code is not guaranteed to be safe, whatever your definition of "safe" may be. Caveat programmor.
-
Play with this. E.g., are the outputs of '(x!(C)&T)&!Q' or '(!(C(&T)&!Q' acceptable?
-
The expression !1 evaluates to '' (the empty string), which can propagate through subsequent logical expressions to produce an empty string as output, so after all you may want the bitwise | & operators, which can produce 0 1 outputs.
-
This code works under ActiveState 5.8.9 and should work, but has not been tested, under any higher Perl version.
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
|
"The expression !1 evaluates to ''"
I tried the following:
#!/usr/bin/perl
use strict;
use warnings;
printf "%b\n", !1;
which output the following:
0
on my Linux machine. So, not sure under what circumstances, like you say that it outputs '' empty string.
Can you elaborate a bit for novices like myself please?
TIA.
| [reply] [d/l] [select] |
|
|
c:\@Work\Perl>perl -wMstrict -le "print '>', !1, '<';"
><
c:\@Work\Perl>perl -wMstrict -le "print '>', !1 && 1, '<';"
><
In numeric contexts such as that supplied by the %b printf format specifier, !1 will, I think, always evaluate to numeric 0 — but it would be best to do some research on this!
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
Re: Logic expression evaluation not working. What am I doing wrong?
by Anonymous Monk on Jan 04, 2016 at 02:29 UTC
|
my %allowed = qw{ ( ( ) ) ! !! & && };
my $finalExpr = map { $allowed{$_} || die "not allowed '$_'" } split '
+', $expr;
my $result = eval $finalExpr;
| [reply] [d/l] |
|
|
#from Anonymous Monk code
> my %allowed = qw{ ( ( ) ) ! !! & && };
> my $finalExpr = map { $allowed{$_} || die "not allowed '$_'" } split
+ '', $expr;
The %allowed hash doesn't look right and it isn't, among other things because it forgets digits [0-9]. A solution along these lines might do something like using taint mode for the script and then:
print "EXPR = ",$newExpr,"\n";
# don't know how to execute shell commands without [A-Za-z] letters
$newExpr =~ /^([\d\s()&|!]+)$/;
printf "%b\n", eval $1;
}
| [reply] [d/l] [select] |
|
|
c:\@Work\Perl>perl -wMstrict -le
"my $expr = '(!(C)&T)&!Q';
my %allowed = qw{ ( ( ) ) ! !! & && C 1 T 1 Q 1 };
my $finalExpr = map { $allowed{$_} || die qq{not allowed '$_'} } spli
+t '', $expr;
print qq{'$finalExpr'};
"
'11'
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
|
|
|
|
|
| [reply] |