Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

563745 views
1
/* mpexpr_evaluate -- shared code for simple expression evaluation
2
3
Copyright 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
4
5
This file is part of the GNU MP Library.
6
7
The GNU MP Library is free software; you can redistribute it and/or modify
8
it under the terms of the GNU Lesser General Public License as published by
9
the Free Software Foundation; either version 2.1 of the License, or (at your
10
option) any later version.
11
12
The GNU MP Library is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15
License for more details.
16
17
You should have received a copy of the GNU Lesser General Public License
18
along with the GNU MP Library; see the file COPYING.LIB. If not, write to
19
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
MA 02110-1301, USA. */
21
22
#include <ctype.h>
23
#include <stdio.h>
24
#include <string.h>
25
26
#include "gmp.h"
27
#include "expr-impl.h"
28
29
30
/* Change this to "#define TRACE(x) x" to get some traces. The trace
31
printfs junk up the code a bit, but it's very hard to tell what's going
32
on without them. Set MPX_TRACE to a suitable output function for the
33
mpz/mpq/mpf being run (if you have the wrong trace function it'll
34
probably segv). */
35
36
#define TRACE(x)
37
#define MPX_TRACE mpz_trace
38
39
40
/* A few helper macros copied from gmp-impl.h */
41
#define ALLOCATE_FUNC_TYPE(n,type) \
42
((type *) (*allocate_func) ((n) * sizeof (type)))
43
#define ALLOCATE_FUNC_LIMBS(n) ALLOCATE_FUNC_TYPE (n, mp_limb_t)
44
#define REALLOCATE_FUNC_TYPE(p, old_size, new_size, type) \
45
((type *) (*reallocate_func) \
46
(p, (old_size) * sizeof (type), (new_size) * sizeof (type)))
47
#define REALLOCATE_FUNC_LIMBS(p, old_size, new_size) \
48
REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t)
49
#define FREE_FUNC_TYPE(p,n,type) (*free_func) (p, (n) * sizeof (type))
50
#define FREE_FUNC_LIMBS(p,n) FREE_FUNC_TYPE (p, n, mp_limb_t)
51
#define ASSERT(x)
52
53
54
55
/* All the error strings are just for diagnostic traces. Only the error
56
code is actually returned. */
57
#define ERROR(str,code) \
58
{ \
59
TRACE (printf ("%s\n", str)); \
60
p->error_code = (code); \
61
goto done; \
62
}
63
64
65
#define REALLOC(ptr, alloc, incr, type) \
66
do { \
67
int new_alloc = (alloc) + (incr); \
68
ptr = REALLOCATE_FUNC_TYPE (ptr, alloc, new_alloc, type); \
69
(alloc) = new_alloc; \
70
} while (0)
71
72
73
/* data stack top element */
74
#define SP (p->data_stack + p->data_top)
75
76
/* Make sure there's room for another data element above current top.
77
reallocate_func is fetched for when this macro is used in lookahead(). */
78
#define DATA_SPACE() \
79
do { \
80
if (p->data_top + 1 >= p->data_alloc) \
81
{ \
82
void *(*reallocate_func) (void *, size_t, size_t); \
83
mp_get_memory_functions (NULL, &reallocate_func, NULL); \
84
TRACE (printf ("grow stack from %d\n", p->data_alloc)); \
85
REALLOC (p->data_stack, p->data_alloc, 20, union mpX_t); \
86
} \
87
ASSERT (p->data_top + 1 <= p->data_inited); \
88
if (p->data_top + 1 == p->data_inited) \
89
{ \
90
TRACE (printf ("initialize %d\n", p->data_top + 1)); \
91
(*p->mpX_init) (&p->data_stack[p->data_top + 1], p->prec); \
92
p->data_inited++; \
93
} \
94
} while (0)
95
96
#define DATA_PUSH() \
97
do { \
98
p->data_top++; \
99
ASSERT (p->data_top < p->data_alloc); \
100
ASSERT (p->data_top < p->data_inited); \
101
} while (0)
102
103
/* the last stack entry is never popped, so top>=0 will be true */
104
#define DATA_POP(n) \
105
do { \
106
p->data_top -= (n); \
107
ASSERT (p->data_top >= 0); \
108
} while (0)
109
110
111
/* lookahead() parses the next token. Return 1 if successful, with some
112
extra data. Return 0 if fail, with reason in p->error_code.
113
114
"prefix" is MPEXPR_TYPE_PREFIX if an operator with that attribute is
115
preferred, or 0 if an operator without is preferred. */
116
117
#define TOKEN_EOF -1 /* no extra data */
118
#define TOKEN_VALUE -2 /* pushed onto data stack */
119
#define TOKEN_OPERATOR -3 /* stored in p->token_op */
120
#define TOKEN_FUNCTION -4 /* stored in p->token_op */
121
122
#define TOKEN_NAME(n) \
123
((n) == TOKEN_EOF ? "TOKEN_EOF" \
124
: (n) == TOKEN_VALUE ? "TOKEN_VALUE" \
125
: (n) == TOKEN_OPERATOR ? "TOKEN_OPERATOR" \
126
: (n) == TOKEN_VALUE ? "TOKEN_FUNCTION" \
127
: "UNKNOWN TOKEN")
128
129
/* Functions default to being parsed as whole words, operators to match just
130
at the start of the string. The type flags override this. */
131
#define WHOLEWORD(op) \
132
(op->precedence == 0 \
133
? (! (op->type & MPEXPR_TYPE_OPERATOR)) \
134
: (op->type & MPEXPR_TYPE_WHOLEWORD))
135
136
#define isasciispace(c) (isascii (c) && isspace (c))
137
138
static int
139
lookahead (struct mpexpr_parse_t *p, int prefix)
140
{
141
__gmp_const struct mpexpr_operator_t *op, *op_found;
142
size_t oplen, oplen_found, wlen;
143
int i;
144
145
/* skip white space */
146
while (p->elen > 0 && isasciispace (*p->e))
147
p->e++, p->elen--;
148
149
if (p->elen == 0)
150
{
151
TRACE (printf ("lookahead EOF\n"));
152
p->token = TOKEN_EOF;
153
return 1;
154
}
155
156
DATA_SPACE ();
157
158
/* Get extent of whole word. */
159
for (wlen = 0; wlen < p->elen; wlen++)
160
if (! isasciicsym (p->e[wlen]))
161
break;
162
163
TRACE (printf ("lookahead at: \"%.*s\" length %u, word %u\n",
164
(int) p->elen, p->e, p->elen, wlen));
165
166
op_found = NULL;
167
oplen_found = 0;
168
for (op = p->table; op->name != NULL; op++)
169
{
170
if (op->type == MPEXPR_TYPE_NEW_TABLE)
171
{
172
printf ("new\n");
173
op = (struct mpexpr_operator_t *) op->name - 1;
174
continue;
175
}
176
177
oplen = strlen (op->name);
178
if (! ((WHOLEWORD (op) ? wlen == oplen : p->elen >= oplen)
179
&& memcmp (p->e, op->name, oplen) == 0))
180
continue;
181
182
/* Shorter matches don't replace longer previous ones. */
183
if (op_found && oplen < oplen_found)
184
continue;
185
186
/* On a match of equal length to a previous one, the old match isn't
187
replaced if it has the preferred prefix, and if it doesn't then
188
it's not replaced if the new one also doesn't. */
189
if (op_found && oplen == oplen_found
190
&& ((op_found->type & MPEXPR_TYPE_PREFIX) == prefix
191
|| (op->type & MPEXPR_TYPE_PREFIX) != prefix))
192
continue;
193
194
/* This is now either the first match seen, or a longer than previous
195
match, or an equal to previous one but with a preferred prefix. */
196
op_found = op;
197
oplen_found = oplen;
198
}
199
200
if (op_found)
201
{
202
p->e += oplen_found, p->elen -= oplen_found;
203
204
if (op_found->type == MPEXPR_TYPE_VARIABLE)
205
{
206
if (p->elen == 0)
207
ERROR ("end of string expecting a variable",
208
MPEXPR_RESULT_PARSE_ERROR);
209
i = p->e[0] - 'a';
210
if (i < 0 || i >= MPEXPR_VARIABLES)
211
ERROR ("bad variable name", MPEXPR_RESULT_BAD_VARIABLE);
212
goto variable;
213
}
214
215
if (op_found->precedence == 0)
216
{
217
TRACE (printf ("lookahead function: %s\n", op_found->name));
218
p->token = TOKEN_FUNCTION;
219
p->token_op = op_found;
220
return 1;
221
}
222
else
223
{
224
TRACE (printf ("lookahead operator: %s\n", op_found->name));
225
p->token = TOKEN_OPERATOR;
226
p->token_op = op_found;
227
return 1;
228
}
229
}
230
231
oplen = (*p->mpX_number) (SP+1, p->e, p->elen, p->base);
232
if (oplen != 0)
233
{
234
p->e += oplen, p->elen -= oplen;
235
p->token = TOKEN_VALUE;
236
DATA_PUSH ();
237
TRACE (MPX_TRACE ("lookahead number", SP));
238
return 1;
239
}
240
241
/* Maybe an unprefixed one character variable */
242
i = p->e[0] - 'a';
243
if (wlen == 1 && i >= 0 && i < MPEXPR_VARIABLES)
244
{
245
variable:
246
p->e++, p->elen--;
247
if (p->var[i] == NULL)
248
ERROR ("NULL variable", MPEXPR_RESULT_BAD_VARIABLE);
249
TRACE (printf ("lookahead variable: var[%d] = ", i);
250
MPX_TRACE ("", p->var[i]));
251
p->token = TOKEN_VALUE;
252
DATA_PUSH ();
253
(*p->mpX_set) (SP, p->var[i]);
254
return 1;
255
}
256
257
ERROR ("no token matched", MPEXPR_RESULT_PARSE_ERROR);
258
259
done:
260
return 0;
261
}
262
263
264
/* control stack current top element */
265
#define CP (p->control_stack + p->control_top)
266
267
/* make sure there's room for another control element above current top */
268
#define CONTROL_SPACE() \
269
do { \
270
if (p->control_top + 1 >= p->control_alloc) \
271
{ \
272
TRACE (printf ("grow control stack from %d\n", p->control_alloc)); \
273
REALLOC (p->control_stack, p->control_alloc, 20, \
274
struct mpexpr_control_t); \
275
} \
276
} while (0)
277
278
/* Push an operator on the control stack, claiming currently to have the
279
given number of args ready. Local variable "op" is used in case opptr is
280
a reference through CP. */
281
#define CONTROL_PUSH(opptr,args) \
282
do { \
283
__gmp_const struct mpexpr_operator_t *op = opptr; \
284
struct mpexpr_control_t *cp; \
285
CONTROL_SPACE (); \
286
p->control_top++; \
287
ASSERT (p->control_top < p->control_alloc); \
288
cp = CP; \
289
cp->op = op; \
290
cp->argcount = (args); \
291
TRACE_CONTROL("control stack push:"); \
292
} while (0)
293
294
/* The special operator_done is never popped, so top>=0 will hold. */
295
#define CONTROL_POP() \
296
do { \
297
p->control_top--; \
298
ASSERT (p->control_top >= 0); \
299
TRACE_CONTROL ("control stack pop:"); \
300
} while (0)
301
302
#define TRACE_CONTROL(str) \
303
TRACE ({ \
304
int i; \
305
printf ("%s depth %d:", str, p->control_top); \
306
for (i = 0; i <= p->control_top; i++) \
307
printf (" \"%s\"(%d)", \
308
p->control_stack[i].op->name, \
309
p->control_stack[i].argcount); \
310
printf ("\n"); \
311
});
312
313
314
#define LOOKAHEAD(prefix) \
315
do { \
316
if (! lookahead (p, prefix)) \
317
goto done; \
318
} while (0)
319
320
#define CHECK_UI(n) \
321
do { \
322
if (! (*p->mpX_ulong_p) (n)) \
323
ERROR ("operand doesn't fit ulong", MPEXPR_RESULT_NOT_UI); \
324
} while (0)
325
326
#define CHECK_ARGCOUNT(str,n) \
327
do { \
328
if (CP->argcount != (n)) \
329
{ \
330
TRACE (printf ("wrong number of arguments for %s, got %d want %d", \
331
str, CP->argcount, n)); \
332
ERROR ("", MPEXPR_RESULT_PARSE_ERROR); \
333
} \
334
} while (0)
335
336
337
/* There's two basic states here. In both p->token is the next token.
338
339
"another_expr" is when a whole expression should be parsed. This means a
340
literal or variable value possibly followed by an operator, or a function
341
or prefix operator followed by a further whole expression.
342
343
"another_operator" is when an expression has been parsed and its value is
344
on the top of the data stack (SP) and an optional further postfix or
345
infix operator should be parsed.
346
347
In "another_operator" precedences determine whether to push the operator
348
onto the control stack, or instead go to "apply_control" to reduce the
349
operator currently on top of the control stack.
350
351
When an operator has both a prefix and postfix/infix form, a LOOKAHEAD()
352
for "another_expr" will seek the prefix form, a LOOKAHEAD() for
353
"another_operator" will seek the postfix/infix form. The grammar is
354
simple enough that the next state is known before reading the next token.
355
356
Argument count checking guards against functions consuming the wrong
357
number of operands from the data stack. The same checks are applied to
358
operators, but will always pass since a UNARY or BINARY will only ever
359
parse with the correct operands. */
360
361
int
362
mpexpr_evaluate (struct mpexpr_parse_t *p)
363
{
364
void *(*allocate_func) (size_t);
365
void *(*reallocate_func) (void *, size_t, size_t);
366
void (*free_func) (void *, size_t);
367
368
mp_get_memory_functions (&allocate_func, &reallocate_func, &free_func);
369
370
TRACE (printf ("mpexpr_evaluate() base %d \"%.*s\"\n",
371
p->base, (int) p->elen, p->e));
372
373
/* "done" is a special sentinel at the bottom of the control stack,
374
precedence -1 is lower than any normal operator. */
375
{
376
static __gmp_const struct mpexpr_operator_t operator_done
377
= { "DONE", NULL, MPEXPR_TYPE_DONE, -1 };
378
379
p->control_alloc = 20;
380
p->control_stack = ALLOCATE_FUNC_TYPE (p->control_alloc,
381
struct mpexpr_control_t);
382
p->control_top = 0;
383
CP->op = &operator_done;
384
CP->argcount = 1;
385
}
386
387
p->data_inited = 0;
388
p->data_alloc = 20;
389
p->data_stack = ALLOCATE_FUNC_TYPE (p->data_alloc, union mpX_t);
390
p->data_top = -1;
391
392
p->error_code = MPEXPR_RESULT_OK;
393
394
395
another_expr_lookahead:
396
LOOKAHEAD (MPEXPR_TYPE_PREFIX);
397
TRACE (printf ("another expr\n"));
398
399
/*another_expr:*/
400
switch (p->token) {
401
case TOKEN_VALUE:
402
goto another_operator_lookahead;
403
404
case TOKEN_OPERATOR:
405
TRACE (printf ("operator %s\n", p->token_op->name));
406
if (! (p->token_op->type & MPEXPR_TYPE_PREFIX))
407
ERROR ("expected a prefix operator", MPEXPR_RESULT_PARSE_ERROR);
408
409
CONTROL_PUSH (p->token_op, 1);
410
goto another_expr_lookahead;
411
412
case TOKEN_FUNCTION:
413
CONTROL_PUSH (p->token_op, 1);
414
415
if (p->token_op->type & MPEXPR_TYPE_CONSTANT)
416
goto apply_control_lookahead;
417
418
LOOKAHEAD (MPEXPR_TYPE_PREFIX);
419
if (! (p->token == TOKEN_OPERATOR
420
&& p->token_op->type == MPEXPR_TYPE_OPENPAREN))
421
ERROR ("expected open paren for function", MPEXPR_RESULT_PARSE_ERROR);
422
423
TRACE (printf ("open paren for function \"%s\"\n", CP->op->name));
424
425
if ((CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) == MPEXPR_TYPE_NARY(0))
426
{
427
LOOKAHEAD (0);
428
if (! (p->token == TOKEN_OPERATOR
429
&& p->token_op->type == MPEXPR_TYPE_CLOSEPAREN))
430
ERROR ("expected close paren for 0ary function",
431
MPEXPR_RESULT_PARSE_ERROR);
432
goto apply_control_lookahead;
433
}
434
435
goto another_expr_lookahead;
436
}
437
ERROR ("unrecognised start of expression", MPEXPR_RESULT_PARSE_ERROR);
438
439
440
another_operator_lookahead:
441
LOOKAHEAD (0);
442
another_operator:
443
TRACE (printf ("another operator maybe: %s\n", TOKEN_NAME(p->token)));
444
445
switch (p->token) {
446
case TOKEN_EOF:
447
goto apply_control;
448
449
case TOKEN_OPERATOR:
450
/* The next operator is compared to the one on top of the control stack.
451
If the next is lower precedence, or the same precedence and not
452
right-associative, then reduce using the control stack and look at
453
the next operator again later. */
454
455
#define PRECEDENCE_TEST_REDUCE(tprec,cprec,ttype,ctype) \
456
((tprec) < (cprec) \
457
|| ((tprec) == (cprec) && ! ((ttype) & MPEXPR_TYPE_RIGHTASSOC)))
458
459
if (PRECEDENCE_TEST_REDUCE (p->token_op->precedence, CP->op->precedence,
460
p->token_op->type, CP->op->type))
461
{
462
TRACE (printf ("defer operator: %s (prec %d vs %d, type 0x%X)\n",
463
p->token_op->name,
464
p->token_op->precedence, CP->op->precedence,
465
p->token_op->type));
466
goto apply_control;
467
}
468
469
/* An argsep is a binary operator, but is never pushed on the control
470
stack, it just accumulates an extra argument for a function. */
471
if (p->token_op->type == MPEXPR_TYPE_ARGSEP)
472
{
473
if (CP->op->precedence != 0)
474
ERROR ("ARGSEP not in a function call", MPEXPR_RESULT_PARSE_ERROR);
475
476
TRACE (printf ("argsep for function \"%s\"(%d)\n",
477
CP->op->name, CP->argcount));
478
479
#define IS_PAIRWISE(type) \
480
(((type) & (MPEXPR_TYPE_MASK_ARGCOUNT | MPEXPR_TYPE_PAIRWISE)) \
481
== (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE))
482
483
if (IS_PAIRWISE (CP->op->type) && CP->argcount >= 2)
484
{
485
TRACE (printf (" will reduce pairwise now\n"));
486
CP->argcount--;
487
CONTROL_PUSH (CP->op, 2);
488
goto apply_control;
489
}
490
491
CP->argcount++;
492
goto another_expr_lookahead;
493
}
494
495
switch (p->token_op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
496
case MPEXPR_TYPE_NARY(1):
497
/* Postfix unary operators can always be applied immediately. The
498
easiest way to do this is just push it on the control stack and go
499
to the normal control stack reduction code. */
500
501
TRACE (printf ("postfix unary operator: %s\n", p->token_op->name));
502
if (p->token_op->type & MPEXPR_TYPE_PREFIX)
503
ERROR ("prefix unary operator used postfix",
504
MPEXPR_RESULT_PARSE_ERROR);
505
CONTROL_PUSH (p->token_op, 1);
506
goto apply_control_lookahead;
507
508
case MPEXPR_TYPE_NARY(2):
509
CONTROL_PUSH (p->token_op, 2);
510
goto another_expr_lookahead;
511
512
case MPEXPR_TYPE_NARY(3):
513
CONTROL_PUSH (p->token_op, 1);
514
goto another_expr_lookahead;
515
}
516
517
TRACE (printf ("unrecognised operator \"%s\" type: 0x%X",
518
CP->op->name, CP->op->type));
519
ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
520
break;
521
522
default:
523
TRACE (printf ("expecting an operator, got token %d", p->token));
524
ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
525
}
526
527
528
apply_control_lookahead:
529
LOOKAHEAD (0);
530
apply_control:
531
/* Apply the top element CP of the control stack. Data values are SP,
532
SP-1, etc. Result is left as stack top SP after popping consumed
533
values.
534
535
The use of sp as a duplicate of SP will help compilers that can't
536
otherwise recognise the various uses of SP as common subexpressions. */
537
538
TRACE (printf ("apply control: nested %d, \"%s\" 0x%X, %d args\n",
539
p->control_top, CP->op->name, CP->op->type, CP->argcount));
540
541
TRACE (printf ("apply 0x%X-ary\n",
542
CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT));
543
switch (CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
544
case MPEXPR_TYPE_NARY(0):
545
{
546
mpX_ptr sp;
547
DATA_SPACE ();
548
DATA_PUSH ();
549
sp = SP;
550
switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
551
case 0:
552
(* (mpexpr_fun_0ary_t) CP->op->fun) (sp);
553
break;
554
case MPEXPR_TYPE_RESULT_INT:
555
(*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_0ary_t) CP->op->fun) ());
556
break;
557
default:
558
ERROR ("unrecognised 0ary argument calling style",
559
MPEXPR_RESULT_BAD_TABLE);
560
}
561
}
562
break;
563
564
case MPEXPR_TYPE_NARY(1):
565
{
566
mpX_ptr sp = SP;
567
CHECK_ARGCOUNT ("unary", 1);
568
TRACE (MPX_TRACE ("before", sp));
569
570
switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
571
case 0:
572
/* not a special */
573
break;
574
575
case MPEXPR_TYPE_DONE & MPEXPR_TYPE_MASK_SPECIAL:
576
TRACE (printf ("special done\n"));
577
goto done;
578
579
case MPEXPR_TYPE_LOGICAL_NOT & MPEXPR_TYPE_MASK_SPECIAL:
580
TRACE (printf ("special logical not\n"));
581
(*p->mpX_set_si)
582
(sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) == 0));
583
goto apply_control_done;
584
585
case MPEXPR_TYPE_CLOSEPAREN & MPEXPR_TYPE_MASK_SPECIAL:
586
CONTROL_POP ();
587
if (CP->op->type == MPEXPR_TYPE_OPENPAREN)
588
{
589
TRACE (printf ("close paren matching open paren\n"));
590
CONTROL_POP ();
591
goto another_operator;
592
}
593
if (CP->op->precedence == 0)
594
{
595
TRACE (printf ("close paren for function\n"));
596
goto apply_control;
597
}
598
ERROR ("unexpected close paren", MPEXPR_RESULT_PARSE_ERROR);
599
600
default:
601
TRACE (printf ("unrecognised special unary operator 0x%X",
602
CP->op->type & MPEXPR_TYPE_MASK_SPECIAL));
603
ERROR ("", MPEXPR_RESULT_BAD_TABLE);
604
}
605
606
switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
607
case 0:
608
(* (mpexpr_fun_unary_t) CP->op->fun) (sp, sp);
609
break;
610
case MPEXPR_TYPE_LAST_UI:
611
CHECK_UI (sp);
612
(* (mpexpr_fun_unary_ui_t) CP->op->fun)
613
(sp, (*p->mpX_get_ui) (sp));
614
break;
615
case MPEXPR_TYPE_RESULT_INT:
616
(*p->mpX_set_si)
617
(sp, (long) (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp));
618
break;
619
case MPEXPR_TYPE_RESULT_INT | MPEXPR_TYPE_LAST_UI:
620
CHECK_UI (sp);
621
(*p->mpX_set_si)
622
(sp,
623
(long) (* (mpexpr_fun_i_unary_ui_t) CP->op->fun)
624
((*p->mpX_get_ui) (sp)));
625
break;
626
default:
627
ERROR ("unrecognised unary argument calling style",
628
MPEXPR_RESULT_BAD_TABLE);
629
}
630
}
631
break;
632
633
case MPEXPR_TYPE_NARY(2):
634
{
635
mpX_ptr sp;
636
637
/* pairwise functions are allowed to have just one argument */
638
if ((CP->op->type & MPEXPR_TYPE_PAIRWISE)
639
&& CP->op->precedence == 0
640
&& CP->argcount == 1)
641
goto apply_control_done;
642
643
CHECK_ARGCOUNT ("binary", 2);
644
DATA_POP (1);
645
sp = SP;
646
TRACE (MPX_TRACE ("lhs", sp);
647
MPX_TRACE ("rhs", sp+1));
648
649
if (CP->op->type & MPEXPR_TYPE_MASK_CMP)
650
{
651
int type = CP->op->type;
652
int cmp = (* (mpexpr_fun_i_binary_t) CP->op->fun)
653
(sp, sp+1);
654
(*p->mpX_set_si)
655
(sp,
656
(long)
657
(( (cmp < 0) & ((type & MPEXPR_TYPE_MASK_CMP_LT) != 0))
658
| ((cmp == 0) & ((type & MPEXPR_TYPE_MASK_CMP_EQ) != 0))
659
| ((cmp > 0) & ((type & MPEXPR_TYPE_MASK_CMP_GT) != 0))));
660
goto apply_control_done;
661
}
662
663
switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
664
case 0:
665
/* not a special */
666
break;
667
668
case MPEXPR_TYPE_QUESTION & MPEXPR_TYPE_MASK_SPECIAL:
669
ERROR ("'?' without ':'", MPEXPR_RESULT_PARSE_ERROR);
670
671
case MPEXPR_TYPE_COLON & MPEXPR_TYPE_MASK_SPECIAL:
672
TRACE (printf ("special colon\n"));
673
CONTROL_POP ();
674
if (CP->op->type != MPEXPR_TYPE_QUESTION)
675
ERROR ("':' without '?'", MPEXPR_RESULT_PARSE_ERROR);
676
677
CP->argcount--;
678
DATA_POP (1);
679
sp--;
680
TRACE (MPX_TRACE ("query", sp);
681
MPX_TRACE ("true", sp+1);
682
MPX_TRACE ("false", sp+2));
683
(*p->mpX_set)
684
(sp, (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
685
? sp+1 : sp+2);
686
goto apply_control_done;
687
688
case MPEXPR_TYPE_LOGICAL_AND & MPEXPR_TYPE_MASK_SPECIAL:
689
TRACE (printf ("special logical and\n"));
690
(*p->mpX_set_si)
691
(sp,
692
(long)
693
((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
694
&& (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
695
goto apply_control_done;
696
697
case MPEXPR_TYPE_LOGICAL_OR & MPEXPR_TYPE_MASK_SPECIAL:
698
TRACE (printf ("special logical and\n"));
699
(*p->mpX_set_si)
700
(sp,
701
(long)
702
((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
703
|| (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
704
goto apply_control_done;
705
706
case MPEXPR_TYPE_MAX & MPEXPR_TYPE_MASK_SPECIAL:
707
TRACE (printf ("special max\n"));
708
if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) < 0)
709
(*p->mpX_swap) (sp, sp+1);
710
goto apply_control_done;
711
case MPEXPR_TYPE_MIN & MPEXPR_TYPE_MASK_SPECIAL:
712
TRACE (printf ("special min\n"));
713
if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) > 0)
714
(*p->mpX_swap) (sp, sp+1);
715
goto apply_control_done;
716
717
default:
718
ERROR ("unrecognised special binary operator",
719
MPEXPR_RESULT_BAD_TABLE);
720
}
721
722
switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
723
case 0:
724
(* (mpexpr_fun_binary_t) CP->op->fun) (sp, sp, sp+1);
725
break;
726
case MPEXPR_TYPE_LAST_UI:
727
CHECK_UI (sp+1);
728
(* (mpexpr_fun_binary_ui_t) CP->op->fun)
729
(sp, sp, (*p->mpX_get_ui) (sp+1));
730
break;
731
case MPEXPR_TYPE_RESULT_INT:
732
(*p->mpX_set_si)
733
(sp,
734
(long) (* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1));
735
break;
736
case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
737
CHECK_UI (sp+1);
738
(*p->mpX_set_si)
739
(sp,
740
(long) (* (mpexpr_fun_i_binary_ui_t) CP->op->fun)
741
(sp, (*p->mpX_get_ui) (sp+1)));
742
break;
743
default:
744
ERROR ("unrecognised binary argument calling style",
745
MPEXPR_RESULT_BAD_TABLE);
746
}
747
}
748
break;
749
750
case MPEXPR_TYPE_NARY(3):
751
{
752
mpX_ptr sp;
753
754
CHECK_ARGCOUNT ("ternary", 3);
755
DATA_POP (2);
756
sp = SP;
757
TRACE (MPX_TRACE ("arg1", sp);
758
MPX_TRACE ("arg2", sp+1);
759
MPX_TRACE ("arg3", sp+1));
760
761
switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
762
case 0:
763
(* (mpexpr_fun_ternary_t) CP->op->fun) (sp, sp, sp+1, sp+2);
764
break;
765
case MPEXPR_TYPE_LAST_UI:
766
CHECK_UI (sp+2);
767
(* (mpexpr_fun_ternary_ui_t) CP->op->fun)
768
(sp, sp, sp+1, (*p->mpX_get_ui) (sp+2));
769
break;
770
case MPEXPR_TYPE_RESULT_INT:
771
(*p->mpX_set_si)
772
(sp,
773
(long) (* (mpexpr_fun_i_ternary_t) CP->op->fun)
774
(sp, sp+1, sp+2));
775
break;
776
case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
777
CHECK_UI (sp+2);
778
(*p->mpX_set_si)
779
(sp,
780
(long) (* (mpexpr_fun_i_ternary_ui_t) CP->op->fun)
781
(sp, sp+1, (*p->mpX_get_ui) (sp+2)));
782
break;
783
default:
784
ERROR ("unrecognised binary argument calling style",
785
MPEXPR_RESULT_BAD_TABLE);
786
}
787
}
788
break;
789
790
default:
791
TRACE (printf ("unrecognised operator type: 0x%X\n", CP->op->type));
792
ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
793
}
794
795
apply_control_done:
796
TRACE (MPX_TRACE ("result", SP));
797
CONTROL_POP ();
798
goto another_operator;
799
800
done:
801
if (p->error_code == MPEXPR_RESULT_OK)
802
{
803
if (p->data_top != 0)
804
{
805
TRACE (printf ("data stack want top at 0, got %d\n", p->data_top));
806
p->error_code = MPEXPR_RESULT_PARSE_ERROR;
807
}
808
else
809
(*p->mpX_set_or_swap) (p->res, SP);
810
}
811
812
{
813
int i;
814
for (i = 0; i < p->data_inited; i++)
815
{
816
TRACE (printf ("clear %d\n", i));
817
(*p->mpX_clear) (p->data_stack+i);
818
}
819
}
820
821
FREE_FUNC_TYPE (p->data_stack, p->data_alloc, union mpX_t);
822
FREE_FUNC_TYPE (p->control_stack, p->control_alloc, struct mpexpr_control_t);
823
824
return p->error_code;
825
}
826
827