File Coverage

blib/lib/Math/Expression/Evaluator.pm
Criterion Covered Total %
statement 344 348 98.8
branch 36 40 90.0
condition 2 2 100.0
subroutine 101 102 99.0
pod 9 9 100.0
total 492 501 98.2


line stmt bran cond sub pod time code
1             package Math::Expression::Evaluator;
2 16     16   409098 use strict;
  16         38  
  16         613  
3 16     16   90 use warnings;
  16         32  
  16         445  
4 16     16   9886 use Math::Expression::Evaluator::Parser;
  16         46  
  16         618  
5 16     16   128 use Math::Expression::Evaluator::Util qw(is_lvalue);
  16         51  
  16         897  
6 16     16   596 use Data::Dumper;
  16         31  
  16         673  
7 16     16   15254 use POSIX qw(ceil floor);
  16         145680  
  16         116  
8 16     16   20067 use Carp;
  16         34  
  16         1046  
9              
10 16     16   17078 use Math::Trig qw(atan asin acos tan);
  16         317600  
  16         49695  
11              
12             our $VERSION = '0.3.2';
13              
14             =encoding UTF-8
15              
16             =head1 NAME
17              
18             Math::Expression::Evaluator - parses, compiles and evaluates mathematic expressions
19              
20             =head1 SYNOPSIS
21              
22             use Math::Expression::Evaluator;
23             my $m = Math::Expression::Evaluator->new;
24              
25             print $m->parse("a = 12; a*3")->val(), "\n";
26             # prints 36
27             print $m->parse("2^(a/3)")->val(), "\n";
28             # prints 8 (ie 2**3)
29             print $m->parse("a / b")->val({ b => 6 }), "\n";
30             # prints 36
31             print $m->parse("log2(16)")->val(), "\n";
32             # prints 4
33              
34             # if you care about speed
35             my $func = $m->parse('2 + (4 * b)')->compiled;
36             for (0 .. 100){
37             print $func->({b => $_}), "\n";
38             }
39              
40              
41             =head1 DESCRIPTION
42              
43             Math::Expression::Evaluator is a parser, compiler and interpreter for
44             mathematical expressions. It can handle normal arithmetics
45             (includings powers wit C<^> or C<**>), builtin functions like sin() and variables.
46              
47             Multiplication C<*>, division C and modulo C<%> have the same precedence,
48             and are evaluated left to right. The modulo operation follows the standard
49             perl semantics, that is is the arguments are castet to integer before
50             preforming the modulo operation.
51              
52             Multiple exressions can be seperated by whitespaces or by semicolons ';'.
53             In case of multiple expressions the value of the last expression is
54             returned.
55              
56             Variables can be assigned with a single '=' sign, their name has to start
57             with a alphabetic character or underscore C<[a-zA-Z_]>, and may contain
58             alphabetic characters, digits and underscores.
59              
60             Values for variables can also be provided as a hash ref as a parameter
61             to val(). In case of collision the explicitly provided value is used:
62              
63             $m->parse("a = 2; a")->val({a => 1});
64              
65             will return 1, not 2.
66              
67             The following builtin functions are supported atm:
68              
69             =over 4
70              
71             =item *
72              
73             trignometric functions: sin, cos, tan
74              
75             =item *
76              
77             inverse trigonomic functions: asin, acos, atan
78              
79             =item *
80              
81             Square root: sqrt
82              
83             =item *
84              
85             exponentials: exp, sinh, cosh
86              
87             =item *
88              
89             logarithms: log, log2, log10
90              
91             =item *
92              
93             constants: pi() (you need the parenthesis to distinguish it from the
94             variable pi)
95              
96             =item *
97              
98             rounding: ceil(), floor()
99              
100             =item *
101              
102             other: theta (theta(x) = 1 for x > 0, theta(x) = 0 for x < 0)
103              
104             =back
105              
106             =head1 METHODS
107              
108             =over 2
109              
110             =item new
111              
112             generates a new MathExpr object. accepts an optional argument, a hash ref
113             that contains configurations. If this hash sets force_semicolon to true,
114             expressions have to be separated by a semicolon ';'.
115              
116             =item parse
117              
118             Takes a string as argument, and generates an Abstract Syntax Tree(AST) that
119             is stored internally.
120              
121             Returns a reference to the object, so that method calls can be chained:
122              
123             print MathExpr->new->parse("1+2")->val;
124              
125             Parse failures cause this method to die with a stack trace.
126              
127             You can call C on an existing Math::Expression::Evaluator object to
128             re-use it, in which case previously set variables and callbacks persist
129             between calls.
130              
131             This (perhaps contrived) example explains this:
132              
133             my $m = Math::Expression::Evaluator->new('a = 3; a');
134             $m->val();
135             $m->parse('a + 5');
136             print $m->val(), "\n" # prints 8, because a = 3 was re-used
137              
138             If that's not what you want, create a new object instead - the constructor is
139             rather cheap.
140              
141             =item compiled
142              
143             Returns an anonymous function that is a compiled version of the current
144             expression. It is much faster to execute than the other methods, but its error
145             messages aren't as informative (instead of complaining about a non-existing
146             variable it dies with C).
147              
148             Note that variables are not persistent between calls to compiled functions
149             (and it wouldn't make sense anyway, because such a function corresponds always
150             to exactly one expression, not many as a MEE object).
151              
152             Variables that were stored at the time when C is called are
153             availble in the compiled function, though.
154              
155             =item val
156              
157             Executes the AST generated by parse(), and returns the number that the
158             expression is evaluated to. It accepts an optional hash reference that
159             contain values for variables:
160              
161             my $m = MathExpr->new;
162             $m->parse("(x - 1) / (x + 1)");
163             foreach (0 .. 10) {
164             print $_, "\t", $m->val({x => $_}), "\n";
165             }
166              
167             =item optimize
168              
169             Optimizes the internal AST, so that subsequent calls to C will be
170             a bit faster. See C for performance
171             considerations and informations on the implemented optimizations.
172              
173             But note that a call to C only pays off if you call C
174             multiple times.
175              
176             =item variables
177              
178             C returns a list of variables that are used in the expression.
179              
180             =item set_var_callback
181              
182             Allows you to set a callback which the Match::Expression::Evaluator object
183             calls when it can't find a variable. The name of the variable is passed in
184             as the first argument. If the callback function can't handle that variable
185             either, it should die, just like the default one does.
186              
187             my $m = Math::Expression::Evaluator->new();
188             $m->parse('1 + a');
189             my $callback = sub { ord($_[0]) };
190             $m->set_var_callback($callback);
191             print $m->val(); # calls $callback, which returns 97
192             # so $m->val() return 98
193              
194             The callback will be called every time the variable is accessed, so if it
195             requires expensive calculations, you are encouraged to cache it either
196             yourself our automatically with L.
197              
198             =item set_function
199              
200             Allows to add a user-defined function, or to override a built-in function.
201              
202             my $m = Math::Expression::Evaluator->new();
203             $m->set_function('abs', sub { abs($_[0]) });
204             $m->parse('abs(10.6)');
205             print $m->val();
206              
207             If you first compile the expression to a perl closure and then call
208             C<<$m->set_function>> again, the compiled function stays unaffected, so
209              
210             $m->set_function('f', sub { 42 });
211             my $compiled = $m->parse('f')->compiled;
212             $m->set_function('f', sub { -23 });
213             print $compiled->();
214              
215             print out C<42>, not C<-23>.
216              
217             =item ast_size
218              
219             C returns an integer which gives a crude measure of the logical
220             size of the expression. Note that this value isn't guarantueed to be stable
221             across multiple versions of this module. It is mainly intended for testing.
222              
223             =back
224              
225             =head1 SPEED
226              
227             MEE isn't as fast as perl, because it is built on top of perl.
228              
229             If you execute an expression multiple times, it pays off to either optimize
230             it first, or (even better) compile it to a pure perl function.
231              
232             Rate no_optimize optimize opt_compiled compiled
233             no_optimize 83.9/s -- -44% -82% -83%
234             optimize 150/s 78% -- -68% -69%
235             opt_compiled 472/s 463% 215% -- -4%
236             compiled 490/s 485% 227% 4% --
237              
238             This shows the time for 200 evaluations of C<2+a+5+(3+4)> (with MEE 0.0.5).
239             As you can see, the non-optimized version is painfully slow, optimization
240             nearly doubles the execution speed. The compiled and the
241             optimized-and-then-compiled versions are both much faster.
242              
243             With this example expression the optimization prior to compilation pays off
244             if you evaluate it more than 1000 times. But even if you call it C<10**5>
245             times the optimized and compiled version is only 3% faster than the directly
246             compiled one (mostly due to perl's overhead for method calls).
247              
248             So to summarize you should compile your expresions, and if you have really
249             many iterations it might pay off to optimize it first (or to write your
250             program in C instead ;-).
251              
252             =head1 BUGS AND LIMITATIONS
253              
254             =over 4
255              
256             =item *
257              
258             Modulo operator produces an unnecessary big AST, making it relatively slow
259              
260             =back
261              
262             =head1 INTERNALS
263              
264             The AST can be accessed as C<$obj->{ast}>. Its structure is described in
265             L (or you can use L
266             to figure it out for yourself). Note that the exact form of the AST is
267             considered to be an implementation detail, and subject to change.
268              
269             =head1 SEE ALSO
270              
271             L also evaluates mathematical expressions, but also handles
272             string operations.
273              
274             If you want to do symbolic (aka algebraic) transformations, L
275             will fit your needs.
276              
277             =head1 LICENSE
278              
279             This module is free software. You may use, redistribute and modify it under
280             the same terms as perl itself.
281              
282             =head1 COPYRIGHT
283              
284             Copyright (C) 2007 - 2009 Moritz Lenz,
285             L, moritz@faui2k3.org
286              
287             =head1 DEVELOPMENT
288              
289             You can obtain the latest development version from github
290             L.
291              
292             git clone git://github.com/moritz/math-expression-evaluator.git
293              
294             If you want to contribute something to this module, please ask me for
295             a commit bit to the github repository, I'm giving them out freely.
296              
297             =head1 ACKNOWLEDGEMENTS
298              
299             The following people have contributed to this module, in no particular order:
300              
301             =over
302              
303             =item Leonardo Herrera
304              
305             Initial patch for C
306              
307             =item Tina Müller
308              
309             Helpful feedback
310              
311             =back
312              
313             =cut
314              
315             sub new {
316 20     20 1 3490 my $class = shift;
317 20         78 my $self = bless {}, $class;
318 20         139 $self->{tokens} = [];
319 20         59 $self->{variables} = {};
320 20     2   140 $self->{var_callback} = sub { confess "Variable '$_[0]' not defined" };
  2         551  
321              
322 20         47 my $first = shift;
323              
324 20 100       87 if (defined $first){
325 3 100       14 if (ref $first){
326 2         7 $self->{config} = $first;
327 2 100       10 $self->parse(shift) if @_;
328             } else {
329 1         6 $self->parse($first);
330             }
331             }
332              
333 20         65 return $self;
334             }
335              
336              
337             # parse a text into an AST, stores the AST in $self->{ast}
338             sub parse {
339 291     291 1 84510 my ($self, $text) = @_;
340 291         1837 $self->{ast} =
341             Math::Expression::Evaluator::Parser::parse($text, $self->{config});
342 277         1361 return $self;
343             }
344              
345              
346              
347             sub optimize {
348 84     84 1 145 my ($self) = @_;
349 84         6228 require Math::Expression::Evaluator::Optimizer;
350 84         406 $self->{ast} = Math::Expression::Evaluator::Optimizer::_optimize($self, $self->{ast});
351 84         389 return $self;
352             }
353              
354             # evaluates an arbitrary AST, and returns its value
355             sub _execute {
356 865     865   1348 my ($self, $ast) = @_;
357 27     27   84 my %dispatch = (
358             '/' => sub {1 / $_[0]->_execute($_[1])},
359 33     33   106 '-' => sub {-$_[0]->_execute($_[1])},
360 22     22   63 '+' => \&_exec_sum,
361             '*' => \&_exec_mul,
362             '%' => sub {$_[0]->_execute($_[1]) % $_[0]->_execute($_[2]) },
363 25     25   76 '^' => sub {$_[0]->_execute($_[1]) ** $self->_execute($_[2])},
364 0     0   0 '**' => sub {$_[0]->_execute($_[1]) ** $self->_execute($_[2])},
365             '=' => \&_exec_assignment,
366             '&' => \&_exec_function_call,
367             '{' => \&_exec_block,
368 31     31   42 '$' => sub { my $self = shift; $self->_variable_lookup(@_) },
  31         97  
369 865         11441 );
370             # print STDERR "Executing " . Dumper($self->{ast});
371 865 100       2487 if (ref $ast ){
372 358         902 my @a = @$ast;
373 358         496 my $op = shift @a;
374 358 50       896 if (my $fun = $dispatch{$op}){
375 358         885 return &$fun($self, @a);
376             } else {
377 0         0 confess ("Operator '$op' not yet implemented\n");
378             }
379             } else {
380 507         6223 $ast;
381             }
382             }
383              
384             sub set_var_callback {
385 1     1 1 15 $_[0]->{var_callback} = $_[1];
386             }
387              
388             # executes a sum
389             sub _exec_sum {
390 72     72   101 my $self = shift;
391             # avoid addition for unary plus, for overloaded objects
392 72         199 my $sum = $self->_execute(shift);
393 72         177 foreach (@_){
394 84         199 $sum = $sum + $self->_execute($_);
395             }
396 72         1486 return $sum;
397             }
398              
399             # executes a value
400             sub val {
401 181     181 1 1364 my $self = shift;
402 181   100     874 $self->{temp_vars} = shift || {};
403 181         589 my $res = $self->_execute($self->{ast});
404 177         603 $self->{temp_vars} = {};
405 177         1386 return +$res;
406             }
407              
408             # executes a block, eg a list of statements
409             sub _exec_block {
410 9     9   16 my $self = shift;
411             # warn "Executing block: ". Dumper(\@_);
412 9         14 my $res;
413 9         35 foreach (@_){
414 18         46 $res = $self->_execute($_);
415             }
416 9         89 $res;
417             }
418              
419             # executes a multiplication
420             sub _exec_mul {
421 90     90   127 my $self = shift;
422 90         114 my $prod = 1;
423 90         171 foreach (@_){
424 180         395 $prod *= $self->_execute($_);
425             }
426 90         1001 $prod;
427             }
428              
429             # executes an _assignment
430             sub _exec_assignment {
431 6     6   12 my ($self, $lvalue, $rvalue) = @_;
432 6 50       21 if (!is_lvalue($lvalue)){
433 0         0 confess('Internal error: $lvalue is not a "variable" AST');
434             }
435 6         25 return $self->{variables}{$lvalue->[1]} = $self->_execute($rvalue);
436             }
437              
438              
439             my %builtin_dispatch_table = (
440             'sqrt' => sub { sqrt $_[0] },
441             'ceil' => sub { ceil $_[0] },
442             'floor' => sub { floor $_[0]},
443             'sin' => sub { sin $_[0] },
444             'asin' => sub { asin $_[0] },
445             'cos' => sub { cos $_[0] },
446             'acos' => sub { acos $_[0] },
447             'tan' => sub { tan $_[0] },
448             'atan' => sub { atan $_[0] },
449             'exp' => sub { exp $_[0] },
450             'log' => sub { log $_[0] },
451             'sinh' => sub { (exp($_[0]) - exp(-$_[0]))/2},
452             'cosh' => sub { (exp($_[0]) + exp(-$_[0]))/2},
453             'log10' => sub { log($_[0]) / log(10) },
454             'log2' => sub { log($_[0]) / log(2) },
455             'theta' => sub { $_[0] > 0 ? 1 : 0 },
456             'pi' => sub { 3.141592653589793 },
457             );
458              
459              
460             sub set_function {
461 6     6 1 2327 my ($self, $name, $func) = @_;
462              
463 6         33 $self->{_user_dispatch_table}->{$name} = $func;
464             }
465              
466             # executes a function call
467             sub _exec_function_call {
468 43     43   53 my $self = shift;
469 43         95 my $name = shift;
470              
471 43         526 my %dispatch_table = %builtin_dispatch_table;
472              
473 43 100       94 my %user_fun = %{$self->{_user_dispatch_table} || {} };
  43         193  
474 43         192 while (my ($k, $v) = each %user_fun) {
475 9         27 $dispatch_table{$k} = $v;
476             }
477              
478 43 100       87 if (my $fun = $dispatch_table{$name}){
479 41         70 return $fun->(map {$self->_execute($_)} @_);
  38         185  
480             } else {
481 2         465 confess("Unknown function: $name");
482             }
483             }
484              
485             # checks if a variable is defined, and returns its value
486             sub _variable_lookup {
487 31     31   54 my ($self, $var) = @_;
488             # warn "Looking up <$var>\n";
489 31 100       107 if (exists $self->{temp_vars}->{$var}){
    100          
490 25         352 return $self->{temp_vars}->{$var};
491             } elsif (exists $self->{variables}->{$var}){
492 3         44 return $self->{variables}->{$var};
493             } else {
494 3         10 $self->{var_callback}->($var);
495             }
496             }
497              
498             # used for testing purposes only:
499             # returns the (recursive) number of operands in the AST
500             sub ast_size {
501 308     308 1 432 my ($self, $ast) = @_;
502 308 100       443 $ast = defined $ast ? $ast : $self->{ast};
503 308 100       774 return 1 unless ref $ast;
504 100         101 my $size = -1; # the initial op/type should be ignored
505 100         137 for (@$ast){
506 268         435 $size += $self->ast_size($_);
507             }
508 100         273 return $size;
509             }
510              
511             sub variables {
512 5     5 1 18 my ($self) = shift;
513 5         5 my %vars;
514             my $v;
515 5         11 my @todo = ($self->{ast});
516 5         47 while (@todo){
517 17         18 my $ast = shift @todo;
518 17 100       34 next unless ref $ast;
519 12 100       21 if ($ast->[0] eq '$'){
520 8         22 $vars{$ast->[1]}++;
521             } else {
522             # XXX do we need push the first element of @$ast?
523 4         11 push @todo, @$ast;
524             }
525             }
526 5         43 return sort keys %vars;
527             }
528              
529             # emit perl code for an AST.
530             # needed for compiling an expression into a anonymous sub
531             sub _ast_to_perl {
532 261     261   415 my ($self, $ast) = @_;;
533 261 100       2590 return $ast unless ref $ast;
534              
535             my $joined_operator = sub {
536 544     544   730 my $op = shift;
537             return sub {
538 63         115 join $op, map { '(' . $self->_ast_to_perl($_). ')' } @_
  120         290  
539 544         3170 };
540 136         494 };
541              
542             my %translations = (
543 4     4   142 '$' => sub { qq/( exists \$vars{$_[0]} ? \$vars{$_[0]} : exists \$default_vars{$_[0]} ? \$default_vars{$_[0]} : \$self->{var_callback}->("$_[0]")) / },
544 4     4   8 '{' => sub { join "\n", map { $self->_ast_to_perl($_) . ";" } @_ },
  8         26  
545 2     2   17 '=' => sub { qq/\$vars{$_[0][1]} = / . $self->_ast_to_perl($_[1]) },
546             '+' => &$joined_operator('+'),
547             '*' => &$joined_operator('*'),
548             '^' => &$joined_operator('**'),
549             '%' => &$joined_operator('%'),
550 10     10   38 '-' => sub { '-(' . $self->_ast_to_perl($_[0]) . ')' },
551 9     9   38 '/' => sub { '1/(' . $self->_ast_to_perl($_[0]) . ')' },
552 44     44   113 '&' => sub { $self->_function_to_perl(@_) },
553 136         1234 );
554 136         431 my ($action, @rest) = @$ast;
555 136         249 my $do = $translations{$action};
556 136 50       292 if ($do){
557 136         287 return &$do(@rest);
558             } else {
559 0         0 confess "Internal error: don't know what to do with '$action'";
560             }
561             }
562              
563             {
564             my %builtins = (
565             sqrt => sub { "sqrt($_[0])" },
566             ceil => sub { "ceil($_[0])" },
567             floor => sub { "floor($_[0])" },
568             sin => sub { "sin($_[0])" },
569             asin => sub { "asin($_[0])" },
570             cos => sub { "cos($_[0])" },
571             acos => sub { "acos($_[0])" },
572             tan => sub { "tan($_[0])" },
573             atan => sub { "atan($_[0])" },
574             exp => sub { "exp($_[0])" },
575             log => sub { "log($_[0])" },
576             sinh => sub { "do { my \$t=$_[0]; (exp(\$t) - exp(-(\$t)))/2}" },
577             cosh => sub { "do { my \$t=$_[0]; (exp(\$t) + exp(-(\$t)))/2}" },
578             log10 => sub { "log($_[0]) / log(10)" },
579             log2 => sub { "log($_[0]) / log(2)" },
580             theta => sub { "$_[0] > 0 ? 1 : 0" },
581             pi => sub { "3.141592653589793" },
582             );
583              
584             sub _function_to_perl {
585 44     44   96 my ($self, $name, @args) = @_;
586 44 100       130 if ($self->{_user_dispatch_table}->{$name}) {
587 6         17 return qq[\$user_functions{'$name'}->(]
588 7         34 . join(',', map { $self->_ast_to_perl($_) } @args)
589             . qq[)];
590             }
591 37         66 my $do = $builtins{$name};
592 37 100       58 if ($do){
593 36         91 return $do->(map { $self->_ast_to_perl($_) } @args );
  33         175  
594             } else {
595 1         474 confess "Unknow function '$name'";
596             }
597             }
598             }
599              
600             sub compiled {
601 73     73 1 3128 my $self = shift;
602 73         142 local $Data::Dumper::Indent = 0;
603 73         104 local $Data::Dumper::Terse = 1;
604              
605             # the eval will close over %user_functions
606             # if it contains any calls to it. Closures FTW!
607 73 100       102 my %user_functions = %{ $self->{_user_dispatch_table} || {} };
  73         401  
608              
609 73         166 my $text = <<'CODE';
610             sub {
611             my %vars = %{; shift || {} };
612             use warnings FATAL => qw(uninitialized);
613             no warnings 'void';
614             my %default_vars = %{;
615             CODE
616 73         146 chomp $text;
617 73         305 $text .= Dumper($self->{variables}) . "};\n ";
618 73         5361 $text .= $self->_ast_to_perl($self->{ast});
619 72         176 $text .= "\n}\n";
620             # print STDERR "\n$text";
621 72     5   10208 my $res = eval $text;
  5     5   35  
  5     5   9  
  5     5   274  
  5     5   21  
  5     5   10  
  5     4   386  
  5     4   38  
  5     3   11  
  5     3   275  
  5     3   86  
  5     3   11  
  5     3   376  
  5     3   34  
  5     2   9  
  5     2   253  
  5     2   26  
  5     2   10  
  5     2   365  
  4     2   26  
  4     2   16  
  4     2   180  
  4     2   19  
  4     2   19  
  4     2   278  
  3     2   20  
  3     2   5  
  3     2   140  
  3     2   14  
  3     2   5  
  3     2   183  
  3     2   19  
  3     2   5  
  3     2   120  
  3     2   13  
  3     2   6  
  3     2   188  
  3     2   18  
  3     2   5  
  3     2   129  
  3     2   14  
  3     2   5  
  3     2   165  
  2     2   11  
  2     2   4  
  2     2   83  
  2     2   9  
  2     2   4  
  2     2   104  
  2     2   11  
  2     2   4  
  2     2   75  
  2     2   8  
  2     2   3  
  2     1   108  
  2     1   12  
  2     1   3  
  2     1   82  
  2     1   10  
  2     1   3  
  2     1   109  
  2     1   12  
  2         3  
  2         91  
  2         10  
  2         3  
  2         126  
  2         14  
  2         5  
  2         96  
  2         9  
  2         5  
  2         123  
  2         13  
  2         3  
  2         101  
  2         10  
  2         3  
  2         115  
  2         13  
  2         4  
  2         120  
  2         9  
  2         3  
  2         235  
  2         13  
  2         4  
  2         87  
  2         8  
  2         4  
  2         136  
  2         11  
  2         4  
  2         85  
  2         9  
  2         2  
  2         145  
  2         12  
  2         2  
  2         84  
  2         8  
  2         3  
  2         128  
  2         12  
  2         4  
  2         82  
  2         9  
  2         4  
  2         151  
  2         17  
  2         5  
  2         126  
  2         12  
  2         4  
  2         152  
  2         15  
  2         5  
  2         101  
  2         10  
  2         4  
  2         120  
  2         17  
  2         5  
  2         140  
  2         11  
  2         5  
  2         137  
  2         14  
  2         3  
  2         91  
  2         10  
  2         4  
  2         118  
  2         13  
  2         4  
  2         110  
  2         9  
  2         4  
  2         117  
  2         21  
  2         7  
  2         111  
  2         9  
  2         3  
  2         131  
  2         13  
  2         3  
  2         91  
  2         10  
  2         2  
  2         122  
  2         13  
  2         3  
  2         89  
  2         8  
  2         4  
  2         102  
  2         15  
  2         5  
  2         117  
  2         10  
  2         3  
  2         107  
  1         6  
  1         2  
  1         43  
  1         5  
  1         2  
  1         63  
  1         7  
  1         2  
  1         45  
  1         5  
  1         2  
  1         99  
  1         5  
  1         2  
  1         33  
  1         6  
  1         2  
  1         55  
  1         6  
  1         2  
  1         81  
  1         5  
  1         2  
  1         62  
622 72 50       222 confess "Internal error while compiling: $@" if $@;
623 72         2854 return $res;
624             }
625              
626             1;
627              
628             # vim: sw=4 ts=4 expandtab