I need to build a simple algebraic parser and evaluator to work with dynamically generated Verilog code and parametric bus assignments, and since Damian's class notes contain such a parser, I started there (code below, original is part of an infix to RPN converter).
Basically, it goes a few simple steps beyond Damian's code: 1) Creating an "equation" variable = expr 2) Allowing multiple equations 3) Instead of translating to RPN, it actually goes and evaluates the expression. 4) As variables are resolved, they are locally stored in a hash to be used in further calculations. It works great, except I need to clear %variables between calls to $parse->eqns. I realize that in this instance that: $list = (); works, but it doesn't feel right. Something cleaner would be nicer. I'd also prefer not to use a global in the main package instead of the private namespace variable. Isn't there a more encapsulated way to either clear the private variable or have a different solution? Thanks, Colin #!/bin/perl -w use strict; use Parse::RecDescent; use Data::Dumper; use Switch qw(Perl6); #$RD_TRACE = 1; sub Parse::RecDescent::calc { my ($self,$result,@list) = @_; return $result unless @list; my ($op, $val); while ( ($op,$val) = splice(@list,0,2) ) { given($op) { when '+' { $result += $val } when '-' { $result -= $val } when '*' { $result *= $val } when '/' { $result /= $val } when '%' { $result %= $val } when '**' { $result **= $val } when '&&' { $result &&= $val } when '||' { $result ||= $val } } } return $result; } sub Parse::RecDescent::spew { print join ":", @_; print "\n"; } my $grammar = q{ { my %variables = (); } eqns : eqn(s) { \%variables } eqn : variable "=" expr { $variables{$item[1]} = $item[3]; } operation : <leftop: <matchrule: $arg[0] > /($arg[1])/ <matchrule: $arg[0] > > { $thisparser->calc(@{ $item[1] }) } expr : operation[ "conj", '\|\|' ] conj : operation[ "addn", '\&\&' ] addn : operation[ "mult", '[+-]' ] mult : operation[ "expo", '[*\/\%]' ] expo : operation[ "unary", '\*\*' ] unary : "(" expr ")" { $item[2] } | literal { $item[1] } | var { $item[1] } var : /[A-Za-z]\w*/ { $variables{ $item[1] } } variable : /\w+/ { $item[1] } literal : /\d+(\.\d+)?/ { $item[1] } }; my $string = <<EOS; a=1 b=2 c=b+3 d=4+a EOS my $parse = Parse::RecDescent->new($grammar) or die "bad grammar\n"; my $list = $parse->eqns($string); print Dumper($list); my $list2 = $parse->eqns("e=d+2"); print Dumper($list2);