tags:

views:

390

answers:

3

I wrote a tool for polar functions. It lists values from an input range like that:

0 Grad: (0 RAD|1 RES)  
20 Grad: (0.349065850398866 RAD|1.3639702342662 RES)  
40 Grad: (0.698131700797732 RAD|1.83909963117728 RES)  
60 Grad: (1.0471975511966 RAD|2.73205080756888 RES)  
80 Grad: (1.39626340159546 RAD|6.67128181961771 RES)  
100 Grad: (1.74532925199433 RAD|4.67128181961771 RES)  
120 Grad: (2.0943951023932 RAD|0.732050807568878 RES)  
140 Grad: (2.44346095279206 RAD|0.16090036882272 RES)  
160 Grad: (2.79252680319093 RAD|0.636029765733797 RES)  
180 Grad: (3.14159265358979 RAD|1 RES)

It is based of the function

 abs(1 + tan($_[0]));

How can I parse such a function from UserInput (Perl syntax) and assign it to a variable?

I want to avoid changing the Perl script; making the function dynamic instead of static.

Greets and thanks for reading.

EDIT: sorry for quadrupelpost....

Thanks for the help, but the following snippet gives wrong values:

print("Eingabe: Funktion (phi = $t); PERL syntax!: > ");
$iFunktion = <STDIN>;
chop($iFunktion);

print("Eingabe: Grad Start: > ");
$iGradStart = <STDIN>; 
chop($iGradStart);

print("Eingabe: Grad End: > ");
$iGradEnd = <STDIN>; 
chop($iGradEnd);

print("Eingabe: Schrittweite: > ");
$iSchrittweite = <STDIN>; 
chop($iSchrittweite);

print("\nBerechne Funktion von $iGradStart bis $iGradEnd Grad mit einer Schrittweite von $iSchrittweite\n");


for ($i = $iGradStart; $i < $iGradEnd; $i = $i + $iSchrittweite)
{
    $flRad = &deg2rad($i);
 #$flResult = &Compute($flRad);
 $t = $i;
 $flResult = eval($iFunktion);
 print("$i Grad: ($flRad RAD|$flResult RES)  \n");
}

Input was abs(1 + tan($t));


(additional info, merged from follow-up)

print("Eingabe: Grad Start: > "); 
$iGradStart = <STDIN>; 
chop($iGradStart); 

print("Eingabe: Grad End: > "); 
$iGradEnd = <STDIN>; 
chop($iGradEnd); 

print("Eingabe: Schrittweite: > "); 
$iSchrittweite = <STDIN>; chop($iSchrittweite); 
print("\nfrom $iGradStart to $iGradEnd Grad with $iSchrittweite\n"); 
for ($i = $iGradStart; $i <= $iGradEnd; $i = $i + $iSchrittweite) 
{ 
  $flRad = &deg2rad($i); 
  $flResult = &Compute($flRad); 
  print("$i Grad: ($flRad RAD|$flResult RES) \n"); 
} 

sub Compute { return abs(1 + tan($_[0])); }
+4  A: 

You should look at the eval statement. It allows you to evaluate a string as Perl code.

For example, this code:

print "Function? ";
chomp($function = <STDIN>);

for ($i = 0;$i < 10;$i++) {
  print $i,"->",eval($function),"\n";
}

Gives this:

Function? $i * $i
0->0
1->1
2->4
3->9
4->16
5->25
6->36
7->49
8->64
9->81

As you're running user input as code, if someone other than use is using your script, you'll want to do something to sanitise user input. You may also want to do a substitution so users could, for example, enter x instead of $i etc. If you want to catch errors from eval check the $@ variable.

Dave Webb
+1  A: 

Depending on what else you have going on, I think I'd skip the parsing idea and have the users create a Perl library or subclass. They wrap their code in subroutine names and tell your script the library and the sub name. You might also combine that with a proper config file or command-line options.

brian d foy
so there is no option to do this?
maxedmelon
There is nothing built into Perl to be a mathemathical parser. If that's the crux of your problem, you're using the wrong language. There are plenty of ways to get this done, including my suggestion.
brian d foy
A: 

Math::Expression::Evaluator almost does what you want, except that has no abs() and no way to add user functions (callbacks.) It took me about five minutes to add some rudimentary support, thought.

#!/usr/bin/perl
use strict;
use warnings;
use Math::Trig;
use Math::Expression::Evaluator;

my $expr = join ' ', @ARGV;
die "No expression provided" unless $expr;
my $m = Math::Expression::Evaluator->new;
# NOT in the distribution
$m->add_user_function('abs', sub { abs($_[0]) });
my $func = $m->parse($expr);
die "Cannot parse" unless $func;
for my $i (0 .. 10){
    my $rads = deg2rad($i);
    my $res = $func->val({x => $_});
    print("$i Grad: ($rads RAD|$res RES)  \n");
}
Leonardo Herrera