14 shift if UNIVERSAL::isa($_[0], 'Imager::Expr');
24 my %default_constants =
26 # too many digits, better than too few
27 pi=>3.14159265358979323846264338327950288419716939937510582097494
31 my ($class, $opts) = @_;
33 # possibly this is a very bad idea
34 my ($type) = grep exists $expr_types{$_}, keys %$opts;
35 die "Imager::Expr: No known expression type"
37 my $self = bless {}, $expr_types{$type};
38 $self->{variables} = [ @{$opts->{variables}} ];
39 $self->{constants} = { %default_constants, %{$opts->{constants} || {}} };
40 $self->{ops} = $self->compile($opts->{$type}, $opts)
44 $self->{code} = $self->assemble()
50 my ($pack, $name) = @_;
51 $expr_types{$name} = $pack;
55 my ($class, $name) = @_;
61 return @{$_[0]->{variables}};
69 return $_[0]->{nregs};
73 return $_[0]->{cregs};
76 my $numre = '[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?';
86 my @ops = @{$self->{ops}};
88 # this function cannot current handle code with jumps
89 return 1 if grep $_->[0] =~ /^jump/, @ops;
91 # optimization - common sub-expression elimination
92 # it's possible to fold this into the code generation - but it will wait
94 my $max_opr = $Imager::Regops::MaxOperands;
95 my $attr = \%Imager::Regops::Attr;
104 my $desc = join(",", @{$op}[0..$max_opr]);
108 my $new = $seen{$desc};
110 for my $reg (@{$op}[1..$max_opr]) {
111 $reg = $new if $reg eq $old;
117 $seen{$desc} = $op->[-1];
124 # reduce division by a constant to multiplication by a constant
125 if ($op->[0] eq 'div' && $op->[2] =~ /^r(\d+)/
126 && defined($self->{"nregs"}[$1])) {
127 my $newreg = @{$self->{"nregs"}};
128 push(@{$self->{"nregs"}}, 1.0/$self->{"nregs"}[$1]);
130 $op->[2] = 'r'.$newreg;
133 $self->{ops} = \@ops;
139 my $attr = \%Imager::Regops::Attr;
140 my $max_opr = $Imager::Regops::MaxOperands;
141 my @ops = @{$self->{ops}};
143 $op->[0] = $attr->{$op->[0]}{opcode};
144 for (@{$op}[1..$max_opr+1]) { s/^[rpj]// }
146 my $pack = $Imager::Regops::PackCode x (2+$Imager::Regops::MaxOperands);
148 return join("", ,map { pack($pack, @$_, ) } @ops);
151 # converts stack code to register code
153 my ($self, @st_ops) = @_;
156 my @vars = $self->_variables();
157 my @nregs = (0) x scalar(@vars);
159 my $attr = \%Imager::Regops::Attr;
162 my $max_opr = $Imager::Regops::MaxOperands;
163 @vars{@vars} = map { "r$_" } 0..$#vars;
168 # combining constants makes the optimization below work
169 if (exists $nregs{$_}) {
170 push(@regstack, $nregs{$_});
173 $nregs{$_} = "r".@nregs;
174 push(@regstack,"r".@nregs);
178 elsif (exists $vars{$_}) {
179 push(@regstack, $vars{$_});
181 elsif (exists $attr->{$_} && length $attr->{$_}{types}) {
182 if (@regstack < $attr->{$_}{parms}) {
183 error("Imager::transform2: stack underflow on $_");
186 my @parms = splice(@regstack, -$attr->{$_}{parms});
187 my $types = join("", map {substr($_,0,1)} @parms);
188 if ($types ne $attr->{$_}{types}) {
189 if (exists $attr->{$_.'p'} && $types eq $attr->{$_.'p'}{types}) {
193 error("Imager::transform2: Call to $_ with incorrect types");
198 if ($attr->{$_}{result} eq 'r') {
199 $result = "r".@nregs;
203 $result = "p".@cregs;
206 push(@regstack, $result);
207 push(@parms, "0") while @parms < $max_opr;
208 push(@ops, [ $_, @parms, $result ]);
209 #print "$result <- $_ @parms\n";
213 error("Imager::transform2: stack underflow with $_");
216 $names{$1} = pop(@regstack);
218 elsif (/^\@(\w+)$/) {
219 if (exists $names{$1}) {
220 push(@regstack, $names{$1});
223 error("Imager::Expr: unknown storage \@$1");
228 error("Imager::Expr: unknown operator $_");
232 if (@regstack != 1) {
233 error("stack must have only one item at end");
236 if ($regstack[0] !~ /^p/) {
237 error("you must have a color value at the top of the stack at end");
240 push(@ops, [ "ret", $regstack[0], (-1) x $max_opr ]);
242 $self->{"nregs"} = \@nregs;
243 $self->{"cregs"} = \@cregs;
250 for my $op (@{$_[0]->{ops}}) {
251 $result .= "@{$op}\n";
256 # unassembles the compiled code
259 my $code = $self->{"code"};
260 my $attr = \%Imager::Regops::Attr;
261 my @code = unpack("${Imager::Regops::PackCode}*", $code);
262 my %names = map { $attr->{$_}{opcode}, $_ } keys %Imager::Regops::Attr;
263 my @vars = $self->_variables();
266 while (my @op = splice(@code, 0, 2+$Imager::Regops::MaxOperands)) {
267 my $opcode = shift @op;
268 my $name = $names{$opcode};
270 $result .= "j$index: $name($opcode)";
271 my @types = split //, $attr->{$name}{types};
272 for my $parm (@types) {
274 $result .= " $parm$reg";
277 $result.= "($vars[$reg])";
279 elsif (defined $self->{"nregs"}[$reg]) {
280 $result .= "($self->{\"nregs\"}[$reg])";
285 $result .= " -> $attr->{$name}{result}$op[-1]"
286 if $attr->{$name}{result};
290 $result .= "unknown($opcode) @op\n";
298 package Imager::Expr::Postfix;
300 @ISA = qw(Imager::Expr);
302 Imager::Expr::Postfix->register_type('rpnexpr');
304 my %op_names = ( '+'=>'add', '-'=>'subtract', '*'=>'mult', '/' => 'div',
305 '%'=>'mod', '**'=>'pow' );
308 my ($self, $expr, $opts) = @_;
310 $expr =~ s/#.*//; # remove comments
311 my @st_ops = split ' ', $expr;
314 $_ = $op_names{$_} if exists $op_names{$_};
315 $_ = $self->{constants}{$_} if exists $self->{constants}{$_};
317 return $self->stack_to_reg(@st_ops);
320 package Imager::Expr::Infix;
323 @ISA = qw(Imager::Expr);
324 use Imager::Regops qw(%Attr $MaxOperands);
328 pop @INC if $INC[-1] eq '.';
329 eval "use Parse::RecDescent;";
330 __PACKAGE__->register_type('expr') if !$@;
333 # I really prefer bottom-up parsers
334 my $grammar = <<'GRAMMAR';
336 code : assigns 'return' expr
337 { $return = [ @item[1,3] ] }
339 assigns : assign(s?) { $return = [ @{$item[1]} ] }
341 assign : identifier '=' expr ';'
342 { $return = [ @item[1,3] ] }
346 relation : addition (relstuff)(s?)
349 for my $op(@{$item[2]}) { $return = [ $op->[0], $return, $op->[1] ] }
353 relstuff : relop addition { $return = [ @item[1,2] ] }
355 relop : '<=' { $return = 'le' }
356 | '<' { $return = 'lt' }
357 | '==' { $return = 'eq' }
358 | '>=' { $return = 'ge' }
359 | '>' { $return = 'gt' }
360 | '!=' { $return = 'ne' }
362 addition : multiply (addstuff)(s?)
365 # for my $op(@{$item[2]}) { $return .= " @{$op}[1,0]"; }
366 for my $op(@{$item[2]}) { $return = [ $op->[0], $return, $op->[1] ] }
369 addstuff : addop multiply { $return = [ @item[1,2] ] }
370 addop : '+' { $return = 'add' }
371 | '-' { $return = 'subtract' }
373 multiply : power mulstuff(s?)
374 { $return = $item[1];
375 # for my $op(@{$item[2]}) { $return .= " @{$op}[1,0]"; }
376 for my $op(@{$item[2]}) { $return = [ $op->[0], $return, $op->[1] ] }
380 mulstuff : mulop power { $return = [ @item[1,2] ] }
381 mulop : '*' { $return = 'mult' }
382 | '/' { $return = 'div' }
383 | '%' { $return = 'mod' }
385 power : powstuff(s?) atom
388 for my $op(reverse @{$item[1]}) { $return = [ @{$op}[1,0], $return ] }
392 powstuff : atom powop { $return = [ @item[1,2] ] }
393 powop : '**' { $return = 'pow' }
395 atom: '(' expr ')' { $return = $item[2] }
396 | '-' atom { $return = [ uminus=>$item[2] ] }
401 number : /[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/
403 exprlist : expr ',' exprlist { $return = [ $item[1], @{$item[3]} ] }
404 | expr { $return = [ $item[1] ] }
406 funccall : identifier '(' exprlist ')'
407 { $return = [ $item[1], @{$item[3]} ] }
409 identifier : /[^\W\d]\w*/ { $return = $item[1] }
417 $parser = Parse::RecDescent->new($grammar);
422 my ($self, $expr, $opts) = @_;
424 $parser = Parse::RecDescent->new($grammar);
426 my $optree = $parser->code($expr);
428 $self->error("Error in $expr\n");
432 @{$self->{inputs}}{$self->_variables} = ();
433 $self->{varregs} = {};
434 @{$self->{varregs}}{$self->_variables} = map { "r$_" } 0..$self->_variables-1;
435 $self->{"nregs"} = [ (undef) x $self->_variables ];
436 $self->{"cregs"} = [];
437 $self->{"lits"} = {};
440 # generate code for the assignments
441 for my $assign (@{$optree->[0]}) {
442 my ($varname, $tree) = @$assign;
443 if (exists $self->{inputs}{$varname}) {
444 $self->error("$varname is an input - you can't assign to it");
447 $self->{varregs}{$varname} = $self->gencode($tree);
450 # generate the final result
451 my $result = $self->gencode($optree->[1]);
452 if ($result !~ /^p\d+$/) {
453 $self->error("You must return a color value");
456 push(@{$self->{genops}}, [ 'ret', $result, (0) x $MaxOperands ])
463 return $self->{genops};
467 my ($self, $tree) = @_;
470 my ($op, @parms) = @$tree;
472 if (!exists $Attr{$op}) {
473 die "Unknown operator or function $op";
476 for my $subtree (@parms) {
477 $subtree = $self->gencode($subtree);
479 my $types = join("", map {substr($_,0,1)} @parms);
481 if (length($types) < length($Attr{$op}{types})) {
482 die "Too few parameters in call to $op";
484 if ($types ne $Attr{$op}{types}) {
485 # some alternate operators have the same name followed by p
487 if (exists $Attr{$opp} &&
488 $types eq $Attr{$opp}{types}) {
492 die "Call to $_ with incorrect types";
496 if ($Attr{$op}{result} eq 'r') {
497 $result = "r".@{$self->{nregs}};
498 push(@{$self->{nregs}}, undef);
501 $result = "p".@{$self->{cregs}};
502 push(@{$self->{cregs}}, undef);
504 push(@parms, "0") while @parms < $MaxOperands;
505 push(@{$self->{genops}}, [ $op, @parms, $result]);
508 elsif (exists $self->{varregs}{$tree}) {
509 return $self->{varregs}{$tree};
511 elsif ($tree =~ /^$numre$/ || exists $self->{constants}{$tree}) {
512 $tree = $self->{constants}{$tree} if exists $self->{constants}{$tree};
514 if (exists $self->{lits}{$tree}) {
515 return $self->{lits}{$tree};
517 my $reg = "r".@{$self->{nregs}};
518 push(@{$self->{nregs}}, $tree);
519 $self->{lits}{$tree} = $reg;
531 Imager::Expr - implements expression parsing and compilation for the
532 expression evaluation engine used by Imager::transform2()
536 my $code = Imager::Expr->new({rpnexpr=>$someexpr})
537 or die "Cannot compile $someexpr: ",Imager::Expr::error();
541 This module is used internally by the Imager::transform2() function.
542 You shouldn't have much need to use it directly, but you may want to
545 To create a new Imager::Expr object, call:
548 my $expr = Imager::Expr->new(\%options)
549 or die Imager::Expr::error();
551 You will need to set an expression value and you may set any of the
560 A hashref defining extra constants for expression parsing. The names
561 of the constants must be valid identifiers (/[^\W\d]\w*/) and the
562 values must be valid numeric constants (that Perl recognizes in
565 Imager::Expr may define it's own constants (currently just pi.)
571 A reference to an array of variable names. These are allocated
572 numeric registers starting from register zero.
578 By default you can define a C<rpnexpr> key (which emulates RPN) or
579 C<expr> (an infix expression). It's also possible to write other
580 expression parsers that will use other keys. Only one expression key
583 =head2 Instance methods
585 The Imager::Expr::error() method is used to retrieve the error if the
586 expression object cannot be created.
590 Imager::Expr provides only a few simple methods meant for external use:
596 =item Imager::Expr->type_registered($keyword)
598 Returns true if the given expression type is available. The parameter
599 is the key supplied to the new() method.
601 if (Imager::Expr->type_registered('expr')) {
602 # use infix expressions
607 Returns the compiled code.
611 Returns a reference to the array of numeric registers.
615 Returns a reference to the array of color registers.
617 =item $expr->dumpops()
619 Returns a string with the generated VM "machine code".
621 =item $expr->dumpcode()
623 Returns a string with the disassembled VM "machine code".
627 =head2 Creating a new parser
629 I'll write this one day.
631 Methods used by parsers:
637 This is the main method you'll need to implement in a parser. See the
638 existing parsers for a guide.
640 It's supplied the following parameters:
646 $expr - the expression to be parsed
650 $options - the options hash supplied to transform2.
654 Return an array ref of array refs containing opcodes and operands.
656 =item @vars = $self->_variables()
658 A list (not a reference) of the input variables. This should be used
659 to allocate as many registers as there are variable as input
662 =item $self->error($message)
664 Set the return value of Imager::Expr::error()
666 =item @ops = $self->stack_to_reg(@stack_ops)
668 Converts marginally parsed RPN to register code.
672 Called to convert op codes into byte code.
676 Returns a regular expression that matches floating point numbers.
680 Optimizes the assembly code, including attempting common subexpression
681 elimination and strength reducing division by a constant into
682 multiplication by a constant.
684 =item register_type()
686 Called by a new expression parser implementation to register itself,
689 YourClassName->register_type('type code');
691 where type code is the parameter that will accept the expression.
695 =head2 Future compatibility
697 Try to avoid doing your own optimization beyond literal folding - if
698 we add some sort of jump, the existing optimizer will need to be
699 rewritten, and any optimization you perform may well be broken too
700 (well, your code generation will probably be broken anyway <sigh>).
704 Tony Cook <tonyc@cpan.org>, Arnar M. Hrafnkelsson