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

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