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 |